很多刚开始用 Git 的朋友,其实都卡在一个很尴尬的位置:知道 git add、git commit、git push 这几个命令,但真到了要从 Gitee 拉一个项目下来改、再推回去的时候,顺序和逻辑经常是乱的。尤其是遇到“推送被拒绝”“冲突一大堆”这种问题,第一反应往往是百度复制粘贴命令,粘贴完也不知道为什么就好了,下次照样踩坑。
这篇内容就是来解决这个问题的。我会以 Gitee 作为远程仓库平台,把“从拉取到推送”的完整工作流一步一步拆开讲,包括每个命令背后的原理、为什么要这么操作、以及哪些地方容易出问题。不管你是刚入门想搭第一个仓库,还是已经用过一段时间但总感觉命令是“背”下来的,这篇应该都能让你把整条链路彻底理顺。
1. 先搞清楚:Git 和 Gitee 各管哪一段
很多新手会把 Git 和 Gitee 当成一个东西,其实它们完全是两个层次。Git 是一个分布式版本控制系统,跑在你本地,负责记录代码的每一次变化,就像给项目拍了一部连续剧,每个 commit 就是一集。而 Gitee 是一个基于 Git 的远程代码托管平台,它解决的是“你的本地仓库怎么跟别人协作、怎么多设备同步”的问题。你可以把 Gitee 理解成一个公共的“存档点”,本地拍完的剧集,推上去备份,别人也能基于这个存档继续拍。
为什么推荐用 Gitee 来走通这个流程?最直接的原因是它的中文界面和国内访问速度对新手足够友好,注册、建仓库、配 SSH 公钥这些操作都有明确的引导。无论你以后用 GitHub、GitLab 还是公司内部的 Git 服务器,命令和思路都是一样的,所以拿 Gitee 练手完全不亏。
1.1 本地仓库的三个区:工作区、暂存区、版本库
想理解 Git 工作流,绕不开这三个区。我见过太多人只把 Git 当成“上传下载工具”,结果一遇到问题就懵。简单说:
- 工作区:就是你本机看到的那些项目文件,你正常编辑代码的地方。
- 暂存区:一个临时存放你“准备提交”的改动的地方,Git 用
git add把工作区的改动放进暂存区,相当于先挑好这一批要交付的文件。 - 版本库:Git 真正记录历史的地方,
git commit会把暂存区的内容生成一个新版本,永久写入版本库。
打个比方:工作区是你的工位,暂存区是公文包,版本库是公司的档案室。你写代码是在工位上写,git add 是把资料装进公文包,git commit 才是正式归档。而 git push 相当于把档案室里的这个副本同步到总部的档案中心(远程仓库)。
理解这三者的关系后,你再看 Git 命令就清楚多了:git status 是看工作区和暂存区的差异,git diff 是看具体改了什么,git log 是看档案室里已经有哪些记录。
1.2 一条命令走完整流程的时代已经过去了
老一辈的习惯是 git add 全部、git commit、git push 三个连招搞定一切。这在单人开发的项目里问题不大,但一旦你开始按功能拆分提交、或者参与多人协作,这种粗糙的用法会埋下很多坑。后面我会详细讲 add 的粒度、commit 的规范、push 前的检查,这些都是从“会敲命令”到“真正会用 Git”的分水岭。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 环境准备:安装 Git、配置身份、搞定 SSH 免密
在从 Gitee 拉取代码之前,得先把本地环境收拾干净。这一步别嫌麻烦,配置好了,后面每一轮操作都能省好几步。
2.1 安装 Git,各平台都给你列清楚
- Windows:去 Git 官网下载安装包,一路 Next 即可。需要注意安装过程中选择“Use Git from the Windows Command Prompt”或“Use Git and optional Unix tools from the Command Prompt”,方便在 CMD 里直接用 git 命令。
- macOS:如果你装了 Homebrew,一条命令搞定:
bash复制
没装 Homebrew 的话,直接下载官方 pkg 安装包也行。brew install git - Linux(Ubuntu/Debian):
bash复制sudo apt update sudo apt install git -y
安装完在终端敲一下:
bash复制git --version
能输出版本号就说明成功了。这里提醒一句:网上有些教程让你装什么“图形化 Git 客户端”,这种东西可以锦上添花,但千万别觉得装了 GUI 就不用学命令行。命令行是 Git 的根,你要理解工作流还是得靠命令。
2.2 全局配置:姓名和邮箱不是随便填的
Git 每次提交都会记录作者信息,这个信息来自你的全局配置。如果你不配或者配错,commit 记录里就会出现乱起八糟的名字,甚至导致 Gitee 上统计不到你的提交。
bash复制git config --global user.name "你的名字"
git config --global user.email "你的邮箱@example.com"
建议姓名用 Gitee 昵称,邮箱用注册 Gitee 时用的邮箱。这样网页端能看到提交。如果不确定当前配置,可以查看:
bash复制git config --list
还有一个容易被忽略的配置:换行符自动转换。Windows 和 Linux/macOS 的换行符不一样,如果不统一,代码明明没改,Git 却告诉你一堆文件有变化。建议 Windows 用户执行:
bash复制git config --global core.autocrlf true
macOS/Linux 用户执行:
bash复制git config --global core.autocrlf input
这个细微的差异,是我见过“莫名其妙的变更”里最高频的元凶之一。
2.3 SSH 免密配置:以后 push 再也不用输账号密码
Gitee 支持 HTTPS 和 SSH 两种远程地址。HTTPS 每次 push 都要输入账号密码或者用个人访问令牌,非常影响体验。SSH 通过密钥对验证身份,配置一次之后,拉取和推送都免密,舒服得多。
生成密钥:
bash复制ssh-keygen -t ed25519 -C "你的邮箱@example.com"
一路回车,默认生成到 ~/.ssh/id_ed25519.pub。然后查看公钥:
bash复制cat ~/.ssh/id_ed25519.pub
复制输出的整段内容,打开 Gitee 网页端,进入“设置 -> SSH 公钥”,粘贴保存。然后在终端测试:
bash复制ssh -T git@gitee.com
如果配置成功,Gitee 会返回欢迎信息,类似 Hi xxx! You've successfully authenticated, but GITEE.COM does not provide shell access.。这里有个容易犯的错:有些人会把邮箱填成 Gitee 账号,其实 ssh 后面跟的 git@gitee.com 是固定写法,不需要改成你自己的邮箱。
3. 从 Gitee 拉取代码:clone、fetch、pull 到底怎么选
“拉取”这个词在日常交流里其实涵盖了三个不同命令:git clone、git fetch、git pull。很多教程混着讲,初学者自然就乱了。我的建议是分场景对待。
3.1 首次拉取:git clone 把整个仓库复制到本地
当你第一次把一个远程仓库弄到本机,唯一正确的命令是 clone。
bash复制git clone git@gitee.com:用户名/仓库名.git
这条命令会做三件事:在当前目录下创建一个仓库同名文件夹、把远程仓库的所有代码和历史记录下载到本地、自动建立一个本地分支并跟踪远程分支。执行完你就有了一份完整可用的本地仓库。
如果想把仓库克隆到指定目录,可以加一个参数:
bash复制git clone git@gitee.com:用户名/仓库名.git 自定义目录名
如果你只需要某个分支,而不是全部分支历史,也可以用 --branch 参数:
bash复制git clone -b main git@gitee.com:用户名/仓库名.git
但我不建议你为了省流量而指定分支。Git 是分布式的,本地拥有完整历史有很多好处,比如你临时想切到其他分支查代码、或者离线看 log,都能操作。
3.2 日常更新:git pull 是 fetch 加 merge 的合体
项目已经 clone 到本地之后,别人的代码可能已经推到了远程。你想同步最新内容,这时候用的是 git pull,而不是再 clone 一遍。命令格式:
bash复制git pull origin main
这里的 origin 是远程仓库的默认别名,main 是分支名。执行 git pull 时,Git 先执行 git fetch(把远程最新提交下载到本地),然后再执行 git merge(把这些提交合并进当前分支)。
你可能会听到有人说“定期 pull 一下代码”,这个操作非常频繁。但 pull 有一个特点:它同时修改你的工作区。如果本地有未提交的修改,pull 可能会因为这些修改与远程更新冲突而中途失败。所以规范操作是:pull 前先 git status 确认工作区是干净的,或者先 commit 再 pull。
3.3 git fetch:只下载不合并,想先看看再决定
fetch 和 pull 的区别在于,fetch 只把远程的提交拉到本地“远程追踪分支”上,比如 origin/main,但不会动你当前所在的分支,也不会动工作区。你可以在 fetch 之后用 git log origin/main --oneline 看看远程都更新了什么,对比一下和自己本地的差异,再决定要不要合并。
什么时候该用 fetch 而不是 pull?最常见的是你在一个稳定分支上做开发,不想让自己的工作区被突然改变,想先确认远程有没有新的提交、以及这些提交影响范围有多大。执行:
bash复制git fetch origin
然后比较本地和远程:
bash复制git log HEAD..origin/main --oneline
如果你想看具体的差异内容,再用 git diff HEAD origin/main。确认没问题后,再手动 merge 或直接 pull。这种做法虽然多一步,但在多人协作项目里能救命——你不会被一个突然的 pull 打乱手头工作。
3.4 拉取代码时容易踩的两个小坑
第一个坑:clone 和 pull 混用。我在工作里见过有人每次同步代码都删了文件夹重新 clone,这非常浪费时间和带宽,而且如果你本地有未提交的改动,直接被冲掉了。正确做法是首次 clone,之后永远用 pull/fetch。
第二个坑:URL 地址选错协议。Gitee 仓库页面上会同时提供 HTTPS 和 SSH 两种地址,如果你之前配置过 SSH 公钥,一定要复制 SSH 地址(git@gitee.com:...)而不是 HTTPS 地址,否则配了半天免密还是没用,因为你在用 HTTPS 协议访问。
另外,如果你 clone 了别人一个仓库,想推到自己的 Gitee 仓库,除了改远程地址之外,还可以在 Gitee 先创建自己的仓库,然后这样操作:
bash复制git remote rename origin upstream
git remote add origin git@gitee.com:你的用户名/你的仓库名.git
upstream 是“上游仓库”的惯用名,这样既能持续拉取原始仓库的更新,又能推到自己的远程。
4. 本地修改到推送的完整闭环:status、add、commit、push
拉取代码只是起点,整个工作流的主角是你自己写的那些改动。这一节我把从改代码到推送的完整闭环拆开讲,每一步都说明为什么。
4.1 动代码之前和之后,先看一眼 git status
很多人上来就 git add .,完全不管自己改了哪些文件。我建议你在改完代码后先执行:
bash复制git status
它会把工作区里所有改动分成三类:未跟踪的新文件(untracked)、已修改但未暂存的文件、已暂存待提交的文件。这个命令是 Git 给你的“仪表盘”。养成看仪表盘的习惯,能避免误提交临时文件、配置文件等一大堆问题。
如果改动太多,可以用 git status -sb 以短格式查看,每个文件的状态更紧凑,还能看到当前分支和远程分支的领先/落后关系。
4.2 git add 的三种用法,以及对“git add .”的警告
git add 是把工作区的改动放入暂存区。常见用法:
bash复制git add src/index.js # 添加指定文件
git add src/ # 添加整个目录
git add . # 添加当前目录下的全部改动
git add . 是最省事的,但也是最容易出事的。如果你没有 .gitignore 文件,或者 .gitignore 配置不完整,很容易把 IDE 配置文件、编译产物、本地环境影响文件全加进去,然后 commit 进版本库。等到推送到 Gitee 后,这些垃圾文件就会一直躺在仓库历史里,清理起来非常麻烦。
所以我的建议是:小改动用 git add <文件>,大改动先用 git status 看清楚再决定。如果确实想一次加多个文件,按目录粒度去 add,也比无脑 git add . 强。
如果你偶尔手滑加了不该加的内容,可以这样撤出暂存区:
bash复制git reset HEAD 文件名
文件会回到工作区,改动不会丢。
4.3 git commit:提交信息写得好,回溯代码没烦恼
暂存区准备好了,就要生成一个版本。提交命令:
bash复制git commit -m "feat(user): 新增用户登录接口"
提交信息看起来是件小事,但很多人不重视。我见过不少项目的历史提交信息是“更新”“修改”“1.0”,等出了问题要查某段代码是哪次提交引入的,根本没法查。
这里给一个我长期使用的提交信息规范模板:
| 类型 | 说明 | 示例 |
|---|---|---|
| feat | 新增功能 | feat: 新增用户注册页面 |
| fix | 修复缺陷 | fix: 修复登录超时未提示的问题 |
| docs | 文档变更 | docs: 更新 README 部署说明 |
| style | 格式调整,不影响逻辑 | style: 调整 eslint 缩进规则 |
| refactor | 重构,不改功能和修复 | refactor: 抽取公共请求方法 |
| test | 测试相关 | test: 新增登录接口单测 |
| chore | 构建辅助工具等 | chore: 升级依赖版本 |
单次提交的粒度也很重要。尽量保证一个 commit 只做一件事。比如你同时改了登录功能和首页样式,这两个改动最好分成两次 commit,而不是揉在一起。原因很简单:将来如果登录功能出问题了,你需要单独回退那个功能,而样式改动不应该被牵连。
4.4 git push:首次推送必须关联上游分支
commit 只是把改动写进了本地版本库,别人在 Gitee 上还看不到。要共享给远程仓库,必须 push。
如果你是在本地新建了一个分支,第一次推送时需要指定远程分支,并建立跟踪关系:
bash复制git push -u origin 你的分支名
-u 就是 --set-upstream,建立本地分支对远程分支的跟踪。之后在这个分支上,直接敲 git push 或 git pull 就行,不需要再写 origin 分支名。
如果分支已经存在且已经跟踪,那么普通推送就够了:
bash复制git push
推送成功后,你会发现 git status 里 “Your branch is up to date with 'origin/你的分支名'” 这句话,意味着本地和远程已经同步了。
但这只是一个理想闭环。真实项目里,你经常会遇到推送被拒绝的情况——这就是下一节要说的重点。
5. 推送被拒绝怎么办:冲突解决与分支保护
“推送被拒绝,非快进更新被忽略”是 Git 新手最恐惧的报错之一。很多人一看到这串英文就慌,其实它背后的逻辑非常简单。
5.1 非快进推送的本质:你的本地落后于远程
先看一个典型场景:你和同事都从 origin/main 拉取了同一个版本。你改了文件 A,他改了文件 B。他把文件 B 的修改推到了远程。这时候你的本地分支还停留在旧版本,你要 push 文件 A 的修改,远程发现你的提交不是基于最新的远程提交,就没有办法直接“快进”到你的版本——因为远程多了一个你不认识的提交。
Git 的策略很简单:不允许你覆盖你不在本地的提交。这就是“non-fast-forward”报错的来源。它保护的不是某个人,而是“任何提交都不应该丢失”这条底线。
5.2 正确的处理顺序:先 commit,再 pull,最后 push
遇到推送被拒绝,正确做法是先把本地改动 commit(如果不 commit,pull 遇到冲突会很难办),然后 pull 远程更新,合并后再 push。
bash复制git add .
git commit -m "feat: 完成某个功能"
git pull origin main
git pull 执行时,Git 会把远程的提交合并进你的本地分支。如果你们两个改的是不同文件,Git 会自动合并,不会产生冲突,然后你直接 push 即可。如果改了同一个文件的同一区域,就会出现冲突。
这里有一个可选项:git pull --rebase。pull 默认使用 merge 方式,会把远程提交和你的本地提交串成一个分叉再合并,产生的历史里会多一个“Merge commit”。用 --rebase 时,Git 会把你本地的提交“变基”到远程提交之后,让提交历史变成一条直线,更干净。但 rebase 会重写本地提交的哈希值,如果分支已经被别人用过,就不要随便 rebase。我的建议是个人开发分支优先考虑 --rebase,多人共享分支老老实实用默认 merge。
冲突破仓后,需要用编辑工具手动解决。
5.3 冲突标记到底怎么读:三组符号讲清楚
冲突发生后,Git 会在冲突文件里插入类似这样的内容:
code复制<<<<<<< HEAD
你本地写的代码
=======
远程拉下来的代码
>>>>>>> origin/main
三组符号的含义很直观:<<<<<<< HEAD 到 ======= 之间是当前分支(本地)的内容,======= 到 >>>>>>> origin/main 是远程分支的内容。你需要打开这个文件,把两边代码梳理成最终想要的版本,然后删掉那些标记符号。
手动解决后,记得执行:
bash复制git add 冲突文件
git commit -m "merge: 解决登录接口冲突"
如果没有额外修改,多人协作的合并提交可以直接用默认信息。但如果你手动调整了很多代码,最好在提交信息里写清楚冲突是怎么解决的,方便同事 review。
解决完冲突后,再执行 git push,这次就能顺利推上去了。
5.4 分支保护与 Pull Request:别直接推 main
如果你只是自己一个人用仓库,那随便怎么推。但如果是项目协作,我非常建议你在 Gitee 里开启“分支保护”,把 main(或 master)设为受保护分支,不允许直接推送,所有变更必须通过 Pull Request(PR)合并。
Gitee 的路径是:仓库“管理 -> 分支管理 -> 保护分支设置”。开启后,你就可以在本地从 main 拉一个新功能分支:
bash复制git checkout -b feature/login
在这个分支上干活、提交、推送:
bash复制git push -u origin feature/login
然后去 Gitee 网页端发起 Pull Request,由代码审查者确认后再合并。这样能大幅减少直接把坏代码推进主分支的概率。而且因为 main 分支受保护,你永远不会把临时的中间提交推到主干,历史干净可控。
很多初学者觉得 PR 流程麻烦,但我想说的是:Git 最有价值的地方不是“代码上传下载”,而是“可控的多人协作”。哪怕你现在是个人项目,练习用分支和 PR 走一遍完整流程,未来进团队就不会手足无措。
6. 让工作流更顺畅的细节:.gitignore、提交模板和命令速查
流程跑通之后,真正影响日常效率的是一些“看不见的配置”。这一节分享几个我长期在用的细节,都是实操里反复验证过的经验。
6.1 .gitignore:把不该提交的文件挡在门外
.gitignore 是用来告诉 Git 哪些文件或目录不要纳入版本控制。它应该在你创建仓库的时候就配好,而不是等到垃圾文件提交了再补救。
常见的需要忽略的内容包括:
- 编译产物:
dist/、build/、target/ - 依赖目录:
node_modules/、vendor/ - 本地环境配置文件:
.env.local、application-local.yml - IDE 配置:
.idea/、.vscode/ - 系统文件:
.DS_Store、Thumbs.db - 日志文件:
*.log
一个简单的规则示例:
gitignore复制node_modules/
dist/
.env.local
*.log
.idea/
.vscode/
.DS_Store
有些人不理解为什么要忽略 IDE 配置。其实每个人的 IDE 设置不一样,个人偏好提交上去,反而会造成噪音。而且一旦某个文件已经被 Git 跟踪,再把它加进 .gitignore 是没用的,必须先执行:
bash复制git rm --cached 文件名
这个命令只把文件从 Git 索引里移除,保留磁盘上的文件,之后它才会被 .gitignore 规则忽略。
6.2 提交模板与命令别名:把常用操作焊成肌肉记忆
如果你所在团队对提交格式有严格的要求,可以配置一个 Commit 模板。在项目根目录建 .gitmessage 文件:
code复制feat(组件范围): 一句话描述
更长的说明,可空。
然后执行:
bash复制git config --local commit.template .gitmessage
这样每次 git commit 不带 -m 时,编辑器会自动带入模板,提醒你按规范写。
另外,Git 支持配置命令别名,我常用的几个:
bash复制git config --global alias.st "status -sb"
git config --global alias.lg "log --oneline --graph --all --decorate"
git config --global alias.unstage "reset HEAD --"
配置好之后,git st 看状态,git lg 看提交历史图,比默认命令直观得多。这些别名自己用越用越顺手,但注意不要过度配置,不然换台电脑容易不适。
6.3 Gitee Pages:把仓库变成一个可访问的网页
除了代码托管,Gitee 历史上有“Gitee Pages”功能,可以把仓库里的静态网页发布成一个可访问的站点,非常适合个人博客、项目文档、前端 Demo。不过这个服务的可用状态和审核规则会不定期调整,建议你使用前先去 Gitee 官方文档确认最新政策。
如果 Pages 不可用,替代方案是把 README.md 写好,Gitee 仓库首页会直接渲染 Markdown 内容,这本身就是一种极好的项目展示方式。README 里写清楚项目简介、安装步骤、使用示例、目录结构,对访问者的帮助远超一个花哨的网页。
6.4 从拉取到推送的命令速查表
把这篇文章里涉及的完整流程浓缩成一张表,供你日常查用:
| 场景 | 命令 |
|---|---|
| 首次拉取仓库 | git clone git@gitee.com:用户名/仓库名.git |
| 查看当前状态 | git status |
| 查看变更内容 | git diff |
| 添加改动到暂存区 | git add 文件/目录 |
| 生成提交 | git commit -m "feat: 新增功能" |
| 拉取远程更新 | git pull origin main |
| 推送本地提交 | git push |
| 首次推送并关联分支 | git push -u origin 分支名 |
| 只下载远程更新 | git fetch origin |
| 撤销暂存 | git reset HEAD 文件名 |
这张表就是一个最小可用的 Git 工作流。刚开始你完全可以按表操作,等熟悉了每个命令背后的含义之后,再慢慢加入 rebase、stash、cherry-pick 这些进阶操作,都是顺理成章的事。
最后再分享一点我个人的实操体会。Git 不是靠背命令学好的,而是靠“敢于错误提示”学好的。我当年也经历过推送被拒、冲突乱掉的阶段,每次都是先静下心看报错信息,再 git status、git log 对齐自己当前的状态,基本都能找到出路。配好 Gitee 的 SSH 免密、写好 commit 规范、保持小粒度提交,这套工作流在你手里会越来越顺,真正成为肌肉记忆。
