分支与远程:协作的基础
什么是分支
回到游戏存档的比喻:
你在某个时间节点选择了两条不同的剧情分支,每条分支各自发展,互不影响。最后你可以决定把某个分支的结果合并到主线。
在 Git 中,分支(branch) 就是从某个提交点开辟的独立开发线路。
为什么要用分支?
- 开发新功能时不影响主线(main 分支)的稳定性
- 多人并行开发不同功能
- 安全地实验新想法,不满意直接删掉分支
main: A --- B --- C ------------------- G
\ /
feature: D --- E --- F ----
git branch — 管理分支
# 查看所有本地分支(* 号表示当前所在分支)
git branch
# 查看所有分支(包括远程分支)
git branch -a
# 创建一个新分支(但不切换过去)
git branch feature-pid
# 删除分支(已合并的分支)
git branch -d feature-pid
# 强制删除分支(未合并也删,谨慎使用!)
git branch -D feature-pid
# 重命名当前分支
git branch -m new-name
git switch — 切换分支
# 切换到已有分支
git switch feature-pid
# 创建并切换到新分支(最常用!)
git switch -c feature-sensor
# 切换到上一个分支(类似 cd -)
git switch -
注意:切换分支前,建议先提交或储藏(stash)当前改动,否则 Git 可能会拒绝切换。
git merge — 合并分支
# 将 feature-pid 合并到当前分支(通常在 main 上操作)
git switch main # 先切换到目标分支
git merge feature-pid # 把 feature-pid 合并进来
合并时有三种结果:
快进合并(Fast-forward):没有冲突,直接移动指针,最干净
合并前:main: A-B feature: A-B-C-D 合并后:main: A-B-C-D三方合并(3-way merge):两个分支都有新提交,Git 自动合并
合并前:main: A-B-E feature: A-B-C-D 合并后:main: A-B-E-C-D-M(M 是合并提交)冲突(Conflict):两个分支修改了同一文件的同一部分,需要手动解决
处理合并冲突
当两人修改了同一文件的同一行,Git 不知道该保留谁的版本,会产生冲突:
git merge feature-sensor
# 输出:CONFLICT (content): Merge conflict in motor.c
# Automatic merge failed; fix conflicts and then commit the result.
打开冲突文件 motor.c,会看到 Git 自动插入的标记:
<<<<<<< HEAD // 当前分支(main)的内容
int motor_speed = 100;
int motor_speed = 150;
>>>>>>> feature-sensor // 被合并分支的内容
解决步骤:
- 手动编辑文件,保留正确的内容
- 删除
<<<<<<<、=======、>>>>>>>标记 - 保存文件
git add motor.c(告诉 Git 这个冲突已经解决)git commit(完成合并)
// 解决冲突后的文件(手动决定保留哪个版本)
int motor_speed = 150; // 保留 feature-sensor 的值
- 现在很多编辑器(VS Code、JetBrains 等)都有图形化的冲突解决界面,会更友好。
- 解决完所有冲突后,一定要 git add 对应文件,否则无法继续。
git rebase — 变基(整理提交历史)
Rebase 是另一种整合分支变更的方式,让提交历史更整洁:
# 在 feature 分支上,把它的基础从旧的 main 移到最新的 main
git switch feature-pid
git rebase main
rebase 前:
main: A-B-E
feature: A-B-C-D
rebase 后:
main: A-B-E
feature: A-B-E-C'-D' ← D 和 E 被"重新播放"到 C 之后
初学者建议:先掌握
merge,rebase等熟练后再使用。团队协作中,已推送到远程的分支不要 rebase!
Mav's Tips:
这里你可能觉得三方合并和rebase很像 的确,一个最后是A-B-E-C-D-M,另一个是A-B-E-C'-D'
但二者有本质区别:
三方合并时: Git 创建了一个新的合并提交 M,这个 M 把 E(main 的修改)和 C、D(feature 的修改)融合在一起。 最终主分支的代码是以 M 为准,包含了 main 和 feature 的所有修改(这正是我们合并的目的)。 同时分支依然存在,C和D看起来是在E的前面,但并不包含任何E的修改,只有M有。 这样的好处是,历史是完整的,你随时可以回退到纯 feature 分支的状态(只有 C 和 D),不受 main 的干扰。
Rebase(变基): 它把 feature 分支的提交 C 和 D “剪下来”,重新应用到最新的 main(E)后面,生成新的提交 C' 和 D'。 这样历史是比较干净,但重写了时间线,再也不能回到只有C,D修改的版本了,C,D已经变成C',D',哈希值被改变,内容也变成了“在 E 的基础上再加上原来的修改”。 (代码层面看不出什么不一样,但git管理层面有代价,不可回退)
GitHub 简介
GitHub 是目前最大的代码托管平台,基于 Git。你可以把它理解为:
- 代码的网盘:把本地 Git 仓库同步到云端,防止丢失
- 协作平台:多人共同开发同一个项目
- 代码展示平台:个人项目组合(Portfolio)
- showoff平台:(bushi)
git clone — 克隆远程仓库
git clone 是最基础的指令之一:
# 克隆公开仓库(HTTPS 方式,不需要登录)
git clone https://github.com/用户名/仓库名.git
# 克隆私有仓库或推送代码(SSH 方式,更推荐)
# 假设你前面配置了SSH密钥,那这里就使用这个方式
git clone [email protected]:用户名/仓库名.git
# 克隆到指定文件夹名
git clone [email protected]:用户名/仓库名.git my-folder
# 只克隆最近1次提交,节省时间(适合大型项目)
git clone --depth=1 [email protected]:用户名/仓库名.git
git clone 做了哪些事?
- 下载仓库所有文件和历史记录
- 自动设置远程连接(名为
origin) - 创建并切换到默认分支(通常是
main)
git remote — 管理远程连接
# 查看远程仓库配置
git remote -v
# 输出示例:
# origin [email protected]:yourname/project.git (fetch)
# origin [email protected]:yourname/project.git (push)
# 添加远程仓库(本地 init 后手动关联远程)
git remote add origin [email protected]:yourname/project.git
# 修改远程仓库的 URL(比如从 HTTPS 换成 SSH)
git remote set-url origin [email protected]:yourname/project.git
# 删除远程连接
git remote remove origin
git push — 推送到远程
# 将当前分支推送到 origin 远程
git push origin main
# 第一次推送分支,设置上游(之后可以直接 git push)
git push -u origin main
# 设置好上游后,直接推送
git push
# 推送所有本地分支
git push --all origin
# 推送标签
git push origin --tags
推送失败的常见原因:
# 错误:远程有你没有的提交(之前说的三方合并)
# error: failed to push some refs to 'github.com:...'
# hint: Updates were rejected because the remote contains work...
# 解决:先拉取,再推送
git pull origin main
git push origin main
git fetch 与 git pull — 从远程获取
# git fetch:只下载远程变化,不自动合并(安全)
git fetch origin
# 之后你可以查看远程改动再决定是否合并
git log origin/main --oneline # 查看远程 main 分支的新提交
# git pull:下载 + 自动合并(= fetch + merge)
git pull origin main
# 设置上游后可以简写
git pull
推荐日常工作流:
# 每天开始工作前,先拉取最新代码
git pull
# 做你的修改...
# 工作结束,提交并推送
git add . # 存到暂存区
git commit -m "feat: 完成今日功能" # 记录修改
git push
GitHub 的 Pull Request(PR)
PR 是 GitHub 上的核心协作机制:
- 你的代码不能直接推送到别人的仓库(没有权限)
- 你需要先 Fork(复制)对方的仓库到你的账号下
- 在你的 Fork 上修改后,发起 Pull Request,请求对方合并你的改动
- 对方审查(Code Review)、讨论、通过后合并
原始仓库(RoboGame-Team/control)
│
│ Fork
▼
你的仓库(YourName/control)
│
│ git clone
▼
本地修改
│
│ git push
▼
你的仓库(YourName/control)
│
│ Pull Request
▼
原始仓库 ← 等待审查合并
git tag — 标签
# 创建轻量标签
git tag v1.0
# 创建附注标签(包含更多信息,推荐)
git tag -a v1.0 -m "第一个正式发布版本"