GIT复制文件保存历史
GIT中有一个令人困惑的问题。 比方说,我有一个文件dir1/A.txt
承诺和git保留提交的历史
现在我需要(由于某些原因)将文件复制到dir2/A.txt
(不移动,但复制)。 我知道有一个git mv
命令,但我需要dir2/A.txt
与dir2/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 blame
和git log
时检测它们。
这些信息大部分来自这里的答案: 使用Gitlogging文件复制操作
就我而言,我在硬盘上进行了修改(将工作副本中的一个path上的200个文件夹/文件剪切/粘贴到另一个path中),然后使用SourceTree(2.0.20.1)将检测到的更改(一个添加,一个删除),只要我同时添加和删除,它会自动组合成一个粉红色的R图标(我假设重命名)的单个更改。
我注意到,因为我一次有这么大的变化,SourceTree检测所有的变化有点慢,所以我的一些staged文件看起来只是增加(绿色加)或只是删除(红色减号),但我不断刷新文件状态,并在最终popup时保持新的变化,几分钟后,整个列表变得完美并准备好提交。
我证实历史是存在的,只要当我查找历史时,我检查“按照重命名的文件”选项。