项目介绍

Git 是由 Linus Torvalds 于 2005 年创建的分布式版本控制系统,最初用于管理 Linux 内核开发。如今,Git 已成为全球软件开发的标准版本控制工具,被超过 95% 的开发者使用。

Git 的核心设计理念是速度、数据完整性和对分布式非线性工作流的支持。每个 Git 目录都是一个完整的仓库,包含完整的版本历史和追踪能力,不依赖网络或中央服务器。在 GitHub 上拥有超过 53,000 Star,是开发者工具领域最重要的基础设施项目之一。

项目信息详情
创建者Linus Torvalds / 社区维护
GitHub Stars53,000+
开源协议GPL-2.0
核心语言C
架构模式分布式(Distributed)
官方网站git-scm.com
最新版本Git 2.x(持续更新)
一句话理解:Git 是一个"时间机器" — 它记录代码的每一次变化,让你可以在任意时间点之间自由穿梭,多人同时修改同一份代码也不会互相覆盖。

Git vs SVN vs Mercurial vs Perforce

对比维度 Git SVN Mercurial Perforce
架构模式 分布式 集中式 分布式 集中式
离线工作 完全支持 不支持 完全支持 部分支持
分支性能 极快(指针切换) 慢(目录复制) 中等
合并能力 强大灵活 较弱 良好 良好
学习曲线 中等偏陡 简单直观 简单 中等
大文件处理 需 Git LFS 原生支持 需扩展 原生支持
超大仓库 需 sparse-checkout 支持 较弱 专为大仓库设计
社区生态 最大最活跃 较大 逐渐萎缩 企业为主
托管平台 GitHub / GitLab / Bitbucket SVN 服务器 Bitbucket(已停用) Helix Core
开源协议 GPL-2.0 免费 Apache 2.0 免费 GPL-2.0 免费 商业付费
市场占有率 ~95% ~3% ~1% ~1%
总结:Git 凭借分布式架构、极速分支切换和庞大的社区生态,已经成为版本控制的事实标准。除非你的团队有特殊需求(如超大二进制资产管理),否则 Git 是最佳选择。

安装配置

系统 1 macOS 安装

macOS 自带 Git(Xcode Command Line Tools),也可通过 Homebrew 安装最新版:
# 方式一:安装 Xcode 命令行工具(自带 Git)
xcode-select --install

# 方式二:Homebrew 安装最新版(推荐)
brew install git

# 验证安装
git --version

系统 2 Linux 安装

各主流 Linux 发行版均可通过包管理器安装:
# Ubuntu / Debian
sudo apt update && sudo apt install git

# CentOS / RHEL / Fedora
sudo dnf install git

# Arch Linux
sudo pacman -S git

# 验证安装
git --version

系统 3 Windows 安装

Windows 用户推荐使用 Git for Windows:
1. 访问 git-scm.com/download/win 下载安装包
2. 运行安装程序,建议勾选"Git Bash"和"将 Git 添加到 PATH"
3. 或使用 winget:
winget install Git.Git
安装完成后打开 Git Bash 或 PowerShell 运行 git --version 验证。

配置 Git 全局配置

安装完成后,设置你的用户信息(每次提交都会使用):
# 必须配置:用户名和邮箱
git config --global user.name "你的名字"
git config --global user.email "你的邮箱@example.com"

# 推荐配置
git config --global init.defaultBranch main          # 默认分支名
git config --global core.autocrlf input              # 换行符处理(macOS/Linux)
git config --global core.autocrlf true               # 换行符处理(Windows)
git config --global pull.rebase true                  # pull 时使用 rebase
git config --global core.editor "code --wait"         # 使用 VS Code 作为编辑器
git config --global merge.conflictstyle diff3         # 三方合并冲突样式
git config --global diff.algorithm histogram          # 更优的 diff 算法

# 查看所有配置
git config --global --list

SSH 配置 SSH 密钥

SSH 密钥让你无需每次输入密码即可推送代码:
# 1. 生成 SSH 密钥对(推荐 Ed25519)
ssh-keygen -t ed25519 -C "你的邮箱@example.com"

# 2. 启动 ssh-agent
eval "$(ssh-agent -s)"

# 3. 添加私钥
ssh-add ~/.ssh/id_ed25519

# 4. 复制公钥(添加到 GitHub/GitLab 设置中)
cat ~/.ssh/id_ed25519.pub

# 5. 测试连接
ssh -T git@github.com
提示:如果你使用多个 Git 托管平台,可以在 ~/.ssh/config 中为不同平台配置不同的密钥。

基础操作

init 初始化仓库

# 在当前目录创建新仓库
git init

# 在指定目录创建新仓库
git init my-project

# 克隆远程仓库
git clone https://github.com/user/repo.git

# 克隆并指定目录名
git clone https://github.com/user/repo.git my-folder

# 浅克隆(只获取最近 1 次提交,适合大仓库)
git clone --depth 1 https://github.com/user/repo.git

add 暂存文件

# 暂存单个文件
git add file.txt

# 暂存多个文件
git add file1.txt file2.txt

# 暂存当前目录所有变更
git add .

# 暂存所有已追踪文件的变更(不含新文件)
git add -u

# 交互式暂存(按补丁块选择)
git add -p
提示:git add -p 可以让你逐块选择要暂存的修改,非常适合将一次大修改拆分为多个有意义的提交。

commit 提交变更

# 提交暂存区的内容
git commit -m "feat: 添加用户登录功能"

# 跳过暂存直接提交所有已追踪文件的变更
git commit -am "fix: 修复空指针异常"

# 修改上一次提交(补充文件或修改信息)
git commit --amend -m "feat: 添加用户登录和注册功能"

# 空提交(触发 CI/CD)
git commit --allow-empty -m "chore: trigger CI"
注意:--amend 会修改提交历史。如果该提交已推送到远程,不要使用 amend,除非你确定没有其他人基于此提交工作。

push 推送到远程

# 推送当前分支到远程
git push

# 首次推送并设置上游追踪
git push -u origin main

# 推送所有分支
git push --all origin

# 推送标签
git push origin v1.0.0
git push --tags

# 强制推送(危险!仅在必要时使用)
git push --force-with-lease
警告:永远不要在共享分支上使用 git push --force。如果必须强制推送,请使用 --force-with-lease,它会在远程有新提交时拒绝推送,防止覆盖他人的工作。

pull 拉取远程更新

# 拉取并合并远程更新
git pull

# 拉取并使用 rebase(推荐,保持线性历史)
git pull --rebase

# 仅获取远程更新(不合并)
git fetch

# 获取所有远程的更新
git fetch --all

# 获取并清理已删除的远程分支引用
git fetch --prune

status 查看状态

# 查看工作区和暂存区状态
git status

# 简洁输出
git status -s

# 显示分支信息
git status -sb
状态标识说明:
M — 已修改   A — 新添加   D — 已删除   ?? — 未追踪   R — 重命名

log 查看历史

# 查看提交历史
git log

# 简洁的单行模式
git log --oneline

# 图形化显示分支关系
git log --oneline --graph --all

# 查看某个文件的修改历史
git log --follow -p file.txt

# 按作者过滤
git log --author="张三"

# 按时间范围过滤
git log --since="2024-01-01" --until="2024-12-31"

# 搜索提交信息
git log --grep="bug fix"

diff 查看差异

# 查看工作区与暂存区的差异
git diff

# 查看暂存区与上次提交的差异
git diff --staged

# 比较两个分支
git diff main..feature

# 比较两个提交
git diff abc1234..def5678

# 仅显示变更的文件名
git diff --name-only

# 显示统计信息
git diff --stat

分支管理

1 创建与切换分支

Git 的分支本质上是一个指向提交对象的可变指针,创建和切换分支几乎是瞬时操作:
# 查看所有分支
git branch          # 本地分支
git branch -a       # 包含远程分支

# 创建新分支
git branch feature-login

# 切换分支
git checkout feature-login
git switch feature-login       # Git 2.23+ 推荐

# 创建并切换(一步完成)
git checkout -b feature-login
git switch -c feature-login    # Git 2.23+ 推荐

# 从指定提交创建分支
git checkout -b hotfix abc1234

# 删除已合并的分支
git branch -d feature-login

# 强制删除未合并的分支
git branch -D feature-login

# 删除远程分支
git push origin --delete feature-login

2 合并分支(merge)

将一个分支的修改合并到当前分支:
# 切换到目标分支
git switch main

# 合并 feature 分支
git merge feature-login

# 使用 --no-ff 强制创建合并提交(推荐)
git merge --no-ff feature-login -m "merge: 合并登录功能"

# 放弃正在进行的合并
git merge --abort

# 查看已合并/未合并的分支
git branch --merged
git branch --no-merged
提示:使用 --no-ff 可以保留分支的历史记录,方便日后追踪某个功能是在哪个分支上开发的。

3 变基(rebase)

Rebase 将当前分支的提交"移植"到目标分支的最新提交之上,产生线性历史:
# 将 feature 分支变基到 main 的最新提交
git switch feature-login
git rebase main

# 发生冲突时
# 1. 解决冲突文件
# 2. git add 已解决的文件
# 3. 继续变基
git rebase --continue

# 跳过当前冲突的提交
git rebase --skip

# 取消变基
git rebase --abort
黄金法则:永远不要对已经推送到远程的公共分支执行 rebase。Rebase 会重写提交历史,可能导致其他协作者的工作出现问题。

4 Cherry-pick(摘取提交)

将指定的提交应用到当前分支,常用于将 bug 修复从一个分支移植到另一个分支:
# 摘取单个提交
git cherry-pick abc1234

# 摘取多个提交
git cherry-pick abc1234 def5678

# 摘取一个范围的提交(不含起始提交)
git cherry-pick abc1234..def5678

# 只应用变更不自动提交
git cherry-pick --no-commit abc1234

# 发生冲突时
git cherry-pick --continue   # 解决后继续
git cherry-pick --abort      # 放弃

5 Git Flow 工作流

Git Flow 是最经典的分支管理模型,适合有明确发布周期的项目:
# 分支模型
main        ── 生产环境代码,只接受合并
develop     ── 开发主线,功能分支从这里分出
feature/*   ── 功能分支,完成后合并回 develop
release/*   ── 发布分支,用于发布前的最终修复
hotfix/*    ── 热修复分支,从 main 分出,修复后同时合并回 main 和 develop
# 使用 git-flow 工具
git flow init
git flow feature start login
git flow feature finish login
git flow release start v1.0.0
git flow release finish v1.0.0
git flow hotfix start fix-crash
git flow hotfix finish fix-crash

6 Trunk-Based Development

主干开发是一种更简洁的分支策略,所有开发者都在主干(main)上工作:
# 核心原则
1. 只有一个长期分支(main/trunk)
2. 功能分支生命周期极短(1-2 天内合并)
3. 使用 Feature Flag 控制未完成功能的可见性
4. 频繁集成,每天至少合并一次
适用场景:Trunk-Based Development 适合持续部署(CD)环境,团队规模较小或有成熟的自动化测试体系的项目。Google、Meta 等大厂广泛使用此模式。

7 解决合并冲突

当两个分支修改了同一文件的同一部分时,Git 无法自动合并,需要手动解决:
# 冲突标记格式
<<<<<<< HEAD
你在当前分支的修改
=======
来自另一个分支的修改
>>>>>>> feature-branch
# 解决步骤
1. 编辑冲突文件,保留正确的内容
2. 删除冲突标记(<<<, ===, >>>)
3. git add 已解决的文件
4. git commit(合并)或 git rebase --continue(变基)
# 使用可视化工具解决冲突
git mergetool

# 常用配置
git config --global merge.tool vscode
git config --global mergetool.vscode.cmd 'code --wait --merge $REMOTE $LOCAL $BASE $MERGED'

8 暂存工作区(stash)

临时保存当前工作区的修改,切换到其他分支处理紧急任务后再恢复:
# 暂存当前修改
git stash

# 暂存并添加描述
git stash push -m "正在开发登录功能"

# 包含未追踪文件
git stash -u

# 查看暂存列表
git stash list

# 恢复最近的暂存(保留暂存记录)
git stash apply

# 恢复并删除暂存记录
git stash pop

# 恢复指定的暂存
git stash apply stash@{2}

# 删除所有暂存
git stash clear

9 标签管理(tags)

标签用于标记重要的版本发布节点:
# 创建轻量标签
git tag v1.0.0

# 创建附注标签(推荐)
git tag -a v1.0.0 -m "正式发布 1.0.0 版本"

# 为历史提交打标签
git tag -a v0.9.0 abc1234 -m "补打 0.9.0 标签"

# 查看所有标签
git tag -l

# 查看标签详情
git show v1.0.0

# 推送标签到远程
git push origin v1.0.0
git push origin --tags

# 删除本地标签
git tag -d v1.0.0

# 删除远程标签
git push origin --delete v1.0.0

10 Worktree 与 Bisect

Git Worktree — 同时在多个分支上工作,无需切换:
# 创建新的工作树
git worktree add ../hotfix-branch hotfix/fix-crash

# 列出所有工作树
git worktree list

# 删除工作树
git worktree remove ../hotfix-branch
Git Bisect — 二分查找引入 bug 的提交:
# 开始二分查找
git bisect start

# 标记当前版本有 bug
git bisect bad

# 标记某个已知正常的版本
git bisect good v1.0.0

# Git 会自动切换到中间提交,测试后标记
git bisect good   # 或 git bisect bad

# 找到问题提交后结束
git bisect reset

# 自动化二分查找(使用测试脚本)
git bisect start HEAD v1.0.0
git bisect run ./test.sh

高级技巧

高级 1 交互式变基(Interactive Rebase)

整理提交历史的最强工具,可以合并、拆分、重排、修改提交:
# 交互式变基最近 5 个提交
git rebase -i HEAD~5
编辑器中会显示:
pick abc1234 feat: 添加用户模型
pick def5678 fix: 修复拼写错误
pick ghi9012 feat: 添加登录页面
pick jkl3456 fix: 修复样式
pick mno7890 feat: 添加验证逻辑
可选操作:
pick — 保留该提交
reword — 修改提交信息
edit — 暂停以修改提交内容
squash — 合并到上一个提交(保留信息)
fixup — 合并到上一个提交(丢弃信息)
drop — 删除该提交
注意:交互式变基会重写历史,仅用于尚未推送的本地提交,或你独自工作的功能分支。

高级 2 Reflog(引用日志)

Reflog 记录了 HEAD 和分支引用的每一次变动,是误操作后的"后悔药":
# 查看 HEAD 的 reflog
git reflog

# 查看特定分支的 reflog
git reflog show main

# 恢复到 reflog 中的某个状态
git reset --hard HEAD@{3}

# 找回已删除的分支
git reflog
# 找到删除前的提交哈希
git checkout -b recovered-branch abc1234

# 找回 rebase 前的状态
git reflog
git reset --hard HEAD@{5}  # 回到 rebase 之前
提示:Reflog 默认保留 90 天。只要在这个期限内,几乎任何误操作都可以通过 reflog 恢复。它是你最后的安全网。

高级 3 子模块(Submodules)

在一个 Git 仓库中嵌入另一个 Git 仓库,适合管理共享依赖:
# 添加子模块
git submodule add https://github.com/user/lib.git libs/lib

# 克隆含子模块的仓库
git clone --recurse-submodules https://github.com/user/project.git

# 已克隆的仓库初始化子模块
git submodule init
git submodule update

# 更新所有子模块到最新
git submodule update --remote --merge

# 删除子模块
git submodule deinit libs/lib
git rm libs/lib
rm -rf .git/modules/libs/lib
替代方案:子模块的使用体验较为复杂,如果可能,考虑使用包管理器(npm、pip、Maven 等)或 Git Subtree 作为替代。

高级 4 稀疏检出(Sparse Checkout)

只检出仓库中的部分目录,适合超大型 monorepo:
# 克隆时启用稀疏检出
git clone --filter=blob:none --sparse https://github.com/user/monorepo.git
cd monorepo

# 设置要检出的目录
git sparse-checkout set packages/my-app packages/shared

# 添加更多目录
git sparse-checkout add docs

# 查看当前稀疏检出配置
git sparse-checkout list

# 禁用稀疏检出(检出所有文件)
git sparse-checkout disable

高级 5 Git Hooks(钩子)

Git Hooks 是在特定事件触发时自动执行的脚本:
# 钩子文件位于 .git/hooks/ 目录
# 常用客户端钩子:
pre-commit      # 提交前运行(代码检查、格式化)
commit-msg      # 验证提交信息格式
pre-push        # 推送前运行(运行测试)
post-merge      # 合并后运行(安装依赖)
示例 — 使用 pre-commit 钩子检查代码格式:
# .git/hooks/pre-commit
#!/bin/sh
npm run lint
if [ $? -ne 0 ]; then
  echo "Lint 检查未通过,请修复后再提交"
  exit 1
fi
推荐工具:使用 Husky(Node.js)或 pre-commit(Python)来管理和共享 Git Hooks,避免每个开发者手动配置。

团队协作

协作 1 Pull Request / Merge Request 工作流

PR/MR 是现代团队协作的标准流程:
# 1. 从 main 创建功能分支
git switch -c feature/user-auth main

# 2. 开发并提交
git add .
git commit -m "feat: 实现用户认证模块"

# 3. 推送到远程
git push -u origin feature/user-auth

# 4. 在 GitHub/GitLab 上创建 Pull Request

# 5. 代码评审通过后合并

# 6. 清理已合并的分支
git switch main
git pull
git branch -d feature/user-auth
PR 最佳实践:
1. 每个 PR 只做一件事,保持变更范围小
2. 写清楚 PR 描述,说明为什么要做这个修改
3. 在合并前确保 CI 通过
4. 使用 Squash Merge 保持主线历史整洁

协作 2 代码评审(Code Review)

高质量的代码评审是团队协作的关键:
# 拉取他人的 PR 到本地测试
git fetch origin pull/123/head:pr-123
git switch pr-123

# 使用 GitHub CLI
gh pr checkout 123

# 查看 PR 的差异
git diff main...pr-123
评审要点:
1. 正确性 — 代码逻辑是否正确,是否处理了边界情况
2. 可读性 — 命名是否清晰,注释是否充分
3. 性能 — 是否有明显的性能问题
4. 安全性 — 是否存在安全漏洞(SQL 注入、XSS 等)
5. 测试 — 是否有足够的测试覆盖

协作 3 .gitignore 配置

.gitignore 文件指定哪些文件不应被 Git 追踪:
# .gitignore 常见配置

# 依赖目录
node_modules/
vendor/
__pycache__/
venv/

# 构建产物
dist/
build/
*.o
*.pyc

# 环境与配置文件
.env
.env.local
*.secret

# IDE 和编辑器
.vscode/
.idea/
*.swp
.DS_Store
Thumbs.db

# 日志
*.log
logs/
# 已追踪的文件加入 .gitignore 后不会自动停止追踪
# 需要先从 Git 缓存中移除
git rm --cached .env
git rm --cached -r node_modules/

# 全局 .gitignore(适用于所有仓库)
git config --global core.excludesfile ~/.gitignore_global

协作 4 Monorepo 管理

在单个仓库中管理多个项目/包的策略:
# Monorepo 目录结构示例
my-monorepo/
├── packages/
│   ├── web-app/
│   ├── api-server/
│   ├── shared-utils/
│   └── ui-components/
├── package.json
└── turbo.json
Git 层面的优化:
1. 稀疏检出 — 只检出需要的子目录
2. 路径过滤git log -- packages/web-app/ 只看特定包的历史
3. CODEOWNERS — 为不同目录指定不同的代码审查者
4. 浅克隆git clone --depth 1 加速首次克隆
工具推荐:使用 TurborepoNxpnpm workspaces 来管理 monorepo 的构建和依赖。

常见问题与解决方案(50 个)

按类别整理,涵盖合并冲突、分支操作、远程同步、撤销回退、配置权限等方面的真实 Git 错误信息与修复方案。

一、合并与冲突 (8 个)

#1 合并冲突 — 自动合并失败

CONFLICT (content): Merge conflict in src/app.js Automatic merge failed; fix conflicts and then commit the result.
两个分支修改了同一文件的同一位置。解决方法:
1. 打开冲突文件,找到 <<<<<<<>>>>>>> 标记
2. 手动选择保留哪部分内容(或合并双方的修改)
3. 删除所有冲突标记
4. git add src/app.js
5. git commit
如果要放弃合并:git merge --abort

#2 Rebase 冲突

CONFLICT (content): Merge conflict in src/utils.js error: could not apply abc1234... feat: add helper hint: Resolve all conflicts manually, mark them as resolved with hint: "git add/rm <conflicted_files>", then run "git rebase --continue".
Rebase 过程中每个提交都可能产生冲突:
1. 解决当前冲突文件
2. git add .
3. git rebase --continue(重复直到所有提交都处理完)
4. 如果要跳过某个提交:git rebase --skip
5. 放弃整个 rebase:git rebase --abort

#3 Cherry-pick 冲突

error: could not apply abc1234... fix: patch hint: After resolving the conflicts, mark the corrected paths hint: with 'git add <paths>' or 'git rm <paths>' hint: and commit the result with 'git commit'
Cherry-pick 的提交与当前分支存在冲突:
1. 解决冲突文件
2. git add .
3. git cherry-pick --continue
放弃:git cherry-pick --abort

#4 合并时提示 unrelated histories

fatal: refusing to merge unrelated histories
两个仓库没有共同的祖先提交(常见于合并两个独立创建的仓库):
git merge origin/main --allow-unrelated-histories
或 pull 时:
git pull origin main --allow-unrelated-histories

#5 合并后发现有误,想撤销

需要撤销已经完成的 merge commit
如果尚未推送:
git reset --hard HEAD~1
如果已经推送(不能直接 reset),使用 revert:
# -m 1 表示保留当前分支的父提交
git revert -m 1 <merge-commit-hash>

#6 merge 时出现 "already up to date"

Already up to date.
目标分支已经包含了要合并分支的所有提交。检查:
1. 确认你在正确的分支上:git branch
2. 确认合并方向正确(在 main 上执行 git merge feature
3. 该分支可能已经被合并过了:git branch --merged

#7 合并时出现二进制文件冲突

warning: Cannot merge binary files: assets/logo.png (HEAD vs feature)
Git 无法合并二进制文件,需要手动选择版本:
# 保留当前分支的版本
git checkout --ours assets/logo.png

# 保留被合并分支的版本
git checkout --theirs assets/logo.png

# 然后暂存并继续
git add assets/logo.png

#8 rebase 后出现重复提交

git log 显示同一修改出现了两次(不同的 commit hash)
通常发生在 rebase 了已推送的分支后又 merge。避免方法:
1. 对已推送的公共分支不要 rebase
2. 如果已经出现重复,用交互式 rebase 清理:
git rebase -i HEAD~10
# 将重复的提交标记为 drop

二、远程操作 (10 个)

#9 Push 被拒绝 — 远程有新提交

! [rejected] main -> main (fetch first) error: failed to push some refs to 'origin' hint: Updates were rejected because the remote contains work that you do hint: not have locally.
远程分支有你本地没有的提交。先拉取再推送:
git pull --rebase origin main
git push origin main

#10 Push 被拒绝 — non-fast-forward

! [rejected] main -> main (non-fast-forward) error: failed to push some refs to 'origin' hint: Updates were rejected because the tip of your current branch is behind
你的本地分支落后于远程。解决方法:
# 方法一:rebase(推荐)
git pull --rebase
git push

# 方法二:如果确定要覆盖远程(谨慎!)
git push --force-with-lease

#11 无法连接远程仓库 — SSH 权限

git@github.com: Permission denied (publickey). fatal: Could not read from remote repository.
SSH 密钥未配置或未添加到 GitHub:
1. 检查是否有 SSH 密钥:ls ~/.ssh/id_ed25519.pub
2. 如果没有,生成新密钥:ssh-keygen -t ed25519 -C "your@email.com"
3. 将公钥添加到 GitHub Settings > SSH Keys
4. 测试连接:ssh -T git@github.com
5. 检查 ssh-agent:eval "$(ssh-agent -s)" && ssh-add ~/.ssh/id_ed25519

#12 HTTPS 认证失败

remote: Support for password authentication was removed on August 13, 2021. fatal: Authentication failed for 'https://github.com/user/repo.git'
GitHub 已停止支持密码认证。解决方法:
1. 切换到 SSH:git remote set-url origin git@github.com:user/repo.git
2. 或使用 Personal Access Token(PAT)替代密码
3. 或安装 GitHub CLI:gh auth login

#13 fatal: remote origin already exists

fatal: remote origin already exists.
尝试添加已存在的远程名称。解决方法:
# 修改现有远程 URL
git remote set-url origin https://github.com/user/new-repo.git

# 或删除后重新添加
git remote remove origin
git remote add origin https://github.com/user/new-repo.git

# 查看现有远程
git remote -v

#14 远程分支已删除但本地仍显示

git branch -a 显示 remotes/origin/feature-old(已在远程删除)
同步远程已删除的分支引用:
# 清理已删除的远程分支
git fetch --prune

# 或设置自动清理
git config --global fetch.prune true

# 同时删除对应的本地分支
git branch -d feature-old

#15 clone 超时或速度极慢

fatal: unable to access 'https://github.com/user/repo.git/': Failed to connect to github.com port 443: Timed out
网络问题或仓库过大:
# 浅克隆(只获取最新提交)
git clone --depth 1 https://github.com/user/repo.git

# 使用代理
git config --global http.proxy http://127.0.0.1:7890

# 增大缓冲区(大仓库)
git config --global http.postBuffer 524288000

# 使用 SSH 替代 HTTPS
git clone git@github.com:user/repo.git

#16 push 时提示没有上游分支

fatal: The current branch feature has no upstream branch. To push the current branch and set the remote as upstream, use git push --set-upstream origin feature
新创建的本地分支还没有关联远程分支:
git push -u origin feature
或设置自动推送行为:
git config --global push.autoSetupRemote true

#17 fetch 后看不到远程新分支

执行 git fetch 后 git branch -a 看不到同事新建的远程分支
尝试获取所有远程引用:
# 获取所有远程的所有分支
git fetch --all

# 查看远程分支
git branch -r

# 切换到远程分支
git switch -c feature-new origin/feature-new

#18 push 大文件失败

remote: error: File data.zip is 150.00 MB; this exceeds GitHub's file size limit of 100.00 MB
GitHub 限制单个文件不超过 100MB。解决方法:
# 使用 Git LFS 管理大文件
git lfs install
git lfs track "*.zip" "*.tar.gz"
git add .gitattributes
git add data.zip
git commit -m "add large file with LFS"
git push
如果文件已在历史中,需要用 BFG 或 filter-branch 清理:
# 使用 BFG Repo-Cleaner(推荐)
java -jar bfg.jar --strip-blobs-bigger-than 100M
git reflog expire --expire=now --all
git gc --prune=now --aggressive

三、撤销与回退 (10 个)

#19 Detached HEAD 状态

You are in 'detached HEAD' state. You can look around, make experimental changes and commit them, and you can discard any commits you make in this state without impacting any branches by switching back to a branch.
HEAD 指向了某个具体的提交而非分支。通常因为 git checkout <commit-hash>
# 如果只是查看旧提交,直接切回分支
git switch main

# 如果在 detached HEAD 中做了有价值的提交,创建新分支保存
git switch -c save-my-work

# 如果想让某个分支指向当前位置
git branch -f main HEAD
git switch main

#20 撤销最近一次提交(保留修改)

提交了错误的内容,想撤回但保留代码修改
# 撤销提交,修改回到暂存区
git reset --soft HEAD~1

# 撤销提交,修改回到工作区(未暂存)
git reset --mixed HEAD~1   # 或简写 git reset HEAD~1

# 撤销提交并丢弃所有修改(危险!)
git reset --hard HEAD~1

#21 撤销已推送的提交

已经 push 到远程的提交需要撤销
使用 revert 创建一个"反向提交"(安全,不修改历史):
# 撤销单个提交
git revert abc1234

# 撤销多个连续提交
git revert abc1234..def5678

# 撤销但不自动提交
git revert --no-commit abc1234

git push

#22 恢复已删除的文件

不小心删除了文件,需要恢复
# 如果文件还没有 commit 删除操作
git checkout -- deleted-file.txt
# 或 Git 2.23+
git restore deleted-file.txt

# 如果删除已经提交,从历史中恢复
git checkout HEAD~1 -- deleted-file.txt

# 找到删除文件的提交并恢复
git log --diff-filter=D --summary  # 找到删除记录
git checkout abc1234^ -- path/to/deleted-file.txt

#23 撤销 git add(取消暂存)

误将文件 git add 到暂存区,想取消
# 取消暂存单个文件
git reset HEAD file.txt
# 或 Git 2.23+
git restore --staged file.txt

# 取消暂存所有文件
git reset HEAD
git restore --staged .

#24 丢弃工作区的修改

想丢弃对某个文件的所有未暂存修改
# 丢弃单个文件的修改
git checkout -- file.txt
# 或 Git 2.23+
git restore file.txt

# 丢弃所有未暂存的修改
git checkout -- .
git restore .

# 删除所有未追踪的文件和目录
git clean -fd

# 先预览将被删除的文件
git clean -fdn
警告:git checkout -- .git clean -fd 会永久丢弃修改,无法恢复。请确认后再执行。

#25 git reset --hard 后想找回代码

执行了 git reset --hard 后发现需要找回之前的提交
使用 reflog 找回:
# 查看操作历史
git reflog

# 找到 reset 之前的提交哈希
# 例如输出:abc1234 HEAD@{1}: commit: important work

# 恢复到那个状态
git reset --hard abc1234

# 或创建新分支保存
git branch recovery abc1234

#26 误删了本地分支

git branch -D feature-important 后需要找回
# 查看 reflog 找到分支最后的提交
git reflog

# 重新创建分支指向该提交
git branch feature-important abc1234

# 如果远程还有该分支
git checkout -b feature-important origin/feature-important

#27 想修改已提交但未推送的提交信息

最近的提交信息写错了,想修正
# 修改最近一次提交信息
git commit --amend -m "正确的提交信息"

# 修改更早的提交信息(交互式 rebase)
git rebase -i HEAD~3
# 将要修改的提交标记从 pick 改为 reword

#28 提交到了错误的分支

本该提交到 feature 分支,却提交到了 main
# 方法:把提交移到正确的分支
# 1. 记下提交哈希
git log --oneline -1

# 2. 在 main 上撤销这个提交
git reset --soft HEAD~1

# 3. 暂存修改
git stash

# 4. 切换到正确的分支
git switch feature

# 5. 恢复修改并提交
git stash pop
git add .
git commit -m "feat: your feature"

四、工作区与暂存 (7 个)

#29 stash 恢复后出现冲突

CONFLICT (content): Merge conflict in src/app.js Auto-merging src/app.js
stash 保存的修改与当前分支代码冲突:
1. 解决冲突文件(与合并冲突相同)
2. git add .
3. stash 内容不会自动删除,可用 git stash drop 手动清理

#30 切换分支时提示有未提交的修改

error: Your local changes to the following files would be overwritten by checkout: src/app.js Please commit your changes or stash them before you switch branches.
当前工作区有未提交的修改,切换分支可能导致冲突:
# 方法一:暂存修改
git stash
git switch other-branch
# 回来后:git stash pop

# 方法二:先提交
git commit -am "wip: 临时保存"

# 方法三:强制切换(丢弃修改,危险!)
git switch -f other-branch

#31 .gitignore 不生效

已在 .gitignore 中添加规则,但文件仍被追踪
.gitignore 只对未追踪的文件生效。已追踪的文件需要先移除缓存:
# 移除单个文件的追踪
git rm --cached config.json

# 移除整个目录的追踪
git rm --cached -r node_modules/

# 移除所有应被忽略的已追踪文件
git rm -r --cached .
git add .
git commit -m "chore: apply .gitignore"

#32 不小心提交了敏感信息

密码、API Key、私钥等敏感信息被提交到仓库
重要:即使删除文件并重新提交,敏感信息仍在 Git 历史中。必须彻底清除!
# 1. 立即撤销凭证(最重要!)
# 在对应平台重置密码/重新生成 API Key

# 2. 从历史中彻底删除文件
# 使用 BFG Repo-Cleaner(推荐)
java -jar bfg.jar --delete-files .env
java -jar bfg.jar --replace-text passwords.txt

# 或使用 git filter-repo
pip install git-filter-repo
git filter-repo --invert-paths --path .env

# 3. 强制推送清理后的历史
git push --force --all

#33 文件权限变更被 Git 追踪

git diff 显示文件有变更,但内容没变,只有 mode 从 100644 变为 100755
Git 默认追踪文件权限变更。在 Windows 或不关心权限的场景下可以关闭:
git config core.fileMode false

#34 行尾符号导致大量文件变更

git diff 显示整个文件都有变更,但实际内容没变(CR/LF 问题)
Windows 和 macOS/Linux 使用不同的换行符:
# Windows 用户
git config --global core.autocrlf true

# macOS/Linux 用户
git config --global core.autocrlf input

# 项目级统一设置(推荐)
# 创建 .gitattributes 文件
* text=auto
*.sh text eol=lf
*.bat text eol=crlf

#35 git add . 添加了不想要的文件

误用 git add . 将 node_modules 或构建产物加入了暂存区
# 取消暂存
git reset HEAD node_modules/

# 将目录加入 .gitignore
echo "node_modules/" >> .gitignore

# 如果已经提交过,从 Git 历史中移除
git rm -r --cached node_modules/
git commit -m "chore: remove node_modules from tracking"

五、分支与标签 (7 个)

#36 无法删除当前所在的分支

error: Cannot delete branch 'feature' checked out at '/path/to/repo'
不能删除正在使用的分支。先切换到其他分支:
git switch main
git branch -d feature

#37 分支名拼写错误,想重命名

分支名 featrue 写错了,想改为 feature
# 重命名当前分支
git branch -m feature

# 重命名指定分支
git branch -m featrue feature

# 如果已推送到远程,还需要更新远程
git push origin --delete featrue
git push -u origin feature

#38 本地分支与远程分支不一致

git status 提示 "Your branch is behind 'origin/main' by X commits"
# 你的本地分支落后于远程
git pull --rebase

# 如果本地有自己的提交(分叉了)
# git status 会提示 "diverged"
git pull --rebase   # 将你的提交放到远程最新提交之上

#39 标签推送失败或冲突

error: failed to push some refs to 'origin' hint: Updates were rejected because the tag already exists in the remote.
远程已存在同名标签:
# 删除远程标签后重新推送
git push origin --delete v1.0.0
git push origin v1.0.0

# 或强制更新远程标签
git push origin v1.0.0 --force

#40 checkout 远程分支提示 "did not match any"

error: pathspec 'feature-new' did not match any file(s) known to git
本地没有远程分支的信息:
# 先获取远程信息
git fetch --all

# 然后切换
git switch -c feature-new origin/feature-new
# 或
git checkout -b feature-new origin/feature-new

#41 HEAD detached from tag

You are in 'detached HEAD' state (checked out tag v1.0.0)
checkout 标签会进入 detached HEAD 状态,因为标签是不可变引用:
# 基于标签创建新分支
git switch -c hotfix-from-v1 v1.0.0

# 或直接切回分支
git switch main

#42 想查看某个标签的代码但不想修改

需要查看 v1.0.0 时的代码
# 方法一:直接 checkout(进入 detached HEAD)
git checkout v1.0.0
# 查看完毕后切回
git switch main

# 方法二:使用 worktree(推荐,不影响当前工作)
git worktree add ../review-v1 v1.0.0
# 在 ../review-v1 目录查看
# 完毕后清理
git worktree remove ../review-v1

六、子模块与 LFS (5 个)

#43 clone 后子模块目录为空

git clone 后 libs/xxx 目录存在但里面没有文件
clone 默认不会下载子模块内容:
# 初始化并更新子模块
git submodule init
git submodule update

# 或一步完成
git submodule update --init --recursive

# 克隆时直接包含子模块
git clone --recurse-submodules https://github.com/user/repo.git

#44 子模块更新后 diff 显示 dirty

diff --git a/libs/sub b/libs/sub --- a/libs/sub +++ b/libs/sub -Subproject commit abc1234 +Subproject commit abc1234-dirty
子模块目录中有未提交的修改:
# 进入子模块目录处理
cd libs/sub
git status
git checkout .    # 丢弃修改
# 或
git stash         # 暂存修改

# 忽略子模块的 dirty 状态
git config diff.ignoreSubmodules dirty

#45 Git LFS 文件下载失败

Smudge error: Error downloading assets/model.bin: batch response: This repository is over its data quota.
LFS 存储或带宽超出限额:
1. 检查 LFS 配额:在 GitHub Settings > Billing 查看
2. 购买额外的 LFS 包
3. 临时跳过 LFS 文件:GIT_LFS_SKIP_SMUDGE=1 git clone ...
4. 考虑将大文件存储到 S3/OSS 等对象存储

#46 LFS 指针文件被直接提交

文件内容变成了 "version https://git-lfs.github.com/spec/v1 oid sha256:..." 的文本
LFS 未正确安装或 .gitattributes 未配置:
# 安装 Git LFS
git lfs install

# 确保 .gitattributes 存在
git lfs track "*.bin" "*.zip"

# 重新处理指针文件
git lfs pull

# 如果问题持续,重新添加文件
git rm --cached assets/model.bin
git add assets/model.bin
git commit -m "fix: re-add file with LFS"

#47 子模块切换分支导致冲突

error: The following untracked working tree files would be overwritten by checkout
不同分支引用了不同的子模块版本或路径:
# 强制更新子模块
git submodule update --force

# 完全重置子模块
git submodule deinit -f .
git submodule update --init --recursive

七、配置与杂项 (3 个)

#48 提交时提示未设置用户信息

Author identity unknown *** Please tell me who you are. Run git config --global user.email "you@example.com" git config --global user.name "Your Name"
首次使用 Git 必须配置用户信息:
git config --global user.name "你的名字"
git config --global user.email "你的邮箱@example.com"
如果不同项目需要不同身份,使用项目级配置(去掉 --global):
cd my-project
git config user.name "工作用名"
git config user.email "work@company.com"

#49 Git 仓库体积过大

git clone 下载超过 1GB,.git 目录占用空间巨大
历史中可能包含大文件或不必要的对象:
# 查看占用最大空间的文件
git rev-list --objects --all | git cat-file --batch-check='%(objecttype) %(objectname) %(objectsize) %(rest)' | sort -k3 -n -r | head -20

# 使用 BFG 清理大文件
java -jar bfg.jar --strip-blobs-bigger-than 50M

# 垃圾回收
git reflog expire --expire=now --all
git gc --prune=now --aggressive

# 克隆时使用浅克隆减少下载量
git clone --depth 1 https://github.com/user/repo.git

#50 pre-commit hook 阻止提交

husky - pre-commit hook exited with code 1 (error)
pre-commit 钩子运行的检查未通过:
1. 查看具体错误信息(通常是 lint 或 format 检查失败)
2. 修复代码问题后重新提交
3. 如果确定要跳过检查(不推荐):git commit --no-verify
# 常见修复方法
npm run lint -- --fix    # 自动修复 lint 问题
npm run format           # 格式化代码

# 重新提交
git add .
git commit -m "feat: your feature"