如何将一个分支基于另一个已经变基的分支进行变基?

87

我的历史记录如下:

o---o---o---o 主分支 \ o---o---o A分支 \ o B分支

那么,来解释一下:

  • 我有一个从 主分支 开始的分支 A
  • 我有一个从 A 开始的只有一个提交的分支 B

我想要的是这样:

o---o---o---o 主分支 \ o---o---o A分支 \ o B分支


我所做的是:

1).

git checkout A git rebase master

这导致了大量的冲突,花费了很多时间来解决,最终出现了以下历史记录:

o---o---o---o 主分支 \ o---o---o A分支

这正是我想要的。

(我不知道现在的 B 在哪里)


2).

之后我进行了许多合并操作,并改变了 A 中提交的顺序,以获得我想要的历史记录。


3).

现在,我想要做的是:

git checkout B git rebase A

但这似乎不起作用,我不知道为什么。如果我运行 git log 命令,我会看到在第一步之前存在的提交。

此外,我会遇到相同数量的冲突,这些冲突已经在第一步中解决了。我花费了大量的时间来解决它,不想再重复一遍。

这个例子 建议使用 --onto 参数,我也这样做了:

git checkout B git rebase --onto A HEAD~1 B

git rebase --onto A的含义是将当前分支从某个特定的提交开始重新定义,并将其应用于另一个基础。但是这样做会完全删除提交B并使A和B指向相同的提交,即A上的最后一个提交。
我的问题是:如何有效地将B重新定义为基于A开始,就像在最初一样?我的猜测是我错误地使用了--onto选项。或者我应该使用类似cherry-pick的其他选项。
3个回答

107

如何有效将B重新基于A进行重定位,以使得B看起来像从A开始?

假设您想移动仅一个提交:
git rebase --onto A B~ B

如果你想移动多个提交,请使用:

git rebase --onto A old_A B

其余的回答。

你的B分支仍然存在(可以检查一下),但它的父提交仍然是之前的提交对象A。
要查看此图形表示,我使用:

git log --graph --decorate --all

查看所有分支及其相对位置。

o---o---o---o  master
     \
      o---o---o  A
               \
                o B

你现在拥有的东西:

o---o---o-----------o  master
     \               \
      o---o---o(B~)   o---o---o A
               \
                o B

在使用--onto时,你需要有一个起始点和一个终点。

git rebase --onto [target] [rebasing stops] [rebasing head]
git rebase --onto A B~ B

你会得到什么:

o---o---o----------o  master
     \              \
      o---o---o      o---o---o A
            (old_A)           \
                               o B

[branch_name]~ 表示该分支的父提交。

B~ 是您不希望更改的分支。(恰好是旧的 A)

或者,如果B是唯一一个将A作为父提交的提交(即,B是从主分支分支出的一系列提交的结尾),则可以这样做:

git checkout B
git rebase master
git checkout B~   # this is the commit before B (the A commit)
git branch -d A   # remove the old A branch (it was rebased, and so is now invalid
git branch A      # recreate the A branch on the commit that is based on the original A

2
谢谢。git rebase --onto A B~ B 完美地工作了。现在我只需要弄清楚为什么 :) :D - Radu Murzea
23
注意对于那些盲目复制粘贴的人(就像我一样):第二个参数需要指向“旧A”,所以B~只有在B只有一个提交时才起作用——在这里,它确实只有一个提交。我喜欢把语法看作是git rebase --onto <new base> <old base> <head><old base>表示<head>当前分支的位置,<new base>则是你希望它分支出的位置。 - Sam

32
我能够协助您进行文本翻译。以下是需要翻译的内容:

我遇到了与我的git工作流相同的问题,并找到了最好且最快的解决方法。

(1) 项目历史记录:

    master ---A---B---C
                \
                 D---E---F feature1
                          \
                           G---H feature2

(2) 将 feature1 变基到 master 并强制推送:

    master ---A---B------------------------C
                \                           \
                 D---E---F feature1(old)     D---E---F feature1
                          \
                           G---H feature2

(3) 把 feature2 变基到 feature1 (新的那个)

    master ---A---B------------------------C
                                            \
                                             D---E---F feature1
                                                      \
                                                       G---H feature2

最困惑的部分是如何执行{{(3)}},但没有人清楚地知道如何做。
我相信许多人遇到了与我相同的问题,在尝试执行“rebase --onto”时,我们发现{{feature1(old)}}实际上不存在!
    git rebase --onto feature1 feature1(old) feature2

解决方案是使用以下内容:
    git rebase --onto feature1 feature1@{1} feature2

语法feature1@{1}表示“rebase之前feature1的最后已知状态”,答案引自https://coderwall.com/p/xzsr9g/rebasing-dependent-branches-with-git

嗯,有趣,我会更深入地研究这部分,谢谢。 - Radu Murzea

2
如果你已经将A变基成功,那么B应该恰好在你离开时的位置。指向A的分支(指针)只是移动到了它的新位置。
我建议有效地将B重新基于A,就像你建议的那样,使用“cherry-pick”。这个命令尝试将提交中所做的更改应用到你运行的分支上。
所以,如果B最初指向的提交ID是'123456',那么我建议将当前的'B'移动到与新的'A'相同的位置,使用git branch -f B A,然后运行git cherry-pick 123456,将更改应用到A上。
我认为--onto标志用于设置要应用提交的目标位置。默认值为“upstream”(来源:http://git-scm.com/docs/git-rebase)。
我喜欢把rebase命令看作是这样的:
git rebase --onto <Starting here> <Apply all commits from HERE> <TO HERE>

使用这种方法,重新将B基于master进行变基,然后将A指向B之前的提交可能会更简单。
git rebase master B

(由于起始点(--onto)隐含为'master')

然后使用git branch -f A B^(^表示'父级')


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接