搞开发这几年,Git 是我每天打开终端后第一个敲的命令。不管是几人的小项目还是几十人的团队协作,代码的提交、分支的合并、版本的回退,本质上都在跟 Git 操作打交道。这篇文章我打算从最基础的安装配置讲起,一直聊到分支合并、回退 merge、Git LFS 大文件管理,再附上一份疑难杂症的排查记录,基本覆盖一线开发日常用得到的场景。不管你是刚装好 Git 还不知道怎么提交代码的新手,还是被 merge 冲突和 clone 卡住折腾过的老手,都可以照着里面的步骤直接试。
1. 环境准备:安装配置与免密登录
先说环境。很多新手上来就急着敲 git clone,结果连 user.name 和 user.email 都没配,提交记录里全是 Unknown,后面追溯问题的时候特别痛苦。这一步别跳过,一次性配好能省掉后面一堆麻烦。
1.1 多平台安装与最低可用配置
Windows 上我推荐直接去 Git 官网下载安装包,一路 Next 就行。有两个选项建议留意一下:一个是默认编辑器,我习惯选手动设置而不是 Vim,不然后面写提交信息时误入 Vim 出不来的情况会让你崩溃;另一个是 PATH 环境变量,选中间那个 "Git from the command line and also from 3rd-party software",这样在终端、IDE 里都能直接调用 git。
macOS 上最简单的方式是装 Homebrew 后跑 brew install git,装出来的是较新版本,比 Xcode 自带的 git 体验好不少。Linux 发行版直接走包管理器,比如 Debian/Ubuntu 系的 apt install git,CentOS/RHEL 系的 yum install git。装完之后先验证一下:
bash复制git --version
看到版本号后,做最小化全局配置:
bash复制git config --global user.name "你的名字"
git config --global user.email "你的邮箱"
git config --global init.defaultBranch main
第三个配置很多人不知道,它把 git init 默认创建的分支名从 master 改成 main,避免后面团队规范不一。想确认配置生效,就运行 git config --list,所有全局配置都会列出来。
1.2 SSH 免密配置与凭据管理
配置好基础信息后,最值得花时间做的一件事就是配 SSH 免密。不然每次 push 都要输账号密码,用 HTTPS 方式的话还容易在切换账号时遇到凭据缓存混乱的问题。
先看本机有没有现成的密钥:
bash复制ls -al ~/.ssh
没有 id_rsa 或 id_ed25519 这类文件,就生成一个。我推荐用 ed25519,安全性更好,长度也短:
bash复制ssh-keygen -t ed25519 -C "你的邮箱"
一路回车会在 ~/.ssh/ 下生成 id_ed25519 和 id_ed25519.pub 两个文件。然后把公钥内容复制到代码托管平台的 SSH Keys 设置里:
bash复制cat ~/.ssh/id_ed25519.pub
登录平台后在个人设置里找到 SSH Keys,把输出粘贴保存。最后测试连接,以常用的托管平台为例:
bash复制ssh -T git@github.com
首次连接会提示确认 host key,输入 yes 回车。看到欢迎语就说明通了。之后 clone 仓库时用 SSH 地址,push 和 pull 就都不需要再输密码。
这里补充一个经验:如果公司内网用自建 GitLab,端口可能不是 22,或者走代理,那需要在 ~/.ssh/config 里单独配置 Host 段,指定 HostName、Port、User。我踩过多台机器 SSH 配置混用的坑,后来养成一个习惯,每台机器只保留当前项目的 Host 配置,避免冲突时排查半天。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 日常核心操作:提交、分支与合并
Git 的日常操作其实就围绕三个动作转:提交、分支、合并。把这三块搞熟了,80% 的开发场景都能应付。
2.1 提交前的工作区梳理与提交信息规范
我见过不少同事 git status 都不看一眼,直接 git add . 一把梭。这样做的问题是:可能把临时文件、编译产物、本地配置都提交上去了,代码评审的人看着一团乱麻。
合理流程是:先 git status 看清当前改动,再 git diff 确认具体改了哪些行,然后选择性 git add 需要提交的文件,最后提交。比如只提交核心代码:
bash复制git status
git diff
git add src/main/java/com/example/UserService.java
git commit -m "fix: 修复用户登录时 token 校验失败的问题"
提交信息建议遵循 Conventional Commits 规范,feat、fix、docs、refactor、test、chore 这些前缀一打出来,看历史记录的人立刻就知道这个提交是干嘛的。团队里如果接了 CI/CD,规范的提交信息还能自动生成 changelog,甚至驱动版本号变化。
提交粒度也很重要。一次提交只做一件事,别把"修 bug"和"重构代码"混在一起,否则将来 git bisect 定位问题时,你会在一堆混合提交里迷失方向。
2.2 分支管理与合并的五种姿势
分支管理上,我习惯遵循一套简单的流程:main 分支保持稳定可发布,开发功能时从 main 拉 feature 分支,完成后再合并回去。创建并切换分支的一行命令是:
bash复制git checkout -b feature/user-login
等价的老写法是 git branch feature/user-login 再加 git checkout feature/user-login。Git 2.23 之后也可以用 git switch -c feature/user-login,语义更清晰。
合并方式有几种,选错了会留下混乱的历史。我把常见方案整理成了一张表:
| 合并方式 | 命令 | 历史形态 | 适用场景 |
|---|---|---|---|
| Fast-forward | git merge feature | 线性 | 分支未分叉,直接推进 |
| 普通合并 | git merge feature | 分叉+合并节点 | 分支已有分叉,保留来源 |
| Squash 合并 | git merge --squash feature | 单点提交 | 想压成一条提交记录 |
| Rebase 后再合并 | git rebase main 后 merge | 线性 | 保持主线干净 |
| Cherry-pick | git cherry-pick |
单点带入 | 只想要某几个提交 |
我在团队里常用的原则:功能分支完成后用普通合并或 squash 合并;多人协作、需要保留每个开发者的提交证据时用普通合并;如果想保持提交历史像一条线一样干净,rebase 是更好的选择,但 rebase 会改写提交哈希,多人共享的分支上别乱 rebase。
2.3 合并冲突的产生与解决
冲突本身不可怕,可怕的是不知道怎么处理。冲突的本质是两个分支修改了同一个文件的同一块区域,Git 没法自行判断谁是对的,只能交给人工。
当合并出现冲突时,冲突文件里会出现这样的标记:
code复制<<<<<<< HEAD
当前分支的内容
=======
被合并分支的内容
>>>>>>> feature/user-login
解决步骤是:打开冲突文件,逐段决定保留哪边或者同时保留并整合,删掉 <<<<<<<、=======、>>>>>>> 这些标记,然后重新 add 并提交。
我处理冲突的独门心得是:先 git log 看两个分支各自的上下文,理解双方意图再改。另外,日常频繁合并是避免大冲突的最有效手段——分支别积攒一周才合一次,每完成一个里程碑就 rebase 或 merge 一下主干,冲突体量会小很多。
3. 回退与撤销:从本地到远端的完整方案
回退是 Git 操作里风险最高的一类操作。一个误操作可能让别人的提交丢失,所以这块我单独展开聊。
3.1 本地回退三板斧:reset、checkout、revert
本地回退有三个常用命令,对应不同诉求:
git reset 是"移动指针",把当前分支退回到某个历史提交。它有三种模式:
- --soft:只移动 HEAD,保留暂存区和工作区改动,适合"刚刚提交完发现漏了一个文件"的场景。
- --mixed(默认):移动 HEAD 并清空暂存区,保留工作区改动,适合"提交了但不想要这次提交内容"的场景。
- --hard:移动 HEAD 并丢弃所有改动,适合"本地改乱了想彻底还原"的场景。
git checkout 常用于丢弃单个文件的改动:git checkout -- src/App.vue,把文件还原到 HEAD 状态。注意这会丢失工作区未提交的修改,操作前务必备份或确认。
git revert 与上面两个完全不同。它不删除历史,而是生成一个新提交,把某个提交的改动反向应用回去。revert 适合远端分支——因为历史没有被改写,其他协作者 pull 时不会遇到"远程分支和本地历史不一致"的麻烦。
3.2 IDEA 中回退 merge 操作的实战记录
很多同事习惯在 IDEA 里完成 Git 操作,这里我把 IDEA 回退 merge 的完整过程记录下来。
场景是这样的:同事在 feature 分支上开发完,不小心把 main 合并进了 feature,导致 feature 分支里混入了大量 main 的提交,评审时一片混乱。要回退这次 merge,先搞清楚"回退到 merge 操作之前的某个提交"。
IDEA 的 Git 面板中,底部有 Log 标签页,能看到分支的提交历史。找到那次 merge 提交(通常提交信息是 Merge branch 'main' into feature),右键点击,选择 "Revert Commit"。这个动作相当于在 feature 分支上生成一个反向提交,把 merge 引入的内容全部撤销。
如果操作完发现不对,还可以继续右键那次 revert 提交选择 "Revert Commit" 再反回来。注意一点:revert 一个 merge 提交时,Git 需要知道拿哪个父提交作为主版本。在命令行里操作是这样的:
bash复制git revert -m 1 <merge-commit-hash>
-m 1 表示保留第一个父提交的版本,也就是当前分支的历史版本。IDEA 界面里一般会自动处理这个参数,但如果你在命令行手动操作,漏掉 -m 会导致命令无法执行或报错。实战中我遇到过 IDEA 版本不同 UI 位置有点差异的情况,但核心逻辑一致:找到目标提交 → Revert Commit → 解决可能出现的冲突 → push 到远端。
3.3 远端同步与风险控制
本地回退做完,要考虑远端分支的状态。如果提交已经 push 到远端,且是可共享的分支(比如 main、develop),不要用 reset --hard 强行覆盖远端历史,会引发协作者的混乱局面。正确做法是 revert。
如果分支只有你自己在用,那 reset 后强推是可以接受的:
bash复制git reset --hard HEAD~2
git push --force-with-lease
--force-with-lease 比我以前常用的 --force 更安全,推送前它会检查远端是否还是你上次拉取的状态,如果有人在你之前推了新提交,推送会被拒绝,避免把别人的工作覆盖掉。
4. 大文件管理:Git LFS 的实战与排障
项目里开始出现设计稿、模型文件、打包产物这类大文件时,普通 Git 仓库很快就扛不住了。仓库体积膨胀,clone 越来越慢,我最早踩这个坑是在接手一个带大量二进制资源的前端项目时,一次 clone 要十几分钟,实在忍不了,最后全量迁移到 Git LFS。
4.1 LFS 的安装与项目配置
Git LFS 的全称是 Large File Storage,它把大文件的实际内容存到独立的存储空间,Git 仓库里只保存一个指针文件,这样 clone 时仓库主体就不会被大文件拖垮。
先安装 LFS 扩展。macOS 用 brew install git-lfs,Windows 安装 Git 时可以直接勾选 Git LFS 组件,Linux 用发行版包管理器安装。然后执行:
bash复制git lfs install
这条命令会做全局初始化,往 Git 配置里写入 LFS 需要的过滤器。之后在项目里指定要托管的大文件类型:
bash复制git lfs track "*.psd" "*.zip" "*.mp4"
运行后会生成(或更新).gitattributes 文件,这个文件最好提交进仓库,这样其他协作者克隆后也自动套用同样的 LFS 规则。
检查一下 tracking 是否生效:
bash复制git lfs track
提交方式和普通文件一样:git add、git commit、git push。推送时 LFS 扩展会负责把大文件传到 LFS 存储。
4.2 clone 卡住的真正原因与解决方案
我在搜索引擎上看到"git lfs clone 卡住"是高频问题。实际排查下来,多数情况不是 LFS 本身故障,而是下面几个原因:
第一,网络链路问题。LFS 的存储服务器和 Git 服务器往往是不同域名,公司内网可能给 Git 域名走了代理,但 LFS 域名没配代理,导致传输卡住或超时。检查代理配置时,务必把 LFS 域名也加进去,或者确认系统代理能正常穿透。
第二,大文件数量过多导致并发请求阻塞。LFS 默认的并发下载数有限,遇到几百上千个大文件时,卡顿几乎是必然的。可以调整并发数:
bash复制git config --global lfs.concurrenttransfers 8
我实测调整后 clone 速度快了不少。
第三,LFS 对象不完整或指针未解析。如果仓库里混入了未真正上传到 LFS 存储的指针文件,clone 时会卡在 smudge filter 那一步。此时可以尝试跳过 LFS 拉取,看看仓库主体是否完整:
bash复制GIT_LFS_SKIP_SMUDGE=1 git clone <repo-url>
之后再手动 git lfs pull 拉取需要的文件。这能帮你区分是 LFS 传输问题还是仓库本身的问题。
4.3 迁移历史文件时要谨慎
如果仓库已经膨胀了,想迁移历史中的大文件到 LFS,情况就复杂了。官方推荐用 git lfs migrate 命令:
bash复制git lfs migrate import --include="*.zip" --everything
这个命令会重写整个提交历史,把所有 zip 文件替换成 LFS 指针。代价是所有提交哈希都会变,仓库里的所有协作者必须重新克隆或者执行 fetch 流程,这是一个重量级操作,必须在团队沟通清楚、确认仓库没有未备份的数据后再执行。迁移前先把仓库完整备份一次,迁移后验证 git lfs fsck 检查数据完整性,再通知团队同步。
5. 高频疑难杂症与排查速查
最后一部分,把我这些年收集的 Git 高频问题整理成速查手册。这些问题单独看都很小,但遇到时都挺耽误时间。
5.1 SSH 认证失败的排查路径
"ssh: Permission denied (publickey)" 是最常见的认证报错。按下面的顺序排查,基本都能定位:
第一步,验证密钥是否被 ssh-agent 加载:
bash复制ssh-add -l
如果列表为空或没有你的密钥,把它加进去:
bash复制ssh-add ~/.ssh/id_ed25519
第二步,确认远端连接使用的是哪个密钥和账户。用 -T 测试时如果显示权限错误,多半是公钥没配置,或者配置到了错误账户。重新把 ~/.ssh/id_ed25519.pub 的内容粘贴到平台对应账户的 SSH Keys 里。
第三步,检查是不是多密钥混用。多个密钥存在时,ssh 默认按顺序尝试,很容易用到错误的那个。这时在 ~/.ssh/config 里为特定 Host 显式指定密钥文件:
code复制Host gitlab.company.com
HostName gitlab.company.com
User git
IdentityFile ~/.ssh/id_ed25519_company
第四步,网络和端口问题。公司内网禁用了 22 端口很常见,可以改用 HTTPS 协议的地址,或确认平台是否支持 443 端口的 SSH 连接。另外防火墙和代理也会拦截 SSH 连接,遇到超时型报错时优先想这方面。
5.2 过滤文件不生效的原因与对策
.gitignore 是另一个高频问题来源。很多新手把文件加进 .gitignore 后发现 git status 里仍然能看到它,于是怀疑规则没生效。真实原因通常是:这个文件之前已经被 Git 跟踪过了。.gitignore 只对未跟踪文件生效,已经被跟踪的文件不受影响。
判断方法是:
bash复制git ls-files | grep "目标文件"
如果有输出,说明文件在版本控制里。需要用下面的命令把它从暂存区移除(同时保留本地文件):
bash复制git rm --cached 目标文件
然后提交这次变更,之后 .gitignore 规则才会正常起作用。另一个坑是 .gitignore 规则写得不够严谨,比如写了 *.logs 但文件实际是 .log,或者把目录规则写成了带斜杠的路径,导致匹配不上。建议用 git check-ignore -v 文件路径 来调试规则,它会明确告诉你哪条规则匹配了文件、为什么匹配。
5.3 高频问题速查表
| 问题现象 | 排查思路 | 常用命令/方案 |
|---|---|---|
| push 被拒绝 non-fast-forward | 远端有别人新推的提交 | git pull --rebase 后再 push |
| 提交信息打错想改最后一次 | 仅本地未推送时可直接改 | git commit --amend -m "新信息" |
| 误删了还没提交的文件 | 文件在本地工作区,可恢复 | git checkout -- 文件路径 |
| 分支误删 | 分支头提交只要还有日志就能找回 | git reflog 找到哈希后 git branch 恢复 |
| clone 超大仓库超时 | 浅克隆减少历史量 | git clone --depth=1 仓库地址 |
| 端口被防火墙拦截 | 改用 HTTPS 或 443 端口 | 平台设置里选 HTTPS 克隆地址 |
| 中文文件名显示为转义 | 让 Git 按原始字符输出 | git config --global core.quotepath false |
使用 git reflog 时注意一点:它记录的是本地仓库的引用变动日志,误删分支、reset 过头都能靠它找回,但 reflog 也有保留期限,默认 90 天,重要的仓库建议养成定期备份的习惯。
另外我再分享一个实测有效的习惯:我把 git status 和 git log --oneline -10 设成了别名,每天开工先看一眼,收工前再确认一次,基本避免了"提交到了错误分支"这种低级失误。Git 这个东西,入门门槛不高,但真正用顺手需要积累,这篇记录里的每个命令和排查思路都是我在实际项目里验证过的,照着走能少走不少弯路。如果你在工作中遇到其他奇怪的 Git 问题,欢迎带着具体报错来交流,很多问题都是在真实场景里才暴露出来的。
