【问题标题】:git pull --rebase leads to unexpected graphgit pull --rebase 导致意外的图表
【发布时间】:2015-04-14 15:26:39
【问题描述】:

我在一个分支上工作,foo。我没有未分级的更改,没有工作更改,完全干净的状态,根据我的盒子,HEAD == foo == origin/foo

$ git status
# On branch foo
# Untracked files:
#   (use "git add <file>..." to include in what will be committed)
#
#   some_irrelevant_file_here

$ git log --pretty=...
* 456520c 2015-02-13 (HEAD, origin/foo, foo) Commit A
* 23bfcd1 2015-02-11 Commit B
* b0bdd18 2015-02-12 Commit C

然后我被要求查看同事推动的一些更改,所以我这样做了:

$ git pull --rebase origin foo
remote: Counting objects: 47, done.
remote: Compressing objects: 100% (34/34), done.
remote: Total 36 (delta 22), reused 0 (delta 0)
Unpacking objects: 100% (36/36), done.
From ...
 * branch            foo       -> FETCH_HEAD
First, rewinding head to replay your work on top of it...
Fast-forwarded foo to 43dad88c737762e0f1e84fdcd135155080bdce2a.

此时,我的图表如下所示:

$ git log --pretty=...
* 43dad88 2015-02-13 (HEAD, foo) Commit D
* 40039f9 2015-02-13 Commit E
* 456520c 2015-02-13 (origin/foo) Commit A
* 23bfcd1 2015-02-11 Commit B
* b0bdd18 2015-02-12 Commit C

为什么我的本地foo 看起来比origin/foo 领先? DE 都不是我的提交,我只是从 origin 中提取了这两个 - 我希望此时仍然有 HEAD == foo == origin/foo

【问题讨论】:

  • “根据我的盒子”。你的盒子可能已经过时了。如果你先运行git fetch origin foo 会发生什么?
  • @jurgemaister pull --rebase 隐式地进行提取。
  • @CodyStott 我们正在查看提交历史记录,而不是差异预览 - 我们已经通过了那个阶段。有一个git pull --rebase origin foo,所以实际上是一个git fetch origin foo 和一个git rebase origin/foo。提取已经发生。
  • @RobertBain 我知道git pull 做了什么。然而,我的评论是基于这样一个事实,即原始问题提到他“知道”他的本地人甚至在他提到做git pull 之前使用远程之前。只要考虑一下他所说的顺序。
  • @CodyStott 在我看来这不是他所说的。我认为他是说他做了一个git pull --rebase origin foo,这与git fetch origin foogit rebase origin/foo 相同。我很乐意在讨论中进一步讨论这个问题,或者也许只是让其他人提出他们的想法。

标签: git git-rebase


【解决方案1】:

pull --rebase 之前的情况是:

x--x--x (foo, HEAD, origin/foo)
       \
        y--y (actual origin/foo)

当您 pull --rebase 时,您要求在 origin/foo 之上重播本地提交:
fooorigin/foo 处重置/签出(在 FETCH_HEAD 中获取),并且由于您的提交 'x' 已经是新更新的FETCH_HEAD 的一部分,foo 只是快进:

x--x--x--y--y (foo, HEAD, FETCH_HEAD)
      |
 (origin/foo)

origin/foo没有改变的事实是 git older than 1.8.4 的典型特征(例如在 Ubuntu Precise 12.04 中找到,它与旧的 git-core 1.7.9.5 一起提供)

一个简单的git fetch 应该足以更新origin/foo,而不仅仅是FETCH_HEAD

更新的 git (1.8.4+) 将同时更新 FETCH_HEADorigin/foo,从而使额外的 git fetch 变得多余。


注意:使用 Git 2.12(2017 年第一季度),这种情况(pull --rebase)将是一个简单的快进合并。

commit 33b842a(2016 年 6 月 29 日)Junio C Hamano (gitster)(2016 年 12 月 19 日由 Junio C Hamano -- gitster --commit 2fb11ec 中合并)

pull:快进“pull --rebase=true

"git pull --rebase" 总是运行 "git rebase" 在获取 承诺作为新基地,即使新基地是 当前 HEAD 的后代,即我们还没有做任何工作。

在这种情况下,我们可以改为快进到新基地,而无需 调用变基进程

【讨论】:

    【解决方案2】:

    因为它没有被推送到 repo,这是一种正常的行为。为什么你可以在 origin 之前进行本地提交?他们将永远处于领先地位。

    【讨论】:

      【解决方案3】:

      为什么我的本地 foo 看起来在 origin/foo 之前?

      fooremote/foo 之前是预期的,因为rebase plays back your current branch on top of the upstream branch。您将foo 重新定位在remote/foo 之上,因此foo 应该在remote/foo 之前。

      HEAD == foo == origin/foo 根据我的盒子。

      因此,提交的顺序也符合预期。以下是分支在变基或合并之前的外观,其中A 是远程的实际状态,C 是远程的陈旧表示。

      D <------C (HEAD, foo, remote/foo) <------B <------A (remote/foo)
      

      您正在执行相当于“快进”变基的操作。 IE。它对提交没有任何作用; remote/foo 上没有可播放的内容!结果应该只改变参考位置:

      D <------C <------B <------A (HEAD, foo, remote/foo)
      

      为什么我的本地 foo 看起来在 origin/foo 之前?

      这是我无法回答的问题。在 rebase 之后,我再次期望 HEAD == foo == remote/foo 但事实并非如此。为什么在foo 变基到remote/foo 之后,后者似乎落后了?

      【讨论】:

      • 是的,这既是我所期望的,也是我的问题。
      • @Barry 当我们需要他时,Linus 在哪里?
      • 这看起来很奇怪,以至于我倾向于认为出了点问题,并且以某种方式本地 repo 已损坏。我毫不怀疑这个问题的目的是消除任何可能的误解,但鉴于任何体面的答案,我很想将 HEAD HEAD~1 差异化到文件中,修补,推送并希望它不会发生再次。
      • @RobertBain 不,它只是一个旧 git(1.8.4 之前):见 my answer above
      • @VonC,多么微妙的一个,很好的捕捉。我可以假设您以前遇到过同样的问题吗?
      猜你喜欢
      • 1970-01-01
      • 2021-11-17
      • 2017-12-07
      • 1970-01-01
      • 2021-08-16
      • 1970-01-01
      • 2013-03-14
      • 2014-02-17
      • 2012-06-10
      相关资源
      最近更新 更多