144

我们使用 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 吗?

4

6 回答 6

98

首先,您和与您一起工作的人需要就主题/开发分支是用于共享开发还是仅用于您自己的开发达成一致。其他开发人员知道不要合并到我的开发分支上,因为它们随时会被重新定位。通常工作流程如下:

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'

因此,所有开发人员主题分支都位于他们自己的嵌套集中。

于 2013-02-28T19:44:13.357 回答
60

您需要强制推送,因为您已将提交进一步移到 git 期望您将提交添加到分支的尖端。git push -f origin myNewFeature将解决您的问题。

提示:以上是强制推送的合法用法。永远不要在可公开访问的存储库上重写历史,否则很多人会讨厌你。

于 2013-02-28T18:39:22.243 回答
31

这里要记住的主要事情是 pull 和 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

这是一个巨大的救命稻草,因为如果您在所有变基/冲突管理中迷失方向,您可以重置回更稳定的状态。

于 2013-02-28T18:52:20.740 回答
2

您需要执行强制推送,即git push -f origin myNewFeature

哦,你最好确保人们不会在你的开发分支上建立任何东西——通常你不应该发布你正在重写历史的分支(或者更确切地说,一旦发布就不要重写历史)。一种方法是使用分支名称wip/myNewFeature,然后提到wip分支将不时重新设置为 master。

于 2013-02-28T18:39:12.180 回答
2

已经给出的一般答案——git push -f origin myNewFeature在推送重新调整的更改时使用——是一个很好的起点。我写这个答案是为了解决关于它是否会破坏你的工作流程的编辑。

如果我们假设您将使用git pull --rebase ...(或一些变体)然后强制推送到远程分支,那么在您的示例中破坏工作流的事情是 developer2 正在合并myNewFeaturehisNewFeature. 只要没有其他人在该分支上工作,就能够重新定位您自己的功能分支是有意义的,因此您需要规则来划分分支领域。

您可以通过 a) 建立一个只从 合并的规则master,或 b) 创建一个集体develop分支,您自己的分支基于该myNewFeature分支,并建立一个您只从 合并的规则developmaster然后将仅保留用于里程碑或发布(或者您想要设置的其他内容),并且develop当您准备好将每个功能集成到其他功能分支中时,它将是您推送每个功能的地方。

我相信这可以被认为是 Gitflow 工作流程的简化版本。

于 2015-11-17T22:22:43.747 回答
2

我同意MrCholo的观点,也许Trevor Norris可以考虑更新它的好答案来替换

git push -f origin devel0

git push --force-with-lease origin devel0
于 2018-11-29T14:33:28.413 回答