1. 写在前面:为什么Git加Gitee这套组合拳值得认真学
平时被问得最多的问题,不是“Git是什么”,而是“我从Gitee上拉了个项目下来,改完怎么推回去”“为什么我推送的时候一直要输密码”“同事改的代码我拉下来怎么跟我本地冲突了”。这些问题听着零散,归根结底就一件事:没有形成一条完整的 Git + Gitee 工作流。
本文就围绕这个核心命题来写。从 Gitee 上拉取一个仓库到本地,完成代码修改,再推送回远端,这条链路说长不长,说短不短,中间涉及的 clone、pull、fetch、add、commit、push、branch、merge、rebase 这些命令,每一个都可能成为卡住你的地方。我会把这条链路上每一个环节都拆开讲清楚,包括命令背后的原理、参数选择的理由、以及我在实际项目中踩过的坑,而不是只给你一份命令清单。
这套内容适合这几类人看:刚开始用 Git 的初学者、在 IDE 里点按钮拉取推送但一直没搞懂底层逻辑的开发者、以及想把日常 Git 操作规范化的团队新人。看完之后,你至少能独立完成从 Gitee 拉取代码到推送回远端的全过程,并且遇到常见的报错知道该从哪里排查。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 环境准备:把 Git 装好、配好、连上 Gitee
很多人还没走到“拉取”这一步,就已经在环境上卡住了。这里我把从安装到连接 Gitee 的完整过程讲一遍,每一步都说明为什么要这么做。
2.1 安装 Git:三个主流系统的安装方式
Windows 用户直接去 Git 官网下载安装包即可,一路点下一步就能装好。但有两个容易忽略的细节。第一个是安装过程中选择默认编辑器时,建议选“Use Nano”或者保持默认的 Vim,不要临时切换到其他编辑器,免得后续操作时被不熟悉的编辑器界面吓到。第二个是安装路径尽量用默认路径,不然后面一些工具扫描 Git 时可能会找不到。
macOS 用户我推荐用 Homebrew 安装,命令就一行:
bash复制brew install git
如果还没装 Homebrew,也可以用 Xcode Command Line Tools 自带的 Git,输命令时系统会弹窗指引安装。Linux 用户则根据发行版选择,Debian/Ubuntu 用 apt install git,CentOS/RHEL 用 yum install git。
装完以后验证版本,能正常输出版本号就说明成功了:
bash复制git --version
注意:我在实际中遇到过一个情况,Windows 上装完 Git 后在命令行里能正常使用,但 IDE 里提示找不到 Git。这通常是因为 IDE 已经打开了,读取不到新加的环境变量,重启 IDE 就能解决。
2.2 配置 Git 用户信息:不让提交记录变成“无名氏”
Git 的全局配置是很多人跳过的一步,但这一步比你想的重要。你每次提交代码,提交记录里都会带一个作者信息,这个信息来自你的 Git 配置。如果没有配置,Git 会尝试从系统用户名猜测,产生一串乱码或者错误的名字,推送到远端后,仓库里的提交记录就是一堆“Unknown”。
配置方式很简单,在命令行里执行:
bash复制git config --global user.name "你的名字"
git config --global user.email "你的邮箱"
这里的邮箱建议填你 Gitee 账号绑定的邮箱,这样提交记录能跟你 Gitee 上的账号关联起来,在仓库页面能正确显示头像和昵称。不信你可以试试,配置一个不存在的邮箱去提交,推上去之后提交记录里作者那个位置是空的或者显示一串随机字符。
还有一个配置我也建议顺手做了,Git 默认分支从 master 改成了 main,但很多老教程还是写 master,所以设置一下默认分支名,避免后续混乱:
bash复制git config --global init.defaultBranch main
2.3 SSH 免密连接 Gitee:一次配置,彻底告别密码
推送代码的时候,最烦的就是每次都输用户名密码。Gitee 支持 HTTPS 和 SSH 两种协议,HTTPS 每次 push 都要验证身份,SSH 通过密钥对自动验证,配置一次就能长期免密。
先检查本地有没有已经生成过的 SSH 密钥:
bash复制ls ~/.ssh
看到 id_rsa 和 id_rsa.pub 这两个文件,说明以前生成过,直接用就行。没有的话生成一个:
bash复制ssh-keygen -t rsa -C "你的邮箱"
一路回车,会在用户目录下生成一个 .ssh 文件夹,里面有两个文件。id_rsa 是私钥,绝对不能泄露给任何人;id_rsa.pub 是公钥,把它内容复制出来:
bash复制cat ~/.ssh/id_rsa.pub
然后登录 Gitee,进入“设置 → 安全设置 → SSH 公钥”,把复制的内容粘贴进去,标题随便写一个方便识别的名字。添加成功后,测试一下连接:
bash复制ssh -T git@gitee.com
第一次连接会询问是否确认主机指纹,输入 yes 回车。看到 Hi 用户名! You've successfully authenticated 类似的提示,就说明通了。
有一点要特别提醒:如果你在公司电脑上生成过 SSH 密钥,换电脑后一定要把新的公钥重新加到 Gitee,不要试图拷贝私钥到多台机器。私钥在本地文件里权限也要注意,别让别人看到。
3. 核心工作流详解:从 Gitee 拉取到推送的每一步
环境配好后,接下来进入正题。这一节把从拉取到推送的完整链路拆开,对应每一步说明命令、原理、以及为什么要这么做。
3.1 拉取代码:clone、pull、fetch 到底怎么选
很多人对这几个命令分不清,这里先说结论:clone 是第一次拿代码用的,pull 是后续同步远端更新用的,fetch 是只下载不合并用的。
第一次从 Gitee 拿项目,在仓库页面找到克隆地址。Gitee 提供 HTTPS 和 SSH 两种地址,既然上面配好了 SSH,这里就选 SSH 那个。在本地准备存放代码的目录下执行:
bash复制git clone git@gitee.com:用户名/仓库名.git
这条命令会做三件事:在当前目录下创建一个跟仓库同名的文件夹、把远端所有分支和历史提交下载到本地、自动把本地分支跟远端分支关联起来。执行完后进入项目目录就能看到代码了。
日常开发中,你本地代码和远端不一致时,需要把远端最新的改动拉下来。这时候用 pull:
bash复制git pull
pull 其实是 fetch 加 merge 的合体。fetch 把远端更新下载到本地,merge 把这些更新合并到你当前所在的分支。如果你只想看看远端改了什么,还不想合并到本地当前分支,那就用 fetch:
bash复制git fetch origin
fetch 之后你可以用 git log origin/main 查看远端分支的提交记录,确认没问题再手动 merge。生产环境上我一般建议用 fetch 加手动 merge 的方式,避免 pull 自动合并带来预料之外的冲突。
这里有个很典型的使用场景:你在 main 分支上改代码,同事在 feature/login 分支上开发并推上去了。你不需要把 feature/login 合到 main,但想看看他的代码,用 fetch 拉下来就行:
bash复制git fetch origin
git diff main origin/feature/login
看完了不合并,不影响自己当前的工作。
3.2 本地修改与提交:add 和 commit 的正确用法
代码拉到本地后,正常的开发流程就是改文件。改完之后,要把改动提交到本地仓库。这里涉及两个命令:add 和 commit。
git add 的作用是把改动放进“暂存区”。可以理解为一个临时容器,你决定哪些改动要进入下一次提交。可以单个文件、多个文件、或者全部:
bash复制git add src/main/java/UserService.java
git add src/main/java/UserService.java src/main/java/UserController.java
git add .
很多新手习惯直接 git add .,把当前目录下所有改动全部加入暂存区,这在一些场景下很容易出问题。比如你临时改了一个配置文件,里面包含了本地调试用的密码,顺手 git add . 就把它提交进去了。所以我的习惯是分开加,按功能模块加,或者至少提交前用 git status 检查一遍。
git commit 是把暂存区的内容固化成本地提交:
bash复制git commit -m "修复用户登录时密码错误次数未重置的问题"
提交信息的写法也有讲究。我看到过很多 git commit -m "修改"、git commit -m "fix" 这类提交信息,到后面回滚版本时根本不知道哪次提交改了什么。规范一点的做法是:用一句话说清楚这次改动的目的,可以带上模块范围。比如 feat(user): 添加用户注册接口、fix(order): 修复订单金额精度问题。
注意:不在暂存区的改动不会被 commit 包含进去。如果你改了两个文件,只 add 了一个,commit 之后另一个文件的改动还在工作区里,重新 add 再 commit 一次即可。
3.3 推送代码:push 前必须检查的三件事
提交到本地之后,下一步就是把本地提交推送到 Gitee 远端。推送命令很简单:
bash复制git push
前提是你当前分支已经关联了远端分支。如果是 clone 下来的项目,本地分支默认关联了对应的远端分支,直接 push 就行。如果是自己新建的分支,第一次推送需要指定远端:
bash复制git push -u origin feature/login
这个 -u 参数会把本地分支跟远端分支建立关联,之后在这个分支上直接 git push 就能推送。
但我在实际中见过很多次这样的场景:push 的时候被远端拒绝了,原因是远端的提交记录比本地多。这种情况一般发生在多人协作时——你 commit 的时候远端已经有别人推了新代码。直接 push 会被拒,因为会产生分叉。
解决办法是先把远端更新拉下来合并,再推送:
bash复制git pull --rebase
git push
这里用 --rebase 是正解。rebase 和 merge 的差别在于:merge 会生成一个合并提交,rebase 会把你的本地提交“挪到”远端最新提交的后面,提交历史是一条直线,更清晰。
Push 之前你要检查的事项,我总结为三条:
- 检查当前分支:在错误的分支上 push 会把不该提交的代码推到远端,尤其是直接操作 main 分支时,要格外小心。
- 检查改动了哪些文件:用
git status和git diff确认要推送的改动都是预期的。 - 检查远端是否领先:
git fetch后对比一下,如果远端有更新,先 pull --rebase 再 push。
3.4 分支与冲突处理:多人协作时的必备技能
分支操作是 Git 工作流里绕不开的环节。在 Gitee 上创建分支有两种方式。一种是在仓库页面手动创建,另一种是在本地创建并推送。我推荐从本地推,因为创建分支前你可以在本地先验证。
bash复制git checkout -b feature/payment
这条命令同时完成了“创建分支”和“切换分支”两件事。在这个分支上改动、提交,最后推送并关联远端:
bash复制git push -u origin feature/payment
之后在 Gitee 仓库页面能看到这个分支,别人也就能拉取这个分支的代码了。
多人修改同一个文件时,冲突几乎不可避免。比如 A 和 B 都改了 UserService.java 的同一行,A 先推送到远端,B 再 pull 时就可能报冲突。
冲突发生时,Git 会在冲突文件里插入标记:
code复制<<<<<<< HEAD
这里是当前分支(本地)的内容
=======
这里是远端分支的内容
>>>>>>> origin/feature/login
<<<<<<< 和 ======= 之间是当前分支的版本,======= 和 >>>>>>> 之间是远端分支的版本。你需要手动决定保留哪一边,或者两边都保留,然后删掉这些标记行。
解决完冲突后,要执行:
bash复制git add 冲突文件名
git commit -m "合并远端分支,解决UserService.java冲突"
git push
这里有个容易踩的坑:冲突解决完了,直接 git push 被拒绝,因为没有经过 commit 这一步。在解决冲突后的流程里,commit 是不能省的。
4. 常见问题与排查技巧实录
这一节把我在群里看到、以及自己踩过的高频问题整理出来,给出排查思路和解决方案。
4.1 “git did not exit cleanly”到底怎么解决
这个报错常见于 Windows 用户在 IDE 里点击拉取或推送时,提示 git did not exit cleanly (exit code 128)。这个报错本身很笼统,重点是看它前面几行的具体错误信息。常见原因有几种:
第一种是仓库地址不对。检查一下 clone 地址有没有带 http:// 或者 git@ 前缀,粘贴时不要漏掉。特别是从 Gitee 复制地址时,要注意是 SSH 还是 HTTPS。
第二种是 SSH 密钥失效或未配置。如果仓库是用 SSH 方式克隆的,而本机没有配置对应的私钥,或者公钥在 Gitee 上被删除了,就会出现 128 错误。排查命令:
bash复制ssh -T git@gitee.com
如果显示权限不足,重新检查密钥配置。
第三种是 IDE 里的 Git 路径配置错了。Windows 上 Git 的可执行文件路径是 C:\Program Files\Git\bin\git.exe,IDE 设置里如果指错了路径,所有 Git 操作都会失败。去 IDE 的设置里找到 Git 配置项,确认路径正确。
4.2 高频报错速查表
我把实际中频率最高的几个问题整理成一张速查表,方便你在遇到问题时快速定位。
| 现象 | 可能原因 | 解决方案 |
|---|---|---|
push 时报 failed to push some refs |
远端有本地没有的提交 | 先 git pull --rebase 再 push |
提交后用 git push 提示 src refspec ... does not match any |
分支名拼写错误或本地分支不存在 | git branch 查看本地分支名,重新 push 正确的分支名 |
pull 时报 Please commit your changes or stash them |
本地有未提交的改动,与远端更新冲突 | 先 commit 或 git stash 暂存,再 pull |
| push 后 Gitee 上提交记录显示为“Unknown” | 没有配置 user.name 和 user.email | 配置全局身份信息后,重新提交 |
clone 时提示 Permission denied (publickey) |
SSH 密钥未配置或未添加到 Gitee | 生成密钥并添加到 Gitee 的 SSH 公钥列表 |
| Windows 上中文文件名显示为乱码 | Git 默认编码设置问题 | 执行 git config --global core.quotepath false |
| 误提交了不想提交的文件 | 没有用 .gitignore 排除 | 用 git rm --cached 文件名 取消跟踪,并加入 .gitignore |
| 提交信息写错了 | 想修改最近一次提交说明 | git commit --amend -m "新的提交信息" |
这里面 git commit --amend 值得多说一句:它只能修改最近一次提交,而且只能修改还没有推送出去的提交。如果已经 push 了,再用 amend 改历史,再 push 会被拒绝,需要强制推送,在多人协作时可能会覆盖别人的提交,很危险。所以我的原则是:推送之前可以随便改,推送之后不要用 amend。
4.3 一套稳妥的日常操作习惯
踩过不少坑之后,我总结了一套日常操作 Git 的固定流程,能规避绝大多数问题。
每次开始改代码前,先确保自己处于正确的分支上,并且分支是最新的:
bash复制git status
git checkout main
git pull
这里 git pull 默认拉取当前分支关联的远端分支,在 main 分支上执行就是拉取远端的 main。然后再切到自己的开发分支,把 main 合并进来,保证自己的分支没有落后太多:
bash复制git checkout feature/payment
git pull
git merge main
改完代码后,提交前先看 diff:
bash复制git diff
确认改动都是预期的,再 add 和 commit。推送前再 fetch 一次,如果远端有更新就 rebase:
bash复制git fetch origin
git pull --rebase
git push
这套流程看着繁琐,但习惯了之后十秒钟就能执行完。它避免了“推送被拒绝”“冲突爆炸”这些问题的发生概率。
5. 让这套流程更好用的进阶技巧
基础工作流跑通之后,下面这几个技巧能让你的操作更顺畅,也能避免一些低级错误。
5.1 用 .gitignore 管理不该提交的文件
第一次接触 Git 的人最容易犯的错,就是把不该提交的文件提交进仓库。比如本地配置文件、编译产物、IDE 配置、日志文件等。这些文件每个人本地都不一样,提交进去之后会造成无穷无尽的冲突和误操作。
好在 Git 提供了 .gitignore 文件,在仓库根目录创建一个,把需要忽略的文件模式写进去:
gitignore复制# 编译产物
target/
build/
dist/
# IDE 配置
.idea/
*.iml
.vscode/
# 日志
*.log
# 本地环境配置
.env.local
application-local.yml
# 系统文件
.DS_Store
Thumbs.db
文件创建好之后,按规则匹配的文件会被 Git 忽略,git status 不会显示它们,自然也不会被 add 进去。
需要注意一种情况:如果某个文件已经被 Git 跟踪了,再写进 .gitignore 是不会生效的,因为 Git 已经在跟踪这个文件了。解决方法是从跟踪列表中移除:
bash复制git rm --cached 文件名
这个命令会把文件从 Git 的跟踪列表里移除,但保留本地文件。执行后提交一次,之后这个文件就受 .gitignore 控制了。
5.2 Gitee Pages:把仓库变成可访问的在线页面
如果你的仓库里有静态网页代码,比如博客页面、项目文档,可以开启 Gitee Pages 服务。这个功能免费,能把仓库内容直接构建成可访问的网页。
在仓库页面找到“服务 → Gitee Pages”,选择要发布的分支,点击启动即可。部署过程一般几分钟内完成,之后会得到一个形如 https://用户名.gitee.io/仓库名/ 的地址。之后 push 新代码到对应分支,Gitee Pages 会自动更新。
我用这个功能部署过个人博客和组内的文档站点,体验下来觉得很适合团队内部用。需要注意 Gitee Pages 要求仓库是公开的,私有仓库无法开启。另外,部署的静态页面如果引用了外部资源,要注意资源地址需要写绝对路径或正确的相对路径,否则页面打开会白屏。
5.3 开源仓库的许可证选择:决定别人能不能合法用你的代码
如果你在 Gitee 上公开自己的项目,通常会有一个“选择开源许可证”的选项。很多人直接跳过或者随便选一个,这其实是个坑。
开源许可证决定了别人能用你的代码做什么。最简单区分是这么看的:
- MIT 协议最宽松,别人可以随便用、改、商用,甚至闭源,只需要保留版权声明。
- Apache 2.0 跟 MIT 类似,但增加了专利保护和明确条款。
- GPL 协议有传染性,别人用了你的代码,那他的项目也必须开源用 GPL 协议。
- BSD 协议也是宽松类的,但要求引用来源。
选择原则很简单:如果你希望代码被广泛应用,选 MIT 或 Apache 2.0;如果你希望代码的衍生版本也保持开源,选 GPL;如果只是个人项目,没这些诉求,选 MIT 就足够了。
还有一个容易被忽略的成本:代码托管在公开仓库,就意味着整个生命周期里任何人都有权基于仓库原有许可证分发你的代码,撤下仓库并不能阻止已经分发的副本继续使用。所以发布前想清楚许可证,比发布后补救要省事得多。
如果你在参与别人的开源项目,标准流程是这样的:先 fork 一份仓库到自己的账号下,再 clone 到本地,在 fork 的仓库里修改代码,推送到自己的 Gitee 仓库后,去原仓库页面发起 Pull Request,等维护者审核合并。这一整个流程用的就是前几节讲的 clone、add、commit、push,只是最后多了一个发起 PR 的动作。
6. 我的一些习惯与收尾建议
写到最后,分享几个我个人的使用习惯。第一个是提交信息的写法。我习惯用 type(scope): description 的格式,type 有 feat(新功能)、fix(修复)、docs(文档)、refactor(重构)、test(测试)这些,scope 表示模块,description 用一句话说明改动。比如:
bash复制git commit -m "feat(user): 添加用户登录日志记录功能"
git commit -m "fix(order): 修复订单金额为 0 时无法提交的问题"
这种格式的好处是后来看提交历史,一眼就能看出每次提交的目的,配合 git log --oneline 使用效果很好。
第二个习惯是频繁提交。一个小功能完成了、一个 bug 修好了,就立即提交一次,而不是攒到下班前一次性 commit。提交粒度小,回滚时定位到具体提交更方便。这个习惯在遇到“改了半天突然发现方案走不通,要回退到几个小时代码之前”的情景时,能帮你省下大把时间。
第三个习惯是关于 stash 的。临时要切换分支但本地有改动时,很多人会犹豫。git stash 可以把未提交的改动暂存起来,切换分支干完活再 git stash pop 恢复。但这个操作有一定风险,stash 弹出时如果当前分支跟暂存时的状态差异过大,可能产生冲突。所以 stash 只适合暂存几分钟到几小时的改动,不要隔夜恢复,隔夜后你很可能已经忘了 stash 里存的是什么了。
这套从拉取到推送的工作流,本质上是让本地代码和远端仓库之间形成清晰、可控的同步关系。大部分人觉得 Git 学起来乱,是因为被各种高级命令和 IDE 按钮分散了注意力,其实核心链路就那几条命令反复用:clone、fetch、pull、add、commit、push、branch、merge。把这几个命令弄明白,日常开发的大部分场景都能覆盖。遇到没见过的报错,先看报错原文,再检查远端状态和本地状态,按本文第四节的方式排查,基本都能定位到问题所在。
