41.4.2 提交替换
提交替换是在1.6.5或更新版本的Git中提供的功能,和提交嫁接类似,不过提交替换不是用一个提交来伪装成另外一个提交的父提交,而是直接替换另外的提交,在不影响其他提交的基础上实现对历史提交的修改。
提交替换是通过在特殊命名空间.git/refs/replace/下定义引用来实现的。引用的名称是要被替换掉的提交SHA1哈希值,而引用文件的内容(引用所指向的提交)就是用于替换的(正确的)提交SHA1哈希值。由于提交替换通过引用进行定义,因此可以在不同的版本库之间传递,而不像提交嫁接只能在本地版本库中使用。
Git提供git replace命令来管理提交替换,用法如下:
用法1:git replace[-f]<object><replacement>
用法2:git replace-d<object>…
用法3:git replace-l[<pattern>]
其中:
用法1用于创建提交替换,即在.git/refs/replace目录下创建名为<object>的引用,其内容为<replacement>。如果使用-f参数,还允许级联替换,即用于替换的提交可以是另外一个已经在.git/refs/replace中定义的替换。
用法2用于删除已经定义的替换。
用法3显示已经存在的提交替换。
提交替换可以被大部分Git命令理解,除了一些针对被替换的提交使用—no-replace-objects参数的命令。例如:
当提交foo被提交bar替换后,显示未被替换前的foo提交:
$git—no-replace-objects cat-file commit foo
…foo的内容…
不使用—no-replace-objects参数,则访问foo会显示替换后的bar提交:
$git cat-file commit foo
…bar的内容…
提交替换使用引用进行定义,因此可以通过git fetch和git push在版本库之间传递。但因为默认Git只同步里程碑和分支,因此需要在命令中显式地给出提交替换的引用表达式,如:
$git fetch origin refs/replace/*
$git push origin refs/replace/*
提交替换也可以实现两个分支的嫁接。例如要将分支A嫁接到B上,就相当于将分支A的根提交<BRANCH_A_ROOT>的父提交设置为分支B的最新提交<BRANCH_B_CURRENT>。可以先创建一个新提交<BRANCH_A_NEW_ROOT>,其父提交设置为<BRANCH_B_CURRENT>而提交的其他字段和<BRANCH_A_ROOT>完全一致。然后设置提交替换,用<BRANCH_A_NEW_ROOT>替换<BRANCH_A_ROOT>即可。
可以使用下面的命令创建<BRANCH_A_NEW_ROOT>,注意要用实际值替换下面命令中的<BRANCH_A_ROOT>和<BRANCH_B_CURRENT>。
$git cat-file commit<BRANCH_A_ROOT>|
sed-e "/^tree/a\