[TOC] #### 1. 命令介绍 --- `git pull` 用于从远程仓库获取代码,然后合并到本地当前分支。它本质上是 git fetch 和 git merge 的合并操作 + git fetch 仅下载远程更新,不合并到本地分支 + git merge 将远程更新合并到本地分支 高级选项 ```bash # 使用变基方式合并,避免产生合并提交 git pull --rebase # 只允许快速合并,防止非快速合并产生额外提交 git pull --ff-only ``` 配置选项 ```bash # 使用 git pull 拉取远程代码默认采用变基策略 git config --global pull.rebase true # 仅允许快速合并(并不常用) git config --global pull.ff only ``` #### 2. 合并方式 --- 为了学习该命令的用法,我们创建一个远程仓库,本文使用的是国内著名代码托管平台 gitee 远程仓库创建之后,我们在自己电脑创建一个本地仓库,并且生成一条提交记录,推送到远程仓库 ```bash git init touch 1.txt git add 1.txt git commit -m '新增1.txt' git remote add origin git@gitee.com:u1s1it/test-1.git git push -u origin master ``` 为了方便区分推送者身份,我们假设有两个开发者,一个是同事小张,一个是我们自己 现在同事小张和我们自己都将远程仓库拉取到本地进行开发,起点都是 “新增1.txt” 这个提交记录 于是,小张和我们自己都开始了各自所分配的功能模块进行开发 ```bash git clone git@gitee.com:u1s1it/test-1.git ``` 小张的功能开发完成了,然后他将代码提交到了本地库,并且推送到了远程仓库 ```bash touch 2.txt git add 2.txt git commit -m '新增2.txt' git push ``` 我们自己的功能也开发完了,此时也将代码提交到了本地库,但是还没有推送到远程库 ```bash touch 3.txt git add 3.txt git commit -m '新增3.txt' ``` 小张、我们自己、远程仓库的提交记录情况如下所示,下一步我们应该将自己的开发的功能 3.txt 推送到远程库 ```plaintext 小张本地库 新增1.txt -> 新增2.txt 远程仓库 新增1.txt -> 新增2.txt 我们自己本地库 新增1.txt -> 新增3.txt ``` 在将自己的代码推送到远程仓库之前,你看到远程库有提交记录,就会想到应该先拉取远程库记录,再将本地库的代码一起推送到远程库,那么你就可能直接执行以下命令 ```bash git pull ``` 然后就会看到以下错误信息,原因是提交记录存在分歧,git 不知道以哪种方式去合并提交记录 ```bash remote: Enumerating objects: 3, done. # ... 推送进度信息 From gitee.com:u1s1it/test-1 925a9c3..8389f6a master -> origin/master hint: You have divergent branches and need to specify how to reconcile them. hint: You can do so by running one of the following commands sometime before hint: your next pull: hint: hint: git config pull.rebase false # merge hint: git config pull.rebase true # rebase hint: git config pull.ff only # fast-forward only hint: hint: You can replace "git config" with "git config --global" to set a default hint: preference for all repositories. You can also pass --rebase, --no-rebase, hint: or --ff-only on the command line to override the configured default per hint: invocation. fatal: Need to specify how to reconcile divergent branches. ``` 关于合并方式,已经通过提示告知我们了,我们依次来看一下,三种方式的区别 ##### 合并策略 合并策略是默认 `git pull` 默认的策略方式,但是默认的并不一定就是最好的 运行以下命令后,在执行 `git pull` 时采用合并策略(merge),而不是变基策略(rebase) ```bash # 当前项目拉取代码合并时,采用 merge 策略 git config pull.rebase false ``` 然后再运行 `git pull` 就可以发现没有报错了,但是会多出一个 Merge branch 的提交记录,这就是合并策略的缺点 ```plaintext Merge branch 'master' of gitee.com:u1s1it/test-1 # Please enter a commit message to explain why this merge is necessary, # especially if it merges an updated upstream into a topic branch. # # Lines starting with '#' will be ignored, and an empty message aborts # the commit. ``` 使用 `git log` 命令查看提交记录,发现确实多了一条无用的提交记录(此时可以正常推送到远程仓库了) ```plaintext 新增1.txt -> 新增2.txt -> 新增3.txt -> Merge branch 'master' .... ``` ##### 变基策略 运行以下命令设置当前项目配置,再执行 `git pull` 时采用变基策略(rebase) ```bash # 当前项目拉取代码合并时,采用 rebase 策略 git config pull.rebase true ``` 再运行 `git pull` 就可以发现只有一个简单的输出,下面是其输出结果,代表已经变基合并成功 ```plaintext Successfully rebased and updated refs/heads/master. ``` 也可以在拉取远程代码时,使用参数指定变基策略方式合并,就无需设置配置项了 ```bash git pull --rebase ``` 使用 `git log` 命令查看提交记录,可以发现完美合并提交记录(没有多余的 Merge branch 记录) ```plaintext 运行 git pull 命令之前 新增1.txt -> 新增3.txt 运行 git pull 命令之后(将同事小张的提交记录插入到了自己提交记录之前) 新增1.txt -> 新增2.txt -> 新增3.txt ``` ##### 快进合并 合并代码可以理解为有两种场景:快速合并(fast-forward merge)、存在分叉的提交(three way merge) + 当远程分支的提交是本地分支的提交的直接延续时,执行的是快速合并 + 如果存在分叉,也就是本地和远程仓库都有新的提交,执行的是较为复杂的三路合并,[合并方式详解](https://www.itqaq.com/index/375.html) 该命令的作用:是否仅允许快速合并。设置该配置后,存在交叉的提交记录将无法进行合并 适用场景:希望保持线性提交记录,避免合并提交的情况,如:保护主分支(main) ```bash # 仅允许快速合并 git config pull.ff only # 删除配置 git config --unset pull.ff only ```