GIT复制文件保存历史

GIT中有一个令人困惑的问题。 比方说,我有一个文件dir1/A.txt承诺和git保留提交的历史

现在我需要(由于某些原因)将文件复制到dir2/A.txt (不移动,但复制)。 我知道有一个git mv命令,但我需要dir2/A.txtdir2/A.txt具有相同的提交历史logging,而dir1/A.txt仍然保留在那里。

创build副本后,我不打算更新A.txt ,并且所有将来的工作都将在dir2/A.txt

我知道这听起来很混乱,我将补充说这种情况是基于Java的模块(mavenized项目),我们需要创build一个新版本的代码,以便我们的客户能够在运行时拥有2个不同的版本,第一个版本将在最后完成alignment时被删除。 当然,我们可以使用maven版本控制,我只是GIT的新手,对git可以在这里提供什么好奇。

与颠覆不同,git没有每个文件的历史logging。 如果您查看提交数据结构,则仅指向此提交的以前提交和新树对象。 提交对象中没有存储明确的信息,哪些文件被提交改变; 也不是这些变化的性质。

检查更改的工具可以基于启发式检测重命名。 例如“git diff”有选项-M打开重命名检测。 所以在重命名的情况下,“git diff”可能会告诉你一个文件已经被删除,另外一个文件被创build,而“git diff -M”将会实际检测到这个移动并相应地显示改变(参见“man git diff”细节)。

所以在git中,这不是你如何提交你的修改的问题,而是你如何看待以后提交的修改。

您只需要将它平行移动到两个不同的位置,合并,然后将一个副本移回到原始位置。 然后你可以在任何副本上运行git blame ,没有特别的select,并且看到两者的最佳历史归因。 你也可以在原版上运行git log并查看完整的历史logging。

详细地说,假设你想将你的仓库中的foo /复制到bar /。 这样做(注意我使用-n提交以避免重写等):

 git mv foo bar git commit -n SAVED=`git rev-parse HEAD` git reset --hard HEAD^ git mv foo foo-magic git commit -n git merge $SAVED # This will generate conflicts git commit -a -n # Trivially resolved like this git mv foo-magic foo git commit -n 

注意:我在Linux上使用git 2.1.4

为什么这个工作

你会得到这样的修订历史logging:

  ORIG_HEAD / \ SAVED ALTERNATE \ / MERGED | RESTORED 

(1)在混合和恢复之间检测到“foo-magic”的重命名,(2)检测到“foo-magic”来自MERGED的ALTERNATE父级, (3)检测ORIG_HEAD和ALTERNATE之间的'foo'重命名。 从那里将深入到“富”的历史。

(1)注意到MERGED和RESTORED之间没有变化,(2)检测到来自MEDED的SAVED父母的'bar',以及(3)检测到从' foo'在ORIG_HEAD和SAVED之间。 从那里将深入到“富”的历史。

就这么简单。 你只需要强制git进入一个合并的情况,你可以接受两个可追踪的文件副本,我们通过平行移动原来的(我们很快恢复)。

为了完整起见,我会补充一点,如果你想复制一个完整的受控和非受控文件的完整目录,你可以使用下面的代码:

 git mv old new git checkout HEAD old 

不受控制的文件将被复制,所以你应该清理它们:

 git clean -fdx new 

只需复制文件,添加并提交它:

 cp dir1/A.txt dir2/A.txt git add dir2/A.txt git commit -m "Duplicated file from dir1/ to dir2/" 

然后下面的命令将显示完整的预复制历史logging:

 git log --follow dir2/A.txt 

要从原始文件中查看inheritance的逐行注释,请使用以下命令:

 git blame -C -C -C dir2/A.txt 

Git不会在提交时跟踪副本,而是在检查历史logging(例如git blamegit log检测它们。

这些信息大部分来自这里的答案: 使用Gitlogging文件复制操作

就我而言,我在硬盘上进行了修改(将工作副本中的一个path上的200个文件夹/文件剪切/粘贴到另一个path中),然后使用SourceTree(2.0.20.1)将检测到的更改(一个添加,一个删除),只要我同时添加和删除,它会自动组合成一个粉红色的R图标(我假设重命名)的单个更改。

我注意到,因为我一次有这么大的变化,SourceTree检测所有的变化有点慢,所以我的一些staged文件看起来只是增加(绿色加)或只是删除(红色减号),但我不断刷新文件状态,并在最终popup时保持新的变化,几分钟后,整个列表变得完美并准备好提交。

我证实历史是存在的,只要当我查找历史时,我检查“按照重命名的文件”选项。