84669 人学习
152542 人学习
20005 人学习
5487 人学习
7821 人学习
359900 人学习
3350 人学习
180660 人学习
48569 人学习
18603 人学习
40936 人学习
1549 人学习
1183 人学习
32909 人学习
用了以后, 树可以非常清晰, 某种程度上便于追踪, 但是 push --force 就多多了, 不用呢, 合并没有远程仓库被修改的麻烦, 可是追踪又不清晰...
push --force
怎样取舍? 团队里一般怎么取舍?
git rebase是对commit history的改写。当你要改写的commit history还没有被提交到远程repo的时候,也就是说,还没有与他人共享之前,commit history是你私人所有的,那么想怎么改写都可以。
git rebase
而一旦被提交到远程后,这时如果再改写history,那么势必和他人的history长的就不一样了。git push的时候,git会比较commit history,如果不一致,commit动作会被拒绝,唯一的办法就是带上-f参数,强制要求commit,这时git会以committer的history覆写远程repo,从而完成代码的提交。虽然代码提交上去了,但是这样可能会造成别人工作成果的丢失,所以使用-f参数要慎重。
git push
-f
楼主遇到的问题,就是改写了公有的commit history造成的。要解决这个问题,就要从提交流程上做规范。
举个正确流程的栗子:
假设楼主的team中有两个developer:tom和jerry,他们共同使用一个远程repo,并各自clone到自己的机器上,为了简化描述,这里假设只有一个branch:master。
master
这时tom机器的repo有两个branchmaster, origin/master, origin/master 而jerry的机器上也是有两个branchmaster, origin/master, origin/master
origin/master
均如下图所示
tom和jerry分别各自开发自己的新feature,不断有新的commit提交到他们各自私有的commit history中,所以他们的master指针不断的向前推移,分别指向不同的commit。而又由于他们都没有git fetch和git push,所以他们的origin/master都维持不变。
git fetch
jerry的repo如下
tom的repo如下,注意T1和上图的J1,分别是两个不同的commit
T1
J1
这时Tom首先把他的commit提交的远程repo中,那么他本机origin/master指针则会前进,和origin/master指针则会前进,和master指针保持一致,如下
远程repo如下
现在jerry也想把他的commit提交到远程repo上去,运行git push,毫无意外的失败了,所以他git fetch了一下,把远程repo,也就是之前tom提交的T1给拉到了他本机repo中,如下
commit history出现了分叉,要想把tom之前提交的内容包含到自己的工作中来,有一个方法就是git merge,它会自动生成一个commit,既包含tom的提交,也包含jerry的提交,这样就把两个分叉的commit重新又合并在一起。但是这个自动生成的commit会有两个parent,review代码的时候必须要比较两次,很不方便。
git merge
jerry为了保证commit history的线性,决定采用另外一种方法,就是git rebase。jerry的提交J1这时还没有被提交到远程repo上去,也就是他完全私有的一个commit,所以使用git rebase改写J1的history完全没有问题,改写之后,如下
注意J1被改写到T1后面了,变成了J1`
J1`
git push后,本机repo
而远程repo
异常的轻松,一条直线,没有-f
所以,在不用-f的前提下,想维持树的整洁,方法就是:在git push之前,先git fetch,再git rebase的前提下,想维持树的整洁,方法就是:在
git fetch origin master git rebase origin/master git push
除非只有自己一个人用,不然用 push --force 的都该去死。
本地分支和远程分支的绑定(tracking),加上 rebase 策略:
[branch "master"] remote = origin merge = refs/heads/master rebase = true
这样一来,更新代码(pull)的时候就会自动应用 rebase 而不是产生 merge commit,除非有其他情况产生,比如三方合并造成了冲突需要人共去干预。大部分时候还是很聪明的,只要团队里的习惯都良好,那么可以保持一个非常干净漂亮的树形。
pull
其实想让树形结构漂亮些清晰些是有很多办法的,但是首先要取决于团队用的是什么样的 Git Model,对症下药即可。在这里就无法一言以蔽之了。
另外,楼上说得对,慎用 push -f!
push -f
这应该是一个git workflow的问题,我们团队也一直在使用rebase保证commit信息的整洁,但不会用到push -f这样的操作。
关于git workflow就是一个见仁见智的问题了,下面几篇文章你可以看下,再找出一套适合自己团队的就可以了,不过最重要的是要保证团队的每个人都熟悉git,防止犯愚蠢的错误。
如果使用github来团队合作的话,用好pull request,它可以解决push -f这种愚蠢问题!
每个人提交前,都应该把自己的修改rebase到服务器的最新代码之上,遵守这个规则就不会有任何问题。如果你需要force push,说明你做反了,把服务器代码rebase到你本地分支之上才会需要force push,这是错误的用法。
建议参考 Pro Git 中关于 rebase 的章节 http://git-scm.com/book/zh/Git-%E5%88%86%E6%94%AF-%E5%88%86%E6%94%AF%E7%9A%84%E8%A1%8D%E5%90%88
衍合的风险 呃,奇妙的衍合也并非完美无缺,要用它得遵守一条准则: 一旦分支中的提交对象发布到公共仓库,就千万不要对该分支进行衍合操作。 如果你遵循这条金科玉律,就不会出差错。否则,人民群众会仇恨你,你的朋友和家人也会嘲笑你,唾弃你。
衍合的风险 呃,奇妙的衍合也并非完美无缺,要用它得遵守一条准则:
一旦分支中的提交对象发布到公共仓库,就千万不要对该分支进行衍合操作。
如果你遵循这条金科玉律,就不会出差错。否则,人民群众会仇恨你,你的朋友和家人也会嘲笑你,唾弃你。
就我而言。如果 rebase 完后,需要使用 push -f 的话,一定代表该 rebase 操作是不合适。除非你是有意在修改提交历史。
不需要push -f啊,如果分支落后就用pull --rebase
楼上的答案都很正,个人认为,除非某个分支只有你自己搞,你怎么rebase都是没有问题的,但是如果你在master或者develop这种分支上来rebase,估计团队里每个人都想拍死你,尤其是对git不熟悉的队友,手足无措是非常正常的表现。
rebase之后 push -f的情况只有一个,就是题主像我一样有强迫症,害怕电脑宕机、系统崩溃这种蛋疼的事情(悲惨的血泪史),完成一个特性commit之后迅速push到远程只属于你的分支上,每天为了拿到develop的新特性,才在自己的分支上rebase develop,重复执行push的操作,这个个人认为是没有问题的,毕竟你只影响了你自己(而你知道这是对的)。
个人认为, 当你在某个分支进行团队合作的时候, 常用rebase真的是不合理。而且容易出问题。慎用 push --force
git rebase 一般自己一个人开发时使用,用来保持提交记录的整洁。一旦上传到github后,不应该使用git rebase,不然被骂死。
git rebase
是对commit history的改写。当你要改写的commit history还没有被提交到远程repo的时候,也就是说,还没有与他人共享之前,commit history是你私人所有的,那么想怎么改写都可以。而一旦被提交到远程后,这时如果再改写history,那么势必和他人的history长的就不一样了。
git push
的时候,git会比较commit history,如果不一致,commit动作会被拒绝,唯一的办法就是带上-f
参数,强制要求commit,这时git会以committer的history覆写远程repo,从而完成代码的提交。虽然代码提交上去了,但是这样可能会造成别人工作成果的丢失,所以使用-f
参数要慎重。楼主遇到的问题,就是改写了公有的commit history造成的。要解决这个问题,就要从提交流程上做规范。
举个正确流程的栗子:
假设楼主的team中有两个developer:tom和jerry,他们共同使用一个远程repo,并各自clone到自己的机器上,为了简化描述,这里假设只有一个branch:
master
。这时tom机器的repo有两个branch
master
,origin/master
,origin/master
而jerry的机器上也是有两个branch
master
,origin/master
,origin/master
均如下图所示
tom和jerry分别各自开发自己的新feature,不断有新的commit提交到他们各自私有的commit history中,所以他们的master指针不断的向前推移,分别指向不同的commit。而又由于他们都没有
git fetch
和git push
,所以他们的origin/master
都维持不变。jerry的repo如下
tom的repo如下,注意
T1
和上图的J1
,分别是两个不同的commit这时Tom首先把他的commit提交的远程repo中,那么他本机
origin/master
指针则会前进,和origin/master
指针则会前进,和master
指针保持一致,如下远程repo如下
现在jerry也想把他的commit提交到远程repo上去,运行
git push
,毫无意外的失败了,所以他git fetch
了一下,把远程repo,也就是之前tom提交的T1
给拉到了他本机repo中,如下commit history出现了分叉,要想把tom之前提交的内容包含到自己的工作中来,有一个方法就是
git merge
,它会自动生成一个commit,既包含tom的提交,也包含jerry的提交,这样就把两个分叉的commit重新又合并在一起。但是这个自动生成的commit会有两个parent,review代码的时候必须要比较两次,很不方便。jerry为了保证commit history的线性,决定采用另外一种方法,就是
git rebase
。jerry的提交J1
这时还没有被提交到远程repo上去,也就是他完全私有的一个commit,所以使用git rebase
改写J1
的history完全没有问题,改写之后,如下注意
J1
被改写到T1
后面了,变成了J1`
git push
后,本机repo而远程repo
异常的轻松,一条直线,没有
-f
所以,在不用
之前,先-f
的前提下,想维持树的整洁,方法就是:在git push
之前,先git fetch
,再git rebase
的前提下,想维持树的整洁,方法就是:在git fetch
,再git rebase
。除非只有自己一个人用,不然用
push --force
的都该去死。本地分支和远程分支的绑定(tracking),加上 rebase 策略:
这样一来,更新代码(
pull
)的时候就会自动应用 rebase 而不是产生 merge commit,除非有其他情况产生,比如三方合并造成了冲突需要人共去干预。大部分时候还是很聪明的,只要团队里的习惯都良好,那么可以保持一个非常干净漂亮的树形。其实想让树形结构漂亮些清晰些是有很多办法的,但是首先要取决于团队用的是什么样的 Git Model,对症下药即可。在这里就无法一言以蔽之了。
另外,楼上说得对,慎用
push -f
!这应该是一个git workflow的问题,我们团队也一直在使用rebase保证commit信息的整洁,但不会用到
push -f
这样的操作。关于git workflow就是一个见仁见智的问题了,下面几篇文章你可以看下,再找出一套适合自己团队的就可以了,不过最重要的是要保证团队的每个人都熟悉git,防止犯愚蠢的错误。
如果使用github来团队合作的话,用好pull request,它可以解决
push -f
这种愚蠢问题!每个人提交前,都应该把自己的修改rebase到服务器的最新代码之上,遵守这个规则就不会有任何问题。如果你需要force push,说明你做反了,把服务器代码rebase到你本地分支之上才会需要force push,这是错误的用法。
建议参考 Pro Git 中关于 rebase 的章节 http://git-scm.com/book/zh/Git-%E5%88%86%E6%94%AF-%E5%88%86%E6%94%AF%E7%9A%84%E8%A1%8D%E5%90%88
就我而言。如果 rebase 完后,需要使用
push -f
的话,一定代表该 rebase 操作是不合适。除非你是有意在修改提交历史。不需要push -f啊,如果分支落后就用pull --rebase
楼上的答案都很正,个人认为,除非某个分支只有你自己搞,你怎么rebase都是没有问题的,但是如果你在master或者develop这种分支上来rebase,估计团队里每个人都想拍死你,尤其是对git不熟悉的队友,手足无措是非常正常的表现。
rebase之后 push -f的情况只有一个,就是题主像我一样有强迫症,害怕电脑宕机、系统崩溃这种蛋疼的事情(悲惨的血泪史),完成一个特性commit之后迅速push到远程只属于你的分支上,每天为了拿到develop的新特性,才在自己的分支上rebase develop,重复执行push的操作,这个个人认为是没有问题的,毕竟你只影响了你自己(而你知道这是对的)。
个人认为, 当你在某个分支进行团队合作的时候, 常用rebase真的是不合理。而且容易出问题。慎用 push --force
git rebase 一般自己一个人开发时使用,用来保持提交记录的整洁。一旦上传到github后,不应该使用git rebase,不然被骂死。