我现在已经在另一个开发人员的项目中使用Git几个月了。我有几年的SVN经验,所以我想我给这种关系带来了很多包袱。
我听说Git在分支和合并方面非常出色,到目前为止,我只是没有看到它。当然,分支非常简单,但是当我尝试合并时,一切都完蛋了。现在,我已经习惯了SVN,但在我看来,我只是用一个低于标准的版本控制系统换了另一个。
我的搭档告诉我,我的问题源于我对合并的渴望,并且在许多情况下我应该使用rebase而不是合并。例如,这是他制定的工作流程:
clone the remote repositorygit checkout -b my_new_feature..work and commit some stuffgit rebase master..work and commit some stuffgit rebase master..finish the featuregit checkout mastergit merge my_new_feature
从本质上讲,创建一个功能分支,始终从master重新定位到分支,并从分支合并回master。重要的是要注意分支始终保持本地。
这是我开始的工作流程
clone remote repositorycreate my_new_feature branch on remote repositorygit checkout -b --track my_new_feature origin/my_new_feature..work, commit, push to origin/my_new_featuregit merge master (to get some changes that my partner added)..work, commit, push to origin/my_new_featuregit merge master..finish my_new_feature, push to origin/my_new_featuregit checkout mastergit merge my_new_featuredelete remote branchdelete local branch
有两个基本的区别(我认为):我总是使用合并而不是rebasing,我将我的功能分支(和我的功能分支提交)推送到远程存储库。
我使用远程分支的理由是,我希望在工作时备份我的工作。我们的存储库会自动备份,如果出现问题,可以恢复。我的笔记本电脑不是,或者没有那么彻底。因此,我讨厌笔记本电脑上的代码没有镜像到其他地方。
我对合并而不是rebase的推理是,合并似乎是标准的,rebase似乎是一个高级功能。我的直觉是,我想做的不是一个高级设置,所以rebase应该是不必要的。我甚至仔细阅读了Git上的新实用编程书,他们广泛地涵盖了合并,几乎没有提到rebase。
不管怎样,我在最近的一个分支上遵循我的工作流程,当我试图将它合并回master时,一切都去了地狱。与不应该重要的事情发生了大量冲突。这些冲突对我来说毫无意义。我花了一天的时间来整理一切,最终我被迫推送到远程master,因为我的本地master已经解决了所有冲突,但是远程的仍然不高兴。
对于这样的事情,“正确”的工作流程是什么?Git应该使分支和合并变得超级容易,我只是没有看到它。
更新2011-04-15
这似乎是一个非常受欢迎的问题,所以我想我会更新我两年的经验,因为我第一次问。
事实证明,最初的工作流程是正确的,至少在我们的情况下是这样的。换句话说,这就是我们所做的,它是有效的:
clone the remote repositorygit checkout -b my_new_feature..work and commit some stuffgit rebase master..work and commit some stuffgit rebase master..finish the feature, commitgit rebase mastergit checkout mastergit merge my_new_feature
事实上,我们的工作流程有点不同,因为我们倾向于做南瓜合并而不是原始合并。(注意:这是有争议的,见下文。)这使我们能够将我们的整个功能分支变成主服务器上的单个提交。然后我们删除我们的功能分支。这使我们能够在逻辑上构建主服务器上的提交,即使它们在我们的分支上有点凌乱。所以,这就是我们所做的:
clone the remote repositorygit checkout -b my_new_feature..work and commit some stuffgit rebase master..work and commit some stuffgit rebase master..finish the feature, commitgit rebase mastergit checkout mastergit merge --squash my_new_featuregit commit -m "added my_new_feature"git branch -D my_new_feature
壁球合并争议-正如几位评论者所指出的,壁球合并将丢弃你的功能分支上的所有历史记录。顾名思义,它将所有提交压缩成一个。对于小功能,这是有道理的,因为它将其压缩成一个包。对于较大的功能,这可能不是一个好主意,特别是如果你的单个提交已经是原子的。这真的归结为个人偏好。
Github和Bitucket(其他?)拉取请求-如果你想知道合并/rebase与拉取请求有什么关系,我建议遵循上述所有步骤,直到你准备好合并回master。你只需接受PR,而不是手动使用git合并。请注意,这不会进行压扁合并(至少默认情况下不会),但非压扁,非快进是拉取请求社区中接受的合并约定(据我所知)。具体来说,它的工作方式是这样的:
clone the remote repositorygit checkout -b my_new_feature..work and commit some stuffgit rebase master..work and commit some stuffgit rebase master..finish the feature, commitgit rebase mastergit push # May need to force push...submit PR, wait for a review, make any changes requested for the PRgit rebase mastergit push # Will probably need to force push (-f), due to previous rebases from master...accept the PR, most likely also deleting the feature branch in the processgit checkout mastergit branch -d my_new_featuregit remote prune origin
我已经爱上了Git,再也不想回到SVN了。如果你在挣扎,只要坚持下去,最终你会看到隧道尽头的光明。