为什么git rebase会丢弃我的提交?

Rya*_*ndy 8 git git-rebase

我试图在主人之上重新分支一个分支,这是我以前做过的一千次.但今天它没有用:

> 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)

>
Run Code Online (Sandbox Code Playgroud)

一切都像平常一样开始,但是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
Run Code Online (Sandbox Code Playgroud)

Luk*_*ood 5

在某个 git 升级之后,这至少让我咬了十几次。还有就是现在差之间git rebase和git rebase master:前者被更改为使用相同的花哨“叉点”的机械。这个问题有详细的解释:

今天我第一次想出具体的步骤来重现它。

我的场景:我有 4 个提交master,我决定现在应该将它们移到一个topic分支中, 另外我想对它们重新排序。如果我这样做...

  1. 创建一个新topic分支,跟踪当前分支 ( master)

    git checkout -b topic -t
    
    Run Code Online (Sandbox Code Playgroud)
  2. 倒带master:

    git checkout master
    git reset --hard origin/master
    
    Run Code Online (Sandbox Code Playgroud)
  3. 重新排序提交 topic

    git checkout topic
    git status  # "Your branch is ahead of 'master' by 4 commits" Good!
    git rebase --interactive
    
    Run Code Online (Sandbox Code Playgroud)

...然后交互式 rebase 屏幕出现了这个不祥的提交列表:

    # no-op
Run Code Online (Sandbox Code Playgroud)

呃-哦...我保存文件并继续。是的,看起来 git 又扔掉了我的工作。topic现在指向与masterand相同的提交origin/master。

所以我认为是什么触发了你:

  1. 升级git

  2. 你在你的master分支上做了类似我第 2 步的事情。

在我的外行人的理解中,fork-point机器通过 reflog 进行搜索并注意到这些提交已从上游分支中删除,并得出结论,为了使您的主题分支“最新”,它们也应该在那里删除。

解决方案是,而不是:

git rebase
Run Code Online (Sandbox Code Playgroud)

使用以下之一:

git rebase --no-fork-point
git rebase master
Run Code Online (Sandbox Code Playgroud)

但我怀疑你不会像我一样每次都这样做。(我的意思是,我们设置一个上游分支是有原因的,对吗?)所以你只需学会识别灾难何时发生,使用git reflog和git reset --hard恢复,然后使用上面的命令。

不过,你现在需要小心——我认为这是非常危险的。我曾经有过重新建立一个大分支的时候,一些提交从一开始就默默地消失了,而且我好几天都没有注意到!我很乐意通过挖矿git reflog来进行灾难恢复,但我不确定每个人都是这样。我想知道 git 是否已经开始变得太聪明了。

  • 啊哈!是的,这就是*问题。它可能会从“注意到提交已从那里*删除*”重新表征为“注意到提交之前与上游*共享*,然后*假设*它们在那里被替换为“改进的副本”” . 没有自动的 `--no-fork-point` 选项,但您可以添加一个:查看 rebase 脚本,大约在第 454 行,使用 `test "$fork_point" = auto &amp;&amp; fork_point=t`。替换为“如果设置为自动,请检查最终值的配置”。 (3认同)