跳过正文

magit

··8481 字
Emacs Emacs
目录

1 Core
#

C-x g magit-status 显示当前 buffer 对应的 git project status
C-x M-g magit-dispatch 在小的 buffer window 中显示当前可以执行的 magit 快捷键命令。
C-c M-g magit-file-dispatch 在小的 buffer window 中显示可以对当前 file 执行的 magit 命令。

在 magit-status buffer 中,执行的命令与当前光标所在位置有关系,如在某一个 commit 上时,SPACE 会显示该 commit 的内容,d 会显示前后两个 commit 的差别:

  • ?/h:根据光标所在的 buffer,显示对应的帮助菜单。
  • $:显示 git process 的输出内容窗口,用于 debug, 用 q 关闭 debug 窗口。
  • k:discard:
    • 当光标在 stage 位置时,丢弃 stage 和 worktree 中的内容。
    • 当在 unstage 位置时,丢弃 worktree 的修改。
    • 当在 untrack 位置时删除文件。
  • v:reverse a changing to worktree, 可以是 staged 或者 commited.
  • s: stage 当前的改动, 可以在 file 级别,也可以在 hunk 级别.
  • S: 将所有 unstaged 的变动提交到 Stage
  • u: unstage 当前的变动, 可以在 file 级别,也可以在 hunk 级别.
  • U: unstage 所有的变动.
  • g: 刷新 magit buffer.

C-SPACE:标记当前 file 或 hunk 区域,最后用 s(stage)、u(unstage) 操作标记的区域。也可以用来在 Commit 或 log 列表中批量选中 commit,后续可以 apply 或 revert。

移动:

  • n/p: 在 section 或者 section 内部的 hunk 之间移动;
  • M-n/M-p: 在 slibling section 之间移动;
  • ^:移动到 section 的上一级(不是 u,u 的含义是 unstage);

显示和展开:

  • TAB 展开当前 section
  • C-TAB:循环展示当前 section 和它的 children;而 TAB 是直接展开所有 children 的内容。
  • Enter:访问当前 section 的文件
  • 1-4:分别在当前 section 的 1-4 级之间之间展开
  • M 1-4: 分别在所有 section 的 1-4 级之间展开

执行命令:

  • !: 在当前工作目录或 git root 目录运行 git 或 shell 命令
  • C-g: 终止当前的 git 命令

C-c M-g: magit-file-dispatch 针对当前文件,支持:

  1. stage、unstage、commit 当前文件;

  2. Diff 和 diff 当前文件与其它 commit 或 master 的差别;其中 Diff 可以查看的更多样:

    1. dwim: 功能同 Diff range;
    2. Diff range: 提示输入比较的 commit ref,然后比较 workspace 当前文件与它的的差别;ref 可以使用 HEAD~N 语法。
    3. Diff paths: 提示输入两个路径的文件,然后显示差别;
    4. Diff unstaged: 显示当前文件 unstaged changes;
    5. Diff staged:显示当前文件 staged changes;
    6. Diff worktree: 显示当前文件在 HEAD 和 working tree 之间的差别;
    7. Show commit: 显示某一个 commit 中当前文件的变更;
  3. status(g): 整个 workspace 当前的状态(untracked、unstaged、staged 等状态文件)。

  4. Log/log: 查看当前文件的历史 commit;其中 Log 功能更丰富:

    1. current: 展示当前文件在当前分支的历史 commit;
    2. other:展示当前文件在其它分支或 commit 中的更新情况;
    3. head: 展示在 HEAD 对应分支中,当前文件的历史 commit 情况;
    4. Local Branchs: 展示在所有本地分支中,当前文件的 commit 情况;
    5. all branchs: 除了所有本地分支外,也包括远程分支,当前文件的 commit 情况;
    6. all reference: 展示所有分支中当前文件的 commit 情况;
  5. trace: 查看光标处所在函数或代码的修改历史(也可以选中区域),如下面的 main -L:sign_request 表示 main 分支的sign_request 函数的修改历史:

2 Branch
#

在 magit-log 页面,用蓝色表示当前所处的分支:

b: branch/revision
checkout 本地或 remote 分支,如果是本地分支则切换过去,如果是 remote 分支,则 HEAD 会变成 detached(因为它不会为 remote 分支创建本地分支)。指定的分支必须存在,不创建新分支。
l: local branch
checkout 本地或 remote 分支,如果是本地则切换过去。如果是远程,则本地创建创建一个同名的 track 分支(自动将本地分支 track remote 分支)。如果是一个新的分支名,则会提示它的 starting-point,并自动 track 这个分支。
c: new branch
Create and checkout BRANCH at branch or revision START-POINT. 创建并 checkout 到新的分支(并不设置 track remote 分支),如果当前分支有未提交的修改则失败。
s: new spin-off
Create new branch from the unpushed commits.

spin-off 是基于当前分支 checkout 一个新的分支,然后将旧的分支重置到上次和 upstream 同步的位置。如果旧的分支没有 upstream 或者没有 unpush 的 commit,则老分支不变。这非常适合在旧的 branch 上提交了一些 commit 但没有 push 到远程分支,想把这些改动转移到新的特性分支的情况:老分支未 commit 的改动将体现在新的分支中。例如:当前是 add-test 分支,并有一些 unstage 的修改,则 new spin-off 创建一个新的 next-test-spinoff 分支,并将 unstage 的内容保留到这个分支:

n: new branch
Create BRANCH at branch or revision START-POINT. 创建分支但是不 checkout。
S: new spin-out
从 unpushed commits 位置创建新的分支,但是不 checkout,当前分支不变。如果当前分支有 uncommitted changes,则和 spin-off 类似,会 checkout 这个新的分支。

小技巧:

  1. 如果想基于历史 commit 创建一个 branch,可以先用 l l 展示当前分支 log,然后移动到目标 commit,再执行上述 branch 命令,则会提示以目标 commit 创建 branch。

3 Stash
#

git stash 保存当前工作进度,把暂存区和工作区的改动保存起来,然后当前是一个干净的工作区。

git stash save ‘message…’
添加注释。
git stash list
显示保存进度的列表。

git stash pop [–index] [stash_id] - git stash pop: 恢复最新的进度到工作区。git 默认会把工作区和暂存区的改动都恢复到工作区。 - git stash pop –index: 恢复最新的进度到工作区和暂存区。(尝试将原来暂存区的改动还恢复到暂存区) - git stash pop stash@{1}: 恢复指定的进度到工作区。stash_id 是通过 git stash list 命令得到的。通过 git stash pop 命令恢复进度后,会删除当前进度。

git stash apply [–index] [stash_id]
除了不删除恢复的进度之外,其余和 git stash pop 命令一样。
git stash drop [stash_id]
删除一个存储的进度。如果不指定 stash_id,则默认删除最新的存储进度。
git stash clear
删除所有存储的进度。

magit 提供了 stash 和 snapshot 两种选择:https://emacs.stackexchange.com/a/22482

对于 snapshot,magit 会创建一个 WIP commit,当前 working tree 内容不变。

Both the “stash” and “snapshot” variants create the same stash objects. The difference is that when you create a snapshot, then the stashed changes are not removed from the files in the working tree and/or the index. (Just like when you take a snapshot of your friends having a good time - that doesn’t cause them to disappear either ;-)

This is intended as a backup mechanism of sorts. Say you are performing some complicated refactoring and you just tested and the modified code still appears to work but you are not done yet. Now would be a good time to create a snapshot, so that you have something to go back to if you mess it up later.

Of course you could just create a temporary "wip" commit, right on the branch you are working on, to accomplish the same. That’s usually what I do.

And you can also automate the process of recording work-in-progress by enabling the Wip modes. I do have these modes enabled as a safety net, but I still create wip commits directly on the current branch or create a snapshot. Those are easier to work with than the wip refs.

Note that Magit comes with its own stash implementation written in Elisp. That was necessary to implement the snapshot variants and the worktree-only and index-only stash variants. Git doesn’t provide any of these variants.

4 Commit
#

修改当前 HEAD:

a Amend
add the staged changes to HEAD and edit its commit message
e Extend
add the staged changes to HEAD without editing the commit message
w Reword
change the message of HEAD without adding the staged changes to it

修改历史 Commit(如果当前没有 stage 修改,则不做任何操作):

f Fixup
选择一个历史 commit,然后将当前 stage 的修改合并进去,创建一个新的 commit,commit msg 是 fixup! 前缀 + 选中的历史 commit msg;
s Squash
选择一个历史 commit,然后将当前 stage 的修改合并进去,创建一个新的 commit,commit msg 是 squash! 前缀 + 选中的历史 commit msg;
A Argument
和 s Squash 类似,也是创建一个 squash commit,但是可以修改 squash message.

效果如下:

后续通过 r i (interactive) 进行 rebase 前,打开 –autosquash 选项,这样会自动将 Commit 进行 fixup 或 squash:

git 使用 fixup! 或 squash! 后的 msg 来匹配历史 commit,然后 rebase 时加到相应commit 的后面:

上面的 Fixup、Squash 还有 Instance 版本,它们是立即启动 rebase,将当前 stage 的内容自动 rebase 到选择的历史commit 中:

  • F:Instance fixup
  • S:Instance squash

在提交 msg 编辑界面:

  • C-c C-c:提交 commit
  • C-c C-k:cancel commit
  • M-p M-n:使用上一次或下一次的 commit message

5 Diff
#

magit 模式是使用 Contex 模式来展示 diff 内容。如果想 side-by-side 则需要使用 ediff 模式。

  • d p: 选择两个路径文件,然后比较内容

M-x ediff: 选择两个文件进行比较。

ediff 在一个单独的 frame 显示一个 ediff control panel,使用 C-x 5 o 切换到该 frame。

~
rotate ediff window 的布局, 可以通过 buffer name 来判断各自显示的内容。
|
在水平和垂直窗口布局间切换;
m
最大化 frame,特别适合水平布局的情况;
C-x 5 o
显示隐藏的 ediff panel;
A/B/C
将 buffer a、b、c 设置为只读。
?
显示 ediff control panel 的帮助菜单,再次按 ? 会隐藏菜单。
n、p
下一个或上一个 diff 位置。
j
跳转到第一个 diff 位置。nj: n 为数字,表示跳转到第 n 个 diff 位置。
g a/b/c
将视图定位到 a/b/c buffer,这样后续该 buffer 中的 diff 总是处于可见区域的中间位置。
v、V
在当前 diff 位置上移或下移滚动,用于查看 diff 上下文信息。
h
切换 highlight 的风格:
  • 高亮所有 diff 区域;
  • 只高亮当前 diff 区域;
  • 使用 ascii 标识 diff 区域;
|
在水平和垂直方向上切换当前显示的方式。
</>
水平向左或向右滚动显示所有 buffer。
#f
提示输出各 buffer 匹配的正则表达式,后续只显示匹配这些正则的 diff 区域。后续再次按 #f 取消选择。

#h ::和 #f 类似,但是隐藏匹配的 diff 预期。后续再次按 #h 取消隐藏。

w a/b/c
将 buffer a、b、c 的内容保存到 新的文件 中。
wd
将 buffer b 和 c 的 diff 内容保存到新的文件中。
D
在单独的 buffer 中显示指定的两个 buffer 的 diff 差别。
z
将当前 diff session 保存到后台,后续可以使用 M-x eregistry 命令查看暂存的 session,非常适合有多个 ediff session 的情况;
q
终止 diff session。如果前面修改了 buffer 内容,会提示 save buffer。
!
刷新 diff region,更新 diff 区域数量。

注:

  1. 如果 ediff panel frame 没有在单独的 frame 中显示,则可使用 C-x b 切换到该 buffer,然后使用 ? 来恢复。
  2. 在 macos 系统下,需要将 ns-use-native-fullscreen 和 ns-use-fullscreen-animation 设置为 nil,否则显示 ediff panel 时有问题。
  3. which-key 可能会导致 ediff 的 gX 命令 hang,这时可以发送 USR2 信号来重新激活 Emacs;
    • update 2021.09.18: 下线 which-key,配置 (setq prefix-help-command #’embark-prefix-help-command) 后,可以使用 C-h 来显示匹配前缀的命令。

ediff 的 buffer 两种类型:

  1. diff view:两个 buffer;
  2. merge view:三个 buffer,第一个是 HEAD,第二个是 Index(Stage),第三个是 Workspace;

在 magit 的 unstage、staged 区域的某个 diff 上:

  1. 按 e:三窗口的 merge view。

  2. 按 E:

    • u(show unstaged): 显示 unstaged 区域的文件与 HEAD 的差别。
    • i(show staged): 显示 stage 区域的文件与 HEAD 的差别。
    • w(show worktree):显示 workspace文件与 HEAD 的差别。

    上面三个 show xxx,都是显示两个 buffer,A 为只读的 HEAD,b 为 unstage、staged 或 worktree 中的文件,可以实现用 index 或 commit 的内容恢复 workspace 的修改。

    • E(dwim) 或者 s(staged): 和上面直接按 e 类似,显示三窗口的 merge view。
    • c(show commit): 显示指定的 commit 的内容,两窗口 diff,指定一个 commit,然后 diff 它和上一次 commit 的差别。
    • r(show range): 两窗口 diff,指定一个 commit,显示和当前 workspace 文件的差别,可以用于从历史恢复当前文件的变更。

三窗口 merge view:

  1. 第一个是 HEAD,只读状态;
  2. 第二个是 Index(Stage),可读写状态;
  3. 第三个是 Worktree,可读写状态。

可以修改 index 和 workspace 中的内容,实现将 workspace 内容(可以部分保存)保存到 index 的效果,或者将 index 或 HEAD 的修改保存到 Workspace的效果。

内容拷贝:

  • 两窗口的情况:a、b:a 表示把 a buffer diff 内容拷贝到 b,反之亦然。
  • 三窗口的情况:ab、ac、bc、cb:将前一个 buffer 当前 diff 区域拷贝到第二个 buffer。
    • a buffer 是 HEAD 的内容,不能修改,所以没有 ba、ca。

内容恢复:

  • ra、rb、rc:将对应 buffer 当前 diff 区域的内容恢复到该 buffer 最开始的内容。

merge: 出现三个窗口,上面两个是冲突的版本,最下面是合并后的版本,可以将 A 或 B 的内容拷贝到 C,退出时提示保存,从而解决冲突。

magit-find-file:指定一个文件的 revision,可以查看该文件的内容。

6 Fetch
#

  • fa:将 remote 仓库的所有 branch、tag 等拉取到本地;

7 Push
#

P:push ::

  • p:push 到上游仓库
  • u:另一个上游仓库

8 Log
#

可以按作者、Commit Msg、修改的内容、 文件等条件搜索历史:

可以查看当前 branch、指定 branch 或所有 branch 的 commit log:

  • SPACE: 显示当前 commit 的内容
  • DELETE:反向显示当前 commit 的内容
  • TAB:显示当前 commit 的内容
  • Enter:显示当前 commit 的内容,并切换到 commit buffer 中,按 q 可以关闭该 buffer。
  • +: 显示更多 commit
  • -:显示更 少 commit
  • C-c C-n:移动到当前 commit 的 parent commit

在查看 commit 内容 buffer (magit-revision) 可以使用

M-[0-9]
来显示和隐藏变化内容:
C-SPC
标记修改内容;然后用 n/p 来选中下一行或上一行;

鼠标放到某个修改位置,然后按 回车,可以查看该位置 commit 后的文件内容;然后按 n/p 可以切换到上一次 commit 或下一次 commit 后的文件内容。

L: 修改 log 显示的信息,如 singlestat、margin 等

小技巧:C-c M-g l 查看当前文件在 当前分支 的提交记录,这时按 l a 则可以看到当前文件在 所有分支 的提交记录,然后就可以按 A 或 a 来 Apply 某个 commit 到当前分支。

9 Merge
#

  • i: Dissolve(merge into): 将当前分支内容 merge 到其它分支,然后删除当前分支,并切换到 merge into 的分支:
  • a: Absorb 将另一个 branch merge 进当前 branch,然后删除那个分支。
  • s: squash merge 将指定分支的修改合并到当前分支,但是不创建 commit。注意:指定分支的多次 commit 内容会合并到当前 worktree,这样后续 commit 时,只会看到一次提交(而不管指定分支有多少次历史提交)。 squash 的含义就是merge 历史合并。在 rebase 时也会使用。

如果只是想把其它分支的 commit 应用到当前分支,除了 merge 外,还可以使用 Appply(A 或 a) 或 Cherry(Y)。

为了得到线性、干净的历史提交记录,在将当前分支 merge 到主干前,可以先将它 rebase 到主干分支(期间还可以修改历史提交记录),这样后续在 merge 时会得到一个线性的提交记录。

如果 merge 出现冲突,magit 会在 magit-status(C-x g) buffer 的 unstage 或 stage change section,而且行首有unmerged 的字符串提示。可以在 unmerge 的位置按 k 丢弃 apply,或者按 e 使用 ediff 解决冲突。

10 Cherry/Apply
#

Cherry 和 Apply 都是将其它 Commit merge 到到当前分支, 在执行相关命令之前需要先切换到要合并到的目标分支。

Y (Cherries)
先输入 HEAD,再输入 UPSTREAM,显示 HEAD 可以 cherry pick 到 UPSTREAM 的 commit 列表,然后使用 Aa、AA 或 a 来选择性的 apply 到当前 branch。 需要先把当前 branch 切换到 UPSTREAM ,这样后续才能使用各种 Apply 命令。
A 或 a(Apply)
是 Cherry 的快捷方式,用于将一个或多个 commit 快速应用到当前分支。

使用流程:

  1. Checkout the branch which you want to add the commit to, b b then select branch name, eg. master.
  2. Still in Magit, l a to open the log buffer and show log for all git references (commits, stashes, etc).
  3. Move the cursor to the commit you wish to cherry pick from.
  4. A A to pick + stage + commit to the currently checked-out branch.
  5. Or use A a to pick and stage if you want to edit the change before committing it to the currently checked-out branch.

示例: 把 origin/Ark-v19.xR-zArm_fs 的部分 commit merge 到 origin/Ark-sm-kylin 分支中:

  1. Cherry head: 选择提供 commit 的分支 origin/Ark-v19.xR-zArm_fs;
  2. Cherry upstream 选择 Ark-sm-kylin;
  3. 出现 commit cherry pick 列表:
    • 以 - 号开始的表示已经 pick 过;
    • 以 + 号开始的表示没有 pick 过;

可以在 Magit 的所有 commit 上执行 AA 或 Aa 或 a 命令来 Apply 这个 commit 到当前 branch。可以使用 C-SPC 来选中多个 commits,然后批量 Apply 或其它操作。

A A:Pick(magit-cherry-copy, 为 pick+stage+commit):

  • 将光标处的或者选中的多个 commit 拷贝到当前 branch,并提示 commit message,如果选中多个 commit,则直接 pick 它们,不提示编辑 commit msg。

A a 或者 a 命令 (magit-cherry-apply, 为 pick+stage):

  • 将光标处或选中的 commit cherry apply 到当前分支,cherry apply 只是在 worktree 中 appy changes, 并不 commit ,后续 commit 时默认使用当前的 commit msg。如果选中了多个 commit,则直接 apply。

Cherry apply 有可能失败,这时 worktree 中会提示冲突,需要解决冲突并 stage 后按 A 继续;

可以在 unmerge 的位置按 k 丢弃 apply,或者按 e 使用 ediff 解决冲突,然后按 A 继续、忽略或终止。

下面这些命令都是将 commit apply 到 some branch,但是这些 commit 也会被从以前的分支移除,以前分支和当前分支都可能出现冲突,需要解决完冲突后才能继续:

A h (magit-cherry-harvest)
将其它分支的 commit 合并到当前分支;
A d (magit-cherry-donate)
将当前分支的 comit 合并到其它分支;
A n (magit-cherry-spinout)
将当前分支的 commit 移动到一个新的分支,结束后当前分支不变;
A s (magit-cherry-spinoff)
将当前分支的 commit 移动到一个新的分支,结束后新的分支会被 checkout;

在 cherrk-pick 进行的过程中,可以执行如下命令:

A A (magit-sequence-continue)
Resume the current cherry-pick or revert sequence.
A s (magit-sequence-skip)
Skip the stopped at commit during a cherry-pick or revert sequence.
A a (magit-sequence-abort)
Abort the current cherry-pick or revert sequence. This discards all changes made since the sequence started.

11 Reset
#

Reset 类型:

  • m mixed:reset HEAD and index;
  • s soft:reset HEAD Only;
  • h hard:reset HEAD、index 和 files;
  • k keep:reset HEAD 和 index,但是保存 uncommitted 的 files;
  • i index only
  • w worktree:只 reset worktree 内容到指定 commit,HEAD 和 index 不变(即提交历史不变,已经 stage 但为 commit的内容还在,但是 unstage 的内容会被 reset);
  • f a file:reset file 到某个 commit;

mixed、soft 命令 reset HEAD 或 index 后,worktree 内容不变,即 reset 到的 commit 之后的变更都还在 worktree 的unstaged 区域中:

但 hard 命令将 HEAD、index 和 worktree 都 reset 到指定 commit 的状态(丢失 commit 以后的变更)。

先切换到要 reset 的分支,然后按 X (reset), 选择 h(reset 所有内容),然后输入要 reset 到的 commit 位置:

  1. 指定 log 中显示的 7 位 commitid;
  2. 或者相对 commit,如 HEAD1、HEAD2;

小技巧:切换到 reset 分支,然后按 l l 显示当前分支 log 历史,然后移动到要 reset 到的 commit 位置,按 X h,这样就不需要手动输入 commitid 了。

全局快捷键 x(magit-reset-quickly) 将当前分支的 HEAD 和 index reset 到指定的 Commit,该 Commit 之后的更新保存到 worktree 的 unstated 区域中:

12 Revert
#

Revert 是创建一个相反的 Commit 来达到清除某次提交全部或部分变更的效果。

使用场景:

  1. Revert 某个 Commit:在 log 中选择某个 commit,然后按 V V,提示 revert 某个commit,然后出现 commit 界面,自动填充 commit msg:Revert xxx;
  1. Revert 某个 Commit 中的个别 change:可以在 commit 的 change list 中选择每个change,然后按 V v(Revert),自动创建一个可以 revert commit change 的修改,并 stage 保存到 worktree 中,提示 Revert 进行中,可以按 A 选择 action 来继续,终止; V v 有 全局快捷键 v

在 Revert 的过程中,由于会创建一个 Revert Change,可能与当前 worktree 的内容冲突,这时 Revert 会暂停,需要手动解决冲突后继续(也可以按 A 然后选择 abort 中断Revert 过程):

解决冲突后,如果 stage 不为空,则 A A 会创建一个 Revert Commit。如果 stage 为空,则说明没有需要 commit 的内容,这时可以 A a(abort) 或 A s(skip) 结束 Revert 过程。

13 Rebase
#

Rebase 原理,以将 feature1 分支 rebase 到 master 为例:

  1. git 把 feature1 分支里面的每个 commit 取消掉;
  2. 把上面的操作临时保存成 patch 文件,存在 .git/rebase 目录下;
  3. 把 feature1 分支 HEAD 指向最新的 master 分支;
  4. 把上面保存的 patch 文件应用到 feature1 分支上;(由于以master分支为 base,应用的时候可能会有冲突)。后续,在 master 分支里 merge feature1 分支时,可以fast-forward,得到一个线性的提交历史。

rebase 冲突的时候会暂停,需要解决冲突后 git add,然后用 git rebase –continue 来继续 rebase,如果要终止 rebase则可以用 git rebase –abort 命令,这时分支会回到rebase 前的状态。

rebase 另外两个用途:

  1. 改写 commit 历史记录,如合并、删除多个 commit,修改 commit 的顺序、message 等。如 git rebase feature~5 feature,可以实现将 feature 分支的最近 5 次提交合并为一个。这可以使用 rebase 的 interactive 模式来轻松实现。
  2. 变基,如有三个分支 master、feature1、feature2,feature1 从 master checkout 出来,做了几次commit,然后feature2 从 feature1 checkout 出来,也做了几次提交。如果希望将 feature2 的修改合并到 master,但是 feature1不变的话,就需要变基了,即用命令 git rebase –onto master feature1 feature2;

rebase(r):

  • i: interactively: 交互式 rebase,在当前分支 commit history 中选择一个 commit,然后交互式的 rebase 从该 commit 开始的后续 commit。用于修改对当前分支提交历史。
  • s: a subset: 选择一个 target newbase,然后在当前分支选择一个 START commit,将 START 到 HEAD 的 commit 都 rebase 到 newbase 上。用于变基合并。

如果当前 commit 已经 push 到远程仓库,则后续执行 rebase 操作后,需要 force push到原仓库,否则会 push 失败。

13.1 rebase on 其它分支-全部
#

按 r e,然后选择将当前分支 rebase 到的其它分支,这会将当前分支的所有 commit rebase 到其它分支:

13.2 rebase on 其它分支-部分
#

使用 l a 命令,定位到要 rabase onto 的分支 commit,然后执行 r s(subset) 命令,选择要 rebase onto 的分支 commit 位置:

选择当前分支的 start commit,例如 deb7,然后按 e,这时从这个 commit 开始到 HEAD的 commit 都会rebase 到第一步的新 base 上:

出现了合并冲突:

解决冲突后,按 A r 继续 rebase:

结束后,可以看到当前分支已经 rebase 到了 master 分支上了:

13.3 rebase 修改历史
#

通过 rebase interactive 实现当前分支 commit 合并、删除、修改、msg 修改。

  • pick = use commit
  • reword = use commit, but edit the commit message
  • edit = use commit, but stop for amending
  • squash = use commit, but meld into previous commit
  • fixup = like “squash”, but discard this commit’s log message
  • exec = run command (the rest of the line) using shell

例如将下面红框中的 5 个 commit 合并为 2 两个:

首先将光标移动到 start commit,然后输入 r i(interactive):

修改历史 commit 的 rebase 方式(从旧到新),结束后 按 C-c C-c 开始:

rebase 过程中,对 pick 类型的 commit,都可以修改它的 commit message:

13.4 rebase: modify a commit
#

这时将 worktree 恢复到 7983d0b,可以修改文件和内容:

只有 stage 修改后的内容,才能继续 rebase。

如果按 e(edit),则出现当前分支到 HEAD 位置的 rebase 界面,可以调整后续 commit的 rebase 行为。

13.5 rebase:remove commit
#

删除一个 commit 时,会将该 commit 后面的 commit 合并到前一个 commit,这时可能会出现冲突(因为删除后面的 commit 还可能含有被删除 commit 涉及的变更):

提示合并冲突:

删除 commit 结束:

13.6 rebase: reword a commit
#

用于修改一个 commit 的 message,选择当前分支的某个 commit( rebase 操作的都是当前分支的 commit,其它分支的不行):

修改的 commit 即以后的 commit 都会以 rebase 的方式重新提交。

14 Refers
#

y:show refers,查看本地或 remote 所有的 branch、tags 等信息。

在分支上,执行 k 命令可以用来删除 branch,使用 b checkout 新的分支,使用空格查看 commit diff。

15 案例
#

修改 commit 的作者信息( Name 和 Email):

  1. 切换到 commit 所在分支;
  2. 执行 r i 命令(interactive rebase);
  3. 光标移动到要修改的 commit 上,按回车;
  4. 按 m,表示 edit 该 commit,然后按 C-c C-c
  5. rebase 暂停,这时按 c -A, -A 表示重写 commit author,这时提示选择一个 author;
  6. 按 a (ammend), 然后按 C-c C-c;
  7. 按 r c,继续完成 Rebase。

相关文章

My Emacs Reference
··15004 字
Emacs

好记性比如烂笔头, 这是我个人总结的 Emacs 手册。

My Emacs Dotfile
··19856 字
Emacs

Emacs 是 Hacker 的一种生活方式,而这是符合我口味的私人定制。

Rust 驱动 Audio - 播放和录音
·6323 字
Rust Esp32 Rust Esp32
Rust 驱动 Camera - 采集和播放
·7304 字
Rust Esp32 Rust Esp32