最近公司来了一个研发实习生,每次拉取代码直接使用git pull,被版本管理员在群里diss了一顿,说直接使用git pull会导致git历史混乱, 自己觉得很委屈,向我诉苦说管理员没事找他事,录取去代码一直使用git pull还有有错吗? 难道其他人不是使用git pull吗? 我看着他一脸的委屈,知道他不清楚git pull后面带上其他参数,下面我们就这个事情来看看直接git pull有什么问题。
git pull里的内在逻辑
几乎所有的开发都知道git pull 命令用于从远程仓库获取最新的更改并合并到当前分支,但估计只有部分知道它其实是 git fetch
和 git merge
的组合。
下面我们逐个看看git fetch和git merge的具体使用和结果:
git fetch
git fetch
命令从远程仓库获取最新的代码到本地,但不会自动合并代码。
git fetch <remote> <branch>
我们看下具体示例:从名为 origin 的远程仓库获取最新代码:
git fetch origin
git merge
git merge
相信大家不陌生,就是将另一个分支的更改合并到当前分支。
通常在使用 git fetch 获取了最新的远程更改后,使用 git merge 将这些更改合并到当前分支。
git merge <branch>
git pull 的过程发生了什么
当我们远端有代码更新,我们需要拉取时
当我们执行git pull的时候,相当于以此执行了
- git fetch :从云端拉取最新代码
- git merge:将云端代码与本地代码合并
git merge,看下图中确实云端代码合并到了本地
接下来讲讲为什么git pull会导致git 历史混乱
假设A和B两个同事在 master 分支上进行开发,他们都拉取了mater的B节点开发。
A同事开发的快,提交了新的分支,现在远程分支最新是C节点了。
随后,B同事也开发完毕了,但B同事的代码落后远端仓库了,所以B同事需要运行git pull拉取代码。这会从远程仓库获取最新C节点的代码,和B同事本地的代码合并,产生新的节点D。
最后,B同事使用git push推送代码,远程master分支就会产生一个新的D节点。
这种历史记录包含了多个分叉点和合并提交,就会导致git历史看起来非常混乱,如下面这样:
那如何才能保证git历史的线性
如何能做到像下面这样清晰的git线性历史?
非常简单,我们只需要使用rebase(变基)命令即可!在正式的介绍命令的使用前,我们先说说什么是变基!
rebase
是 Git 中的一种操作,用于将一个分支的提交历史“重新应用”到另一个分支上。与 merge
不同,rebase
不会创建新的合并提交,而是将提交历史“重放”到目标分支上,从而保持历史的线性。
Rebase 的工作原理
找到共同祖先
Git 首先会找到当前分支和目标分支的共同祖先提交。这个共同祖先是两个分支最后一次分叉的地方。
保存当前分支的提交
Git 会将当前分支上的所有提交保存为临时文件。这些提交将被“重放”到目标分支上。
切换到目标分支
Git 会将当前分支的指针移动到目标分支的最新提交上。
重新应用提交
Git 会将之前保存的提交依次应用到目标分支上。如果有冲突,Git 会暂停 rebase 过程,让你解决冲突。
完成 rebase
当所有提交都成功应用后,rebase 过程完成,当前分支的提交历史将变为线性。
简单来说,rebase的作用就是永远会让我们本地的代码处于最新状态。
比如,我们一开始是使用B节点开发代码的,开发到B2时,此时远程已经有人推送了C节点。
在B2节点使用rebase变基,会让我们的B1节点和B2节点位于C节点上,产生的git历史是这样:
使用rebase变基后,git永远只有一条线性历史,非常直观
rebase命令使用
rebase
的使用非常简单,我们只需要在git pull的时候,添加上额外命令即可!
git pull --rebase
如何让git pull自动变基
每次提交代码都使用git pull --rebase
命令繁琐而且容易出错,我们可以全局设置git pull默认使用变基的方式,一次设置永久生效。
// git pull默认使用变基操作
git config --global pull.rebase true
直接运行上面的命令即可设置成功:
如果不像在git pull时不想rebase,还是喜欢git pull的时候merge,那么使用下面的命令
// git pull默认使用合并操作
git config --global pull.rebase false
运行下面的命令:
rebase自动变基的问题
自动变基会面临一个额外的问题:就是如果你本地文件有更改的话,变基会失败,因为变基前服务区必须是干净的。
有两种方法解决这个问题
- git pull前,先使用git commit暂存代码
- git pull前,先将使用 git stash将保存
git commit大家肯定在熟悉不过,这里简单介绍下git stash
。
git stash
是一个有用的 Git 命令,它允许你将当前工作目录中的未提交更改(包括已暂存和未暂存的更改)保存到一个栈(stash)中,并将工作目录恢复到干净的状态。这在你需要在多个任务之间切换但又不想提交不完整的代码时非常有用
它的用法非常简单:
假设我们代码进行了更改,但没有完全改好,我们git pull前,可以先执行
git stash
此时,我们修改的代码就看不见了。
此时,我们可以使用git pull拉取代码,拉取完代码,我们使用下面的命令
git stash pop
此时,我们修改的代码又可以看见了!
冲突问题解决
如果使用git pull有冲突,则合并完冲突之后,执行一下 git rebase --continue 就好了,其它和原先的用法没有任何区别。
最后的小总结
本篇文章我们介绍了git pull
的用法,明白了它有merge和rebase两种模式。默认情况下,它使用的是merge。使用merge的方式拉取代码会导致git历史变得复杂,不利于维护和溯源。
因此,建议使用rebase的方式拉取代码。我们只需要做如下设置即可
git config --global pull.rebase true
设置完成后,你就可以放心的使用git pull了,不用在被git老手或者版本管理员给diss咱们git命令不精通了^_^, 下面这张图大家可以详细看看,理解下git的其他命令
祝大家git顺利,分支大吉