1. 哪些文件该交给Git管,哪些不该
聊Git具体操作之前,先把一个认知问题掰扯清楚:Git不是用来管“所有文件”的,它只负责管那些“需要追踪变更”的文件。很多人刚入坑时习惯git add .一把梭,结果把依赖、密钥、构建产物全提进仓库,之后每次拉取都痛不欲生。
按我自己的经验,适合交给Git管理的文件大致分三类:
- 源代码文件:
.py、.js、.java、.go、.vue、.c这一类,Git最基本的职责就是追踪它们的每一次增删改。 - 配置类模板:比如
.env.example、nginx.conf.example、docker-compose.yml,注意是模板而不是真实配置。真实配置往往带密钥和机器专属路径,不应该进版本库。 - 文档与脚本:
README.md、docs/目录、部署脚本.sh、数据迁移脚本等,这些为团队沉淀知识,配合Git的diff能力再好不过。
反过来,下面这几种文件我强烈建议你挡在Git门外:
node_modules/、vendor/、target/、dist/这类依赖和构建产物,它们可以被锁文件或构建脚本一键生成;.env、config/local.yml、*.pem、*.key这类带敏感信息的文件,一旦提交就可能造成凭据泄露;- 本地IDE配置里属于个人习惯的部分,比如
.idea/workspace.xml、.vscode/下某些只对你生效的配置; - 日志文件与大体积资源,
*.log、超过几十MB的二进制包,这些命中Git无法高效处理的痛点。
一句话总结:Git管理的是“源”和“模板”,而不是“结果”和“秘密”。先把这两类分清楚,后面的所有命令才用得安心。
2. 零基础到跑通第一笔提交:完整动手流程
还没装Git的话,先去官网下载对应系统的安装包。安装过程基本不用改选项,只有一步注意一下:安装Git Bash时保留默认勾选即可,这是Windows下非常好用的命令行环境,后续所有操作都用它,避开CMD的坑。装完在终端敲:
git --version能输出版本号就说明装好了。要是连版本都输不出来,大概率是环境变量没配上,走系统环境变量把Git的cmd目录加进去就行。
2.1 先配置身份:不配用户名和邮箱没法提交
第一次用Git的人往往会卡在这样一个报错上:
Please tell me who you are.这是因为Git在提交记录里要写着作者是谁。给机器和人一样,代码仓库也要知道“谁在干活”。配置方式:
git config --global user.name "你的昵称" git config --global user.email "你@example.com"--global表示全局生效,作用于这台机器上所有仓库。如果某个项目想用另一个身份,只要在仓库目录里去掉--global重新配一次即可,作用域更小的配置会覆盖全局配置。
2.2 从零建仓库:让Git开始观察这个文件夹
mkdir my-project cd my-project git init执行完git init后,文件夹里会出现一个隐藏的.git目录,Git从这个瞬间开始跟踪所有被add过的文件的变动。此时库里还没有任何提交记录。
接着创建几个文件并建立首个提交:
echo "# 我的第一个项目" > README.md git add README.md git commit -m "初始化项目,添加README"git add先文件加入暂存区,git commit再生成一条不可变的快照记录。这个顺序就是Git最核心的工作流:修改 -> 暂存 -> 提交。
2.3 修改文件并看差异:Git到底在帮你记录什么
继续加一个.gitignore文件,放上丢给Git忽略的东西:
node_modules/ dist/ *.log .env保存后,用git status能看到它是未跟踪状态,之后执行git add .gitignore再git commit -m "添加忽略规则"完成提交。
此时再把README改一行:
echo "更详细的说明" >> README.md git diffgit diff输出的是工作区相对暂存区的差异。看完几处改动你觉得没问题,还是老一套:git add再git commit。这就是正常工作状态下的循环,真正把这个循环养成肌肉记忆,后续的高级操作自然就顺了。
3. 版本回退的保命操作:后悔药这样吃
写代码不可能不犯错,版本回退就是干这个用的。它解决的问题是:做了一堆改动后发现全错了,或者在分叉的某次提交里留下了Bug,我想跳回到之前某个稳定状态。
3.1 先用 log 看清历史
任何回退操作之前,先搞清楚自己在哪里、有哪些历史提交:
git log --oneline --graph --all--oneline让每次提交只显示一行,--graph用字符画出分支图,--all把远程和本地分支的历史都展示出来。执行后你会看到类似这样的信息:
* 3b5f1c9 (HEAD -> main) 修复登录态问题 * 9e7a2d1 完成用户模块模板 * 4d1c0aa 初始化项目这里每一行开头那一串字母数字就是commit哈希,它是这次提交的身份证号。想回退到4d1c0aa,那这就是你的目标点。
3.2 reset 的三个档位
git reset按影响范围分成三档,别用错:
第一档:--soft,只移动HEAD指针,工作区与暂存区都不动,改完之后所有差异全部停留在暂存区。
git reset --soft 4d1c0aa执行完git status一看,后面两次提交的改动全在绿色暂存区里等着。这个档位的用途是合并提交记录:连续提交了好几次发现“这几笔可以合成一笔”,回退后重新git commit即可。
第二档:--mixed(默认行为),移动HEAD并清空暂存区,但工作区文件内容保持不变。
git reset 4d1c0aa此时后面提交的改动会以“未暂存”状态出现在工作区,需要重新git add再提交。
第三档:--hard,全量回退,工作区文件内容也一起变回目标提交。
git reset --hard 4d1c0aa这一档最省心也最危险,连同工作区里的修改一并丢弃。执行前确认没有留下任何有价值的未提交内容。
3.3 回退错了也有后悔药
被reset抹掉的提交不会彻底消失。Git的引用日志reflog会记录HEAD的每一次移动,哪怕那次移动把提交“删掉了”。
git reflog输出里能看到每次HEAD、分支等引用的变动历史,包括被reset丢弃的那个提交哈希。想找回时直接:
git reset --hard 这个哈希值所以秘诀是:对当前仓库状态不确定、怕搞坏的时候,先看一眼git reflog,再决定要不要下手。我自己的习惯是每次reset --hard之前都会先记下当前哈希,给自己留个“再反悔一次”的机会。
3.4 reset 和 revert 到底该用哪个
reset会改写历史,适合在代码还没推送到远端时使用;一旦提交已经被其他人拉取或者被推送到公共分支,再用reset就相当于对别人说“我改写了历史,请重新同步”,很容易引发混乱。
这种情况的正解是revert:它不动原提交,而是生成一种“反向提交”把改动抵消掉。
git revert 3b5f1c9执行后会新增一条提交,内容是把3b5f1c9本次提交引入的差异全部撤销。这也意味着历史里能保留那条原始提交,溯源性更好。所以判断标准很简单:本地未推送用reset,公共分支用revert。
4. 撤销各种状态的修改:从工作区到暂存区到远端
撤销修改最常见的场景我分了四类,每一类有不同的套路,选择错误会导致改动没能按预期恢复。
场景一:工作区改坏了但还没add
比如我把README.md改成乱码,又不想保留。这时候直接:
git restore README.md这个命令会用暂存区或HEAD里的内容覆盖工作区。它只会动这个指定文件,其他文件不会受到牵连;执行后那些未暂存的改动就消失了。
场景二:已经add进暂存区,想反悔
git restore --staged README.md--staged参数表示把暂存区的添加动作取消,让文件回到未暂存状态。注意这里只是取消暂存,文件内容改动依然保留在工作区里。
场景三:提交记录里面出了错,想改掉但又不想新增一条提交
这种情况用commit --amend。假设我提交信息写错了,可以:
git commit --amend -m "修正后的提交信息"或者忘记加某个文件,也可以重新add之后再amend,把新改动并入上一个提交。务必注意,它实际上是在替换最后一次提交,如果这个“最后一次提交”已经被推送到公共分支,请改用上面讲过的revert。
场景四:错误提交已经推送到远端
这个没有“一键撤回”,最稳妥的路线是组合拳:
git revert 出问题的哈希 git push origin main先用revert制作反向提交,再推送这个反向提交到远端。这条新旧提交并存的方案是全团队都能接受的回退方式,其他人同步时不会遇到历史被改写的冲突。
这四类场景分别对应同一套底层逻辑:修改到底停留在哪一层,就从哪一层下手恢复。区分清楚工作区、暂存区、本地仓库、远程仓库这四个概念,绕开80%的撤销事故。
5. 删除文件:从版本库中出局的正确方法
删除是版本管理里最容易被误解的动作。很多人直接用系统删除工具或者rm删文件,以为自己已经“删除干净了”,结果一看git status发现Git还在那跟踪着它。
5.1 用 git rm 而非系统 rm
命令行环境里,正确做法:
git rm README.md这句命令等价于先系统删除文件,再执行git add把删除动作放入暂存区。这样一次操作就把“删除”这个事实告诉了Git,再git commit -m "删除README.md"即可让改动正式生效。
想删除一整个目录:
git rm -r docs/-r表示递归删除docs目录下的所有文件。
5.2 误删之后怎么找回
分了两种误删:
已提交的场景,用restore恢复:
git restore README.md因为Git仓库中还有这个文件的提交历史,restore会从HEAD把它重新捡回工作区。
未提交的场景,需要查看版本库内是否留有这个文件的提交,如果从未提交过且未跟踪,那么删除后就无法找回了。所以日常写代码时,任何有价值的文件创建后都应尽快进入版本库。
5.3 只想让文件不再被跟踪,但保留本地
这种情况常见于使用.env之前,文件已经提交进了仓库,之后想改成“不入库”的状态。方法:
git rm --cached .env--cached意思是只把文件从暂存区(也就是版本跟踪范围)里移除,本地磁盘文件不动。执行后记得把这个文件名加入.gitignore,避免再次误add。然后提交这条删除,远程仓库里的对应文件也会消失。
5.4 清理凭据文件时务必确认两遍
我因为在演示项目里提交过真实密钥文件吃了不少亏,现在养成的习惯是删除任何含密钥、cookie、私有token的文件之前,都先git log --all --oneline -- 文件名查一遍该文件是否曾出现在历史提交中。如果出现过,单纯删除当前版本即可,但历史提交里仍然保留着旧内容,此时需要配合git filter-repo或改写历史来彻底清理。
这一步跟删除文件本身是两个层级的问题:版本库里的内容一旦提交过,就永久存在于历史中,删除只影响后续记录,不影响过去。涉及真实生产密钥的场景,需要一个不漏地把历史一并清理干净。
6. 一个仓库的完整日常操作刷卡轮回
把前面各节的操作串成一个完整的日常循环,这就是每个接触Git的人每天都要走的流程。
早上到岗后先拉取最新代码:
git pull origin main注意origin是Github/Gitee等远端仓库的默认别名,main是需要同步的分支名。拉完自己新建功能分支去开发:
git checkout -b feature-login这条命令创建一个新分支并切换过去。在这个分支上做若干次修改,中间多次走edit → git add → git commit小循环。全部完成并测试后,合并回主分支:
git checkout main git merge feature-login如果合出冲突,git status会标出冲突文件,手动处理后重新git add再git commit即可。最后推送:
git push origin main这套动作熟练之后,可以在1分钟内完成“拉取-开发-提交-推送”的全部环节。最大的好处是每次改动都有迹可查:哪个提交改了什么,什么时候改的,为什么这么改,全都有信息可追诉。
很多初学者在折腾merge后,误以为分支是一种很复杂的架构;其实分支只是一条提交时间线上的游标工具。理解了这一点,常用的git checkout、git merge、git rebase这些操作就不再像黑魔法,而是一次干净的普通切换。
7. 配置远程仓库并学会推送代码
自己本地练熟了之后,很快就遇到“想让代码备份到云端”或者“和同事协作”的需求。这就要用到远程仓库。
第一步,在代码托管平台建一个空的远端仓库,通常选择“创建新仓库(New Repository)”。创建时不要勾选生成README,避免与本地仓库历史产生分叉。
第二步,本地关联远端:
git remote add origin git@gitee.com:你的用户名/my-project.git这里的地址是SSH形式,更常见的还有HTTPS形式,例如:
git remote add origin https://github.com/你的用户名/my-project.gitSSH需要先在本地生成并配置公钥,好处是以后推送免输密码;HTTPS在启用了Personal Access Token之后同样可以比较顺滑地推送。个人经验是SSH更省事,一次配好长期受益。
第三步,推送本地内容:
git push -u origin main-u的作用是把本地main分支和远端main分支建立跟踪关系,之后直接git push、git pull就能配对到这条分支,不用每次重复写远端地址。
以后每次写完代码就是两句话:
git add . git commit -m "写出提交说明" git push在我看来,git push 就是这个工具链里的出口管道,前端的暂存和提交都是为这个出口服务的。只要日常习惯保持了一小步一小步地提交,推送时基本不会出大问题。
8. 新手最常踩的坑:commit消息混乱,分支纠缠不清
严格来说这一节不是命令教程,而是我对几年git实操教训的总结。不少人在前面部分学得挺顺利,一到真实项目里却手忙脚乱,问题往往不在技术,而在习惯。
第一坑:提交写得像流水账,例如“更新”“修改”“改bug”。几次提交之后自己都看不懂之前做了什么。尽量遵循一句话前缀加内容说明的习惯:fix(登录): 修复token过期后未跳转的问题、feat(商品): 新增库存预警字段。格式没有统一标准,但至少让别人和自己一眼就懂。
第二坑:把大量无关改动打包成一次commit。这在代码评审时几乎没法review,回退时也很痛苦。尽量让每次提交保持“单一目的”,这样一条提交只对应一个问题或一个功能点。
第三坑:合并分支时不清楚当前HEAD在哪。执行git merge之前先git status确认所在分支,不然可能把别人的分支合并到自己还没有准备好的位置上。
第四坑:使用git commit --amend时大家共同使用的分支上操作。多人协作分支上改历史提交,几乎必然导致其他人拉取时冲突;后端应只对自己的本地分支使用amend。
第五坑:git reset --hard前备份手感。我在真实项目里见过有人在未提交状态下直接reset导致一天工作消失。再强调一次:先git stash或复制文件到临时目录再操作。
第六坑:为图省事想.all in,把不该入库的内容(.env、密钥、构建产物)全推上去。前面第1节已经强调过分类原则,实际执行时就靠 .gitignore 和白名单。
这套操作在你日常写代码时用到的频次远比想象中高:每次写代码前习惯性看git status,写完一处就提交一个原子commit,保持仓库历史的清爽度,等回头找bug、做回退时会感谢自己。
这一套流程走通,你就不再是只会点IDE按钮的Git用户了。