Skip to content

数据拉取与推送

远程仓库的数据同步是团队协作的核心操作,包括拉取(fetch/pull)和推送(push)。

git fetch:仅拉取,不合并

git fetch 从远程仓库下载新数据,但不修改本地工作区和当前分支:

bash
# 拉取默认远程仓库(origin)的所有分支
git fetch

# 拉取指定远程仓库
git fetch origin

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

# 拉取特定分支
git fetch origin main
git fetch origin feature/login

# 拉取并清理已删除的远程分支(见后面章节)
git fetch --prune
git fetch -p      # 简写

fetch 之后需要手动合并:

bash
git fetch origin
git log HEAD..origin/main --oneline  # 查看有哪些新提交
git merge origin/main                 # 合并到当前分支
# 或
git rebase origin/main

fetch 的优势:

  • 安全:不会改变本地工作状态
  • 可以先查看远程改动再决定如何合并
  • 更新所有远程追踪分支(origin/*)

git pull:拉取并合并

git pullgit fetch + git merge 的组合:

bash
# 拉取并合并(默认:fetch + merge)
git pull

# 拉取指定分支
git pull origin main

# 等价于:
git fetch origin main
git merge origin/main

git pull --rebase:拉取并变基

bash
# 拉取并用 rebase 代替 merge
git pull --rebase
git pull --rebase origin main

# 等价于:
git fetch origin
git rebase origin/main

优点: 保持线性历史,避免产生不必要的合并提交

推荐配置: 将 rebase 设为 pull 的默认行为:

bash
git config --global pull.rebase true

pull --rebase 的工作原理:

远程:A ← B ← C(新提交)
本地:A ← D(本地提交)

git pull --rebase 后:
A ← B ← C ← D'(D 被重新应用到 C 之后)

git push:推送到远程

bash
# 推送当前分支到远程同名分支
git push

# 推送到指定远程和分支
git push origin main
git push origin feature/login

# 推送所有分支
git push --all origin

git push -u:设置上游追踪

首次推送新分支时,使用 -u 设置追踪关系:

bash
# 推送并设置 upstream(上游追踪)
git push -u origin feature/login
git push --set-upstream origin feature/login

# 设置后,后续直接 git push/pull 即可
git push
git pull

追踪关系的作用:

  • git push 不带参数时,知道推送到哪里
  • git pull 不带参数时,知道从哪里拉取
  • git status 显示与追踪分支的领先/落后关系

git push --force vs --force-with-lease

--force(危险!)

强制推送,直接覆盖远程分支,不管远程是否有新提交:

bash
git push --force
git push -f         # 简写

风险: 如果有人在你之后推送了提交,你的 force push 会直接覆盖他们的工作!

--force-with-lease(推荐)

更安全的强制推送:只有当远程与你预期的状态一致时,才允许推送:

bash
git push --force-with-lease
git push --force-with-lease origin main

如果远程在你最后一次 fetch 之后有新提交,--force-with-lease拒绝推送并报错,避免覆盖他人的工作。

什么时候需要 force push?

  • 修改了已推送的提交(amend)
  • 对功能分支进行了 rebase
  • 清理了提交历史(interactive rebase)

黄金法则: 永远不要对共享分支(main、develop)进行 force push!

git push --tags:推送标签

bash
# 推送所有本地标签
git push --tags
git push origin --tags

# 推送单个标签
git push origin v1.0.0

# 不推送标签(默认 push 不包含标签)
git push    # 默认不推送标签

git push 删除远程分支

bash
# 删除远程分支(新语法)
git push origin --delete feature/login

# 删除远程分支(旧语法,等价)
git push origin :feature/login

# 删除远程标签
git push origin --delete v1.0.0
git push origin :refs/tags/v1.0.0

推送配置

bash
# 设置默认 push 行为(只推送当前分支对应的远程分支)
git config --global push.default current
# simple    - 只推送有追踪关系的同名分支(2.0+ 默认)
# current   - 推送到同名分支(无论是否设置追踪)
# upstream  - 推送到上游分支(可以不同名)
# matching  - 推送所有有对应关系的分支(旧默认)
# nothing   - 不推送任何东西(需要明确指定)

# 自动设置追踪(推送时自动 -u)
git config --global push.autoSetupRemote true  # Git 2.37+

实用场景

首次发布项目

bash
git init -b main
git add .
git commit -m "Initial commit"
git remote add origin git@github.com:user/repo.git
git push -u origin main

日常工作流

bash
# 开始工作前同步
git pull --rebase

# 完成功能后推送
git push

# 推送新功能分支
git switch -c feature/new-feature
# 开发...
git push -u origin feature/new-feature

推送前检查

bash
# 检查本地与远程的差异
git fetch
git log origin/main..HEAD --oneline  # 查看将要推送的提交

# 确认无误后推送
git push

处理推送冲突

bash
# 推送时提示:
# ! [rejected] main -> main (non-fast-forward)
# hint: Updates were rejected because the tip of your current branch is behind
# hint: its remote counterpart.

# 解决方案1:先拉取,再推送
git pull --rebase
git push

# 解决方案2(只有个人分支):force push
git push --force-with-lease

理解 fetch 和 pull 的区别

                      远程仓库
                      /      \
                 fetch        \
                /              \
          origin/main         (网络)
              |
           merge/rebase
              |
            HEAD(本地分支)

pull = fetch + merge/rebase(一步完成)

建议养成的习惯: 优先使用 git fetch + 手动合并,这样可以在合并前查看远程的改动,做出更明智的决策。

总结

操作命令说明
只拉取不合并git fetch安全,不修改工作区
拉取并合并git pullfetch + merge
拉取并变基git pull --rebasefetch + rebase,保持线性
推送git push推送到追踪分支
首次推送设追踪git push -u origin <branch>设置追踪关系
安全强制推送git push --force-with-lease优于 git push -f
删除远程分支git push origin --delete <branch>
推送标签git push --tags