我试图在主人之上改变一个分支,这是我以前做过一千次的事情。但是今天,它没有工作:
> git status
On branch mystuff
Your branch and 'master' have diverged,
and have 6 and 2 different commits each, respectively.
(use "git pull" to merge the remote branch into yours)
nothing to commit, working directory clean
> git rebase
First, rewinding head to replay your work on top of it...
> git status
On branch mystuff
Your branch is up-to-date with 'master'.
Untracked files:
(use "git add <file>..." to include in what will be committed)
[a directory from the project]
nothing added to commit but untracked files present (use "git add" to track)
>
一切都像平常一样开始,但是Git完成了rebase而没有在我那里提交任何提交;我的分支mystuff最终与master相同。
显而易见的结论是,我的提交已经在某处掌握。但我发誓他们不会 。我已经回顾了历史。提交是在其他几个功能分支上,但它们并不在任何地方的主历史中。 (而且我可以告诉他们,当我签出主人的时候,文件的状态还不是主人。)
那么,如果提交已不在我的上游历史记录中,那么为什么git rebase
会拒绝将我的提交堆叠在最顶层?
奇怪的是,如果我一个接一个地将这些提交给主人,那就行了。然后我可以移动我的mystuff分支到最后,然后回到原来的位置。 (但为什么我需要这样做?)
修改:
git rebase
上的文档说明了这一点:
如果提供了
<upstream>
选项,则当前分支将重置为<newbase>
或--onto
。这与git reset --hard <upstream>
(或<newbase>
)具有完全相同的效果。ORIG_HEAD
设置为在重置之前指向分支的顶端。然后,先前保存到临时区域的提交将按顺序逐个重新应用于当前分支。请注意,
HEAD
中引入与HEAD..<upstream>
中的提交相同的文本更改的任何提交都将被省略(即,将跳过已使用不同提交消息或时间戳的上游接受的修补程序)。
这与我看到如果提交实际存在于上游的行为一致......但他们不会这样做。并且如评论中所述,git rebase master
正常工作并应用所有提交。但git rebase
没有master
的情况也没有,即使将master设置为上游分支。
我的分支机构的配置:
[branch "master"]
remote = origin
merge = refs/heads/master
[branch "mystuff"]
remote = .
merge = refs/heads/master
答案 0 :(得分:4)
在某次git升级后,这已经让我至少被咬了十几次。 现在是git rebase
和git rebase master
之间的差异:前者被更改为使用相同的花式“fork-point”机制。回答这个问题有一个详细的解释:
今天我第一次想出了重现它的具体步骤。
我的情景:master
我有4次提交我已经决定现在应该进入topic
分支,加我想重新排序它们。如果我这样做......
创建新的topic
分支,跟踪当前分支(master
)
git checkout -b topic -t
快退master
:
git checkout master
git reset --hard origin/master
对topic
git checkout topic
git status # "Your branch is ahead of 'master' by 4 commits" Good!
git rebase --interactive
...然后交互式rebase屏幕出现了这个不祥的提交列表:
# no-op
呃 - 哦......我保存文件并继续。是的,看起来git再次抛弃了我的工作。 topic
现在指向与master
和origin/master
相同的提交。
所以我猜想是什么触发了这个:
升级git
您在master
分支上执行了类似我的第2步的操作。
在我的伙计们的理解中,fork-point
机制通过reflog搜索并注意到这些提交已从上游分支中删除,并得出结论:使您的主题分支“更新“他们也应该被移除。
解决方案是,而不是:
git rebase
使用以下其中一项:
git rebase --no-fork-point
git rebase master
但我怀疑和我一样,你不会每次都这样做。 (我的意思是,我们设置一个上游分支是有原因的,对吗?)所以你只需要学会识别灾难发生的时间,使用git reflog
和git reset --hard
进行恢复,然后然后< / em>使用上面的命令。
但是,你现在需要小心 - 我认为这是非常危险的。我曾经有一段时间我重新组建了一个大型分支机构,并且一些提交从一开始就默默地消失了,我几天都没注意到!我很乐意挖掘git reflog
进行灾难恢复,但我不确定每个人都是。我想知道git是否已经开始太聪明了。
答案 1 :(得分:0)
运行git branch -vv
以查看上游分支。听起来mystuff
的上游不是你想象的那样。也许您遇到了编辑事故并最终在配置中出现了多个[branch "mystuff"]
条目?
答案 2 :(得分:0)
我本来想自己问这个问题,但当我试着问的时候,找到了答案。
当您需要变基时,您可能会遇到两种情况。考虑以下历史记录:
A---B---C master
协作者 #1 更改提交 C,添加提交 D 并执行 git push -f
:
A---B---C'---D master
合作者 #2 添加提交 E 并执行 git fetch
:
A---B---C'---D origin/master
\
C---E master
您可能会说,“B 是最后一个共同祖先,C 和 C' 不同,我想保留所有更改。”那么您预期的历史记录是:
A---B---C'---D---C"---E" master
另一种思考方式是,“另一个人改变了 C 提交,一定是有原因的,我想要这个新版本的 C 来代替我的。”然后你想到的是:
A---B---C'---D---E" master
这意味着当提交在上游被删除时,当您进行 rebase 时会在本地发生。
当您明确指定上游时选择前一种模式:
$ git rebase origin/master
后者(“--fork-point”模式):
$ git -c pull.rebase=true pull
$ git pull --rebase
$ git rebase
$ git rebase --fork-point origin/master