基于「=10=」

Rebase onto Rebase/Squash

这是我遇到的常见情况,我正在寻找一个干净的解决方案。

  1. 在 git 分支上做一些工作 (my-first-work)
  2. 推送到 github
  3. 在工作my-first-work
  4. 的基础上开始一个新的分支(some-further-work

未指定的时间量

  1. 批准者将 my-first-work 变基或压缩到 master
  2. 这会创建新的提交,git 不会将其视为等同于我所基于的内容,即使最终结果相同(即 master 的头部与my-first-work)
  3. 的头
  4. 我 运行 git rebase mastersome-further-work 移动到 master
  5. 我现在所基于的来自 my-first-work 的提交都与已经发生的冲突 squash/merged

目前,我通过使用 git rebase -i master 然后删除所有提交直到 my-first-work 的头部来解决这个问题。这会在 master.

之上干净地重播额外的提交

是否有更清洁的解决方案?有没有办法让 git 在 rebase/squash(如 4)发生时自动识别?

Cleaner 在旁观者/工人的眼中(或手上?),但您可以使用 git rebase --onto 分离出 哪些提交从 复制 副本 .

记住 git rebase 表示:1 我有一个线性提交链,如图 1 所示,我想将其复制到一个新的线性提交链,如图 2 所示。复制完成后,我希望我的分支名称指向最后复制的提交。原来的A-B-C链即使还在也已经没用了

[drawing 1]
...--o--*--o   <-- upstream/master
         \
          A--B--C   <-- topic

[drawing 2]
...--o--*--o   <-- upstream/master
            \
             A'-B'-C'  <-- topic

原始提交和副本之间的区别在于,原始提交基于提交*之前upstream/master的提示。副本基于 upstream/master 的(新)提示。短语 based on 这里有两个字面意思: parent of commit A 是 commit * 但是 parent of commit A' 是后面的提交,snapshot in commit A*-plus-在 快照 提交 A' 中将 相同的 更改添加到 之后的 提交。

由于我们使用闪亮的新提交 A'(具有不同的哈希值)来支持旧的沉闷 A,因此我们需要将 B 复制到 B'CC',完成后我们需要我们的名字topic不指向C,而是指向最后复制的提交,C'.

普通旧 git rebase 正是这样做的。我们说:

git checkout topic; git rebase upstream/master

这告诉 Git:

  1. 枚举从 C 开始并向后计算的所有提交。C 然后 B 然后 A 然后 * 然后是 *.
  2. 之前的所有内容
  3. 枚举从 upstream/master 开始并向后工作的所有提交。 那是第二个 o,然后是 *,然后是 *.
  4. 第二个列表中的所有内容从第一个列表中敲出。这样就敲了out * 和所有较早的提交。第二个 o 不在第一个列表中,但没关系:如果它 中,我们会把它淘汰,但事实并非如此,所以我们什么都不做。我们的列表现在变为 CBA
  5. 反转列表以将其放入正确的顺序,然后一次一个,将每个提交复制到新位置。新位置从 upstream/master 指向的提交开始。 所以这会将 A 复制到 A'BB',并且 CC'.
  6. 将当前分支名称 topic 从其先前的位置剥离,并像往常一样将其粘贴到新的提交链上。 所以这使得 topic 指向 C' 而不是 C.

不过,在您的新案例中,您有:

...--o--*   <-- upstream/master
         \
          A--B--C   <-- feature1
                 \
                  D--E--F--G   <-- feature2

他们在他们的上游,没有拿走你的 A-B-C 链。相反,他们做出了自己不同的 ABC 壁球提交。您从上游存储库中获取了它,所以您现在拥有:

...--o--*--ABC   <-- upstream/master
         \
          A--B--C   <-- feature1
                 \
                  D--E--F--G   <-- feature2

如果你只是 运行 git checkout feature2; git rebase upstream/master,你的 Git 将枚举提交 G-F-E-D-C-B-A-*-...,枚举 ABC-*-...,从第一个中减去第二个,然后是留下复制 G-F-E-D-C-B-A 链的说明。

更高级的 rebase 命令是:

git checkout feature2
git rebase --onto upstream/master feature1

这样做是将 target 参数(Git 将开始复制的地方)与 limit 分开争论。 target 现在是 upstream/master(Git 文档将其称为 onto 参数)。 限制 参数现在是 feature1。如果您愿意,可以使用提交 C 的原始哈希 ID。 Git 只需要知道:我从哪里开始淘汰这些提交枚举?(令人困惑的是,Git 文档将其称为 上游 参数。)

如您所见,这现在删除了 C-B-A-* 提交,而不仅仅是 * 提交,因此在复制之后,您有:

               D'-E'-F'-G'  [in progress]
              /
...--o--*--ABC   <-- upstream/master
         \
          A--B--C   <-- feature1
                 \
                  D--E--F--G   <-- feature2

现在 Git 可以将标签 feature2 撕下 G 并贴在 G2 上。


1从技术上讲,git rebase 的功能还有很多,尤其是现在新增了 --rebase-merges 选项。这个我有一个线性提交链仍然是它的主要用途,不过

作为一个很好的奖励,rebase 通常可以判断他们是否已经将您的 A-B-C 链复制到他们自己的 A'-B'-C' 链中。但这只是 通常 。 Rebase 可以 永远不会 告诉他们已经拿走了你的 A-B-C 并将其压缩成他们自己的 ABC,所以对于这种情况你只能使用 --onto.