Git 学习总帖(二):远程仓库、GitHub 与多人协作,从 GitHub 到 Git Flow
这篇是 Git 学习总帖的第二部分。上一篇主要整理的是本地仓库:
.git、工作区、暂存区、版本库、回退、撤销、分支、合并、冲突、stash 等内容。
这一篇接着往后走,开始把代码放到远程仓库里。也就是:GitHub 仓库页面怎么看、怎么 clone 到本地、怎么 push、怎么 pull、怎么建立本地分支和远程分支的连接、
.gitignore怎么用、标签怎么管理,以及多人协作时到底应该怎么合并。
🌈 个人主页: 小小、码农的 CSDN 博客
🔥 系列方向: git学习
💪 学习宣言: 命令可以慢慢背,但逻辑一定要先想通。
目录
- 一、Git 是分布式版本控制器
- 二、创建远程仓库,先认识 GitHub 页面
- 三、把远程仓库克隆到本地:HTTPS 和 SSH
- 四、向远程仓库推送:
git push - 五、从远程仓库拉取:
git pull - 六、本地分支和远程分支怎么建立连接?
- 七、
.gitignore:哪些文件不应该提交 - 八、配置命令别名:让长命令短一点
- 九、标签管理:给重要版本起名字
- 十、多人协作一:远程先有分支,本地再连接
- 十一、多人协作二:本地先有分支,再推送到远程
- 十二、远程分支删除了,本地为什么还能看到?
- 十三、企业级开发模型:Git Flow
- 十四、总结
一、Git 是分布式版本控制器
上一篇文章里,我们一直在本地使用 Git。比如:
git init
git add .
git commit -m "第一次提交"
这时候代码的版本记录都在自己电脑上,也就是本地仓库里。
但是 Git 不只是能在本地用,它是一个分布式版本控制器。分布式的意思是:每个人电脑上都可以有一份完整的仓库,大家再通过远程仓库进行同步。
可以先这样理解:
本地仓库:自己电脑上的 Git 仓库
远程仓库:GitHub / Gitee / GitLab 上的 Git 仓库
它们之间最常见的关系如下:

常见命令主要有三个:
| 命令 | 作用 |
|---|---|
git clone |
把远程仓库复制到本地 |
git push |
把本地提交推送到远程仓库 |
git pull |
把远程仓库的更新拉取到本地,并尝试合并 |
这里要先记住一句话:
git commit只是提交到本地仓库,不是提交到 GitHub。想让 GitHub 上也有这次提交,还需要git push。
也就是说,平时写代码的基本路线是:
修改文件 -> git add -> git commit -> git push
前两个阶段上一篇已经学过,这一篇重点就是从 push 开始,真正和远程仓库打交道。
二、创建远程仓库,先认识 GitHub 页面
远程仓库可以放在很多平台上,比如 GitHub、Gitee、GitLab。这里我用 GitHub 举例。
创建 GitHub 仓库的过程本身不复杂:登录 GitHub,点击创建仓库,填写仓库名,选择公开或私有,然后创建即可。
创建完之后,会进入类似这样的仓库页面:

作为新手,不需要一上来把 GitHub 所有功能都学完,先认识几个最常用的地方就行。
| 区域 | 作用 |
|---|---|
Code |
查看代码、切换分支、复制 clone 地址 |
Issues |
提问题、记录 bug、记录需求、讨论任务 |
Pull requests |
提交合并请求,团队协作里经常用 |
Actions |
自动化构建、测试、部署 |
Branches |
查看仓库里的分支 |
Tags |
查看版本标签 |
1. Code:代码入口
Code 是最常用的入口。
点绿色的 Code 按钮,可以看到仓库的克隆地址。这个地址后面会用于:
git clone 仓库地址
它一般有两种形式:
HTTPS 地址:https://github.com/用户名/仓库名.git
SSH 地址:git@github.com:用户名/仓库名.git
后面会单独讲 HTTPS 和 SSH 的区别。
2. Issues:问题和任务记录
Issue 可以理解为项目里的“问题单”或“任务单”。
它不只用来记录 bug,也可以记录:
- 新需求;
- 文档改进;
- 待讨论的问题;
- 某个功能的开发任务;
- 用户反馈。

比如团队里有人发现登录功能有问题,就可以提一个 Issue。后面修复这个问题时,也可以把对应分支、提交、PR 关联起来。
3. Pull Request:请求合并代码
Pull Request 简称 PR,可以先理解成一句话:
我这个分支写完了,请求把它合并到目标分支,麻烦大家看一下有没有问题。

PR 里一般能看到:
- 从哪个分支合并到哪个分支;
- 改了哪些文件;
- 每一行代码的差异;
- 代码审查评论;
- 自动测试有没有通过;
- 最后能不能合并。
自己练习时,可以先在本地 merge。但以后真正工作里,更推荐通过 PR 来合并,因为这样方便代码评审,也方便留下协作记录。
三、把远程仓库克隆到本地:HTTPS 和 SSH
远程仓库创建好之后,我们要把它拿到本地开发,就需要 git clone。
命令格式:
git clone 仓库地址
1. HTTPS 克隆
HTTPS 地址一般长这样:
https://github.com/用户名/仓库名.git
在你想存放项目的文件夹里打开终端,执行:
git clone https://github.com/用户名/仓库名.git
克隆完成后,会多出一个项目文件夹。进入这个文件夹:
cd 仓库名
查看当前仓库关联的远程地址:
git remote -v
可能看到类似结果:
origin https://github.com/用户名/仓库名.git (fetch)
origin https://github.com/用户名/仓库名.git (push)
这里的 origin 是 Git 默认给远程仓库起的名字。
fetch 表示从这个地址拉取,push 表示往这个地址推送。也就是说,这个本地仓库已经知道自己要和哪个远程仓库同步了。
2. SSH 克隆
SSH 地址一般长这样:
git@github.com:用户名/仓库名.git
使用方式:
git clone git@github.com:用户名/仓库名.git
但是 SSH 不是复制地址就一定能用。它需要先配置 SSH key。
如果没有配置,可能会出现:
Permission denied (publickey).
fatal: Could not read from remote repository.
这句话的意思是:GitHub 还不认识你这台电脑,所以不让你通过 SSH 操作仓库。
3. SSH key 的基本配置思路
生成 SSH key:
ssh-keygen -t rsa -C "你的邮箱"
一路回车后,一般会在用户目录下生成:
~/.ssh/id_rsa
~/.ssh/id_rsa.pub
注意:
id_rsa是私钥,不能随便发给别人;id_rsa.pub是公钥,可以添加到 GitHub。
查看公钥:
cat ~/.ssh/id_rsa.pub
把输出内容复制到 GitHub 的 SSH keys 里。配置好之后,可以测试:
ssh -T git@github.com
如果提示认证成功,之后就可以用 SSH 地址进行 clone、push、pull 了。
4. name 和 email 要注意
本地提交时,Git 会记录提交者信息:
git config user.name
git config user.email
如果是全局配置:
git config --global user.name "你的名字"
git config --global user.email "你的邮箱"
建议 user.email 使用 GitHub 账号里已经验证过的邮箱。这样提交推到 GitHub 后,贡献记录更容易正常关联到你的账号。
四、向远程仓库推送:git push
本地提交之后,想把提交同步到远程仓库,就用 git push。
比如本地主分支叫 master:
git push origin master
它的意思是:
把本地 master 分支推送到 origin 远程仓库的 master 分支
更完整的写法是:
git push origin master:master
冒号左边是本地分支,冒号右边是远程分支:
git push origin 本地分支名:远程分支名
如果本地分支名和远程分支名一样,就可以省略冒号和冒号后面的内容:
git push origin master
这里一定要分清:
origin 是远程仓库名
master / main 是分支名
它俩不是一个东西。
五、从远程仓库拉取:git pull
如果远程仓库有新提交,本地想同步下来,就用 git pull。
常见写法:
git pull origin master
意思是:
从 origin 远程仓库拉取 master 分支的更新,并合并到当前分支
这里和 push 有一点容易混:
git push origin master:master这种冒号写法用来表达“本地分支推到远程哪个分支”;- 新手阶段使用
pull时,先记git pull origin master这种写法即可,不要硬套master:master。
git pull 其实做了两步
git pull 不是单纯下载,它大概等价于:
git fetch
git merge
也就是:
- 先把远程的新内容拉下来;
- 再尝试合并到当前本地分支。
所以多人协作时,如果你和别人改了同一块内容,git pull 也可能产生冲突。
六、本地分支和远程分支怎么建立连接?
我们有时候可以写:
git push origin master
有时候又可以直接写:
git push
这是因为本地分支和远程分支之间可以建立“跟踪关系”。

查看当前分支和远程分支的连接关系:
git branch -vv
如果看到类似:
* master abc1234 [origin/master] 提交说明
这里的 [origin/master] 就表示:
本地 master 分支正在跟踪远程 origin/master 分支
建立连接之后,在当前分支上就可以直接:
git pull
git push
1. 查看远程分支
查看远程分支:
git branch -r
查看本地和远程所有分支:
git branch -a
2. 远程有 dev,本地也想创建 dev 并连接
假设远程仓库里已经有:
origin/dev
现在本地想创建一个 dev 分支,并且让它跟踪远程的 origin/dev,可以写:
git checkout -b dev origin/dev
新版本 Git 也可以写:
git switch -c dev --track origin/dev
这条命令做了两件事:
- 在本地创建
dev分支; - 让本地
dev和远程origin/dev建立连接。
建立好之后,后面在 dev 分支上就可以直接:
git pull
git push
七、.gitignore:哪些文件不应该提交
项目里不是所有文件都应该提交到 Git。
比如:
- 编译生成的文件;
- 日志文件;
- 临时文件;
- 本地 IDE 配置;
.env这种环境配置;- 密码、密钥、token。
这些文件可以写进 .gitignore。
示例:
# 编译产物
dist/
build/
# 日志文件
*.log
# 环境配置
.env
# 临时文件
*.tmp
1. 强制提交被忽略的文件
如果一个文件被 .gitignore 忽略了,但这次你就是想提交它,可以使用:
git add -f 文件名
-f 可以理解为 force,强制添加。
2. 在 .gitignore 里取消忽略
如果想忽略一类文件,但保留其中某个文件,可以用 !:
*.log
!important.log
意思是:
忽略所有 .log 文件
但是不要忽略 important.log,这样比强制提交更好,因为他更尊重.gitignore规则
3. 查看某个文件为什么被忽略
开发的文件多了,有时候会忘记某个文件到底被哪条规则忽略了。
可以用:
git check-ignore -v 文件名
它会告诉你具体是哪一个 .gitignore 规则导致这个文件被忽略。
八、配置命令别名:让长命令短一点
有些 Git 命令经常用,但名字比较长,比如 status。
我们可以给它起一个别名:
git config --global alias.st status
前面的 st 是你想起的别名,后面的 status 是原命令。
配置之后:
git st
就等价于:
git status
当然原来的 git status 依然可以使用。
再比如,查提交历史时,可能会用到比较长的命令:
git log --pretty=oneline --abbrev-commit
也可以给它起别名,比如:
git config --global alias.lg "log --pretty=oneline --abbrev-commit"
之后直接:
git lg
就能看到简短的提交记录。
九、标签管理:给重要版本起名字
有时候某次提交很重要,比如:
- 第一次正式发布;
v1.0版本;- 某个稳定版本;
- 某次上线版本。
这时就可以给这个提交打一个标签。

标签可以理解为:
给某个 commit ID 起一个更好记的名字。
比如 v1.0 肯定比一长串 commit ID 好记。
1. 给最新一次提交打标签
git tag v1.0
查看标签:
git tag
2. 从 .git 里看看 tag 本质是什么
上一篇文章里提过 .git 是 Git 的版本库,里面保存着 Git 的很多核心信息。
打完标签后,可以看一下:
tree .git
或者直接看标签文件:
cat .git/refs/tags/v1.0
里面通常会看到一个 commit ID。
这就说明,轻量标签的本质很简单:
标签名 -> 某个 commit ID
所以我们说标签是给某次重要提交起名字。
3. 给之前的版本打标签
如果想给之前某次提交打标签,先查看提交历史:
git log --pretty=oneline --abbrev-commit
找到你想打标签的 commit ID,然后:
git tag v1.0 commitID
4. 创建带说明的标签
如果怕以后忘记这个标签是什么意思,可以加说明:
git tag -a v1.0 -m "important tag" commitID
查看标签详情:
git show v1.0
这样就可以看到标签对应的提交,以及你写的说明。
5. 推送标签到远程
标签默认也是在本地创建的。如果想让远程仓库也有这个标签,需要推送。
推送某一个标签:
git push origin v1.0
一次性推送所有标签:
git push origin --tags
这里常用写法是 --tags。
6. 删除标签
删除本地标签:
git tag -d v1.0
删除远程标签:
git push origin :refs/tags/v1.0
也经常能看到简写:
git push origin :v1.0
但新手阶段,我更建议先记完整写法,因为它能看出来删除的是远程的 tag。
十、多人协作一:远程先有分支,本地再连接
接下来进入最重要的内容:多人协作开发。
为了模拟多人协作,可以把自己的一台电脑当作一个开发者,再用另一台电脑、虚拟机、云服务器,或者另一个目录模拟另一个开发者。
多人协作时,最容易混乱的不是命令本身,而是这几个问题:
远程有没有这个分支?
本地有没有这个分支?
本地分支和远程分支有没有建立连接?
最后要合并到哪个分支?
先看第一种情况:
远程仓库里已经有一个分支,本地现在要把它拉下来开发。

假设远程仓库已经有 dev 分支。
先更新远程信息:
git fetch origin
查看所有分支:
git branch -a
如果看到:
remotes/origin/dev
说明远程确实有 dev 分支。
然后本地创建 dev 分支,并连接远程 origin/dev:
git checkout -b dev origin/dev
之后正常开发:
git add .
git commit -m "完成 dev 分支功能"
git push
因为本地 dev 已经和远程 origin/dev 建立了连接,所以这里可以直接 git push。
把 dev 合并到 master/main
开发完成后,最终要把 dev 合并到主分支。
有两种方式:
方式一:本地 merge 后 push
方式二:提交 Pull Request,在 GitHub 上合并
自己初学时,可以先练本地 merge,这样能更熟悉命令。
比如主分支叫 master:
第一步,先把本地 master 更新到最新:
git checkout master
git pull
第二步,切回 dev,让 dev 先合并最新的 master:
git checkout dev
git merge master
如果这里发生冲突,就在 dev 分支上解决冲突,防止污染主分支:
git add .
git commit -m "解决 dev 与 master 的冲突"
git push origin dev
这一步的目的很重要:先在开发分支上把冲突处理干净,不要一上来就把冲突现场带到主分支。
第三步,确认 dev 已经能正常合并后,再切回 master 合并 dev:
git checkout master
git merge dev
git add .
git commit -m "解决 dev 合并冲突"
git push origin master
这样做的好处是:master 已经是最新的,dev 也提前处理过和 master 的差异,最后 master 合并 dev 时通常会更干净。
工作中更推荐 PR:
dev -> master/main
PR 的好处是:合并前可以看差异、做代码评审、跑自动测试,也能留下讨论记录。
十一、多人协作二:本地先有分支,再推送到远程
第二种情况是:
远程还没有这个功能分支,我先在本地创建,写完后再推送到远程。
比如现在要开发 feature-1。
第一步,创建并切换分支:
git checkout -b feature-1
第二步,编辑文件。比如新建或修改 function1。
第三步,提交:
git add .
git commit -m "完成 feature-1"
第四步,推送到远程:
git push origin feature-1
默认建立了追踪关系
这样以后在 feature-1 分支上就可以直接:
git push
git pull
这种方式为什么方便?
因为每个人开发自己的功能分支,不会一直挤在同一个分支上。
比如:
feature-1:你开发的功能
feature-2:同事开发的功能
master:稳定主分支
这样平时大家互不影响,只有最后合并到主分支时,才可能出现冲突。
同事生病了,你要接着他的分支开发怎么办?
这个场景很真实。
假设同事开发的是 feature-2,他已经把分支 push 到远程了,但你本地看不到。
先拉取远程信息:
git pull
再查看所有分支:
git branch -a
如果看到:
remotes/origin/feature-2
说明远程有这个分支。
接下来创建本地分支,并连接远程分支:
git checkout -b feature-2 origin/feature-2
之后你就可以继续开发:
git add .
git commit -m "继续完成 feature-2"
git push
因为创建时已经建立连接,所以可以直接 git push。
为什么 git branch -a 能看到远程分支?
这里有个容易误解的点。
本地没有建立 feature-2 分支,不代表本地完全不知道远程有这个分支。
当你执行:
git pull
Git 会把远程仓库的分支信息更新到本地,所以你能通过:
git branch -a
看到:
remotes/origin/feature-2
但是,看到远程分支不等于你已经在本地创建了对应分支。
如果你要真正切过去开发,还需要:
git checkout -b feature-2 origin/feature-2
也就是说:
拉取远程分支信息,不一定需要建立跟踪关系;
但想在本地开发这个分支,就要创建本地分支并连接它。
feature-1 和 feature-2 最后怎么合并?
可以用 PR,也可以本地合并。
初学时为了练命令,可以本地 merge。工作中更建议 PR。
假设现在 feature-1 已经合进了 master,此时 master 变新了。再合并 feature-2 时,可能会冲突。
比较稳的做法是:先让 feature-2 合并最新的 master,在 feature-2 上解决冲突。
git checkout master
git pull
git checkout feature-2
git merge master
如果有冲突,就在 feature-2 上解决:
git add .
git commit -m "解决 feature-2 与 master 的冲突"
git push origin feature-2
如果你是通过 PR 合并,接下来就可以提 PR:
feature-2 -> master/main
如果你是本地练习 merge,那还要继续回到 master,把已经处理好冲突的 feature-2 合并进来:
git checkout master
git merge feature-2
git push origin master
也就是说,完整流程是:
master 先 pull 到最新
-> feature-2 合并 master
-> 在 feature-2 上解决冲突
-> 回到 master 合并 feature-2
-> push master
这样比直接在主分支上解决冲突更安全,因为主分支不会被半成品冲突现场污染。
十二、远程分支删除了,本地为什么还能看到?
多人协作中还有一个问题:
远程分支明明已经删了,但本地执行:
git branch -a
还是能看到:
remotes/origin/old-feature
这是因为本地保存的远程分支记录还没清理。
可以先查看远程仓库状态:
git remote show origin
如果看到 stale,意思就是陈旧的、远程已经不存在的引用。
Git 一般也会提示你可以用什么命令清理。
直接清理:
git remote prune origin
注意,这里清理的是:
本地保存的远程分支记录
不是删除远程仓库上真实存在的分支。
十三、企业级开发模型:Git Flow
前面讲的是个人和多人协作时最常见的 Git 操作。
但到了企业项目,事情会更复杂一点。一个软件从零开始到上线,不只是写代码,通常会经历:
规划 -> 编码 -> 构建 -> 测试 -> 发布 -> 部署 -> 维护
这也是为什么课程里会提到 DevOps。
DevOps 可以先粗略理解为:让开发人员和运维人员更好地协作,通过工具和流程自动化,让软件构建、测试、发布、部署更加稳定和高效。
对我们现在学 Git 来说,重点不是立刻把 DevOps 全学完,而是明白:
公司项目通常会按照不同环境和不同阶段设计分支。
1. 常见开发环境
企业项目里经常会听到这些环境:
| 环境 | 作用 |
|---|---|
| 开发环境 | 程序员日常开发、调试使用 |
| 测试环境 | 测试人员验证功能和 bug |
| 预发布环境 | 尽量接近生产环境,上线前最后确认 |
| 生产环境 | 正式提供给用户使用的线上环境 |
简单理解:
开发环境:写代码
测试环境:测功能
预发布环境:上线前演练
生产环境:用户真正访问
不同环境需要相对稳定的代码来源,所以就会有分支设计。
2. Git Flow 常见分支
Git Flow 是一种企业里比较常见的分支模型。

常见分支如下:
| 分支 | 作用 |
|---|---|
master / main |
主分支,通常对应生产环境,保存稳定版本 |
develop |
开发分支,保存已经完成但还没正式发布的功能 |
feature/... |
功能分支,从 develop 切出来开发某个需求 |
release/... |
预发布分支,用来测试和准备上线 |
hotfix/... |
紧急修复分支,通常从 master/main 切出来 |
3. master/main 分支
master 或 main 一般是最稳定的分支。
它通常对应生产环境,也就是用户真正使用的版本。
一般不建议直接在这个分支上写代码,更常见的是通过合并得到:
release -> master/main
hotfix -> master/main
正式发布后,通常还会打标签:
git tag -a v1.0.0 -m "发布 v1.0.0"
git push origin v1.0.0
这样以后线上出了问题,就能快速知道当前生产环境对应的是哪个版本。
4. develop 分支
develop 是开发主分支。
新功能一般不会直接写在 master/main 上,而是先从 develop 切出功能分支。
功能完成后,再合并回 develop。
develop -> feature/login -> develop
5. feature 分支
开发新功能时,从 develop 创建 feature 分支:
git checkout develop
git pull
git checkout -b feature/login
开发完成后:
git add .
git commit -m "完成登录功能"
git push -u origin feature/login
然后通过 PR 或 merge 合并回 develop。
feature 分支的好处是:一个功能一个分支,没写完不会影响别人。
6. release 分支
当 develop 上的一批功能准备上线时,会从 develop 切出 release 分支:
git checkout develop
git pull
git checkout -b release/v1.0.0
git push -u origin release/v1.0.0
release 分支通常用来:
- 交给测试人员测试;
- 修复上线前发现的问题;
- 部署到测试环境或预发布环境;
- 确认这一版到底包含哪些功能。
测试通过后,再合并到 master/main。
7. hotfix 分支
如果线上突然出现严重 bug,需要马上修复,一般会从 master/main 切 hotfix 分支:
git checkout main
git pull
git checkout -b hotfix/fix-login-error
修复完成后:
git add .
git commit -m "修复登录异常"
git push -u origin hotfix/fix-login-error
hotfix 修完后,通常要合并到两个地方:
hotfix -> master/main
hotfix -> develop
为什么还要合回 develop?
因为如果只修了线上分支,而开发分支没修,下一次从 develop 发版时,老 bug 可能又被带回线上。
8. Git Flow 不是死规则
最后要注意:Git Flow 很常见,但不是所有团队都必须这样用。
有些小项目可能只需要 main + feature;有些团队发布很频繁,可能更喜欢主干开发;有些公司会有自己的分支命名规范。
所以学 Git Flow,不是为了死背模板,而是理解它想解决什么问题:
- 新功能开发不要影响稳定版本;
- 测试和上线要有明确代码来源;
- 线上 bug 要能快速修;
- 每次发布要能追溯;
- 多人协作时分支关系不能乱。
十四、总结
这一篇从我的笔记顺序出发,把远程仓库和多人协作整理了一遍。
最核心的线是:
GitHub 创建仓库
-> clone 到本地
-> 本地 commit
-> push 到远程
-> pull 拉取远程更新
-> branch -vv 查看连接关系
-> 多人通过分支和 PR 协作
几个容易混的点再总结一下:
commit是提交到本地;push才是推送到远程;pull会拉取并尝试合并;origin是远程仓库名,不是分支名;master/main/dev/feature-1才是分支名;git branch -vv可以看本地分支跟踪哪个远程分支;- 远程有分支,本地可以
git checkout -b dev origin/dev建立连接; - 本地新建分支,第一次推送推荐
git push -u origin 分支名; .gitignore是为了避免提交不该提交的文件;tag可以理解为给重要 commit 起名字;git remote prune origin可以清理本地陈旧的远程分支记录;- 企业里常见 Git Flow,但具体分支模型要看团队规范。
我现在对远程仓库的理解是:Git 命令看起来很多,但只要一直问自己三个问题,思路就不会乱:
我现在在哪个本地分支?
这个分支连接的是哪个远程分支?
我最终要把代码合并到哪里?
把这三个问题想明白,多人协作就不再只是背命令了。
更多推荐




所有评论(0)