git pull 可能正在创建提交。如果您进行本地提交,然后在其他人将提交推送到存储库后运行 git pull,Git 会下载其他开发人员的提交,然后将其合并到您的本地分支中。
以后如何避免这些合并提交
您可以使用git pull --rebase 来防止这种情况在未来发生,但变基有其危险,而I recommend avoiding pull altogether。
相反,我鼓励您遵循以下使用模式:
# download the latest commits
git remote update -p
# update the local branch
git merge --ff-only @{u}
# if the above fails with a complaint that the local branch has
# diverged:
git rebase -p @{u}
说明
-
git remote update -p 下载远程存储库中的所有提交并更新远程跟踪分支(例如,origin/master)。它不会触及您的工作目录、索引或本地分支。
-p 参数修剪已删除的上游分支。因此,如果foo 分支在origin 存储库中被删除,git remote update -p 将自动删除您的origin/foo 参考。
git merge --ff-only @{u} 告诉 Git 将上游分支(@{u} 参数)合并到您的本地分支,但前提是您的本地分支可以“快速转发”到上游分支(换句话说,如果它没有分歧)。
-
git rebase -p @{u} 有效地移动了您已经做出但尚未推送到上游分支之上的提交,这消除了创建您试图避免的愚蠢合并提交的需要。这提高了开发历史的线性度,使其更易于查看。
-p 选项告诉 Git 保留合并。这可以防止 Git 线性化被 rebase 的提交。例如,如果您将功能分支合并到 master,这很重要。如果没有-p,功能分支上的每个提交都将在master 上复制,作为git rebase 完成的线性化的一部分。这将使开发历史更难审查,而不是更容易。
当心:git rebase 可能不会按照您的预期执行,因此请在推送之前查看结果。例如:
git log --graph --oneline --decorate --date-order --color --boundary @{u}..
我更喜欢这种方法而不是git pull --rebase,原因如下:
简写:git up 而不是 git pull
为了方便执行上述操作,我建议创建一个名为 up 的别名:
git config --global alias.up '!git remote update -p; git merge --ff-only @{u}'
现在你需要做的就是让你的分支保持最新状态:
git up
而不是git pull。如果您因为本地分支与上游分支不同而收到错误消息,那么这就是您要进行 rebase 的提示。
为什么不git pull --rebase?
运行git pull --rebase 相当于运行git fetch 后跟git rebase。这会尝试快进到新的上游提交,但如果这不可能,那么它将您的本地提交重新定位到新的上游提交。这通常没问题,但要小心:
- 变基是一个高级主题,您应该在变基之前了解其含义。
-
git pull --rebase 不会让您有机会在合并提交之前检查它们。根据上游的变化,很可能 rebase 是错误的操作——rebase --onto、merge、reset 或 push -f 可能比普通的 rebase 更合适。
- (当前)不可能将
--preserve-merges 传递给 rebase 操作,因此任何有意合并的功能分支都将被线性化,重放(并因此复制)所有功能分支提交。
“修复”git pull 创建的现有合并提交
如果您还没有推送由git pull 创建的合并提交,您可以重新设置合并提交。假设您没有进行任何有意的合并(例如,将已经推送的功能分支合并到您当前的分支中),则应该执行以下操作:
git rebase @{u}
上面的命令告诉 Git 选择所有可以从HEAD(当前提交)访问的非合并提交,减去所有从@{u}(这是“上游分支”的简写,即origin/master 如果HEAD 是master),则在上游分支上重播(cherry-pick)它们,然后移动当前分支引用以指向重播提交的结果。这有效地将非合并提交移动到最近的上游提交,从而消除了由git pull 创建的合并。
如果你有一个有意的合并提交,你不想运行git rebase @{u},因为它会重播来自另一个分支的所有内容。处理这种情况要复杂得多,这就是为什么最好使用git up 而完全避免git pull。您可能必须使用reset 撤消由pull 创建的合并,然后执行git rebase -p @{u}。 git rebase 的 -p 参数对我来说并不可靠,因此您最终可能不得不使用 reset 撤消有意合并,将本地分支更新为 @{u},然后重做有意合并(如果有很多毛茸茸的合并冲突,这会很痛苦)。