Git rebase 基础知识

我已经开始使用 git rebase最近,并不是100% 确定我做的正确。为了回答这个问题,有两个分支,masternext,它们是从 master分支出来的。

自从上次两者之间的同步以来,master有2次提交,而 next有6次:

$ git log --oneline origin/next..origin/master
59b5552 master commit #2
485a811 master commit #1


$ git log --oneline origin/master..origin/next
4ebf401 next commit #6
e9b6586 next commit #5
197ada0 next commit #4
4a2c3c6 next commit #3
040a055 next commit #2
84537bf next commit #1

当我签出 next并执行 git rebase -i origin/master时,我得到以下结果:

$ git status
# On branch next
# Your branch and 'origin/next' have diverged,
# and have 8 and 6 different commits each, respectively.

最后,在执行 git pull --rebase之后,来自 master的两次提交在 next中:

$ git log --oneline origin/next..next
8741d09 master commit #2
485a811 master commit #1

问题:

  1. 这是正确的方法吗?
  2. 为什么在运行 pull --rebase之前有不同的 8 and 6提交?
  3. 有可能简化流程吗?

非常感谢

74696 次浏览

让我们从头开始,这是你的原始状态图:

A-B-C  (master, origin/master)
\
D-E-F-G-H-I  (next, origin/next)

当您签出 next并将 next重新基于 origin/master时,它在 origin/master上已有的两次提交之后又创建了6次新提交。这些新的提交有“ master commit # 2”(我的图中是 C)作为它们的祖先,而不是它们原来的祖先,在那里 origin/masterorigin/next发生了分歧(我的图中是 A) ,所以它们的散列将会不同。我相信这就是为什么您将看到 nextorigin/next有8次不同的提交: origin/master的2次提交和 origin/next上的6次“重新散列”提交。

git checkout next ; git rebase -i origin/master之后,你应该有这个:

A-B-C  (master, origin/master)
\   \
\   D'-E'-F'-G'-H'-I' (next)
\
D-E-F-G-H-I  (origin/next)

您可以看到,next确实有8次不在 origin/next上的提交,而 origin/next确实有6次不在 next上的提交。假定这只是根据提交的 SHA-1哈希表。如果您使用的是 git diff origin/next next,那么实际的内容应该非常接近——差异应该只显示来自 BC的更改(如图中标记的那样)。

当您在 next上执行 git pull --rebase时,它将从源(远程 origin/next)获取更改,并将当前分支(next)重新基于该远程。这导致 next中的变化,而 origin/next中的 没有origin/next之后出现在新的 next分支上。它应该是这样的:

A-B-C  (master, origin/master)
\
D-E-F-G-H-I  (origin/next)
\
B'-C' (next)

如果这就是您想要的历史图表,那么您已经成功了。

但是,我怀疑您真的希望事情看起来像中间的图,特别是如果 next是一个功能分支,您正在处理项目的下一部分,而 master是用于稳定的代码和小的 bug 修复。如果是这样,那么您应该使用 git push而不是 git pull --rebase来使远程反映您的历史版本,而不是反过来。

从非常简单的步骤开始,重新定位你的分支与主人; 姓名;

git-rebase

提要;

git rebase [-i | --interactive] [options] [--exec <cmd>] [--onto <newbase>]
[<upstream>] [<branch>]
git rebase [-i | --interactive] [options] [--exec <cmd>] [--onto <newbase>]
--root [<branch>]
git rebase --continue | --skip | --abort | --edit-todo

描述; 假设存在以下历史记录,当前分支是“ sample”:

 A---B---C sample
/
D---E---F---G master

从这里开始,下列任一命令的结果:

git rebase master
git rebase master sample

就是:

A'--B'--C' sample
/
D---E---F---G master

注意 : 后一种形式只是 git checkout samplegit rebase master的简写。当 rebase 出口 sample 将保留签出分支。

如果上游分支已经包含您所做的更改(例如,因为您邮寄了一个应用于上游的补丁) ,那么该提交将被跳过。例如,在以下历史记录上运行‘ git rebase master’(其中 A 和 A 引入了相同的更改集,但提交者信息不同) :

A---B---C sample
/
D---E---A'---F master

会导致:

 B'---C' sample
/
D---E---A'---F master

所有这些都是对 rebase 过程的图解理解。 一旦您解决了键入 git rebase master后发现的冲突 解决冲突并键入 git add -u将更改后的代码添加到存储库中。 之后执行命令 git rebase --continue并继续解决冲突和重复命令;

git add -u

还有

git rebase --continue

直到没有发现冲突。 最后的命令是,

git push --force origin sample(your branch name)

我并不总是使用 git rebase,但是当我这样做时,我使用这个“ 锤子”:

o---o---o---o---o  A
\
o---o---o---o---o  B
\
o---o---o  C


git rebase -r B C --onto A    # C should be branch, not hash


o---o---o---o---o  A
|            \
|             o'--o'--o'  C
\
o---o---o---o---o  B

不必再强调对每种情况下进行 git rebase 的最佳方法是什么(“我应该使用 rebase -i吗?我应该使用 cherry-pick吗?”)然后花时间查找它们。

当然,这并不适用于每个人,例如,在我们想要分割提交的情况下,有些人不喜欢 “在一家新分店做一些奇怪的工作”。但是有些人,像我,“对互动方式有恐惧症”

不要害怕一次做1000种变基方法的人,而是害怕一次做1000种变基方法的人。不是李