☰
Git实战指南:从配置到分支管理的完整工作流
2026/10/20 23:19:32 网站建设 项目流程

1. 环境准备与全局配置:先把地基打牢

Git这个东西,刚接触的人总觉得命令多、概念绕,实际上真正天天用的就那么几条。我在带新人或者帮同事排查问题的时候,发现九成的手忙脚乱都不是因为Git本身难,而是一开始的配置就没弄对,后面每一步都在还债。所以这篇文章我不想按文档顺序罗列命令,而是按照一个真实项目从零到一的推进节奏,把用户名配置、下载代码、提交修改、切换分支、配置密钥这些高频操作串起来讲,顺便把我这些年踩过的坑也一并交代清楚。

先说第一个问题:Git装好之后,第一件事不是急着clone代码,而是告诉Git“你是谁”。这个身份信息会写进每一次提交记录里,别人在代码评审、追溯历史的时候看到的就是这个名字和邮箱。如果这一步随便糊弄,后面会出现两种尴尬:一是提交记录里显示一堆Unidentified或乱码名字,二是同一个人的提交因为邮箱不一致被算成好几个人,团队统计贡献和回溯bug时非常头疼。

配置分两级,全局配置(global)和仓库级配置(local)。全局配置作用于当前电脑上的所有仓库,适合设置个人默认身份;仓库级配置只对当前仓库生效,适合公司项目里临时覆盖个人身份的情况。

# 全局配置 git config --global user.name "你的名字" git config --global user.email "you@example.com" # 仓库级配置(在仓库目录内执行) git config --local user.name "项目专用名字" git config --local user.email "project@example.com"

配置完之后一定要验证一下,很多人配完就忘,等到push上去才发现身份错了。验证命令:

git config --global --list git config --local --list

这里有个细节容易被忽略:邮箱不一定要用真实邮箱,但必须是一个能收到邮件的地址。因为Git托管平台的通知、代码评审提醒、找回密码都靠这个邮箱,如果你随手敲了个不存在的地址,遇到账号异常时连找回的入口都没有。

还有一个更隐蔽的问题:如果你在公司电脑上配了个人邮箱,提交到公司仓库后,个人邮箱会暴露在内部系统里。我见过有团队强制要求公司项目必须使用公司邮箱,通过pre-commit钩子或者服务端规则拦截个人邮箱提交。所以我的习惯是:工作电脑全局配置用个人常用账号,涉及公司仓库时再用--local覆盖成公司邮箱,互不污染。

Windows用户还要多做一步换行符检查。因为Windows和Linux/macOS对换行的处理方式不一样,Git默认的autocrlf设置如果不对,会出现整个文件都被标记为修改的诡异现象。建议执行:

git config --global core.autocrlf true # Windows 用户 git config --global core.autocrlf input # macOS/Linux 用户

这个设置的意义在于:提交到仓库时统一转换成LF(Unix换行),检出到本地时Windows再转回CRLF。不设置的话,你在Windows上改了一行代码,Git会认为整个文件都变了,因为换行符全被改了一遍,代码评审时差异列表能把你逼疯。这是我刚参加工作时踩过的坑,当时发出去的变更请求里有几百行diff,其实只动了三行代码,被导师拎出来当反面教材说了很久。

2. 配置SSH密钥:不用每次输密码的通行证

身份配好了,接下来要解决的就是“怎么安全地把代码拉下来”。Git托管平台支持的协议主要就两种:HTTPS和SSH。HTTPS简单直接,但每次push都要输账号密码或被要求输入访问令牌,有的平台还需要在网页端勾选一堆权限才能生成令牌,用起来很繁琐。SSH密钥的本质是一对加密钥匙:私钥留在你电脑上,公钥放到Git托管平台后台,配对成功之后就能免密操作。

关于密钥的生成方式,这里我要专门提一句:现在网上一搜全是ssh-keygen -t rsa,但如果你用的是Git Bash或者新版Windows Terminal,直接用Ed25519算法更稳。RSA默认是2048位,安全性没问题,但Ed25519的密钥更短、生成更快、安全强度也更高,而且新版OpenSSH对它的支持已经非常成熟。我用Ed25519生成了几百个密钥,从没遇到过兼容性问题。

# 生成Ed25519密钥(推荐) ssh-keygen -t ed25519 -C "you@example.com" -f ~/.ssh/id_ed25519 # 生成RSA密钥(老系统兼容) ssh-keygen -t rsa -b 4096 -C "you@example.com" -f ~/.ssh/id_rsa

执行过程中会提示你设置passphrase,也就是密钥口令。这里大多数人会直接回车跳过,图省事。我个人的建议是:本地个人电脑可以跳,公司电脑强烈建议设置。因为公司电脑存在被其他人使用的可能,一旦私钥泄露,对方拿着你的私钥就能随意访问你有权限的所有仓库。设置了口令之后,即使私钥文件被拷走,对方没有口令也白搭。

生成完成后,公钥文件是id_ed25519.pub,私钥是id_ed25519。注意:公钥可以到处发,私钥连同事都不要给,更不要提交到代码仓库里。这个提醒不是开玩笑,GitHub上有个著名的爬虫项目专门扫描公开仓库里的私钥文件,只要发现BEGIN OPENSSH PRIVATE KEY开头的字符串就自动收集,检测到之后平台方一般会直接发邮件警告你。

接下来把公钥内容添加到Git托管平台。不管是哪家平台,操作路径大同小异:进入个人设置(Settings),找到SSH Keys或者SSH and GPG Keys这个入口,把id_ed25519.pub里的整段内容粘贴进去,起个名字方便识别是哪台电脑,保存即可。

添加完密钥之后,用这条命令验证连接是否正常:

ssh -T git@github.com

不同平台返回的欢迎语不一样,有的会显示Hi username! You've successfully authenticated,有的会提示Welcome之类的信息。看到欢迎语就说明密钥配置成功了,而第一次执行时如果弹出一个确认指纹的提示,输入yes即可。

这里有个坑我要特意说一下:如果你电脑上配置了多个SSH密钥,比如一个用于个人GitHub,一个用于公司GitLab,直接执行ssh -T git@github.com可能会报错Permission denied (publickey)。原因是SSH默认只会去找~/.ssh/id_rsa或id_ed25519,找不到就放弃,不会自动尝试其他密钥文件。解决办法是编辑~/.ssh/config文件,把不同域名对应到不同密钥上:

Host github.com HostName github.com User git IdentityFile ~/.ssh/id_ed25519_github Host gitlab.company.com HostName gitlab.company.com User git IdentityFile ~/.ssh/id_ed25519_work

配置好之后,SSH会根据你连接的域名自动选择合适的私钥,彻底告别指定密钥的烦恼。

3. 克隆代码与日常提交:打通“拉-改-推”的闭环

密钥配好了,终于到了正式操作环节。把远程仓库的代码下载到本地,标准动作就是clone:

git clone git@github.com:username/repository.git # 或者指定目录名 git clone git@github.com:username/repository.git my-project

这个命令背后的逻辑是:除了把默认分支(通常是main或master)的代码拉下来,还会自动建立一个origin远程连接指向原仓库地址。以后你执行git pull、git push、git fetch,Git都知道该跟谁通信,不需要你再手动添加远程地址。

clone完成之后,我强烈建议你先建一个自己专属的分支再动手改代码。原因很简单:直接在主分支上修改,万一改到一半发现思路不对想回退,会污染主分支的历史记录;如果多人协作,别人pull下来还可能跟你改到同一个文件产生冲突。而新建一个分支,改坏了就删掉重来,主分支永远干干净净。

创建并切换到新分支:

git checkout -b feature/login-page

这个命令是两条命令的合并写法,等价于:

git branch feature/login-page git checkout feature/login-page

checkout -b带来的分支是本地分支,只存在于你电脑上,远程仓库里暂时没有。后面你执行push提交时,加上-u参数就能在推送的同时建立本地分支和远程分支的追踪关系:

git push -u origin feature/login-page

-u全称是--set-upstream,它做的事是告诉Git:这个本地分支的默认上游(要推送的目标)是远程的feature/login-page。设置过一次之后,后续再执行git push或git pull就不用带远程仓库名和分支名了,直接裸敲命令就行。我见过不少人每次push都要把git push origin xxx完整打一遍,其实就是当初少加了一个-u。

接下来是日常开发里最核心的三连:改文件、暂存、提交。

# 查看工作区状态 git status # 查看具体改了什么内容 git diff # 暂存所有改动(新增/修改/删除) git add . # 提交并写备注 git commit -m "feat: 实现登录页面表单校验"

git add也分几个层次。git add .会把当前目录下所有变更都加入暂存区,适合改动不复杂的场景;git add src/可以只暂存某个目录;git add src/App.js只暂存单个文件;git add -p则进入交互模式,逐个hunk地确认要不要暂存。交互模式在你想把一个文件的改动拆成多个提交时非常好用,比如一个文件里既有格式调整又有新功能,用git add -p就能把这两部分分开提交,历史记录会清晰得多。

提交信息这块值得多说两句。我见过太多update、fix、aa这种备注,过两周回头看根本不知道当时做了什么。好的提交信息最好遵循统一的格式,社区通用的写法是:

  • feat: 新功能
  • fix: 修复bug
  • docs: 文档变更
  • style: 格式调整(不影响代码运行)
  • refactor: 重构(不是新功能也不是修bug)
  • test: 添加或修改测试
  • chore: 构建或辅助工具变动

比如feat: 增加用户头像上传接口、fix: 修复登录超时后跳转错误。这种结构化的提交信息除了让人看得懂,还能配合发布工具自动生成changelog,算是一劳永逸的投资。

提交流程走完之后,把本地提交推送到远程:

git push

如果推送时提示remote contains work that you do not have locally,说明远程仓库有别人先推了代码,Git出于安全考虑拒绝你的推送,避免覆盖别人的提交。这时候的处理顺序应该是先pull再push:

git pull origin main git push

git pull实际上是两条命令的合并:git fetch(把远程的更新拉下来但不合并)加git merge(将拉下来的更新合并到当前分支)。如果你的代码和别人的改动互不冲突,会自动完成合并;如果改了同一个文件的同一块区域,就会产生冲突,Git会把冲突标记打到文件里让你手工解决。这个过程后面专门讲。

这里我还想提一个很多新手不知道的好习惯:不要在主分支上直接提交代码。不管是你自己的个人项目还是团队协作,主分支都应该保持“随时可部署”的稳定状态。我的常规做法是:新建功能分支开发,开发完成后切回主分支,执行git pull把最新代码拉下来,再合并自己的分支。如果合并过程中有冲突,就在本地解决掉再推上去。这样主分支的历史永远是干净的,不会出现一堆“临时提交”“改一下”“又改一下”的垃圾记录。

4. 分支管理与合并策略:多人协作不打架的关键

分支是Git里最值得花时间理解的概念。网上有个比喻很形象:分支就像平行宇宙,你可以在自己的宇宙里随便改动,改砸了也不影响主宇宙。这个理解方向是对的,但实际使用中还有几个容易混淆的操作点需要厘清,不然切换分支的时候哭都来不及。

先看最基础的三个动作:

# 查看所有本地分支 git branch # 查看所有远程分支 git branch -r # 查看所有本地+远程分支 git branch -a # 切换到已有分支 git checkout main # 或者新版写法 git switch main

checkout和switch在功能上高度重叠,新版本Git推荐用switch做分支切换,语义更清晰,不容易跟git checkout丢弃工作区改动的功能混淆。对于老司机来说用什么无所谓,新手我建议直接用switch系列命令:git switch -c创建并切换,git switch切换。

未提交的改动会被带到切换后的分支去,这是个特别容易翻车的点。比如你在feature-A分支改了一个文件,还没commit,直接切到main分支,这个未提交的改动会跟着你跑到main分支上。如果两边分支的内容存在差异,Git有时候会切不过去,提示你Your local changes would be overwritten。这时候有两个选择:

一是把改动提交到当前分支再切换:

git add . git stash push -m "临时保存未完成的改动"

二是用git stash把改动暂存起来:

git stash push -m "登录页面布局调整中" git checkout main # 等切回来之后恢复 git stash pop

stash就像一个临时储物柜,把你手头没干完的活先锁起来,等切回来再取出来接着干。弹出的命令是git stash pop,它会恢复最近一次暂存的改动;git stash list可以查看当前暂存了几个记录;git stash apply stash@{1}可以恢复指定的一条记录。

我自己处理临时切换需求时基本都用stash,比自己复制文件到外面再粘贴回来安全太多了。复制粘贴的方式容易遗漏修改过的文件,比如你改了三个文件但只记得复制了两个,回到原分支后发现丢掉的那个改动再也找不回来。

分支合并常用的两招:merge和rebase。它们的差别在于历史记录的形状。

# merge:把另一个分支的改动合并进来,保留完整的历史分岔 git merge feature/login-page # rebase:把你的提交按到目标分支的最新提交之后,历史变成一条直线 git rebase main

merge的特点是“真实记录发生过什么”,缺点是比较提交历史时会有分岔,看起来不是线性的。rebase的特点是整洁,像你直接在最新版代码上从零开发一样,但代价是它会重写提交的哈希值,如果你已经把分支推到了远程并且有别人在基于你的分支开发,这时候rebase会把别人搞得很难受。

我个人的习惯是:自己开发的功能分支在合回主分支前,可以考虑用rebase把时间线拉直;已经推上远程的共享分支,绝对不用rebase。这个原则能避免绝大多数历史混乱的问题。

再来说冲突。冲突的本质是两个人改了同一个地方的代码,Git不知道该听谁的。冲突文件的标记长这样:

<<<<<<< HEAD 你当前分支的内容 ======= 对方分支的内容 >>>>>>> feature/login-page

解决方式就是打开文件,把不需要的部分删掉,保留最终想要的代码,然后删掉<<<<<<<、=======、>>>>>>>这几行标记,保存文件,再执行git add和git commit。整个过程不复杂,但需要你了解两边的代码逻辑,胡乱合并的后果往往是一堆隐藏的语法错误或行为异常。

有一个非常实用的避坑方法:在每次merge之前先把目标分支的最新代码拉下来。比如你要把feature/login-page合入main,先切到main执行git pull,再切回feature/login-page执行git merge main,把主分支的更新提前合并进自己的分支。这样真正要把功能分支合入主分支时,冲突已经在你自己的分支上解决过了,主分支的merge操作会非常干净。这个习惯我保持了几年,团队里出问题的次数屈指可数。

5. 远程仓库协作:团队开发必须掌握的同步技巧

单人开发时clone、push、pull就够用了,但一旦进入团队协作,你还会遇到更多跟远程仓库相关的操作。这节我把几个高频场景逐个说清楚,配合具体命令和排查思路。

第一个是频繁pull导致本地落后太多的情况。假设你的本地分支已经落后远程分支好几个commit,同时你本地也有未推送的提交,这时候需要小心处理的工作流一般是:

git fetch origin git rebase origin/main

用fetch把远程更新拉到本地暂存区,用rebase把自己的提交变基到新的远程提交之后。这样做可以避免产生一个“合并提交”,历史看起来更清晰。如果双方的改动没有冲突,rebase是静默完成的,你甚至感受不到变化。如果产生冲突,Git会停下来,让你逐个解决,解决完执行git rebase --continue继续,想放弃就执行git rebase --abort回到rebase之前的状态。

fetch和pull的区别值得强调一下。fetch只负责把远程的更新拉到本地,但不会自动合并到你的工作区,你的代码还是原来的样子;pull等于fetch + merge,拉下来之后立即尝试合并。所以当你不想立刻合并、只想看看远程有什么变化时,用fetch更安全。看完之后对比一下差异:

git fetch origin git log --oneline HEAD..origin/main

这条log命令显示的是origin/main上有、但你本地HEAD没有的提交。确认不影响自己之后,再决定要不要合并。这套流程在多人同时开发同一个功能分支时格外实用,能让你在merge之前就心里有数。

第二个高频场景是误操作或推送了不该推送的内容。比如不小心把包含密码的配置文件提交并推送到了远程仓库。很多人第一反应是执行git reset退回之前的提交,然后强制推送覆盖远程。这里要分两种情况:

如果你是在推送到远程之前就发现了,处理很简单:

git reset --soft HEAD~1

--soft保留工作区和暂存区的内容,只把HEAD指向上一个提交,相当于撤销了这次commit但保留所有改动,你可以重新组织后再次提交。如果想要同时撤销暂存区但保留工作区,用git reset HEAD~1(默认mixed模式)。如果连工作区的改动都不要了,用git reset --hard HEAD~1,这条路不能反悔,执行前务必确保改动可舍弃。

如果已经推送到了远程,单纯git reset只在本地生效,远程还是旧状态。需要强制推送覆盖:

git push --force-with-lease origin feature/login-page

注意我用的是--force-with-lease而不是裸--force。--force-with-lease会在推送前检查远程分支是否还是你上次fetch时的状态,如果这期间别人推了新代码,推送会被拒绝,避免你覆盖掉同事的提交。裸--force是无条件覆盖,危险系数高得多。我在生产环境分支上从来不用裸--force。

第三个场景是删除分支。分支合并完成后,本地分支可以删掉,命令很简短:

git branch -d feature/login-page

如果分支里有未合并的提交,-d会拒绝删除,需要改用git branch -D feature/login-page强制删除。删除远程分支用:

git push origin --delete feature/login-page

远程分支删了之后,本地还会保留一个可以查看的引用origin/feature/login-page,但如果别人在你删除远程分支之后执行了git fetch --prune,这个引用也会被清理掉。平时我清理分支的习惯是:每完成一个功能的合并,顺手删除本地和远程对应的分支,保持仓库清爽。

6. 高频问题排查:这些错误信息我全遇到并解决过

最后把平时被问得最多、我自己也反复踩过的问题集中梳理一遍,做成一个速查表,每条附上解决方案和背后的原理。收藏这个列表,基本可以应对日常开发中九成以上的Git报错。

报错/问题出现原因解决方案
fatal: Not a git repository当前目录不是一个Git仓库确认是否进入了正确的项目目录,执行git init初始化或cd到已有仓库
Permission denied (publickey)SSH密钥未配置或未被识别检查~/.ssh下是否有密钥、公钥是否添加到平台、~/.ssh/config是否配置正确
fatal: remote origin already exists当前仓库已经关联了一个远程地址用git remote set-url origin 新地址修改或git remote remove origin删除
error: failed to push some refs远程有本地没有的提交,推送被拒先git pull再git push,或者git fetch后对比差异再处理
Merge conflict in xxx双方修改了同一个文件的同一区域打开冲突文件,删除冲突标记,保留最终代码,git add+git commit
fatal: refusing to merge unrelated histories两个仓库没有共同的提交历史(比如远程是新建的,本地是另一个版本)如果确认要合并,执行git pull origin main --allow-unrelated-histories
LF will be replaced by CRLF换行符自动转换提示确认core.autocrlf设置是否符合你的操作系统

这些报错里最典型的还是Permission denied (publickey),出现频率极高。排查思路按照下面三步走:

# 第一步:确认本地有没有密钥文件 ls -la ~/.ssh/ # 第二步:确认ssh-agent里有没有加进私钥(macOS/Windows都有这个服务) eval "$(ssh-agent -s)" ssh-add ~/.ssh/id_ed25519 # 第三步:测试连接 ssh -T git@github.com

如果这三步都正常但还是报错,优先检查~/.ssh/config里的IdentityFile路径是不是配错了,或者公钥粘贴到平台时多了空格、换行。我还遇到过一种很隐蔽的情况:Windows系统下~/.ssh目录的权限设置不正确,SSH直接拒绝读取私钥文件。解决方法是右键这个文件夹 -> 属性 -> 安全,给当前用户赋予完全控制权限,再重试就能通过。

另一个让很多人困惑的问题是**git pull和git fetch之后代码“没变”**。其实不是没变,而是fetch不会自动合并。如果你执行的是git fetch,发现远程有更新但本地代码没变化,这是正常现象,再执行git merge origin/main或者直接git pull origin main才会真正合并到工作区。这就像你去快递柜取件:fetch是收到取件码通知,merge才是打开柜子拿到包裹。

有些时候你还会遇到提交信息写错了的情况,比如git commit -m "feat: 修复登录"结果发现这是个bug修复不是新功能,想改一下提交说明。如果提交还没推送,直接用:

git commit --amend -m "fix: 修复登录超时问题"

这条命令会替换掉最近一条提交的信息,但提交的内容不变。如果已经推送了,还是能用--amend改,但之后需要强制推送,而且必须遵守一个前提:这个分支只有你自己在用,没有别人基于它开发。有同事在用的分支,不要amend,不要rebase,不要强制推送,这三个操作都会让别人的历史记录跟你出现分歧,最终只能手工协调,费力不讨好。

再补充一个几乎每个开发者都绕不开的场景:临时切换分支时潜在未提交的代码怎么办。我前面提到过git stash,这里把完整流程再走一遍,因为这是高频中的高频:

# 保存当前所有未提交的改动 git stash push -m "购物车样式调整中" # 查看stash列表 git stash list # 切到别的分支干活 git checkout main # 干完活切回来 git checkout feature/shopping-cart # 恢复之前暂存的改动 git stash pop

git stash pop和git stash apply的区别在于:pop会从stash列表中移除该条记录并应用变更;apply会保留记录只应用变更。如果你恢复之后发现改动有冲突,pop会停止并保留stash记录,你可以解决完冲突再用git stash drop手动删除这条记录。反正我在恢复应用完之后,都会顺手看一眼git status,确认要恢复的改动都在。

7. 日常使用中的几个建议

最后写几条我自己摸索出来的使用习惯。这些不是功能讲解,而是实际工作中沉淀下来的操作偏好,分享出来仅供参考。

第一条,提交之前先看diff。很多人是改完直接git add .加git commit -m "xxx"一条龙,从来不检查自己到底改了哪些东西。结果经常把调试代码、临时打印、甚至无用文件一起提交上去。我现在养成的固定动作是:git add之后、git commit之前,看一眼git diff --cached,确认暂存区里的每个改动都是自己想要的。这个习惯能过滤掉至少七成的误提交。

第二条,每次登录新电脑,先配置ssh key再接仓库。我在换电脑时遇到过太多次“明明之前的电脑都好好的”这样的困惑,其实就是新电脑没有生成密钥。按照文章前面的流程走一遍,十分钟内能全部搞定。

第三条,给提交信息留个规范模板。我见过有的团队用模板引擎来约束提交格式,但更多人是靠自觉。如果你管不住自己,可以给Git配置一个提交模板文件,每次执行git commit时自动加载模板内容:

git config --global commit.template ~/.git-commit-template.txt

模板文件里写好格式说明和示例,提交时会自动打开编辑器,输入完成保存退出即可。这个办法对团队统一风格非常有效,比管理文化管用得多。

第四条,定期git fetch --prune清理远端分支引用。团队协作一段时间后,本地会积累一堆别人已经删除的远程分支引用,git branch -a看起来乱七八糟。执行:

git fetch --prune

这条命令会把本地记录的、但远程已经不存在了的分支引用清理掉。实测下来,每隔一两周跑一次,仓库会清爽很多。

第五条,也是我反复想在文章里强调的:Git只是一个工具,它的核心价值不是让你炫技,而是让你的代码历史清晰可追踪、让团队协作不失控。很多人学了十几个高级命令就以为自己精通Git了,但真正到了生产环境,零失误地处理好每一次提交、每一次合并,比背下来多少命令参数重要得多。

如果这篇文章能帮你少走几步弯路,那这些内容就没有白写。Git的文档永远是全面但不亲和的,真正让知识落地的,永远是实操、踩坑、再实操的循环。

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

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

立即咨询