先说个真实的感受:Git 的“常用命令”可能是被写烂了的话题,搜出来十条有八条都在罗列命令清单——git add、git commit、git push,一条条排下来,看着很全,真到用的时候还是懵。我写这篇东西的出发点很简单,就是想把它换一种讲法:不按命令字典的顺序讲,而是按真实开发一天里会经历的场景讲,比如“我刚改完代码想提交”“我发现刚才那次提交信息写错了”“我本地和远程打架了”“我不小心把分支删了”。把这些场景拆开,你会发现真正高频的 Git 命令其实不多,而且每一个背后都有明确的“为什么”。
这篇文章适合两类人:一类是刚入行、被 Git 复杂的输出和概念吓住的新手,另一类是用了两三年 Git、日常只会 add/commit/push 的老开发。前者可以把这篇文章当一条主线,按顺序读下来;后者可以直接跳到第 4、5 章,重点看分支整合和历史回滚的部分,里面有我踩过坑之后总结出来的实操习惯。
1. 先把思路理顺:Git 命令不是背出来的,是“走流程”走出来的
1.1 为什么很多人学完命令还是不会用
我给不少同事做过 Git 培训,发现一个规律:单独拎出一个命令,比如 git branch、git merge,大家都能说出大概意思;但一旦遇到“我在 dev 分支上改到一半,临时要去修 bug”“我提交推上去了发现里面有敏感信息”这种实际场景,就卡住了。问题不在命令本身,而在于大脑里没有建立 Git 的“状态模型”。
Git 本质上是一套内容寻址的文件系统,这句话听起来玄乎,其实可以比喻成写文章:你的工作区是桌面上的草稿纸,你随便写随便画;暂存区是一个半透明的文件夹,你决定把哪些段落先放进去排队;本地仓库是保险柜,你把排好队的段落正式归档;远程仓库是出版社,你把保险柜里的内容公开给团队看。这四个区域之间的移动,就是 Git 命令在做的事。
理解了这个模型,你会发现一切命令都可以归纳成一句话:把文件从哪个区域移动到哪个区域。git add 是从工作区到暂存区,git commit 是从暂存区到本地仓库,git push 是从本地仓库到远程仓库。反过来,git restore 是从暂存区拉回工作区,git reset 是回退本地仓库的指针,git pull 是把远程仓库的内容抓到本地并与当前工作区合并。区域模型一旦建立,命令就不会再忘。
1.2 我用得最多的“命令主线”
日常开发中,有 90% 的操作其实只围绕一条主线在转:改代码 -> 看差异 -> 暂存 -> 提交 -> 拉取最新 -> 推送 -> 看历史。
- 改完代码,先
git status看有哪些文件变了; - 用
git diff确认具体改了什么; - 用
git add把要提交的文件放上暂存区; - 用
git commit生成一个本地提交; - 推送前先
git pull --rebase把远程最新内容合进来; - 用
git push推到远程; - 需要回溯时用
git log看提交历史。
这条主线的每个节点,背后都有若干替代命令,这就是 Git 的全部“常用命令”。所以我这篇文章的主体结构,就是围绕这条主线展开的:先讲环境安装与配置(没装好工具,后面全是空谈),再讲日常提交与历史管理,然后讲分支整合(这是多人协作的核心),最后讲远程协作与状态恢复(这是“后悔药”和“救火现场”)。
1.3 一个小建议:提前配好别名,效率翻倍
在进入正题之前,先分享一个能显著提升日常效率的习惯:配置命令别名。Git 支持通过git config --global alias.xxx把长命令缩短,我的配置是:
git config --global alias.co checkout git config --global alias.ci commit git config --global alias.st status git config --global alias.br branch git config --global alias.lg "log --oneline --graph --decorate --all" git config --global alias.unstage "restore --staged"配完之后,git st就是git status,git lg就是一张带分支图和装饰信息的简洁历史图。很多人会觉得“多用几个字母也没差”,但实际当你一天执行上百次 Git 命令时,这点差别会直接影响注意力的连续性。我所有后续章节里的演示,都会用完整命令名来写,方便你理解底层逻辑;实际使用时你可以根据自己的别名习惯来敲。
2. 环境准备:把 Git 装好,才是所有命令的前提
2.1 不同系统下的安装方式
安装没有统一标准,不同操作系统各有各的取舍,我一个个说:
- Windows:直接下载 Git for Windows 安装包,一路下一步即可。有两个注意事项:第一,安装过程中会让你选择 PATH 环境变量,建议选“Recommended”那个中间选项,这样 Git 命令可以在 CMD 和 PowerShell 里直接用;第二,换行符转换那一页,如果你主要在 Windows 上写代码,选默认的“Checkout Windows-style, commit Unix-style”就好,这个背后的坑我后面讲。
- macOS:优先用 Homebrew 安装,
brew install git,这样能拿到较新的版本。macOS 自带的 Mojave 和更早版本里默认带的 Git 版本偏老,有些新语法(比如 git switch、git restore)不支持,建议升级。 - Linux:Debian/Ubuntu 系用
apt install git,CentOS/RHEL 系用yum install git或dnf install git。版本通常比较稳定,但可能不是最新,日常使用问题不大。
安装完以后,先验证一下:git --version。我见过太多人装完了不验证,实际 PATH 里指向的还是旧版本,到真正遇到命令行为不一致的时候才排查出来。
2.2 配置用户名与邮箱:这件事比你想的重要
第一次装好 Git,有两件事必须做:配置用户名和邮箱。这俩配置最终会写进每一次提交记录里,等于给每个 commit 盖了个章。
git config --global user.name "你的名字" git config --global user.email "你的邮箱"Git 的配置体系分成三层:system(整个机器生效)、global(当前用户生效)、local(当前仓库生效)。优先级是 local > global > system。默认情况下git config --global写入的是用户级配置,这个粒度最合适;如果某个项目需要提交成公司身份,再在项目目录里单独配置 local 覆盖它。
有个细节值得提:如果你用了不同的邮箱提交,GitHub/Gitee 这种平台可能没法把它和你账号绑定起来,贡献图就不显示。更麻烦的是,已经提交的历史里带上错误身份之后,要改就不是简单一条命令能搞定的了,得重写历史,涉及其他同事拉取后的冲突。所以我的习惯是:安装完第一件事,先配好身份再干活。
2.3 SSH 密钥配置:远程协作的第一步
配置 SSH 密钥,是为了让本地和远程仓库(内网 GitLab、Gitee、GitHub 都适用)之间通信时不用反复输密码。原理是本地生成一对公私钥,公钥交给托管平台,私钥留在本地机器上,连接时通过加密握手完成身份认证。
生成密钥的命令:
ssh-keygen -t ed25519 -C "你的邮箱"一路回车,默认会在~/.ssh/下生成两个文件:id_ed25519(私钥)和id_ed25519.pub(公钥)。注意:私钥千万不要泄露,不要提交到仓库里。然后查看公钥内容:
cat ~/.ssh/id_ed25519.pub把输出的那一整行内容复制到 Gitee/GitLab/GitHub 的 SSH Keys 设置页里。验证是否配置成功:
ssh -T git@gitee.com如果返回类似 “Hi xxx! You've successfully authenticated” 的信息,就说明通了。这个过程里最容易踩的坑是:Windows 用户把公钥复制到网页的时候,不小心带了换行或空格,会导致认证失败,这种错误是肉眼很难看出来的,复制完检查一下首尾字符。
2.4 三组值得提前配置的选项
除了身份信息之外,我每次在新环境上都会顺手配这几组选项,它们属于“不配也能用,但配了能少很多天坑”的范畴。
git config --global core.autocrlf input git config --global core.quotepath false git config --global push.default simple git config --global init.defaultBranch main- core.autocrlf:解决跨平台换行符问题。Windows 上默认是 true(换行符自动转 CRLF),macOS/Linux 上建议设为 input,提交时转成 LF。多人协作时如果各系统配得不一致,会出现“整个文件标红但实际没有内容变化”的经典假 diff 问题。
- core.quotepath false:让 Git 在显示中文文件名时不转义成八进制编码。我见过很多人用 Git 状态看中文文件时显示成一串
\345\222\214,其实就是这个选项没开。 - push.default simple:设置默认推送行为。新版 Git 默认就是 simple,它规定只有当前分支的上游分支存在时才推送,避免了一次 push 把一堆本地分支全推出去的误操作。
- init.defaultBranch main:让
git init创建的初始分支名是 main 而不是 master,这是基于行业内近几年的命名习惯变化,对个人项目没什么影响,但能省去后面改名的操作。
最后提一个和热搜词相关的场景:“git 目录泄露如何下载”。这类问题常出现在安全测试或授权排查场景里。核心做法是,如果.git目录被暴露在 Web 服务里,可以用 Git 自带的命令尝试恢复对象,比如git log --reflog、git fsck --lost-found等。但我要明确提醒一句:这属于敏感操作,只能在你自己拥有权限或已经获得授权的环境下做,绝不能拿来扫描、下载别人的站点,否则有安全法律风险。从防御角度看,确保 Web 部署时不要把.git目录放到公开根目录下才是正解。
3. 日常开发主循环:status、diff、add、commit、log 的用法与细节
3.1 提交前先看差异:status 和 diff 是黄金搭档
很多人拿到代码就喜欢直接git add .一把梭,这是我最不推荐的习惯。git add .会把当前目录下所有变更(包括临时文件、日志文件、误放的密钥)全部加进暂存区,等你发现的时候,要么提交了不该提交的内容,要么把调试代码也一起提交了。
我的建议是,每次提交前先走两步:
git status git diffgit status告诉你哪些文件处于什么状态:已修改、已暂存、未跟踪。git diff告诉你还没暂存的那些改动具体是什么内容。等到你把该提交的文件看清楚了,再决定git add哪个文件。
如果这次改动横跨多个文件,但只有部分改动想提交,可以用交互式暂存:git add -p。这个命令会把每个文件的改动拆成若干“代码块”,逐个询问你是否要暂存,按 y 暂存、按 n 跳过、按 s 进一步拆分。它特别适合“我在一个文件里同时改了两个不相关功能,想拆成两次提交”的场景,是专业开发里非常推荐的习惯。第一次用会觉得麻烦,用惯了之后会离不开。
3.2 提交信息怎么写才合格
提交的时候,git commit -m "xx"确实是命令的写法,但提交信息本身的质量,直接决定了团队协作的效率。我见过最崩溃的提交日志是一条“fix bug”,完全不知道修的是什么 bug、在哪个模块。业界比较通用的规范是 Conventional Commits,格式大致是:
<type>[optional scope]: <description> [optional body]其中 type 常用的是:
feat:新功能fix:修 bugdocs:文档变更style:格式调整,不影响逻辑refactor:重构,不改变外部行为test:补测试chore:构建、工具链相关
举例来说,feat: 增加用户注册功能、fix: 修复登录态过期后页面不跳转的问题。这样写有一个额外的好处:很多自动化工具(比如生成 changelog、自动发版)都可以直接解析这些前缀来生成更新日志,等于提交信息变成了机器可读的数据。
如果要写详细的提交说明,可以用git commit不加-m参数,Git 会打开默认编辑器让你写多行信息。如果你不习惯 vim,可以把默认编辑器改成 VSCode:git config --global core.editor "code --wait"。
3.3 查看历史:log 不只是看记录,还能看“故事”
git log最基础的用法是看提交列表,但直接用git log的输出太冗长。我日常用的几个变体:
git log --oneline git log --oneline --graph --decorate --all git log -p git log --stat git log --follow -- <file>--oneline把每次提交压缩成一行,只显示简短的提交哈希和描述。--graph会在左侧画出分支和合并的拓扑图,配合--all(查看所有分支)和--decorate(显示分支/标签指向),基本可以替代很多 GUI 工具的浏览功能。-p展示每次提交的完整 diff,适合排查“这个文件是从哪次提交开始变成这个样子的”。--stat只显示变更统计,不展示具体内容,适合快速了解一次提交动过哪些文件。--follow -- <file>跟踪单个文件的重命名历史,即使某个文件被改名了,也能查到它原来的提交记录。
如果你觉得这些参数太长,就回到我前面说的做法:配成git lg这样的别名,一次搞定。
3.4 提交信息写错了?--amend 登场
如果你的最新一次提交信息写错了,或者发现少提交了一个文件,git commit --amend就是用来“修正最近一次提交”的命令。
git commit --amend -m "修正后的提交信息"这个命令不是真的“修改”了原提交,而是生成一个新的提交对象,把原来的提交替换掉。如果只是想把漏掉的文件补进去,可以先git add漏掉的文件,再执行git commit --amend --no-edit,这样提交信息不变,但文件内容被更新进来。
这里有一个必须讲清楚的限制:--amend的前提是这次提交还没有推送到远程。如果已经 push 了,你在本地 amend 后,本地和远程的历史就会分叉,推送时会被拒绝,这时如果强行用git push -f,会把远程历史重写,其他同事拉取时会遇到无法快进的问题。在团队协作中,强制推送是有纪律的,除非是紧急修复并且所有协作者都知情同意,否则不要这么干。
如果发现写错的不是最近一次提交,而是更早的某一条,那就要用git rebase -i进入交互式变基,找到对应的提交记录,把pick改成reword,再保存退出,Git 会逐条让你重新编辑提交信息。这个操作同样会改写历史,推送到远程前要谨慎。
4. 分支管理与历史整合:switch、merge、rebase、worktree
4.1 分支操作:创建、切换、删除的日常姿势
分支是 Git 最核心的设计,它让多人并行开发互不干扰。基础操作其实就四个:
git branch # 查看本地分支 git branch -a # 查看本地+远程分支 git switch -c new-branch # 创建并切换新分支 git switch main # 切换到已有分支 git branch -d new-branch # 删除分支(已合并时可删) git branch -D new-branch # 强制删除分支(未合并也删)很多人习惯用git checkout来切换分支,我也理解,老教程都是这么教的。新版 Git 推出的git switch和git restore,其实是把 checkout 这个“大而全”命令拆开了:git switch只负责分支切换,git restore只负责文件恢复。好处是语义更清晰,新手不容易把“切换分支”和“恢复文件”搞混。老手用哪个全凭习惯,但我建议新人在学习阶段直接用git switch和git restore,可以减少概念负担。
删除分支有个细节:git branch -d会检查该分支是否已经合并到当前分支,如果没合并会拒绝删除,防止你丢失未合并的提交;-D是强制删除,用之前务必确认这个分支上没有什么有价值的东西。我自己以前就手滑删过一个只存在于某分支上的本地提交,后来是靠 reflog 找回来的,这个后面展开讲。
4.2 merge 和 rebase 的底层区别
合并分支有两种主流方式,很多人纠结选哪个,其实它们解决的侧重点不一样。
git merge会保留两条分支的完整历史,合并时生成一个“合并提交”(merge commit),它的祖先有两个父提交。历史图看起来是分叉再汇合的,能清楚地看到“这里有一次合并基于两个分支”。代价是历史不是线性的,git log里会有分叉。
git rebase是把当前分支的提交“搬到”目标分支的最新提交之后,重新应用一遍。它不会产生 merge commit,历史是一条直线,非常干净。代价是当前分支上的提交对象会被重新创建,哈希值全部改变,所以如果这个分支已经被推送到远程并被别人拉了,再做 rebase 就会引发历史不一致。
场景上,我的习惯是:个人开发分支整合到共享主干前,用 rebase 让历史线性;共享分支之间同步,或release分支往主干合并,用 merge 保留准确的合并记录。但要注意,团队协作里一定要先约定规则,否则有人用 merge 有人用 rebase,历史会乱成一锅粥。
4.3 交互式变基:把多个小提交整理成有意义的记录
开发过程中,你可能提交了多次“中间状态”,比如 “wip”、“改了一部分”、“再修一下”。推到远程之前,把这些小提交整理成几个逻辑完整的提交,能让历史干净很多。这就是git rebase -i的主要用途。
假设当前分支上有 3 个提交需要整理:
git rebase -i HEAD~3执行后进入编辑器,内容类似:
pick abc123 添加用户模块 pick def456 修复用户模块的小问题 pick 789abc 补充用户模块的单元测试常见的操作是:
- 把
pick改成squash,表示把该提交合并进上一个提交,并允许你重新编辑合并后的提交信息; - 改成
fixup,表示合并进上一个提交,保留上一个提交的信息,当前提交的信息被丢弃; - 改成
reword,表示保留该提交,但重新编辑提交信息。
比如我想把后两个合并进第一个,就把 def456 和 789abc 前面的pick改成fixup,保存退出,Git 会自动重放这 3 个提交,最后只剩下一个包含完整改动的提交。这个命令功能很强,但也容易触发冲突,如果 rebase 过程中有冲突,Git 会停下来让你解决,解决完用git add标记后执行git rebase --continue继续。如果中间决定放弃,用git rebase --abort回到操作前的状态。
4.4 git worktree:多分支并行,真正的神器
热搜词里有git worktree,这个命令在日常里确实被严重低估了。它在“我需要同时处理两个分支”的场景下非常好用。
普通情况下,一个仓库目录同一时刻只能检出一个分支。你正在 dev 分支上改到一半,突然线上反馈有个 bug 要马上修,你的选择无非是:先提交/暂存当前工作,切换回 main 分支再拉新分支修复。这个流程每次都要处理当前工作区,很打断节奏。
git worktree允许你从同一个仓库派生出多个工作目录,每个目录可以各自检出不同的分支,互不影响。用法:
git worktree add ../project-hotfix hotfix这会在../project-hotfix创建一个新的工作目录,并且把 hotfix 分支检出来。你可以在这个目录里专注修 bug,原来目录里的 dev 分支工作区完全不被打扰。修完之后推送/合并,再清理:
git worktree remove ../project-hotfix小坑提醒:
- 同一个分支不能在多个 worktree 里同时检出,否则 Git 会报错,这个设计是为了避免一个分支在多工作目录同时写导致索引错乱。
- worktree 的元数据记录在
.git/worktrees目录里,删掉 worktree 之后可以执行git worktree prune清理失效记录。 - 如果是临时用一下,记得用完就删,别堆一堆目录在那里,否则时间长了自己都分不清。
我第一次用 worktree 是因为“dev 开发到一半 + 线上紧急 bug”同时出现,从那之后就离不开了。建议有条件的朋友都在日常流程里试一下。
5. 远程协作与状态恢复:remote、push、pull、reset、revert
5.1 远程仓库管理:add、remote、clone、fetch 一起讲清
远程协作最基本的操作是git clone,这个命令会把远程仓库完整复制到本地,包括所有分支和历史。之后通过git remote -v查看当前配置的远程地址:
git remote -v git remote add origin git@gitee.com:your/your-project.git git remote set-url origin git@gitee.com:your/your-project.git大多数人一个仓库只有一个远程,叫 origin。如果参与开源项目,你往往会 fork 一个到自己名下,再同时配置自己的 fork(通常叫 origin)和上游项目(通常叫 upstream):
git remote add upstream git@gitee.com:upstream/your-project.git这种“双远程”模式下,日常同步时从 upstream 拉取更新,推送时推到自己的 origin,再通过 Merge Request 向上游贡献代码。
很多人分不清git fetch、git pull的区别。简单说,fetch只会把远程最新提交下载到本地“远程跟踪分支”(比如 origin/main),不会动你当前工作区的任何内容;pull是 fetch + merge 的组合,会把远程变更直接合并进当前分支。如果你想先看看远程改了啥、再决定怎么合并,就先git fetch再git log origin/main分析,最后手动git merge origin/main。如果你确定远程变更可以直接合,就省略中间步骤直接用git pull。
5.2 推送被拒绝的经典场景:处理非快进合并
git push最常见的报错是:
! [rejected] main -> main (non-fast-forward) error: failed to push some refs原因很简单:你本地 main 分支落后于远程 main 分支,远程有本地没有的新提交。Git 不允许直接覆盖,所以拒绝推送。解决办法是先拉取再推送:
git pull --rebase git push为什么我要推荐git pull --rebase而不是直接git pull?因为直接git pull在双方都改了同一文件时会产生一个 merge commit,历史会多一条分叉。git pull --rebase等价于先把本地提交“暂存”起来,把远程新提交拉下来,再把本地提交重新应用到远程最新提交之后,历史最终是一条直线。如果 rebase 过程中有冲突,Git 会停下来让你手动解决,处理方式跟上文 rebase 冲突一样:改文件、git add、git rebase --continue。
我还碰到过一次输出:
login failed. check api token or gitlab version. log in via git if the version...这个场景通常在 GitLab 的 Web IDE 上操作时报错,常见原因是访问令牌过期、或 IDE 插件和 GitLab 版本不匹配。解决办法是先确认令牌有效性,再检查 GitLab 版本是否在插件支持的范围内,必要时重新生成 access token 并在 IDE 里重新登录。这类问题不是 Git 命令本身的问题,但遇到时要会判断排查方向。
5.3 三种撤销场景:reset、restore、revert 的分工
撤销操作是 Git 里最容易被绕晕的部分,因为有三套命令,关键词相似,适用场景却完全不同。我先把结论放在前面,再逐个解释:
| 命令 | 适用场景 | 对历史的影响 |
|---|---|---|
git restore <file> | 工作区误改,想还原 | 不改动暂存区、不改历史 |
git restore --staged <file> | 误加了暂存区,想取消 | 只把暂存区退回工作区 |
git reset --soft HEAD~1 | 提交了但想保留改动重新提交 | 撤销提交,改动保留在暂存区 |
git reset --mixed HEAD~1 | 提交了但想保留改动在工作区 | 撤销提交,改动保留在工作区 |
git reset --hard HEAD~1 | 提交错了且改动全不要 | 撤销提交,直接丢弃改动 |
| `git revert | 已推送到远程,想撤销某次提交 | 提交一个反向提交,改写不了过去 |
git restore是“后悔工作区/暂存区的操作”,不会动提交历史,最安全;git reset是“移动当前分支指针”,可以退回提交,但这种“缺失”的提交只在 reflog 里可找回;git revert适用于远程已推送的场景,它不会删除已有提交,而是新建一个“反过来的提交”来抵消原来的改动,保证历史不被重写,团队其他人拉取时是安全的。
举个例子:你执行了git commit,推到了远程,过一会儿发现这次提交里引入了一个严重的 bug。你不要想着git reset回退再强推,直接:
git revert <commit-hash>Git 会生成一个Revert "xxx"的新提交,把之前那次提交的改动内容全部反向执行一遍,然后正常推送即可。这样远程历史始终是一条追加的线,所有协作者的本地仓库都能平滑同步,不会出现“我这边历史变了你们全得重新拉”的尴尬。
reset和revert怎么选,我的判断标准就一条:提交有没有推到远程。没有推送,用 reset 随意整理;已经推送,就用 revert 追加一个反向提交。这条规则写进团队约定里,能避免绝大多数历史冲突。
5.4 reflog:Git 里的“后悔药”
不管是 reset 回退了、分支被强制删除、还是提交被 rebase 重放,只要这些对象还残留在本地仓库里,git reflog就能找到它们的踪迹。reflog 是 Git 在每个本地仓库上维护的“操作日志”,记录了 HEAD 指针每一次移动的历史。
举个例子,假设我误删了一个分支 hotfix,可以先看 reflog:
git reflog输出类似:
abc123 (HEAD -> main) HEAD@{0}: checkout: moving from hotfix to main def456 HEAD@{1}: commit: fix: 修复登录跳转bug看到 hotfix 分支最后指向的提交是def456,然后直接恢复分支:
git branch hotfix def456提交就找回来了。如果是git reset --hard把提交回退了,也可以从 reflog 里找到回退前的哈希,再git reset --hard <hash>跳回去。
这里有个重要提醒:reflog 是本地记录,不是远程数据,它默认只保留 90 天,而且只在当前机器上有效。如果提交已经清理过一段时间,或者换了一台电脑,reflog 也救不了你。所以万一误操作,先别慌,也别做任何新的提交或 fetch/prune 操作,尽快去查 reflog。
6. 常见问题速查表与我的使用习惯
6.1 高频小故障排查
把我在群里、Stack Overflow 上、同事工位上见过的高频问题整理成了速查表,按“现象 -> 原因 -> 解决”一条条对照:
| 现象 | 常见原因 | 解决办法 |
|---|---|---|
中文文件名显示为\345\274\200 | core.quotepath 为 true | git config --global core.quotepath false |
| 提交者名字不对 | 未配 user.name/user.email | 按 2.2 配置,已有提交需改写历史 |
| push 被拒 non-fast-forward | 本地落后于远程 | git pull --rebase后重新 push |
| 文件内容没改但 diff 全红 | 换行符 CRLF/LF 不一致 | 统一配置 core.autocrlf |
| 执行 git pull 时有冲突 | 双方改了同一文件同一区域 | 手动改冲突文件,add 后 commit 或 rebase --continue |
| commit --amend 后 push 失败 | 已推送过的提交被改写 | 团队协商后用 revert 或谨慎强推 |
| SSH 连接 Permission denied | 公钥未配或私钥不对 | 重新配置 SSH 密钥,见 2.3 |
| git worktree 报错无法检出分支 | 该分支已在其他 worktree 检出 | 先切走该分支再添加,或直接换新分支 |
| 找回被 reset 的提交 | reflog 里找 hash | git branch recover <hash>后合并 |
这张表覆盖了我日常 80% 以上的求助场景。如果你遇到的问题不在表里,也可以试着用git help <命令>或git <命令> -h查看内置帮助,Git 的自带文档质量非常高,只是很多人从没打开过。
6.2 一个容易被忽略的细节:git -c 是什么
热搜词里有这么一条:git -c diff.mnemonicprefix=false -c core.quotepath=false --no-optional-locks。有些人可能好奇,这串东西是什么?
git -c的意思是“本次执行临时生效的配置项”,不会写入 config 文件。比如:
git -c core.quotepath=false status等同于临时把core.quotepath关掉再执行 status,对这条命令单独生效。而--no-optional-locks是让 Git 在读取操作时不上可选的锁文件,常被 IDE 在执行后台 Git 操作时使用,避免因为锁文件拖慢性能或引起冲突。在我实际使用经验里,最强的场景是:当你不想长期改动全局配置,又想在某个特定命令里试试某个选项是否有效果时,git -c是最合适的方式。
6.3 最后想分享的实操心得
很多开发者在学 Git 时,总想“背完所有命令再上手”,结果越看越焦虑。实际上,日常主线的命令就十来个,我在这篇文章里已经全部覆盖。把状态模型建立起来,把场景对应到命令,再通过反反复复的日常操作,把这些命令变成肌肉记忆,Git 就不再是拦路虎。
如果让我给三个建议,我会说:
第一,提交频率要高,粒度要小。小步快跑不仅让git log可读性更强,更重要的是,每次回滚、cherry-pick 时,小提交意味着更低的风险,不会因为一次回退牵动一大批无关改动。
第二,多个分支并行时多用git worktree。这是我在 2024 年之后用下来提升最明显的习惯,它让我不再被“切换分支打断状态”这件事困扰。
第三,凡是已经推送到远程的提交,绝不用 reset 重写,用 revert 互补。只要这个原则被团队所有成员坚持,几乎所有历史冲突都不会发生。
根据我个人的经验,这些习惯越早建立,后面踩的坑越少。希望这篇文章能在你下一次“不知道用什么命令”的时候,帮你省下十分钟搜索时间。