写在前面
当我只在自己的电脑上使用 Git 时,add、commit、分支和合并已经能解决大部分版本管理问题。可一旦两个人同时开发,问题就会立刻升级:代码放在哪里交换?为什么我能提交却推不上去?origin/master 到底是远程分支还是本地分支?冲突该由谁解决?测试环境和生产环境又应该对应哪条分支?
这一篇从一个最容易建立直觉的事实出发:commit 只写入本地历史,push 才把某条本地分支的历史交给远端。 然后把远程操作、多人协作、Pull Request、环境隔离、Git Flow 与 AoneFlow 串成一条完整主线。
文中的示例沿用 master、dev、feature-* 等分支名。真实项目也可能把稳定分支命名为 main;名字不是重点,团队统一的语义、权限和合并规则才是重点。
知识框架

读图时可以把整套知识压缩为六个问题:
- 代码放在哪里共享:远程托管平台。
- 本地怎样认识远端:远程名、URL 和远程跟踪引用。
- 历史怎样来回移动:
clone、fetch、pull、push。 - 团队怎样控制合入:Issue、PR、Review 和受保护分支。
- 多人怎样减少互相干扰:功能分支与明确的上游关系。
- 代码怎样稳定上线:环境隔离、发布分支和版本标签。
目录
- 一、Git 是分布式的,为什么还要远程托管平台
- 二、创建远程仓库:成员、Issue、PR 与权限
- 三、HTTPS、SSH、origin 和远程跟踪分支
- 四、clone、fetch、pull、push 到底改变了什么
- 五、.gitignore、别名与标签
- 六、同一开发分支上的两人协作
- 七、功能分支协作与 Pull Request
- 八、远程分支删除后,为什么本地还能看见
- 九、从 DevOps 到开发、测试、预发布和生产环境
- 十、Git Flow:开发、发布与线上热修复
- 十一、AoneFlow:按环境组合功能
- 十二、企业研发空间、项目与代码仓库的边界
- 十三、一套可直接落地的协作流程
- 十四、常见误区与排错顺序
- 十五、总结
一、Git 是分布式的,为什么还要远程托管平台
"分布式"最容易被误解成"大家必须依赖一个中央数据库"。Git 恰好相反:正常克隆得到的不是一份只含当前文件的副本,而是一套带历史、分支和对象数据库的本地仓库。断网时,我仍然可以查看日志、创建分支、提交和回退。
既然每个人都有完整历史,理论上两台电脑可以直接互相交换提交;现实中却很少这样做,因为个人电脑可能关机、换网、没有固定地址,也不适合承担权限管理和代码审查。于是团队通常放置一个全天在线、地址稳定的远程仓库作为交换枢纽。
这带来三个结论:
- Git 本身是分布式版本控制系统,GitHub、Gitee 等是托管 Git 仓库并提供协作能力的平台。
- 每个克隆都拥有自己的本地分支和历史;远程平台不是 Git 原理上的"唯一真本"。
- 团队仍会通过权限、备份、流水线和发布制度,把某个远程仓库定义为协作基准。
远程仓库最大的价值不只是"存一份代码",还包括成员权限、Issue、Pull Request、Review、分支保护、制品和流水线等协作能力。
二、创建远程仓库:成员、Issue、PR 与权限
2.1 建库时先决定什么
创建远程仓库时,至少要先确定:
- 仓库可见性:公开还是私有。
- 默认分支:
main或master。 - 是否初始化
README.md、.gitignore、许可证。 - 谁能读、谁能推送、谁能审查、谁能管理。
- 稳定分支是否禁止直接推送。
如果远端已经用 README 创建了第一次提交,本地又单独 git init 并提交了一套无共同祖先的历史,第一次合并会变得麻烦。新手最省心的选择通常是二选一:要么先建远端再 clone,要么先有本地仓库,再创建空远端并添加 URL。
2.2 Issue 是"问题单",PR 是"变更申请"
Issue 适合记录缺陷、需求、讨论和跟踪信息。一份清楚的问题单至少要回答:
- 发生了什么?
- 怎样稳定复现?
- 期望结果是什么?
- 实际错误信息、版本和环境是什么?
Pull Request,简称 PR,可以理解为"请把我的这组提交合入目标分支"。它不是另一个 Git 提交命令,而是托管平台围绕分支差异建立的评审流程。一个合格的 PR 通常说明:
- 改了什么,为什么改。
- 从哪条源分支合入哪条目标分支。
- 怎样测试,测试结果如何。
- 是否引入依赖、配置或兼容性变化。
- 审查者需要重点关注哪些风险。
正确的权限设计不是让所有人都能直接改稳定分支,而是让开发者推送功能分支,再由具备权限的人评审和合并 PR。这样,代码作者、审查者和发布责任人形成可追踪的责任链。
三、HTTPS、SSH、origin 和远程跟踪分支
3.1 HTTPS 与 SSH 怎么选
HTTPS 地址直观,适合刚开始使用或需要通过浏览器式凭证登录的场景:
bash
# 通过 HTTPS 地址克隆远程仓库,并在当前目录生成项目文件夹
git clone https://example.com/team/project.git
SSH 适合长期、频繁地与远端交互。它使用密钥对证明身份:公钥可以交给平台,私钥只能留在自己的机器上。
bash
# 首选现代密钥类型
ssh-keygen -t ed25519 -C "you@example.com"
# 老旧环境不支持 Ed25519 时再考虑 RSA
ssh-keygen -t rsa -b 4096 -C "you@example.com"
生成后,通常把带 .pub 后缀的公钥内容添加到托管平台。不要上传或发送不带 .pub 的私钥文件。
bash
# 通过 SSH 地址克隆远程仓库;前提是公钥已经添加到托管平台
git clone git@example.com:team/project.git
HTTPS 和 SSH 解决的是"怎样连接、怎样认证",不会改变 Git 的提交、分支和合并原理。
3.2 origin 只是一个远程名称
克隆后先看远程配置:
bash
# 只列出已经配置的远程名称,克隆得到的远程通常叫 origin
git remote
# 同时显示每个远程用于 fetch 和 push 的 URL
git remote -v
# 查看 origin 的详细信息,包括跟踪分支与远端分支状态
git remote show origin
常见输出类似:
console
origin git@example.com:team/project.git (fetch)
origin git@example.com:team/project.git (push)
这里的 origin 是 Git 自动为克隆来源创建的默认远程名,可以改名,也可以同时配置多个远程。它不是分支,更不是"云端"的同义词。
如果不是通过 clone 得到本地仓库,可以手动关联:
bash
# 把给定 URL 登记为名叫 origin 的远程
git remote add origin git@example.com:team/project.git
3.3 master、origin/master 和远端 master
这三个名字必须分开:
master:本地分支,可以直接提交。- 远端的
master:远程仓库里真正的分支。 origin/master:保存在本地的远程跟踪引用,记录"上次与 origin 通信时,我看到远端 master 在哪里"。
origin/master 不是一个适合日常直接提交的本地开发分支。执行 fetch 后,它会跟着远端状态更新;但本地 master 是否移动,取决于后续是否合并、变基或快进。
四、clone、fetch、pull、push 到底改变了什么

4.1 clone:第一次把整个项目带回本地
git clone 通常会完成几件事:
- 创建本地仓库。
- 下载提交对象与引用。
- 添加名为
origin的远程配置。 - 创建远程跟踪引用。
- 检出远端默认分支对应的本地分支。
因此,clone 不是"只下载一个文件夹",而是建立后续同步关系的起点。Git 官方对克隆行为的完整说明可查看 git-clone 文档。
4.2 push:把一条本地引用更新到远端
完整写法能够暴露 push 的本质:
bash
# 把本地 master 推送到 origin 上的 master;冒号两侧分别是本地源分支和远端目标分支
git push origin master:master
冒号左边是本地来源分支,右边是远端目标分支。两边同名时可以缩写:
bash
# 本地与远端分支同名时,可以省略冒号右侧的 master
git push origin master
新分支第一次推送时,建议顺便建立上游关系:
bash
# 第一次推送 feature-1,并用 -u 建立本地分支与 origin/feature-1 的上游关系
git push -u origin feature-1
之后当前分支通常可以直接使用 git push 和 git pull。-u 的核心作用是记录当前本地分支所跟踪的远程分支,不是让提交"更完整"。更详细的引用映射规则见 git-push 文档。
4.3 fetch:只更新我对远端的认识
bash
# 下载 origin 的新提交并刷新远程跟踪引用,但不修改当前工作区
git fetch origin
fetch 会下载远端新对象并更新 origin/* 等远程跟踪引用,但不会自动把这些改动写进当前工作区。它适合"先看看别人改了什么,再决定怎样整合"。
bash
# 用图形化单行日志查看所有本地分支和远程跟踪引用的提交关系
git log --oneline --graph --decorate --all
# 比较当前提交 HEAD 与 origin/dev 之间的文件差异
git diff HEAD..origin/dev
4.4 pull:先获取,再整合
bash
# 从 origin 获取 dev,并把它整合到当前所在的本地分支
git pull origin dev
可以先建立这样的基础直觉:pull = fetch + integrate。但"integrate"不永远等于创建一次 merge 提交。根据参数和配置,它可能快进、合并、变基,或者在只允许快进时拒绝继续:
bash
# 只允许快进更新;一旦本地与远端已经分叉就停止
git pull --ff-only
# 明确使用 merge 方式整合远端历史
git pull --no-rebase
# 获取远端提交后,把本地提交变基到远端最新提交之上
git pull --rebase
如果团队没有明确约定,新手不要随意混用三种策略。先 fetch,查看提交图,再显式选择 merge,往往更容易理解发生了什么。Git 官方当前把 pull 描述为"先 fetch,再把所选远程分支整合进当前分支",详见 git-pull 文档。
五、.gitignore、别名与标签
5.1 .gitignore 是筛选未跟踪文件,不是删除器
例如下面的规则会忽略所有 .so 和 .ini 文件,但重新允许 c.so:
gitignore
# 可以直接写文件名
*.so
*.ini
!c.so
常见规则直觉:
*.so:任意层级下以.so结尾的文件。/build/:只匹配仓库根目录的build目录。temp/:匹配任意层级中名为temp的目录。!c.so:对前面的忽略规则做例外处理。- 以
#开头:注释。
不知道某文件为什么被忽略时,不要猜,直接查规则来源:
bash
# 显示究竟是哪一条 .gitignore 规则忽略了指定文件
git check-ignore -v path/to/file
git add -f 可以强制添加被忽略文件,但它应当是经过判断后的例外,而不是日常习惯。更关键的一点是:.gitignore 主要影响尚未被 Git 跟踪的路径。一个文件如果已经提交过,仅仅把它写进 .gitignore 并不会让 Git 停止跟踪;通常还要执行:
bash
# 只把文件从 Git 索引中移除,保留工作区里的实体文件
git rm --cached path/to/file
# 提交"停止跟踪该生成文件"这一索引变化
git commit -m "stop tracking generated file"
规则细节见 gitignore 官方文档。
5.2 别名是效率工具,不是新命令
bash
# 创建全局别名:以后 git st 等价于 git status
git config --global alias.st status
# 创建全局别名:以后 git lg 显示带分支关系的单行提交图
git config --global alias.lg "log --oneline --graph --decorate --all"
此后可以使用:
bash
# 使用刚才配置的 st 别名查看工作区状态
git st
# 使用刚才配置的 lg 别名查看完整提交图
git lg
省略 --global 时,配置通常只作用于当前仓库。学习阶段建议先掌握完整命令,再引入少量统一别名,否则排错时容易不知道别名背后真正执行了什么。
5.3 tag 是给某个提交起稳定版本名
轻量标签只是一个指向提交的名字:
bash
# 在当前提交上创建一个名为 v1.0.0 的轻量标签
git tag v1.0.0
附注标签会保存标签作者、时间和说明,更适合正式发布:
bash
# 在当前提交上创建带说明信息的附注标签
git tag -a v1.0.0 -m "release v1.0.0"
# 查看该标签指向的提交以及附注信息
git show v1.0.0
标签默认不会随着普通 git push 自动全部上传:
bash
# 只把 v1.0.0 这一枚标签推送到 origin
git push origin v1.0.0
# 把本地尚未推送的所有标签一次性推送到 origin
git push origin --tags
删除本地和远端标签:
bash
# 删除本地的 v1.0.0 标签
git tag -d v1.0.0
# 删除 origin 上的同名远端标签
git push origin --delete v1.0.0
也可以为旧提交打标签:
bash
# 在指定的历史提交上创建 v0.9.0 附注标签,而不是默认标记当前 HEAD
git tag -a v0.9.0 -m "historical release" <commit-id>
附注标签与轻量标签的差异可继续查阅 git-tag 文档。
六、同一开发分支上的两人协作

假设甲、乙都在远端 dev 上协作。甲先提交并推送了 aaa,乙的本地却已经基于旧提交写好了 bbb。
甲的操作:
bash
# 切换到本地 dev 分支,后续提交都会记录在 dev 上
git switch dev
# 把 file.txt 当前内容加入暂存区
git add file.txt
# 把暂存区内容提交为一条本地历史,提交说明为 add aaa
git commit -m "add aaa"
# 把本地 dev 的新提交推送到 origin 的 dev
git push origin dev
乙如果直接推送,常见结果是:
console
! [rejected] dev -> dev (non-fast-forward)
6.1 为什么被拒绝
远端 dev 已经包含甲的新提交,而乙的本地 dev 不包含它。如果允许乙直接更新远端,甲的提交可能从分支可达历史中消失,所以服务器拒绝这次非快进更新。
推送被拒绝不等于已经发生冲突。 它只说明远端存在乙尚未整合的提交。乙先获取并整合:
bash
# 先下载 origin 的最新提交,并刷新本地的 origin/dev
git fetch origin
# 再把 origin/dev 合入当前分支;有重叠修改时可能出现冲突
git merge origin/dev
如果甲和乙改的是不同位置,Git 可能自动合并成功;只有当两边的修改重叠、Git 无法自动判断保留哪一边时,才会产生内容冲突。
6.2 解决冲突的标准动作
先查看状态:
bash
# 查看当前分支、未提交修改和所有待解决的冲突文件
git status
冲突文件中常见标记如下:
console
<<<<<<< HEAD
乙的本地修改
=======
甲已经推到远端的修改
>>>>>>> origin/dev
我需要手工编辑成真正想保留的结果,并删除这些标记,然后执行:
bash
# 把已经手工解决冲突的 file.txt 重新加入暂存区
git add file.txt
# 提交最终的冲突解决结果
git commit -m "resolve conflict between aaa and bbb"
# 把包含双方修改的新 dev 历史推送到 origin
git push origin dev
如果发现整合方向不对、暂时不想处理,可以在合并未完成时撤销:
bash
# 放弃当前尚未完成的 merge,恢复到合并开始前的状态
git merge --abort
6.3 同分支协作能用,但成本更高
多人共享 dev 的优点是分支少、流程直观;缺点是大家的半成品互相可见,推送失败和集成风险更集中。小型练习可以这样做,真实团队通常更倾向"一项功能一条分支"。
当 dev 达到合入条件时,先让它吸收目标分支的最新变化并完成验证,再通过 PR 合入受保护的 master。不要为了省一步而让所有人直接推稳定分支。
七、功能分支协作与 Pull Request

7.1 从最新基线创建功能分支
先刷新远端状态,再从明确的远程基线创建本地分支:
bash
# 刷新 origin/master,确保新分支基于远端最新状态
git fetch origin
# 从 origin/master 创建本地 feature-1,并暂时建立跟踪关系
git switch -c feature-1 --track origin/master
开发、提交并第一次推送:
bash
# 把 function1 的修改加入暂存区
git add function1
# 在本地 feature-1 上提交功能 1
git commit -m "finish feature 1"
# 第一次推送 feature-1,同时把上游设置为 origin/feature-1
git push -u origin feature-1
另一位开发者可以独立处理 feature-2。两条分支互不覆盖,即使其中一条功能延期,也不会阻挡另一条进入评审。
7.2 帮同事继续一条已有功能分支
协作者先刷新并创建跟踪分支:
bash
# 下载远端最新引用,确保本地能够找到 origin/feature-2
git fetch origin
# 从 origin/feature-2 创建同名本地分支并建立跟踪关系
git switch -c feature-2 --track origin/feature-2
完成修改后正常提交、推送。原负责人再次工作前,通过 fetch/pull 获取协作者的提交。判断跟踪关系可用:
bash
# 查看所有本地分支当前提交,以及各自跟踪的远程分支
git branch -vv
显式写 git push origin feature-2 即使没有上游关系也能工作;而省略远程名和分支名的短命令,依赖当前分支已经配置正确 upstream。
7.3 发起 PR 前先同步目标分支
PR 快结束时才发现冲突,代价往往最高。更稳妥的做法是在功能分支内先整合最新目标分支:
bash
# 切换到准备提交 PR 的 feature-1
git switch feature-1
# 刷新 origin/master,避免拿旧的目标分支做合并
git fetch origin
# 把最新 origin/master 合入 feature-1,并在功能分支上提前解决冲突
git merge origin/master
在 feature-1 上解决冲突、测试并推送,然后发起 PR:
console
feature-1 → master
这样风险留在功能分支,不会让受保护的 master 长时间处于冲突处理中。PR 的合理检查链路是:
console
提交说明 → 代码差异 → 自动化检查 → 人工 Review → 测试结论 → 合并
合并完成后再删除远端和本地临时分支:
bash
# 删除 origin 上已经合并完成的 feature-1
git push origin --delete feature-1
# 安全删除本地 feature-1;若它尚未合并,-d 会拒绝删除
git branch -d feature-1
-d 会在分支未被合并时保护我;-D 是强制删除,只有确认提交不再需要时才使用。
八、远程分支删除后,为什么本地还能看见
远端分支被删除后,本地的 origin/feature-1 可能仍然存在,因为它只是上一次通信留下的远程跟踪引用。先查看远程状态:
bash
# 查看 origin 的 URL、跟踪关系,以及哪些远程跟踪引用已经失效
git remote show origin
清理失效引用:
bash
# 清理本地已经失效的 origin/* 引用,不会删除服务器上的真实分支
git remote prune origin
或者每次获取时顺便清理:
bash
# 获取 origin 的最新历史,并同时清理已经在远端删除的跟踪引用
git fetch --prune origin
必须分清三件事:
git push origin --delete feature-1:删除远端真实分支。git remote prune origin:删除本地已经失效的origin/*引用。git branch -d feature-1:删除本地分支。
prune 不会替我删除远端分支,也不会自动删掉本地开发分支。官方语义可核对 git-remote 文档。
九、从 DevOps 到开发、测试、预发布和生产环境
DevOps 不是某一个软件,也不是"开发人员顺便负责服务器"。它是一组文化、实践与工具组合,目标是让开发和运维围绕同一条交付链合作,用自动化降低交接损耗,让变更更频繁、可重复、可观察、可回滚。
一条常见的软件交付链可以概括为:
console
计划 → 编码 → 构建 → 测试 → 发布 → 部署 → 运行与反馈
Git 主要解决代码与配置的版本历史问题;构建、测试、制品、部署、监控和告警仍需要 CI/CD 与运维体系配合。

9.1 四类环境各自负责什么
- 开发环境:频繁修改、自测和联调,允许较快迭代。
- 测试环境:执行功能测试、回归测试和缺陷验证。
- 预发布环境:尽量贴近生产,用于验收、容量验证和发布演练。
- 生产环境:面向真实用户,稳定性、安全和可恢复性优先。
环境必须隔离,但不代表每个环境重新手工构建一次代码。更可靠的思路是:同一份已构建制品逐级晋升,环境差异通过外置配置处理。 这样能减少"测试通过的不是最终上线那一份"的风险。
灰度或金丝雀发布则在正式扩大流量前,让少量用户先验证新版本。指标正常就逐步扩大,异常就快速回滚。它解决的是发布风险控制,不等同于 Git 分支本身。
十、Git Flow:开发、发布与线上热修复

Git Flow 用不同分支承担不同生命周期责任:
10.1 两条长期分支
master:生产稳定线,发布点通常打 tag,并通过平台策略保护。develop:日常集成线,承接已经完成的功能。
"长期""受保护"是团队约定与托管平台策略,不是 Git 自动赋予这些名字的魔法。
10.2 三类临时分支
功能分支 feature/*
从 develop 创建,完成后通过 PR 合回 develop:
bash
# 切换到作为日常集成线的 develop
git switch develop
# 只在能够快进时更新 develop,避免意外产生合并提交
git pull --ff-only
# 从最新 develop 创建 feature/login 功能分支并立即切换过去
git switch -c feature/login
发布分支 release/*
当一批功能准备进入测试和发布收口时,从 develop 创建。这里只接受发布相关修正,不继续塞入不确定的新功能。验证完成后,通常同时合入 master 和 develop,并在稳定分支打版本标签。
热修复分支 hotfix/*
生产出现紧急问题时,从当前 master 创建。修复验证后同时回到 master 和 develop,避免线上修复在下一版本中再次丢失。
10.3 一次正常发布的路径
console
feature/* → develop → release/* → master → tag
└────────→ develop(回合修正)
10.4 一次线上紧急修复的路径
console
master → hotfix/* → master → tag
└→ develop
Git Flow 适合有明确发布窗口、多环境验收和版本维护要求的团队,但它并不是唯一答案。持续部署团队可能选择更短的主干开发流程;小团队也可能只用稳定分支加短生命周期功能分支。分支越多,管理和回合成本越高,模型应服务于交付风险,而不是追求形式复杂。
十一、AoneFlow:按环境组合功能
传统 Git Flow 的发布路径相对固定。当多个功能需要在不同环境独立验证、组合上线时,可以进一步考虑 AoneFlow 的思路。

AoneFlow 常被概括为 feature + n×release + master:
feature/*独立承载功能。- 多条
release/*分别服务不同环境或发布组合。 - 每条 release 按需要合入若干 feature,而不是所有功能被迫一起前进。
master保存稳定发布基线,下一轮功能从最新基线开始。
它解决的核心问题是"功能组合",不是发明了新的 Git 命令。例如功能 A 可以进入测试环境,功能 B 只进入开发环境,功能 C 因风险暂不上线;不同 release 分支承载不同组合,验证通过的组合再进入稳定线。
这种灵活性也会带来更高治理要求:功能最好具备独立开关,自动化测试要足够可靠,团队必须严格控制合入路径与分支权限。否则,多条 release 很容易演变成难以追踪的长期分叉。
更完整的背景和原始方案可以阅读 AoneFlow 实践文章。这里最值得带走的不是分支名,而是"让分支结构匹配环境与发布组合"的设计思路。
十二、企业研发空间、项目与代码仓库的边界

企业级平台通常不只管理 Git 仓库,而是形成三层结构:
- 企业空间:成员、组织、全局权限和统一规范的顶层边界。
- 项目:需求、任务、迭代、测试和交付的协作边界。
- 代码仓库:源代码、提交、分支、Issue、PR、Review 和 Tag 的版本管理边界。
一个企业空间可以包含多个项目,一个项目也可能关联前端、后端、部署配置等多个代码仓库。因此,"项目"和"仓库"不是同义词。
常见职责也应分开:
- 组织管理员管理成员、权限和统一策略。
- 项目负责人协调范围、迭代、质量与发布节奏。
- 开发者通过功能分支、提交、PR 和 Review 交付变更。
具体菜单会随平台版本变化,但这些抽象相对稳定。想观察当前平台怎样实现项目、流水线和企业空间,可以继续查看 Gitee 企业版、CODING 与 阿里云云效。不要把任一平台的页面布局误当成 Git 本身的规则。
十三、一套可直接落地的协作流程
13.1 第一次加入项目
bash
# 克隆远程项目;把占位符替换成真实的 HTTPS 或 SSH 地址
git clone <repository-url>
# 进入 clone 自动创建的项目目录;这不是 Git 命令
cd <repository-directory>
# 核对 fetch 与 push 使用的远程地址
git remote -v
# 列出本地分支和远程跟踪分支
git branch -a
# 确认当前分支以及工作区是否干净
git status
先确认远程地址、默认分支和工作区状态,再开始修改。
13.2 开始一个功能
bash
# 回到本地稳定分支 master
git switch master
# 从 origin/master 快进更新本地 master;分叉时会停止
git pull --ff-only origin master
# 从更新后的 master 创建并切换到 feature/login
git switch -c feature/login
小步提交:
bash
# 把这次功能涉及的文件加入暂存区;占位符要换成真实路径
git add <changed-files>
# 在本地功能分支创建一条说明清楚的提交
git commit -m "implement login validation"
# 第一次推送功能分支,并建立 origin/feature/login 上游关系
git push -u origin feature/login
13.3 准备 PR
bash
# 获取 origin 的最新提交和引用,但暂不修改当前工作区
git fetch origin
# 把最新目标分支 origin/master 合入当前功能分支
git merge origin/master
# 解决冲突并完成测试
# 把更新后的当前功能分支推送到它已经配置好的上游分支
git push
然后在平台发起 feature/login → master 的 PR,写清变更目的、测试方法和风险点,等待自动检查与 Review。
13.4 合并后收尾
bash
# PR 合并后切回本地 master
git switch master
# 快进获取刚刚合入 master 的远端提交
git pull --ff-only origin master
# 安全删除已经合并完成的本地功能分支
git branch -d feature/login
# 刷新 origin 并清理远端已删除分支留下的本地跟踪引用
git fetch --prune origin
发布时再按团队规范创建附注标签:
bash
# 在当前发布提交上创建带说明的 v1.2.0 附注标签
git tag -a v1.2.0 -m "release v1.2.0"
# 把 v1.2.0 标签单独推送到 origin
git push origin v1.2.0
13.5 每次操作前的五秒检查
我会先问自己五个问题:
- 我现在在哪条本地分支?
- 工作区是否干净?
- 当前分支跟踪哪个远程分支?
- 远端是否已经有别人提交的新历史?
- 这次变更应该直接推送,还是必须走 PR?
对应命令:
bash
# 确认当前分支、未提交修改和冲突状态
git status
# 查看本地分支各自跟踪哪个远程分支
git branch -vv
# 核对远程名称及 fetch、push 地址
git remote -v
# 刷新远端状态并清理过期的 origin/* 引用
git fetch --prune origin
# 用提交图检查各分支是否分叉以及 HEAD 当前所在位置
git log --oneline --graph --decorate --all
十四、常见误区与排错顺序
误区一:commit 之后同事就能看见
不能。commit 只进入本地仓库;还要把对应分支 push 到双方约定的远端。
误区二:origin/master 就是服务器上的分支
不是。它是本地保存的远程跟踪引用。远端真实分支是远端仓库里的 master。
误区三:pull 永远等于 fetch + merge
这是方便入门的近似。现代 Git 可以根据参数或配置采用快进、merge、rebase 等整合方式。团队应统一策略。
误区四:push 被拒绝就一定要解决冲突
不一定。被拒绝先说明不是快进更新;获取远端提交后,如果双方修改不重叠,Git 可以自动整合。
误区五:写进 .gitignore,已经提交的文件就会消失
不会。已跟踪文件需要先从索引停止跟踪,并提交这次变化。
误区六:git remote prune origin 会删除服务器分支
不会。它清理的是本地失效的远程跟踪引用。删除远端分支要用 git push origin --delete <branch>。
误区七:功能分支一定要先在网页上创建
不一定。从最新 origin/master 或 origin/develop 在本地创建,再用 git push -u 推送,同样可以获得清楚、安全的起点。
误区八:Git Flow 越完整,团队越专业
不成立。模型越复杂,维护成本越高。发布频率、团队规模、测试能力和监管要求才决定需要多少分支。
排错顺序
遇到远程协作问题时,我按这个顺序检查:
bash
# 查看当前分支、冲突和未提交修改
git status
# 查看本地分支与 upstream 的对应关系
git branch -vv
# 检查远程名称和 URL 是否正确
git remote -v
# 下载远端新提交,同时清理失效的远程跟踪引用
git fetch --prune origin
# 展示所有分支的提交图,判断历史从哪里发生分叉
git log --graph --oneline --decorate --all
如果是认证失败,再检查 HTTPS 凭证或 SSH 公钥;如果是推送拒绝,再看提交图是否分叉;如果是 PR 无法合并,再在源分支内整合最新目标分支。按状态、关系、远端、历史的顺序排查,比反复强推安全得多。
十五、总结
Git 远程协作的难点不在命令数量,而在于始终知道"哪个名字位于哪里、哪条历史正在移动"。master 是本地分支,origin/master 是本地保存的远程视图,远端还有一条真实的 master;fetch 只刷新视图,pull 获取并整合,push 尝试更新远端引用。
进入多人开发后,稳定分支不应依赖每个人都小心,而应依赖功能分支、PR、Review、测试和权限共同保护。再向企业交付推进,环境隔离、版本标签、release 与 hotfix 才把"代码写完"连接到"版本可靠上线"。
最终我会记住一句话:分支模型没有绝对最佳答案,只有是否与团队的发布风险、协作规模和自动化能力匹配。