背景:
我们发现很多同学习惯性用git pull拉取远端仓库代码,
但是这会带来一个问题,如果有了本地commit再git pull的话,会产生一个merge commit,
这样的merge commit会导致git log分支节点很多,很乱。
首先聊一聊git pull,git merge,git rebase这些常听到的命令吧,初入git的同学一定还是一脸蒙,尤其是git rebase,算是git的中高阶操作了。
git fetch, git pull, git rebase
1. git fetch和git pull
git pull = git fetch + git merge
git pull
的过程可以理解为:
git fetch origin master //从远程主机的master分支拉取最新内容
git merge FETCH_HEAD //将拉取下来的最新内容合并到当前所在的分支中
将远程主机的某个分支的更新取回,并与本地指定的分支合并,完整格式可表示为:(默认的远程主机别名为origin)
$ git pull <远程主机别名> <远程分支名>:<本地分支名>
如果远程分支是与当前分支合并,则冒号后面的部分可以省略:
$ git pull <远程主机名> <远程分支名>
2. git merge
有一个远程仓库origin:
本地在此基础上又进行了两次提交:
这时候其他人进行了一次远程push:
因为git是分布式的,原则上可以不用连服务器,所以此时本地并不知道远程分支已经变更(本地的origin/master已经过时):
git fetch命令会将远程最新的版本拉取到本地,但是并不会影响本地的分支线:git fetch <远程主机名> <远程分支>
git merge会将本地和远程的最新提交混合起来,并生成新的最新提交(混合并解决冲突后的提交):
git pull命令等于git fetch + git meger命令。
3. git rebase
我们再看下上面git fetch命令后的本地状态:
这时候我们并不想混合提交,而是想在C2的基础上直接提交L2和L3,这时候在提交历史线上不会有分支线。这个可以用git rebase命令实现:
rebase(换基命令)说明:
git rebase origin/master #将当前分支换基到origin/master指向的分支。具体为先将本分支的提交全部暂存,然后从origin/master指向的分支开始依次应用暂存的提交,若出现冲突会要求解决,解决后用git add暂存,然后git rebase --continue继续,直到解决完所有冲突,换基操作完成。
git rebase origin/master dev #将dev分支的所有提交换基到origin/master指向的提交
4. git pull vs git pull --rebase
git pull
是
git pull --merge
的简写。
git pull
与
git pull --rebase
的关系如下:
git pull = git fetch + git merge
git pull --rebase = git fetch + git rebase
可以看出merge和rebase的区别:
- merge 会多出一次 commit生成一个新节点,rebase不会。
- merge 的提交树是非线性的,rebase 的提交树是线性的(通过重写提交历史)。
遇到的问题和使用场景
当我在提议开发同学平时使用git pull --rebase来更新代码时,却遇到了几个问题:
1)git rebase会导致时间日志时间错乱。
git merge会按照时间顺序进行commit的排练,但是git rebase会把本地的提交直接变基到当前最新,所以会导致老的提交
在当前最新的提交前面。
2)git rebase时本地不能有未提交的文件
当本地有未暂存的文件时,git rebase会报error。
$ git pull --rebase
error: cannot pull with rebase: You have unstaged changes.
error: please commit or stash them.
但是使用git pull却不会报错。
这个时候我们或者要提交文件,或者用git stash
git stash # 存储工作区
git pull --rebase # 更新代码
git stash pop # 恢复工作区
3)git rebase时冲突解决
会出现如下报错:
error: could not apply fa39187... something to add to patch A
When you have resolved this problem, run "git rebase --continue".
If you prefer to skip this patch, run "git rebase --skip" instead.
To check out the original branch and stop rebasing, run "git rebase --abort".
Could not apply fa39187f3c3dfd2ab5faa38ac01cf3de7ce2e841... Change fake file
步骤:
a) 修改冲突文件:打开冲突文件,搜索:<<<<<< ,git 会用<<<<<<,======,>>>>>>>把冲突的部分标记出来,你可以选择保留某些行,或者删除,或者更改。记得把<<<<<<<, =======, >>>>>>>这些删除掉。
b) 解决完冲突后,执行git add命令标记冲突已解决
c) 继续rebase:git rebase --continue (后续的过程中还有可能产生冲突,解决方法同上)
所以,当本地commit很多时执行git rebase是一件比较痛苦的事情。
总结
综上,我们还是根据不同的场景合理的使用git pull 和 git pull --rebase。
我目前给开发同学的建议是:本地有单个commit时建议用git pull --rebase, 本地有多个commit时建议用 git pull。
对了,前提条件是,远端仓库是可以直接push的,而不是gerrit的那种push成code-review的那种。
如果是gerrit上要生成code-review,那么必定是要使用git pull --rebase的。
版权归原作者 送你一朵小莲花 所有, 如有侵权,请联系我们删除。