用Git记录文件复制操作

Posted

技术标签:

【中文标题】用Git记录文件复制操作【英文标题】:Record file copy operation with Git 【发布时间】:2010-11-05 19:34:47 【问题描述】:

当我使用 git-mv 在 git 中移动文件时,状态显示文件已被重命名,即使我更改了某些部分,它仍然认为几乎是同一件事(这很好,因为它让我可以跟踪历史其中)。

当我复制一个文件时,原始文件有一些我想与新副本关联的历史记录。

我已尝试移动文件,然后尝试在原始位置重新签出 - 一旦移动 git 将不会让我签出原始位置。

我尝试过复制文件系统,然后添加文件 - git 将其列为新文件。

有没有办法让 git 记录文件复制操作,就像它记录文件重命名/移动的方式一样,历史可以追溯到原始文件?

【问题讨论】:

您应该考虑接受罗伯特的回答。效果很好。 【参考方案1】:

Git 不进行重命名跟踪或复制跟踪,这意味着它不记录重命名或复制。它所做的是重命名并复制 detection。您可以使用-M 选项请求git diff(和git show)中的重命名检测,您可以使用-C 选项请求更改文件中的额外副本检测,并且您可以请求更昂贵的副本检测所有带有-C -C 的文件。请参阅 git-diff 联机帮助页。

-C -C 隐含-C-C 隐含-M

-M--find-renames 的缩写,-C 表示--find-copies-C -C 也可以拼写为--find-copies-harder

您还可以通过将diff.renames 设置为布尔真值(例如true1)将git 配置为始终进行重命名检测,并且您也可以通过将其设置为@987654341 来请求git 进行复制检测@ 或 copies。请参阅 git-config 联机帮助页。

还要检查git diff-l 选项和相关的配置变量diff.renameLimit


请注意 git log <pathspec> 在 Git 中的工作方式不同:这里 <pathspec> 是一组路径分隔符,其中路径可以是(子)目录名称。它过滤和简化历史之前重命名和复制检测发挥作用。如果您想关注重命名和复制,请使用git log --follow <filename>(目前有点受限,仅适用于单个文件)。

【讨论】:

@allyourcode:你对什么感到困惑?要默认打开复制检测,请将​​ diff.renames 设置为 copies(例如“git config diff.renames copies”)。我同意这有点违反直觉。 我似乎无法解析的一个部分是“默认情况下您也可以请求重命名检测”。你是说 diff.renames 可以使用四个值(true、1、copy、copys),并且它们都做同样的事情? @allyourcode:对不起,我没有注意到这一点。现已修复,谢谢。 @peschü:Git 使用内容寻址对象数据库作为存储库存储。文件内容存储在地址下的“blob”内容中,该地址是内容的 SHA-1 哈希(嗯,类型+长度+内容)。这意味着给定的内容只存储一次。 NB。这种自动重复数据删除是使用 git pack 格式创建“bup”备份系统的原因。 与下面的解决方案不同,这不适用于范围内的更改跟踪。 Git 日志允许范围参数 (git log -L123,456:file.xyz) 正确地跟随重命名,但不是副本,在这种情况下你不能传递 --follow ;另外,AFAICT,这不适用于 git blame。【参考方案2】:

如果由于某种原因您无法像 Jakub Narębski 的回答那样打开 复制检测,您可以 强制 Git 在三个提交中检测复制文件的历史记录:

不要复制,而是切换到新分支并将文件移动到那里的新位置。 在那里重新添加原始文件。 使用无快进选项 --no-ff 将新分支合并到原始分支。

感谢Raymond Chen。接下来是他的程序。假设文件名为orig,并且您希望将副本命名为apple

git checkout -b dup # create and switch to branch

git mv orig apple # make the duplicate
git commit -m "duplicate orig to apple"

git checkout HEAD~ orig # bring back the original
git commit -m "restore orig"

git checkout - # switch back to source branch
git merge --no-ff dup # merge dup into source branch

2020-05-19:上述方案的优点是不改变原始文件的日志,不产生合并冲突,并且更短。前一个解决方案有四个提交:

不要复制,而是切换到新分支并将文件移动到那里的新位置。 切换到原始分支并重命名文件。 将新分支合并到原始分支中,通过保留两个文件来解决琐碎的冲突。 在单独的提交中恢复原始文件名。

(取自https://***.com/a/44036771/1389680.的解决方案)

【讨论】:

简单,简洁,100%...这个答案是公共服务...支持所有可见的东西 moverename有什么区别? 我尝试按照这个(新)食谱进行操作,但没有成功。如果您显示实际命令可能会有所帮助。 @RobertPollak 我尝试了各种版本,但都没有成功。 “移动文件”是指git mv orig new? “阅读原文”是指cp new orig && git add orig 您必须创建一个分支,在那里提交,然后将其合并回来的想法......而最重要的评论是“简单和简洁”......令人难以置信。在 Mercurial 中,您只需执行 hg cp(或 hg cp -A,如果您已经自己复制了它)。 git 赢得了 VCS 人气竞赛,真可惜。

以上是关于用Git记录文件复制操作的主要内容,如果未能解决你的问题,请参考以下文章

如何 git 将文件夹和文件移动到新文件夹并保留历史记录? [复制]

上传文件到git

C#怎监控例似WORD这样用临时文档记录修改过的文件,并复制修改后的文件?

怎么复制文件到另一个文件夹上?

git 创建分支会把复制所有代码吗

如何 Git 取消暂存所有暂存文件? [复制]