我在工作中是如何使用 Git 的
Category(分类): git Status: 未知
本文尽量保留原文关于 Git 环境配置、工作区、rebase、merge、cherry-pick、revert、stash、reset、reflog 和 alias 的内容,并结合 Git 官方文档、GitHub 当前认证文档补充现代实践。
文中的历史截图仍然保留,但截图里的默认分支、命令输出和界面可能已经过时。示例中的
master可以替换为当前项目实际使用的main或其他默认分支。
入职后如何配置 Git 并拉取公司代码?
案例引申出一个问题:入职一家新公司,leader 给你分配了仓库权限后,如何配置本地 Git 环境并拉取代码?可以按下面的步骤操作。公司可能使用 GitHub、GitLab、Gitea、内部代码平台或自建 SSH 服务,页面名称和权限策略会略有不同。
1. 安装 Git
到 Git 官方下载页面 选择对应操作系统的安装包。安装完成后检查版本:
git --version
Windows 用户可以使用 Git Bash、PowerShell 或 Windows Terminal;macOS/Linux 用户可以使用系统终端。公司电脑通常还需要配置代理、证书、单点登录或内部 CA,这些应按照公司 IT 文档处理,不要为了绕过证书错误而关闭 TLS 校验。
2. 生成 SSH 密钥
原文使用 RSA:
ssh-keygen -t rsa -C "你公司内部邮箱地址"
RSA 仍然可以使用,但新建密钥时更推荐 Ed25519:
ssh-keygen -t ed25519 -C "你的公司邮箱"
按提示选择默认保存路径(通常是 ~/.ssh/id_ed25519),并设置一个安全的 passphrase。不要把私钥上传、粘贴到网页或提交进代码仓库;通常只需要复制 .pub 结尾的公钥文件。
# 查看公钥,复制整行内容
cat ~/.ssh/id_ed25519.pub
# Windows PowerShell 也可以使用
Get-Content $HOME\.ssh\id_ed25519.pub
如果公司安全策略要求使用 RSA、硬件密钥或证书认证,应遵循公司要求。生成密钥后可以使用 ssh-agent 缓存解锁后的私钥:
eval "$(ssh-agent -s)"
ssh-add ~/.ssh/id_ed25519
Windows、macOS 和 Linux 对 ssh-agent 的启动方式可能不同,Git for Windows 也可以配合系统 OpenSSH 使用。

3. 把公钥添加到代码托管平台
以 GitHub 为例,进入 Settings → SSH and GPG keys,添加刚才复制的公钥。GitLab、Gitea 或企业平台通常也有类似的 SSH Keys 页面。
公钥:可以上传到代码托管平台
私钥:只能保存在自己的设备或安全的密钥管理系统中

测试 GitHub SSH 连接:
ssh -T git@github.com
第一次连接时,SSH 可能会提示确认服务器主机指纹。确认指纹来源可信后再接受,避免无条件输入 yes。公司内部服务器的用户名、端口和主机名以公司文档为准。
4. 配置 Git 提交身份
Git 的 user.name 和 user.email 是写入提交对象的作者/提交者信息,不等于 GitHub 登录账号,也不负责 SSH 身份认证。可以设置全局配置,也可以在某个仓库内覆盖:
# 所有仓库默认使用
git config --global user.name "你的姓名"
git config --global user.email "你的公司邮箱"
# 只配置当前仓库(进入仓库目录后执行)
git config user.name "项目显示名"
git config user.email "项目邮箱"
# 查看配置及来源
git config --list --show-origin
上面第一行命令前不应有多余空格;这里的空格只用于 Markdown 排版时要特别注意。公司如果要求提交签名,还需要额外配置 SSH/GPG 签名或平台认可的签名方式。
5. 克隆仓库并确认远程地址
拿到仓库地址后,根据公司要求选择 SSH 或 HTTPS:
# SSH 示例
git clone git@github.com:组织名/仓库名.git
# HTTPS 示例
git clone https://github.com/组织名/仓库名.git
cd 仓库名
git remote -v
git status
如果仓库需要克隆指定分支:
git clone --branch main --single-branch <仓库地址>
完成以上步骤后,就可以开始开发。SSH 通常不需要每次输入账号密码,但私钥仍应使用 passphrase 和 ssh-agent 保护。HTTPS 也不是“每次提交都输入用户名和密码”:GitHub 已经移除 HTTPS 密码认证,通常需要个人访问令牌(PAT)、Git Credential Manager 或企业统一认证;其他平台可能使用 OAuth、令牌或内部凭据助手。
认证方式的区别是:
- SSH:本地私钥签名,服务器保存并信任对应公钥;
- HTTPS:通过 HTTPS 连接,使用凭据助手、PAT、OAuth 或企业认证;
- 提交身份:由
user.name、user.email等配置写入 commit,不等于上述传输认证。
Git 简介
Git(读音为 /ɡɪt/)是一个开源的分布式版本控制系统,适合管理从小型项目到大型项目的版本历史。它可以在本地创建提交、查看差异、切换分支和合并历史,远程仓库则用于共享、备份、代码评审和协作。
Linux 内核早期由全球贡献者通过邮件提交补丁,维护者需要手工合并大量变更。2002 年起,Linux 社区曾使用 BitKeeper 管理源码;2005 年,由于 BitKeeper 的使用条件发生变化,Linus Torvalds 开始创建 Git。Git 的早期版本在很短时间内完成了核心原型,并迅速用于 Linux 内核开发。原文“花两周时间用 C 语言写完 Git”的说法体现了历史故事的戏剧性,但不应理解为现代 Git 的全部功能只在两周内完成。

Git 的核心对象包括 blob、tree、commit 和 tag object;分支、标签、HEAD 等引用则为这些对象提供可读入口。理解“工作区—暂存区—提交对象—远程引用”四个层次,比死记某个托管平台的按钮更重要。
Git 的工作区域和流程
原文把工作区域画成四个部分:
- Workspace/Working tree:工作区,平时编辑文件的目录;
- Index/Staging area:暂存区/索引,下一次提交将要写入的快照;
- Repository:本地仓库,保存对象、引用和本地历史,普通仓库通常位于
.git; - Remote:远程仓库,用于共享和协作,不是本地 Git 工作区的一部分。

git add 并不是把文件永久“移入”另一个文件夹,也不是只标记“哪些文件由 Git 管理”。它把工作区文件在当前时刻的内容写入暂存区。之后如果再次修改文件,工作区和暂存区就会再次产生差异,需要重新 git add 才会进入下一次提交。
git commit 把暂存区的快照写成新的本地提交;git fetch 把远程对象和引用更新到本地;git merge 或 git rebase 才会把远程变更整合到当前分支;git push 请求远程仓库更新指定引用。
常见工作流程
工作区编辑文件
│ git add / git add -p
▼
暂存区(Index)
│ git commit
▼
本地提交图
│ git fetch + merge/rebase,或 git pull
▼
本地分支与远程跟踪分支同步
│ git push
▼
远程仓库分支
每天开始工作时,可以先检查状态并获取远程更新:
git status --short
git fetch origin
git log --oneline --graph --decorate --all -n 20
Git 基本操作
git add
把文件或补丁加入暂存区:
# 暂存指定文件
git add path/to/file.js
# 暂存多个指定文件
git add file1.js file2.js
# 交互式选择文件中的部分改动
git add -p
# 暂存当前目录下的改动(包括删除和新增,需确认范围)
git add .
# 从仓库根目录暂存所有工作区改动
git add -A
git add . 的范围与执行目录有关,且可能把不想提交的文件加入暂存区;团队应使用 .gitignore 排除构建产物、依赖目录、日志、密钥和本地配置,并在提交前运行 git status 和 git diff --staged 检查。
git commit
# 提交暂存区内容,打开编辑器填写提交信息
git commit
# 使用简短提交信息
git commit -m "修复登录校验"
# 只适用于已经被 Git 跟踪的文件:暂存并提交其已修改内容
git commit -am "更新配置"
# 修改最近一次提交,通常会改变 commit ID
git commit --amend
# 不修改最近一次提交信息
git commit --amend --no-edit
git commit -am 不会自动包含未跟踪的新文件;新文件仍需先 git add。提交信息应说明“做了什么”,不要把密钥、密码、令牌和大型生成文件提交到历史中。
git pull
git pull 通常先执行 fetch,再按照配置或命令参数进行整合。不能简单断言它永远等同于 git fetch && git merge,因为它也可以采用 rebase 或只允许快进:
# 获取远程并按默认策略整合当前上游
git pull
# 明确使用 merge
git pull --no-rebase origin main
# 明确使用 rebase
git pull --rebase origin main
# 只允许 fast-forward,有分叉就停止
git pull --ff-only origin main
常见显式写法:
git pull <远程名> <远程分支>:<本地分支>
实际工作中推荐先 git fetch,查看差异后再选择 merge 或 rebase;这样不会因为一个默认配置不清楚而意外改写当前分支历史。
git fetch
git fetch 只从远程获取对象和引用,更新 origin/main 等远程跟踪分支,不会自动修改当前本地分支的工作区:
# 获取 origin 的远程更新
git fetch origin
# 获取指定远程分支
git fetch origin main
# 获取所有远程
git fetch --all --prune
--prune 会清理远程已删除、但本地仍保留的 remote-tracking 引用。fetch 完成后可以比较:
git log --oneline HEAD..origin/main
git diff HEAD..origin/main
git branch、switch 和远程分支
# 查看本地分支
git branch
# 创建本地分支但不切换
git branch feature/login
# 推荐:切换到已有分支
git switch feature/login
# 推荐:创建并切换
git switch -c feature/login
# 查看远程跟踪分支
git branch -r
# 查看本地和远程跟踪分支
git branch -a
# 安全删除已经合并的本地分支
git branch -d feature/login
# 强制删除本地分支,可能丢失未合并提交的引用
git branch -D feature/login
# 重命名当前分支
git branch -m new-name
# 首次推送并建立上游关系
git push -u origin feature/login
# 删除服务器上的远程分支
git push origin --delete feature/login
旧版本和历史文章常使用:
git checkout feature/login
git checkout -b feature/login
checkout 仍然有效,但 Git 2.23 之后更推荐用 switch 表达分支切换,用 restore 表达文件恢复。
工作中使用 Git 解决问题的场景
git rebase:让提交记录更清晰
rebase(变基)会把一组提交重新应用到新的基础提交上。它与 merge 都能整合两个开发方向,但 rebase 会生成新的提交对象并改变提交 ID,因此一般只对个人分支、未共享历史或已取得团队同意的分支使用。

假设有两条分支:master 和 feature/1,它们都从初始提交 add readme 创建。之后:
master增加3.js和4.js,产生两次提交;feature/1增加1.js和2.js,也产生两次提交。
master 分支的历史:

feature/1 分支的历史:

合在一起看,两个分支从共同祖先分叉:

切换到功能分支后执行:
git switch feature/1
git fetch origin
git rebase master
如果以 origin/main 为集成分支,现代项目通常写成:
git rebase origin/main
rebase 会找到功能分支相对于共同祖先的提交,暂时移除这些提交,把当前分支基点移动到 master 最新提交,再按顺序重新应用功能分支的提交。它不是“把 master 的每个提交复制到 feature 后再保留原 feature 提交”,而是重放 feature 的独有提交。

完成后,两个分支通常会呈现一条较直的历史,但提交 ID 已经发生变化。如果功能分支之前已经推送到远程,更新远程时应优先使用:
git push --force-with-lease origin feature/1
--force-with-lease 会检查远端分支仍是自己预期的旧状态,比无保护的 git push -f 安全,但仍应先确认分支和协作者影响。
rebase 冲突处理
rebase 过程中如果某个提交与新基础发生冲突,Git 会暂停:
# 编辑冲突文件后
git add <已解决的文件>
git rebase --continue
# 放弃当前 rebase
git rebase --abort
# 确认当前提交的改动不需要时跳过
git rebase --skip
由于 rebase 是逐个重放提交,多个提交可能分别产生冲突;merge 则通常在一次三方合并中解决冲突,但复杂合并仍可能需要多轮处理。解决冲突后一定要运行测试,不能只看到 rebase 成功就认为功能正确。
git merge 和 git rebase 的区别
当不是 fast-forward 时,git merge 通常生成一个新的合并提交:
git switch main
git merge feature/1

| 对比项 | merge | rebase |
|---|---|---|
| 历史 | 保留真实分叉和合并关系 | 重新生成提交,通常更线性 |
| 提交 ID | 原提交通常保留 | 被重放的提交会生成新 ID |
| 共享分支 | 通常更安全 | 需要谨慎,可能改写公共历史 |
| 冲突 | 通常在合并过程中集中处理 | 可能随每个重放提交逐步处理 |
| 适合场景 | 公共分支整合、保留拓扑 | 个人分支同步主线、整理未公开提交 |
merge 是否生成合并提交还取决于是否 fast-forward、--no-ff 和团队策略。rebase 也不是“让历史变漂亮”的无风险按钮:它会改变提交身份,公共分支通常应通过受保护分支、合并请求和明确的线性历史策略完成。
git rebase 交互模式
开发中经常会产生“修正拼写”“调试日志”“临时尝试”等不适合保留在公共历史中的提交。交互式 rebase 可以重新排序、编辑、合并或删除一段尚未共享的提交。

执行:
git rebase -i <base-commit>
<base-commit> 是提交范围的上游边界,Git 会编辑“该基点之后、当前分支可达”的提交。比如想整理基于 ac18084 之后的提交:
git rebase -i ac18084
在编辑器中常见操作:
pick 保留提交
reword 保留改动但修改提交信息
edit 应用提交后暂停,手动修改
squash 合并到前一个提交并重新编辑信息
fixup 合并到前一个提交并丢弃当前提交信息
drop 删除当前提交

例如把后面几个提交压缩成一个:
pick 第一个有效提交
squash 第二个提交
squash 第三个提交
squash 第四个提交
至少需要保留一个提交行;如果确实希望删除整个范围,要明确处理结果和工作区。s 是 squash 的缩写,f 是 fixup 的缩写。
保存退出 Vim 通常是 Esc、输入 :wq、回车;也可以使用 VS Code 等编辑器,通过 git config --global core.editor 配置。之后 Git 可能打开另一个提交信息编辑器:
git add <文件>
git commit --amend --no-edit
git rebase --continue
完成后,历史会被整理成新的提交序列:

特别注意:不要在别人已经基于其开发的集成分支上随意 rebase。技术上并非“任何共享分支绝对不能 rebase”,但必须先达成一致,否则会迫使协作者重新同步、解决重复提交和强制推送问题。
使用 git cherry-pick 获取指定 commit
git cherry-pick 可以理解为“挑拣”提交:它把一个或多个已有提交引入当前分支,并为每个变更创建新的提交。它不同于 merge 的地方是,不会把整个分支的提交图合并进来。
常见场景:
- 把已经完成的线上修复从开发分支带到 release 分支;
- 只把某个功能提交带入稳定分支,不引入同一分支的其他实验提交;
- 在干净分支上选择性恢复一组提交。



切换到目标分支后,复制单个提交:
git switch main
git cherry-pick <commit-hash>
cherry-pick 会生成新的提交,因此新提交的对象 ID 通常不同;提交内容、作者时间等信息可能被保留,但提交者和父提交会是当前分支环境。

cherry-pick 多个提交
可以列出多个不连续提交:
git cherry-pick <commit-1> <commit-2>
连续提交可以使用范围:
git cherry-pick <first-commit>^..<last-commit>
A^..B 在常见线性历史中表示包含 A 和 B 的区间(左边界通过 A^ 排除其父提交)。遇到合并提交、多父提交或复杂图时,范围仍按提交可达性解释,应先用日志确认实际选中的提交:
git log --oneline <first-commit>^..<last-commit>
cherry-pick 冲突处理
多个提交按顺序应用时,某一步可能产生冲突:
git switch main
git cherry-pick <commit-c>^..<commit-e>
如果在提交 d 处冲突:
# 解决冲突并暂存结果
git add <文件>
git cherry-pick --continue
# 放弃整个 cherry-pick 序列
git cherry-pick --abort
# 停止流程但保留当前工作区和已完成的提交
git cherry-pick --quit
# 跳过当前提交(确认该提交不需要时)
git cherry-pick --skip
原文中 abort 命令的 Git 子命令拼写有误,正确形式见上面的代码。cherry-pick 前应尽量保持工作区干净,冲突解决后应检查测试和提交内容。
使用 git revert 回滚某次提交
想象这样一个场景:线上功能存在 bug,但目标分支还包含其他同事的提交。如果直接 reset,可能把整个分支指针和工作区回退,影响其他人的历史。git revert 更适合在共享分支上公开撤销一个已经存在的提交。
git revert不删除原提交,而是根据原提交的变更创建一个新的反向提交。它要求工作区干净,冲突时需要手动处理。
revert 普通提交
git revert <commit-id>
可以添加 --no-edit 使用默认提交信息,也可以一次指定多个提交:
git revert --no-edit <commit-a> <commit-b>
多个参数表示多个明确提交,不是“前开后闭区间”。如果要撤销连续范围,常见写法是:
git revert <oldest-commit>^..<newest-commit>
Git 会按适合撤销的顺序处理范围,但复杂提交图仍可能冲突,执行前建议先查看范围和备份分支。

git revert 21dcd937fe555f58841b17466a99118deb489212

Git 可能打开编辑器填写提交信息。保存后会生成新的 Revert "原提交信息" 提交:
原提交仍保留在历史中,但它引入的文件变化被新的反向提交抵消。反向提交也可能与后续代码冲突,不能保证永远一键完成。
revert 合并提交
合并提交有多个父提交,Git 需要知道哪一个父提交是主线。语法是:
git revert -m <parent-number> <merge-commit>
通常 -m 1 表示把第一个父提交当作主线,撤销相对于该主线引入的另一侧变更;1 不是“保留主分支”的绝对规则,必须结合提交图确认父提交含义。


直接对合并提交执行普通 revert 可能报错,因为 Git 不知道应当相对于哪个父提交计算反向变更:
git revert -m 1 <merge-commit>
revert 合并提交后再次合并
revert 一个合并提交后,原功能分支的提交对象仍然在历史中,Git 可能判断该分支已经合并过,因此再次直接 merge 不会自动重新引入原来的变更。这不是“以后永远不能合并”,而是提交图的祖先关系仍然存在。

如果确认要恢复之前被 revert 的整体变更,通常可以 revert 那个 revert 提交:
git revert <revert-merge-commit>

如果功能分支已经产生了新的修复提交,也可以创建新的提交或新分支,再通过合并请求处理。恢复前应确认哪些代码已经修复,避免把原来的 bug 一起恢复。
使用 git stash 临时保存文件
开发功能时,线上出现紧急 bug,但当前功能还没有完成,不想创建一个质量很差的临时提交,可以使用 stash 保存本地改动,然后切换到 hotfix 分支。
git stash 保存的是本地工作区/索引状态,不是远程备份,也不应代替长期提交。默认主要处理已跟踪文件;未跟踪文件需要 -u,被忽略文件需要 -a。
# 使用现代写法并添加说明
git stash push -m "暂存登录功能"
# 同时保存未跟踪文件
git stash push -u -m "暂存未跟踪文件"
# 查看 stash 列表
git stash list
# 应用最近一条并删除该条 stash
git stash pop
# 应用但保留 stash
git stash apply stash@{0}
原文中的 git stash save "message" 是历史写法,目前更推荐 git stash push -m "message"。save 在许多版本仍可用,但不应作为新文档的首选。
stash 的应用场景
如果当前工作区有改动,直接切换到 hotfix 可能会出现:

error: Your local changes to the following files would be overwritten by checkout:
1.js
Please commit your changes or stash them before you switch branches.
可以先查看状态,再保存:
git status --short
git stash push -m "WIP: 暂存未完成功能"
git switch hotfix
# 修复并提交线上问题
git switch feature/login
git stash pop
如果 pop 产生冲突,先解决冲突并检查工作区;应用冲突时 stash 通常不会自动丢失,处理前不要直接执行 clear。

VS Code 中使用 stash
VS Code 的 Source Control 面板和 Git 扩展可以创建、查看和应用 stash。不同版本界面可能不同,命令行仍然是最稳定、可复现的方式。

填写备注或直接确认:

在 STASHES 菜单中查看保存记录:

选择记录后可以执行 Apply 或 Pop:

不同工作区域如何撤销更改
开发中要区分“工作区改动”“暂存区改动”和“已经提交的历史”。现代 Git 推荐使用 restore 表达文件恢复;reset 仍然适合移动当前分支或取消暂存。
首先检查状态:
git status --short
git diff
git diff --staged

修改文件后:

丢弃工作区未暂存改动
# 恢复指定文件到暂存区版本,丢弃该文件未暂存修改
git restore -- <filename>
# 一次恢复多个文件
git restore -- file1.js file2.js
旧命令 git checkout -- <filename> 仍然有效,但语义不如 restore 明确。以下命令会丢弃工作区改动,执行前确认没有需要保留的数据:

取消暂存但保留工作区改动
文件已经 git add 后,如果暂时不想提交,可以:
# 推荐
git restore --staged <filename>
# 历史写法,不移动 HEAD
git reset HEAD -- <filename>
这只会把文件从暂存区取消暂存,工作区内容仍然保留:

git reset <filename> 是路径形式,不要和 git reset --hard <commit> 混淆。前者只操作暂存区,后者会移动 HEAD 并可能丢弃已跟踪工作区改动。
配置 Git alias 提升工作效率
在工作中经常要使用 branch、switch、fetch、rebase、add、commit 和 push。可以为高频、无歧义的命令配置别名:
git config --global alias.st "status --short --branch"
git config --global alias.ci commit
git config --global alias.br branch
git config --global alias.sw switch
git config --global alias.unstage "restore --staged"
原文中的 co=checkout、ci=commit、br=branch 仍可用,但新项目可以使用 sw=switch 和 unstage=restore --staged,减少 checkout 的多重语义。

--global 表示写入当前用户的全局配置,通常是 ~/.gitconfig;不加 --global 则只写入当前仓库配置:
git config --list --show-origin
git config --global --edit

也可以直接编辑配置文件中的 [alias] 区域:
[alias]
st = status --short --branch
sw = switch
ci = commit
br = branch
mg = merge
ds = diff --staged
last = log -1 HEAD
type = cat-file -t
dump = cat-file -p
lg = log --color --graph --pretty=format:"%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %Cblue<%an>%Creset" --abbrev-commit
复杂 alias 中的引号、百分号和转义符可能受到 shell、配置文件和平台差异影响,应先用 git config --get-regexp '^alias\.' 检查。带 ! 的 shell alias 可以执行任意命令,团队共享配置前要审查安全性。
以后可以使用:
git lg
git st

Git 不要只会 pull 和 push:实用命令补充
前面介绍了常用工作流,下面保留原文的“5 条提高效率的命令”部分,并用当前 Git 语义重新整理。命令的价值不在于背诵,而在于明确它会修改工作区、暂存区、当前分支还是远程引用。

stash:保存未完成工作
线上修复场景可以使用:
git status --short
git stash push -u -m "WIP: 未完成的功能"
git switch hotfix
git pull --ff-only origin hotfix
# 修复、测试、提交
git switch feature/login
git stash pop
如果改动已经足够形成一个有意义的阶段性版本,创建临时提交或临时分支通常比长期 stash 更容易追踪。stash 适合短期切换上下文,不适合团队协作传递代码。

reset --soft:重新整理本地提交
reset --soft 会移动 HEAD/当前分支,但保留暂存区和工作区内容。它适合整理尚未共享的提交:
# 把最近一次提交撤回,但保留其内容在暂存区
git reset --soft HEAD^
# 重新整理后提交
git commit -m "整理后的提交信息"

例如提交历史为 a - b - c,执行:
git reset --soft a
HEAD 移到 a,b 和 c 引入的差异会进入暂存区;它们不是“只恢复某一个 commit”,而是恢复目标提交之后直到原 HEAD 的累计差异。

如果这些提交已经推送且只是自己的功能分支,可以在确认没有覆盖他人工作的前提下:
git push --force-with-lease origin feature/login
共享分支不建议这样改写,优先使用 git revert。
cherry-pick:复制指定提交
使用场景包括把某个修复提交带到 release 分支,或把功能分支中的独立提交选择性带到干净分支:
git switch main
git cherry-pick <commit-hash>



多个连续提交:
git cherry-pick commit1^..commit2
这里的范围在普通线性历史中包含 commit1 和 commit2;复杂提交图中应使用 git log commit1^..commit2 检查实际范围。发生冲突时:


git add <已解决文件>
git cherry-pick --continue
# 放弃整个序列
git cherry-pick --abort
# 退出序列但保留当前结果
git cherry-pick --quit

revert:公开撤销提交
revert 适合已经进入共享分支的错误提交:
git revert <commit-id>
它新增反向提交,不删除原提交。普通提交可以直接 revert;合并提交需要指定主线父编号:
git revert -m 1 <merge-commit>

Git 可能打开提交信息编辑器;可以保留默认的 Revert "..." 信息,也可以通过 --no-edit 跳过编辑器:


对于连续提交可以使用 oldest^..newest 范围,但要先确认撤销顺序和依赖关系。revert 可能冲突,完成后要运行测试和部署检查。
reflog:错误操作后的恢复入口
reflog 是本地引用的变更记录,不是“所有 commit 操作的远程日志”。它经常能帮助找回 reset、rebase、误删分支或 detached HEAD 前的提交:
git reflog
git reflog show main
典型事故:误执行 git reset --hard,分支指针退得太远。先不要继续提交或运行会清理对象的命令,查看 reflog 找到旧位置:
git reflog
# 找到类似 HEAD@{1} 或旧 commit-id 后
git switch --detach <旧提交>
git switch -c recovery/restore-work
也可以把分支直接重置回恢复点,但要先确认当前分支和工作区:
git reset --hard <recovery-commit>




注意:
- reflog 默认是本地记录,不会随 push 上传;
- reflog 会按配置过期,不能永久保存;
- 没有引用可达的对象最终可能被垃圾回收;
- 误操作后应尽快建立恢复分支或复制对象 ID;
- 远程已经被覆盖的分支还需要根据远程日志、其他克隆或托管平台记录恢复。
一套更稳健的日常工作流
# 开始工作
git status --short
git fetch origin
git switch -c feature/login # 如果分支尚不存在
# 开发和提交
git add -p
git diff --staged
git commit -m "实现登录功能"
# 同步主线
git fetch origin
# 二选一:个人分支常用 rebase
git rebase origin/main
# 或者在团队策略要求下使用 merge:
# git merge origin/main
# 推送个人功能分支
git push -u origin feature/login
# 合并请求通过后清理
git switch main
git pull --ff-only origin main
git branch -d feature/login
git push origin --delete feature/login
提交或推送前建议检查:
git status是否存在未预期的文件;git diff --staged是否只包含当前需求;- 是否误提交
.env、令牌、私钥、构建产物或依赖目录; - 是否在公共分支上使用了 reset、rebase 或 force push;
- cherry-pick、revert、merge 后是否运行测试;
- 远程分支是否受保护、是否必须通过 CI 和代码评审。
总结
本文主要分享了 Git 环境配置和工作中常用的命令:
add:把工作区快照放入暂存区;commit:把暂存区写入本地提交图;pull/fetch:从远程获取更新,pull 还会执行整合;rebase/merge:整合分支历史;cherry-pick:选择性复制提交;revert:用新提交公开撤销旧提交;stash:短期保存未完成工作;reset --soft:整理未共享的本地提交并保留改动;restore:恢复工作区或取消暂存;reflog:查找本地引用曾经指向的位置;alias:缩短高频命令,但复杂 alias 要注意可读性和安全性。
最重要的是理解命令会改变哪一层:工作区、暂存区、本地提交历史、当前分支,还是远程引用。个人分支可以在确认影响后整理历史;多人协作的集成分支优先通过 merge 请求、revert、分支保护和 CI 保持可追踪性。
参考资料
- Git 官方文档
- Git 官方快速参考
- git-pull
- git-fetch
- git-branch
- git-switch
- git-restore
- git-rebase
- git-merge
- git-cherry-pick
- git-revert
- git-stash
- git-reset
- git-reflog
- git-config
- GitHub:使用 SSH 连接
- GitHub:认证方式
- 阮一峰的 Git 教程
- Git merge 和 rebase 分支合并命令的区别