Skip to content

Daily Study

更新: 7/28/2025 字数: 0 字 时长: 0 分钟

Daily Plan

#todo

  • [ ]

Git 冲突解决

分支问题

当两个或多个开发者在不同的分支上对同一文件的同一部分进行了修改,并在合并(Merge)或变基(Rebase)时,Git 无法自动判断应保留哪个版本,便会产生冲突。

Git 冲突的根源

  • 内容冲突 (Content Conflict):这是最常见的冲突类型。两个分支修改了同一个文件的相同行
  • 文件与目录的修改/删除冲突 (Modify/Delete Conflict):一个分支修改了某个文件,而另一个分支删除了这个文件。Git 不知道是应该保留修改后的文件,还是彻底删除它。

冲突的识别

当执行 git mergegit pull (pull = fetch + merge) 命令时,如果发生冲突,Git 会在命令行中给出明确提示,指出哪些文件存在冲突。

$ git merge feature-branch
Auto-merging your-file.txt
CONFLICT (content): Merge conflict in your-file.txt
Automatic merge failed; fix conflicts and then commit the result.

此时,使用 git status 命令可以查看冲突文件的详细状态:

$ git status
On branch master
You have unmerged paths.
  (fix conflicts and run "git commit")
  (use "git merge --abort" to abort the merge)

Unmerged paths:
  (use "git add <file>..." to mark resolution)
        both modified:   your-file.txt

no changes added to commit (use "git add" and/or "git commit -a")

Git 会在冲突的文件中插入特殊的冲突标记

Here is some content that is not in conflict.
<<<<<<< HEAD This is the content from your current branch (master). 
======= This is the content from the feature-branch. >>>>>>> feature-branch And here is more content that is not in conflict.

各类冲突的解决办法

1. 内容冲突 (Content Conflict)

这是最常见的冲突场景。

解决方法:

  1. 手动编辑
  2. 暂存已解决的文件:使用 git add 命令将手动解决后的文件标记为“已解决”。
  3. 提交合并:当所有冲突文件都已解决并暂存后,执行 git commit 来完成整个合并过程。Git 会自动生成一个合并提交(Merge Commit)信息。

如果你确定要完全接受某一方的修改,可以使用 git checkout 命令快速解决。

  • 完全采用当前分支的版本
git checkout --ours your-file.txt
  • 完全采用被合并分支的版本
git checkout --theirs your-file.txt

使用上述命令后,别忘了 git add your-file.txtgit commit

2. 修改/删除冲突 (Modify/Delete Conflict)

当一个分支修改了文件,而另一个分支删除了它时,git status 会显示如下信息:

Unmerged paths:
  (use "git add/rm <file>..." as appropriate to mark resolution)
        deleted by them: a-file.txt
        modified by us:  a-file.txt

解决方法:

  • 如果决定保留该文件 (保留修改):使用 git add 将文件重新添加到暂存区。
git add a-file.txt
  • 如果决定删除该文件 (接受删除):使用 git rm 将该文件从工作区和暂存区删除。git rm a-file.txt

完成选择后,同样执行 git commit 来完成合并。

3. 文件重命名冲突 (Rename Conflict)

当两个分支都对同一个文件进行了重命名,或者一个分支重命名了文件,而另一个分支修改了原文件时,也可能产生冲突。例如,两个分支都重命名了 old-name.txt:

Unmerged paths:
  (use "git add <file>..." to mark resolution)
        added by us:     new-name-ours.txt
        added by them:   new-name-theirs.txt
        both deleted:    old-name.txt

解决方法:

  • 保留其中一个:假设保留 new-name-theirs.txt,则需要删除另一个,并把正确的版本添加到暂存区。
git rm new-name-ours.txt
# 确保 new-name-theirs.txt 的内容是正确的,如果它也有内容冲突,需要先解决
git add new-name-theirs.txt
  • 如果重命名的同时还修改了内容,导致内容冲突:你需要先选择一个文件名,将另一个文件的内容合并进去,解决内容冲突后,再删除多余的文件并 git add 正确的文件
4. 二进制文件冲突

对于图片、视频、编译后的库等二进制文件,Git 无法像文本文件一样展示冲突内容。如果发生冲突,Git 会提示文件是二进制文件,无法自动合并。

解决方法:

二进制文件的冲突解决非常直接:二选一。使用 git checkout --oursgit checkout --theirs 来选择保留哪个版本。

Merge 与 Rebase 中的冲突解决

虽然冲突的本质相同,但在 mergerebase 过程中的解决流程略有不同。

  • git merge
    • 所有冲突在一次合并操作中全部暴露出来。
    • 解决所有文件的冲突后,只需执行一次 git commit 即可生成一个新的合并提交。
    • 整个过程是:merge -> 解决所有冲突 -> add -> commit
  • git rebase
    • Rebase 会将当前分支的提交一个个地“重放”到目标分支上。
    • 冲突是逐个提交出现的。你解决完一个提交带来的冲突后,需要使用 git rebase --continue 来继续处理下一个提交,直到所有提交都重放完毕。
    • 整个过程是:rebase -> 遇到冲突 -> 解决冲突 -> add -> git rebase --continue -> (重复直到结束)

Rebase 过程中的常用指令:

  • git rebase --continue:在解决完当前冲突并 git add 之后,用此命令继续 rebase 过程。
  • git rebase --skip:完全跳过当前这个提交(即放弃这个提交的所有修改)。
  • git rebase --abort:取消整个 rebase 操作,分支将回到 rebase 开始之前的状态。

有用的工具和命令

  • git merge --abort / git rebase --abort 如果在解决冲突时感到困惑或把事情搞砸了,随时可以使用这两个命令来撤销合并或变基,一切将回到操作开始前的状态,可以安全地重来一次。

  • git mergetool 对于不习惯在命令行和文本编辑器中直接修改冲突标记的开发者,可以使用图形化的合并工具。配置好后,运行 git mergetool 会为每个冲突文件启动一个可视化界面,更直观地展示差异并进行合并。

    常见的 mergetool 包括:kdiff3, p4merge, meld, beyond compare 等。

  • git log --merge

    在合并冲突期间,此命令可以清晰地展示出导致冲突的双方分支的提交历史,帮助理解上下文。

权限问题

主要使用两个命令:

  • 使用 ls -la 查看文件所属的用户和用户组,出现问题常见的原因:
    • 文件是root的,但是你得用user用户来push和pull,导致Permission Deny
    • 使用root打开了类似Claude Code,然后CC进行编辑文件所属于root
  • 使用 sudo chown -R <用户>:<用户组> . 来更改文件的权限

Git Fetch

既然 git pull 看起来更直接,为什么我们还要用 git fetch?因为“先检查再合并”的工作流在很多场景下更安全、更专业。

  1. 检查远程更新而不影响当前工作 这是最核心的用途。你可能正在处理一个复杂的任务,不想被远程的更新打断。你可以随时执行 git fetch,然后使用 git log 或图形化工具查看远程分支有哪些新提交。

    # 1. 获取所有远程更新
    git fetch origin
    
    # 2. 比较你本地的 main 分支和远程的 main 分支有什么不同
    git log main..origin/main
    
    # 3. 如果你使用的是图形化工具(如 VS Code, GitKraken),
    #    你可以在分支视图中直观地看到 origin/main 比你的 main 超前了几个提交。
  2. 保持代码审查(Code Review)的同步 当同事在另一个分支上推送了更新,并请你进行代码审查时,你可以这样做:

    # 1. 获取最新的所有分支信息
    git fetch origin
    
    # 2. 切换到同事的分支进行审查,这个分支现在只存在于你的本地仓库中
    git checkout origin/feature-colleague
    # 注意:此时你会处于一个“分离头指针”状态,这是只读审查的理想状态。
  3. 清理过时的远程跟踪分支 当远程仓库删除了某个分支后,你本地的远程跟踪分支(如 origin/deleted-feature)默认还会存在。使用带 --prune-p 选项的 fetch 可以清理掉这些无效的“书签”。

    # 下载更新的同时,删除本地不再存在的远程跟踪分支
    git fetch --prune origin
  4. 在合并前选择合并策略 git pull 默认使用 merge 策略。但有时你可能想使用变基(rebase)来保持提交历史的线性。fetch 给了你这个选择权。

    # 推荐的工作流:
    # 1. 获取更新
    git fetch
    
    # 2. 查看更新(可选但推荐)
    git log main..origin/main
    
    # 3. 决定使用 rebase 而不是 merge 来同步更新
    git rebase origin/main

菜就多练

本站访客数 人次 本站总访问量