文章目录
为什么 git push 会失败?
简单来说,是因为 GitHub 仓库里的代码版本比你电脑上的旧——不对,是新。
这种情况通常发生在:
- 你在 GitHub 网页上直接修改了文件(比如编辑了
README.md) - 你在初始化仓库时勾选了"添加 LICENSE"或"添加 .gitignore",导致远程多了这些文件
- 其他协作者在你上次
pull之后提交了代码
Git 的规则是:你必须先同步远程的所有修改,才能上传你自己的修改。
图解:为什么路径分叉了
</> PLAINTEXT
远程 (Remote): A --> B --> C ← C 是别人提交的
本地 (Local): A --> B --> D ← D 是你刚写的
当远程分支走到了 C,而你的本地还在 B 且想提交 D 时,路径就分叉了。Git 不允许直接覆盖远程的 C。
三种解决方案
✅ 方案一(推荐):变基 git pull --rebase
将远程的新改动"垫"在你的修改之下,提交历史保持一条直线,干净、优雅。
</> BASH
git pull --rebase origin main
git push origin main
🔵 方案二(稳妥):普通合并 git pull
会拉取远程改动,并自动产生一条 Merge branch 'main'... 的合并记录。
</> BASH
git pull origin main
git push origin main
⚠️ 方案三(危险):强制覆盖
仅限个人项目! 确定本地才是最终版本,且不在乎 GitHub 上的改动时使用。
</> BASH
git push origin main --force
深入理解:git pull --rebase 的"移花接木"
为了让你理解得更透彻,把 Git 的提交历史想象成一场火炬接力。
第一步:临时保存
Git 把你本地特有的提交(D)先"摘"下来,存入一个临时区域。
</> PLAINTEXT
本地: A --> B --> C (D 被摘走了)
↑
临时区: [D]
第二步:同步远程
Git 把远程的新提交(C)拉取到你的本地。
</> PLAINTEXT
本地: A --> B --> C
第三步:重新接回(Rebase)
Git 把临时保存的 D "接"在 C 的后面。
</> PLAINTEXT
本地: A --> B --> C --> D 🎉
对比:Merge vs Rebase
| 特性 | git pull(Merge) |
git pull --rebase |
|---|---|---|
| 历史线条 | 产生分叉再合并,多一条 Merge 记录 | 一条直线,极其干净 |
| 可读性 | 复杂项目里历史线会像"麻花" | 提交顺序逻辑清晰 |
| 风险 | 相对安全 | 若有冲突需手动处理后执行 git rebase --continue |
遇到冲突怎么办?
如果 C 和 D 修改了同一行代码,执行 rebase 后会提示 CONFLICT。此时:
</> BASH
# 1. 手动打开冲突文件,解决 <<<<<<< 标记的冲突内容
# 2. 标记冲突已解决
git add <冲突文件>
# 3. 继续 rebase
git rebase --continue
# 4. 最后推送
git push origin main
总结
git pull --rebase的本质:把你的修改"挪"到远程最新进度之后,
伪造出一种"我一直是在最新代码基础上开发"的假象。
这正是它让提交历史如此干净的秘密。对于个人项目和团队协作,这都是值得养成的好习惯。
如有疑问,欢迎在评论区留言。
评论