我在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进入合并状态,这样您就可以接受文件的两个可跟踪副本,我们通过并行移动原始文件(很快就会恢复)来实现这一点。