使用BitBucket进行Git Rebase

3
我遇到了一个问题,让我很困惑。我的分支中有一些代码与主分支(在我这个案例中是develop)冲突。这不是什么大问题,因为只有7行代码很容易识别。
BitBucket友好地告诉我,为了解决合并冲突,我需要执行以下步骤:
- git checkout <branch in question> - git pull <master>(在我这个案例中是develop) - 解决冲突 - 此时命令行还提供了以下指导: - "手动解决所有冲突,并使用"git add/rm <conflicted_files>"将其标记为已解决,然后运行"git rebase --continue"。" - 运行"git rebase --continue"后,会出现一个新文档,可以更改原始提交消息。我只需关闭它,合并就会继续进行。 - git commit - git的结果是"Successfully rebased and updated <current branch>" - git push origin HEAD - 我期望收到一条成功的消息,说明一切都正常工作,但我一直收到这条消息: - On branch <current branch> - Your branch and '<current branch>' have diverged, and have 4 and 3 different commits each, respectively. - (use "git pull" to merge the remote branch into yours) - 没问题,让我们运行git pull...然后我们不得不重新开始,就好像我从未解决过合并冲突一样。
我读到了其他类似问题的评论,发现有人使用-f标志(强制)推送代码。我尝试了一下,当然可以工作,但我的7行更改变成了多个文件更改。合并冲突已经消失,但我担心在主分支(develop)中添加不必要的提交。

1
我认为,考虑到你已经进行了变基(而不是合并),历史记录已经分叉(出于变基的目的),所以错误是可以预料的。我希望你能够强制推送到“特性分支”中,用新的历史记录替换旧的历史记录(顺便说一下,在你的推送命令中,我不会期望它只使用“HEAD”就能正常工作。这是否被Git翻译为“将我本地检出的分支推送到同名的远程分支”?) - eftshift0
1
另外一点,git commit 是什么意思呢?在 rebase 过程中并不会使用它,除非你在做一些非常规的操作。 - eftshift0
1
@eftshift0: Helmut Granda在rebase过程中可能遇到了一些合并冲突;很可能他们将pull.rebase配置为true,以便所有的pull都运行git rebase,即使那些本应该运行git merge的也是如此... - torek
1
我弄清楚了这是一个变基操作……只是我似乎不明白为什么会涉及到提交(commit)。如果你在交互式变基中设置了reword,它就会被用到,但这并不是这种情况。所以,鉴于这是出乎意料的……这就是我问的原因。 - eftshift0
@eftshift0,老实说,我对于“git commit”的指令感到困惑,但这正是Bitbucket GUI告诉我要做的。请按照我上面突出显示的4个步骤进行操作。过去,我曾使用“git merge”来解决合并冲突,但我们团队要求使用“git rebase”,这对我来说是新的,所以我正在努力学习如何正确解决这种问题,而这已经是我第三次遇到这种情况了。前两次我创建了一个新分支并重新添加了我的代码,这一次我决定,不行了!我需要学会如何解决这个问题 :)。 - Helmut Granda
1
没问题。重新定位可能需要一点时间来弄清楚它的工作原理...一旦你掌握了它,你会惊讶地发现自己在没有它的情况下是如何生活这么久的。 - eftshift0
1个回答

6
TL;DR: 你需要运行 git push --force-with-lease origin HEAD 命令。
你遇到这个问题是因为你正在使用 rebase。(这里 Bitbucket 不相关,我删掉了那个标签。)
rebase 操作,本质上是一个 Git 命令:
  • 我有一些旧的提交。它们...还算过得去,但不够好。
  • 请删除旧提交,创建一些新的、改进后的替换提交,代替旧的提交。
完成后,旧的提交就被删除了(大概),你现在正在使用新的和改进后的替换提交。
当你运行 git push origin HEAD 命令时,你的 Git 会将你的名称 HEAD 解析为当前分支名称(无论该名称是什么),然后像运行 git push origin branch 一样操作。这让你的 Git 调用他们的 Git,在 origin 处发送你的新提交,然后礼貌地请求:如果可以的话,请将它们的分支名称设置为与你的分支名称相同的最后一个提交。
由于你使用了 rebase,这个“请设置分支名称 ______(填写名称)为 _______(填写哈希 ID)”等同于对他们的 Git 发出指令:“使用这些相同的替换提交,丢弃我丢弃的相同旧提交”。但此时他们不知道你的新替换提交是替换提交。他们已经完全忘记了之前告诉你的任何东西。他们只看到你要求他们“丢弃一些提交”。因此,他们会说“No!如果这样做,我会丢失一些提交。”
为了克服他们抛弃提交的不愿意,你必须发送一个更加强制性的命令,而不是礼貌的请求。你必须告诉他们:“是的,我知道这可能会丢弃一些提交,但还是这样做吧!”为了做到这一点,你必须在 git push 命令中使用 --force--force-with-lease 选项。 --force-with-lease选项在某种程度上更加“安全”:当您使用此选项时,您的命令形式为:我想要更新_____(将空白处填写分支名称)。我相信您的最新提交是______(将空白处填写哈希ID)。如果是这样,请放弃一些提交; 使用______(将空白处填写哈希ID)。您的Git将填充所有空白并发送此信息。如果他们的Git自上次与您的Git通信以来没有累积任何新的提交,则您的替换提交是正确的替换提交,并且如果他们服从这个强制性命令,那就万事大吉。 --force选项跳过安全检查:将_____(将空白处填写名称)更新到_____(将空白处填写哈希ID)!只要没有其他人在您开始工作后添加了新的提交,则此强制命令将实现与更谨慎的--force-with-lease相同的结果。
当您使用带有强制选项的git pull而不是git push时,您会获取它们的最新提交,这些提交是您之前丢弃的提交,并且现在您遇到了相同的问题。无论是使用提取和重放式的拉(fetch-and-rebase)还是提取和合并式的拉(fetch-and-merge),您都会遇到此问题。(我个人建议避免使用git pull:自己运行git fetch,然后根据您打算使用哪个命令,自己运行git mergegit rebase。然后当它出现问题时,您就知道哪个命令实际上失败了。当您使用git pull为您运行两个Git命令,并且某些事情失败时,您甚至可能不知道哪个Git命令失败了。但有些人发现输入一些额外字符很困难。正如您可以根据我的答案长度看到的那样,我没有这个特定的问题。)
Git 对提交非常贪婪,而不愿意放弃任何提交。出于这个原因,以及作为备份(以防您改变主意),旧的提交尚未真正消失。默认情况下,您在它们真正消失之前至少有30天的时间来恢复它们。在该30天窗口中恢复它们略微痛苦。

1
git push origin HEAD 我之前不知道这个命令。之前浪费了好多时间打分支的名字 :-) - eftshift0
1
@eftshift0:这是一个作弊的方法,但我经常使用。有时候我担心会走到一个意想不到的分支上,哈哈。 - torek
1
我的典型推送命令也是这样的 :-) @torek,你说的“在一个意外的分支上”是什么意思?你是指可能出现的情况,即上游分支不应该是远程同名分支的那个吗?(顺便说一句:这怎么算是“作弊”呢?哈哈) - Romain Valeri
@torek,非常感谢你的解释。我在网上搜索了一段时间,没有人涵盖如何解决这些问题。有关如何变基的帖子和演示,但没有关于如何正确解决变基冲突的内容,这很奇怪。我猜一旦我们学会了正确的方法,就可以继续前进了。希望这对将来的其他人有所帮助。 - Helmut Granda
1
@RomainValeri:当我进行变基操作时,我倾向于保存旧分支(因此最终会得到foo.0、foo.1、foo.2和foo,此时为v3),有时我会忘记我上次查看的是哪一个。我可能会意外地执行git push -f origin HEAD,结果保存了foo.2,而我本打算只在本地保留它并更新foo。对于较短的分支名称,只需输入foo会更容易,但有时我会在历史记录中搜索最后一次推送并重复使用它。(对我来说,这更像是一种大脑快捷方式,而不是一种打字快捷方式,所以这有点作弊...) - torek
太棒了。这是一个非常清晰明了的答案,也提高了我对Git的理解。如果我可以给它超过一个赞,我会的。 - haz

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