Есть ли эквивалент Mercurial для git log --first-parent?

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?


person Max Nanasy    schedule 13.03.2013    source источник
comment
Это интересный вариант использования. Можете ли вы сказать мне, чего вы пытаетесь достичь, делая это? Я не верю, что в Mercurial есть единственная команда, которая делает это. Но я озадачен, почему вы хотите.   -  person Omnifarious    schedule 15.03.2013
comment
@Omnifarious Мне больше всего любопытно, есть ли у Mercurial такая функциональность.   -  person Max Nanasy    schedule 15.03.2013
comment
Ну, это можно было бы собрать воедино. Но это также не было бы ужасно полезным ни для чего. Какой родитель Mercurial считает «первым», является произвольным и не связан ни с чем конкретным (я думаю, что он сортирует хэши, а «самый низкий хеш» - это первый родитель).   -  person Omnifarious    schedule 15.03.2013
comment
@Omnifarious В git первый родитель — это тот коммит, который был проверен при запуске git merge. Поэтому, если я объединяю функцию ветки с главной (т.е. на главной, git merge feature), текущая главная фиксация является первым родителем коммита слияния, тогда как, если я объединяю основную ветку с функцией (т.е. на функции, git merge master), текущая фиксация функции будет первый родитель коммита слияния.   -  person Max Nanasy    schedule 15.03.2013
comment
Я подумал, что дело в этом. Знаете, где-то Mercurial, должно быть, делает что-то подобное. Потому что, хотя он всегда перечисляет родитель 0 как наименьший хеш, он иногда перечисляет родитель 1 и родитель 0 в разных порядках, по-видимому, связанных с тем, какой родитель был «объединен». Хм...   -  person Omnifarious    schedule 15.03.2013
comment
Да, порядок наборов изменений в журнале изменений отражает, какой из них был «объединен», но на внутренних слоях чуть выше этого он имеет тенденцию быть скрытым за счет их сортировки в соответствии с тем, какой из них имеет более низкий хэш. И это, похоже, сохраняется при выполнении пулов по сети и подобных вещах. Интересно. Позвольте мне проверить еще одну вещь....   -  person Omnifarious    schedule 15.03.2013
comment
Да, этот порядок, кажется, сохраняется, когда вы делаете пуллы и тому подобное по сети. Хммм... Итак, да, похоже, можно было бы написать команду Mercurial, которая делала бы это. Информация не теряется. Он также недоступен для любой существующей команды (за исключением команд отладки *). Конечно, я сделал только несколько различных тестов. Мне пришлось бы подробно изучить код, чтобы выяснить, сохраняется ли эта информация намеренно или случайно (всегда следуя определенному соглашению или что-то в этом роде).   -  person Omnifarious    schedule 15.03.2013
comment
Ну, revset будет длиннее (в символах и затраченном времени), но это возможно, так что - эквивалент Mercurial будет логироваться с revset   -  person Lazy Badger    schedule 17.03.2013


Ответы (4)


Прямой эквивалент: hg log -r '_firstancestors(...)'

Существует прямой эквивалент: скрытый набор ревизий _firstancestors следует за стороной первого родителя (p1) каждого слияния. В Mercurial, как и в Git, первый родитель — это коммит, который был проверен при вызове hg merge [second parent].

hg log -r '_firstancestors(myfeature)'

«скрытый» означает, что он начинается со знака подчеркивания и не указан в справке и т. д., но его можно использовать, если вы знаете, что он существует. Я не знаю, почему это скрыто.

Примеры

Этот псевдоним revset перечисляет все коммиты в функциональной ветке, игнорируя все предки всякий раз, когда 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
person Esteis    schedule 03.10.2016

Для этого вы можете использовать revsets:

hg log -r "p1(merge())"

merge() получает все коммиты слияния, а p1() получает первого родителя этих коммитов.

Используйте hg help revsets для получения дополнительной информации о наборах изменений.

person Steve Kaye    schedule 13.03.2013
comment
Я не уверен, что этого хочет ОП. Похоже, ему может понадобиться прямая линия истории, возникающая из-за того, что он всегда следует только левой стороне слияний. - person djc; 13.03.2013
comment
Посмотрев документацию git, я думаю, что вы правы. Это похоже на жесткое. - person Steve Kaye; 13.03.2013

>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). Надеюсь, подборка достаточно показательна для решаемой задачи.

Необходимый набор изменений (на английском языке) будет

"Диапазон 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

которые (все еще) включают некоторые нежелательные изменения

введите здесь описание изображения

person Lazy Badger    schedule 18.03.2013
comment
Ясно, что я не полностью владею языком revset. - person Omnifarious; 18.03.2013
comment
@Omnifarious - не волнуйтесь, моя текущая версия в ответе также содержит ошибки, и я пытаюсь (сейчас) ее отполировать (получил длинную трудночитаемую строку и даже еще не окончательную версию) - person Lazy Badger; 18.03.2013
comment
Я по-прежнему считаю, что лучший способ решить эту проблему — использовать именованные ветки. Затем вы можете просто выбрать нужную ветку. Вам не всегда нужно помнить о слиянии в «правильном» направлении, чтобы это работало. - person Omnifarious; 18.03.2013
comment
RE: чрезвычайно вырожденный случай из сути: gist.github.com/MaxNanasy/5184202 взят из selenic.com/hg, первый реальный репозиторий, с которым я пробовал hg log -G --follow-first. - person Max Nanasy; 18.03.2013
comment
Я считаю, что это не работает, потому что исключает слишком много наборов изменений: не все предки вторых родителей коммитов слияния должны быть исключены; только те, которые не являются также предками первых родителей. - person Max Nanasy; 18.03.2013
comment
@Omnifarious RE: не забудьте объединиться в «правильном» направлении: по крайней мере, в Git это обычно не будет проблемой, поскольку слияние в неправильном направлении A. не обновит правильный указатель ветки и B. будет иметь другую семантику интерпретация (например, слияние функции с мастером — это добавление функции, а слияние мастера с функцией — обновление из восходящего потока). - person Max Nanasy; 19.03.2013
comment
@MaxNanasy: у меня обычно есть разработчики, которые «объединяют мастер с функцией» и локально тестируют, прежде чем они «объединяют функцию с мастером». Это часто приводит к тому, что «функция слияния с мастером» становится слиянием с быстрой перемоткой вперед, поэтому родительские элементы слияния оказываются в «неправильном» порядке. - person Omnifarious; 19.03.2013
comment
@Omnifarious Проблема в этой ситуации заключается в антипаттерне (IMO) использования быстрого слияния для слияния веток функций с несколькими фиксациями. - person Max Nanasy; 19.03.2013
comment
@MaxNanasy - Возможно, так. Но какая у вас гарантия, что случайный репозиторий сообщит полезную информацию с --first-parent тогда? Как вы удерживаете других людей от того, что вы считаете анти-шаблоном? - person Omnifarious; 19.03.2013
comment
@Omnifarious Думаю, ты прав. OTOH, тот же аргумент можно привести в отношении предложенного вами решения именованных ветвей, так что, в конечном счете, это может быть просто примером несоответствия импеданса между философиями git и mercurial branch. - person Max Nanasy; 19.03.2013

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 неразрешима, потому что тогда hg log без -G будет единственным полезным способом использования --follow-first AFAICT.

person Max Nanasy    schedule 18.03.2013
comment
Если вам нужно такое поведение, я бы предложил именованные ветки в Mercurial. Это гораздо более надежный способ добиться чего-то подобного. Просто убедитесь, что «специальная» ветвь, о которой вы хотите получить все данные, имеет определенное имя. Затем вы можете использовать язык набора изменений, чтобы довольно легко выбрать только те изменения, которые являются его частью. - person Omnifarious; 18.03.2013
comment
1. Устарело, потому что (я полагаю) revset делает работу лучше 2. Прочтите о параметре -r и опциях (в худшем случае снова revsets) для указания диапазона или некоторой ревизии - person Lazy Badger; 18.03.2013
comment
@LazyBadger Если наборы ревизий справляются со своей задачей лучше, то какое выражение набора ревизий эквивалентно --follow-first? - person Max Nanasy; 18.03.2013
comment
@Omnifarious Именованные ветки действительно работают, например, в случае сам репозиторий HG (hg log -G -r 'branch(stable)' дает тот же результат, что и hg log -G --follow-first (включая громоздкие строки слияния)), но что, если, например. репозиторий, который я просматриваю, не находится под моим контролем и не использует именованные ветки таким образом? - person Max Nanasy; 18.03.2013
comment
@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) показывает, что они охватывают разные наборы наборов изменений, тем самым подтверждая мою точку зрения о том, что делать, когда репозиторий, который я просматриваю, не находится под моим контролем. - person Max Nanasy; 18.03.2013
comment
Я бы на самом деле был удивлен, если бы результат был таким же. Я подозреваю, что они разветвлялись и сливались в «ветви» (что-то вроде неправильного названия), помеченной как «стабильная». Но я думаю, что вывод -r 'branch(stable)' на самом деле является более точным отражением того, что происходит. - person Omnifarious; 18.03.2013
comment
@Omnifarious Что вы подразумеваете под более точным отражением происходящего? - person Max Nanasy; 19.03.2013