我们使用 git 并有一个 master 分支和 developer 分支。我需要添加一个新功能,然后将提交重新设置为 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 在 hisNewFeature 上工作都使用 master 作为主分支
developer2 将 myNewFeature 合并到 hisNewFeature
developer1 变基,解决冲突,然后强制推送到 myNewFeature 的远程分支
几天后,developer2 再次将 myNewFeature 合并到 hisNewFeature
这会导致其他开发者讨厌 developer1 吗?
we
是谁?你的团队不仅仅是你吗? they
说(比我了解更多的人)如果您共享您的代码,那么您不应该使用 rebase
。你为什么不只做git pull
和git merge
?
force
推送)
rewriting history
时,那是 rebase
首先,您和与您一起工作的人需要就主题/开发分支是用于共享开发还是仅用于您自己的开发达成一致。其他开发人员知道不要合并到我的开发分支上,因为它们随时会被重新定位。通常工作流程如下:
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 分支切换。其次,这是一种安全机制,可确保我不会覆盖任何未隐藏/提交的更改。另外,如果我不能快进合并到 master 分支,这意味着有人已经重新设置了远程 master 的基础(为此他们需要被严厉地鞭打),或者我不小心提交给 master 并且需要清理我的结束。
然后当远程发生变化并且我快速转发到最新的时,我将重新设置:
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'
因此,所有开发人员主题分支都位于他们自己的嵌套集中。
您需要强制推送,因为您已将提交进一步移到 git 期望您将提交添加到分支的尖端。 git push -f origin myNewFeature
将解决您的问题。
提示:以上是强制推送的合法用法。永远不要在可公开访问的存储库上重写历史,否则很多人会讨厌你。
git push --force-with-lease
比使用 git push --force
安全得多
git push --force-with-lease origin HEAD
- 假设您的目标分支已经签出
--force-with-lease
做什么?
这里要记住的主要事情是 pull 和 rebase 在幕后做了什么。
拉取基本上会做两件事:获取和合并。当您包含 --rebase 时,它将执行变基而不是合并。
rebase 非常类似于存储分支以来的所有本地更改,将分支快速转发到目标上的最新提交,然后按顺序取消存储更改。
(这解释了为什么在执行 rebase 时可能会收到多个冲突解决提示,而不是在合并时可能会收到一个冲突解决提示。您有机会解决正在 rebase 的每个提交的冲突,以便以其他方式保留您的提交。 )
您永远不想将重新设置的更改推送到远程分支,因为这是重写历史。 Ofcoarse, never is a bit strong 因为几乎总是有例外。例如,您需要维护本地存储库的远程版本以在特定环境中工作的情况。
这将要求您有时使用强制推送重新调整的更改:
git push -f origin newfeature
或者在某些情况下,您的管理员可能已删除强制功能,因此您必须删除并重新创建:
git push origin :newfeature
git push origin newfeature
无论哪种情况,如果其他人在您的远程分支上与您合作,您必须绝对确定您知道自己在做什么。这可能意味着您最初与合并一起工作,并将它们重新设置为更易于管理的提交格式,然后再去掌握和删除您的工作分支。
请记住,您几乎总是可以通过以下优势回退到 git 的 GC:
git reflog
这是一个巨大的救命稻草,因为如果您在所有变基/冲突管理中迷失方向,您可以重置回更稳定的状态。
您需要执行强制推送,即git push -f origin myNewFeature
哦,你最好确保人们不会在你的开发分支上建立任何东西——通常你不应该发布你正在重写历史的分支(或者更确切地说,一旦发布就不要重写历史)。一种方法是使用像 wip/myNewFeature
这样的分支名称,然后提及 wip
分支将不时重新设置为主分支。
git push --force-with-lease
比使用 git push --force
安全得多
-f
用于正常强制推送:)
已经给出的一般答案——在推送重新设置的更改时使用 git push -f origin myNewFeature
——是一个很好的起点。我写这个答案是为了解决关于它是否会破坏你的工作流程的编辑。
如果我们假设您将使用 git pull --rebase ...
(或其他一些变体)然后强制推送到远程分支,那么在您的示例中破坏工作流的事情是 developer2 将 myNewFeature
合并到hisNewFeature
。只要没有其他人在该分支上工作,就能够重新定位您自己的功能分支是有意义的,因此您需要规则来划分分支领域。
您可以通过以下方式解决此问题:a) 建立一个您只从 master
合并的规则,或 b) 创建一个集体 develop
分支,您自己的 myNewFeature
分支基于该分支,并建立一个您只从 develop
合并。然后,master
将仅保留用于里程碑或版本(或者您想要设置的其他任何内容),并且当每个功能准备好集成到其他功能分支中时,develop
将是您推送每个功能的地方。
我相信这可以被认为是 Gitflow 工作流程的简化版本。
我同意 MrCholo,也许 Trevor Norris 可以考虑更新其 good answer 以替换
git push -f origin devel0
和
git push --force-with-lease origin devel0
因为这个线程是 this google search 的唯一结果,所以对于任何疯狂滚动的人来说,我只是将这个命令放在其他命令中:
git reset --soft HEAD~1
取消提交您的更改,您的文件将不会被修改,如果您运行 git status
,它们将恢复为已编辑的状态
不定期副业成功案例分享
git push -f origin devel0
时使用--force
标志?git push
不能快进(即 sha 历史不匹配)时,您必须强制 push 用从git rebase
生成的新历史覆盖以前的历史。