我们使用git并拥有一个主分支和开发人员分支。我需要添加一个新功能,然后将提交重新设置为master,然后将master推送到CI服务器。
问题是,如果我在rebase期间遇到冲突,我就无法在rebase完成后推送到我的远程开发人员分支(在Github上),直到我拉出我的远程分支。这会导致重复提交。如果没有冲突,按预期工作。
问题:在rebase和冲突解决之后,如何在不创建重复提交的情况下同步我的本地和远程开发人员分支
设定:
// master branch is the main branch
git checkout master
git checkout -b myNewFeature
// I will work on this at work and at home
git push origin myNewFeature
// work work work on myNewFeature
// master branch has been updated and will conflict with myNewFeature
git pull --rebase origin master
// we have conflicts
// solve conflict
git rebase --continue
//repeat until rebase is complete
git push origin myNewFeature
//ERROR
error: failed to push some refs to 'git@github.com:ariklevy/dropLocker.git'
hint: Updates were rejected because the tip of your current branch is behind
hint: its remote counterpart. Merge the remote changes (e.g. 'git pull')
hint: before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.
// do what git says and pull
git pull origin myNewFeature
git push origin myNewFeature
// Now I have duplicate commits on the remote branch myNewFeature
所以听起来这会打破工作流程:
developer1处理myNewFeature developer2正在开发他的新功能 都使用master作为主分支
developer2将myNewFeature合并到他的新功能
中developer1 rebases,解决冲突,然后强制推送到myNewFeature的远程分支
几天后,developer2再次将myNewFeature合并到他的NewFeature中
这是否会导致其他开发人员讨厌developer1?
答案 0 :(得分:81)
首先,您和您正在合作的人需要同意主题/开发分支是用于共享开发还是仅用于您自己的开发。其他开发人员知道不要在我的开发分支上合并,因为他们将随时进行重新定位。通常工作流程如下:
o-----o-----o-----o-----o-----o master
\
o-----o-----o devel0
\
o-----o-----o devel1
然后,为了与遥控器保持同步,我将执行以下操作:
git fetch origin
git checkout master
git merge --ff origin/master
我这样做有两个原因。首先是因为它允许我查看是否有远程更改而无需从我的devel分支切换。其次,它是一种安全机制,以确保我不会覆盖任何未存储/提交的更改。此外,如果我不能快速合并到主分支,这意味着有人已经重新设置远程主机(他们需要严重鞭打)或我不小心承诺掌握并需要清理我的结束。
然后,当遥控器发生变化时,我已快速转发到最新的,我将改装:
git checkout devel0
git rebase master
git push -f origin devel0
其他开发人员随后知道他们需要根据我的最新版本重新开发他们的开发分支:
git fetch <remote>
git checkout devel1
git rebase <remote>/devel0
这导致了更清晰的历史:
o-----o master
\
o-----o-----o devel0
\
o-----o-----o devel1
不要随心所欲地来回合并提交。它不仅会创建重复提交并使历史无法遵循,从特定更改中找到回归几乎不可能(这就是为什么您首先使用版本控制,对吧?)。你遇到的问题是这样做的结果。
此外,它听起来像其他开发人员可能正在向您的开发分支提交。你能证实一下吗?
合并的唯一时间是您的主题分支已准备好接受master
。
旁注。如果多个开发人员提交到同一个存储库,那么您应该考虑使用命名分支来区分开发人员开发分支。例如:
git branch 'my-name/devel-branch'
因此,所有开发人员主题分支都驻留在他们自己的嵌套集中。
答案 1 :(得分:39)
你需要强制推送,因为你已经将提交进一步向下移动,git期望你将提交添加到分支的尖端。 git push -f origin myNewFeature
会解决您的问题。
提示:上面是强制推动的合法用法。永远不要在公共可访问的存储库中重写历史记录,否则许多人会讨厌你。
答案 2 :(得分:28)
这里要记住的主要事情是拉幕和底板在幕后做什么。
拉取基本上会做两件事:获取和合并。当您包含--rebase时,它将执行rebase而不是合并。
rebase非常类似于存储所有本地更改,因为您已经分支,快速转发您的分支到目标上的最新提交,并按顺序取消您的更改。
(这解释了为什么在进行rebase时你可能会得到多个冲突解决提示与你可能通过合并获得的一个冲突解决方案。你有机会解决正在重新定位的EACH提交的冲突,以便保留你的提交。)
您永远不想将重新定位的更改推送到远程分支,因为这会重写历史记录。由于几乎总是有例外,因此有点强大。例如,您需要维护本地存储库的远程版本以在特定环境中工作。
这将要求您使用force:
有时推送重新定义的更改git push -f origin newfeature
或者在某些情况下,您的管理员可能已取消强制执行功能,因此您必须删除并重新创建:
git push origin :newfeature
git push origin newfeature
在任何一种情况下,如果其他人在您的远程分支上与您合作,您必须完全确定自己知道自己在做什么。这可能意味着您最初使用合并进行协作,并在掌握和删除工作分支之前将其重新绑定为更易于管理的提交格式。
请记住,您几乎可以通过以下方式使用git的GC:
git reflog
这是一个巨大的生命保护程序,因为如果你在所有的rebase /冲突管理中迷失了,你可以重置回一个更稳定的状态。
答案 3 :(得分:2)
您需要执行强制推送,即git push -f origin myNewFeature
哦,你最好确定人们不会在你的开发分支上建立任何东西 - 通常你不应该发布你重写历史的分支(或者更确切地说,一旦发布就不重写历史)。一种方法是使用分支名称,如wip/myNewFeature
,然后提及wip
分支将不时变为主人。
答案 4 :(得分:1)
已经给出的一般答案 - 在推送重新变更时使用git push -f origin myNewFeature
- 是一个很好的起点。我正在写这个答案来解决关于它是否会破坏你的工作流程的编辑。
如果我们假设您将使用git pull --rebase ...
(或其中的某些变体),然后强行推送到远程分支,那么打破您示例中的工作流程的事情就是developer2正在将myNewFeature
合并到hisNewFeature
中。只要没有其他人在该分支上工作,就能够重新定义自己的功能分支是有意义的,因此您需要规则来划分分支区域。
你可以通过a)建立一个你只能从master
合并的规则来解决这个问题,或者b)创建一个集体develop
分支,在此基础上建立你自己的myNewFeature
分支,并建立一个只能从develop
合并的规则。 master
将仅保留用于里程碑或版本(或者您想要设置的其他内容),develop
将在您准备好集成到每个功能时将其推送到的位置其他功能分支。
我认为这可以被视为Gitflow工作流程的简化版本。
答案 5 :(得分:0)
我同意MrCholo,也许Trevor Norris可以考虑更新其good answer以取代
git push -f origin devel0
使用
git push --force-with-lease origin devel0