Skip to content

Git 常用命令

Git 是最常用的分布式版本控制系统。

安装

Windows

bash
# 下载安装包
# https://git-scm.com/download/win

# 安装后验证
git --version

macOS

bash
# 通过 Homebrew 安装
brew install git

# 或通过 Xcode Command Line Tools
xcode-select --install

Linux

bash
# Debian/Ubuntu
sudo apt-get install git

# CentOS/Fedora
sudo yum install git

基础配置

bash
# 设置用户名
git config --global user.name "你的名字"

# 设置邮箱
git config --global user.email "[email protected]"

# 设置默认分支名
git config --global init.defaultBranch main

# 设置换行符(Windows 用户推荐)
git config --global core.autocrlf true

# 查看配置
git config --list

日常操作

创建仓库

bash
# 初始化新仓库
git init

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

查看状态与差异

bash
git status                       # 查看工作区状态
git status -s                    # 简洁模式(M 修改 A 新增 D 删除)
git diff                         # 查看未暂存的修改
git diff --staged                # 查看已暂存的修改(对比上一次 commit)

提交代码

bash
# 添加所有文件到暂存区
git add .

# 添加指定文件
git add filename.txt

# 添加指定目录
git add src/

# 提交
git commit -m "feat: 添加新功能"

# 添加并提交(仅限已跟踪文件的修改,跳过 git add)
# ⚠️ 不能暂存新文件(untracked),新文件仍需先 git add
git commit -am "fix: 修复 bug"

分支操作

bash
# 查看分支
git branch

# 查看所有分支(含远程)
git branch -a

# 创建新分支
git branch feature-name

# 切换分支(推荐使用 git switch)
git switch feature-name

# 创建并切换到新分支
git switch -c feature-name

# 合并分支
git merge feature-name

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

# 强制删除分支
git branch -D feature-name

💡 git checkout 也能切换分支,但 git switch(Git 2.23+)语义更清晰,专门用于分支切换。

远程操作

bash
# 查看远程仓库
git remote -v

# 关联远程仓库
git remote add origin https://github.com/user/repo.git

# 推送到远程
git push origin main

# 推送并设置上游分支(首次推送后可简写 git push)
git push -u origin feature-name

# 拉取远程更新(= fetch + merge)
git pull origin main

# 拉取并变基(避免多余的合并提交)
git pull --rebase

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

撤销操作

撤销工作区修改(未 add)

bash
# 恢复单个文件
git restore filename.txt

# 恢复所有修改
git restore .

撤销暂存(已 add 未 commit)

bash
# 取消暂存单个文件
git restore --staged filename.txt

# 取消暂存所有
git restore --staged .

撤销提交(已 commit)

bash
# 撤销提交,保留修改在暂存区
git reset --soft HEAD~1

# 撤销提交,保留修改在工作区
git reset --mixed HEAD~1

# 撤销提交,丢弃所有修改(不可恢复,慎用)
git reset --hard HEAD~1

修改最后一次提交

bash
# 修改提交信息
git commit --amend -m "新的提交信息"

# 追加文件到上一次提交(不改信息)
git add forgotten-file.js
git commit --amend --no-edit

git revert(安全撤销已推送的提交)

什么是 git revert?

git revert 会创建一个新的提交,用来"反转"指定提交的修改。与 git reset 不同,revert 不会改变历史,而是新增一个"反向提交",适合撤销已推送到远程的代码。

什么时候用 revert 而不是 reset?

  • 已推送到远程的提交,用 revert(不改变历史,不影响其他人)
  • 未推送的本地提交,用 reset(可以修改历史)
bash
# 撤销指定提交(创建一个新的反向提交)
git revert <commit-hash>

# 撤销最近一次提交
git revert HEAD

# 撤销但不自动提交(可以修改后再提交)
git revert --no-commit <commit-hash>

# 撤销多个连续提交
git revert <older-hash>..<newer-hash>

# 撤销合并提交(-m 1 表示保留主分支的内容)
git revert -m 1 <merge-commit-hash>

reset / revert / restore 三者区别

命令作用对象是否改变历史典型场景
git reset分支指针(HEAD)是(本地)/ 否(远程未推送)撤销本地提交、整理提交历史
git revert提交记录否(新增反向提交)撤销已推送到远程的提交
git restore工作区 / 暂存区撤销文件修改、取消暂存

使用场景对比:

场景 1:刚写完代码,还没 git add
→ git restore filename.txt(撤销工作区修改)

场景 2:已经 git add,还没 git commit
→ git restore --staged filename.txt(取消暂存)

场景 3:已经 git commit,但还没推送到远程
→ git reset --soft HEAD~1(撤销提交,保留修改)

场景 4:已经推送到远程,需要撤销
→ git revert HEAD(安全撤销,不影响其他人)

⚠️ git reset --hard 会丢失未提交的修改,无法恢复。操作前建议先 git stash 备份当前工作。


高级操作

暂存工作区

bash
# 暂存当前修改(切换分支时很有用)
git stash

# 查看暂存列表
git stash list

# 恢复最近一次暂存并删除记录
git stash pop

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

# 删除最近一次暂存
git stash drop

# 清空所有暂存
git stash clear

查看日志

bash
# 查看提交日志
git log

# 简洁模式(最近 10 条)
git log --oneline -10

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

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

# 查看某次提交的详细内容
git show <commit-hash>

# 查看每一行是谁改的
git blame filename.txt

变基(Rebase)vs 合并(Merge)

什么时候用 rebase?什么时候用 merge?

简单说:

  • rebase:把你的提交"搬"到目标分支的最新提交后面,保持提交历史是一条直线
  • merge:把两个分支合并,会产生一个"合并提交",历史会分叉再合并
# rebase 后的历史(线性):
A - B - C - D' - E'  (D' 和 E' 是你的提交"搬"过来的)

# merge 后的历史(有分叉):
A - B - C - F(合并提交)
     \     /
      D - E

什么时候用 rebase?

  • 你自己的功能分支,还没有其他人基于它开发
  • 想保持提交历史干净、线性
  • 整理提交记录(比如把 5 个小提交合并成 1 个)

什么时候用 merge?

  • 公共分支(如 main、develop),因为 rebase 会改变提交历史,影响其他人
  • 想保留完整的合并记录(知道哪些提交是在哪个分支上做的)
bash
# 将当前分支变基到 main(保持提交历史线性)
git rebase main

# 交互式变基(合并、修改、删除最近 3 次提交)
git rebase -i HEAD~3

⚠️ 不要对已推送到远程的公共分支执行 rebase,会导致其他人的代码冲突。

Cherry-pick

什么是 cherry-pick?

cherry-pick 是"摘樱桃"的意思。假设你在 feature-A 分支上提交了一个紧急修复,但 feature-A 还没开发完不能合并到 main。这时候可以用 cherry-pick 把那个"修复提交"单独"摘"到 main 分支上。

什么时候用?

  • 紧急 bug 修复需要从开发分支提取到生产分支
  • 某个分支上的某个提交很有用,想应用到其他分支
  • 不想合并整个分支,只需要其中的某次提交
bash
# 将指定提交应用到当前分支
git cherry-pick <commit-hash>

# 应用多个提交
git cherry-pick <hash1> <hash2>

# 应用但不自动提交(可以修改后再提交)
git cherry-pick --no-commit <commit-hash>

解决合并冲突

bash
# 合并时出现冲突,手动解决后
git add <conflicted-files>
git commit

# 放弃本次合并
git merge --abort

# 放弃本次 rebase
git rebase --abort

冲突文件的标记:

<<<<<<< HEAD
当前分支的内容
=======
要合并的分支内容
>>>>>>> feature-name

标签管理

什么是标签?为什么要用标签?

标签就像是给某个提交贴一个"书签",通常用于标记发布版本(如 v1.0.0、v2.1.3)。

为什么要用标签?

  • 方便回溯:想看 v1.0.0 版本的代码是什么样的,直接 git checkout v1.0.0
  • 发布记录:配合 GitHub/Gitee 的 Release 功能,自动生成版本更新日志
  • 部署管理:CI/CD 可以根据标签自动触发发布流程

什么时候打标签?

  • 每次发布新版本时(npm publish 前、部署生产环境前)
  • 重要的里程碑节点
bash
# 查看标签
git tag

# 创建轻量标签(只是一个指针,不推荐)
git tag v1.0.0

# 创建附注标签(推荐,包含标签信息)
git tag -a v1.0.0 -m "版本 1.0.0:新增用户登录功能"

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

# 推送所有标签
git push origin --tags

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

二分查找(bisect)

用二分法快速定位哪个提交引入了 bug:

bash
# 开始二分查找
git bisect start

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

# 标记某个版本没有 bug
git bisect good v1.0.0

# Git 会自动 checkout 中间版本,你测试后标记:
git bisect good   # 这个版本没问题
git bisect bad    # 这个版本有问题

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

# 自动化(用脚本自动测试)
git bisect start HEAD v1.0.0
git bisect run npm test

从历史中删除文件

bash
# 误提交了大文件或敏感文件,从历史中彻底删除
pip install git-filter-repo
git filter-repo --path src/assets/large-file.mp4 --invert-paths
git push --force-with-lease   # ⚠️ 仅在远程未被他人更新时才允许 force push

⚠️ git push --force 会覆盖远程历史,影响所有协作者。推荐使用 --force-with-lease(仅在远程未被他人更新时才允许 force push)。执行前必须通知所有协作者。


前端项目常用 Git 工作流

分支命名规范

main(或 master)     → 生产环境代码
develop               → 开发环境代码
feature/xxx           → 功能分支(如 feature/user-login)
fix/xxx               → 修复分支(如 fix/token-expire)
hotfix/xxx            → 紧急修复(如 hotfix/crash-on-payment)
release/x.x.x         → 发布分支(如 release/1.2.0)

前端项目典型工作流

bash
# 1. 从 develop 创建功能分支
git switch develop
git pull origin develop
git switch -c feature/user-login

# 2. 开发完成后提交
git add src/views/Login.vue src/api/auth.ts
git commit -m "feat(auth): 添加用户登录功能"

# 3. 推送到远程并创建 PR
git push -u origin feature/user-login

# 4. PR 合并后清理本地分支
git switch develop
git pull origin develop
git branch -d feature/user-login

前端项目 .gitignore 完整配置

bash
# 依赖目录
node_modules/

# 构建产物
dist/
build/
.output/

# 环境变量(敏感信息)
.env
.env.local
.env.*.local

# 系统文件
.DS_Store
Thumbs.db

# 日志
*.log
npm-debug.log*

# 编辑器
.vscode/
.idea/
*.swp
*.swo

# TypeScript 缓存
*.tsbuildinfo

# Vite 缓存
.vite/

# 测试覆盖率
coverage/

# 反向规则(虽然 *.log 被忽略,但保留 important.log)
!important.log

# 忽略某个目录下所有文件但保留目录本身
logs/*
!logs/.gitkeep

常见报错及解决方案

fatal: not a git repository

bash
# 原因:当前目录不是 Git 仓库
# 解决:初始化或切换到正确的目录
git init
# 或
cd /path/to/your/project

fatal: remote origin already exists

bash
# 原因:已经关联了远程仓库
# 解决:先删除再重新关联
git remote remove origin
git remote add origin https://github.com/user/repo.git

error: failed to push some refs

bash
# 原因:远程有本地没有的提交(远程代码更新了)
# 解决:先拉取远程更新再推送
git pull --rebase origin main
git push origin main

CONFLICT (content): Merge conflict in xxx

bash
# 原因:两个分支修改了同一文件的同一位置
# 解决:
# 1. 打开冲突文件,找到 <<<<<<< HEAD 标记
# 2. 手动选择保留哪个版本(或合并两者)
# 3. 删除冲突标记(<<<<<<<、=======、>>>>>>>)
# 4. 标记冲突已解决
git add <conflicted-file>
git commit

fatal: refusing to merge unrelated histories

bash
# 原因:两个仓库没有共同的提交历史
# 解决:添加 --allow-unrelated-histories 参数
git pull origin main --allow-unrelated-histories

error: Your local changes would be overwritten

bash
# 原因:本地有未提交的修改,切换分支会丢失
# 解决:先暂存修改
git stash
git switch <other-branch>
# 切换回来后恢复
git switch <original-branch>
git stash pop

参考

个人学习笔记,部分内容借助 AI 辅助整理,仅供查阅参考,请以官方文档为准