Git: Git拉取与远程更新详解

拉取(Pull)是从远程仓库获取更新并合并到本地分支的操作。通过拉取,可以同步团队成员的修改,保持本地代码与远程一致。理解pull与fetch的区别对团队协作至关重要。

1. 拉取基础概念

(1) 什么是拉取

拉取是两个操作的组合:

  1. fetch:从远程仓库下载更新
  2. merge:将远程分支合并到当前分支
100%
graph TB
    A[远程仓库<br/>Remote] -->|git fetch| B[远程分支副本<br/>origin/main]
    B -->|git merge| C[当前分支<br/>main]
    
    A -.->|git pull = fetch + merge| C
    
    style A fill:#d4edda
    style B fill:#fff3cd
    style C fill:#c3e6cb

(2) pull vs fetch

操作 说明 影响
pull fetch + merge 修改当前分支
fetch 只下载更新 不修改当前分支

(3) 拉取的作用


2. 基本拉取操作

(1) 拉取当前分支

▶ 示例:拉取更新

BASH
# 拉取当前分支的更新
git pull

# 输出:
# remote: Enumerating objects: 5, done.
# remote: Counting objects: 100% (5/5), done.
# remote: Compressing objects: 100% (3/3), done.
# remote: Total 3 (delta 1), reused 0 (delta 0), pack-reused 0
# Unpacking objects: 100% (3/3), 285 bytes | 285.00 KiB/s, done.
# From https://github.com/user/repo
#    a1b2c3d..d4e5f6g  main        -> origin/main
# Updating a1b2c3d..d4e5f6g
# Fast-forward
#  file.js | 1 +
#  1 file changed, 1 insertion(+)

(2) 拉取指定分支

▶ 示例:拉取指定分支

BASH
# 拉取指定远程分支
git pull origin main

# 拉取远程分支到本地不同名称的分支
git pull origin remote-branch:local-branch

# 拉取所有远程分支的更新
git pull --all

# 拉取并查看详细信息
git pull --verbose

(3) 拉取前的检查

▶ 示例:拉取前检查

BASH
# 查看本地和远程的差异
git fetch
git diff main origin/main

# 查看远程的新提交
git log main..origin/main

# 输出:
# d4e5f6g (origin/main) feat: 添加新功能
# h7i8j9k fix: 修复Bug

# 查看将要拉取的文件
git diff --name-only main origin/main

# 输出:
# src/auth.js
# src/user.js

# 确认后再拉取
git pull

3. 拉取策略

(1) 使用merge拉取(默认)

▶ 示例:merge拉取

BASH
# 默认使用merge拉取
git pull

# 等价于
git fetch
git merge origin/main

# 拉取后会产生合并提交(如果有分叉)
git log --oneline --graph

# 输出:
# *   a1b2c3d Merge branch 'main' of https://github.com/user/repo
# |\
# | * d4e5f6g (origin/main) Remote commit
# * | h7i8j9k Local commit
# |/
# * k9l0m1n Base commit

(2) 使用rebase拉取

▶ 示例:rebase拉取

BASH
# 使用rebase拉取
git pull --rebase

# 输出:
# remote: Enumerating objects: 5, done.
# From https://github.com/user/repo
#    a1b2c3d..d4e5f6g  main        -> origin/main
# First, rewinding head to replay your work on top of it...
# Fast-forwarded main to d4e5f6g.

# 查看历史(线性,无合并提交)
git log --oneline --graph

# 输出:
# * h7i8j9k Local commit
# * d4e5f6g (origin/main) Remote commit
# * k9l0m1n Base commit

(3) merge vs rebase拉取

100%
graph TB
    subgraph merge拉取
        A1[本地提交] --> M1[合并提交]
        B1[远程提交] --> M1
    end
    
    subgraph rebase拉取
        A2[远程提交] --> B2[本地提交<br/>rebase后]
    end
    
    style M1 fill:#fff3cd
    style B2 fill:#d4edda

merge拉取:

rebase拉取:


4. 拉取冲突处理

(1) 拉取时产生冲突

▶ 示例:拉取冲突

BASH
# 本地和远程修改了同一文件
git pull

# 输出:
# remote: Enumerating objects: 5, done.
# From https://github.com/user/repo
#    a1b2c3d..d4e5f6g  main        -> origin/main
# Auto-merging file.js
# CONFLICT (content): Merge conflict in file.js
# Automatic merge failed; fix conflicts and then commit the result.

(2) 解决拉取冲突

▶ 示例:解决冲突

BASH
# 查看冲突状态
git status

# 输出:
# You have unmerged paths.
#   (fix conflicts and run "git commit")
# 
# Unmerged paths:
#   (use "git add <file>..." to mark resolution)
#   both modified:   file.js

# 查看冲突内容
cat file.js

# 输出:
# <<<<<<< HEAD
# 本地修改内容
# =======
# 远程修改内容
# >>>>>>> d4e5f6g

# 编辑文件解决冲突
# 保留需要的内容

# 标记冲突已解决
git add file.js

# 完成合并
git commit

# 推送到远程
git push

(3) 取消拉取

▶ 示例:取消拉取

BASH
# 拉取产生冲突,想取消
git merge --abort

# 或者
git reset --merge

# 对于rebase拉取
git rebase --abort

5. 拉取选项详解

(1) 常用拉取选项

选项 说明 使用场景
--rebase 使用rebase拉取 保持线性历史
--no-rebase 使用merge拉取 保留完整历史
--ff-only 只允许快进合并 确保无分叉
--force 强制拉取 覆盖本地修改
--all 拉取所有远程 更新所有远程
--dry-run 模拟拉取 预览拉取内容

▶ 示例:使用拉取选项

BASH
# 只允许快进合并
git pull --ff-only

# 输出(如果不能快进):
# fatal: Not possible to fast-forward, aborting.

# 模拟拉取
git pull --dry-run

# 拉取所有远程仓库
git pull --all

# 设置默认拉取方式
git config pull.rebase true  # 默认使用rebase
git config pull.rebase false # 默认使用merge
git config pull.ff only      # 只允许快进

(2) 拉取特定远程

▶ 示例:拉取特定远程

BASH
# 拉取origin
git pull origin

# 拉取upstream
git pull upstream main

# 拉取特定分支
git pull origin feature

# 拉取并设置上游
git pull --set-upstream origin feature

6. pull vs fetch详解

(1) fetch的使用

▶ 示例:使用fetch

BASH
# 获取远程更新(不合并)
git fetch origin

# 输出:
# remote: Enumerating objects: 5, done.
# From https://github.com/user/repo
#    a1b2c3d..d4e5f6g  main        -> origin/main
#  * [new branch]      feature     -> origin/feature

# 查看远程分支
git branch -r

# 输出:
#   origin/main
#   origin/feature

# 查看远程更新
git log origin/main

# 比较差异
git diff main origin/main

# 手动合并
git merge origin/main

# 或者rebase
git rebase origin/main

(2) 何时使用fetch

100%
graph TB
    A[需要查看远程更新] --> B[使用fetch]
    B --> C[查看差异]
    C --> D{是否合并?}
    D -->|是| E[手动merge/rebase]
    D -->|否| F[保持当前状态]
    
    style B fill:#d4edda
    style E fill:#c3e6cb

使用fetch的场景:

使用pull的场景:

(3) fetch + merge vs pull

▶ 示例:对比两种方式

BASH
# 方式1:直接pull
git pull origin main

# 方式2:fetch + merge(更安全)
git fetch origin
git diff main origin/main  # 查看差异
git merge origin/main      # 确认后合并

# 方式3:fetch + rebase
git fetch origin
git diff main origin/main
git rebase origin/main

7. 拉取最佳实践

(1) 日常拉取工作流

▶ 示例:推荐工作流

BASH
# 1. 开始工作前拉取最新代码
git checkout main
git pull --rebase origin main

# 2. 创建功能分支
git checkout -b feature/new-feature

# 3. 开发并提交
git add .
git commit -m "feat: 添加新功能"

# 4. 推送前再次拉取更新
git fetch origin
git rebase origin/main

# 5. 推送
git push origin feature/new-feature

(2) 处理拉取冲突的最佳实践

▶ 示例:冲突处理流程

BASH
# 拉取产生冲突
git pull

# 1. 查看冲突文件
git status

# 2. 使用工具解决冲突
git mergetool

# 3. 或者手动编辑文件

# 4. 测试代码
npm test

# 5. 标记冲突已解决
git add .

# 6. 完成合并
git commit

# 7. 推送
git push

(3) 保持分支同步

▶ 示例:定期同步

BASH
# 定期同步远程更新
git fetch origin

# 查看所有分支的状态
git branch -vv

# 输出:
# * main    a1b2c3d [origin/main: behind 3] feat: 添加功能
#   develop d4e5f6g [origin/develop: ahead 2] Fix: 修复Bug
#   feature h7i8j9k [origin/feature] WIP: 新功能

# 同步落后的分支
git checkout main
git pull

# 或者同步所有分支
git pull --all

❓ 常见问题

Q pull和fetch有什么区别?
A git pull = git fetch + git merge,会下载更新并合并到当前分支。git fetch 只下载更新,不修改当前分支,更安全。
Q 什么时候使用--rebase拉取?
A 当希望保持提交历史线性,避免产生合并提交时使用。rebase拉取会将本地提交放在远程提交之上,历史更清晰。
Q 拉取时产生冲突怎么办?
A 编辑冲突文件解决冲突,使用 git add 标记冲突已解决,然后 git commit 完成合并。如果不想解决冲突,可以使用 git merge --abort 取消拉取。
Q 如何查看远程有哪些新提交?
Agit fetch 下载更新,然后使用 git log HEAD..origin/main 查看远程的新提交,或使用 git diff HEAD origin/main 查看差异。
Q 拉取失败提示"unrelated histories"怎么办?
A 这表示本地和远程没有共同历史(如本地和远程分别初始化)。使用 git pull --allow-unrelated-histories 允许合并不相关的历史。

📖 小节


📝 作业

  1. 基础题:在本地仓库创建提交并推送到远程,然后在另一位置克隆仓库,修改并推送,回到原仓库拉取更新,体验完整的拉取流程。

  2. 进阶题:对比merge拉取和rebase拉取:在本地和远程分别创建提交,使用两种方式拉取,观察历史图的差异。

  3. 挑战题:模拟拉取冲突场景:在本地和远程修改同一文件的同一位置,拉取产生冲突,手动解决冲突并完成合并。

Web-Tutorial.com

Web-Tutorial 技术团队

由多位开发者共同维护的编程教程平台。每篇教程由对应领域的开发者编写和审核,确保内容准确可靠。如发现任何问题,欢迎向我们反馈。

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏