使git格式的补丁遵循git log之类的重命名--遵循
我试图将文件从一个本地git存储库移动到另一个本地git存储库,用于不同的项目,同时保留原始存储库中的历史记录。到目前为止,如果在源repo中从未移动或重命名该文件,则该文件运行良好:使git格式的补丁遵循git log之类的重命名--遵循,git,Git,我试图将文件从一个本地git存储库移动到另一个本地git存储库,用于不同的项目,同时保留原始存储库中的历史记录。到目前为止,如果在源repo中从未移动或重命名该文件,则该文件运行良好: # Executed from a directory in the target repository ( cd $SOURCE_REPOSITORY_DIRECTORY && git format-patch -B -M --stdout --root $SOURCE_FILENAME) |
# Executed from a directory in the target repository
( cd $SOURCE_REPOSITORY_DIRECTORY && git format-patch -B -M --stdout --root $SOURCE_FILENAME) | git am --committer-date-is-author-date
这是因为两个存储库的目录结构是相同的。如果它们不一样,我就必须创建补丁文件,并使用sed
或其他方法修复目录名
不管怎么说,在我找到一个被重命名的文件之前,这一切都太棒了。即使我指定了-B-m
(并获得了与-B-m-C相同的结果——更难找到副本
),我也不会在移动之前获得补丁,即使文件被干净地移动(相似性指数100%)
这尤其奇怪,因为git log--follow
显示所有提交,而git log--follow-p
提供所有差异。除了它以相反的顺序提供它们,所以我不能将它们输入到gitam
还请注意,git log--follow-p filename
将显示以下“补丁”以显示重命名:
diff --git a/old_dir_name/dir1/dir2/filename b/new_dir_name/dir0/dir1/dir2/filename
similarity index 100%
rename from old_dir_name/dir1/dir2/filename
rename to new_dir_name/dir0/dir1/dir2/filename
现在,如果git log
将以正确的格式和顺序显示补丁,以便git am
应用它们,我可以使用它,但事实并非如此。使用git log--reverse--follow-p filename
只输出名称更改补丁,而不输出其他内容
那么,如何让git格式补丁
真正按照帮助文件/手册页所说的方式重命名,同时只输出单个文件的补丁呢?或者,如何让git log-p
生成补丁,并将它们输入git am
以重新创建具有历史记录的文件
我使用的是git版本1.8.4.3。真恶心。我认为问题出在逻辑上。特别是,当您将
--reverse
和--follow
组合在一起时,必须指定旧文件名:
[rename foo to bar]
$ git log --follow bar # works
$ git log --follow --reverse -- foo # requires "--" because foo is not in HEAD
这个。。。这类作品。除此之外,当它点击重命名按钮时,它会将文件视为已删除,所有操作都会停止
tree-diff.c
包含以下功能:
static void try_to_follow_renames(...)
{
...
/* Remove the file creation entry from the diff queue, and remember it */
choice = q->queue[0];
q->nr = 0;
如果diff\u maybe\u\u rename
返回true,则调用该函数:
static inline int diff_might_be_rename(void)
{
return diff_queued_diff.nr == 1 &&
!DIFF_FILE_VALID(diff_queued_diff.queue[0]->one);
}
...
int diff_tree_sha1(...)
{
...
if (!*base && DIFF_OPT_TST(opt, FOLLOW_RENAMES) && diff_might_be_rename()) {
我在这里做了一些大的假设,但是当你按照另一个顺序去做时,我们来看看是否能找到一个被重命名的foo
,而不是刚刚创建的“filebar
”,如果日志被反转,你需要删除“filefoo
,看看我们是否能找到一个被重命名的bar
”,那只是。。。如果评论准确,则缺少
如果你有很多事情要做,我建议尝试在这里添加一些东西来记住差异是否被反转(就像格式补丁
和日志-反转
)一样,并根据需要更改差异可能是重命名()
和尝试遵循重命名()
代码
如果您只有一个,那么,手动整理一些差异可能更容易。:-) 我已经取得了一些进展,但现在更需要手动操作了
- 对于每个文件,使用带和不带
查看哪些文件已被重命名/移动/复制(为了简单起见,将它们全部称为“重命名”)的
——followlog
- 对于已重命名的文件,从
输出中提取以前完整的路径和文件名日志
- 然后使用
,但在命令行上给出所有旧名称和当前名称格式化补丁
git format-patch -B -M -o /tmp/patches --root -- old_dir_name/dir1/dir2/filename new_dir_name/dir0/dir1/dir2/filename
这将创建修补程序以创建旧文件,将其重命名为新名称,然后继续修补该文件。当然,对我来说,问题是旧目录在新的repo中不存在,并且目录级别已经改变,因此在让目录名正常工作方面仍然存在一些麻烦
这应该更容易一些。我最近遇到了与此问题相同的用例,我使用Bash实现了一个解决方案,因此我想与大家分享,因为此代码可能对其他人有用 它包括一个脚本
git格式的补丁程序follow
,可在
,可用于OP的问题,如下所示:
( cd "$SOURCE_REPOSITORY_DIRECTORY" && git format-patch-follow -B -M --stdout --root --follow -- "$SOURCE_FILENAME" ) | git am --committer-date-is-author-date
更一般地说,语法是:
git format-patch-follow <options/revisions...> --follow -- <paths...>
git格式修补程序跟随--跟随--
因此,可以将此Bash脚本视为自动运行@OldPro概述的算法的方法,我特别注意处理一些特殊情况,例如带有空格的文件名、在CLI上传递的多个文件,或者从Git源repo的子目录运行脚本
最后,正如所指出的,将这样一个脚本放在一个人的路径中就足够了,Git可以像Git子命令Git格式补丁遵循那样集成脚本
免责声明:git格式补丁
,从而git格式补丁遵循
,进入非线性历史(涉及合并提交)。恶心是对的。我在使用git时已经够辛苦的了,我不可能尝试修补源代码。不过,感谢您深入研究,我希望您能激发一些人来清理这个问题。(旁白)注意:git log--follow
对git 2.9做了一些改进:@VonC:看起来这主要是为了修复git 2.0中引入的一些破损(当父目录和最终文件名都发生更改时)。@torek是的,考虑到git 2.0是从2014年5月开始的,这可能涉及相当多的用户。这是一个非常好的方法。我通常运行命令grep“rename from”/tmp/patches/*
,以验证在格式化修补大量文件时没有忽略任何重命名。如果某些文件是从grepping输出的,而我的命令中没有这些文件,我知道我需要添加它们并重新运行format-patch.interest