【Git 学习笔记】第四章 git rebase 变基操作与相关示例(下)

文章目录

    • [4.4 利用交互式变基聚合版本](#4.4 利用交互式变基聚合版本)
    • [4.5 利用交互式变基变更提交者](#4.5 利用交互式变基变更提交者)
    • [4.6 自动聚合版本](#4.6 自动聚合版本)

4.4 利用交互式变基聚合版本

在自己的新分支开发一个特性时,可能会产生多个细粒度的提交版本,而往往这些版本并不需要在并入正式分支时参与代码评审或功能测试。这时就需要在合并分支前,将本地分支通过交互式变基压缩成满足要求的精简版。

本节示例从 origin/stable-3.1 签出新分支 rebaseExample3,并在其中模拟出 6 个新增 commit 记录,然后演示怎样将这 6 个版本压缩为两个指定版本:

bash 复制代码
$ git checkout -b rebaseExample3 --track origin/stable-3.1
Switched to a new branch 'rebaseExample3'
Branch 'rebaseExample3' set up to track remote branch 'stable-3.1' from 'origin'.
$ git log origin/stable-3.1..origin/stable-3.2 --oneline --reverse
# Reset to the 7th commit listed
$ git reset --hard 5218f7b
# Rebase interactively
$ git rebase --interactive
hint: Waiting for your editor to close the file...

弹出编辑器界面如下:

将第二个、第四个版本改为 squash 后保存退出:

接着,git 会按指定的版本弹出两次编辑器窗口,用以确认被并入的两个 commit 的提交信息,可以不作任何修改,退出即可。Git 将自动完成其余工作:

bash 复制代码
$ git rebase --interactive
[detached HEAD f3ca970dd] Do not close ArchiveOutputStream on error
 Author: Jonathan Nieder <jrn@google.com>
 Date: Mon Sep 23 17:06:18 2013 -0700
 6 files changed, 537 insertions(+), 2 deletions(-)
 create mode 100644 org.eclipse.jgit.test/tst/org/eclipse/jgit/api/DescribeCommandTest.java
 create mode 100644 org.eclipse.jgit/src/org/eclipse/jgit/api/DescribeCommand.java
[detached HEAD b4e20341a] Prepare 3.2.0-SNAPSHOT builds
 Author: Matthias Sohn <matthias.sohn@sap.com>
 Date: Thu Oct 3 17:40:22 2013 +0200
 67 files changed, 422 insertions(+), 372 deletions(-)
 rewrite org.eclipse.jgit.http.server/META-INF/MANIFEST.MF (61%)
 rewrite org.eclipse.jgit.java7.test/META-INF/MANIFEST.MF (66%)
 rewrite org.eclipse.jgit.junit/META-INF/MANIFEST.MF (73%)
 rewrite org.eclipse.jgit.pgm.test/META-INF/MANIFEST.MF (61%)
 rewrite org.eclipse.jgit.pgm/META-INF/MANIFEST.MF (63%)
 rewrite org.eclipse.jgit.test/META-INF/MANIFEST.MF (77%)
 rewrite org.eclipse.jgit.ui/META-INF/MANIFEST.MF (67%)
 rewrite org.eclipse.jgit/META-INF/MANIFEST.MF (64%)
Successfully rebased and updated refs/heads/rebaseExample3.
# Check in gitk
$ gitk

结果如下:

示例拓展

除了关键词 squash,交互式变基过程中还可以使用 fixup 功能,区别在于:squash 会保留被压缩 commit 的提交信息,而 fixup 不会。可以通过 git log -1 查看结果,或者与最终版本比较差异:git diff 5218f7b。使用 fixup 的情况下,应该没有差异内容输出:

bash 复制代码
$ git checkout -b rebaseExample4 --track origin/stable-3.1
$ git log origin/stable-3.1..origin/stable-3.2 --reverse --oneline
$ git reset --hard 5218f7b33
$ git rebase --interactive
# Using fixup or f for short:

保存后关闭编辑器:

bash 复制代码
$ git rebase --interactive
Successfully rebased and updated refs/heads/rebaseExample4.
# Check via gitk
bash 复制代码
# Check via git status
$ git status -1
commit 9bb94368060f0af6cbf0138c0d10d9b7df98780a (HEAD -> rebaseExample4)
Author: Matthias Sohn <matthias.sohn@sap.com>
Date:   Thu Oct 3 17:40:22 2013 +0200

    Prepare 3.2.0-SNAPSHOT builds

    Change-Id: Iac6cf7a5bb6146ee3fe38abe8020fc3fc4217584
    Signed-off-by: Matthias Sohn <matthias.sohn@sap.com>
# no commit message related to fixup commits
# 
# Check git diff
$ git diff 5218f7b33
# no output as expected

实测效果:

与前述期望结果一致。

小结

  1. 交互式变基的编辑器视图中,commit 列表是按照从近到远的顺序展示的,与 git log 的默认顺序 相反
  2. squashfixup 的作用对象,是其 上一个pick 标记的 commit,时间顺序上看则是 下一个pickcommit
  3. 虽然选了 6 个版本来演示版本压缩,但实际进入操作列表的只有 4 个版本,另两个其实是合并产生的 commit,根据 Git 的相关文档,这样的 commit 不参与交互式变基,也不推荐使用 --preserve-merges 标记保留它们。

4.5 利用交互式变基变更提交者

开发一个新项目时,一开始可能设置的作者和邮箱并不是最终需要的,这时可能需要批量更正为正确的提交人信息。然而一般的 git commit --amend 只对 HEAD 处的 commit 有效,如果要应用到指定范围的 commit 对象上,可以借助交互式变基实现。

示例将从 master 分支签出一个新分支 resetAuthorRebase

bash 复制代码
# Checkout new branch from master
$ git checkout -b resetAuthorRebase -t origin/master
# Update HEAD's committer info (exit without modifying anything)
$ git commit --amend --reset-author
# Check the updated status (already updated)
$ git log --format='format:%h %an <%ae>' origin/stable-3.2..HEAD -5

b76ed52f8 SafeWinter <zandong_19@aliyun.com>
caea5a26f Matthias Sohn <matthias.sohn@sap.com>
284d2b5b9 Matthias Sohn <matthias.sohn@sap.com>
35713588f Matthias Sohn <matthias.sohn@sap.com>
1cffba438 Matthias Sohn <matthias.sohn@sap.com>
$ git rebase --interactive --exec "git commit --amend --reset-author --reuse-message=HEAD" origin/stable-3.2
# When the editor view appeared, close it without modification
# Check via git log
$ git log --format='format:%h %an <%ae>' origin/stable-3.2..HEAD
c5365deec SafeWinter <zandong_19@aliyun.com>
13512ccd0 SafeWinter <zandong_19@aliyun.com>
d54c9e86b SafeWinter <zandong_19@aliyun.com>
6f090c0ea SafeWinter <zandong_19@aliyun.com>
96260fb33 SafeWinter <zandong_19@aliyun.com>
0d55fae34 SafeWinter <zandong_19@aliyun.com>
308bd65f7 SafeWinter <zandong_19@aliyun.com>
849ec32b1 SafeWinter <zandong_19@aliyun.com>
9f5b85b33 SafeWinter <zandong_19@aliyun.com>
5a74b14af SafeWinter <zandong_19@aliyun.com>
... more logs omitted

实测效果:

小结

  1. 执行交互式变基时,一个非常重要的参数,是在 --exec 参数指定的命令中,加入 --reuse-message=HEAD,表示将 HEAD 的修改结果复用到变基命令指定的 commit 对象中。如果不加该参数,Git 就会逐一弹出编辑器窗口让用户确认提交消息。加了 --reuse-message=HEAD 后才能自动取消弹窗提示;
  2. --exec 有一个特性,就是在每次执行前,自动检测工作区是否有未暂存(unstaged)的内容,因此如果示例不是修改提交人信息(如修改源代码),则变基过程中可能中断报错。解决方案是将这些操作在一个 --exec 中一次性执行完毕。

本节示例功能虽然应用场景不常见,但却非常实用。


4.6 自动聚合版本

在新分支上修复项目 bug 时,本地可能有多个细粒度的提交版本,但最终修复 bug 并入 master 或总开发分支 develop 时,该 bug 应该只产生一个 bug 提交。根据 4.5 介绍的方法,可以使用交互式变基实现 commit 压缩;但作为常规操作流程,Git 还提供了一个现成的自动压缩(autosquashing),可以很方便地将本地多个 commit 压缩成一个统一的版本。

本节将演示 autosquashing 的用法。继续沿用 chapter4 本地库:

bash 复制代码
# Checkout a new branch from master branch
$ git checkout -b readme_update_developer --track origin/master
# Create a new commit
$ echo "More information for developers" >> README.md
$ git status
# here -a means adding any unstaged changes to the commit
$ git commit -a -m "Updating information for developers"
[readme_update_developer 41cb31e16] Updating information for developers
 1 file changed, 1 insertion(+)
# remember the abbreviated commit hash -- 41cb31e16
# Add 3 commits, then squash the first 2 onto the original commit with SHA-1 abbreviated as 1648e821c  
$ echo "even More information for developers" >> README.md
$ git commit -a --squash=41cb31e16 --no-edit
$ echo "even More information for developers" >> README.md
$ git commit -a --squash=41cb31e16 --no-edit
# Add the last commit which not squashed into 1648e821c
$ echo "Adding configuration information" >> README.md
$ git commit -a -m "Updating information on configuration"
# Rebase interactively with --autosquash
$ git rebase -i --autosquash

由于在需要压缩的提交前加入了 --squash 参数,交互式变基时会自动将所在版本标记为按 squash 关键字进行处理;同时提交信息中也会多出 squash! 字样的前缀,如图所示:

此时无需任何操作,关闭变基交互页即可。关闭后 Git 会按照预定的版本自动弹出提交窗口,以确认聚合版本的注释信息。如果无需改动,则直接跳过即可。最终的命令行结果为:

bash 复制代码
$ git rebase -i --autosquash
[detached HEAD 9728d0cb8] Updating information for developers
 Date: Wed Dec 15 19:34:32 2021 +0800
 1 file changed, 3 insertions(+)
Successfully rebased and updated refs/heads/readme_update_developer.
# Check via gitk
$ gitk

最终效果如下:

如果希望在变基时默认按自动压缩的方式进行,可以设置如下配置:

bash 复制代码
$ git config rebase.autosquash true

这样,之后的所有 git rebase -i 都会默认追加 --autosquash 标记。

回到本节最开始提到的场景,如果要将本地的所有 bug 分支上的版本压缩为一个版本,则变基交互页关闭后,Git 还会弹出编辑器窗口确认该聚合版本的提交消息(commit message)。如果不需要该弹窗,后续的本地压缩 commit 在执行提交时,可将 --squash=41cb31e16 改为 --fixup=41cb31e16 即可。

相关推荐
hehedadaq5 分钟前
FunAudioLLM-SenseVoice+CosyVoice-论文阅读笔记
论文阅读·笔记
神效的枫叶c9 分钟前
第二十二天学习笔记2024.8.6
笔记·学习·centos
qq210846295321 分钟前
【编程笔记】解决移动硬盘无法访问文件或目录损坏且无法读取
笔记
m0_6969975823 分钟前
学习笔记第二十天
笔记·学习
独影月下酌酒29 分钟前
DAMA学习笔记(十一)-元数据管理
数据库·笔记·学习
软茸兔37 分钟前
笔记:Oracle LOGMNR
数据库·笔记·oracle
努力自学的小夏39 分钟前
秋招复习笔记——八股文部分:网络IP
网络·笔记·网络协议·学习·tcp/ip
冰榫1 小时前
Git分布式版本控制--2+day018 LeetCode235 701 450
git
@qike1 小时前
【数据结构】——二叉树OJ题
c语言·数据结构·数据库·redis·笔记·缓存
仁希'1 小时前
《Unity3D高级编程 主程手记》第四章 用户界面(五) 快速构建一个简单易用的 UI 框架
笔记·ui·unity·c#