☰
Git 常用命令实战:从安装配置到分支管理、撤销回滚与远程协作
2026/9/26 16:55:00 网站建设 项目流程

1. 安装与环境准备

1.1 Git 安装方式小结

Git 是当下开发者绕不开的工具,就算平时用 IDE 的图形按钮提交代码,底层的还是这一套命令。与其等出了问题对着错误提示干瞪眼,不如先把常用指令摸透。这篇文章没有废话,也不按什么“入门到精通”的套路来,纯粹是我这么多年干活时反复在敲的命令,从安装、配置、日常提交到分支合并、后悔药、远程推送,一条条拆开讲明白。

先收下环境这一关。不同系统装 Git 的方式不太一样,说几个我实测过最省心的:

  • Linux(Debian/Ubuntu 系):sudo apt install git
  • Linux(CentOS/RHEL 系):sudo yum install git
  • macOS:装了 Homebrew 就直接brew install git,没装的话去官网下 pkg 安装包也行
  • Windows:推荐用 Git for Windows,它自带一个 Git Bash 终端,模拟 Linux 环境,很多命令行为跟 macOS/Linux 保持一致,踩坑少

装完先跑一句验证:

git --version

能输出版本号就说明装好了。Windows 用户如果是在 CMD 里敲的,记得把 Git 的 bin 目录加到 PATH,正常安装包会帮你勾选,不用手动折腾。

1.2 首次使用前的必做配置

这一步很多人跳过去了,结果就是第一次git commit报错,或者提交记录里出现一串乱码一样的名字。Git 每次提交都会记录“谁做的”,靠的不是登录账号,而是本地的全局配置。所以开工前先配置身份:

git config --global user.name "你的名字" git config --global user.email "你的邮箱"

注意这里填的邮箱最好是你代码托管平台上常用的邮箱,因为平台会把提交邮箱和你账号关联起来。我记得早年有个同事随便填了个邮箱,提交记录挂在了一个陌生账号名下,找都找不回来,非常尴尬。

还有几个我建议顺手配掉的:

git config --global init.defaultBranch main git config --global core.autocrlf input git config --global core.quotepath false

init.defaultBranch是把新仓库的默认分支从master改成main,跟 GitHub/Gitee 新建仓库的默认保持一致,少一点心智负担。core.autocrlf是换行符策略:Windows 上建议设成true,Mac/Linux 设成input,避免出现整个文件所有行都被标记为修改的“换行符灾难”。core.quotepath false这个对中文用户特别友好,不然git status显示中文文件名时全是一堆反斜杠转义,看着头大。

查看当前配置用:

git config --list

想改某一条就重新执行对应的 config 命令。配置作用域分三层:system、global、local,默认不写作用域时操作的是 local 层,它会覆盖 global 的相同配置,很适合不同项目用不同身份的情况。实际工作中我在公司电脑上就靠这个区分个人项目和公司项目。

2. 日常开发最常用的基础指令

2.1 初始化仓库与克隆远程项目

拿到一个新项目,一般就两种情况:从零开始,或者把远程已有的仓库拉下来。

从零开始,在项目目录里执行:

git init

执行完目录下会多一个.git隐藏文件夹,这就是仓库的核心,所有版本历史都存这里面。这里提醒一句:千万不要手贱去删.git目录,删了等于历史全没了。

如果远程已经有人建好了仓库,用clone拉一份到本地:

git clone <仓库地址>

仓库地址一般有两种形式:

  • HTTPS:https://github.com/user/repo.git
  • SSH:git@github.com:user/repo.git

HTTPS 每次 push 都要输账号密码,不过可以用凭据管理器记住。SSH 需要配置密钥,后面第六章会专门说。我个人的习惯是走 SSH,一劳永逸。

clone 有个小参数我经常用:

git clone -b dev <仓库地址>

这个可以指定克隆某个分支,而不是默认的 main/master。有些仓库默认分支是坏的或者不是你想用的,这个能省掉一次切分支的麻烦。

2.2 状态检查、暂存与提交

日常开发三连:status看状态,add暂存,commit提交。

git status

这条一定是最高频的命令,没有之一。它会告诉你当前工作区干不干净,哪些文件改过、哪些是新文件、哪些已进入暂存区。我个人的习惯是:任何操作之前先跑一遍git status,就像你开车前先看一眼仪表盘,尤其是准备执行 reset 或 checkout 这种危险命令时,这一眼能救你命。

add是把改动放入暂存区,也就是告诉 Git“我要把这些文件纳入下一次提交”:

git add <文件名> # 暂存指定文件 git add . # 暂存当前目录所有改动 git add src/ utils/ # 暂存多个目录

有些新手喜欢无脑git add .,我的建议是提交前先用git status和git diff确认一下哪些文件动了。尤其是项目里可能有本地配置文件、临时文件,无脑 add 会把不该提交的东西带进去。如果确实想全加,也要先看一遍列表,确认没有.env之类的敏感文件。

然后提交:

git commit -m "提交说明"

提交说明就是 commit message,这里多说两句。写好提交信息比写好代码还重要,因为半年后你回头看历史,靠的就是这些信息。一个比较通用的格式是:

<type>: <subject>

比如:

fix: 修复登录接口空指针异常 feat: 新增用户导出功能 docs: 更新 README

type可以是feat(新功能)、fix(修 bug)、docs(文档)、refactor(重构)、test(测试)等。这是我见过最省事的规范,既不过度工程化,又能让历史记录一眼扫明白。

2.3 提交信息的补救:git commit --amend

有没有遇到这种情况:提交完发现 message 打错字了,或者漏了一个文件没加进去?

git commit --amend

它会打开编辑器让你修改上一次的提交信息。如果只是想顺带补文件,先 add 再 amend:

git add 漏掉的文件.txt git commit --amend

执行完之后,上一次提交就被“覆盖”成了一个新的提交,不会多出一条历史记录。

这里有一条非常重要的红线:amend只适合处理还没有推送到远程的提交。如果这个提交已经 push 出去了,别人可能基于它做了分支,你这边一 amend,两边的提交哈希就对不上了,后面会引发一连串合并冲突。所以我的原则是:本地 commit 后发现小问题,随便 amend;已经 push 的,老老实实用git revert(后面会讲)。

3. 分支管理与远程协作

3.1 分支的创建、切换与合并

分支是 Git 相比 SVN 最大的优势。你可以理解成平行宇宙:在dev分支上改代码不会影响main,等开发完了再合并回来。

查看当前分支:

git branch

创建新分支:

git branch feature-login

切换分支:

git switch feature-login

Git 2.23 之后推荐用switch,语义更清晰。老一点的命令git checkout feature-login也能用,但checkout身兼数职(既能切分支又能丢弃文件改动),新手容易混淆。

更常用的是“创建并切换”一步到位:

git switch -c feature-login

等于git branch feature-login+git switch feature-login。

合并分支回到主分支:

git switch main git merge feature-login

如果合并时没有冲突,Git 会直接走 fast-forward,把 main 的指针挪到 feature-login 上。如果有冲突,就会进入冲突解决流程,这个在 3.3 细说。

3.2 远程仓库:remote、push、pull、fetch

本地分支搞完了,得把代码推到远程,不然合作的人看不到。

关联一个远程仓库:

git remote add origin https://github.com/user/repo.git

origin是远程仓库的默认别名,你叫它什么都行,但行业约定俗成就是origin。

查看远程仓库列表:

git remote -v

第一次推送时需要指定上游分支:

git push -u origin main

-u是--set-upstream的简写,意思是“把本地的 main 分支和远程的 main 分支关联起来”。加过一次之后,后续直接敲git push就行了。

拉取远程更新:

git pull

这里必须讲一个很多人栽过的坑:git pull默认执行的是fetch+merge。如果你的本地提交和远程提交出现了分叉,Git 会自动创建一个 merge commit,历史会变得很乱。更推荐的做法是:

git pull --rebase

这会把你在本地还没推送的提交“摘下来”,暂存到一边,先把远程的提交拉下来,再把你自己的提交按顺序“放”上去,历史保持线性,干净很多。我自己把pull.rebase设为默认配置了:

git config --global pull.rebase true

设完之后git pull就等价于git pull --rebase,省心。

3.3 合并冲突的解决思路

冲突这玩意儿,第一次遇到的人基本都会慌。别慌,它没那么可怕。

什么时候会有冲突?两个人改了同一个文件的同一个区域,Git 不知道怎么自动合并,就会把这个文件标记为冲突状态。

冲突状态的文件,打开之后长这样:

<<<<<<< HEAD 这里是当前分支的内容 ======= 这里是合并进来的分支的内容 >>>>>>> feature-login

<<<<<<<和=======之间的是当前分支版本,=======和>>>>>>>之间的是被合并分支版本。你要做的就是把该留的留下,该删的删掉,包括这三种标记符号,一个都不能留。

处理完保存文件,然后:

git add 冲突解决后的文件 git commit

Git 会自动生成一条 merge commit。如果你不确定怎么解决,我建议到 IDE 里看,VS Code 和 IntelliJ 系列都有可视化冲突解决界面,谁会保留、谁会丢弃,点几下就好。

有一条经验:冲突解决时先看清哪个版本是最近的。宁可少留不要乱留,把模棱两可的逻辑拿出来跟当事人对一下,千万别“凭感觉留一份”。

4. 撤销与回滚

4.1 工作区、暂存区、本地仓库三个区域的底层认知

要理解撤销操作,先得搞清楚 Git 的三个区域。我用个购物类比:

  • 工作区(Working Directory):你的项目目录,相当于手里的草稿纸,改代码都是在这里发生的
  • 暂存区(Index/Staging Area):相当于购物车,你把看中的商品(改动的文件)放进去,等待结算
  • 本地仓库(HEAD):相当于已经结账打包回家的货架,commit就是结算的动作

每个文件在这三个区域之间移动的状态,就是git status里看到的那些提示:

  • modified:工作区有改动,但还没 add
  • staged:已经 add,待 commit
  • committed:已经 commit,和 HEAD 一致

理解了这三个区域,撤销操作就只是“把文件恢复到某个区域的状态”的问题了。

4.2 各种撤销场景对应指令表

先给一个速查表,再做详细解释:

场景指令风险程度
丢弃工作区某个文件的改动git restore <file>或git checkout -- <file>危险,改动不可找回
把暂存区的文件退回到工作区git restore --staged <file>低风险,内容不会丢
撤销上一次提交并保留改动git reset --soft HEAD~1低风险
撤销上一次提交并取消暂存git reset HEAD~1(默认 mixed)低风险
撤销上一次提交并删除改动git reset --hard HEAD~1极度危险
撤销某一次已推送的提交git revert <commit>安全,会生成新提交

不推荐用git checkout恢复文件,因为它和“切换分支”是同一个命令,容易误解。新版 Git 提供git restore,语义明确,我只推荐这个。

4.3 reset、revert、clean 的正确打开方式

先说git reset。它有三种模式,区别在于“回撤之后,改动还在不在”:

  • --soft:只移动 HEAD 指针,暂存区和工作区都不动。相当于提交 history 没了,但代码改动都在,等着你重新提交
  • --mixed(默认):移动 HEAD 指针,并重置暂存区,但工作区不动。改动保留但在工作区,需要重新 add
  • --hard:移动 HEAD 指针,同时重置暂存区和工作区。改动彻底消失,找不回来

一个我常用的场景:刚 commit 完发现里面有个多余文件,想拆成两个提交。用git reset --soft HEAD~1,把提交撤掉,但改动全部保留在暂存区,然后重新 add 拆分。

git reset --hard要慎用,它不会保留任何备份。但如果只是恢复到之前某次提交,而且你的分支已经推到远程了,可以考虑git reset --hard origin/main来“强制同步”到远程状态。

再说git revert。它不删历史,而是生成一个“反向提交”把之前的改动抵消掉。这适合已经 push 出去的提交。因为历史里会留下完整的操作记录,团队成员看到的是“有人用一次提交撤销了另一次提交”,非常透明。

我自己作为团队里经常 review 代码的人,特别反感有人对已推送的提交用reset --hard,因为一旦别人基于之前的提交继续开发,后面强行 push 会把别人辛辛苦苦推上去的提交冲掉。这个场景必须用revert。

最后提一下git clean。它清理的是工作区里未跟踪的文件,比如编译生成的临时文件。我偶尔会用:

git clean -fd

-f是强制删除,-d是连同目录一起删。这个命令不会询问太多,执行前一定先看git status,确认哪些是未跟踪文件,否则误删了就凭空消失。

5. 查看历史与代码排查

5.1 git log 的常用参数,一眼看懂提交记录

Git 历史记录我用得最多的是几个参数组合:

git log --oneline --graph --decorate --all
  • --oneline:每条提交只用一行显示,包含短哈希和提交信息
  • --graph:用线条画出分支合并走向,网络图效果,特别适合理解分支结构
  • --decorate:显示分支/标签指向了哪个提交
  • --all:显示所有分支,而不只是当前分支

还可以带作者过滤和时间过滤:

git log --author="张三" --since="2024-01-01" --until="2024-06-01"

这个我在做月度复盘或者代码审计时经常用,能快速统计某个人在某段时间的提交量。

想搜索某段代码是哪个提交引入的:

git log -S "某段字符串"

-S也叫“pickaxe”,它会找出新增或删除这个字符串的所有提交。定位 bug 是谁引入的,这个命令比人肉翻代码高效一百倍。

查看某次提交的改动内容:

git show <commit哈希>

5.2 用 blame 定位“罪魁祸首”

git blame是我排查问题时的神器。它可以显示文件每一行最后被谁修改、在哪次提交里改的:

git blame 文件名

只看某几行:

git blame -L 100,120 文件名

看到某一行是问题代码,但不知道为什么这么写时,拿提交哈希去问当事人是最直接的。当然,blame不是为了“追责”,而是为了理解代码演化过程。很多时候你看到一段奇怪的代码,骂骂咧咧点进去一查,发现是半年前你自己写的,那体验可酸爽了。正因为这样,我养成了写提交信息时把“为什么这样改”也写进去的习惯,能帮未来的自己和同事省很多时间。

5.3 用 diff 看清楚改动细节

代码审查和提交之前,git diff是必备的一步。

  • 查看工作区相对暂存区改了什么:git diff
  • 查看暂存区相对上次提交改了什么:git diff --cached(或--staged)
  • 查看两个分支之间的差异:git diff 分支A 分支B
  • 查看某次提交改了什么:git show <哈希>

特别是git diff --cached,提交前扫一眼,防止把调试代码、敏感信息、无意义的空格变化一起提交上去。我有个坏毛病就是喜欢改完代码顺手多敲几个空格,这种噪音会让diff变得很难看,如果被 reviewer 看到,虽然没问题但阅读体验很差。所以提交前我会挨个文件看 diff,把不该有的格式调整拆到单独的 commit 里。

6. SSH 密钥配置与远程推送实战

6.1 生成密钥并添加到代码托管平台

前面说过 SSH 方式推送可以免输密码,这里详细走一遍。

首先生成密钥对。我推荐用 ed25519 算法,生成快、安全性强:

ssh-keygen -t ed25519 -C "你的邮箱@example.com"

一路回车把文件保存在~/.ssh/下。如果你之前已经生成过 RSA 密钥,不想覆盖它,可以在提示输入文件名时改个名,比如id_ed25519_gitee。

生成的公钥文件是~/.ssh/id_ed25519.pub,查看内容:

cat ~/.ssh/id_ed25519.pub

复制输出的一整段内容,去代码托管平台(GitHub 或 Gitee)的设置页面,找到“SSH Keys”,粘贴保存。

验证是否配置成功:

ssh -T git@gitee.com

第一次连接会提示你确认 host key,输yes。成功后平台会返回一段欢迎语,看到类似 “Hi xxx! You've successfully authenticated” 就成了。

6.2 手动关联远程仓库并推送

在托管平台上新建一个空仓库,然后把本地代码推上去。步骤:

git init git add . git commit -m "初始提交" git remote add origin git@gitee.com:你的用户名/仓库名.git git push -u origin main

如果仓库里已经有 README 等文件,直接 push 会失败,提示远程包含本地不存在的提交。这时要么先git pull --rebase origin main,要么干脆建空仓库不勾选“初始化 README”。

第一次 push 一个大项目时会比较慢,属于正常现象。后续再推送就只是一些增量数据了。

6.3 多平台多密钥管理的实际经验

如果你同时用 GitHub 和 Gitee,甚至还有公司内部的 GitLab,同一对密钥是不能跨平台用的(不同平台的账号体系不同),也不建议所有平台都用同一个密钥。正确做法是给每个平台生成不同的密钥,然后在~/.ssh/config里做匹配:

Host github.com HostName github.com User git IdentityFile ~/.ssh/id_ed25519_github Host gitee.com HostName gitee.com User git IdentityFile ~/.ssh/id_ed25519_gitee

这样 SSH 连接时会按 Host 自动选择对应的密钥文件,不用每次手动指定。我最早没有配这个,为了图省事把同一个密钥加到两个平台,后面发现有人在 GitHub 上用我的身份推送代码,吓得我赶紧把密钥撤掉重新配。密钥泄漏的排查很麻烦,所以从一开始就分别管理是正确的姿势。

7. 高频问题速查与避坑心得

问题原因解决方式
push 被拒绝,提示 non-fast-forward远程有新提交本地没有git pull --rebase后重新 push
每次 push 都要输密码用了 HTTPS 且未缓存凭据配置 SSH 密钥或用git config --global credential.helper store(注意安全性)
提交信息写错了手滑 / 忘改git commit --amend修改最近一次
不小心提交了敏感文件误将.env等加入暂存区立即从历史移除,参考git filter-branch或第三方工具,并立刻去平台撤销/更换密钥
误删了本地分支git branch -D删错了用git reflog找到分支指向的哈希,git branch <名字> <哈希>重建
文件中文名显示乱码核心配置缺少core.quotepath false执行git config --global core.quotepath false
合并冲突出现一堆重复代码换行符混乱统一core.autocrlf配置

git reflog这条值得单独说一下。它记录的是 HEAD 指针每次移动的历史,相当于 Git 的操作“黑匣子”。哪怕你对一个分支执行了git reset --hard,只要 reflog 里还有记录,就能找回之前的状态。我吃过一次亏之后,现在每次执行破坏性命令前都会快速看一下 reflog 和 status。操作流程是:

git reflog git branch 救援分支 <目标哈希>

reflog的日志不会永久保留,默认过期时间是 90 天,但关键时刻就是救命的稻草。

还有一条经验:在团队协作里,不要对已经推送的分支做amend或reset --hard。如果你真的做了,那被强行覆盖的同事基本要骂人了。已经推送的代码要修改历史,走revert,留一条完整的记录,比“悄悄改写历史”要干净得多。

最后讲一个我踩过好多次的坑:提交前不看 status 和 diff。尤其是项目比较大时,随手git add .,结果把自己配了一下午的本地调试配置也提交上去了。后来我给自己定了一条规则:

执行任何会影响代码的命令之前,必须先看一遍git status和git diff,确认改动范围完全在自己预期内。

这是 Git 使用中最简单同时也是最有效的一条自律。命令行确实高效,但效率不应该建立在侥幸之上。命令那么多,真正能记住的其实不多,我这些年也只用其中不到十个,但把每个用熟练、用对场景,远远好过背熟一百个却总在重要时刻把分支搞乱。

如果你刚接触 Git,建议从status、add、commit三件套练起,然后把log、branch、merge玩顺,最后再碰reset、revert这类危险操作。一切顺利之后,记得常备reflog这个守护神,它会在你最慌乱的时候给你兜底。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询