Git的git merge 和 git rebase操作

在日常开发过程中,rebase很容易和merge混淆,因为就结果而言,两条命令是类似的,具体请看

1. git merge branch-name

git merge branch-name 就是将名为branch-name的分支合并到当前分支的意思,如果在merge的过程中遇到冲突,那么就解决冲突,然后提交本地仓库就行。

2. git rebase branch-name

git rebase branch-name的意思就是改变当前分支的基点为名称为branch-name分支最新的提交,假设当前的分支状态如下图所示:

假设 master 是主流分支,development 是某个测试分支,当测试完局部功能之后接到master分支的owner通知,说 master 已经有了新的改动,所有的局部功能测试必须基于新的 master 状态,此时对于development分支来说,就需要对自己当前的分支”改变几点“。如下代码所示:

$git checkout development
$git rebase master  

rebase后如果有冲突,那么就解决冲突,冲突解决之后,调用 git commit 进行提交即可,rebase成功后如图所示:

rebase 后,之前的提交并没有被删除,而依然存在,并且自动新添加了两个提交,分别为D1'和D3' 。新添加的提交内容D1'是D1和C2的差别,D3'是D3和C2的差别。rebase的具体过程是找到两个分支的共同父节点,在本例中就是C2,找到父节点之后,逐个找到当前分支中的每个节点与父节点之间的差别,并保存在一个临时文件中,然后把这个临时文件应用到目标基点上。

理论上来说,development最终的状态D3,也可以通过合并D3和C4来实现,然而,merge和rebase 还是有一些区别。

  • rebase和merge 所产生的提交记录不同,并且rebase后会产生"无引用"的提交,比如D3和D1。
  • rebase的理念是改变“局部小功能”基点,基点对应的是“主体大功能”;而merge的理念是相同重量功能的合并。
  • rebase 一般是临时性的合并,比如本例中,development 分支可能还需要继续针对该功能进行开发,当前只是为了和基础代码保持一致而已;而 merge 一般是阶段性的合并,合并后有可能不再针对该功能单独开发,并且合并后会删除临时性的分支。

rebase 除了改变当前分支的基点外,还可以改变当前分支中某段修改的基点。这句话的含义是当开发某个局部功能时,假设局部功能由三个小功能组成:f1, f2, f3 , 当前测试表明 f2 和 f3 是比较稳定的,而f1 有些不稳定。可是master 分支要求尽快提交已经成熟的功能,此时就可以仅仅针对f2和f3改变基点,这个真是太灵活了,在执行 rebase 之前的分支状态如下:

 执行以下命令之后的分支状态如下所示:

$git rebase --onto master issue1 development

--onto 选项的含义是把development分支中与issue1分支“共父”的那一段f1提交排除,然后把剩余的f2,f3提交保留,rebase到master分支上。 

 git rebase实操部分

一、将development分支变基到master分支最新

1. 首先准备好各个分支的提交,如下是master分支和develoment分支的提交历史

$ git log
commit 46552acf1fb63ea060bc5b11c9f74cfc639137d5 (HEAD -> master)
Author: zhangfengzhou <zhangfengzhou@qq.com>
Date:   Sun Aug 29 17:12:30 2021 +0800

    master分支提交的第三行代码

commit 1334235f768ffea125c9514335649f4769fec862
Author: zhangfengzhou <zhangfengzhou@qq.com>
Date:   Sun Aug 29 17:08:21 2021 +0800

    master分支提交的第二行代码

commit 7c5927b52bbe4afb1b7bc110c0664020bcebff1e
Author: zhangfengzhou <zhangfengzhou@qq.com>
Date:   Sun Aug 29 17:05:29 2021 +0800

    master分支提交的第一行代码
$ git checkout -
Switched to branch 'development'
$ git log
commit 8de590739612b334dcb36137fb30b1c5c0cb233b (HEAD -> development)
Author: zhangfengzhou <zhangfengzhou@qq.com>
Date:   Sun Aug 29 17:11:06 2021 +0800

    development提交的第二行代码

commit 89cf38f3f0f7cfde153025285e24d138d274a06a
Author: zhangfengzhou <zhangfengzhou@qq.com>
Date:   Sun Aug 29 17:09:56 2021 +0800

    development分支提交的第一行代码

commit 1334235f768ffea125c9514335649f4769fec862
Author: zhangfengzhou <zhangfengzhou@qq.com>
Date:   Sun Aug 29 17:08:21 2021 +0800

    master分支提交的第二行代码

commit 7c5927b52bbe4afb1b7bc110c0664020bcebff1e
Author: zhangfengzhou <zhangfengzhou@qq.com>
Date:   Sun Aug 29 17:05:29 2021 +0800

    master分支提交的第一行代码

2. 在developemnt分支上进行变基操作

# development分支 hello.txt中的内容
master分支提交的第一行代码
masetr分支提交的第二行代码
developemnt分支提交的第一行代码
development分支提交的第二行代码
# master分支中 hello.txt中的内容
master分支提交的第一行代码
masetr分支提交的第二行代码
master分支提交的第三行代码
# 执行 git rebase master 发生的冲突
master分支提交的第一行代码
masetr分支提交的第二行代码
<<<<<<< HEAD
master分支提交的第三行代码
=======
developemnt分支提交的第一行代码
>>>>>>> development分支提交的第一行代码
master分支提交的第一行代码
masetr分支提交的第二行代码
master分支提交的第三行代码
developemnt分支提交的第一行代码
development分支提交的第一行代码

开始正式的变基操作,如下: 

# 当前分支是 development 分支
$ git rebase master
First, rewinding head to replay your work on top of it...
Applying: development分支提交的第一行代码
Using index info to reconstruct a base tree...
M	hello.txt
Falling back to patching base and 3-way merge...
Auto-merging hello.txt
CONFLICT (content): Merge conflict in hello.txt
error: Failed to merge in the changes.
Patch failed at 0001 development分支提交的第一行代码
hint: Use 'git am --show-current-patch' to see the failed patch
Resolve all conflicts manually, mark them as resolved with
"git add/rm <conflicted_files>", then run "git rebase --continue".
You can instead skip this commit: run "git rebase --skip".
To abort and get back to the state before "git rebase", run "git rebase --abort".

# 解决冲突
zfz:practise zhangfengzhou$ vim hello.txt
zfz:practise zhangfengzhou$ git status
rebase in progress; onto 46552ac
You are currently rebasing branch 'development' on '46552ac'.
  (fix conflicts and then run "git rebase --continue")
  (use "git rebase --skip" to skip this patch)
  (use "git rebase --abort" to check out the original branch)

Unmerged paths:
  (use "git reset HEAD <file>..." to unstage)
  (use "git add <file>..." to mark resolution)

	both modified:   hello.txt

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

# 执行 git add hello.txt 操作,标记冲突已经解决
$ git add hello.txt
$ git status
rebase in progress; onto 46552ac
You are currently rebasing branch 'development' on '46552ac'.
  (all conflicts fixed: run "git rebase --continue")

Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

	modified:   hello.txt

$ git rebase --continue
Applying: development分支提交的第一行代码
Applying: development提交的第二行代码
Using index info to reconstruct a base tree...
M	hello.txt
Falling back to patching base and 3-way merge...
Auto-merging hello.txt
CONFLICT (content): Merge conflict in hello.txt
master分支提交的第一行代码
error: Failed to merge in the changes.
Patch failed at 0002 development提交的第二行代码
hint: Use 'git am --show-current-patch' to see the failed patch
Resolve all conflicts manually, mark them as resolved with
"git add/rm <conflicted_files>", then run "git rebase --continue".
You can instead skip this commit: run "git rebase --skip".
To abort and get back to the state before "git rebase", run "git rebase --abort".

$ vim hello.txt
$ git add hello.txt
$ git status
rebase in progress; onto 46552ac
You are currently rebasing branch 'development' on '46552ac'.
  (all conflicts fixed: run "git rebase --continue")

Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

	modified:   hello.txt

$ git rebase --continue
Applying: development提交的第二行代码

# 已经rebase成功,可以发现development分支已经变基到master的第三次提交之后
$ git log
commit 9399e2c70025e3af4dbc8b0297849f09650e6336 (HEAD -> development)
Author: zhangfengzhou <zhangfengzhou@qq.com>
Date:   Sun Aug 29 17:11:06 2021 +0800

    development提交的第二行代码

commit f60b59a00677ea836c1a06fd4600244e4370015c
Author: zhangfengzhou <zhangfengzhou@qq.com>
Date:   Sun Aug 29 17:09:56 2021 +0800

    development分支提交的第一行代码

commit 46552acf1fb63ea060bc5b11c9f74cfc639137d5 (master)
Author: zhangfengzhou <zhangfengzhou@qq.com>
Date:   Sun Aug 29 17:12:30 2021 +0800

    master分支提交的第三行代码

commit 1334235f768ffea125c9514335649f4769fec862
Author: zhangfengzhou <zhangfengzhou@qq.com>
Date:   Sun Aug 29 17:08:21 2021 +0800

    master分支提交的第二行代码

commit 7c5927b52bbe4afb1b7bc110c0664020bcebff1e
Author: zhangfengzhou <zhangfengzhou@qq.com>
Date:   Sun Aug 29 17:05:29 2021 +0800

    master分支提交的第一行代码

$ git log --pretty=oneline
9399e2c70025e3af4dbc8b0297849f09650e6336 (HEAD -> development) development提交的第二行代码
f60b59a00677ea836c1a06fd4600244e4370015c development分支提交的第一行代码
46552acf1fb63ea060bc5b11c9f74cfc639137d5 (master) master分支提交的第三行代码
1334235f768ffea125c9514335649f4769fec862 master分支提交的第二行代码
7c5927b52bbe4afb1b7bc110c0664020bcebff1e master分支提交的第一行代码

二、将development分支中比较稳定的一段提交变基到master分支

$rebase --onto master issue1 development 

# 注意 issue1是被排除的分支 development是被rebase分支,master是目标分支

1. 首先看下各个分支的提交记录

$ git log --pretty=oneline
55de7558a605b7c5e2f2de1316cc99cd95773da3 (HEAD -> master) M3,主线功能M3
cc86398b66f0c58388f1e58e7e3f8227c7fafab7 M2,主线功能M2
6a329ba64e3f358f3579dd9d5800e142778ee47b M1,主线功能M1
# develope分支的提交记录

$ git log --pretty=oneline
8ba962657e1465113ef2b62c5cfaa78547f02cef (HEAD -> development) develop分支添加Feature3功能
d8f6b88f7cffcc2a8ce73bb26e671f2855859208 develop分支添加Feature2功能
53456308a4c2463c89d074c9390e75d147f9e57b develop分支添加Feature1功能
6a329ba64e3f358f3579dd9d5800e142778ee47b (master) M1,主线功能M1
# issue1 分支
$ git log --pretty=oneline
cc8941e240efacf0d85419f7e27928a79cb46e3d (HEAD -> issue1) 发现feature1问题,等待修改
53456308a4c2463c89d074c9390e75d147f9e57b develop分支添加Feature1功能
6a329ba64e3f358f3579dd9d5800e142778ee47b M1,主线功能M1

开始执行 rebase --onto 操作,将development分支与issue1“共父”的一段,rebase到master分支上

根据某次commit 创建新的分支

1、git log 查看提交
2、通过checkout 跟上commitId 即可创建制定commit之前的本地分支
#    git checkout commitId -b 本地新branchName

3、 commitId 后面的提交便不会出现在新分支上面了

$ git checkout 5345630 -b issue1  # 根据commitId 来创建新的本地分支
Switched to a new branch 'issue1'

$ git checkout development
Switched to branch 'development'

# 排除issue1和development分支共有的内容,然后将其他的内容rebase到master分支上
# 注意顺序,否则就会发生错误

$ git rebase --onto master issue1 development
First, rewinding head to replay your work on top of it...
Applying: develop分支添加Feature2功能
Applying: develop分支添加Feature3功能
zfz:rebase_onto zhangfengzhou$ git log
commit d6e559591234612a7a59f11820377c3470dc50a5 (HEAD -> development)
Author: zhangfengzhou <zhangfengzhou@qq.com>
Date:   Sun Aug 29 18:18:42 2021 +0800

    develop分支添加Feature3功能

commit 298ce776423e914922581feb5f0beff5b9e60d27
Author: zhangfengzhou <zhangfengzhou@qq.com>
Date:   Sun Aug 29 18:17:41 2021 +0800

    develop分支添加Feature2功能

commit 55de7558a605b7c5e2f2de1316cc99cd95773da3 (master)
Author: zhangfengzhou <zhangfengzhou@qq.com>
Date:   Sun Aug 29 18:23:39 2021 +0800

    M3,主线功能M3

commit cc86398b66f0c58388f1e58e7e3f8227c7fafab7
Author: zhangfengzhou <zhangfengzhou@qq.com>
Date:   Sun Aug 29 18:22:46 2021 +0800

    M2,主线功能M2

# rebase成功之后,查看devlopment分支的提交记录,发现Feature1功能的提交已经被删除
$ git log --pretty=oneline
d6e559591234612a7a59f11820377c3470dc50a5 (HEAD -> development) develop分支添加Feature3功能
298ce776423e914922581feb5f0beff5b9e60d27 develop分支添加Feature2功能
55de7558a605b7c5e2f2de1316cc99cd95773da3 (master) M3,主线功能M3
cc86398b66f0c58388f1e58e7e3f8227c7fafab7 M2,主线功能M2
6a329ba64e3f358f3579dd9d5800e142778ee47b M1,主线功能M1

参考:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
`git rebase` 和 `git merge` 都是 Git 中用于合并分支的操作,但它们的工作方式和影响略有不同: 1. **git rebase**: - **原理**: `git rebase` 将一个分支(通常是你的工作分支)的提交历史移动到另一个分支(通常是最新的主分支,如 `master` 或 `main`)之上,这样整个分支的历史看起来像是连续的。它会应用目标分支的每个提交到你的分支上,然后记录一个新的提交。 - **优点**: 可能导致更干净的提交历史,因为提交顺序更加线性,便于阅读和追踪更改。同时,如果在 rebase 过程中发现错误,可以很容易地进行编辑或交互式处理。 - **缺点**: 如果目标分支在你 rebase 期间有其他人的提交,可能会导致你的分支与主干产生冲突,需要解决。此外,如果在公共仓库中使用不当,可能会导致历史混乱。 2. **git merge**: - **原理**: `git merge` 合并两个分支的内容,创建一个新的提交,该提交包含合并点之后两分支的所有更改。这个操作不会改变原有分支的提交历史,而是添加一个新的提交到合并点之后。 - **优点**: 更安全,因为合并操作不会改变已有分支的历史,不会对其他开发者造成困扰。更适合用于合并已经稳定的代码更改。 - **缺点**: 提交历史不连续,可能导致分支分支图显得混乱。如果有大量的合并,历史审查可能会变得困难。 **相关问题--:** 1. 在什么情况下你会选择使用 `git rebase`? 2. 在哪些情况下你更倾向于使用 `git merge`? 3. 如果我想保留原始提交顺序并避免冲突,应该使用哪种方法?

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值