☰
Git实战手册:从安装配置到分支合并与冲突处理
2026/9/29 15:55:52 网站建设 项目流程

如果你问一个干了三五年的开发者,Git在他的日常工作中占了多重的分量,他大概率会想都不想地回答:每天几十次。Git不是那种装完设置完就扔在一边的小工具,它贯穿代码编写、版本回退、多人协作、发布上线的每一个环节。但我见过太多人把Git用成了“网盘”,只会add、commit、push三连,一旦提交写错了、分支合乱了、代码冲突冒出来,就只能靠复制整个项目目录来救火。这里不打算把Git的全部命令平铺一遍,而是聚焦真正高频、真正影响效率的关键点:安装配置、日常命令、提交修改、分支合并,以及那些我在实际项目里反复踩过的坑。无论你是刚开始学Git的新手,还是用了一阵子但总在同一个地方栽跟头的人,都可以照着这里的方法试一试。

1. 为什么Git值得花一个下午认真吃透

很多人对Git的第一认知是“代码备份工具”,觉得Git就是把自己写的文件传到服务器上存起来。这个理解其实低估了Git。Git的本质是一台带完整操作记录的“时间机器”,也是一个允许几十个人同时修改同一批文件的“协作平台”。

Git的核心模型,说出来其实非常简单:每次commit都是一次项目快照,但Git不是把文件简单打包存起来,而是记录每次提交的哈希值、提交信息、作者信息,以及上一次提交的哈希作为父指针。这一条条父子关系串起来,就形成了一条完整的历史链。至于分支,本质上只是一个可移动的指针,指向某一次提交。理解了这两件事,后面所有命令都不难掌握。

为什么要花时间去理解这些概念?因为日常开发中这些场景每天都在发生:

  • 你辛辛苦苦写了两小时的代码,突然发现思路错了,想把项目恢复到上午某个稳定状态
  • 测试反馈说某个功能上次还好好的,这次发布后坏了,你想精确找出是哪一次提交引入的问题
  • 团队五六个人同时改一个模块,每个人都在各自的feature分支上开发,最后需要把所有工作合并起来
  • 你提交了一个包含密钥的文件,必须想办法让它从历史记录里彻底消失

这四种场景,不用Git都能做,但效率天差地别。不用Git,你可能靠人工备份zip包,靠肉眼比对代码,靠“记得好像上周改过某某文件”来追查问题。用Git,这些都是一条命令或者几次点击的事。所以第一课不是背命令,而是建立“一切皆有记录、一切皆可回退、一切修改都可追溯”的心智模型。

提示:Git最反直觉的一点是,除了push、pull、fetch等少数命令需要网络,其他所有操作都在本地完成。这意味着你完全可以在本地仓库里随意实验,建多少个分支都不怕,改写本地历史也不会影响任何人,只要你没有强制推送到公共分支。

2. 安装与首次配置:把Git从陌生工具变成顺手工具

Git的安装本身不复杂,但很多人踩坑都踩在安装之后的配置上。尤其是换行符、用户名、凭据缓存这些参数,直接决定你后面用起来是顺滑还是暴躁。

2.1 各平台安装路径与验证

Windows上最省事的方式是去Git官网下载官方安装包。安装过程中我会特别留意两个地方:一是默认分支名,新版安装器会问你想用main还是master,推荐选main,GitHub和GitLab新建仓库的默认分支现在也都是main;二是调整PATH环境的选项,选默认的“Git from the command line and also from third-party software”就好,这样你在VS Code、JetBrains这类IDE里也能直接调用Git。装完建议通过Git Bash来操作,而不是Windows自带的cmd或PowerShell,原因很简单:Git Bash的shell环境跟Linux一致,命令习惯可以迁移到任何平台上。

macOS用户有个更简单的选择:先用Homebrew安装,执行brew install git,就能拿到最新版。如果不想用Homebrew,也可以直接下载官方pkg安装包。Linux阵营则根据发行版选包管理器,Ubuntu/Debian用apt install git,CentOS/RHEL用dnf install git或yum install git。装完第一件事不是急着建仓库,而是跑一遍git --version,确认终端里能识别出git version 2.4x.x这样的输出。如果你在IDE里看到“找不到Git”的报错,通常就是安装时没有把Git加入PATH,重新装一遍、选对选项即可。

2.2 全局配置三件套与几个关键参数

安装完成后,先做全局配置。新手最容易忽略这一步,结果提交出来的代码显示“Unknown”或者别人的名字,到后面想改非常麻烦。

最小配置只需要两条命令:

git config --global user.name "你的名字" git config --global user.email "your_email@example.com"

为什么必须配?因为Git每一次commit都会把作者信息跟提交一起永久记录在历史里。邮箱尤其重要:在GitHub上,邮箱只要在你的账号设置里登记过,提交就能正确地对应到你的头像和贡献图;在GitLab上,公司域名邮箱一般直接关联企业账号。如果邮箱填错,轻则贡献记录丢失,重则代码审查系统无法识别提交人。

除了身份信息,还有几个全局参数我也建议你一上手就配好。这里整理成一张表,方便对照:

参数推荐值作用
user.name真实姓名或常用ID写入每次提交的作者名
user.email常用邮箱写入每次提交的邮箱,关联代码平台账号
core.autocrlfWindows设true,Mac/Linux设input自动处理换行符,避免跨平台diff刷屏
init.defaultBranchmain让git init默认创建main分支,与主流平台一致
core.editorcode --wait 或 vim设置commit message默认编辑器
credential.helpermanager-core / cache缓存HTTPS凭据,省去每次输入账号密码

配置可随时查看:git config --list。如果某条配错了,直接重跑一遍同名的git config --global覆盖即可,也可以在~/.gitconfig文件里手动改,效果一样。

2.3 SSH密钥:少输账号密码的根治方案

接下来要解决连接远程仓库的问题。用HTTPS地址clone仓库,最烦的是每次push都要输账号密码,就算配置了凭据管理器,也偶尔会被各种校验弹窗打断。我更推荐一次性配好SSH密钥。

SSH密钥的原理可以理解成一对钥匙:公钥放在GitHub或GitLab服务器上,私钥留在本地,配对成功才能通信。生成方式很简单:

ssh-keygen -t ed25519 -C "your_email@example.com"

一路回车,默认会写到~/.ssh/id_ed25519。生成后查看公钥内容:

cat ~/.ssh/id_ed25519.pub

把输出的整行文本复制到GitHub的Settings → SSH and GPG keys,或者GitLab的Preferences → SSH Keys里,粘贴保存即可。验证是否连通执行ssh -T git@github.com,能收到欢迎消息就说明通了。

配好之后,clone仓库时优先选SSH地址,也就是git@github.com:用户名/仓库名.git这种格式,从此push不再需要输密码。如果你在公司内网用GitLab,端口不同或域名特殊,还可以在~/.ssh/config里配置Host别名,指向对应的HostName和Port。这个小配置文件能解决很多网络环境的奇葩问题,值得专门研究一下。

3. 日常高频命令:围绕工作流反复出现的核心操作

安装配置搞定之后,进入真正每天都在重复的Git操作。这一节我按“初始化提交、撤销恢复、分支切换、临时保存”四条线来讲,每一组命令都是实际工作流的组成部分。

3.1 初始化仓库与第一次提交

新项目起步时,进入项目根目录执行:

git init

然后立刻创建一份.gitignore文件,把依赖目录、构建产物、本地配置排除在版本控制之外,否则后面会痛苦不堪(详见第六章)。接着把当前目录所有文件加入暂存区并提交:

git add . git commit -m "项目初始提交"

如果是接手已有项目,用git clone拉取即可:

git clone git@github.com:user/project.git

克隆下来的仓库自带完整历史,git log --oneline就能看到之前的每一次提交。

日常开发中最重要的命令是git status和git diff。git status告诉你当前仓库处于什么状态,哪些文件修改了、哪些新文件还没加入跟踪、当前在哪个分支。git diff则精确展示每一处代码改动。我习惯在提交前执行一遍git diff,逐行扫一眼改动内容,确认没有把调试用的console.log、临时代码带进去。这比提交之后再后悔要省事得多。

3.2 提交与撤销:掌握状态流转就掌握了一半

Git的工作区状态可以理解为三个区域:工作区(你正在编辑的文件)、暂存区(执行过add的文件)、版本库(commit过的历次快照)。每天的工作流就是文件在这三个区域之间流转。

git add有三种常用姿势:

git add . # 添加所有改动 git add src/App.js # 添加指定文件 git add -p # 交互式逐块选择改动

git add -p是我的最爱。它能让你自己决定哪些hunk进入暂存区,哪些先留着。比如一个文件里既有重构又有临时调试代码,用这个命令就可以只提交重构的部分,逻辑隔离非常干净。

出现撤销需求时,先判断改动在哪个区域。下面按场景列出对应命令:

  • 工作区有修改但还没add,想撤销这个文件的改动:git restore <file>,本质是用版本库内容覆盖工作区
  • 已经执行过add,想把它从暂存区拿出来但保留工作区改动:git restore --staged <file>
  • 提交之后发现信息写错了,或者漏了文件:用git commit --amend,下一章重点讲
  • 提交之后想整体撤回,但还想保留代码改动:git reset --soft HEAD~1,只动分支指针,不动暂存区
  • 提交之后想连同代码改动一起扔掉:git reset --hard HEAD~1,慎用,这会让改动彻底丢失
  • 提交已经push到远程共享分支,想再反悔:不要reset,用git revert <commit>生成一个反向提交

很多新手搞混reset和revert,记住一个简单的判断标准:如果这个提交只存在于你本地、还没push,可以用reset自由改写;如果已经push并且可能有同事拉取过了,就用revert,不要重写已经公开的历史。

查看历史时,最实用的命令是这个组合:

git log --oneline --graph --all --decorate

--oneline压缩成一行一个提交,--graph画出分支分叉线,--all显示所有分支,--decorate标出分支和标签指向。我每次需要理解仓库整体脉络时都会复用这一条命令,它能把纷乱的分支关系可视化得明明白白。

3.3 分支操作与stash:并行开发的两大武器

分支是Git里最有价值的设计。创建分支极轻量,因为它只是创建一个指向当前提交的指针,而不是复制任何代码。常用命令:

git branch feature/login # 创建分支 git switch feature/login # 切换分支 git switch -c feature/login # 创建并切换 git branch -d feature/login # 删除已合并分支 git branch -a # 查看所有本地和远程分支

注意不要再用老的git checkout -b,虽然还能用,但git switch语义更清晰,更符合“切换工作上下文”这个动作。

还有一个高频场景:你正在改一个功能,改到一半突然来了个线上bug要紧急修复。这时候工作区有一堆未提交的改动,又不能直接把半成品也带过去。正确做法是:

git stash # 保存当前工作区改动,回到干净状态 git stump # 切到修复分支,修完合并后再切回来 git stash pop # 恢复之前保存的改动

stash默认不会保存未跟踪的新文件,如果连新建的文件也要一起保存,用git stash -u。如果保存了多个stash,可以用git stash list查看,用git stash apply stash@{1}恢复指定条目。stash本质上是一个“临时寄存处”,让手头工作可以被完整挂起、稍后恢复,这是多任务切换时最容易出错的环节,建议每个新人都单独练习几遍。

4. git commit --amend:修改最近一次提交的两种用法与边界条件

热搜词里专门有“git commit --amend怎么使用”,可见这个命令让不少人犯过难。ame nd本身不复杂,但是因为很多人不理解“改写历史”的本质,用起来总是心里没底。这一章把它拆透。

4.1 它到底是什么,会带来什么后果

git commit --amend的作用,用一句话说:用一次新的提交替换最近的那次提交。结果是新的提交会生成新的哈希值,旧提交不复存在。

这句话看起来简单,含义却很重。你以为你只是“改了一下提交信息”,但Git视角里,你是把整个提交记录重写了一遍,所以commit的哈希值也变了。如果这个提交还没有推送到远程,改写完全没问题;如果已经推送到了共享分支,问题就会蔓延到所有同事的本地仓库,导致历史分叉。

所以使用前,先确认一个硬性前提:这个提交还没被push到共享分支。如果你在自己的feature分支上连续提交了好几次、还没有发起合并请求,那么这期间用amend完全安全。

4.2 两种最常见的用法

第一种,纯修改提交信息。提交之后发现拼写错误、措辞不清,想改一下:

git commit --amend -m "新的提交信息"

第二种,把漏掉的文件或修正内容归入上一个提交。比如你已经提交了登录功能,突然发现自己少改了一个样式文件,或者上一个提交里有个明显的低级错误,这时先修改代码,再:

git add . git commit --amend --no-edit

--no-edit表示“沿用原来的提交信息,不要打开编辑器”,省去一步交互。这样改动就并入了上一笔提交,不会在历史上留下“fix login style”这种废话提交。

如果你忘了加-m或--no-edit,Git会直接打开你配置的默认编辑器(常见的是Vim)。很多人在这卡住:文件打开了但不知道怎么退出。记住最简单的处理方式:按i进入编辑模式修改内容,改完按Esc退出编辑模式,然后输入wq再按回车,保存并退出。如果什么都不想改,输入q!强制退出不保存即可。

4.3 用错之后的补救

如果已经把amend的提交push到远程了,有三种处理路径,按严重程度从轻到重排序:

  • 影响不大,团队也没人合并过这个分支:可以直接再补一次新的commit修复问题,不折腾历史
  • 只是你一个人在用这个远程分支,并且团队成员明确不会拉取它:可以用git push --force-with-lease强制更新远程分支
  • 已经合并到公共主干,或不确定同事是否拉取过:老老实实加一个新提交,不要在公共历史上强行改写

--force-with-lease值得单独说一下。前面那个--force是“什么都不管,强推”,会造成让同事的历史与远端脱节;后面带--with-lease的版本会先检查本地是否基于远程的最新状态,如果发现远程已经出现了本地不知道的提交,就拒绝推送并报错。这个保护机制能救你很多次,宁可多敲几个字符也要用它,而不是用裸的--force。

注意:有些团队文化里非常忌讳在公共分支上执行amend,即使只是改个提交信息。原因在于它会改变提交哈希,而哈希又是代码审查、CD流水线、版本回溯的重要依据。建议在动手之前先问一句:这个分支除了我,还有别人在用吗?

5. 分支合并与冲突处理:实战中的分水岭

如果只会add、commit、push,你还在Git的舒适区。真正把人和人区分开来的,是分支合并时如何处理冲突。这一节是整篇文章里最需要反复练习的部分。

5.1 merge与rebase的选择逻辑

把两个分支的改动合并起来,主流方法有两种:merge和rebase。

git merge的逻辑是把两个分支的历史“汇合”到一个点,操作时会生成一个额外的merge commit,保留完整的分叉和汇合痕迹。优点是历史真实,缺点是历史图会像立交桥一样交错,看多了容易头晕。

git rebase的逻辑则是先把当前分支的提交“摘下来”,然后放在目标分支当前尖端之后重新拼接,最终形成一条线性历史。代码内容一样,形态完全不像,阅读体验更流畅,代价是当前分支的提交哈希全部被重写。

我的取舍标准是这样的:

  • 公共共享分支(main、develop)之间只merge,绝不rebase
  • 个人feature分支同步主分支最新代码时,愿意用rebase,让分支历史保持干净
  • 一个长期存在的多人协作分支,倾向用merge,避免大量提交被反复改写导致合作混乱

这是经验之谈,不是标准答案。每个团队都可以有自己的约定,但全队必须统一,混用merge和rebase最容易造成“历史看起来正常,一push就冲突”的诡异现象。

5.2 冲突的产生与解决完整流程

冲突的本质是:两个分支对同一个文件的同一块区域做了不同的修改,Git无法自动判断哪个是你要的,只能请你来裁决。这不是Git的缺陷,而是它的诚实。

模拟一次冲突:你在main分支上创建了feature分支,改完App.js后,同事也在main上改完了App.js并把变更合入主干。你合并feature到main时,Git看到两边都动了相同区域的代码,就会停下来报冲突。

冲突出现后,先别急。按以下顺序操作:

  1. 执行git status,找到标着both modified的文件
  2. 打开这些文件,你会看到类似下面的内容:
<<<<<<< HEAD 这是当前分支的代码 ======= 这是另一个分支的代码 >>>>>>> feature/login
  1. 逐块决定:保留头部的、保留尾部的、两边都要、或者重写这段逻辑
  2. 删除所有<<<<<<<、=======、>>>>>>>标记
  3. 对每个处理完的文件执行git add
  4. 全部处理完毕后执行git commit,完成合并

整个过程一句话概括:看代码、做决定、删标记、提交。不要用编辑器自动替换工具一键清除所有标记,那会把Git给你的选择信息丢掉,大概率造成代码错乱。

如果合到一半发现不想合并了,可以git merge --abort回到合并前。rebase过程冲突则用git rebase --abort。这是安全出口,用到不丢人,硬着头皮把冲突文件乱改一气才是灾难。

5.3 用交互式rebase把历史整理得干干净净

冲突不是只能事后解决,很多冲突可以通过小步提交和及时同步来避免。我见过的高手,提交粒度都很小,一次提交只干一件事:改一个接口、修一个bug、调整一段样式。这样合并时双方改动范围重叠的概率大幅降低。

除了控制粒度,你还可以用交互式rebase在push之前把本地多个碎提交整理成几个语义完整的提交。命令是:

git rebase -i HEAD~5

执行后Git会打开一个列表,列出最近5个提交:

pick a1b2c3d feat: add login page pick e4f5g6h fix: correct title typo pick i7j8k9l feat: finish user center

把某一行前面的pick改成squash,Git会把这一笔提交和上一笔合并成一个,并在编辑器中让你填写新的提交信息;如果改成fixup,则会直接合入上一笔提交、丢弃这条提交信息。比如我想把第二条“fix title typo”合进第一条提交,就把它改成fixup后保存退出。

这样做的最大好处是给代码审查者一个干净的历史:他们看到的是一组有意义的提交,而不是“改了一下”“又改了一下”的流水账。交互式rebase只适用于未推送的分支,一旦push过了,请参考上一章关于amend边界条件的判断逻辑。

6. 那些反复踩的坑与团队协作约定

到了这一章,命令层面的东西基本收尾了。接下来是真正让Git项目变得可持续管理的“软技能”——规则、约定、风险防范。

6.1 .gitignore和不该进入版本库的文件

neoprene版本库里,最先被坑的一定是.gitignore。很多新手喜欢把node_modules、target、dist、__pycache__、.env一股脑全部提交进去,结果仓库迅速膨胀、同事pull下来卡半天、甚至生产环境的密钥被泄露。.env这种文件尤其危险,里面通常放着数据库密码、第三方API密钥、OSS的accessKey,一旦进入历史,即使你后来删除,密钥也依然躺在提交历史里可被翻查。

正确做法是项目初始化时立刻创建.gitignore。常见生成方式是去gitignore.io或GitHub的模板仓库里选一套模板,然后按项目实际情况微调。如果某个文件已经被提交过,执行git rm --cached <file>可以把文件从跟踪中移走、保留本地磁盘文件,但历史里的记录还在,真正的清理需要借助git filter-repo等工具,过程较复杂,最好提前预防。

6.2 强推与reflog这道最后的保险

前文反复强调:不要对共享分支用git push -f。但总有控制不住手的时候,或者rebase之后不得不更新个人分支。这里的安全写法再强调一遍:git push --force-with-lease。它的检查机制能阻止你把别人的提交悄悄覆盖掉,是很多事故的防火墙。

如果你操作失误导致提交“丢失”,别慌,还有最后一道保险:git reflog。reflog记录的是本地仓库所有分支指针的移动历史,包括reset、rebase、checkout。比如我执行了git reset --hard HEAD~5,写完发现想找回其中一笔做了一半的代码,先查:

git reflog

你会看到一行行操作记录,每行前面带一个哈希值。找到你想要恢复的那次提交的哈希,然后:

git cherry-pick <那个哈希>

就能把那次提交捡回来。这个能力我用过不止一次,每次都庆幸Git把本地操作也全程记录了。建议所有开发者在心里记住reflog这个救命符。

6.3 commit message与分支命名约定的沉淀

最后聊团队约定。约定不是官僚,是给未来的人留线索。我所在的团队通常推荐这样的提交信息格式:

feat: 新增用户登录功能 fix: 修复订单列表分页失效的问题 docs: 补充README部署说明 refactor: 重构支付回调逻辑,抽出统一校验

前缀让代码历史变成一张可扫描的“变更说明书”,review时一眼就能定位某次提交的类型。分支命名也尽量统一,比如feature/order-detail、fix/avatar-upload,避免出现dev、test、asdf这类无法表达语义的名字。

还有一个很实际的经验:新成员接手项目时,我会让他们先执行git log --oneline -20观察团队的提交习惯,再动手改代码。提交习惯是团队协作风格最直观的体现,比看README更能了解这个团队怎么工作。

最后说一点切身感受。Git的命令非常多,但真正每天用到的也就二十个不到。我建议每个新人都刻意练习一遍“从提交到撤销再到恢复”的完整闭环:故意弄脏工作区、写错提交信息、在分支上制造一次冲突,然后挨个用restore、reset、amend、revert、rebase把它们处理干净。这个过程会把你对Git的恐惧彻底消除。等你能在一个playground仓库里随心所欲地折腾一遍,真实项目的压力就不会再让你手忙脚乱了。

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

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

立即咨询