Mercurial有类似于"git log --first-parent"的功能吗?

3

git log --first-parent 只会显示合并提交的第一个父提交。

例如:

$ git log --oneline --graph

* 087f5ed Master C
*   36c50a2 Merge branch 'feature'
|\  
| * 98c89df Feature B
| * 89b3a7b Feature A
* | 9a95133 Master B
|/  
* 766c9b0 Master A

$ git log --oneline --graph --first-parent

* 087f5ed Master C
* 36c50a2 Merge branch 'feature'
* 9a95133 Master B
* 766c9b0 Master A

是否有与Mercurial相当的替代品?


这是一个有趣的用例。你能告诉我你想通过这样做实现什么吗?我不认为在Mercurial中有一个单一的命令可以做到这一点。但我很困惑,你为什么想要这样做。 - Omnifarious
@Omnifarious,我主要想知道Mercurial是否具有这样的功能。 - Max Nanasy
我想那应该就是这样。你知道,在某个地方,Mercurial一定也在做类似的事情。因为虽然它总是将parent 0列为最小的哈希值,但有时会以不同的顺序列出parent 1和parent 0,似乎与哪个“合并进来”的父级有关。嗯... - Omnifarious
是的,变更集在版本记录中的顺序反映了哪个是“合并”的,但在靠近此层的内部层次中,它往往被按较低哈希值排序的方式所掩盖。当通过网络进行拉取等操作时,似乎也会保持这种排序方式。有趣。让我再检查一件事情... - Omnifarious
好的,“revset”会更长(在字符和时间上),但是这是可能的,所以“Mercurial等效将是具有revset的日志”。 - Lazy Badger
显示剩余3条评论
4个回答

4

直接等价替代:hg log -r '_firstancestors(...)

有一种直接等价的替代方法:隐藏的版本集_firstancestors沿着每个合并的第一个父提交(p1)跟踪。在Mercurial和Git中,第一个父提交是在调用hg merge [second parent]时检出的提交。

hg log -r '_firstancestors(myfeature)'

'hidden'意味着它以下划线开头,并且不会列在帮助信息中,但如果您知道它的存在,则仍然可以使用。我不知道为什么它是隐藏的。

示例

这个版本集别名列出了特性分支上的所有提交,同时忽略了将其与master合并以使其保持最新状态时的所有祖先关系。(我工作的商店更喜欢合并而不是变基)。

[revsetalias]
feature($1) = _firstancestors($1) and not _firstancestors(master)

[alias]
f = log -r "feature($(echo $HG_ARGS| sed 's/^f //'))"

示例用法(使用我的自定义日志模板):

$ hg f myfeature
o  423 myfeature default/myfeature -- Esteis -- 2016-07-12 -- 123abc
|  this
o    422 -- Esteis -- 2016-07-12 -- 123def
|\   merge master into myfeature
o ~  421 -- Esteis -- 2016-07-12 -- 456abc
|    that
o  420 -- Esteis -- 2016-07-12 -- 789def
|  and the other

1
你可以使用 revsets 来完成这个操作:
hg log -r "p1(merge())"

merge() 获取所有合并提交,p1() 获取这些提交的第一个父节点。

使用 hg help revsets 获取有关修订集的更多信息。


1
我不确定这是否是原帖作者想要的。听起来他可能想要沿着合并操作左侧始终遵循的历史直线。 - djc
在查看了Git文档之后,我认为你是正确的。那看起来很棘手。 - Steve Kaye

1
>hg glog -r 410:426 --template "{rev} - {desc|firstline|fill68}\n"
o    426 - Merge test fixes for dulwich changes and output changes.
|\
| o    425 - Merge incoming fix.
| |\
| | o  424 - getremotechanges: fix incoming support
| | |
o | |  423 - overlay: stop using deprecated tree.entries() method
| | |
| o |  422 - Fix all-version-tests.
| | |
o | |  421 - Test output format tweaks for test-outgoing.
| | |
o | |  420 - test-incoming: fixes for hg 1.7
| | |
| o |    419 - Merge fix for `hg out` failing on empty repo.
| |\ \
| | o |  418 - In some situations where a reference is being used but does not
| | | |  exist in _map_git or _map_hg, silently skip the reference rather
| | | |  than throwing an error. This allows hg outgoing to work on
| | | |  repositories which do not contain any revisions at all.
| o | |  417 - only want heads and tags
| |/ /
| o |  416 - test-url-parsing: update expecations missed by edaadbd99074
| | |
| o |  415 - to be recognized port number in path to repository
| | |
| o |  414 - Unbreak outgoing to non-git repos with hg pre-1.9
| | |
| o |  413 - test fixes for progress cleanup
| |/
| o  412 - Fix mercurial issue2855
| |
| o  411 - Convert dulwich progress into mercurial ui.progress
|/
o  410 - test-incoming: only run on hg 1.7.x and newer

与其使用gist中极度退化的情况,我使用了真实仓库DAG(hg-git仓库)的一部分。我希望这个选择足以说明问题已得到解决。

所需的revset(简明英语)为

"A:B范围内没有第二个父级及其祖先的合并集"

在revset函数语言中(TBT!)

-r "410::426 - (p2(merge()) or ancestors(p2(merge())))"

如果源是完整的变更集范围,则更易读的形式将是:

hg log -r "!(p2(merge()) or ancestors(p2(merge())))"

编辑1

我测试了revset,重新思考了方法论(不排除我想要的只是向空集添加所需的),目前对我的用例最接近的迭代(有错误,找不到解决方案)是

(p1(ancestors(p1(426))) or p1(426) or 426) and 410::426

其中(仍然)包括一些不需要的修订版。

enter image description here


显然我并没有完全掌握revset语言。 - Omnifarious
@Omnifarious - 别担心,我的回答中当前的revset也有漏洞,我现在正在努力完善它(得到了一行很长且难以阅读的版本,甚至还不是最终版本)。 - Lazy Badger
我认为它不起作用是因为它排除了太多的变更集:不应该排除所有合并提交的第二个父级祖先;只需排除那些不是第一个父级祖先的祖先即可。 - Max Nanasy
@Omnifarious 在这种情况下的问题是使用快速向前合并来进行多次提交的特性分支合并,这是一个反模式(在我看来)。 - Max Nanasy
1
@Omnifarious,我想你是对的。另一方面,关于你提出的命名分支解决方案,也可以提出同样的论点,因此,这可能只是git和mercurial分支理念之间阻抗不匹配的一个例子。 - Max Nanasy
显示剩余5条评论

0

hg log --follow-first 看起来大致上做了相同的事情,但有一些规定:

  1. 它已被弃用(我找不到任何解释)。

  2. 我无法弄清楚如何使其显示除当前变更集的直线历史之外的任何内容(例如,显示从两个分叉头的第一个父节点开始的历史记录(相当于 git log --first-parent branch-a branch-b),尽管这可能只是因为我对Mercurial的了解不足。

  3. 它会在使用hg log -G时显示空分支行:

    $ hg log -G --template '{node|short} {desc|firstline}'
    
    @  51b90923fc9d Master C
    |
    o    bb51d979fd68 Merge branch 'feature'
    |\
    | o  a9ca2597ebbc Feature B
    | |
    | o  d0a54af09272 Feature A
    | |
    o |  77ceb31100be Master B
    |/
    o  b5a0b2c7468f Master A
    
    $ hg log -G --template '{node|short} {desc|firstline}' --follow-first
    
    @  51b90923fc9d Master C
    |
    o    bb51d979fd68 Merge branch 'feature'
    |\
    o |  77ceb31100be Master B
    |/
    o  b5a0b2c7468f Master A
    

    上面的例子可能看起来不太糟糕,但请参见https://gist.github.com/MaxNanasy/5184202,其中此行为会导致难以处理的输出。

    如果问题#2无法解决,则此问题可能并不重要,因为在我看来,--follow-first只有在没有-G的情况下使用hg log才是有用的。


如果您需要这样的行为,我建议在Mercurial中使用命名分支。这是一种更可靠的方式来实现类似的功能。只需确保您想要所有数据的“特殊”分支具有特定名称。然后,您可以使用revset语言轻松选择仅属于此分支的更改。 - Omnifarious
  1. 已过时,因为(我想)revset能更好地完成工作。
  2. 阅读关于-r参数和选项的相关信息(在最坏的情况下再次使用revsets来指定范围或某个版本)。
- Lazy Badger
@LazyBadger如果revsets能更好地完成任务,那么与“--follow-first”等效的revset表达式是什么? - Max Nanasy
@Omnifarious,命名分支确实在例如HG存储库本身的情况下起作用(hg log -G -r 'branch(stable)'hg log -G --follow-first(包括笨重的合并行)给出相同的输出),但是如果我查看的存储库不在我的控制范围内,并且不以这种方式使用命名分支,那该怎么办? - Max Nanasy
@Omnifarious 我说得太早了:实际上只有前1000行会给出相同的输出;diff -u <(hg log -r 'branch(stable)' --template '{node|short} {desc|firstline}\n' | sort) <(hg log --follow-first --template '{node|short} {desc|firstline}\n' | sort) 显示它们跨越不同的修改集,因此证明了我关于在查看的仓库不受我的控制时该怎么做的观点。 - Max Nanasy
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接