如果你是刚接触代码版本管理,或者已经用了一段时间 Git 但总在几十个命令之间反复试错,这篇内容应该能帮上忙。Git 本身不是一个难上手的工具,麻烦的是命令体系太庞杂,网上资料又多,初学者很容易今天记这个明天忘那个。日常工作里真正高频使用的 Git 命令其实就几十个,把每个命令背后的行为逻辑搞清楚,比死记硬背几百条命令有效得多。这份指南按“从装好 Git 到团队协作、再到疑难问题排查”的路线整理,覆盖了大多数人从入门到进阶会遇到的真实场景,你可以把它当成手边查阅手册来用。
1. 从拿到 Git 到提交第一个版本:安装与配置
1.1 安装:不同系统的差别和坑
在 Windows 上安装 Git,直接去官网下载安装包,或者用 winget 这样的命令行工具安装,都比较省事。我在 Windows 上最常用的安装方式是这样:
bash复制winget install --id Git.Git -e --source winget
装完后会自动提供 Git Bash、Git GUI 和系统 PATH 里的 git 命令。这里有一个很多人踩过的坑:安装过程中会让你选“调整 PATH 环境变量”,一定要选中间那一项 “Git from the command line and also from 3rd-party software”,否则后面在 VSCode 终端或者其他终端里可能找不到 git 命令,报错提示“git 无法识别为 cmdlet、函数、脚本文件或可运行程序的名称”。如果你已经遇到这个报错,路径里没有 Git 的 bin 目录,可以手动把 C:\Program Files\Git\bin 加到系统环境变量的 PATH 里,然后新开一个终端窗口。
macOS 上最简单的是通过 Homebrew 安装:
bash复制brew install git
Linux 的发行版一般自带 Git,如果没有,Ubuntu/Debian 系用 apt install git,CentOS/RHEL 系用 yum install git 或者 dnf install git。装完先验证一下版本:
bash复制git --version
顺手把 shell 里的 Git 补全功能打开,用起来会舒服很多,具体配置跟 shell 类型有关,这里不展开。
1.2 全局配置:提交信息、默认分支、换行符
Git 装好后第一件事不是建仓库,而是配置身份信息。提交记录里会带上 user.name 和 user.email,没配置的话 Git 会提示你补上,而且很多团队还会通过提交邮箱关联到代码平台账号,所以这一步别跳过:
bash复制git config --global user.name "你的名字"
git config --global user.email "你的邮箱"
查看当前配置用 git config --list。如果只是想看某个单独的配置,用 git config user.name。
另外有几个全局配置我建议顺手设置好。第一个是默认分支名,现在 GitHub 和 GitLab 上的新仓库都默认用 main,但老版本 Git 默认还是 master,直接改掉:
bash复制git config --global init.defaultBranch main
第二个是换行符。Windows 上 core.autocrlf 建议设为 true,macOS/Linux 上建议设为 input:
bash复制git config --global core.autocrlf true # Windows
git config --global core.autocrlf input # macOS / Linux
如果不做这个设置,跨平台协作时经常会出现“整个文件都被标记为修改”的诡异现象,表面上是 Git 的问题,实际上是换行符(CRLF 与 LF)在捣乱。第三个是可以把默认编辑器改成 VSCode 或者 vim,看个人习惯,但改了之后执行 commit 需要编辑提交信息时不会卡在陌生的编辑器里:
bash复制git config --global core.editor "code --wait"
1.3 SSH 免密配置:不用每次输入账号密码
用 HTTPS 方式连接远程仓库时,每次 push 都可能要求输入用户名和密码,虽然现在很多平台支持个人访问令牌(Personal Access Token),但比起 SSH key 还是麻烦。我习惯直接用 SSH 方式,生成密钥后一劳永逸:
bash复制ssh-keygen -t ed25519 -C "你的邮箱"
一路回车即可,生成的公钥在 ~/.ssh/id_ed25519.pub,私钥在 ~/.ssh/id_ed25519。把公钥内容复制到代码平台的 SSH Keys 设置里,然后测试一下:
bash复制ssh -T git@github.com
看到提示认证成功的消息就说明配置好了。这里有个经验:如果是公司内网多台机器共用一套 key,私钥文件权限不能太开放,尤其 Linux 下如果报 “Permissions too open” 错误,执行 chmod 600 ~/.ssh/id_ed25519 就能解决。另外,如果你管理多个平台(公司 GitLab 和个人 GitHub),可以编辑 ~/.ssh/config 为不同 Host 指定不同密钥文件。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 每天都会用的核心命令:状态、暂存与提交
2.1 先理解 Git 的三区模型,命令才不会乱
很多人 Git 命令记不住,不是记忆力问题,而是没有建立“工作区、暂存区、版本库”这三区模型。简单理解:
- 工作区:你本地能看到的文件和目录,改动都在这里发生。
- 暂存区:用
git add把改动放进去的地方,相当于“待提交清单”。 - 版本库:用
git commit把暂存区内容固化成一次提交记录。
平时输入最多的 git status 就是用来查看这三个区之间的差异。每次改动文件后,先 git status 看情况,再决定下一步,这个习惯能避免很多误操作。git status 的简洁模式我推荐用 git status -sb,一行显示分支状态和跟踪情况,比默认输出清爽得多。
2.2 暂存和提交:add、commit 的正确打开方式
单文件的提交很直接:
bash复制git add index.html
git commit -m "更新首页标题"
如果一次改了多个文件,但又不想全部提交,可以用 git add 指定文件名;如果确认所有改动都要提交,可以用 git add . 或 git add -A。这里有个小区别:git add . 只添加当前目录下的改动,git add -A 会添加整个仓库的改动,包括文件删除。建议多使用 -A 或直接写 --all,语义更明确。
git add 之后发现某个文件不该提交,用 git restore --staged <file> 把文件从暂存区撤回来,但保留工作区改动:
bash复制git restore --staged package.json
如果文件已经提交了,想修改提交信息,可以用 git commit --amend,它会打开编辑器让你修改最近一次提交的信息。注意这条命令会改写提交历史,如果这次提交已经 push 到远程且别人拉下来了,就不要乱用,否则会带来一堆协作问题。
2.3 查看历史与差异:log、diff、show
提交记录用 git log 查看,默认输出很详细但有点冗长。我常用的是美化版:
bash复制git log --oneline --graph --decorate --all
--oneline 让每条提交只显示一行,--graph 显示分支图形,--decorate 显示分支和标签信息,--all 显示所有分支。基于这行命令可以扩展出很多查询方式,比如只看某个人的提交:
bash复制git log --oneline --author="张三"
查看某个文件的修改历史:
bash复制git log --oneline -- path/to/file
git diff 用来查看工作区与暂存区、暂存区与上次提交之间的差异。不带参数时 git diff 查看的是工作区改动,还没 add;加了 --staged 后查看已经 add 但还没 commit 的内容:
bash复制git diff
git diff --staged
如果想看某次提交到底改了什么东西,用 git show <commit-id>。提交 ID 不需要写全,一般写前 7 位就足够,比如 git show 3f2ab1c。
3. 分支管理与合并:多人协作的“主干道”
3.1 分支的创建、切换与删除
分支是 Git 最核心的功能,但理解起来并不难:它就像一个平行宇宙,你在自己的分支上折腾不影响主线,等稳定了再合并回去。
创建并切换到新分支:
bash复制git checkout -b feature/login
等价于:
bash复制git branch feature/login
git checkout feature/login
Git 2.23 之后推荐用 switch 系列命令,语义更清晰:
bash复制git switch -c feature/login
-c 表示 create。切换分支用:
bash复制git switch main
查看本地分支:
bash复制git branch -v
查看所有分支(包含远程分支):
bash复制git branch -a
删除本地分支:
bash复制git branch -d feature/login
如果分支上有未合并的提交,-d 会拒绝删除,这时候如果确认不要了,用大写 -D 强制删除。这个保护机制很有用,能防止手滑删掉还没合并的工作。
3.2 合并与变基:merge 和 rebase 怎么选
把 feature 分支合并回 main,最直接的方式:
bash复制git checkout main
git merge feature/login
Git 会自动创建一次 merge commit。这种方式的好处是保留完整的分支历史,坏处是历史图上会出现很多“分叉点”,看多了像一团毛线。另一种方式是 rebase,把 feature 分支上的提交“重新放到” main 分支的最新提交之上:
bash复制git checkout feature/login
git rebase main
这样做出来的历史是一条直线,阅读性更好。但 rebase 会改写提交 ID,所以只建议在还没 push 到远程的分支上使用。我的经验是:对自己本地还没共享的分支,用 rebase 整理历史;对已经共享的分支,老老实实用 merge。毕竟协作里最重要的事情是让别人的工作不受影响。
3.3 stash:临时保存现场,切分支不丢工作
正在 feature 分支写着代码,突然要切到 main 修一个紧急 bug,但改动做到一半不想提交,这时候 git stash 就是救命的:
bash复制git stash
工作区的改动会被保存并恢复到干净状态。切到 main 修完 bug 后,切回来再恢复现场:
bash复制git stash pop
多个 stash 需要管理时,用 git stash list 查看,git stash apply stash@{1} 恢复指定条目。注意 apply 不会删除 stash 条目,而 pop 会。如果 stash 后分支代码已经发生很大变化,恢复时可能产生冲突,这时候只能手工处理。
4. 远程仓库协作:克隆、推送与拉取
4.1 remote 与 clone:把代码挪到云端
参与一个已有项目最常见的操作是克隆:
bash复制git clone git@github.com:user/repo.git
也可以指定目录名:
bash复制git clone git@github.com:user/repo.git my-project
如果仓库特别大,或者你只需要最近代码而不需要完整历史,可以用浅克隆:
bash复制git clone --depth 1 git@github.com:user/repo.git
这样只拉取最近一次提交,速度会快很多。如果在克隆 GitHub 仓库时经常遇到网络问题,一个更稳妥的思路是使用国内代码托管平台的镜像仓库,或者在公司的 GitLab/Gitea 上先做一次中转,然后把代码同步过去。平时自己练习时也可以把 GitHub 仓库 git remote add 指向多个地址,同时推送到不同平台作为备份。
查看当前仓库关联的远程地址:
bash复制git remote -v
添加远程仓库:
bash复制git remote add origin git@github.com:user/repo.git
修改远程地址:
bash复制git remote set-url origin git@github.com:user/repo.git
4.2 push、pull 与冲突处理
把本地提交推送到远程:
bash复制git push origin main
第一次推送本地新建分支时,可以加上 -u 参数,会建立本地分支与远程分支的跟踪关系,以后直接 git push 就能推到对应远程分支:
bash复制git push -u origin feature/login
拉取远程更新,我推荐的写法是:
bash复制git pull --rebase
为什么加 --rebase?因为默认的 git pull 等价于 fetch + merge,会产生多余的 merge commit;加 --rebase 后等价于 fetch + rebase,本地提交会先暂时挪开,远程更新完成后重新放回顶部,提交历史更干净。如果团队大家都比较习惯 merge 流程,用默认的 pull 也行,但一定要先统一约定,否则仓库历史会乱。
多人协作时最常见的冲突场景是:你和同事同时改了同一个文件的同一段代码。pull 之后 Git 会提示冲突,冲突文件里会出现类似这样的标记:
text复制<<<<<<< HEAD
你的代码
=======
别人的代码
>>>>>>> feature/login
手动选择保留哪部分,删除标记行,然后 git add 该文件,再 git commit 完成合并。记住一个原则:冲突不是错误,是 Git 在保护代码,它不知道该替你保留哪份,必须由人来决定。遇到解决不了的冲突,先确认原始文件可以随时丢,可以执行 git merge --abort 回到 merge 之前的状态。
4.3 我参与的开源协作流程:fork 与 Pull Request
很多人在公司内部是直接在一个仓库里开分支协作,但参与开源项目时,通常没有直接推送权限,流程是:
- fork 上游仓库到自己账号下。
- clone 自己 fork 出来的仓库。
- 添加上游仓库为另一个 remote,一般叫 upstream。
- 新建分支开发,push 到自己的 fork。
- 在代码平台发起 Pull Request(或 Merge Request)。
整个过程中 git remote 非常重要。我一般会这样配置:
bash复制git remote add upstream git@github.com:original/repo.git
git fetch upstream
git checkout -b feature/xxx upstream/main
开发完准备提交 PR 前,先用 git fetch upstream 拿到最新上游代码,然后 git rebase upstream/main 把本地提交变基到最新版本上。这样做能让 PR 审查者看到干净的改动,而不是一堆“Merge branch”噪音。
5. 进阶操作:回滚、找回与效率工具
5.1 reset、revert、reflog:后悔药怎么吃
误提交、误删除、想回退到某个版本,这些都是新手最害怕的场景。Git 提供了不止一种“后悔药”,用对了就很从容。
撤销工作区未暂存的文件改动:
bash复制git restore <file>
撤销暂存区的文件(等同于老命令 git reset HEAD <file>):
bash复制git restore --staged <file>
回退最近一次提交,但保留改动:
bash复制git reset --soft HEAD~1
--soft 只移动 HEAD 指针,所有改动还在暂存区,适合刚 commit 完发现漏了文件,想重新提交。如果想要连暂存区也清空,用 --mixed,这是默认模式。如果想把提交和工作区改动全部丢弃,用 --hard,这个非常危险,用了之后这些改动就找不回来了:
bash复制git reset --hard HEAD~1
但是即便用了 --hard,也不是完全没有救。Git 有 reflog 机制,它会记录 HEAD 的移动历史,相当于“操作日志”。找回误删提交的操作是这样:
bash复制git reflog
git reset --hard <commit-id>
git reflog 会列出最近几十条操作以及对应的 commit-id,找到你想回到的那一次,直接硬重置过去即可。我自己就曾在 --hard 后靠 reflog 找回过一个重要文件,所以强烈建议所有人都记着这个命令。
5.2 撤销已推送到远程的提交:revert 比 reset 安全
如果误提交已经 push 到远程,而且别人可能已经拉取了,git reset 就不合适了,因为会改写公共历史。这时候用 git revert:
bash复制git revert <commit-id>
revert 会生成一次“反向提交”来抵消目标提交的改动,不修改历史,只是新增一条提交记录。团队协作中最安全的原则是:只要是已经共享的提交,一律用 revert 而不是 reset。
5.3 tag、cherry-pick、bisect:这些场景太常用了
打标签用于发布版本,一般配合语义化版本号:
bash复制git tag v1.0.0
git push origin v1.0.0
查看标签:git tag -l。如果你发现线上紧急 bug 修复是在 develop 分支上提交的,但 release 分支也需要这个修复,直接切到 release 分支执行 cherry-pick:
bash复制git cherry-pick <commit-id>
它可以把某个提交原样复制到当前分支。另外一个很有用的命令是 git bisect,用于二分定位“从哪个提交开始引入的 bug”。流程是:
bash复制git bisect start
git bisect bad # 当前版本是坏的
git bisect good v1.0.0 # 这个版本是好的
Git 会每次给你一个中间提交,你测试后输入 git bisect good 或 git bisect bad,它会自动缩小范围,直到定位到首个出问题的提交。遇到“上一版还好好的,这版就坏了”的问题时,这个命令效率极高。
5.4 给 Git 配置别名与提交规范
高频命令可以用别名缩短,比如:
bash复制git config --global alias.st status
git config --global alias.co checkout
git config --global alias.br branch
git config --global alias.cm commit
git config --global alias.lg "log --oneline --graph --all --decorate"
配置之后 git st 就是 git status,git lg 就是一条图形式的完整历史。这不算偷懒,是提升效率的正当手段。即使团队里别人用完整命令,你自己用别名一点也不影响仓库数据。
提交规范方面,我建议团队先约定一套简单的 commit message 格式,常见的 Conventional Commits 就够用:
feat: 新功能fix: 修复bugdocs: 文档变更style: 代码格式调整refactor: 重构test: 测试相关chore: 构建/工具/依赖相关
加上 -m 后面写清楚“做了什么”,别写“修改代码”、“更新”这种没有信息量的内容。如果团队更讲究,可以在 pre-commit 钩子里接入 commitlint 做格式校验。
6. 常见问题与避坑实录
6.1 命令找不到、权限失败、换行符问题
我在群里见得最多的一个是:“git 无法将‘git’项识别为 cmdlet、函数、脚本文件或可运行程序的名称”。原因几乎都是 Windows 环境没把 Git 加到 PATH。解决办法有两个:重装 Git,在安装向导里确保勾选将 Git 加入 PATH;或者手动把 C:\Program Files\Git\cmd 加进系统环境变量。加完后一定要重新打开终端窗口,不要只刷新当前窗口。
push 时提示权限失败(Permission denied),95% 是 SSH key 没配对。先确认本地 key 存在,再确认公钥已经添加到代码平台。用 ssh -T git@github.com 测试能直接看到问题所在。
换行符问题表现为“克隆下来后 git status 全红,但文件内容明明没改”。前面说过,用 core.autocrlf 配置可以规避。已经中招的仓库可以执行:
bash复制git config core.autocrlf true
git rm --cached -r .
git reset --hard
重新规范化文件后,提交一次,后续就正常了。操作前确认工作区没有未保存的改动。
6.2 中文乱码、目录泄露与超大文件
Windows 上 Git 显示中文文件名会变成转义字符,比如输出 \346\265\213\350\257\225.txt,原因是 Git 默认对非 ASCII 文件名做了转义。运行:
bash复制git config --global core.quotepath false
中文就正常了。另外 git log 中的中文乱码有时是终端编码问题,把终端编码切到 UTF-8 基本能解决。
还有一个安全性问题:如果你的网站或者项目目录被部署到线上,但又意外把 .git 文件夹一起暴露到公网,就可能导致源码泄露。判断方法很简单,在浏览器里访问 https://你的域名/.git/,如果返回目录列表或没有 403/404,说明配置有风险。正面的解决方法是立刻在 Web 服务器层面禁止访问 .git 路径,并及时检查是否已有源码泄露;如果使用的是代码托管平台,不要在这种仓库中提交任何敏感信息,比如密码、密钥、云厂商 AccessKey。.gitignore 应该从一开始就添加环境变量文件、密钥文件、日志文件。
超大文件也会经常给团队带来麻烦。超过 100MB 的文件直接推送到普通 Git 仓库,后续每次 clone 都会很痛苦。遇到这种情况有两条路:如果文件本身不该在仓库里,加进 .gitignore 并移除;如果确实需要版本管理大文件,使用 Git LFS(Large File Storage):
bash复制git lfs install
git lfs track "*.psd"
git add .gitattributes
这样后续匹配 *.psd 的文件会用 LFS 存储指针而不是直接保存整个文件。
6.3 我再强调一遍的协作规范
最后分享一个我踩过多次坑之后沉淀下来的团队 Git 协作建议,适合中小团队直接抄作业:
- 主分支(main/master)保持随时可发布状态,不要直接往上面提交代码。
- 新功能从 main 拉分支,分支命名用
feature/xxx、fix/xxx这种格式。 - 个人开发分支尽量自己维护,commit 信息写清楚,但不要随意修改已经推到远程的分支历史。
- 合并代码前先
git fetch最新代码,能 rebase 就 rebase,不能 rebase 就 merge。重点是全团队统一。 - 每次提交前先
git diff确认改动,避免把调试代码、临时文件一起提交进去。 - 提交信息写清楚“为什么改”,而不是只写“改了”。
这些习惯不会让你的 Git 技术一瞬间变得多强,但能让合作的项目少很多互相踩踏的情况。真正熟练之后你会发现,Git 的命令学来学去,最后每天都在用的还是那几十个,重要的是理解它们各自在什么场景下使用,以及为什么这样用更安全。希望这篇指南能帮你少走弯路,把这些命令真正变成肌肉记忆。
