好吧,我认为这是一个简单的git场景,我错过了什么?
我有一个master分支和一个feature分支。我在master上做了一些工作,在feature上做了一些工作,然后在master上做了一些工作。我最终得到这样的东西(词典顺序暗示了提交的顺序):
1 2 3
| A--B--C------F--G (master)
\
D--E (feature) |
我没有问题git push origin master保持远程master更新,也没有git push origin feature(当在feature上时)维护我的feature工作的远程备份。到目前为止,我们很好。
但是现在我想在master上的F--G提交之上重新定义feature,所以我git checkout feature和git rebase master。还好。现在我们有:
1 2 3
| A--B--C------F--G (master)
\
D'--E' (feature) |
问题:当我想用git push origin feature备份新的rebased feature分支时,推送被拒绝,因为树由于变基而发生了变化。这只能用git push --force origin feature解决。
我讨厌使用--force而不确定我是否需要它。那么,我需要它吗?变异是否必然意味着下一个push应该--force?
这个功能分支不与任何其他开发者共享,所以我事实上没有问题,推力,我不会丢失任何数据,问题更具概念性。
问题是git push假设远程分支可以快速转发到本地分支,即本地和远程分支之间的所有区别都在本地有一些新的提交,如下所示:
1 2 3
| Z--X--R <- origin/some-branch (can be fast-forwarded to Y commit)
\
T--Y <- some-branch |
执行git rebase提交时,D和E将应用于新基础并创建新提交。这意味着在rebase之后你会有类似的东西:
1 2 3
| A--B--C------F--G--D'--E' <- feature-branch
\
D--E <- origin/feature-branch |
在那种情况下,远程分支无法快速转发到本地。虽然,理论上本地分支可以合并到远程(显然你不需要它),但由于git push只执行快进合并,它会引发错误。
而--force选项所做的只是忽略远程分支的状态并将其设置为您正在推送的提交。所以git push --force origin feature-branch只需用本地feature-branch覆盖origin/feature-branch。
在我看来,只要您是唯一一个在该分支上工作的人,就可以在master上重新定义功能分支并强制将它们推回到远程存储库。
-
说实话,将功能分支的原始版本拉出并合并到重新设计的一种类型中,可以消除整体反思的想法。
-
也许我没有正确理解你,但是如果你拉动功能分支,将它重新绑定到新的主分支上,你就不能没有强制推回它,因为功能分支的远程版本无法快速转发到你的新(重新定义)功能分支的版本。这正是OP在他的问题中所描述的。如果在重新定位之后,但在推送之前,您执行git pull feature-branch,此拉动将生成新的合并提交(通过合并功能分支的远程和本地版本)。因此,要么在重新定位后获得不必要的合并,要么使用--force进行推送。
-
啊,我想我明白了。您正在描述与Mark Longair的回答相同的方法。但它确实生成了合并提交。在某些情况下它可能很有用,但我主要在我自己的功能分支中使用rebase(因此push --force不是问题)来保持提交历史线性而没有任何合并提交。
-
这也表明,DVCS的整个想法是你永远不会进入同一个分支。你拉其他人所做的改变,永远不应该被推给你。您只是推动避免防火墙(以及用于备份目的),因此推送的分支应该只镜像您的工作,而不是权威分支。恕我直言,强制推动应该是默认的,但我想有太多人正在推进同一个分支,以便快乐地结束。 :)
-
"强制推送"的问题是,你确实可以"松散的东西"(先前提交),这在任何版本控制系统中通常都是不可能的?因此,至少有一个"master-ish"分支应该具有不接受强制推动的设置,以限制潜在的损害。 (说出以下任何一种情况:脾气暴躁/被解雇的员工,自己的白痴,疲惫和过度劳累的'决定'......)。
-
我认为这可以解决我的问题,看起来很相似,但是:$ git push --force origin myBranch返回"一切都是最新的",然后紧接着git checkout myBranch给出相同的"切换到分支'myBranch'你的分支超前于'原点/特征/ myBranch'由34提交。"
-
--force-with-lease as @hardev建议是一个很好的选择
-
请注意,--force-with-lease比--force更安全,在这种情况下这是正确的做法。
-
"git push origin + my_branch"也会有所帮助。
而不是使用-f或--force开发人员应该使用
为什么?因为它检查远程分支的更改,这绝对是个好主意。让我们想象一下,詹姆斯和丽莎正在研究同一个功能分支,丽莎已经推动了提交。詹姆斯现在重新调整他的当地分支,并在试图推动时被拒绝。当然,詹姆斯认为这是因为改变并使用--force并且会改写所有Lisa的变化。如果詹姆斯曾经使用过--force-with-lease,那么他会收到一个警告,告知其他人已做过提交。我不明白为什么有人会在推销一个rebase之后使用--force而不是--force-with-lease。
-
很棒的解释。 git push --force-with-lease为我节省了一大堆。
-
这是一个有用的评论,但并不是这个问题的真正答案。
-
这就是答案,对master / develop的重新定位会产生问题,这正是为什么--force-with-lease存在的原因。
-
这应该是公认的答案。完全解决了所描述的问题 - 如果其他人在此期间提交,则强制推动而不强迫。
-
我认为接受的答案和这个都解决了这个问题。接受的答案解释了为什么你需要强迫。这个解释了为什么--force-with-lease解决了使用--force的问题
我会用"checkout -b"代替它,它更容易理解。
1 2 3 4
| git checkout myFeature
git rebase master
git push origin --delete myFeature
git push origin myFeature |
当您删除时,阻止推入包含不同SHA ID的现有分支。
在这种情况下,我只删除远程分支。
-
这很好用,特别是如果你的团队有一个拒绝所有git push --force命令的git钩子。
-
谢谢你,它运作良好。以下是我阅读的更多细节,以便更好地理解。当您不想或不能强制推动时,这非常有用。删除远程分支和重新定位
-
这与push --force具有相同的结果,因此只是一种绕过git repo阻止--force的方法。因此,我认为这不是一个好主意 - 要么回购允许push --force,要么是有充分理由它禁用它。如果在远程仓库上禁用--force,Nabi的答案更合适,因为它没有丢失来自其他开发人员的提交或导致问题的风险。
对此的一个解决方案是执行msysGit的rebasing合并脚本所做的事情 - 在rebase之后,将feature的旧头与-s ours合并。你最终得到了提交图:
1 2 3 4 5 6 7
| A--B--C------F--G (master)
\ \
\ D'--E' (feature)
\ /
\ --
\ /
D--E (old-feature) |
...而你推动feature将是一个快进。
换句话说,你可以这样做:
1 2 3 4 5
| git checkout feature
git branch old-feature
git rebase master
git merge -s ours old-feature
git push origin feature |
(未经测试,但我认为这是正确的......)
-
我相信使用git rebase(而不是将master重新合并到您的功能分支中)的最常见原因是制作干净的线性提交历史记录。随着你的方法提交历史变得更糟。由于rebasing在没有引用其先前版本的情况下创建新提交,我甚至不确定此合并的结果是否足够。
-
@ KL-7:merge -s ours的重点是它人为地添加了对先前版本的父引用。当然,历史看起来并不干净,但提问者似乎特别担心不得不强行推动feature分支,这就可以解决这个问题。如果你想要改变,那么它或多或少就是一个或另一个。 :)更一般地说,我认为msysgit项目这样做很有意思....
-
@ KL-7:顺便说一下,我给你的回答,这显然是正确的 - 我只是觉得这也可能很有趣。
-
它绝对有趣,至少对我而言。谢谢。我之前见过ours策略,但我认为它只适用于冲突情况,可以通过我们分支中的更改自动解决它们。事实证明它的工作方式不同。并且以这种方式工作它非常有用,如果你需要重新定义的版本(例如,让repo维护者将它干净地应用于master)但是想要避免强制推送(如果由于某种原因许多其他ppl正在使用你的功能分支)。
可能是也可能不是这个分支上只有一个开发人员,现在(在rebase之后)不与原点/特征内联。
因此我建议使用以下顺序:
1 2 3
| git rebase master
git checkout -b feature_branch_2
git push origin feature_branch_2 |
是的,新的分支,这应该解决这个没有--force,我认为通常是一个主要的git缺点。
-
很抱歉,但是:?继续生成分支"以避免强制覆盖现有的分支没有帮助?孤独的功能开发人员"(谁可以覆盖)也不是多个人在功能分支上工作(需要传达该分支"增量"并告知移动,伙计们)。 - 它更像是版本控制系统中的手动版本控制("thesis_00.doc,thesis_01.doc,...")...
-
另外,当你在一个分支名称上打开github PR时,这没有用,你必须为你推送的新分支名称创建一个新的PR。
-
@frankee根据我的经验,半真实。对于一个孤独的开发者来说,是的,只是强行推动很容易,但这是习惯,可能会在以后咬你。 +一个新的开发刚刚加入?或者某些CI系统没有使用--hard reset?对于团队协作,我认为传达新的分支名称很容易,这也很容易编写脚本+对于一个团队,我建议在本地进行变基,或者当分支准备好合并时,而不是在白天工作因此,额外提交比处理rebase / merge冲突更麻烦。
-
对于PR来说,@ gprasant再一次,我认为这对于rebase来说是错误的,我实际上想要看一下PR修复的单一提交。一个rebase(壁球)应该只在稍后作为合并到掌握的一部分以及PR完成并准备就绪时发生(因此不需要打开新的PR)。
我避免强制推送的方法是创建一个新的分支并继续在新分支上工作,并在一些稳定之后,删除已重新分支的旧分支:
-
在本地重新签出已签出的分支
-
从重新分支分支到新分支
-
将该分支作为新分支推送到远程。并删除远程旧分支
-
为什么不爱这个选项?它绝对是最干净,最简单,最安全的。
-
因为我有大约200个系统跟踪分支名称,它必须是任务的特定名称,如果我开始做分支重命名每次推送我会放松我的想法。
-
@TamirDaniely我没有尝试过,但是在推送和推送具有相同旧名称的新分支解决问题之前,是否删除旧分支(来自远程)?
-
@Nabi这正是--force-with-lease所做的,除了它还验证没有新的提交不是你的。
其他人已经回答了你的问题。如果你重新分支一个分支,你将需要强制推动该分支。
Rebase和共享存储库通常不相处。这是重写历史。如果其他人正在使用该分支或从该分支分支,那么rebase将是非常不愉快的。
一般而言,rebase适用于本地分支机构管理。远程分支管理最适合使用显式合并(--no-ff)。
我们还避免将master合并到功能分支中。相反,我们使用新的分支名称(例如添加版本后缀)来重新掌握。这避免了共享存储库中的重新定位问题。
feature分支上的git merge master有什么问题?这将保留您的工作,同时将其与主线分支分开。
1 2 3
| A--B--C------F--G
\ \
D--E------H |
编辑:啊抱歉没有看到你的问题陈述。执行rebase时需要强制。修改历史记录的所有命令都需要--force参数。这是一个防止您丢失工作的故障保护(旧的D和E将丢失)。
所以你执行了一个git rebase,它使树看起来像(虽然部分隐藏为D并且E不再在命名分支中):
1 2 3
| A--B--C------F--G
\ \
D--E D'--E' |
因此,当您尝试推送新的feature分支(其中包含D'和E')时,您将丢失D和E。
-
这没什么不对,我知道它会起作用。这不是我需要的。就像我说的那样,问题更具概念性而非实际性。
-
对不起,请看我的编辑以获得答案。
以下适用于我:
git push -f origin branch_name
并且它不会删除我的任何代码。
但是,如果您想避免这种情况,那么您可以执行以下操作:
1 2 3
| git checkout master
git pull --rebase
git checkout -b new_branch_name |
然后你可以挑选你所有的提交到新的分支。
git cherry-pick COMMIT ID
然后推动你的新分支。
-
-f是--force的别名,如果可能,这是问题试图避免的问题。
-
谢谢@PresidentEvil我已经更新了我的答案。
对我来说,遵循简单的步骤:
1 2 3 4 5 6
| 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 |
完成上述操作后,我们可以通过以下命令删除myFeature分支:
1
| git push origin --delete myFeature |
由于OP确实理解了这个问题,只需寻找更好的解决方案......
这个练习怎么样?
此方法可能已存在模式名称。