Git 详细使用指南 - 合并冲突处理与工作原理

98 阅读6分钟

目录

  1. Git 基础概念
  2. Git 工作流程
  3. Git Pull 与合并处理详解
  4. 合并冲突解决方案
  5. Git 分支策略
  6. 高级技巧
  7. Git 内部原理

Git 基础概念

Git 是一个分布式版本控制系统,它跟踪文件随时间的变化,并允许多人协作开发。

核心区域

graph LR
    A[工作区 Working Directory] --> B[暂存区 Staging Area]
    B --> C[本地仓库 Local Repository]
    C --> D[远程仓库 Remote Repository]

文件状态

graph LR
    A[未跟踪 Untracked] -->|git add| B[已暂存 Staged]
    C[已修改 Modified] -->|git add| B
    B -->|git commit| D[已提交 Committed]
    D -->|修改文件| C

Git 工作流程

基本工作流程包括:

  1. 克隆/初始化仓库
  2. 创建/切换分支
  3. 修改文件
  4. 暂存更改
  5. 提交更改
  6. 推送到远程
  7. 拉取远程更新

常用命令

# 初始化仓库
git init

# 克隆仓库
git clone <repository-url>

# 查看状态
git status

# 添加文件到暂存区
git add <file>
git add .  # 添加所有更改

# 提交更改
git commit -m "提交信息"

# 查看提交历史
git log
git log --graph --oneline --all  # 图形化展示所有分支

# 创建分支
git branch <branch-name>

# 切换分支
git checkout <branch-name>
# 或使用新命令(Git 2.23+)
git switch <branch-name>

# 创建并切换分支
git checkout -b <branch-name>
# 或使用新命令
git switch -c <branch-name>

# 推送到远程
git push origin <branch-name>

# 拉取远程更新
git pull origin <branch-name>

Git Pull 与合并处理详解

git pull 实际上是 git fetchgit merge 的组合操作。

sequenceDiagram
    participant 本地仓库
    participant 远程仓库
    本地仓库->>远程仓库: git fetch (获取远程更新)
    远程仓库-->>本地仓库: 返回远程分支信息
    本地仓库->>本地仓库: git merge (合并到本地分支)

Pull 的不同方式

  1. 普通合并 (默认)
git pull origin master
# 等同于
git fetch origin master
git merge origin/master
  1. 使用 rebase 方式
git pull --rebase origin master
# 等同于
git fetch origin master
git rebase origin/master

Pull 策略选择

flowchart TD
    A[是否有本地未推送的提交?] -->|是| B[本地提交是否形成独立功能?]
    A -->|否| C[使用默认 pull 即可]
    B -->|是| D[建议使用 --rebase]
    B -->|否| E[可使用普通 merge]
    D --> F[git pull --rebase]
    E --> G[git pull]
    C --> G

合并冲突解决方案

git pullgit merge 遇到冲突时,需要手动解决。

冲突解决流程

flowchart TD
    A[执行 git pull] --> B{是否有冲突?}
    B -->|是| C[查看冲突文件]
    B -->|否| D[合并完成]
    C --> E[编辑解决冲突]
    E --> F[git add 标记为已解决]
    F --> G[git commit 完成合并]
    G --> H[推送到远程 git push]

解决冲突的详细步骤

  1. 识别冲突文件
git pull
# 如果有冲突,会显示类似信息
# CONFLICT (content): Merge conflict in <filename>
# Automatic merge failed; fix conflicts and then commit the result.

# 查看冲突文件
git status
  1. 理解冲突标记

冲突文件中会包含类似标记:

<<<<<<< HEAD
本地修改的内容
=======
远程修改的内容
>>>>>>> branch-name
  1. 解决冲突方法

    a. 手动编辑:直接编辑冲突文件,删除冲突标记,保留需要的内容

    b. 使用合并工具

    git mergetool
    

    c. 选择其中一个版本

    # 使用当前分支(HEAD)的版本
    git checkout --ours <filename>
    
    # 使用合并进来的分支版本
    git checkout --theirs <filename>
    
  2. 标记为已解决并提交

# 标记文件冲突已解决
git add <filename>

# 完成合并提交
git commit
# 此时会自动生成合并提交信息,可以修改或直接保存

高级合并策略

# 在合并时指定策略
git pull -s recursive -X ours    # 冲突时优先保留本地修改
git pull -s recursive -X theirs  # 冲突时优先保留远程修改
git pull -s recursive -X patience # 使用patience算法,更智能地处理代码移动

# 放弃合并
git merge --abort

使用 Rebase 处理冲突

# 拉取并使用rebase方式合并
git pull --rebase

# 当遇到冲突时
# 1. 解决冲突
# 2. 标记为已解决
git add <conflicted-files>

# 3. 继续rebase
git rebase --continue

# 放弃rebase
git rebase --abort

Git 分支策略

Gitflow 工作流

gitGraph
    commit
    commit
    branch develop
    checkout develop
    commit
    branch feature/login
    checkout feature/login
    commit
    commit
    checkout develop
    merge feature/login
    branch release/1.0
    checkout release/1.0
    commit
    checkout main
    merge release/1.0 tag: "v1.0"
    checkout develop
    merge release/1.0
    branch hotfix/1.0.1
    checkout hotfix/1.0.1
    commit
    checkout main
    merge hotfix/1.0.1 tag: "v1.0.1"
    checkout develop
    merge hotfix/1.0.1

推荐的分支策略

flowchart TD
    A[Main/Master] -->|"git checkout -b"| B[开发分支 Develop]
    B -->|"git checkout -b"| C[特性分支 Feature]
    C -->|"完成后 git merge"| B
    B -->|"准备发布 git checkout -b"| D[发布分支 Release]
    D -->|"完成后 git merge"| A
    D -->|"同时 git merge"| B
    A -->|"修复紧急bug git checkout -b"| E[热修复 Hotfix]
    E -->|"完成后 git merge"| A
    E -->|"同时 git merge"| B

高级技巧

交互式变基

# 对最近的 3 个提交进行重新整理
git rebase -i HEAD~3

常用选项:

  • pick:保留该提交
  • reword:修改提交信息
  • edit:修改该提交
  • squash:将该提交融合到前一个提交
  • fixup:将该提交融合到前一个提交,丢弃提交信息
  • drop:删除该提交

暂存工作区

# 暂存当前工作
git stash save "工作描述"

# 查看暂存列表
git stash list

# 应用最近的暂存
git stash apply

# 应用指定暂存
git stash apply stash@{1}

# 应用并删除暂存
git stash pop

# 删除所有暂存
git stash clear

精确查找

# 查找引入特定代码的提交
git log -S "代码片段"

# 查找某行代码的修改历史
git blame <file>

# 查找特定作者的提交
git log --author="作者名"

撤销操作

# 撤销工作区修改
git checkout -- <file>
# 或使用新命令
git restore <file>

# 撤销暂存区修改
git reset HEAD <file>
# 或使用新命令
git restore --staged <file>

# 修改最近的提交
git commit --amend

# 撤销提交(生成新提交)
git revert <commit-hash>

# 重置到指定提交
git reset --soft <commit-hash>  # 保留修改在暂存区
git reset --mixed <commit-hash> # 保留修改在工作区
git reset --hard <commit-hash>  # 丢弃所有修改

Git 内部原理

Git 的核心是一个简单的键值存储数据库,对象存储在 .git/objects 目录中。

Git 对象类型

classDiagram
    class Blob {
        +文件内容
    }
    class Tree {
        +指向Blob或子Tree
        +文件名/目录名
        +文件模式
    }
    class Commit {
        +指向Tree(项目根目录)
        +父Commit引用
        +作者信息
        +提交者信息
        +提交信息
    }
    class Tag {
        +指向Commit
        +标签名
        +标签信息
    }
    
    Commit --> Tree
    Tree --> Blob
    Tree --> Tree
    Tag --> Commit

分支与引用

分支本质上是指向某个提交对象的可移动指针,存储在 .git/refs/heads/ 目录中。

gitGraph
    commit id: "C1"
    commit id: "C2"
    branch feature
    checkout feature
    commit id: "C3"
    commit id: "C4"
    checkout main
    merge feature
    commit id: "C5"

上图中:

  • main 分支指针移动到合并提交 C5
  • feature 分支指针仍然指向 C4

合并原理

  1. 快进合并(Fast-forward):
gitGraph
    commit id: "A"
    commit id: "B"
    branch feature
    checkout feature
    commit id: "C"
    commit id: "D"
    checkout main
    merge feature

快进合并只是简单地将当前分支指针向前移动到目标分支的最新提交。

  1. 三方合并(3-way merge):
gitGraph
    commit id: "A"
    commit id: "B"
    branch feature
    checkout feature
    commit id: "C"
    checkout main
    commit id: "D"
    merge feature

三方合并会生成一个新的合并提交,它有两个父提交。

Rebase 原理

gitGraph
    commit id: "A"
    commit id: "B"
    branch feature
    checkout feature
    commit id: "C"
    commit id: "D"
    checkout main
    commit id: "E"
    checkout feature
    commit id: "C'" type: HIGHLIGHT
    commit id: "D'" type: HIGHLIGHT

Rebase 会找到共同祖先(B),然后依次应用 feature 分支上的更改(C、D)到 main 分支的最新提交(E)之上,生成新的提交(C'、D')。

Git Pull 完整流程

sequenceDiagram
    participant 工作区
    participant 本地仓库
    participant 远程仓库
    
    本地仓库->>远程仓库: git fetch (获取远程引用和对象)
    远程仓库-->>本地仓库: 传输对象和引用
    
    alt 无冲突
        本地仓库->>本地仓库: 快进合并
        本地仓库->>工作区: 更新工作区文件
    else 有冲突,普通合并
        本地仓库->>本地仓库: 创建合并提交
        本地仓库->>工作区: 标记冲突文件
        工作区->>本地仓库: 解决冲突并提交
    else 有冲突,rebase方式
        本地仓库->>本地仓库: 暂存本地提交
        本地仓库->>本地仓库: 应用远程提交
        本地仓库->>本地仓库: 重放本地提交
        本地仓库->>工作区: 标记冲突文件
        工作区->>本地仓库: 解决冲突并继续rebase
    end

实战技巧

处理大型合并冲突

当面临大型项目合并时:

  1. 提前同步:定期从主分支拉取更新

    # 在特性分支上定期执行
    git fetch origin master
    git merge origin/master
    # 或
    git rebase origin/master
    
  2. 分块合并:复杂功能分多个小分支开发

    # 创建子功能分支
    git checkout -b feature/part1
    git checkout -b feature/part2
    
    # 逐个合并到开发分支
    git checkout develop
    git merge feature/part1
    git merge feature/part2
    
  3. 使用合并工具:配置好的合并工具能极大提高效率

    # 配置合并工具
    git config --global merge.tool vscode
    git config --global mergetool.vscode.cmd 'code --wait $MERGED'
    
    # 使用
    git mergetool
    

Git Pull 冲突处理流程图

flowchart TD
    A[git pull] --> B{是否有冲突?}
    B -->|否| C[完成]
    B -->|是| D{冲突类型?}
    
    D -->|文件内容冲突| E[使用文本编辑器或合并工具解决]
    D -->|文件删除/修改冲突| F[选择保留或删除]
    
    E --> G{内容复杂度?}
    G -->|简单| H[手动编辑]
    G -->|复杂| I[使用git mergetool]
    
    H --> J[删除冲突标记]
    I --> J
    F --> J
    
    J --> K[git add 标记为已解决]
    K --> L{所有冲突已解决?}
    L -->|否| E
    L -->|是| M[git commit 完成合并]
    M --> C

高效处理合并冲突的最佳实践

  1. 提前了解变更范围

    # 查看将要合并的分支有哪些变更
    git log --oneline master..feature
    
    # 查看具体文件变更
    git diff master...feature
    
  2. 预先检查潜在冲突

    # 模拟合并,不实际提交
    git merge --no-commit --no-ff feature
    # 检查后取消
    git merge --abort
    
  3. 合并前先清理工作区

    # 检查工作区状态
    git status
    
    # 暂存当前工作
    git stash
    
    # 合并后恢复
    git stash pop
    
  4. 使用特定合并策略

    # 冲突时优先采用本地版本
    git merge -X ours feature
    
    # 冲突时优先采用合入版本
    git merge -X theirs feature
    
  5. 大型项目合并建议

    # 先创建临时分支进行合并测试
    git checkout -b temp_merge
    git merge feature
    # 测试成功后再合并到主分支
    

总结

Git 是一个功能强大的版本控制系统,掌握合并冲突处理是高效使用 Git 的关键技能。通过理解 Git 的内部原理,采用合适的分支策略,使用正确的合并方法,可以大大提高团队协作效率,减少合并冲突带来的麻烦。