提高效率
设置别名
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
> 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
> vim ~/.bash_profile
alias hgst="hg status"
alias hgd="hg diff"
alias hga="hg add"
> source ~/.bash_profile
# Using
> hgst
方式三:bash function
> vim ~/.bash_profile
function hgpl() {
hg pull --rebase
}
> source ~/.bash_profile
# Using
> hgpl
方式四:bash function + hg alias
> 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 功能。
> 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 中:
> 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
更多例子
# 复制单个并且编辑提交信息
> 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 命令,它可以将多个目录链接同一个仓库,并且可以在各自的目录下切换到不同的分支,特别适合以下场景:
- 并行开发:在两个不同的分支上开发,不需要频繁回来地切换。
- 快速试验、修复:在开发中需要验证、或修复某个 BUG,但不想影响现有的工作目录,就可以在新的工作目录中进行开发。
- 代码迁移合并:假如 A 分支和 B 分支版本区别过大,无法直接使用
graft
,这时候就可以从新的工作目录中直接拷贝文件。
其实 hg 也有类似的命令,那就是 share,需要先开启扩展:
> vim ~/.hgrc
[extensions]
share =
然后这样操作:
> hg share xxx-project project-v2
> cd project-v2
> hg up feature/xxx
操作历史
注意:以下操作请谨慎执行,除非有特别声明,否则均只能操作未发布的提交。
撤销前一次提交
如果提交后发现某个文件忘记添加了,可以使用 rollback 进行回滚:
> hg commit -m "feat: do something"
> hg rollback
该操作会把最后一次 commit 移除,但这个 commit 的改动仍在。
回滚某个 commit
如果想要回滚某个 commit,可以使用 backout:
# 回滚最后一个提交
> hg backout -r .
# 回滚某个提交
> hg backout -r 9487
# 回滚某个提交,但先不提交(推荐使用这种方式)
> hg backout -r 9487 --no-commit
效果就和 git revert
一样。
撤销某个 commit 及其后代
如果想要撤销某个 commit 及以后的所有改动,可以使用 strip,需要先开启扩展:
> vim ~/.hgrc
[extensions]
strip =
然后这样使用:
# 移除单个
> hg strip -r 9487
# 移除多个
> hg strip -r 9487 9488
# 移除 commit,但保留改动
> hg strip -r 9487--keep
注意:该操作不属于修改历史,可用于已发布的 commit。
修改前一次提交
如果我们在提交一次 commit 后,想要修改 commit 信息,或者想要再做一些改动,可以使用:
> hg add .
> hg commit -m "feat: first commit"
# 修改一下
> hg commit --amend
修改前 N 次提交
如果要支持更复杂的修改历史操作,我们可以使用 histedit 扩展,类似于 git rebase -i
,使用它能够实现:
- 修改某个 commit 的 commit 信息
- 移除某个提交
- 合并多次提交
- 等等..
需要在 .hgrc
开启:
> vim ~/.hgrc
[extensions]
histedit =
注意:
- 每次修改后 changeset 都会改变。
假设,我们现在有下面几个提交:
> 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 信息:
# 想要修改倒数第三个的 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 信息,我们可以直接在这里改:
- 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 的改动内容,比如新增一个文件,我们改成这样:
- 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
这时候就可以改动文件内容,最后再进行提交:
> 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:
- 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,并且保留所有提交信息:
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 还支持很多高阶操作,这里举几个最常使用的,推荐配合别名使用:
# 查看当前分支的的 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 命令查看文件中每一行的最后改动者:
> hg annotate -ulc package.json
ps:该命令还有另一个别名 blame。
二分法定位出问题的 commit
如果想知道哪一次代码提交引入了错误,可以使用 bisect 命令。
具体操作看阮一峰老师的这篇文章: 《git bisect 命令教程》 。
工具推荐
diff tool 差异对比工具
使用一个称手的 diff 工具可帮助你提高很多效率,比如:
- 快速对比两个版本的差异
- 快速对比两个文件、文件夹的差异
我个人使用 Beyond Compare,不过这个软件略贵,也可以使用其它同类工具,例如:KDiff3、WinMergeU、P4Merge 等。
下面以 Beyond Compare 为例进行配置,其实基本大同小异:
> 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
使用方式:
# 对比某个版本与当前工作区
> 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 添加配置并重启:
"hg.path": "/opt/homebrew/bin/hg" // 可通过 which hg 查看 hg 的可执行脚本路径
另外推荐开启 hg.lineAnnotationEnabled
,即可轻松查看当前文件每一行最后改动,类似于 GitLens 扩展。