Git 这东西,说难不难,说简单也不简单。我见过太多人一开始“不就是存个代码嘛”,结果分支一多、冲突一撞、历史一乱,直接满头大汗。也有人把 git 当网盘用,每天 add . 加 commit 加 push 三连,哪天不小心 reset 错了,恨不得穿越回去。这篇内容我准备从安装配置讲到日常提交流程,再聊到 commit --amend 这种历史改写技巧和 Gitee 密钥配置,最后把常见的坑和排查思路一次讲透。不管你是刚接触 git 的新手,还是用了几年但在团队协作里偶尔犯迷糊的老兵,都能从中拿到点能直接落地的操作。
1. 安装与初始配置:把地基打牢
1.1 不同平台的安装方式
安装 git 本身没什么技术含量,但不同平台踩的坑完全不一样。
Windows 上推荐直接去官网下载安装包,一路 Next 就能装完。唯一要留意的是安装过程中那个“Adjusting your PATH environment”选项,默认的 “Git from the command line and also from 3rd-party software” 是最省心的,选这个就行。如果选了 “Use Git from Git Bash only”,后面在 PowerShell 或 CMD 里敲 git 命令大概率会提示“无法识别”,到时候还得手动改环境变量,纯属给自己找事。
macOS 上如果你装了 Homebrew,一条 brew install git 就能搞定。没装 Homebrew 的话,直接 xcode-select --install 也可以,它会顺带把 git 装好。不过我实测下来 Homebrew 装的版本通常比 Xcode Command Line Tools 自带的版本新一些,功能上也更完整。
Linux 用户最简单,Debian/Ubuntu 用 apt install git,CentOS/RHEL 用 yum install git。装完记得敲一下 git --version 确认版本号,顺便检查是否装进了 PATH。
1.2 全局配置与三区概念
装好之后第一步不是急着建仓库,而是配置身份信息:
bash复制git config --global user.name "你的名字"
git config --global user.email "你的邮箱"
这一步不做的后果是,commit 记录里会显示一个系统自动生成的身份,比如 user@DESKTOP-XXXX,在团队协作里根本认不出是谁提交的。更麻烦的是,Gitee、GitHub 这类平台通过邮箱关联账号,邮箱不对,提交记录就无法点亮贡献图。
关于全局配置,还有一个容易被忽略的换行符问题。Windows 和 Linux/macOS 的换行符不一样,如果不做处理,跨平台协作时 diff 会变得极其难看。常见的做法是:
bash复制# Windows 用户
git config --global core.autocrlf true
# macOS / Linux 用户
git config --global core.autocrlf input
然后需要理解 git 的三区模型:工作区、暂存区、本地仓库。很多新手对 add 和 commit 的关系搞不清楚,简单说,工作区就是你的项目目录,暂存区是“准备打包但还没封箱”的区域,本地仓库是真正存储历史版本的地方。每一次 commit 都是在本地仓库里新建一个永久快照,而 add 只是在告诉 git“这次打包要包含哪些文件”。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 日常操作主链路:从工作区到远程仓库
2.1 初始化仓库与首次提交
拿到一个新项目,第一件事是 git init。这条命令会在当前目录下生成一个 .git 文件夹,里面装着整个版本的元数据。做完这一步,你就可以开始第一次提交了:
bash复制git add .
git commit -m "Initial commit"
有些新手会问,为什么要先 add 再 commit,不能一步到位吗?因为 add 给了你选择权——你可以在一次提交里包含所有改动,也可以只挑某个文件提交。比如这轮改了两个 bug,但其中一个还没测完,你可以只把另一个文件加入暂存区,提交信息写清楚,历史记录就会非常干净。
这里有个经验技巧:提交信息要写得让人看得懂。"fix bug" 这种信息等于没写,"fix login page crash when username is empty" 才是有效信息。好的提交信息应该能回答两个问题:改了什么,为什么这么改。团队协作时,一份清晰的 commit 历史能省下大量沟通时间。
2.2 从本地推送到远程仓库
远程仓库不是 git 的核心,但没有远程仓库的 git 就像是单机游戏——只能自己存档,没法联机。本地和远程打通的关键命令是:
bash复制git remote add origin https://gitee.com/用户名/仓库名.git
git push -u origin main
-u 参数的作用是建立本地分支和远程分支的关联关系。有了这层关联,之后在同一个分支上直接敲 git push 就能推送,不用每次都写全量参数。
首次推送前要注意分支名。近年来的默认分支名逐渐从 master 改成 main,Gitee 官方新建仓库时默认模板就是 master,两者差别不大,但团队内部最好统一,避免每次都要处理“找不到本地分支与远程分支关联”的提示。
2.3 分支操作:并行开发的基石
分支是 git 最核心的设计之一,也是最容易被无视的设计。我见过有人在一个分支上做完所有功能,理由是“懒得切”,等到提测时才发现没法把某个功能单独摘出来。
标准的分支实践是:main(或 master)作为稳定发布分支,新功能从上面拉出一个 feature/xxx 分支,开发完再合并回来:
bash复制# 创建并切换分支
git checkout -b feature/login
# 开发完成后切回主分支
git checkout main
# 合并功能分支
git merge feature/login
# 删除已合并的分支
git branch -d feature/login
checkout -b 等于 git branch 分支名 + git checkout 分支名 的组合,是日常用得最多的命令之一。合并时如果遇到冲突,git 会直接在文件里标注冲突位置,你需要手动决定保留哪一边的代码,然后再次 add 和 commit。稍后我会专门展开冲突处理。
有些团队推崇 git rebase 替代 merge 来保持历史线性,这个思路没错,但我要强调一句:rebase 永远不要用于公共分支,否则团队其他人的历史会变得一团糟。关于 rebase 的话题可以单独写一篇,初学者先老老实实用 merge 就好。
3. 进阶技巧:改写历史与撤销操作
3.1 commit --amend:让提交历史保持整洁
git commit --amend 是热词里出现频率很高的一个命令,它解决的核心痛点是:提交完了才发现漏了个文件,或者提交信息打错了字。
用法很简单:
bash复制# 漏加了文件,想补进上一条提交
git add 漏掉的文件
git commit --amend --no-edit
# 只想修改提交信息
git commit --amend -m "新的提交信息"
--no-edit 表示沿用原有提交信息,-m 则是直接指定新的提交信息。默认情况下 --amend 会重新打开编辑器,对不熟悉 Vim 的新手来说一进去就卡住,所以给个明确参数可以少踩一个坑。
这里必须强调一个适用边界:amend 只适合尚未推送到远程的本地提交。如果这条 commit 已经被 git push 到远程,别人也拉下来了,你再 amend 就是在破坏公共历史,强行覆盖会导致协作者的提交记录和你对不上,引发各种莫名其妙的分叉和冲突。所以在团队里改公共分支的历史,比改产品需求的破坏性还大。
如果你有几条连续的提交需要合并成一整块,可以用 git rebase -i HEAD~n,在打开的交互界面里把 pick 改成 squash,不过这个命令对新手不太友好,我用顺手的经验是——先把改动整理好再提交,尽量少用 amend 和 rebase 去收拾残局。
3.2 撤销操作:reset、revert 和 restore 的取舍
撤销操作是 git 使用中最容易混淆的部分。git reset、git revert、git restore 三个命令各自负责的场景不同:
git restore --staged <file>:把已add到暂存区的文件移回工作区,相当于撤销 add 操作。git reset --hard HEAD~1:彻底回退上一条提交,工作区、暂存区、本地仓库全部对齐到上一个版本。这个操作会丢掉改动,慎用。git revert <commit>:生成一条新的提交,内容是把指定提交的改动反向应用。好处是不动历史,适合公共分支上的回滚。
reset 和 revert 的区别,用一句话概括:reset 是“回到过去”,revert 是“沿着时间轴往前走,但把过去的某些改动翻案”。在公共分支上误操作,首选 revert,不要用 reset。
如果你已经执行了 reset --hard,又想让被丢弃的提交回来,也别慌。git 的 reflog 会记录所有分支引用的变化历史:
bash复制git reflog
git reset --hard HEAD@{1}
只要那个提交还在 reflog 的存活期(默认 90 天)内,基本都有救。这就是 git 相对传统“复制备份”方案的最大优势——绝大多数误操作都有后悔药。
3.3 临时保存现场:stash 的正确打开方式
开发到一半突然被叫去修个线上 bug,手上的改动还没到能提交的状态,这个场景极其常见。git stash 就是为这种情况准备的:
bash复制git stash # 保存当前进度并清空工作区
git stash list # 查看保存的现场列表
git stash pop # 恢复最近一次保存的现场
stash 和 commit 的差别在于,stash 不进入提交历史,只相当于临时寄存。恢复时如果工作区已经有改动,pop 可能会产生冲突,这时候手动解决即可,不用太紧张。
一个小经验:stash 的时候顺手带一句说明,git stash save "登录模块未完成",比纯靠记忆区分多个 stash 靠谱得多。恢复时先看一眼 git stash list,确认编号再 pop。
4. 远程仓库协同:Gitee 密钥配置与团队协作
4.1 SSH 密钥生成与配置流程
Gitee 是国内的代码托管平台,访问速度和稳定性都很有优势,尤其是在连接境外平台不稳定的时候,Gitee 几乎是首选。配置 SSH 密钥是为了让本地和远程通信免去每次输账号密码的麻烦。
整个流程分三步走。
第一步,在本地生成密钥对。我实测过多次,用如下命令即可:
bash复制ssh-keygen -t rsa -b 4096 -C "你的邮箱"
回车后会提示保存路径,默认在 ~/.ssh/id_rsa,一路回车即可。接着会让你设置 passphrase,这是该密钥的密码保护。嫌麻烦可以不设,但设了更安全,看个人取舍。
第二步,查看公钥并复制:
bash复制cat ~/.ssh/id_rsa.pub
第三步,登录 Gitee,进入“设置 -> SSH 公钥”,把输出的内容粘贴进去,标题可以随便填,比如“我的笔记本”。完成后验证一下:
bash复制ssh -T git@gitee.com
看到 Hi 用户名! You've successfully authenticated 之类提示就代表通了。
4.2 HTTPS 与 SSH 的选择
很多教程默认教你用 SSH,但从实际体验来说,如果只是个人使用,HTTPS + 凭据管理器也够用,而且配置更简单。HTTPS 方式 clone 下来后,首次推送会让你输入用户名密码,输入一次下次就记住了(Windows 上凭据管理器会自动存储,macOS 上会提示存到钥匙串)。
不过 HTTPS 的坑在于:如果配置了双重认证(2FA),密码框里填的就不是登录密码,而是私人访问令牌(Personal Access Token)。Gitee 上这个需要在设置里生成,截图或下载后就没机会再看到完整值。
SSH 的优势是免密,而且密钥不经过网络传输,相对更安全。劣势是换电脑换密钥的时候需要重新配置,对多设备使用者来说,管理成本更高。我的选择是:经常跑代码的业务机器用 SSH,临时用的机器用 HTTPS + 令牌,两者各司其职。
4.3 团队协作中最常用的远程命令
前面讲的多是个人开发场景,到了团队协作,命令组合会有些变化。最重要的区别是:团队协作中,提交前先拉取最新代码是基本纪律。
bash复制git pull --rebase origin main
--rebase 的作用是把自己的提交“叠加”到远程最新提交之上,这样 git 历史是一条直线,不会出现一个“merge branch”的无意义提交节点。不过重复前面那句话——rebase 只适合本地私有提交,如果在公共分支上用了,会让历史变得复杂。
团队协作常常涉及多人修改同一个文件,冲突几乎无法避免。处理冲突的步骤大致如下:
git pull时报冲突,先别慌,git 会把冲突文件标注出来;- 打开冲突文件,搜索
<<<<<<< HEAD和=======以及>>>>>>>等标记; - 手动确认保留哪一部分代码,把冲突标记删干净;
git add冲突文件,然后git commit完成合并提交。
这里有个血泪经验:解决冲突时最容易犯的错误是“两边都想要”,但实际写出来的代码是两边逻辑叠加之后的怪胎。遇到真正拿不准的冲突,最好的做法是约写这段代码的同事当面沟通,而不是自己“合理推断”。因为冲突的本质是双方对同一逻辑的不同理解,只有理解达成一致,代码才不至于出问题。
4.4 常见远程操作速查
| 场景 | 命令 | 说明 |
|---|---|---|
| 拉取远程新分支 | git fetch origin |
只获取远程数据,不自动合并 |
| 强制同步本地 | git reset --hard origin/main |
以远程为准覆盖本地,本地改动会丢失 |
| 删除远程分支 | git push origin --delete branch-name |
谨慎操作 |
| 查看远程地址 | git remote -v |
核对 origin 指向是否正确 |
| 推送新分支 | git push -u origin 分支名 |
首次推送需加 -u |
fetch 和 pull 的差异值得多说两句。pull 实质上是 fetch + 自动合并,但它隐含了“自动合并到当前分支”这个动作,如果对合并策略不敏感,很容易造成莫名其妙的分叉。所以遇到比较关键的更新,我会先 git fetch,再用 git log origin/main 查看远程分支的提交记录,确认无误后再选择合并方式。
5. 常见问题排查与避坑指南
5.1 误删文件与恢复数据
开发中误删文件是比较常见的意外。如果你只是删了工作区的文件,还没 add,直接用 git checkout -- <文件> 就能恢复:
bash复制git checkout -- 误删的文件.txt
如果删除之后已经 add 到暂存区,这个命令就不灵了,要用:
bash复制git reset HEAD 误删的文件.txt
git checkout -- 误删的文件.txt
再极端一点,如果删除后连 commit 都做了,就用 git reset --hard HEAD~1 回到上一个提交。当然“误删恢复”并不是万能的,它只能恢复“曾经被 git 跟踪过的文件”,那些新增但从未提交过的文件,git 帮不了你。所以一个重要心得是:重要文件务必先提交到本地仓库,哪怕提交信息写得粗糙一点,也比没有提交强。
5.2 忽略文件的正确配置
很多新手会疑惑,为什么我项目里有 node_modules、target、.idea 这类目录,提交之后队友拉下来总是多出一堆奇怪的东西?答案是需要 .gitignore 文件。
在仓库根目录创建 .gitignore,按照语言和工具链写入需要忽略的内容:
text复制node_modules/
target/
*.log
.idea/
.DS_Store
.gitignore 是对 git 的重要约束:它告诉 git 哪些路径不被跟踪。如果你在添加 .gitignore 之前已经把某些文件提交了,那需要先删除缓存:
bash复制git rm -r --cached 文件名或目录
之后再提交才会生效。有一个关于 .gitignore 的重要细节:空目录不会被 git 跟踪。很多项目里需要保留“文件夹结构”但文件夹里又是空的,此时可以在目录里放一个 .gitkeep 空文件,这样 git 就会保留这个目录。
5.3 高频报错与对应处理
| 报错信息 | 原因 | 处理方式 |
|---|---|---|
Permission denied (publickey) |
SSH 密钥未配置或未生效 | 重新检查 ssh -T git@gitee.com,确认公钥已添加到 Gitee |
src refspec main does not match any |
本地没有 main 分支,或分支名不同 | 检查 git branch 确认分支名,推送时用实际分支名 |
failed to push some refs |
远程有你本地没有的提交 | 先 git pull --rebase origin main 再推送 |
Authentication failed |
密码或令牌错误 | 在 Gitee 生成一个私人令牌作为密码 |
There is no tracking information for the current branch |
本地分支没有关联远程分支 | 首次推送用 git push -u origin 分支名 |
上面这个速查表基本覆盖了我实际接触到的八成报错场景。遇到“failed to push”这种问题,除了按表格操作,还有一种简单粗暴但有效的思路:看清楚报错英文的单词,比如 fetch first 的意思就是让你先拉取再推送,git 的报错信息大部分时候已经点明了解决方案,不要一报错就慌着去复制网上的命令。
5.4 一条提升体验的配置建议
最后分享一个让命令行界面舒服很多的小配置:
bash复制git config --global color.ui true
git config --global alias.lg "log --oneline --graph --all --decorate"
color.ui 让命令输出带颜色,lg 别名让你以后敲 git lg 就能看到漂亮的提交树状图。这个别名在形如“查询某次提交在哪个分支上”的场景下尤其好用,一眼就能看清全局分支网络。类似地,还可以给常用命令起别名:
bash复制git config --global alias.st status
git config --global alias.co checkout
git config --global alias.br branch
配置越多,命令行使用越顺手,逐渐就不再依赖 IDE 里的图形界面了。我在实际使用中的体会是,记住 git 的核心命令并不难,难的是理解它背后的数据模型。一旦你理解了每一次提交都是对文件树的快照,分支只是移动的指针,rebase 是重新开采提交记录,很多看起来吓人的操作就会变得顺理成章。
git 的学习曲线确实有些陡峭,但它可能是所有开发工具里“投入产出比”最高的一个。你花两小时把基本流程走通,之后每天的开发都能实实在在受益。不要盲目复制网上的命令,逐条理解参数的含义,遇到问题多思考一下 git 底层是怎么运作的,上手速度会比机械记忆快得多。
