功能分支rebase后Git推送被拒绝

Yuv*_*dam 848 git

好吧,我认为这是一个简单的git场景,我错过了什么?

我有一个master分支和一个feature分支.我做了一些工作master,一些工作,feature然后再做一些工作master.我最终得到这样的东西(词典顺序暗示了提交的顺序):

A--B--C------F--G  (master)
       \    
        D--E  (feature)
Run Code Online (Sandbox Code Playgroud)

我没有问题要git push origin master保持远程master更新,也没有git push origin feature(当打开时feature)为我的feature工作维护远程备份.到目前为止,我们很好.

但现在我想在主人featureF--G提交之上重新定义,所以我git checkout featuregit rebase master.还好.现在我们有:

A--B--C------F--G  (master)
                 \
                  D'--E'  (feature)
Run Code Online (Sandbox Code Playgroud)

问题:当我想要备份新的rebased feature分支时git push origin feature,推送被拒绝,因为树由于变基而发生了变化.这只能通过解决git push --force origin feature.

我讨厌使用--force而不确定我是否需要它.那么,我需要它吗?重新定位是否必然意味着下一个push应该是--force完美的?

这个功能分支不与任何其他开发者共享,所以我事实上没有问题,推力,我不会丢失任何数据,问题更具概念性.

KL-*_*L-7 611

问题是git push假设远程分支可以快速转发到本地分支,即本地和远程分支之间的所有区别在本地有一些新的提交,如下所示:

Z--X--R         <- origin/some-branch (can be fast-forwarded to Y commit)
       \        
        T--Y    <- some-branch
Run Code Online (Sandbox Code Playgroud)

执行git rebase提交时,D和E将应用于新基础,并创建新的提交.这意味着在rebase之后你会有类似的东西:

A--B--C------F--G--D'--E'   <- feature-branch
       \  
        D--E                <- origin/feature-branch
Run Code Online (Sandbox Code Playgroud)

在那种情况下,远程分支无法快速转发到本地.虽然,理论上本地分支可以合并到远程(显然你在这种情况下你不需要它),但是git push只执行快进合并它会引发错误.

什么--force选项只是忽略远程分支的状态并将其设置为您正在推送它的提交.所以git push --force origin feature-branch简单地origin/feature-branch用本地覆盖feature-branch.

在我看来,master只要您是唯一一个在该分支上工作的人,就可以将功能分支和强制推送回远程存储库.

  • 说实话,将功能分支的原始版本拉出并合并到重新设计的一种类型中,可以消除整体反思的想法. (58认同)
  • 也许我没有理解错的话,但是如果你拉特性分支,它重订到新鲜主分支,你不能将其推回,而不力,因为该功能分支的远程版本无法快进到新(重新定义)功能分支的版本.这正是OP在他的问题中所描述的.如果重订基期后,但前推,你做`混帐拉功能branch`,这拉将产生一个新的合并提交(通过合并的分支中远程和本地版本).因此,要么在重新定位后获得不必要的合并,要么使用`--force`. (23认同)
  • "强制推送"的问题在于,您确实可以"松散的东西"(先前提交),这在任何版本控制系统中通常都是不可能的.因此,至少有一个"master-ish"分支应该具有设置为[不接受强制推送](http://stackoverflow.com/a/1754553/444255),以限制潜在的损害.(以下任何一个名称:脾气暴躁/被解雇的员工,自己的白痴,疲惫和过度劳累的'决定'......). (10认同)
  • `--AND-with-lease`为@hardev建议是一个很好的选择 (8认同)
  • 啊,我想我明白了.您正在描述与Mark Longair的回答相同的方法.但它确实生成了合并提交.在某些情况下它可能很有用,但我主要在我自己的功能分支中使用rebase(因此`push --force`不是问题)来保持提交历史线性而没有任何合并提交. (6认同)
  • 请注意,`--force-with-lease` 比`--force` 安全得多,在这种情况下这是正确的做法。 (5认同)

Har*_*dev 389

而不是使用-f或--force开发人员应该使用

--force-with-lease
Run Code Online (Sandbox Code Playgroud)

为什么?因为它检查远程分支的更改,这绝对是个好主意.让我们想象一下,詹姆斯和丽莎正在研究同一个功能分支,丽莎已经推动了提交.詹姆斯现在重新调整他的当地分支,并在试图推动时被拒绝.当然,詹姆斯认为这是因为改变并使用--force并且会改写所有Lisa的变化.如果詹姆斯曾经使用过--force-with-lease,那么他会收到一个警告,告知其他人已做过提交.我不明白为什么有人会在推销一个rebase之后使用--force而不是--force-with-lease.

  • 很棒的解释.`git push --force-with-lease`为我节省了一大堆. (27认同)
  • 这就是答案,rebase 到 master/develop 会产生问题,这正是 --force-with-lease 存在的原因。 (6认同)
  • 这是一个有用的评论,但并不是这个问题的真正答案. (5认同)
  • 我认为公认的答案和这个答案都解决了这个问题。接受的答案解释了为什么你需要强制。这个解释了为什么`--force-with-lease`解决了使用`--force`的问题 (5认同)
  • 这应该是公认的答案。完全解决所描述的问题 - 如果其他人同时提交,则强制推送而不强制。 (4认同)

Edd*_*dez 43

我会用"checkout -b"代替它,它更容易理解.

git checkout myFeature
git rebase master
git push origin --delete myFeature
git push origin myFeature
Run Code Online (Sandbox Code Playgroud)

当您删除时,阻止推入包含不同SHA ID的现有分支.在这种情况下,我只删除远程分支.

  • 这很好用,特别是如果你的团队有一个拒绝所有git push --force命令的git钩子. (5认同)
  • 这与`push --force`具有相同的结果,因此只是一种绕过git repo来阻止`--force`的方法.因此,我不认为这是一个好主意 - 要么回购允许`push --force`,要么是有充分理由它禁用它.如果在远程仓库上禁用`--force`,Nabi的答案更合适,因为它没有丢失来自其他开发人员的提交或导致问题的风险. (4认同)

Mar*_*air 19

对此的一个解决方案是执行msysGit的rebasing合并脚本所做的事情- 在rebase之后,在旧的head中feature合并-s ours.你最终得到了提交图:

A--B--C------F--G (master)
       \         \
        \         D'--E' (feature)
         \           /
          \       --
           \    /
            D--E (old-feature)
Run Code Online (Sandbox Code Playgroud)

...而你的推动feature将是一个快速前进.

换句话说,你可以这样做:

git checkout feature
git branch old-feature
git rebase master
git merge -s ours old-feature
git push origin feature
Run Code Online (Sandbox Code Playgroud)

(未经测试,但我认为这是正确的......)

  • 我相信使用`git rebase`(而不是将`master`合并回你的功能分支)的最常见原因是制作干净的线性提交历史.随着你的方法提交历史变得更糟.由于rebasing在没有引用其先前版本的情况下创建新提交,我甚至不确定此合并的结果是否足够. (22认同)
  • @ KL-7:`merge -s our`的重点在于它人为地添加了对前一版本的父引用.当然,历史看起来并不干净,但是提问者似乎特别担心不得不强行推动"功能"分支,这就解决了这个问题.如果你想要改变,那么它或多或少就是一个或另一个.:)更一般地说,我认为msysgit项目这样做很有意思.... (6认同)

JAR*_*ans 15

可能是也可能不是这个分支上只有一个开发人员,现在(在rebase之后)不与原点/特征内联.

因此我建议使用以下顺序:

git rebase master
git checkout -b feature_branch_2
git push origin feature_branch_2
Run Code Online (Sandbox Code Playgroud)

是的,新的分支,这应该解决这个没有--force,我认为通常是一个主要的git缺点.

  • 很抱歉,但是:"继续生成分支"以避免强制覆盖现有的分支无助于"孤独的功能开发人员"(谁可以覆盖),也不会帮助多个人在功能分支上工作(需要通信该分支"增量"并告知移动,伙计们). - 它更像是版本控制系统中的手动版本控制("thesis_00.doc,thesis_01.doc,...")... (2认同)
  • 另外,当您在一个分支名称上打开 github PR 时,这无济于事,您必须为您推送的新分支名称创建一个新 PR。 (2认同)

Nab*_*abi 13

我避免强制推送的方法是创建一个新分支并继续在新分支上工作,并在一些稳定之后,删除已重新分支的旧分支:

  • 在本地重新签出已签出的分支
  • 从重新分支分支到新分支
  • 将该分支作为新分支推送到远程.并删除远程旧分支

  • 因为我有大约 200 个系统跟踪分支名称,并且它必须是任务的特定名称,如果我开始在每次推送时都重命名分支,我就会失去理智。 (3认同)
  • @Nabi 这正是 --force-with-lease 所做的,除了它还验证没有不属于您的新提交。 (2认同)

Bil*_*oor 12

其他人已经回答了你的问题.如果你重新分支一个分支,你将需要强制推动该分支.

Rebase和共享存储库通常不相处.这是重写历史.如果其他人正在使用该分支或从该分支分支,那么rebase将是非常不愉快的.

一般而言,rebase适用于本地分支机构管理.远程分支管理最适合使用显式合并(--no-ff).

我们还避免将master合并到功能分支中.相反,我们使用新的分支名称(例如添加版本后缀)重新掌握.这避免了共享存储库中的重新定位问题.

  • 你能加一个例子吗? (4认同)

Bou*_*uke 8

分支git merge master上有什么问题feature?这将保留您的工作,同时将其与主线分支分开.

A--B--C------F--G
       \         \
        D--E------H
Run Code Online (Sandbox Code Playgroud)

编辑:啊抱歉没有看到你的问题陈述.当你表演时你将需要武力rebase.修改历史记录的所有命令都需要--force参数.这是一个可以防止您丢失工作的故障保险(旧的D并且E会丢失).

所以你执行了一个git rebase使树看起来像(虽然部分隐藏为D并且E不再在命名分支中):

A--B--C------F--G
       \         \
        D--E      D'--E'
Run Code Online (Sandbox Code Playgroud)

所以,当你试图推动你的新feature分支(包括D'E'在其中)时,你会失去DE.

  • 这没什么不对,我知道它会起作用.这不是我需要的.就像我说的那样,问题更具概念性而非实际性. (3认同)

Soh*_*mad 6

以下对我有用:

git push -f origin branch_name

它不会删除我的任何代码。

但是,如果您想避免这种情况,可以执行以下操作:

git checkout master
git pull --rebase
git checkout -b new_branch_name
Run Code Online (Sandbox Code Playgroud)

然后你可以挑选所有提交到新分支的内容。 git cherry-pick COMMIT ID 然后推送你的新分支。

  • “-f”是“--force”的别名,这是问题尽可能避免的。 (7认同)

Nee*_*ede 5

对我来说,以下简单的步骤有效:

1. git checkout myFeature
2. git rebase master
3. git push --force-with-lease
4. git branch -f master HEAD
5. git checkout master
6. git pull
Run Code Online (Sandbox Code Playgroud)

完成上述所有操作后,我们也可以通过以下命令删除 myFeature 分支:

git push origin --delete myFeature
Run Code Online (Sandbox Code Playgroud)