跳至正文
来两杯美式
返回

Git 知识系列(四):分支管理与远程协作

By 来两杯美式
发布于

Git 鼓励大量使用分支,本篇覆盖本地分支操作、合并策略、远程协作三大块。

本地分支

$ git branch                  # 列出所有本地分支(当前分支前有 *)
$ git branch <name>           # 创建新分支(不切换)
$ git checkout <name>         # 切换分支
$ git checkout -b <name>      # 创建并切换
$ git branch -d <name>        # 删除分支(已合并才能删)
$ git branch -D <name>        # 强制删除(未合并也能删)

恢复未提交的文件到线上最新版本

$ git checkout -- <filename>

或带匹配符:

$ git checkout -- src/*.java

恢复的是 HEAD 指向版本,工作区未提交的改动会丢失。

合并策略

git merge 基础

$ git merge <branch>          # 把 branch 合并到当前分支

合并时 Git 默认启用 fast-forward——如果当前分支没有新提交,Git 只会把指针向前移动,看起来像没合并过一样。

--no-ff 模式合并

$ git merge --no-ff <branch>

强制生成一个 merge commit,保留分支历史

# fast-forward 后
A - B - C - D         (看不出 D 是合并进来的)

# --no-ff 后
A - B - C - M         M 是合并提交,能看出曾经做过合并
       \         /
        D - E - F

何时用 —no-ff:合并 feature 分支到 main 时,建议用 --no-ff,让 git log 能看到”这里曾经合并过 feature 分支”,便于追溯。

冲突解决流程

合并两个分支时如果改了同一行,Git 会停下来让你手动解决:

$ git merge feature-x
# Auto-merging src/UserService.java
# CONFLICT (content): Merge conflict in src/UserService.java
# Automatic merge failed; fix conflicts and then commit the result.

冲突文件里会出现冲突标记:

public class UserService {
<<<<<<< HEAD
    private String name = "main";      // 当前分支的版本
=======
    private String name = "feature";   // 传入分支的版本
>>>>>>> feature-x
}

解决步骤:

  1. 手动编辑文件,决定保留哪段或合并两段
  2. 删除 <<<<<<<=======>>>>>>> 标记
  3. git add <file>(标记冲突已解决)
  4. git commit(Git 默认会带 merge message)

也可以 git merge --abort 放弃这次合并,回到合并前的状态。

rebase vs merge 取舍

git rebase 把当前分支的提交”重放”到目标分支最新提交之后,让历史变直线:

$ git checkout feature
$ git rebase main             # 把 feature 的提交重放到 main 最新位置

对比

维度mergerebase
历史真实保留分支结构改成直线(改写历史)
适用分支公共分支私有本地分支
协作风险已推送的提交 rebase 会让别人 pull 困难

黄金法则

“未推送用 rebase,已推送用 merge”

  • 在私有 feature 分支上提交 → rebase 整理后再合并
  • 已经推送到公共分支的提交 → 永远不要 rebase

远程分支

查看远程分支

$ git branch -a               # 看所有分支(本地 + 远程)
$ git branch -vv              # 看每个本地分支的远程追踪关系
$ git remote -v               # 看远程仓库地址

推送新分支

$ git push origin <branch>
$ git push -u origin <branch>   # -u 建立追踪关系

删除远程分支

$ git push origin -d <branch>          # 简写
$ git push origin --delete <branch>    # 完整写法

切换远程分支到本地

clone 项目后想切到已有的远程分支上开发:

$ git branch -a
# * master
#   remotes/origin/dev
#   remotes/origin/master

错误做法(推荐度低):

$ git checkout -b dev
# 这种方式创建的 dev 跟远程 dev **毫无关系**,只是名字相同
# 下次 push 会报"没有追踪信息"的错

正确做法:

# 方式一:直接 checkout 远程分支
$ git checkout dev                  # 自动追踪 origin/dev

# 方式二:显式指定来源
$ git checkout -b dev origin/dev

效果对比:

git branch -a

切到 dev 后再 push 时如果报”没有追踪信息”:

pull/push 报错

解决:

$ git push -u origin dev

-u 相当于建立”本地 dev 永远对应远程 origin/dev”的关系,之后 push/pull 不用再带参数。

远程分支名带 origin/ 前缀的原因

git branch -a 看到的 remotes/origin/dev远程跟踪分支——它只是本地对远程分支状态的缓存,不是真正的”远程分支”。本地可以基于它创建工作分支,但不要直接提交到远程跟踪分支上。

fetch vs pull

$ git fetch <remote>            # 下载远程更新,**不自动合并**
$ git pull <remote>             # fetch + merge 的组合
命令行为适用场景
git fetch只下载,需要手动 merge/rebase想先看更新再决定
git pull自动 fetch + merge快速同步

推荐做法:本地用 git pull --rebase,等价于”fetch + rebase”,让本地历史保持直线。

多人协作的标准流程

1. git push origin branch-name
   ↓ 失败(远程比本地新)
2. git pull
   ↓ 无冲突 → 直接 push 成功
   ↓ 有冲突 → 解决冲突 → commit → push

如果 git pull 提示 “no tracking information”,说明本地分支和远程分支的链接关系没建立:

$ git branch --set-upstream branch-name origin/branch-name

或者推送时直接 -u

$ git push -u origin branch-name

强制推送的安全姿势

如果需要覆盖远程分支(rebase 之后、删了某些 commit 后),需要 force push:

$ git push --force                 # 直接覆盖(危险,可能丢别人的提交)
$ git push --force-with-lease      # 推荐:只在"远程没被别人推过新提交"时才覆盖

--force-with-lease--force 安全:它会先检查远程分支是否和你上次 fetch 的一致,不一致就拒绝 push——避免无意中覆盖别人的提交。


下一篇:Git 知识系列(五):标签、忽略与子模块,讲 tag 的轻量/附注区别、.gitignore 语法、submodule 子模块管理。


分享这篇文章:
通过邮件分享这篇文章✓ 链接已复制
所属专题
Git
第 4 / 8 篇
查看系列全部文章
  1. 01.Git 知识系列(一):安装与基础配置
  2. 02.Git 知识系列(二):日常工作流
  3. 03.Git 知识系列(三):撤销与回退
  4. 04.Git 知识系列(四):分支管理与远程协作
  5. 05.Git 知识系列(五):标签、忽略与子模块
  6. 06.Git 知识系列(六):仓库维护与排错
  7. 07.Git 知识系列(七):Submodule 操作指南
  8. 08.Git 知识系列(八):多 Remote 双向同步

上一篇
Git 知识系列(五):标签、忽略与子模块
下一篇
Git 知识系列(三):撤销与回退