是否可以在不更改当前提交中的文件的情况下修改父提交?

时间:2018-06-27 20:47:35

标签: git rebase git-rebase

在某些情况下,为了代码检查或更清晰的版本历史记录,我想将现有提交分成两部分。但是,在拆分提交时,您会发现某些不一致之处出现,或者您必须修改新的父提交来维护构建。但是,我往往不得不做很多手工工作来跟踪/维护我编写的最终代码。

是否可以在不修改最终提交的树形哈希的情况下运行变基。

示例我们有3个提交,分别为ABC: 这是提交A

# test_file.py
# this is commit A
does_stuff()

这是一个新的提交B

# test_file.py
# this is commit B
does_stuff()

这是一个新的提交C

# test_file.py
# this is commit C
does_stuff()

原始树的样子

... -- C -- A

但是我们想将A“拆分”为两个提交

... -- C -- B -- A

当我们使用交互式资源库创建B时,A的注释也将被更新以显示# this is commit B(假设除了该文件以外,还有其他一些更改)。但是,我们希望保持原样。注意:A由于具有不同的父对象而具有不同的整体哈希值,但是其树哈希值应与以前相同。

1 个答案:

答案 0 :(得分:3)

不可能修改任何提交。相反,您将一些现有的提交集复制到新的提交集。这实际上是个好消息,因为这意味着原始提交仍然可用

  

当我们使用交互式资源库创建B时,A的注释也将被更新以显示# this is commit B(假设除了该文件以外,还有其他一些更改)。

在您显示的特定示例中,它不应:您应该遇到合并冲突。

对于其他案例,您当然是正确的。

  

但是,我们希望保持注释不变。注意:A由于具有不同的父对象而具有不同的整体哈希值,但是其树哈希值应与以前相同。

请记住,您从开始:

... -- C -- A

我将其绘制为:

...--C--A   <-- branchname (HEAD)

表示某些名为branchname的现有分支指向提交C,并且HEAD附加到A

然后您运行了git rebase -i <hash-of-C>或类似名称。这为您提供了要做的事情的清单,您可以选择“编辑” A。现在Git:

  • 将HEAD分离到变基目标:

           A   <-- branchname
          /
    ...--C   <-- HEAD
    
  • 复制提交A(在这种情况下,使用完全相同的副本/快进,以便它重新使用A本身;如果您喜欢{{ 1}},尽管最终没有什么区别:

    --no-ff

    或:

           A   <-- HEAD, branchname
          /
    ...--C
    

    (使用 A <-- branchname / ...--C--A' <-- HEAD 强制复制)。

这时,您将进行一些更改并运行--no-ffgit add以将当前的提交移开,并使git commit --amend指向新的提交HEAD ,其父为B。假设您没有使用C;结果是:

--no-ff

((如果您确实使用过 A <-- branchname / ...--C--B <-- HEAD ,还会有另外--no-ff个没有名字的视频群聊;它将在大约一个月内被垃圾回收。然后,我们必须调用下一个副本{ {1}}来区分它们,所以假设您没有使用A'。)

现在,您要从提交A"获取文件,并从提交--no-ff获取提交消息,然后进行新的提交。由于A仍指向原始提交A,因此只需执行以下操作:

branchname

现在您拥有:

A

此时,您使用$ git checkout branchname -- . # assumes you're at the top level of your repo $ git commit -C branchname # or -c if you want to edit it again 完成了重新配置。由于没有要复制的提交,就涉及rebase而言,您已经完成了对最后一个提交 A <-- branchname / ...--C--B--A' <-- HEAD 的复制,因此,完成了rebase的最后一步,即从原始提交中删除分支名称。链并移动它以指向与git rebase --continue相同的提交,同时重新附加A

HEAD

作为副作用,rebase会将HEAD设置为记住 A <-- ORIG_HEAD / ...--C--B--A' <-- branchname (HEAD) 所指向的位置,因此很容易确保一切正常工作,并且最终处于所需的状态:

ORIG_HEAD

,如果错了,您可以branchname,结果是:

git diff ORIG_HEAD HEAD

请注意,其他命令(包括git reset --hard ORIG_HEAD)设置了 A <-- branchname (HEAD) / ...--C--B--A' <-- ORIG_HEAD (这就是它们在此处交换的原因)。最终,除了reflog条目外,这两个提交之一将被完全放弃,并且当这些到期时,无法访问的提交将真正消失。这种提交的默认到期时间是30天。