用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
设置为布尔真值(例如true
或1
)将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%...这个答案是公共服务...支持所有可见的东西move
和rename
有什么区别?
我尝试按照这个(新)食谱进行操作,但没有成功。如果您显示实际命令可能会有所帮助。
@RobertPollak 我尝试了各种版本,但都没有成功。 “移动文件”是指git mv orig new
? “阅读原文”是指cp new orig && git add orig
?
您必须创建一个分支,在那里提交,然后将其合并回来的想法......而最重要的评论是“简单和简洁”......令人难以置信。在 Mercurial 中,您只需执行 hg cp
(或 hg cp -A
,如果您已经自己复制了它)。 git 赢得了 VCS 人气竞赛,真可惜。以上是关于用Git记录文件复制操作的主要内容,如果未能解决你的问题,请参考以下文章
如何 git 将文件夹和文件移动到新文件夹并保留历史记录? [复制]