一个人开发时,Git 只是备份工具;两个人以上开发时,Git 才真正显示威力。但协作必然带来一个问题:你和同事同时改了同一个文件,怎么办?本文用一个双人模拟项目走完完整协作流程:分支策略、先拉后推、制造并解决冲突、merge 与 rebase 的选择,最后过一遍 Code Review。

1. 协作的基本模型

多人协作最常见的是共享仓库模式:所有人都有同一个远程仓库的推送权限,各自在功能分支上开发,完成后合并回主分支。流程是:

git checkout -b feature/login
# ……开发、提交……
git push -u origin feature/login

git checkout -b 创建并切换到新分支;git push -u 把新分支推到远程并建立追踪关系。功能分支的名字要能说明意图,比如 feature/login、fix/typo,这样别人一眼就知道你在干什么。

推荐的分支策略很简单:主分支 main 永远保持可发布状态,开发都在功能分支上做。这样即使某人的功能做了一半,也不会污染别人的代码。

2. 先拉后推:协作的交通规则

两个人都基于同一份代码开发,必然出现"你推的时候,远程已经有别人的新提交"的情况。此时直接 git push 会被拒绝:

git push
# ! [rejected] main -> main (fetch first)
# 别慌,这是 Git 在保护你
git pull --rebase
git push

看到 rejected 不是错误:直接覆盖会把同事的提交弄丢。正确的动作是先拉后推:git pull --rebase 先把远程的新提交拉下来,再把你的本地提交"重放"到最新代码之上,历史是一条干净的直线,然后再 push 就顺理成章了。

3. 制造一场冲突

冲突的根源是两个人改了同一个文件的同一处。Git 很聪明,能自动合并不同位置的修改;只有改到同一行时,它才不知道听谁的,把决定权交给你。来亲手制造一个,先建一个文件推上去:

echo "print('你好')" > hello.py
git add hello.py && git commit -m "add hello"
git push

# —— 终端 A:改了问候语并推送 ——
echo "print('早上好')" > hello.py
git commit -am "A 改的问候语"
git push

# —— 终端 B:晚一步,也改了同一行 ——
echo "print('晚上好')" > hello.py
git commit -am "B 改的问候语"
git pull --rebase

第二个终端(终端 B)的 git pull --rebase 会停下来,告诉你 CONFLICT:两个提交都改了 print('你好') 这一行,Git 不知道该保留哪个。注意 git commit -am 中的 -a 会自动暂存已跟踪文件的修改,但前提是文件已经被跟踪过。

4. 解决冲突

冲突发生时,Git 会在文件里插入冲突标记。打开 hello.py 会看到:

<<<<<<< HEAD
print('早上好')
=======
print('晚上好')
>>>>>>> B 改的问候语

<<<<<<< HEAD 和 ======= 之间是当前分支(你的)版本,======= 和 >>>>>>> 之间是对方分支的版本。你的任务是手动决定最终内容——可以选 A、选 B,或者两行都留。把冲突标记删掉,写成想要的样子:

print('早上好')
print('晚上好')

改完后告诉 Git"我解决了":

git add hello.py
git rebase --continue

git add 标记冲突已解决,git rebase --continue 让 rebase 继续把后面的提交重放完,然后正常 git push 即可。小技巧:冲突越少越好,方法就是勤 git pull,别让本地分支落后远程太久。

5. merge 还是 rebase

合并分支有两条路线,风格截然不同:

方式历史形态特点
git merge保留分叉,多一个合并提交忠实记录"发生过什么",适合大型团队
git rebase线性历史,没有分叉历史清爽,但会改写提交

实际项目里两者常配合使用:功能分支开发时,定期 git rebase main 把主分支的新代码合进来,保持分支不落后;功能完成合并回 main 时,用 git merge 保留一次合并记录:

git checkout main
git pull
git merge feature/login

规则只有一条:rebase 只用于本地未推送的分支。已经推送出去的分支被 rebase,等于改写公共历史,队友会崩溃。

6. Code Review 与 Pull Request

在 GitHub 或 GitLab 上,功能分支通常不直接合并,而是走 Pull Request(MR)流程:推分支 → 网页上发起 PR → 同事审查代码、留言 → 通过后合并。这套流程叫 Code Review,是团队质量的第一道防线:

git push -u origin feature/login
# 在 GitHub 上点击 Compare & pull request
# 填写描述,指派 reviewer,等待审查

PR 里可以直接对某一行代码留言讨论,修改后重新 push,PR 会自动更新。审查通过后,可以选择 Merge(保留合并提交)或 Squash and merge(把整个分支压成一个提交,历史最干净)。

7. 总结与练习

多人协作的三个关键词:分支隔离、先拉后推、冲突可控。功能分支开发、git pull --rebase 保持同步、冲突时手动裁决、rebase 只碰本地分支、合并走 PR 审查,这套流程足够支撑一个十人团队。练习:

💡 冲突不是坏事,说明大家在认真改代码。关键是解决冲突前先理解对方为什么这么改——必要时直接问,比闷头删标记靠谱得多。