Git 这东西,刚入行那会儿我也觉得它玄乎。不就是保存文件吗,我复制一份改个名不就行了?直到有一次改崩了一个功能,想退回昨天的版本,结果发现文件夹里躺着"最终版""最终版2""真最终版""打死也不改了版"——那一刻我才明白,靠手动复制管理版本,迟早要出事。Git 就是来解决这个问题的:它帮你把每一次改动都记下来,随时能翻旧账、随时能开新路、随时能跟别人合着干。这篇文章不堆术语,我按一个零基础的人从"完全不懂"到"能上手干活"的路径来讲,把安装、配置、仓库、分支、合并、协作这些事一件件说清楚,顺带把新手最容易踩的坑提前给你标出来。看完你至少能做到:自己建仓库、提交代码、开分支、合并分支、推到远程、跟同事协作不打架。
1. 先把 Git 到底解决什么问题讲透
1.1 没有版本控制的日子是什么样的
我先描述一个场景,你看看熟不熟悉。你写一个文档或者一段代码,改到一半觉得不对劲,想回到上午十点的状态。这时候你有两个选择:一是凭记忆手动改回去,二是提前复制过一份。大多数人靠的是第二种,于是文件夹里就出现了这种命名:方案.docx、方案_改.docx、方案_最终.docx、方案_最终_真的最终.docx、方案_最终_老板改过.docx。
这种土办法有三个致命问题。第一,你根本记不住每个文件到底改了啥,时间一长自己都分不清哪个是哪个。第二,多人协作时彻底乱套,你把文件发给我,我改完发回给你,你手上那份和我手上那份就不一样了,谁覆盖谁全靠运气。第三,出了问题没法追溯,你只知道"昨天还好好的",但昨天到底动了哪一行,完全查不到。
Git 的出现就是为了干掉这三个问题。它做的事情本质上一句话:给项目的每一次变化拍一张快照,并且记录下是谁、什么时候、为什么拍的这张快照。有了这些快照,你就能在任意两个时间点之间来回跳,也能清楚地看到每次改动具体动了哪些内容。
1.2 Git 和"网盘""复制粘贴"的本质区别
很多人第一次接触 Git 会问:这不就是个网盘吗,我把代码传上去不就行了?这个理解差得比较远,我用一个类比说清楚。
网盘存的是文件的结果,它只知道"你上传了一个叫 a.txt 的文件"。Git 存的是文件的演变过程,它知道"a.txt 在第 1 版有 3 行,第 2 版你加了 2 行删了 1 行,第 3 版你把第 2 行改了"。这个区别带来的直接好处是:网盘只能给你"最新版",Git 能给你"任意一版",还能告诉你"每一版之间差在哪"。
再打个比方。复制粘贴管理版本,就像你每次改稿都重新打印一份纸质稿堆在桌上,改到第十版桌上堆了十份纸,你想找第三版里的一句话得一张张翻。Git 更像是一个带时间轴的编辑器,你拖动时间轴就能看到任意时刻的完整内容,还能高亮显示每次改动的部分。
还有一个关键区别是分支。这个后面会详细讲,你先记住一句话:Git 允许你在不影响主线的情况下,另开一条线去试新想法,试成了就合回来,试砸了直接扔掉,主线毫发无伤。这是复制粘贴永远做不到的。
1.3 谁需要学 Git,学到什么程度够用
不是所有人都需要把 Git 学成专家。我按使用场景分三档,你对号入座。
第一档,个人开发者或者独立写作者。你只需要掌握:安装配置、建仓库、提交、看历史、回退。这几个命令学会了,你一个人干活就够用了,能彻底告别"最终版2"。
第二档,团队协作中的普通成员。在上一档基础上,你还要会:拉取远程代码、推送自己的改动、开分支、合并分支、解决冲突。这是绝大多数公司里程序员、文档写作者、设计稿管理者的日常需求。
第三档,团队里的 Git 负责人或者 DevOps。你需要懂:分支策略设计、代码评审流程、标签发布、钩子脚本、仓库迁移。这一档涉及团队规范,不是本文重点,但我会在协作那部分点到。
对绝大多数人来说,第二档就是天花板了,把第二档的内容吃透,你在团队里就不会因为 Git 掉链子。下面我就按这个路径带你走一遍。
2. 安装和第一次配置:别在这一步就埋雷
2.1 各平台安装方式的选择逻辑
安装本身不难,但选错方式会给后面添麻烦,我说说我的选择逻辑。
Windows 上,最省心的是去官网下载安装包,一路下一步。安装过程中有一个选项叫"Adjusting your PATH environment",默认选的是"Git from the command line and also from 3rd-party software",这个保持默认就行,它会把 Git 加到系统环境变量里,这样你在任意命令行窗口都能用git命令。另一个选项是换行符处理,默认"Checkout Windows-style, commit Unix-style line endings"就可以,这个设置能避免 Windows 和 Linux 协作时的换行符冲突。
macOS 上,如果你装了 Xcode 命令行工具,Git 通常已经自带了,终端里敲git --version能出版本号就说明有。想装新版本可以用 Homebrew,一条命令搞定。我个人的习惯是能用系统自带就用自带的,除非版本太老影响功能。
Linux 上直接用包管理器,Debian 系用apt,RedHat 系用yum或dnf,这个不用多说。
提示:安装完成后一定要在终端里敲一次
git --version确认能出版本号。我见过不少人装完了但环境变量没配好,敲 git 提示"不是内部或外部命令",白折腾半天。
2.2 那三行必须配置的命令,以及为什么必须配
装完之后,第一件事不是急着建仓库,而是配置身份。Git 每次提交都会记录"是谁提交的",这个信息就来自你的配置。命令是这两条:
git config --global user.name "你的名字" git config --global user.email "你的邮箱"--global表示这是全局配置,对你这台机器上所有仓库生效。为什么必须配?因为如果你不配,第一次提交时 Git 会报错或者用一堆默认值,导致提交记录里作者信息是乱的。团队协作时,别人看到你的提交不知道是谁干的,追责和沟通都成问题。
第三条建议配的是默认分支名:
git config --global init.defaultBranch main老版本的 Git 默认分支叫master,新版本逐渐转向main。你提前设好,新建仓库时就不会因为分支名不一致跟团队对不上。这个不是必须,但能省掉后面改名的麻烦。
配置完可以用git config --list查看所有配置,确认写进去了。这里有个新手常问的问题:邮箱能不能随便填?技术上可以,但强烈建议填你真实在用的邮箱,因为很多代码托管平台靠邮箱来关联你的提交和账号,填错了你的贡献记录就挂到别人名下了。
2.3 配置错了怎么改,以及配置存在哪
配置写错了不用慌,重新执行一遍同样的命令就会覆盖。比如名字写错了,再跑一次git config --global user.name "正确的名字"就行。
这些配置存在哪?全局配置存在你用户目录下的.gitconfig文件里,Windows 一般在C:\Users\你的用户名\.gitconfig,macOS 和 Linux 在~/.gitconfig。你可以直接用文本编辑器打开看,内容就是一堆键值对。
除了全局配置,还有仓库级配置。你在某个仓库目录里执行不带--global的git config,改的就是这个仓库的配置,存在仓库的.git/config文件里。仓库级配置优先级高于全局配置,这个机制在需要给某个项目单独设邮箱时很有用。
注意:如果你在公司电脑上配了个人邮箱,提交到公司仓库时作者信息就是个人的,有些公司对此有规范要求。反过来也一样。所以换项目时留意一下当前生效的是哪套配置,用
git config user.email可以查看当前仓库实际生效的值。
3. 仓库、提交、历史:Git 的日常三件事
3.1 仓库到底是什么,本地仓库和远程仓库的关系
仓库这个词听着唬人,其实就是一个被 Git 管理的文件夹。你在一个文件夹里执行git init,这个文件夹就变成了一个 Git 仓库,Git 会在里面建一个隐藏的.git目录,所有版本信息都存在这里。
这里要分清两个概念:本地仓库和远程仓库。本地仓库就是你电脑上这个文件夹,你所有的提交操作默认都是先提交到本地。远程仓库是放在服务器上的仓库,比如公司内网的 GitLab、或者公网的代码托管平台。本地和远程之间通过"推送"和"拉取"来同步。
为什么要分本地和远程?因为这样你可以在没网的时候照样提交,等有网了再一次性推上去。这个设计对经常在飞机上、地铁里干活的人特别友好。而且本地提交速度快,不依赖网络,体验比每次保存都往服务器传要好得多。
一个容易混淆的点:git init建的仓库和从远程"克隆"下来的仓库,本质上是一样的,区别只是克隆下来的仓库已经跟远程建立了关联,而 init 建的仓库需要你手动关联远程地址。
3.2 提交的完整流程:工作区、暂存区、版本库
这是 Git 最核心也最容易让新手懵的地方。Git 把文件的状态分成三个区域,我一个个说。
工作区就是你眼睛能看到的文件夹,你在这里改文件。暂存区是一个中间地带,你改完的文件要先"放"到这里。版本库就是.git目录,提交之后内容才真正存进版本库。
为什么要有暂存区这个中间层?直接提交不行吗?可以,但暂存区给了你一个"挑选"的机会。比如你今天改了三个文件,其中两个是修 bug,一个是顺手改的格式。你可以只把修 bug 的两个文件放进暂存区提交,格式改动单独再提交一次。这样每次提交都对应一件完整的事,历史记录清晰,将来回退也精准。
完整流程是这样的:
git status # 看当前有哪些改动 git add 文件名 # 把指定文件放进暂存区 git add . # 把所有改动放进暂存区 git commit -m "说明" # 把暂存区的内容提交到版本库git status是你最该养成的习惯,改完东西先看一眼状态,它会用红字标出没暂存的改动,绿字标出已暂存的改动。新手经常犯的错是git add完忘了commit,以为已经保存了,其实只是放进了暂存区。
3.3 提交信息怎么写才算合格
-m后面那句话不是随便写的,它是给未来的你看的。我见过太多提交信息写"修改""更新""fix"的,过一个月自己都不知道改了啥。
我的写法习惯是:第一行用一句话说清楚这次提交干了什么,控制在 50 字以内;如果一句话说不完,空一行再写详细说明。比如:
修复登录页在 Safari 下按钮错位的问题 原因是 flex 布局在旧版 Safari 下需要加 -webkit- 前缀, 给按钮容器补上后测试通过。这样写的好处是,git log一眼扫过去能看懂每次提交的主题,需要细节时再看正文。团队协作时,别人 review 你的代码也能快速理解你的意图。
还有一个实用技巧:提交信息里可以写"关联的工单号",比如修复登录超时问题 #1234,很多平台会自动把提交和工单关联起来,追溯起来非常方便。
3.4 查看历史:log 的几种常用姿势
git log是查看提交历史的命令,但默认输出信息量太大,新手容易看花眼。我推荐几个常用参数。
git log --oneline # 每个提交压成一行,最常用 git log --oneline --graph # 加上分支合并的图形化展示 git log -5 # 只看最近 5 条 git log --author="名字" # 只看某人的提交 git log 文件名 # 只看某个文件的改动历史--oneline是我用得最多的,输出像这样:
a1b2c3d 修复登录页按钮错位 e4f5g6h 新增用户头像上传功能 i7j8k9l 初始化项目前面那串字符是提交的"身份证号",叫 commit hash,后面回退的时候要用到。--graph在分支多的时候特别有用,它用字符画出分支的分叉和合并,一眼就能看出项目是怎么演进的。
提示:如果
git log输出太长卡在了一个冒号提示符那里,按q就能退出。这是分页器在起作用,不是卡死了,新手经常在这里慌。
4. 分支:Git 最值钱的功能,也是最容易用错的功能
4.1 分支的本质:一个可以移动的指针
很多人觉得分支很神秘,其实它的本质简单到离谱:分支就是一个指向某次提交的指针。你建一个分支,就是新建一个指针指向当前提交;你在分支上提交,指针就往前移动一格。
理解这一点,很多操作就顺了。比如"切换分支"其实就是把 HEAD(当前所在位置的标记)指向另一个指针;"合并分支"就是把两个指针指向的历史合到一起。
为什么这个设计厉害?因为它意味着建分支的成本极低。在 Git 里建一个分支几乎是瞬间完成的,不复制任何文件,只是写一个 41 字节的指针。所以 Git 鼓励你"多开分支",想试什么新东西就开一个,试完不满意直接删,主线完全不受影响。
对比一下老式的版本控制工具,建分支要复制整个项目目录,慢且占空间,所以那时候大家都不敢随便开分支。Git 把这个成本降到接近零,工作方式就彻底变了。
4.2 分支的日常操作:建、切、看、删
常用命令就这几个:
git branch # 列出所有本地分支,当前分支前面有星号 git branch 新分支名 # 基于当前提交建一个新分支 git checkout 分支名 # 切换到指定分支 git checkout -b 新分支名 # 建一个新分支并立刻切过去,最常用 git branch -d 分支名 # 删除已合并的分支 git branch -D 分支名 # 强制删除未合并的分支git checkout -b这个组合命令是我用得最多的,建分支和切换一步到位。新版本 Git 还提供了git switch命令专门用来切分支,语义更清晰:
git switch 分支名 git switch -c 新分支名checkout和switch功能上有重叠,switch是后来加的,专门管分支切换,避免checkout一个命令干太多事造成混淆。你用哪个都行,团队里统一就好。
删除分支时要注意,-d只能删已经合并的分支,如果分支上有没合并的提交,Git 会拦着你不让删,这是保护机制。确实想删就用-D,但删之前想清楚,那些提交可能就找不回来了(其实还能通过 reflog 找回,但那是进阶话题)。
4.3 分支命名和分支策略的实战建议
分支名怎么起,团队最好有个约定。我见过比较清晰的几种命名方式:
- 功能分支:
feature/用户登录或feature/login - 修复分支:
fix/登录超时或bugfix/login-timeout - 发布分支:
release/1.2.0 - 紧急修复:
hotfix/支付崩溃
用斜杠分层的好处是,git branch列出来时同类分支会排在一起,一目了然。纯中文分支名技术上没问题,但有些平台或工具对中文支持不好,我一般建议用英文加短横线。
分支策略上,小团队最简单的是"主干开发加功能分支":main分支始终保持可发布状态,任何人做新功能都从main切一个功能分支出去,做完合并回来。大一点的团队可能会用develop作为集成分支,main只放正式发布版本,功能分支先合到develop,测试通过再合到main。
注意:不管用哪种策略,有一条铁律——不要在 main 分支上直接改代码。main 是大家的公共财产,直接在上面改容易把别人的工作搞乱。养成"干活先切分支"的习惯,能避免 90% 的协作事故。
4.4 合并分支的两种方式:merge 和 rebase
把分支合回来有两种方式,这是新手最容易搞混的地方,我重点讲。
merge的做法是:把两个分支的历史合到一起,如果两边都有新提交,Git 会自动生成一个"合并提交"来记录这次合并。历史会呈现分叉再汇合的形状。
rebase的做法是:把你分支上的提交一个个"摘"下来,重新"接"到目标分支的最新提交后面。历史会变成一条直线,看起来像你一直在目标分支上顺序开发一样。
用哪个?我的经验是:
| 场景 | 推荐方式 | 原因 |
|---|---|---|
| 功能分支合并回主干 | merge | 保留分支存在的痕迹,历史真实 |
| 本地分支同步主干最新代码 | rebase | 让本地历史保持整洁,避免无意义的合并提交 |
| 已经推送到远程的公共分支 | 绝对不要 rebase | 会改写历史,导致别人拉取时冲突 |
| 个人本地整理提交 | rebase | 可以合并琐碎提交,让历史更清晰 |
rebase 有个大坑:它会改写提交的 hash。如果你 rebase 了一个已经推送到远程、别人也在用的分支,别人再拉取时历史就对不上了,会引发一堆冲突。所以记住一句话:只 rebase 自己本地、还没推送的提交。
5. 远程协作:从单机玩家到团队作战
5.1 关联远程仓库和第一次推送
本地仓库建好后,要跟远程仓库建立联系,命令是:
git remote add origin 远程仓库地址 git remote -v # 查看已关联的远程 git push -u origin main # 第一次推送,-u 记住关联关系origin是远程仓库的默认别名,你可以改成别的名字,但大家都用 origin,没必要标新立异。-u参数的作用是把本地 main 分支和远程 main 分支关联起来,之后你在这个分支上直接敲git push和git pull就行,不用再指定远程和分支名。
远程仓库地址有两种协议:HTTPS 和 SSH。HTTPS 用起来简单,但每次推送要输账号密码(现在多数平台用令牌代替密码)。SSH 需要先配置密钥,配好之后免密推送,一劳永逸。团队内部一般推荐 SSH,配置一次省心很久。
5.2 拉取、推送、冲突:协作的日常循环
团队协作的日常循环基本是这样的:
git pull # 先把远程最新代码拉下来 # 干活,改文件 git add . git commit -m "说明" git push # 推上去看起来简单,但git pull这一步经常出问题。git pull实际上是两个动作的合体:先git fetch把远程最新内容下载到本地,再git merge合并到你当前分支。如果远程和本地都改了同一个文件的同一部分,合并时就会冲突。
冲突长什么样?Git 会在文件里插入这样的标记:
<<<<<<< HEAD 你本地的内容 ======= 远程的内容 >>>>>>> 远程分支你需要手动决定保留哪部分,把标记删掉,改成最终想要的样子,然后git add这个文件,再git commit完成合并。这个过程第一次遇到会慌,其实就是在问你"这两段你想留哪个",你手动编辑成想要的结果就行。
提示:解决冲突时不要怕,Git 不会自动帮你选,它把决定权交给你。改完之后一定要跑一遍测试,确认合并结果是对的,因为冲突解决错了很容易引入 bug。
5.3 减少冲突的实操习惯
冲突虽然能解决,但解决起来费时费力,最好的办法是少产生冲突。我总结几个习惯:
第一,勤拉取。每天开工前先git pull,别等攒了一周才拉,那时候冲突会多到你想哭。
第二,小步提交、小步推送。一个功能拆成几次提交,做完一小块就推一次,别憋一个大招。改动越小,跟别人冲突的概率越低。
第三,别动别人的文件。如果你发现要改的文件别人也在改,先沟通一下,看能不能分工或者错开时间。
第四,功能分支生命周期要短。一个功能分支从建到合并最好控制在几天内,拖得越久,跟主干偏离越大,合并时冲突越多。
第五,合并前先同步主干。在功能分支上先git merge main或者git rebase main,把主干最新改动合进来,在本地解决完冲突再推,这样主干上的合并就干净了。
5.4 代码评审和合并请求的基本流程
团队协作里,功能分支做完不是直接合到主干,而是先发一个"合并请求"(不同平台叫法不同,有的叫 Pull Request,有的叫 Merge Request),让同事 review 一下。
这个流程的价值在于:多一双眼睛看代码,能提前发现 bug、风格问题、安全隐患。review 的人可以在具体某一行上留评论,作者根据评论修改,改完再推,评论会自动关联到新的提交上。
作为作者,发合并请求时写清楚这几件事:这个改动解决了什么问题、怎么实现的、测试情况如何、有没有需要特别注意的地方。作为 reviewer,重点看逻辑对不对、边界情况处理了没、有没有明显的性能问题、命名和风格是否符合团队规范。
这个流程刚开始会觉得麻烦,但它是团队代码质量的重要保障。我待过的团队里,坚持做 review 的,线上事故明显少。
6. 新手最容易踩的坑和救命命令
6.1 提交错了、提交多了、提交漏了怎么办
提交信息写错了,用:
git commit --amend -m "新的提交信息"这个命令会修改最近一次提交的信息。如果只是想补充几个文件到最近一次提交里,先git add那些文件,再git commit --amend --no-edit,--no-edit表示不改提交信息。
提交漏了文件,同样用git add加上git commit --amend --no-edit。
想撤销最近一次提交但保留改动,用:
git reset --soft HEAD~1这会把最近一次提交撤掉,但改动还在暂存区,你可以重新组织再提交。如果把--soft换成--mixed(默认),改动会回到工作区但不在暂存区;换成--hard,改动直接丢弃,这个要慎用。
注意:
--amend和reset都会改写历史,如果那次提交已经推送到远程,改完再推需要强制推送,而强制推送会影响别人。所以这些操作尽量在推送之前做。
6.2 改崩了想回到某个历史版本
如果只是想让某个文件回到历史版本,用:
git checkout 提交号 -- 文件名如果想让整个项目回到某个历史提交的状态,用:
git reset --hard 提交号但--hard会丢弃之后的所有改动,用之前想清楚。更安全的做法是新建一个分支指向那个历史提交,先看看再说:
git checkout -b 临时分支 提交号这样你可以在临时分支上检查历史状态,确认没问题再决定怎么处理,主线不受影响。
还有一个救命命令是git reflog,它记录了 HEAD 的所有移动历史,包括那些你以为已经丢失的提交。如果你不小心reset --hard删掉了东西,用git reflog找到那个提交号,再git reset --hard 提交号就能找回来。这个命令救过我好几次,强烈建议记住。
6.3 那些让人一脸懵的报错和应对
新手最常遇到的几个报错,我列出来:
"Your local changes would be overwritten by merge":你想切换分支或拉取,但本地有未提交的改动会冲突。解决办法是先提交或暂存(git stash)本地改动,再操作。
"fatal: refusing to merge unrelated histories":两个仓库的历史没有共同祖先,常见于把两个独立初始化的仓库合并。加--allow-unrelated-histories参数可以强制合并,但要想清楚是不是真的需要。
"Permission denied (publickey)":SSH 密钥没配好或者没加到平台账号里。检查密钥是否生成、是否添加到平台的 SSH 设置里。
"Updates were rejected because the remote contains work that you do not have":远程有你本地没有的提交,直接推会被拒。先git pull把远程内容拉下来合并,再推。
"detached HEAD":你 checkout 到了一个具体的提交号而不是分支名,处于"游离"状态。这时候的提交不属于任何分支,容易丢。想保留就git switch -c 新分支名建个分支接住。
6.4 暂存和忽略:两个提升效率的小工具
git stash用来临时保存未提交的改动,让你能干净地切换分支。比如你改到一半突然要去修个紧急 bug,又不想把半成品提交,就可以:
git stash # 把当前改动存起来 # 切分支修 bug git stash pop # 回来把改动恢复出来.gitignore文件用来告诉 Git 哪些文件不要管,比如编译产物、日志、本地配置、依赖目录。这个文件很重要,如果不配,你会把一堆没用的文件提交进去,仓库越来越臃肿。常见的忽略内容:
node_modules/ *.log .env dist/ .idea/提示:
.gitignore只对还没被跟踪的文件生效。如果一个文件已经被提交过,再加到.gitignore里是不起作用的,需要先用git rm --cached 文件名把它从跟踪列表里移除。
7. 从"会用"到"用顺"的几个进阶习惯
7.1 图形化工具和命令行的取舍
命令行是 Git 的原生形态,功能最全,但有些操作确实不如图形界面直观,比如看分支图、逐行暂存、解决复杂冲突。我的建议是:日常提交、拉取、推送用命令行,看历史和解决冲突可以借助图形工具。
常见的图形工具有 Git 自带的gitk、跨平台的 Sourcetree、以及各种编辑器内置的 Git 面板。编辑器内置的 Git 功能现在做得很好,改动的文件、逐行 diff、暂存、提交都能在编辑器里完成,不用来回切窗口。
但我不建议新手一上来就全靠图形工具,因为图形工具会隐藏很多细节,出了问题你不知道底层发生了什么。先用命令行把基本概念和流程走通,再用图形工具提效,这个顺序比较合理。
7.2 提交粒度:为什么"一次提交只做一件事"
这个习惯我反复强调,因为它对历史可读性影响巨大。一次提交只做一件事,意味着:修 bug 的提交里不要夹带格式调整,加功能的提交里不要顺手重构无关代码。
好处有三个。第一,回退精准,某个提交出问题,直接 revert 那一个就行,不会误伤别的改动。第二,review 容易,reviewer 一眼能看懂这次提交的意图。第三,排查问题快,用git log和git blame定位问题时,每个提交的边界清晰。
怎么做到?靠暂存区。改完一堆东西后,用git add只挑相关的文件或代码块放进暂存区,分多次提交。编辑器里通常支持"逐块暂存",可以把一个文件里的不同改动分开提交,非常实用。
7.3 标签:给重要版本打个记号
标签(tag)用来给某个提交起一个固定的名字,通常用于标记发布版本。比如:
git tag v1.0.0 git tag -a v1.0.0 -m "第一个正式版本" # 带说明的标签 git push origin v1.0.0 # 推送标签到远程标签和分支的区别是:分支会移动,标签不会。你给 v1.0.0 打了标签,它就永远指向那个提交,不管后面分支怎么走。发布版本、里程碑节点用标签标记,将来想找回某个版本直接 checkout 标签就行,比记提交号方便得多。
7.4 保持仓库健康的日常维护
仓库用久了会有些小问题,定期做几件事能保持健康。
git gc会清理仓库里的垃圾对象,压缩存储,仓库大的时候能明显减小体积。一般不用手动跑,Git 会自动触发,但仓库特别大时可以手动执行一次。
git fsck用来检查仓库完整性,偶尔跑一下能提前发现损坏的对象。
定期清理已经合并的本地分支,用git branch --merged列出已合并的分支,确认后批量删除。远程分支也可以清理,git remote prune origin会删掉远程已经不存在但本地还留着的分支引用。
还有一点,别把大文件提交进仓库。二进制文件、视频、数据集这类东西一旦提交,会永久留在历史里,仓库体积会爆炸。这类文件应该用专门的大文件存储方案,或者干脆放在仓库外面。
8. 我这些年用 Git 攒下的实在经验
8.1 关于学习路径的一点真心话
Git 的命令很多,但真正常用的就那么十几个。新手不要试图把所有命令背下来,那样既痛苦又记不住。正确的做法是:先把"提交、拉取、推送、分支、合并"这五个动作练熟,能独立完成一个完整的协作循环,然后再按需学其他命令。
遇到问题先查git status和git log,这两个命令能告诉你当前处于什么状态、历史发生了什么,大部分困惑看一眼就清楚了。实在搞不定,git reflog是最后的救命稻草,它记录了一切。
我见过太多人因为怕把仓库搞坏而不敢操作,结果一直停留在"只会提交"的阶段。其实 Git 的容错性比想象中强,只要提交过的东西,基本都能找回来。大胆用,出问题再查,这是学 Git 最快的方式。
8.2 团队协作里那些不成文的规矩
技术之外,团队协作有些软性的规矩,我分享几条。
提交信息用团队统一的语言和格式,别一个人写中文一个人写英文,混在一起看着乱。分支命名也统一,别有人用feature/xxx有人用dev-xxx。
合并别人的分支前先看一眼对方的改动,别闭着眼睛合。合并请求里该写的说明写清楚,别让 reviewer 猜你的意图。
遇到冲突拿不准怎么解决,找改动那部分代码的同事一起看,别自己瞎猜着合。合错了引入的 bug 往往很隐蔽,排查起来更费劲。
还有,别在公共分支上强制推送。强制推送会改写历史,别人本地的记录就跟远程对不上了,轻则冲突,重则丢代码。这个规矩在团队里基本是红线。
8.3 遇到搞不定的情况,先备份再折腾
最后分享一个保命习惯:在尝试不确定的操作之前,先给当前状态留个后路。
最简单的做法是建一个临时分支指向当前提交:
git branch backup-20240101这样不管后面怎么折腾,你都能通过git checkout backup-20240101回到折腾前的状态。等确认新操作没问题了,再把这个临时分支删掉。
这个习惯看起来多余,但真到了关键时刻能救命。我有一次在整理历史时手滑,差点丢掉一整天的提交,就是靠之前随手建的备份分支找回来的。花几秒钟建个备份,换的是折腾时的底气,这笔账怎么算都划算。
Git 这东西,说到底就是个工具,它的价值在于让你敢改、能退、好协作。把上面这些走一遍,你就能从"怕用 Git"变成"离不开 Git"。剩下的就是在实际项目里多用,用着用着就顺了。