Hg tips

提高效率

设置别名

Hg 本身支持简写,如:

  • hg status => hg st
  • hg shelve => hg she
  • hg unshelve => hg unshe
  • hg update => hg up
  • hg commit => hg ci
  • hg diff => hg d

也可以通过下面几种方式来自定义想要的别名。

方式一:hg alias

1
2
3
4
5
6
7
8
9
10
11
12
13
> vim ~/.hgrc

[alias]
amend = commit --amend
br = branch
brs = branches
wip = !$HG addremove >/dev/null 2>&1 && $HG ci -m "--wip-- [skip ci]"

# Using
> hg amend
> hg br
> hg brs
> hg wip

方式二:bash alias

1
2
3
4
5
6
7
8
9
10
> vim ~/.bash_profile

alias hgst="hg status"
alias hgd="hg diff"
alias hga="hg add"

> source ~/.bash_profile

# Using
> hgst

方式三:bash function

1
2
3
4
5
6
7
8
9
10
> vim ~/.bash_profile

function hgpl() {
hg pull --rebase
}

> source ~/.bash_profile

# Using
> hgpl

方式四:bash function + hg alias

1
2
3
4
5
6
7
8
9
10
11
12
13
> vim ~/.bash_profile

function hgpl() {
hg pull --rebase
}

> vim ~/.hgrc

[alias]
pl = !source ~/.bash_profile && hgpl

# Using
> hg pl

复制其它分支的 commit

假设我们有多个分支在并行开发,在 A 分支做了某些改动,希望把这些改动也应用到 B 分支。

这时候可以用 graft 命令将这个 commit 从别的分支复制到当前分支,类似于 Git cherry-pick 功能。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
> hg brs
feature/v1 6:f8528de0eb4c
feature/v1.1 5:288d0414598d

> hg log -G --style compact
@ 6[tip]:1 f8528de0eb4c 2021-12-14 13:04 +0800 4Ark
| feat: feature-v1-04
|
| o 5 288d0414598d 2021-12-14 12:57 +0800 4Ark
| | feat: feature-v1.1-03
| |
| o 4 d72548bcd32b 2021-12-14 12:56 +0800 4Ark
| | feat: feature-v1.1-02
| |
| o 3 8719f541d5d8 2021-12-14 12:55 +0800 4Ark
| | feat: feature-v1.1-00
| |
| o 2 e7eb9420534e 2021-12-14 12:55 +0800 4Ark
|/ feat: feature-v1.1-00
|
o 1 431a3844a58c 2021-12-14 12:54 +0800 4Ark
| feat: feature-v1-01
|
o 0 5d35d7d5baf8 2021-12-14 12:53 +0800 4Ark
feat: feature-v1

feature/v1.1 分支是基于 feature/v1 创建的,目前两个分支都分别提交了一些东西,我们希望将 feature/1.1 的最后一个提交(5:288d0414598d)复制到 feature/1 中:

1
2
3
4
5
6
> hg update feature/v1
> hg graft -r 5

> hg log -r tip --style compact
7[tip] 42cf5e6dfe1e 2021-12-14 12:57 +0800 4Ark
feat: feature-v1.1-03

更多例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 复制单个并且编辑提交信息
> hg graft --edit 5

# 复制多个并且编辑提交信息
> hg graft --edit 2 3 4

# 连续复制多个
> hg graft -D "2:5"

# 连续复制多个,但有一个例外
> hg graft -D "2::5 and not 3"

# 连续复制多个并且编辑提交信息
> hg graft --edit "2:5"

# 将整个分支作为一个提交复制过来,如果要编辑提交信息将 -r 改成 --edi
> hg graft -r feature/v1.1 --base "ancestor('feature/v1.1','feature/v1')"

如果在 graft 过程中有冲突,可以解决后使用 hg graft --continue 继续进行,或者使用 hg graft --abort 终止本次操作。

同一个仓库链接到多个目录(worktree)

如果熟悉 git 的同学应该知道 git 有一个 worktree 命令,它可以将多个目录链接同一个仓库,并且可以在各自的目录下切换到不同的分支,特别适合以下场景:

  1. 并行开发:在两个不同的分支上开发,不需要频繁回来地切换。
  2. 快速试验、修复:在开发中需要验证、或修复某个 BUG,但不想影响现有的工作目录,就可以在新的工作目录中进行开发。
  3. 代码迁移合并:假如 A 分支和 B 分支版本区别过大,无法直接使用 graft,这时候就可以从新的工作目录中直接拷贝文件。

其实 hg 也有类似的命令,那就是 share,需要先开启扩展:

1
2
3
4
> vim ~/.hgrc 

[extensions]
share =

然后这样操作:

1
2
3
> hg share xxx-project project-v2
> cd project-v2
> hg up feature/xxx

操作历史

注意:以下操作请谨慎执行,除非有特别声明,否则均只能操作未发布的提交。

撤销前一次提交

如果提交后发现某个文件忘记添加了,可以使用 rollback 进行回滚:

1
2
> hg commit -m "feat: do something"
> hg rollback

该操作会把最后一次 commit 移除,但这个 commit 的改动仍在。

回滚某个 commit

如果想要回滚某个 commit,可以使用 backout

1
2
3
4
5
6
7
8
# 回滚最后一个提交
> hg backout -r .

# 回滚某个提交
> hg backout -r 9487

# 回滚某个提交,但先不提交(推荐使用这种方式)
> hg backout -r 9487 --no-commit

效果就和 git revert 一样。

撤销某个 commit 及其后代

如果想要撤销某个 commit 及以后的所有改动,可以使用 strip,需要先开启扩展:

1
2
3
4
> vim ~/.hgrc

[extensions]
strip =

然后这样使用:

1
2
3
4
5
6
7
8
# 移除单个
> hg strip -r 9487

# 移除多个
> hg strip -r 9487 9488

# 移除 commit,但保留改动
> hg strip -r 9487--keep

注意:该操作不属于修改历史,可用于已发布的 commit。

修改前一次提交

如果我们在提交一次 commit 后,想要修改 commit 信息,或者想要再做一些改动,可以使用:

1
2
3
4
5
> hg add .
> hg commit -m "feat: first commit"

# 修改一下
> hg commit --amend

修改前 N 次提交

如果要支持更复杂的修改历史操作,我们可以使用 histedit 扩展,类似于 git rebase -i,使用它能够实现:

  • 修改某个 commit 的 commit 信息
  • 移除某个提交
  • 合并多次提交
  • 等等..

需要在 .hgrc 开启:

1
2
3
4
> vim ~/.hgrc

[extensions]
histedit =

注意:

  • 每次修改后 changeset 都会改变。

假设,我们现在有下面几个提交:

1
2
3
4
5
6
7
8
9
10
11
12
13
> hg log -b . --style compact

5 288d0414598d 2021-12-14 12:57 +0800 4Ark
feat: feature-v1.1-03

4 d72548bcd32b 2021-12-14 12:56 +0800 4Ark
feat: feature-v1.1-02

3 8719f541d5d8 2021-12-14 12:55 +0800 4Ark
feat: feature-v1.1-00

2 e7eb9420534e 2021-12-14 12:55 +0800 4Ark
feat: feature-v1.1-00

如果只是修改最后一个 commit 信息,我们可以使用 hg commit --amend,如果要修改前几个的 commit 信息:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 想要修改倒数第三个的 commit 信息
> hg histedit 8719f541d5d8

# 编辑内容:
pick 8719f541d5d8 3 feat: feature-v1.1-00
pick d72548bcd32b 4 feat: feature-v1.1-02
pick 288d0414598d 5 feat: feature-v1.1-03
# Edit history between 8719f541d5d8 and 288d0414598d
#
# Commits are listed from least to most recent
#
# You can reorder changesets by reordering the lines
#
# Commands:
#
# e, edit = use commit, but allow edits before making new commit
# m, mess = edit commit message without changing commit content
# p, pick = use commit
# b, base = checkout changeset and apply further changesets from there
# d, drop = remove commit from history
# f, fold = use commit, but combine it with the one above
# r, roll = like fold, but discard this commit's description and date

根据描述,如果我们只是想要修改 commit 信息,我们可以直接在这里改:

1
2
3
4
- pick 8719f541d5d8 3 feat: feature-v1.1-00
+ mess 8719f541d5d8 3 feat: feature-v1.1-00
pick d72548bcd32b 4 feat: feature-v1.1-02
pick 288d0414598d 5 feat: feature-v1.1-03

但是如果想要修改这个 commit 的改动内容,比如新增一个文件,我们改成这样:

1
2
3
4
- pick 8719f541d5d8 3 feat: feature-v1.1-00
+ edit 8719f541d5d8 3 feat: feature-v1.1-00
pick d72548bcd32b 4 feat: feature-v1.1-02
pick 288d0414598d 5 feat: feature-v1.1-03

这时候就可以改动文件内容,最后再进行提交:

1
2
3
4
5
6
> echo 'new' > new-file.txt
> hg add .
> hg commit -m "feat: feat: feature-v1.1-00(changed)"
created new head

> hg histedit --continue # 你也可以使用 hg histedit --abort 来终止本次操作

如果要移除某个 commit:

1
2
3
4
- edit 8719f541d5d8 3 feat: feature-v1.1-00
+ drop 8719f541d5d8 3 feat: feature-v1.1-00
pick d72548bcd32b 4 feat: feature-v1.1-02
pick 288d0414598d 5 feat: feature-v1.1-03

如果要合并多个 commit,并且保留所有提交信息:

1
2
3
4
5
	pick 8719f541d5d8 3 feat: feature-v1.1-00  # 只能合并到第一个 commit
- pick d72548bcd32b 4 feat: feature-v1.1-02
- pick 288d0414598d 5 feat: feature-v1.1-03
+ fold d72548bcd32b 4 feat: feature-v1.1-02
+ fold 288d0414598d 5 feat: feature-v1.1-03

如果要合并多个 commit,并且不保留提交信息(直接采用第一个 commit 信息),只需要将 fold 改成 roll

查找历史

查看 commit 的信息

使用 log 命令某个提交的信息,通常我们使用 source tree 能够满足大部分日常需求。

但 log 还支持很多高阶操作,这里举几个最常使用的,推荐配合别名使用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# 查看当前分支的的 log
> hg log -b .

# 更清晰地查看 log 历史
> hg log --template "{label('custom.rev', rev)}\t{label('custom.node',node|short)} {label('custom.phase',phase)} \t{label('custom.age',date|age)}\t{desc|firstline} {label('custom.user', author|user)} {label('custom.branch',branch)} {label('custom.tag',tags)} {label('custom.book',bookmarks)}\n"

# 查看某个提交的信息以及文件改动
> hg log -p -r 9487

# 查看某个文件的改动信息
< hg log package.json

# 查看某个文件的改动信息(包括删除)
> hg log --remove package

# 查看某个目录的改动信息
> hg log -M src

# 查看某个文件某几行的所有改动信息
> hg log -L package.json,1:23 --follow

# 查看多个文件某几行的所有改动信息
> hg log -L package.json,1:23 -L package2.json,1:23 --follow

# 查看未发布的提交
> hg log -r "draft()"

查看某个文件每一行的最后改动者

可以使用 annotate 命令查看文件中每一行的最后改动者:

1
> hg annotate -ulc package.json

ps:该命令还有另一个别名 blame。

二分法定位出问题的 commit

如果想知道哪一次代码提交引入了错误,可以使用 bisect 命令。

具体操作看阮一峰老师的这篇文章: 《git bisect 命令教程》

工具推荐

diff tool 差异对比工具

使用一个称手的 diff 工具可帮助你提高很多效率,比如:

  • 快速对比两个版本的差异
  • 快速对比两个文件、文件夹的差异

我个人使用 Beyond Compare,不过这个软件略贵,也可以使用其它同类工具,例如:KDiff3WinMergeUP4Merge 等。

下面以 Beyond Compare 为例进行配置,其实基本大同小异:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
> vim ~/.hgrc

[extensions]
# uncomment the lines below to enable some popular extensions
# (see 'hg help extensions' for more info)
#
extdiff =
hgext.extdiff =

[extdiff]
cmd.bcomp = bcomp
opts.bcomp = -leftreadonly -solo

[merge-tools]
bcomp.executable = Applications/Beyond Compare.app/Contents/MacOS/bcomp
bcomp.priority=-1
bcomp.args=$local $other $base /mergeoutput=$output /ro /lefttitle=local /centertitle=base /righttitle=other /outputtitle=merged /automerge /reviewconflicts /solo
bcomp.premerge=False
bcomp.regname=ExePath
bcomp.gui=True
bcomp.diffargs=/lro /lefttitle='$plabel1' /righttitle='$clabel' /solo /expandall $parent $child
bcomp.diff3args=$parent1 $parent2 $child /lefttitle='$plabel1' /centertitle='$clabel' /righttitle='$plabel2' /solo /ro
bcomp.dirdiff=True
bcomp.binary=True

使用方式:

1
2
3
4
5
6
7
8
9
10
11
12
# 对比某个版本与当前工作区
> hg bcomp -r 9816 -r .

# 比较两个版本、分支
> hg bcomp -r 9646 -r 9677
> hg bcomp -r default -r 9677

# 比较两个版本的某个文件、文件夹
> hg bcomp -r 9552 -r 9553 filepath

# 比较两个文件夹
> bcomp dir-a dir-b

Beyond Compare 还支持三路比较、合并,就是比较 A 版本、B 版本、C 版本(两者共同祖先),不过要支持这个功能价格就更贵了。

vscode-hg

在使用 VSCode 的同学,推荐使用 vscode-hg 这个扩展,可支持大部分 hg 操作。

如果遇到 Mercurial installation not found. 报错 ,在 settings.json 添加配置并重启:

1
"hg.path": "/opt/homebrew/bin/hg" // 可通过 which hg 查看 hg 的可执行脚本路径

另外推荐开启 hg.lineAnnotationEnabled ,即可轻松查看当前文件每一行最后改动,类似于 GitLens 扩展。


作者 : 4Ark
来源 : https://4ark.me
著作权归作者所有,转载请联系作者获得授权。

🥳 加载 Disqus 评论