开发过程中经常要进行代码的合并,然而合并的时候会有冲突,下面通过rebase实现冲突的解决,这个目前是最好的方式:
git rebase 解决分支冲突的操作[适用于很多分支,很多功能一起开发的场景,前提是在已经知道有冲突的情况下,通过这种方式解决冲突,比如 gitlab下新增了merge request]
k8s@root:~/code/sciforum.net$ git rebase origin/dev
fatal: It seems that there is already a rebase-merge directory, and
I wonder if you are in the middle of another rebase. If that is the
case, please try
git rebase (--continue | --abort | --skip)
If that is not the case, please
rm -fr ".git/rebase-merge"
and run me again. I am stopping in case you still have something
valuable there.
#如果报上面的提示,可能之前执行过rebase,这里我就执行 rm -fr ".git/rebase-merge",然后再次执行git rebase origin/dev,那么就会提示哪些地方冲突了,直接修改文件,解决冲突
#当冲突解决完了,直接 [git add .] 然后, git commit -m 'fix conflict' [如果是首次提交的话,需要 add, 如果已经将分支推送到远程仓库,那就直接commit]
k8s@root:~/code/sciforum.net$ git rebase --continue //必须要执行
dropping 43672c0b5a9a08108cd72e6ea07cf7c6f79047a2 SCIF-211 -- patch contents already upstream
Successfully rebased and updated refs/heads/SCIF-211-t.
#再执行 git push --force origin <分支名>,[如果你已经将分支推送到远程仓库,并且之后对该分支进行了 git rebase 操作,那么你必须使用 --force 标志来覆盖远程分支上的历史记录。这是因为 rebase 会修改提交历史,不允许通过普通推送来更新远程分支。如果这里不用 forece的话,通过普通的push,可能会报本地和远程对应的分支冲突,需要merge,所以直接forece最好了,因为就是想把本地的应用到对应的远程.]
#注意事项:
在使用这个命令的过程中,我发现一个问题,有如下场景:
比如说我的代码分值为 tt, 修改了如下内容:
$a = "hello world",
然后我执行 git rebase origin/dev
然后提示冲突,对比文件发现
左边$a="say no",右边为$a="say yes",我希望看到的是 左边为我当前的修改 $a="hello world",但是现在不是,那就没办法直接进行比对操作
解决办法是:只能删除<<<<<<< HEAD和=======之间的行,以及>>>>>>> origin/dev之后的行,然后手动把 $a="hello world" 写到这个位置
针对这个问题,我通过Chat-GPT了解到如下内容:
问:
但是就是不明白为什么会出现这种情况,那不是我最新的修改在解决冲突的时候,有被覆盖的风险吗
答:
你的困惑是理解git rebase过程中的冲突解决方式的一个常见问题。在git rebase过程中,Git会将你的本地提交按顺序应用到目标分支(在你的情况下是origin/dev),因此冲突发生时,Git会尝试合并两个不同的更改。
问:
这句 在git rebase过程中,Git会将你的本地提交按顺序应用到目标分支 其中按顺序是什么意思,为什么不是最新提交呢
答:
在Git中,git rebase命令将会将你的本地提交按照它们的提交顺序(时间顺序)依次应用到目标分支上。这意味着git rebase会从你当前分支的最旧提交开始,然后逐个应用你的本地提交,直到最新的提交。因此,它会按照提交历史中的时间顺序应用这些提交,而不是按照它们在分支上的顺序。
这个行为的原因是为了确保在目标分支上的提交历史中,你的本地提交按照它们在时间上的顺序排列,以保持提交历史的一致性和可读性。这样,目标分支上的提交历史将会看起来好像你的更改是在最初的基础上按照顺序逐个应用的。
如果git rebase按照最新提交的顺序应用本地提交,可能会导致一些问题,因为这可能会破坏提交历史的顺序性,使提交历史变得混乱难以理解。
所以,虽然你的最新提交可能会在git rebase过程中被处理,但它会在其他提交之后。当有冲突时,Git会停下来等待你解决冲突,以确保在合并过程中不会丢失任何信息。
问:
也就是说 我上面的问题 :
$a = "hello world",
然后我执行 git rebase origin/dev
然后提示冲突,对比文件发现
左边$a="say no",右边为$a="say yes"
这个$a="say no" 是我之前的某一次旧的提交,和dev 冲突了吗,然后 我最新的提交 $a = "hello world", 还没有被应用
答:
是的,根据你的描述,$a="say no" 是你之前的某一次旧的提交,而$a = "hello world" 是你的最新提交。当你执行git rebase origin/dev时,Git 将尝试将你的本地提交按照它们的提交顺序应用到 origin/dev 分支上。
在这个过程中,Git 首先会尝试应用旧的提交$a="say no",然后应用你的最新提交 $a = "hello world"。如果在这两个提交之间存在冲突,Git 会停止重播过程并提示你解决这些冲突。
所以,$a="say no" 与 origin/dev 分支上的某些提交冲突,导致了冲突的发生。在冲突解决之前,你的最新提交 $a = "hello world" 尚未被应用到 origin/dev 分支上。你需要手动解决冲突并继续重播过程,以确保你的最新修改被正确地应用到最终的分支状态中。
其实上面出现的旧代码,并不是我们需要的,实际上我们只需要把最新的版本和目标版本比较就可以了,可以通过下面的方法实现:
执行: $ git rebase -i origin/dev , 加上-i参数,会发现如下信息:
pick ee14fc5fa scif-309
pick d53e200e1 scif-309
pick 00dd45cee scif-309
pick 44ba1cb64 scif-309
pick 794e04704 scif-309
pick c8e8284aa scif-309 //这个是最新一次提交的内容
...
...
我们要选择:pick c8e8284aa scif-309 进行rebase, 需要如下操作:
可以直接编辑,改为
drop ee14fc5fa scif-309
drop d53e200e1 scif-309
drop 00dd45cee scif-309
drop 44ba1cb64 scif-309
drop 794e04704 scif-309
pick c8e8284aa scif-309
...
...
^G Help ^O Write Out ^W Where Is ^K Cut ^T Execute ^C Location M-U Undo M-A Set Mark M-] To Bracket M-Q Previous ^B Back ^◂ Prev Word ^A Home
^X Exit ^R Read File ^\ Replace ^U Paste ^J Justify ^/ Go To Line M-E Redo M-6 Copy ^Q Where Was M-W Next ^F Forward ^▸ Next Word ^E End
然后下面又有这么多命令,我要选择哪个保存呢,选择 ^O Write Out [ctrl+O]即可,当执行了ctrl+O以后,会出现下面的信息:
File Name to Write: /home/k8s/code/sciforum.net/.git/rebase-merge/git-rebase-todo //这里也是可以输入信息的,默认可以不输入,直接点击 Enter 键就可以了 [必须要敲enter]
^G Help M-D DOS Format M-A Append M-B Backup File
^C Cancel M-M Mac Format M-P Prepend ^T Browse
然后再ctrl+X 即可完成当前rebase.
大概率会出现如下信息, 下面的就是合并[最新的代码]的过程,以及冲突:
Auto-merging src/Controller/Admin/DashboardController.php
Auto-merging src/Entity/Submission.php
CONFLICT (content): Merge conflict in src/Entity/Submission.php
error: could not apply c8e8284aa... scif-309
hint: Resolve all conflicts manually, mark them as resolved with
hint: "git add/rm <conflicted_files>", then run "git rebase --continue".
hint: You can instead skip this commit: run "git rebase --skip".
hint: To abort and get back to the state before "git rebase", run "git rebase --abort".
Could not apply c8e8284aa... scif-309
然后就是手动解决冲突,然后提交,注意这里只用 commit,不要push
然后再执行:$ git rebase --continue
Successfully rebased and updated refs/heads/SCIF-309-t. //因为我们已经选择了最新的版本,所以这个 continue 不会再继续rebase了,直接给结果
这样整个冲突就解决完了,最后将当前分支直接覆盖到远程:
$ git push --force origin SCIF-309-t
更新 feature 分支,使它基于最新 base 分支, 同时整理分支, 使用rebase -X 实现
🔄 流程解释
git fetch origin
git rebase -X ours origin/base-branch
git push --force origin feature-branch
git fetch origin- 拉取远程仓库最新的提交到本地引用。
- 不改动你当前分支,只更新
origin/base-branch等远程分支信息。
git rebase -X ours origin/base-branch- 把当前分支(
feature-branch)的提交 重新应用在origin/base-branch最新提交上。 -X ours:如果发生冲突,优先保留你的feature-branch改动。- 最终结果:你的 feature 分支基于最新的 base 分支,同时保留你的修改。
- 把当前分支(
git push --force origin feature-branch因为 rebase 改写了提交历史,所以必须强制推送。
更新远程
feature-branch,远程base-branch不受影响。更安全做法:
git push --force-with-lease origin feature-branch避免意外覆盖别人提交。
💡 场景总结
- 用途:保持 feature 分支基于最新 base 分支开发,同时整理提交历史。
- 特点:不会产生 merge commit,提交历史整洁。
- 注意事项:
- 仅适用于个人的 feature 分支,如果多人共用,需要注意强推风险。
