Git 是由 Linus Torvalds 于 2005 年创建的分布式版本控制系统,最初用于管理 Linux 内核开发。如今,Git 已成为全球软件开发的标准版本控制工具,被超过 95% 的开发者使用。
Git 的核心设计理念是速度、数据完整性和对分布式非线性工作流的支持。每个 Git 目录都是一个完整的仓库,包含完整的版本历史和追踪能力,不依赖网络或中央服务器。在 GitHub 上拥有超过 53,000 Star,是开发者工具领域最重要的基础设施项目之一。
| 项目信息 | 详情 |
|---|---|
| 创建者 | Linus Torvalds / 社区维护 |
| GitHub Stars | 53,000+ |
| 开源协议 | GPL-2.0 |
| 核心语言 | C |
| 架构模式 | 分布式(Distributed) |
| 官方网站 | git-scm.com |
| 最新版本 | Git 2.x(持续更新) |
| 对比维度 | 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% |
# 方式一:安装 Xcode 命令行工具(自带 Git) xcode-select --install # 方式二:Homebrew 安装最新版(推荐) brew install git # 验证安装 git --version
# Ubuntu / Debian sudo apt update && sudo apt install git # CentOS / RHEL / Fedora sudo dnf install git # Arch Linux sudo pacman -S git # 验证安装 git --version
winget install Git.Git安装完成后打开 Git Bash 或 PowerShell 运行
git --version 验证。
# 必须配置:用户名和邮箱 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
# 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
~/.ssh/config 中为不同平台配置不同的密钥。
# 在当前目录创建新仓库 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
# 暂存单个文件 git add file.txt # 暂存多个文件 git add file1.txt file2.txt # 暂存当前目录所有变更 git add . # 暂存所有已追踪文件的变更(不含新文件) git add -u # 交互式暂存(按补丁块选择) git add -p
git add -p 可以让你逐块选择要暂存的修改,非常适合将一次大修改拆分为多个有意义的提交。
# 提交暂存区的内容 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,除非你确定没有其他人基于此提交工作。
# 推送当前分支到远程 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,它会在远程有新提交时拒绝推送,防止覆盖他人的工作。
# 拉取并合并远程更新 git pull # 拉取并使用 rebase(推荐,保持线性历史) git pull --rebase # 仅获取远程更新(不合并) git fetch # 获取所有远程的更新 git fetch --all # 获取并清理已删除的远程分支引用 git fetch --prune
# 查看工作区和暂存区状态 git status # 简洁输出 git status -s # 显示分支信息 git status -sb状态标识说明:
M — 已修改 A — 新添加 D — 已删除 ?? — 未追踪 R — 重命名
# 查看提交历史 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"
# 查看工作区与暂存区的差异 git diff # 查看暂存区与上次提交的差异 git diff --staged # 比较两个分支 git diff main..feature # 比较两个提交 git diff abc1234..def5678 # 仅显示变更的文件名 git diff --name-only # 显示统计信息 git diff --stat
# 查看所有分支 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
# 切换到目标分支 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 可以保留分支的历史记录,方便日后追踪某个功能是在哪个分支上开发的。
# 将 feature 分支变基到 main 的最新提交 git switch feature-login git rebase main # 发生冲突时 # 1. 解决冲突文件 # 2. git add 已解决的文件 # 3. 继续变基 git rebase --continue # 跳过当前冲突的提交 git rebase --skip # 取消变基 git rebase --abort
# 摘取单个提交 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 # 放弃
# 分支模型 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
# 核心原则 1. 只有一个长期分支(main/trunk) 2. 功能分支生命周期极短(1-2 天内合并) 3. 使用 Feature Flag 控制未完成功能的可见性 4. 频繁集成,每天至少合并一次
# 冲突标记格式 <<<<<<< 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'
# 暂存当前修改
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
# 创建轻量标签 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
# 创建新的工作树 git worktree add ../hotfix-branch hotfix/fix-crash # 列出所有工作树 git worktree list # 删除工作树 git worktree remove ../hotfix-branchGit 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
# 交互式变基最近 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 — 删除该提交
# 查看 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 之前
# 添加子模块 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
# 克隆时启用稀疏检出 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
# 钩子文件位于 .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
# 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 到本地测试 git fetch origin pull/123/head:pr-123 git switch pr-123 # 使用 GitHub CLI gh pr checkout 123 # 查看 PR 的差异 git diff main...pr-123评审要点:
.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
# Monorepo 目录结构示例 my-monorepo/ ├── packages/ │ ├── web-app/ │ ├── api-server/ │ ├── shared-utils/ │ └── ui-components/ ├── package.json └── turbo.jsonGit 层面的优化:
git log -- packages/web-app/ 只看特定包的历史
git clone --depth 1 加速首次克隆
按类别整理,涵盖合并冲突、分支操作、远程同步、撤销回退、配置权限等方面的真实 Git 错误信息与修复方案。
<<<<<<< 和 >>>>>>> 标记
git add src/app.js
git commit
git merge --abort
git add .
git rebase --continue(重复直到所有提交都处理完)
git rebase --skip
git rebase --abort
git add .
git cherry-pick --continue
git cherry-pick --abort
git merge origin/main --allow-unrelated-histories或 pull 时:
git pull origin main --allow-unrelated-histories
git reset --hard HEAD~1如果已经推送(不能直接 reset),使用 revert:
# -m 1 表示保留当前分支的父提交 git revert -m 1 <merge-commit-hash>
git branch
git merge feature)
git branch --merged
# 保留当前分支的版本 git checkout --ours assets/logo.png # 保留被合并分支的版本 git checkout --theirs assets/logo.png # 然后暂存并继续 git add assets/logo.png
git rebase -i HEAD~10 # 将重复的提交标记为 drop
git pull --rebase origin main git push origin main
# 方法一:rebase(推荐) git pull --rebase git push # 方法二:如果确定要覆盖远程(谨慎!) git push --force-with-lease
ls ~/.ssh/id_ed25519.pub
ssh-keygen -t ed25519 -C "your@email.com"
ssh -T git@github.com
eval "$(ssh-agent -s)" && ssh-add ~/.ssh/id_ed25519
git remote set-url origin git@github.com:user/repo.git
gh auth login
# 修改现有远程 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
# 清理已删除的远程分支 git fetch --prune # 或设置自动清理 git config --global fetch.prune true # 同时删除对应的本地分支 git branch -d feature-old
# 浅克隆(只获取最新提交) 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
git push -u origin feature或设置自动推送行为:
git config --global push.autoSetupRemote true
# 获取所有远程的所有分支 git fetch --all # 查看远程分支 git branch -r # 切换到远程分支 git switch -c feature-new origin/feature-new
# 使用 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
git checkout <commit-hash>:
# 如果只是查看旧提交,直接切回分支 git switch main # 如果在 detached HEAD 中做了有价值的提交,创建新分支保存 git switch -c save-my-work # 如果想让某个分支指向当前位置 git branch -f main HEAD git switch main
# 撤销提交,修改回到暂存区 git reset --soft HEAD~1 # 撤销提交,修改回到工作区(未暂存) git reset --mixed HEAD~1 # 或简写 git reset HEAD~1 # 撤销提交并丢弃所有修改(危险!) git reset --hard HEAD~1
# 撤销单个提交 git revert abc1234 # 撤销多个连续提交 git revert abc1234..def5678 # 撤销但不自动提交 git revert --no-commit abc1234 git push
# 如果文件还没有 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
# 取消暂存单个文件 git reset HEAD file.txt # 或 Git 2.23+ git restore --staged file.txt # 取消暂存所有文件 git reset HEAD git restore --staged .
# 丢弃单个文件的修改 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 会永久丢弃修改,无法恢复。请确认后再执行。
# 查看操作历史
git reflog
# 找到 reset 之前的提交哈希
# 例如输出:abc1234 HEAD@{1}: commit: important work
# 恢复到那个状态
git reset --hard abc1234
# 或创建新分支保存
git branch recovery abc1234
# 查看 reflog 找到分支最后的提交 git reflog # 重新创建分支指向该提交 git branch feature-important abc1234 # 如果远程还有该分支 git checkout -b feature-important origin/feature-important
# 修改最近一次提交信息 git commit --amend -m "正确的提交信息" # 修改更早的提交信息(交互式 rebase) git rebase -i HEAD~3 # 将要修改的提交标记从 pick 改为 reword
# 方法:把提交移到正确的分支 # 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"
git add .
git stash drop 手动清理
# 方法一:暂存修改 git stash git switch other-branch # 回来后:git stash pop # 方法二:先提交 git commit -am "wip: 临时保存" # 方法三:强制切换(丢弃修改,危险!) git switch -f other-branch
# 移除单个文件的追踪 git rm --cached config.json # 移除整个目录的追踪 git rm --cached -r node_modules/ # 移除所有应被忽略的已追踪文件 git rm -r --cached . git add . git commit -m "chore: apply .gitignore"
# 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
git config core.fileMode false
# 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
# 取消暂存 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"
git switch main git branch -d feature
# 重命名当前分支 git branch -m feature # 重命名指定分支 git branch -m featrue feature # 如果已推送到远程,还需要更新远程 git push origin --delete featrue git push -u origin feature
# 你的本地分支落后于远程 git pull --rebase # 如果本地有自己的提交(分叉了) # git status 会提示 "diverged" git pull --rebase # 将你的提交放到远程最新提交之上
# 删除远程标签后重新推送 git push origin --delete v1.0.0 git push origin v1.0.0 # 或强制更新远程标签 git push origin v1.0.0 --force
# 先获取远程信息 git fetch --all # 然后切换 git switch -c feature-new origin/feature-new # 或 git checkout -b feature-new origin/feature-new
# 基于标签创建新分支 git switch -c hotfix-from-v1 v1.0.0 # 或直接切回分支 git switch main
# 方法一:直接 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
# 初始化并更新子模块 git submodule init git submodule update # 或一步完成 git submodule update --init --recursive # 克隆时直接包含子模块 git clone --recurse-submodules https://github.com/user/repo.git
# 进入子模块目录处理 cd libs/sub git status git checkout . # 丢弃修改 # 或 git stash # 暂存修改 # 忽略子模块的 dirty 状态 git config diff.ignoreSubmodules dirty
GIT_LFS_SKIP_SMUDGE=1 git clone ...
# 安装 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"
# 强制更新子模块 git submodule update --force # 完全重置子模块 git submodule deinit -f . git submodule update --init --recursive
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"
# 查看占用最大空间的文件 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
git commit --no-verify
# 常见修复方法 npm run lint -- --fix # 自动修复 lint 问题 npm run format # 格式化代码 # 重新提交 git add . git commit -m "feat: your feature"