我在Git中有一个有点令人困惑的问题。
假设,我提交了一个文件dir1/ a .txt, git保存了一个提交历史
现在我需要将文件复制到dir2/A.txt(不是移动,而是复制)。
我知道有一个git mv命令,但我需要dir2/ a .txt具有与dir1/ a .txt相同的提交历史,并且dir1/ a .txt仍然保留在那里。
我不打算在创建副本后更新A.txt,所有未来的工作都将在dir2/A.txt上完成
我知道这听起来很混乱,我会补充说,这种情况是基于java的模块(mavenized项目),我们需要创建一个新版本的代码,以便我们的客户能够在运行时有2个不同的版本,第一个版本将最终在对齐时被删除。
当然,我们可以使用maven版本,我只是Git的新手,对Git在这里能提供什么很好奇。
你所要做的就是:
将文件移动到两个不同的位置,
合并执行上述操作的两个提交,和
将一份拷贝移回原来的位置。
您将能够看到两个文件的历史属性(使用git blame)和完整的更改历史(使用git log)。
假设您想要创建一个名为bar的文件foo的副本。在这种情况下,您将使用的工作流看起来像这样:
git mv foo bar
git commit
SAVED=`git rev-parse HEAD`
git reset --hard HEAD^
git mv foo copy
git commit
git merge $SAVED # This will generate conflicts
git commit -a # Trivially resolved like this
git mv copy foo
git commit
为什么会这样
在你执行上面的命令之后,你最终会得到一个修订历史,看起来像这样:
( revision history ) ( files )
ORIG_HEAD foo
/ \ / \
SAVED ALTERNATE bar copy
\ / \ /
MERGED bar,copy
| |
RESTORED bar,foo
当你向Git询问foo的历史时,它会:
在merge和RESTORED之间检测副本的重命名,
检测副本来自merge的ALTERNATE父类,并且
检测foo在ORIG_HEAD和ALTERNATE之间的重命名。
从那里,它将深入到foo的历史。
当你向Git询问酒吧的历史时,它会:
注意到MERGED和RESTORED之间没有变化,
检测bar来自MERGED的SAVED父节点,并且
检测foo在ORIG_HEAD和SAVED之间的重命名。
从那里,它将深入到foo的历史。
就是这么简单。:)
您只需要强制Git进入合并状态,这样您就可以接受文件的两个可跟踪副本,我们通过并行移动原始文件(很快就会恢复)来实现这一点。
简单地复制文件,添加并提交:
cp dir1/A.txt dir2/A.txt
git add dir2/A.txt
git commit -m "Duplicated file from dir1/ to dir2/"
然后,下面的命令将显示完整的预拷贝历史记录:
git log --follow dir2/A.txt
要查看从原始文件继承的逐行注释,请使用以下命令:
git blame -C -C -C dir2/A.txt
Git不会在提交时跟踪副本,而是在检查历史记录时进行检测,例如Git blame和Git log。
大部分信息来自这里的答案:用Git记录文件复制操作