MocLab

本机

站点

你真的会用Fork和分支吗

从本地仓库、origin 与 upstream 的关系出发,梳理 Fork 同步、分支隔离、Merge 与常见协作流程。

分类
工具
发布
阅读时间
约 12 分钟
目录23 节
  1. 1. 先分清楚:本地仓库、自己的远程仓库、原始远程仓库
  2. 2. Fork 之后,原仓库更新会自动同步吗?
  3. 3. Fork 的更新是同步到 GitHub 里,还是同步到本地里?
  4. 4. Clone 是什么?
  5. 5. Fork 和 Clone 的区别
  6. 6. Branch 分支是什么?
  7. 7. 分支 A 和分支 B 的文件会互相影响吗?
  8. 8. 如果 A 和 B 都修改了公共文件 n,会怎样?
    1. 情况一:修改的是 n 文件的不同位置
    2. 情况二:修改的是 n 文件的同一位置
  9. 9. Merge 到底是合并到哪个分支?
  10. 10. 要不要单独搞一个分支作为主分支?
  11. 11. Fork 之后,自己的远程仓库是不是 main 分支?
  12. 12. 自己要不要搞一个 self 分支?
  13. 13. Fork 项目的推荐工作流
    1. 第一步:Fork
    2. 第二步:Clone 自己的 fork
    3. 第三步:添加原始仓库 upstream
    4. 第四步:保持 main 干净
    5. 第五步:从 main 新建功能分支
    6. 第六步:提交修改
    7. 第七步:推送到自己的 fork 仓库
    8. 第八步:发起 Pull Request
  14. 14. 合并 Pull Request 是合并到哪里?
  15. 15. 常见命令总结
    1. 查看当前状态
    2. 查看当前分支
    3. 查看所有分支,包括远程分支
    4. 新建并切换分支
    5. 切换分支
    6. 查看远程仓库
    7. 添加 upstream
    8. 从远程获取更新,但不自动合并
    9. 拉取并合并远程更新
    10. 合并分支
    11. 推送分支到远程
    12. 删除本地分支
    13. 删除远程分支
  16. 16. fetch、pull、merge 的区别
    1. fetch
    2. merge
    3. pull
  17. 17. rebase 是什么?和 merge 有什么区别?
  18. 18. 一个很常见的场景:原仓库更新了,我的分支怎么办?
  19. 19. 最容易搞混的几个问题
    1. 问题 1:fork 后原仓库更新会同步到我的 fork 吗?
    2. 问题 2:GitHub 上同步了 fork,本地会自动更新吗?
    3. 问题 3:我在 A 分支改文件,会影响 B 分支吗?
    4. 问题 4:两个分支都改了同一个公共文件,会怎样?
    5. 问题 5:merge 是合并到哪个分支?
    6. 问题 6:fork 后我应该直接在 main 上改吗?
    7. 问题 7:要不要创建 self 分支?
  20. 20. 推荐的安全习惯
    1. 习惯一:动手前先看状态
    2. 习惯二:不要直接在 main 上开发
    3. 习惯三:每个功能一个分支
    4. 习惯四:提交信息写清楚
    5. 习惯五:PR 前先同步主分支
  21. 21. 一张图理解完整流程
  22. 22. 最推荐的新手工作流
  23. 23. 最核心的一句话总结

很多人一开始学 Git 和 GitHub 的时候,会把 clone、fork、branch、merge、pull request 混在一起。它们确实经常一起出现,但本质上是不同层次的东西。 简单来说:

  • clone:把远程仓库复制到本地电脑。
  • fork:在 GitHub 上复制别人的仓库,变成你自己账号下的远程仓库。
  • branch:在同一个仓库里开一条新的开发线。
  • merge:把一个分支的修改合并到另一个分支。
  • pull request / PR:在 GitHub 上请求把你的修改合并到某个目标分支。

1. 先分清楚:本地仓库、自己的远程仓库、原始远程仓库

假设有一个开源项目:

原始仓库:
github.com/original/project

你点击 GitHub 上的 Fork 之后,会得到一个你自己账号下的仓库:

你的 Fork 仓库:
github.com/yourname/project

然后你在本地执行:

终端
git clone https://github.com/yourname/project.git

这时你电脑里会有一份本地仓库。 所以一个标准的 fork 工作流里,通常有三份仓库:

原始仓库 upstream:github.com/original/project
你的远程仓库 origin:github.com/yourname/project
你的本地仓库 local:你电脑上的 project 文件夹

其中:

  • upstream 通常表示原始仓库,也就是你 fork 的来源。
  • origin 通常表示你自己的远程仓库,也就是你 clone 下来的那个地址。
  • local 表示你电脑上的本地仓库。

2. Fork 之后,原仓库更新会自动同步吗?

不会完全自动同步。 Fork 之后,你的 GitHub 仓库是原仓库在某一时刻的副本。 比如你在 6 月 1 日 fork 了项目:

original/project 6月1日版本
yourname/project 6月1日版本

后来原始仓库在 6 月 10 日更新了:

original/project 6月10日版本
yourname/project 仍然是6月1日版本

你的 fork 仓库不会自动变成最新状态。 GitHub 页面上有时候会显示:

This branch is 5 commits behind original:main

意思是你的 fork 落后于原仓库。 你可以在 GitHub 网页上点 Sync fork 来同步,也可以在本地用命令同步。


3. Fork 的更新是同步到 GitHub 里,还是同步到本地里?

这要看你怎么操作。 如果你在 GitHub 网页上点 Sync fork,同步的是:

原始远程仓库 upstream → 你的远程仓库 origin

也就是说,GitHub 上你的 fork 更新了,但你本地电脑里的代码不会自动更新。

你还需要在本地执行:

终端
git pull

把你远程仓库的新内容拉到本地。

如果你在本地用命令同步,一般流程是:

终端
git remote add upstream https://github.com/original/project.git
git fetch upstream
git checkout main
git merge upstream/main 表示远程仓库 upstream 里的 main 分支
git push origin main

这套命令的含义是:

1. 添加原始仓库地址,命名为 upstream
2. 从 upstream 获取最新内容
3. 切换到本地 main 分支
4. 把 upstream/main 合并到本地 main
5. 把更新后的本地 main 推送到自己的 GitHub fork 仓库

这样本地和你的 GitHub fork 都会更新。


4. Clone 是什么?

clone 是把远程仓库下载到本地。 比如:

终端
git clone https://github.com/yourname/project.git

执行之后,本地会出现一个 project 文件夹。 这个文件夹不仅包含项目文件,还包含一个隐藏目录:

.git/

.git 里面保存了 Git 的版本信息、分支信息、提交历史、远程仓库地址等。 可以用下面的命令查看远程仓库地址:

终端
git remote -v

一般你会看到:

终端
origin https://github.com/yourname/project.git (fetch)
origin https://github.com/yourname/project.git (push)

这里的 origin 就是你自己的 fork 仓库。


5. Fork 和 Clone 的区别

很多人会把 fork 和 clone 搞混。 它们的区别是:

fork:发生在 GitHub 上,是复制一个远程仓库到你的 GitHub 账号下。
clone:发生在本地电脑上,是把某个远程仓库下载到本地。

举个例子:

别人仓库:original/project
点击 Fork
你的仓库:yourname/project
执行 git clone
本地仓库:电脑里的 project 文件夹

所以 fork 和 clone 通常是配合使用的:

先 fork,再 clone。

6. Branch 分支是什么?

分支可以理解成一条独立的开发线。

假设 main 分支是项目的主线:

main

你想开发一个新功能,不应该直接在 main 上乱改,而是新建一个分支:

终端
git checkout -b feature-login

这表示:

从当前分支切出一个新分支,名字叫 feature-login,并切换过去。

现在你在 feature-login 分支上改代码,不会影响 main 分支。


7. 分支 A 和分支 B 的文件会互相影响吗?

假设有两个分支:

分支 A:有 x、y、z、n 文件
分支 B:有 o、p、q、n 文件

这里 n 是公共文件。 如果你在分支 A 修改 n 文件:

A 分支的 n 被修改

此时不会影响 B 分支里的 n 文件。 因为每个分支都有自己的一套文件状态。 也就是说:

只要你还没有 merge,A 分支和 B 分支之间互不影响。

但是如果你后来把 A 合并到 B,或者把 B 合并到 A,就可能发生影响。


8. 如果 A 和 B 都修改了公共文件 n,会怎样?

情况分两种。

情况一:修改的是 n 文件的不同位置

比如:

A 分支修改了 n 文件第 10 行
B 分支修改了 n 文件第 50 行

这种情况下,Git 通常可以自动合并。

情况二:修改的是 n 文件的同一位置

比如:

A 分支修改了 n 文件第 10 行
B 分支也修改了 n 文件第 10 行

这时 Git 不知道应该保留谁的修改,就会产生冲突。 冲突文件里通常会出现类似内容:

<<<<<<< HEAD
这是当前分支的内容
=======
这是要合并进来的分支的内容
>>>>>>> branch-name

你需要手动修改成最终想要的样子,然后执行:

终端
git add n
git commit

这样冲突才算解决。


9. Merge 到底是合并到哪个分支?

这是一个非常重要的问题。 Git 的 merge 规则是:

当前你在哪个分支,merge 就是把别的分支合并到当前分支。

比如现在有两个分支:

main
feature-login

如果你执行:

终端
git checkout main
git merge feature-login

意思是:

把 feature-login 合并到 main。

如果你执行:

终端
git checkout feature-login
git merge main

意思是:

把 main 合并到 feature-login。

所以 merge 的方向不是看命令里的分支是谁,而是看你当前所在的分支是谁。 记住一句话:

git merge xxx = 把 xxx 合并到我当前所在的分支。

10. 要不要单独搞一个分支作为主分支?

通常不需要额外搞一个奇怪的“合并分支”。 一般项目结构是:

main:稳定主分支
dev:开发集成分支,可选
feature-xxx:具体功能分支
fix-xxx:修复 bug 分支

如果是个人小项目,通常这样就够了:

main
feature-xxx

开发流程:

终端
git checkout main
git pull
git checkout -b feature-login
# 修改代码
git add .
git commit -m "add login feature"
git push origin feature-login

然后在 GitHub 上发 PR,把:

feature-login → main

合并进去。 如果是多人协作,可能会有:

main:正式稳定版本
dev:日常开发整合分支
feature-a:成员 A 的功能
feature-b:成员 B 的功能

流程可能是:

feature-a → dev
feature-b → dev
dev 测试稳定后 → main

但是对于大多数个人项目或者课程项目,不需要搞得太复杂。


11. Fork 之后,自己的远程仓库是不是 main 分支?

一般是。 当你 fork 一个仓库时,你会复制原仓库的默认分支。 如果原仓库默认分支叫:

main

你的 fork 仓库默认分支通常也叫:

main

如果原仓库默认分支叫:

master

你的 fork 仓库默认分支通常也叫:

master

所以 fork 之后,你自己的远程仓库不一定必须是 main,要看原仓库默认分支叫什么。 可以用下面命令查看本地分支:

终端
git branch

查看本地和远程所有分支:

终端
git branch -a

12. 自己要不要搞一个 self 分支?

一般不建议叫 self 分支。 更推荐按照任务命名,比如:

feature-login
feature-user-page
fix-navbar-bug
docs-update-readme
experiment-model-v2

如果你是 fork 了别人的仓库,想长期保留自己的修改版本,可以有一个自己的长期分支,比如:

my-main
custom
personal

但普通协作里,更推荐:

main:和原仓库主分支保持同步
feature-xxx:自己真正开发的内容

这样更清楚。 推荐结构:

upstream/main:原始仓库主分支
origin/main:你的 fork 仓库主分支,尽量和 upstream/main 保持同步
origin/feature-xxx:你自己的开发分支
local feature-xxx:你本地的开发分支

不要长期直接在自己的 main 上乱改,否则以后同步 upstream/main 的时候容易冲突。

简单来说就是自己新建一个自己的开发分支,然后你就在自己的开发分支里改东西即可,然后源仓库有修改的话直接合并到main分支,然后再把main分支里的东西合并到你自己的开发分支


13. Fork 项目的推荐工作流

假设你 fork 了一个开源项目。

第一步:Fork

在 GitHub 页面点击 Fork。 得到:

github.com/yourname/project

第二步:Clone 自己的 fork

终端
git clone https://github.com/yourname/project.git
cd project

第三步:添加原始仓库 upstream

终端
git remote add upstream https://github.com/original/project.git

查看远程地址:

终端
git remote -v

应该看到:

origin https://github.com/yourname/project.git
upstream https://github.com/original/project.git

第四步:保持 main 干净

终端
git checkout main
git fetch upstream
git merge upstream/main
git push origin main

这一步的作用是让自己的 main 和原始仓库 main 保持一致。

第五步:从 main 新建功能分支

终端
git checkout -b feature-login

然后开始修改代码。

第六步:提交修改

终端
git status
git add .
git commit -m "add login feature"

第七步:推送到自己的 fork 仓库

终端
git push origin feature-login

第八步:发起 Pull Request

在 GitHub 页面上创建 PR:

yourname/project:feature-login
→ original/project:main

意思是:

请求把你 fork 仓库里的 feature-login 分支合并到原始仓库的 main 分支。

14. 合并 Pull Request 是合并到哪里?

PR 合并到哪里,取决于 PR 页面里选择的目标分支。

比如:

base repository: original/project
base branch: main
compare repository: yourname/project
compare branch: feature-login

这表示:

把 yourname/project 的 feature-login 合并到 original/project 的 main。

如果是你自己的项目,也可以是:

base repository: yourname/project
base branch: main
compare branch: feature-login

这表示:

把自己的 feature-login 合并到自己的 main。

所以 PR 的方向一定要看清楚:

compare → base

也就是:

你的修改分支 → 目标分支

15. 常见命令总结

查看当前状态

终端
git status

查看当前分支

终端
git branch

查看所有分支,包括远程分支

终端
git branch -a

新建并切换分支

终端
git checkout -b feature-name

或者新版本 Git 可以用:

终端
git switch -c feature-name

切换分支

终端
git checkout main

或者:

终端
git switch main

查看远程仓库

终端
git remote -v

添加 upstream

终端
git remote add upstream https://github.com/original/project.git

从远程获取更新,但不自动合并

终端
git fetch origin
git fetch upstream

拉取并合并远程更新

终端
git pull origin main

等价于:

终端
git fetch origin
git merge origin/main

合并分支

终端
git checkout main
git merge feature-name

意思是:

把 feature-name 合并到 main。

推送分支到远程

终端
git push origin feature-name

删除本地分支

终端
git branch -d feature-name

如果没有合并但强制删除:

终端
git branch -D feature-name

删除远程分支

终端
git push origin --delete feature-name

16. fetch、pull、merge 的区别

fetch

终端
git fetch upstream

意思是:

把远程仓库的新提交拿到本地,但不修改当前代码。

fetch 是比较安全的,因为它只是“下载更新信息”,不会直接动你的工作区。

merge

终端
git merge upstream/main

意思是:

把 upstream/main 合并到当前分支。

pull

终端
git pull upstream main

大致等于:

终端
git fetch upstream
git merge upstream/main

所以 pull 是 fetch + merge。

新手建议多用:

终端
git fetch
git merge

这样你更清楚发生了什么。


17. rebase 是什么?和 merge 有什么区别?

merge 是把两个分支合并起来,会保留分叉历史。

例如:

main: A---B---C
feature: \---D---E

执行 merge 后可能变成:

main: A---B---C-------M
\ /
feature: D---E----

M 是一个 merge commit。

rebase 是把你的提交“搬到”最新主分支后面。

main: A---B---C
feature: \---D---E

执行 rebase 后变成:

main: A---B---C
feature: \---D'---E'

rebase 的历史更直,但对新手来说更容易出问题。

简单建议:

个人功能分支可以 rebase。
公共分支不要随便 rebase。
新手先用 merge。

18. 一个很常见的场景:原仓库更新了,我的分支怎么办?

你正在 feature-login 分支开发,但原仓库 main 更新了。

推荐流程:

终端
git checkout main
git fetch upstream
git merge upstream/main
git push origin main

这一步先更新自己的 main。

然后切回自己的功能分支:

终端
git checkout feature-login
git merge main

意思是:

把最新 main 合并到自己的 feature-login。

这样你的功能分支就基于最新代码继续开发。

也可以用 rebase:

终端
git checkout feature-login
git rebase main

但新手可以先用 merge。


19. 最容易搞混的几个问题

问题 1:fork 后原仓库更新会同步到我的 fork 吗?

不会自动同步。你需要手动 Sync fork,或者用命令 fetch upstream 再 merge。

问题 2:GitHub 上同步了 fork,本地会自动更新吗?

不会。本地还需要 git pull。

问题 3:我在 A 分支改文件,会影响 B 分支吗?

不会。只要没有 merge,两个分支互不影响。

问题 4:两个分支都改了同一个公共文件,会怎样?

如果改的是不同位置,通常可以自动合并;如果改的是同一位置,可能出现冲突,需要手动解决。

问题 5:merge 是合并到哪个分支?

合并到你当前所在的分支。

终端
git checkout main
git merge feature-a

表示把 feature-a 合并到 main。

问题 6:fork 后我应该直接在 main 上改吗?

不推荐。更好的方式是:

main 保持和原仓库同步
feature-xxx 用来写自己的修改

问题 7:要不要创建 self 分支?

一般不需要。更推荐创建具体任务分支,比如 feature-login、fix-bug、docs-update。


20. 推荐的安全习惯

习惯一:动手前先看状态

终端
git status
git branch

确认自己在哪个分支,当前有没有未提交修改。

习惯二:不要直接在 main 上开发

推荐:

终端
git checkout main
git pull
git checkout -b feature-xxx

习惯三:每个功能一个分支

不要一个分支里同时改登录、首页、数据库、样式、文档。

更好的方式是:

feature-login
feature-homepage
fix-database-config
docs-readme

习惯四:提交信息写清楚

不要总是:

终端
git commit -m "update"

更好的写法:

终端
git commit -m "fix navbar layout on mobile"
git commit -m "add user login form"
git commit -m "update README installation steps"

习惯五:PR 前先同步主分支

终端
git checkout main
git fetch upstream
git merge upstream/main
git push origin main
git checkout feature-xxx
git merge main
git push origin feature-xxx

这样可以减少 PR 冲突。


21. 一张图理解完整流程

原始仓库 upstream
github.com/original/project
│
│ Fork
▼
你的远程仓库 origin
github.com/yourname/project
│
│ Clone
▼
你的本地仓库 local
电脑里的 project 文件夹

开发时:

upstream/main
│
│ 同步
▼
origin/main
│
│ clone / pull
▼
local/main
│
│ checkout -b
▼
local/feature-xxx
│
│ push
▼
origin/feature-xxx
│
│ Pull Request
▼
upstream/main

22. 最推荐的新手工作流

如果你 fork 了别人的项目,推荐这样做:

终端
# 1. 克隆自己的 fork
git clone https://github.com/yourname/project.git
cd project
# 2. 添加原始仓库
git remote add upstream https://github.com/original/project.git
# 3. 更新自己的 main
git checkout main
git fetch upstream
git merge upstream/main
git push origin main
# 4. 新建功能分支
git checkout -b feature-my-change
# 5. 修改代码后提交
git add .
git commit -m "add my change"
# 6. 推送到自己的 fork
git push origin feature-my-change

然后在 GitHub 上发 PR:

yourname/project:feature-my-change
→ original/project:main

如果只是自己的项目,不涉及 fork,可以简化成:

终端
git checkout main
git pull
git checkout -b feature-my-change
git add .
git commit -m "add my change"
git push origin feature-my-change

然后在 GitHub 上把 feature-my-change 合并到 main。


23. 最核心的一句话总结

Fork 是复制别人的远程仓库,clone 是下载仓库到本地,branch 是在同一个仓库里开新的开发线,merge 是把一个分支合并到当前分支,PR 是在 GitHub 上请求把一个分支合并到另一个分支。

真正推荐的方式是:

main 保持干净和同步;
每个功能单独开分支;
开发完成后通过 PR 合并;
合并前先同步最新 main;
出现冲突就手动解决。

输入关键词,搜索全部文章的标题和正文。

↑↓ 选择 Enter 打开 Esc 关闭