编程进阶网 编程进阶网
首页
  • 计算机原理
  • 操作系统
  • 网络协议
  • 数据库原理
  • 面向对象
  • 设计原则
  • 设计模式
  • 系统架构
  • 性能优化
  • 编程原理
  • 方案设计
  • 稳定可靠
  • 工程运维
  • 基础认知
  • 线性结构
  • 树与哈希
  • 工业级实现
  • 算法思想
  • 实战与综合
  • 算法题考核
  • C语言入门
  • C综合案例
  • C专栏博客
  • C标准集库
  • C++入门教程
  • C++综合案例
  • C++专栏博客
  • C++开发技巧
  • Java入门教程
  • Java综合案例
  • Java专栏博客
  • Go入门教程
  • Go综合案例
  • Go专栏博客
  • Go开发技巧
  • JavaScript入门
  • JavaScript高级
  • Android库解读
  • Android专栏
  • Android智能硬件
  • iOS ObjC入门
  • iOS Swift入门
  • iOS入门精通
  • Web之Html手册
  • Web之TypeScript
  • Web之Vue高级进阶
  • Linux之QML入门
  • Linux之QT核心库
  • Linux实践开发
  • Python教程
  • Shell&Bash教程
  • 工具脚本
  • 自动化脚本
  • 质量保障
  • 产品思考
  • 软实力
  • 开发流程
  • Git应用
  • 技术模版
  • 技术规范
  • Markdown
  • Mermaid
  • 开源协议
  • JSON工具
  • 文本工具
  • 图片处理
  • 文档转化
  • 代码压缩
  • 关于我
  • 自我精进
  • 职场管理
  • 职场面试
  • 心情杂货
  • 友情链接

杨充

专注编程 · 终身学习者
首页
  • 计算机原理
  • 操作系统
  • 网络协议
  • 数据库原理
  • 面向对象
  • 设计原则
  • 设计模式
  • 系统架构
  • 性能优化
  • 编程原理
  • 方案设计
  • 稳定可靠
  • 工程运维
  • 基础认知
  • 线性结构
  • 树与哈希
  • 工业级实现
  • 算法思想
  • 实战与综合
  • 算法题考核
  • C语言入门
  • C综合案例
  • C专栏博客
  • C标准集库
  • C++入门教程
  • C++综合案例
  • C++专栏博客
  • C++开发技巧
  • Java入门教程
  • Java综合案例
  • Java专栏博客
  • Go入门教程
  • Go综合案例
  • Go专栏博客
  • Go开发技巧
  • JavaScript入门
  • JavaScript高级
  • Android库解读
  • Android专栏
  • Android智能硬件
  • iOS ObjC入门
  • iOS Swift入门
  • iOS入门精通
  • Web之Html手册
  • Web之TypeScript
  • Web之Vue高级进阶
  • Linux之QML入门
  • Linux之QT核心库
  • Linux实践开发
  • Python教程
  • Shell&Bash教程
  • 工具脚本
  • 自动化脚本
  • 质量保障
  • 产品思考
  • 软实力
  • 开发流程
  • Git应用
  • 技术模版
  • 技术规范
  • Markdown
  • Mermaid
  • 开源协议
  • JSON工具
  • 文本工具
  • 图片处理
  • 文档转化
  • 代码压缩
  • 关于我
  • 自我精进
  • 职场管理
  • 职场面试
  • 心情杂货
  • 友情链接
  • README
  • 质量保障

  • 产品思考

  • 软实力

  • 开发流程

  • Git应用

    • README
    • 版本控制的诞生:从一场灾难说起
    • 单人工作流:在 Git 的时光机里自由穿梭
    • 分支:Git 的灵魂——像开平行宇宙一样开发
    • 远程协作:把你的代码推到全世界
      • 一、代码被覆盖
      • 二、远程本质
        • 2.1 先纠正一个认知
        • 2.2 三个核心概念
      • 三、三大命令
        • 3.1 数据流动方向
        • 3.2 实战:fetch 到底拉了什么?
        • 3.3 为什么建议 fetch 再看,而不是直接 pull
      • 四、克隆仓库
        • 4.1 三种协议
        • 4.2 clone 到底做了什么?
      • 五、PR 工作流
        • 5.1 为什么需要 PR?
        • 5.2 实战:一个人分饰两角,走完 PR 全流程
        • 5.3 Code Review + 合并
      • 六、协作冲突
        • 场景:小李和小王同时改 products.js
        • 6.1 正确处理流程
        • 6.2 ⚠️ 错误的处理方式(千万别学)
      • 七、版本标签
        • 7.1 标签 vs 分支
        • 7.2 两种标签
      • 八、综合实战
        • 场景设定
        • 实战开始
      • 启动
    • Git特种作战:stash、cherry-pick、bisect三件套
    • 团队工作流实战:从一个人能打到一队人能战
    • Git故障排除:遇到报错不再慌的急诊手册
    • Git 场景速查地图:遇到问题对号入座
    • 常见操作实践:从理论到实战的最后一步
  • 技术模版

  • 技术规范

  • markdown

  • mermaid

  • license

  • 博客部署

  • 技术招聘

  • 测试经验

  • 技术
  • Git应用
杨充
2025-06-06
目录

远程协作:把你的代码推到全世界

# 第4章 · 远程协作指南

# 一、代码被覆盖

小李的优惠券系统终于写完了。前一天晚上,他把代码 push 到团队仓库,心满意足地回了家。

第二天早上 9 点,他的同事小王来上班,打开终端:

$ git push

 ! [rejected]        master -> master (fetch first)
error: failed to push some refs to 'https://github.com/team/shop.git'
hint: Updates were rejected because the remote contains work that you do
hint: not have locally.
1
2
3
4
5
6

小王愣住了。他昨天也改了 products.js,而且提交了。但现在 GitHub 说「远程有你看不到的代码」,拒绝了他的 push。

更糟的是,他按照提示执行了 git pull——然后终端弹出了冲突标记。他不知道怎么解决,手忙脚乱中敲了 git push --force。

五分钟后,全组人发现:小李昨晚写的优惠券系统,从远程仓库里消失了。

这不是段子。git push --force 是新人最危险的武器,而根源就在于不理解「远程协作」的机制。


# 二、远程本质

# 2.1 先纠正一个认知

很多新手以为:

「GitHub 上的仓库 = 主仓库,我本地的 = 副本」

错了。在 Git 的世界观里:

你本地的仓库 + 远程的仓库 = 两个地位平等的 Git 仓库。 只是它们之间通过网络互相传输数据。

这和第 1 章的「分布式」一脉相承:没有谁比谁更「权威」,哪个仓库该接收谁的代码,是人定的约定,不是 Git 的技术限制。

# 2.2 三个核心概念

mkdir remote-lab && cd remote-lab && git init

# 添加远程仓库链接
git remote add origin https://github.com/username/repo.git

# 看看远程配置
git remote -v
# origin  https://github.com/username/repo.git (fetch)
# origin  https://github.com/username/repo.git (push)
1
2
3
4
5
6
7
8
9
概念 含义 一句话
remote 远程仓库的「地址簿名称」 origin 只是一个别名,不是特殊关键字
origin 惯例上的默认远程仓库名 clone 时自动命名,你可以改
upstream 上游仓库(fork 场景) 别人的原始仓库,你 fork 了一份
# 可以添加多个 remote
git remote add upstream https://github.com/original/repo.git
git remote add backup https://gitlab.com/username/repo.git

# 重命名 remote
git remote rename origin github

# 删除 remote
git remote remove backup
1
2
3
4
5
6
7
8
9

# 三、三大命令

# 3.1 数据流动方向

    你的本地仓库                              远程仓库
   ┌─────────────┐                        ┌─────────────┐
   │   commit A  │                        │   commit A  │
   │   commit B  │ ─── git push ────────→ │   commit B  │  ← 你的 commit 过去了
   │   commit C  │                        │   commit C  │
   └─────────────┘                        └─────────────┘
         ↑                                      │
         │                                      │
         └──── git fetch / git pull ────────────┘
              ← 远程的数据拉下来了
1
2
3
4
5
6
7
8
9
10

关键区别:

命令 干了什么 改了工作区吗
git push 把本地 commit 推上去 不关心(远程仓库没有「工作区」)
git fetch 把远程 commit 拉下来 ❌ 只更新本地「远程分支引用」
git pull fetch + merge 的合体 ✅ 直接把代码合到工作区

# 3.2 实战:fetch 到底拉了什么?

# 首先,在 GitHub 上创建一个仓库(通过网页操作)
# 获取 URL,例如:https://github.com/你的用户名/remote-lab.git

# 关联远程
git remote add origin https://github.com/你的用户名/remote-lab.git

# 创建并推送初始内容
echo "# 远程协作实验" > README.md
git add . && git commit -m "init: README"
git push -u origin master
# -u = --set-upstream:记住 master 对应 origin/master,以后直接 git push

# 现在,去 GitHub 网页上直接编辑 README.md,加一行文字,提交
# 这样远程就比本地多了一个 commit

# 回到终端,只 fetch,不 merge
git fetch origin

# 看看发生了什么
git log --oneline --all --graph
# 输出类似:
# * cccccc (origin/master) 在 GitHub 上编辑的  ← 远程的新 commit
# * aaaaaa (HEAD -> master) init: README

# origin/master 是本地保存的「远程仓库的指针」
# fetch 只是更新了这个指针,没有动你的工作区
cat README.md
# 内容没变!fetch 不会改你的文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

# 3.3 为什么建议 fetch 再看,而不是直接 pull

# 不推荐(盲目合并):
git pull              # 你可能不知道远程有什么,自动 merge 了

# 推荐(先侦察再决定):
git fetch origin      # 拉最新信息,不改工作区
git log --oneline master..origin/master  # 看看远程多了什么
git diff master origin/master            # 看看具体改了什么
# 然后你再决定:
git merge origin/master                  # 确认无误再合并
# 或者
git rebase origin/master                 # 想保持线性历史就 rebase
1
2
3
4
5
6
7
8
9
10
11

💡 核心习惯:把 git pull 当成 git fetch + 你手动决定 merge 还是 rebase。盲目 pull 是大多数冲突的根源。


# 四、克隆仓库

# 4.1 三种协议

# HTTPS(最简单,需要输入密码或 token)
git clone https://github.com/username/repo.git

# SSH(推荐,配置一次密钥,后续免密)
git clone git@github.com:username/repo.git

# Git 协议(只读,开放项目用)
git clone git://github.com/username/repo.git
1
2
3
4
5
6
7
8

# 4.2 clone 到底做了什么?

git clone https://github.com/username/repo.git my-project

# 等价于:
# mkdir my-project && cd my-project
# git init
# git remote add origin https://github.com/username/repo.git
# git fetch origin
# git checkout master  (或 main)
1
2
3
4
5
6
7
8

克隆下来的仓库自带完整的提交历史、所有分支的引用,以及 origin 这个 remote。


# 五、PR 工作流

# 5.1 为什么需要 PR?

你可能会想:「我直接 push 到 master 不就行了?」

在一个人的项目里,可以。在团队里,这是灾难。PR 的本质是一个请求审查的流程:

你开发 feature → push 到远程 → 创建 PR → 别人审查 → 批准 → 合并到主分支
1

它解决了三个问题:

  1. 代码质量:不会有人直接把 bug push 到 master
  2. 知识传播:至少一个人看过你的代码,知道你在做什么
  3. 可追溯:每一个改动都有讨论记录存档

# 5.2 实战:一个人分饰两角,走完 PR 全流程

mkdir pr-lab && cd pr-lab && git init

echo "const app = { version: '1.0' };" > app.js
git add . && git commit -m "init: 应用骨架"

# 创建 feature 分支
git switch -c feature/添加日志

echo "function log(msg) { console.log(\`[LOG] \${msg}\`); }" >> app.js
git add . && git commit -m "feat: 添加日志函数"

echo "function error(msg) { console.error(\`[ERROR] \${msg}\`); }" >> app.js
git add . && git commit -m "feat: 添加错误日志函数"
1
2
3
4
5
6
7
8
9
10
11
12
13

现在 feature 分支上有 2 个 commit,推送到 GitHub:

# 在 GitHub 上创建仓库(通过网页),然后:
git remote add origin https://github.com/你的用户名/pr-lab.git
git push -u origin feature/添加日志

# 去 GitHub 网页 → Pull Requests → New Pull Request
# base: master ← compare: feature/添加日志
# 填写标题和描述,点击 Create Pull Request
1
2
3
4
5
6
7

一个规范的 PR 描述应该这样写:

## 做了什么
- 添加了 log() 函数,统一日志输出格式
- 添加了 error() 函数,专门处理错误日志

## 测试方法
1. 调用 log('测试消息'),确认控制台输出 [LOG] 测试消息
2. 调用 error('错误'),确认控制台输出 [ERROR] 错误

## 相关 Issue
Closes #42
1
2
3
4
5
6
7
8
9
10

# 5.3 Code Review + 合并

在 GitHub 上:

  1. 审查者查看 Files changed 标签页,逐行审查
  2. 可以在具体行上留言、提建议
  3. 审查通过后,点击 Merge pull request
  4. 选择合并策略:Create a merge commit(推荐)或 Squash and merge(压缩成一个 commit)或 Rebase and merge(线性历史)

合并完成后,本地同步:

git switch master
git pull origin master    # 把 PR 合并后的 master 拉下来
git branch -d feature/添加日志   # 清理本地 feature 分支
1
2
3

# 六、协作冲突

# 场景:小李和小王同时改 products.js

小李的操作:

mkdir team-lab && cd team-lab && git init

echo 'const products = [{ id: 1, name: "iPhone" }];' > products.js
git add . && git commit -m "init: 商品数据"
# 假设已 push 到远程
1
2
3
4
5

小王 clone 下来,开始改:

git clone https://github.com/team/team-lab.git wang-local
cd wang-local

# 小王给 iPhone 加了价格
sed -i '' 's/"iPhone"}/"iPhone", price: 6999}/' products.js
cat products.js
# const products = [{ id: 1, name: "iPhone", price: 6999 }];

git add . && git commit -m "feat: 添加 iPhone 价格"
git push origin master
# ✅ 成功!小王是第一个 push 的人
1
2
3
4
5
6
7
8
9
10
11

现在小李也想改同一行:

# 小李不知道小王已经改了
sed -i '' 's/"iPhone"}/"iPhone", stock: 100}/' products.js
git add . && git commit -m "feat: 添加 iPhone 库存"

git push origin master
# ❌ 被拒绝了!
# ! [rejected] master -> master (fetch first)
1
2
3
4
5
6
7

# 6.1 正确处理流程

# Step 1:先 fetch,看看远程多了什么
git fetch origin
git log --oneline master..origin/master
# 输出类似:
# abc1234 feat: 添加 iPhone 价格    ← 小王的 commit,你本地没有

# Step 2:看看远程改了什么
git diff master origin/master
# 输出:iPhone 被加了 price: 6999

# Step 3:把远程的改动合并到本地
git merge origin/master

# 如果有冲突(同一行),就需要手动解决:
# products.js 会显示:
#   const products = [{ id: 1, name: "iPhone", price: 6999 }];  ← 小王的
#   const products = [{ id: 1, name: "iPhone", stock: 100 }];    ← 小李的

# Step 4:手动融合——保留两边的改动:
# 编辑 products.js:
# const products = [{ id: 1, name: "iPhone", price: 6999, stock: 100 }];

git add products.js
git commit -m "merge: 合并价格和库存字段"

# Step 5:再 push
git push origin master
# ✅ 成功!
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

# 6.2 ⚠️ 错误的处理方式(千万别学)

# ❌ 错误1:盲目 force push
git push --force
# 后果:小王的 commit 被覆盖,price 字段永远丢失

# ❌ 错误2:git pull 看到冲突就慌,放弃解决直接 force
git pull          # 冲突了
git push --force  # 💀 同事的代码没了

# ❌ 错误3:reset 远程到自己的版本
git reset --hard HEAD~1
git push --force  # 💀 同上
1
2
3
4
5
6
7
8
9
10
11

🛑 团队铁律:git push --force 需要至少两个人确认。更安全的是 git push --force-with-lease——它会在覆盖之前检查远程是否有人推了新代码,如果有人推了,它会拒绝执行。


# 七、版本标签

# 7.1 标签 vs 分支

分支 标签
本质 会移动的指针 固定的指针
作用 日常开发 标记里程碑
创建后 随新 commit 自动前进 永远钉在那个 commit 上
典型用途 feature/xxx、hotfix/xxx v1.0.0、v2.3.1

# 7.2 两种标签

mkdir tag-lab && cd tag-lab && git init

echo "v1.0 代码" > app.js
git add . && git commit -m "v1.0.0 发布"

# 轻量标签:只是一个指向 commit 的引用
git tag v1.0.0

# 附注标签:包含作者、日期、message(推荐)
git tag -a v1.0.1 -m "修复了登录崩溃的版本"

# 给过去的 commit 打标签
git log --oneline
# abc1234 v1.0.0 发布
git tag -a v0.9.0 abc1234 -m "第一个内部测试版"

# 查看标签
git tag                        # 列出所有
git tag -l "v1.*"              # 按模式过滤
git show v1.0.1                # 查看标签详细信息

# 推送标签到远程(push 默认不推标签!)
git push origin v1.0.1         # 推送单个标签
git push origin --tags         # 推送所有标签

# 删除标签
git tag -d v0.9.0              # 删除本地
git push origin :refs/tags/v0.9.0  # 删除远程(冒号语法)

# 基于标签开分支(发布后修 bug)
git checkout -b hotfix/v1.0.1 v1.0.1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

💡 发布规范:每次正式发布用附注标签(-a),message 写清楚"这个版本修了什么"。语义化版本:主版本号.次版本号.修订号(例如 v2.1.3 = 主版本 2 + 新增了 1 个功能 + 打了 3 次补丁)。


# 八、综合实战

# 场景设定

你是小李,团队要发布电商平台 v1.0.0。你负责完善商品搜索功能,小王负责修一个购物车 bug。你们通过 GitHub Flow 协作。

# 实战开始

# ==================== Phase 1:准备工作(小李视角) ====================
mkdir shop-collab && cd shop-collab && git init

echo 'const products = [
  { id: 1, name: "iPhone 15", price: 6999, category: "手机" },
  { id: 2, name: "MacBook Pro", price: 12999, category: "电脑" },
  { id: 3, name: "AirPods", price: 1299, category: "配件" }
];

function getAllProducts() {
  return products;
}
' > products.js

echo 'const cart = [];
function addToCart(productId) {
  const product = products.find(p => p.id === productId);
  if (product) cart.push(product);
}
' > cart.js

echo '# 电商平台项目
## 安装
```bash
npm install
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

# 启动

npm start
1

' > README.md

git add . && git commit -m "init: 电商平台基础代码"

# 假设已 push 到 GitHub(https://github.com/team/shop.git)

git remote add origin https://github.com/team/shop.git git push -u origin master

# 打第一个标签

git tag -a v0.1.0 -m "项目初始化完成" git push origin v0.1.0

# ==================== Phase 2:小李开发商品搜索功能 ====================

git switch -c feature/商品搜索

echo ' function searchProducts(keyword) { return products.filter(p => p.name.includes(keyword) || p.category.includes(keyword) ); }

function searchByPrice(min, max) { return products.filter(p => p.price >= min && p.price <= max); } ' >> products.js

git add . && git commit -m "feat: 添加商品搜索功能"

echo ' function sortProducts(sortBy = "price") { return [...products].sort((a, b) => a[sortBy] - b[sortBy]); } ' >> products.js

git add . && git commit -m "feat: 添加商品排序功能"

# 整理 commit,准备提 PR

git rebase -i HEAD~2

# 把两个 squash 成一个:

# feat: 实现完整商品搜索功能(关键字搜索 + 价格区间 + 排序)

# 推送并创建 PR

git push -u origin feature/商品搜索

# 去 GitHub 创建 Pull Request

# base: master ← compare: feature/商品搜索

# 标题:feat: 实现完整商品搜索功能

# 等待审查...

# ==================== Phase 3:小王修购物车 bug ====================

# 切换到小王视角(你在另一台电脑/目录模拟)

cd .. git clone https://github.com/team/shop.git wang-shop cd wang-shop

git switch -c bugfix/购物车重复添加

# bug:addToCart 没有检查重复,同一个商品可以加多次

# 修复:

cat > cart.js << 'EOF' const cart = [];

function addToCart(productId) { const product = products.find(p => p.id === productId); if (!product) return;

const existing = cart.find(item => item.id === productId); if (existing) { existing.quantity += 1; } else { cart.push({ ...product, quantity: 1 }); } }

function removeFromCart(productId) { const idx = cart.findIndex(item => item.id === productId); if (idx !== -1) cart.splice(idx, 1); } EOF

git add . && git commit -m "fix: 修复购物车重复添加 bug,添加移除功能"

git push -u origin bugfix/购物车重复添加

# 去 GitHub 创建 PR

# ==================== Phase 4:审查 & 合并 ====================

# 审查者在 GitHub 上审查两个 PR

# 场景1:审查通过 → Merge

# 小李的 feature/商品搜索 审查通过,点击 "Merge pull request"

# 场景2:审查提了修改意见

# 审查者留言:"searchByPrice 的边界条件没处理,min 可能大于 max"

# 小李修复:

git switch feature/商品搜索

# 在 searchByPrice 开头加:

# if (min > max) [min, max] = [max, min];

git add . && git commit -m "fix: 处理搜索价格区间边界条件" git push origin feature/商品搜索

# PR 自动更新,审查者重新审查 → 通过 → Merge

# 场景3:小王的 bugfix PR 也通过了 → Merge

# ==================== Phase 5:发布 v1.0.0 ====================

# 两个 PR 都合并到 master 后,准备发布

# 小李拉最新 master

git switch master git pull origin master

# 确认所有功能都在

git log --oneline

# 输出类似:

# abcdef1 Merge pull request #2 (bugfix/购物车重复添加)

# 1234567 Merge pull request #1 (feature/商品搜索)

# 0000000 init: 电商平台基础代码

# 打发布标签

git tag -a v1.0.0 -m "v1.0.0 正式版发布:商品搜索功能上线 + 购物车 bug 修复" git push origin v1.0.0

# 🎉 发布完成!

# ==================== Phase 6:清理战场 ====================

# 删除远程已合并的分支

git push origin --delete feature/商品搜索 git push origin --delete bugfix/购物车重复添加

# 清理本地分支

git branch -d feature/商品搜索

# 如果本地没有 bugfix 分支,先 fetch 一下远程分支信息

git fetch --prune

# --prune 会清理本地已经不存在的远程分支引用

# 看看干净的状态

git branch -v

# * master abcdef1 Merge pull request #2

# 一切井然有序!


### 🎯 时间线全景

1
2
3
                9:00 AM              10:00 AM           11:00 AM           12:00 PM
──────────────────┼────────────────────┼──────────────────┼──────────────────┼────→
                   │                    │                  │                  │
小李:创建 feature │ 开发中...          │ 提 PR             │ 审查通过         │
小王:创建 bugfix  │ 开发中...          │ 提 PR             │ 审查通过         │
                   │                    │                  │                  │
远程 master:  v0.1.0 ──────────────── 无变化 ────────── Merge #1 ──── Merge #2
                   │                    │                  │                  │
                   │                    │                  │            打 tag v1.0.0 🎉

---

## 九、本章回顾

| 我学会了什么 | 一句话总结 |
|---|---|
| 远程仓库概念 | `origin` 只是别名;远程和本地是平等的 Git 仓库 |
| fetch vs pull | `fetch` 只看不改;`pull` = fetch + merge(更激进) |
| 最佳实践 | 永远先 `fetch` → 查看 → 再决定 merge 还是 rebase |
| clone | 一键获取完整仓库 + 历史 + remote 配置 |
| PR 工作流 | 分支开发 → push → 提 PR → 审查 → 合并 → 清理分支 |
| 多人冲突 | fetch → diff → merge → 解决冲突 → commit → push |
| `push --force` 的代价 | 能覆盖别人的代码,团队协作禁用 |
| 标签 | 轻量标签只是指针;附注标签(-a)含完整信息,推荐用于发布 |
| 语义化版本 | `主.次.修订`——v2.1.3:主版本 2 + 1 个功能 + 3 次补丁 |

> 🎯 **核心习惯(三个)**:
> 1. **永远先 fetch 再决定**——不要盲目 `git pull`。
> 2. **用 PR 而不是直接 push master**——审查是质量的最后防线。
> 3. **`git push --force` 是核武器**——永远用 `--force-with-lease`,永远先确认。

---

> 🏃 **下一章预告**:基础都学完了。接下来是「特种作战」技巧——`stash` 临时保存工作现场、`cherry-pick` 精准移植一个 commit、`bisect` 二分法定位 bug。当你遇到「改了一半被叫去修 bug」「只想把某个 commit 挪到另一个分支」这些场景时,这些技巧就是你的瑞士军刀。

---

### 📎 本章涉及的命令速查

```bash
# === 远程仓库管理 ===
git remote -v                                       # 查看所有远程仓库
git remote add <name> <url>                         # 添加远程
git remote rename <old> <new>                       # 重命名
git remote remove <name>                            # 删除远程

# === 推送与拉取 ===
git push <remote> <branch>                          # 推送
git push -u <remote> <branch>                       # 推送并建立追踪
git fetch <remote>                                  # 拉取(不改工作区)
git fetch --prune                                   # 拉取并清理无效远程引用
git pull <remote> <branch>                          # fetch + merge
git pull --rebase <remote> <branch>                 # fetch + rebase(推荐)

# === 克隆 ===
git clone <url>                                     # HTTPS 克隆
git clone git@github.com:user/repo.git              # SSH 克隆
git clone <url> <folder-name>                       # 指定目录名

# === 标签 ===
git tag                                             # 列出所有标签
git tag -l "v1.*"                                   # 按模式过滤
git tag <name>                                      # 轻量标签
git tag -a <name> -m "message"                      # 附注标签(推荐)
git tag -a <name> <commit-hash> -m "message"        # 给过去的 commit 打标签
git show <tag>                                      # 查看标签详情
git push origin <tag>                               # 推送单个标签
git push origin --tags                              # 推送所有标签
git tag -d <tag>                                    # 删除本地标签
git push origin :refs/tags/<tag>                    # 删除远程标签

# === 分支清理 ===
git push origin --delete <branch>                   # 删除远程分支
git fetch --prune                                   # 同步删除后的远程分支状态

# === 安全推拉检查 ===
git log --oneline <branch>..<remote/branch>         # 看远程比我多了什么
git log --oneline <remote/branch>..<branch>         # 看我比远程多了什么
git diff <branch> <remote/branch>                   # 看具体差异
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
#Git
上次更新: 2026/06/07, 10:26:12
分支:Git 的灵魂——像开平行宇宙一样开发
Git特种作战:stash、cherry-pick、bisect三件套

← 分支:Git 的灵魂——像开平行宇宙一样开发 Git特种作战:stash、cherry-pick、bisect三件套→

最近更新
01
信号崩溃快速排查
06-15
02
CoreDump破案
06-15
03
perf火焰图实战
06-15
更多文章>
Theme by Vdoing | Copyright © 2019-2026 杨充 | MIT License | 桂ICP备2024034950号 | 桂公网安备45142202000030
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式