注:译文出自 GitHub edx,经做者 @whilgeek 提醒,对一些错误已纠正。git
英文原文在此github
有些词翻译过来反而不如原文精彩,就保留了,好比fork
,push
等等。segmentfault
(OK正文开始)服务器
当不少人同时在一个工程上工做的时候,一个拉取请求也许很快就会过期。一个“过期”的拉取请求就是一个再也不和开发主线保持同步的开发分支,它在合并到工程里面以前须要被更新。拉取请求之因此会过期的最多见缘由是由于冲突的存在:若是两个拉取请求修改了同一个文件中的相同的几行,一个拉取请求被合并以后,没被合并的拉取请求和工程之间就会存在一个冲突。有时候,一个拉取请求在没有冲突的状况下也会过期。或许是代码基础中的一个不一样文件发生了改动,须要你在拉取请求中作出相应的改变,以保证和新架构一致。又或许是某人意外将失败了的单元测试代码合并进了主分支时建立了新分支。不论是什么缘由,若是你的拉取请求已通过时了,在你的分支能被合并以前,你须要将你的分支变基到主分支最新版本。
架构
为了理解这个,咱们须要首先理解一点git运行的原理。一个git仓库是一个树形结构,树上的每一个点都表明一个提交。这里有一个简单的关于仓库的例子:在主分支上它有4个提交,每一个提交都有一个ID(在这里个例子中,ID是a
,b
,c
和d
)。你会注意到d
目前是主分支中最新的提交(或者称为HEAD
)。编辑器
这里咱们有两个分支,master
和my-branch
。你会看到master
和my-branch
中都包含a
和b
提交。而后它们开始分叉:master
包含c
和d
,而my-branch
包含e
和f
。b
就是所谓的my-branch
相对于master
的合并基础
,或者更通常的说,就是基础
。这颇有意义:你能够看到my-branch
是基于master
的一个早期版本。单元测试
因此咱们称my-branch
是过期的,并且你想让它和master
分支的最新版本保持同步。换种说法,my-branch
须要包含c
和d
。你能够作一个合并操做,可是这会让这个分支包含一些怪异的合并提交,让代码审查更为困难。为了避免这样,你能够作一个rebase
操做。学习
当你变基的时候,git会找到你分支的base(在这个例子中是b
)以及base和HEAD中的全部提交历史(在这个例子中是e
和f
)。而且将这些提交历史在你要变基进去的分支(在这个例子中是master)的HEAD(头提交)上重演一遍。参照你的修改,git建立了一些看起来就像是在master分支顶部进行修改的提交历史:在这个图中,这些提交被叫作e
和f
。git并不会擦除你以前的提交:e
和f
不会有人动的,并且若是在变基过程当中出现了某些错误,你彻底能够回到以前的状态,就像没变过基同样。测试
然而,另外须要注意的一点就是,git只把分支看成是标签。主分支就是主标签指向的,同时也是全部提交的祖先。当你给一个分支变基的时候,git移动分支标签指向新建立的分支,my-branch
如今再也不指向f
,而是指向f'
。退回到以前状态的方式,仅仅是改变了分支标签,因此它后退并指向了f
。fetch
你会注意到从f
到f'
没有一条直接的通路,在其余人看来,历史好像被忽然改变了。c
和d
被有效注入了my-branch
分支,就好像它们一直在那里同样。不像其余的版本控制系统,git容许你修改你的项目的历史 -- 可是对这种容许必定要谨慎。咱们稍后会讲到这一点。
好吧,如今你知道变基是什么了,下一步就是学习如何去变。假定你已经fork了edx-platform
,并且你建立了一个分支。就像这样:
git clone https://github.com/my-username/dex-platform.git cd edx-platform git checkout -b my-branch
在你的分支里你已经作了一些提交,而且将它们push到了Github上,并建立了一个拉取请求。你经历了代码审查,回应了别人的评论,而后某人要求你将你的拉取请求变基,下面是你要作的:
在git的定义中,远程分支就是你能提交修改的仓库的克隆。当你从官方的edx/edx-platform
中克隆出一份后。你建立了一个新的,名叫your-username/edx-platform
的仓库
,可是这两个仓库能够共享所做的提交。
为了将edx
添加为一个远程分支,在你的本地仓库中运行:
git remote add edx https://github.com/edx/dex-platform.git
你能够运行git remote -v
来验证是否成功,你应该看到edx
在你的远程分支列表中。记住:这一步在每一个克隆过程当中只须要执行一次。
你的计算机须要从Github上下载关于这个官方仓库的信息,这样它就会知道主分支的最新版本。而后你的远程分支就创建好了,这很简单。在你的本地仓库中运行:
get fetch edx
这一步是可选的,可是很建议你走这一步。这涉及到你在你的分支上所做的全部提交,而后将他们压缩成一个大点的提交。这样作的目的是为了在变基的时候能够更简单地结局冲突,以及让咱们来审查你的拉取请求。
为了这样作,咱们将会作一个交互式的变基。首先,找到你分支的基础。你能够这样来找:
git merge-base my-branch master
这条命令会返回一个提交哈希。在下面这条命令中使用你获得的哈希:
git rebase --interactive $${HASH}
举例来讲,若是你合并的基础是abc123
,你会运行git rebase --interactive abc123
。你的文本编辑器会打开一个文本文件,其中列举了你对你的分支所做的全部提交。 并且,在每一个提交以前都有一个写做pick
的单词。就像这样:
pick 1fc6c95 do something pick 6b2481b do something else pick dd1475d changed some things pick c619268 fixing typos
你须要将除了第一行外全部的行以前的“pick”换作“squash”,作完的时候,应当是这样的:
pick 1fc6c95 do something squash 6b2481b do something else squash dd1475d changed some things squash c619268 fixing typos
保存并关闭这个文件,稍等片刻,一个新的文件会在你的编辑器中弹出来:包含着全部提交的全部信息。随意修改这些提交信息,一样的保存并关闭这个文件。保存的这些提交信息会变成一条提交信息,这是由那多条合并而来的。一旦你保存并关闭了这个文件你的这些提交就要被压缩成一个,这一步就完成了!
在你本地分支中运行
git rebase edx/master
git会开始在主分支的最新版本上重演你的提交。这一步你可能会遇到冲突:若是确实遇到了的话,git会暂停并让你在继续以前先解决冲突。就像在合并的时候解决冲突同样:你能够用git status
来看哪些文件存在冲突,编辑这些文件以解决冲突,而后git add
来表示冲突已经解决了。然而,你要运行git rebase --continue
而不是git commit
来告诉git能够继续来重演提交了。若是在作这一步以前,你已经压缩了你的提交,你能够一次性地解决冲突 -- 若是你没有压缩,你会屡次解决冲突。
就像上面解释的,当你变基的时候,你在修改你的分支的历史。结果就是,若是你在变基以后作一个普通的git push
,git会拒绝它,由于在服务器的分支和你的分支之间没有一条直接的通路。因此,你要使用-f
或--force
标志来告诉git你知道你正在作什么。当你在作强制推送的时候,强烈建议你将你的push.default
设置改成Git2.0中默认的simple
。为了确保你的配置是正确的,运行:
git config --global push.default simple
一旦修改正确,你就能够运行:
git push -f
而后你检查一下你的拉取请求,它应该已经更新啦!