一、问题起源
在执行 git pull 时,遭遇了经典的"本地与远程分支分叉"(diverged)问题,随后引发了一系列连锁反应。
二、问题演进过程
┌─────────────────────────────────────────────────────────────┐
│ 问题时间线 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 1. git pull 失败 │
│ ↓ │
│ 2. 尝试 stash __pycache__ → 成功 │
│ ↓ │
│ 3. 再次 git pull → 又有新的 __pycache__ 冲突 │
│ ↓ │
│ 4. 多次 stash + pull → 代码同步成功 │
│ ↓ │
│ 5. 远程又有新提交 → 分支分叉 (dev has 1 commit ahead) │
│ ↓ │
│ 6. git pull → 触发三方合并 → 产生 UNMERGED paths │
│ ↓ │
│ 7. 手动解决 __pycache__ 冲突 → git commit │
│ ↓ │
│ 8. ✅ 问题解决 │
│ │
└─────────────────────────────────────────────────────────────┘
三、根本原因分析
1. __pycache__ 已被 Git 跟踪
这是核心问题。虽然 .gitignore 中配置了 __pycache__/,但这些文件在某个历史时刻被 git add 过,导致:
.gitignore 配置 → ❌ 无效(对已跟踪文件)
2. 分支分叉触发合并
本地 dev: A --- B --- C (本地提交)
\
远程 origin/dev: A --- D --- E --- F (远程提交)
当两个分支"分叉"后,git pull 会自动尝试三方合并,此时如果存在冲突文件,就会进入 Unmerged paths 状态。
四、解决方案回顾
方案 A:重新 base(推荐)
bash
# 如果确定本地提交可以 rebase
git rebase origin/dev
优点 :线性历史,更干净
缺点:如果本地有协作的提交,可能影响他人
方案 B:三方合并(本次使用)
bash
# 1. 查看冲突状态
git status
# 2. 解决冲突文件
git add <resolved-files>
# 3. 提交合并
git commit -m "merge: resolve conflicts"
五、本次踩坑总结
| 步骤 | 操作 | 结果 | 评价 |
|---|---|---|---|
| stash pycache | git stash push -- pycache |
部分成功 | 治标不治本 |
| 多次 pull | git pull × 3 |
同步了代码 | 效率低 |
| 解决合并 | git add -u |
冲突解决 | 正确方式 |
六、预防措施
1. 一次性清理所有被跟踪的 __pycache__
bash
#!/bin/bash
# clean_pycache.sh
echo "=== Step 1: Find all tracked pycache files ==="
PYCFILES=$(git ls-files | grep -E '__pycache__|\.pyc$')
echo "$PYCFILES"
echo "=== Step 2: Remove from git index ==="
echo "$PYCFILES" | xargs -I {} git rm --cached {}
echo "=== Step 3: Commit ==="
git commit -m "chore: remove all pycache from git tracking"
2. 配置全局 Gitignore
bash
# 创建全局忽略文件
echo "__pycache__/" >> ~/.gitignore_global
echo "*.pyc" >> ~/.gitignore_global
echo ".DS_Store" >> ~/.gitignore_global
# 配置 Git 使用全局忽略文件
git config --global core.excludesFile ~/.gitignore_global
3. 项目初始化检查清单
□ .gitignore 已配置
□ __pycache__/ 已添加
□ *.pyc 已添加
□ node_modules/ 已添加(前端项目)
□ .env 已添加
□ 运行 git status 确认无异常文件
七、Git 分支状态图解
正常状态:
A --- B --- C origin/dev, dev (同一位置)
分叉状态:
A --- B --- C --- D origin/dev
\
E --- F dev (领先 2 个提交)
或
A --- B --- C --- D --- E --- F origin/dev (领先)
\
G dev (1 个提交)
合并后:
A --- B --- C --- D --- E --- F origin/dev
\ /
G --------------- dev (合并提交)
八、经验教训
┌─────────────────────────────────────────────────────────────┐
│ 核心要点 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 1. .gitignore 只对未跟踪文件生效 │
│ → 已跟踪文件必须 git rm --cached │
│ │
│ 2. stash 是临时方案,不是根本解决 │
│ → 应该一次性清理 + commit │
│ │
│ 3. 分支分叉时优先考虑 rebase │
│ → 历史线性、冲突集中、易于追踪 │
│ │
│ 4. 合并冲突时优先保留"删除"意愿 │
│ → __pycache__ 本就不该被跟踪 │
│ │
└─────────────────────────────────────────────────────────────┘
九、后续建议
- 立即执行 :清理项目中所有被跟踪的
__pycache__ - 长期维护 :新项目初始化时先配置
.gitignore - 团队规范:在代码审查中检查是否意外提交了缓存文件
