Найти коммиты с заданными предками - PullRequest
0 голосов
/ 08 октября 2018

В какой-то момент мой репозиторий git содержит следующую структуру:

A1    A2    A3
 o-----o-----o
        \     \
         o X   o Y
B1    B2/   B3/
 o-----o-----o
        \
         o Z
C1    C2/
 o-----o

Я пытаюсь получить самый ранний коммит, являющийся потомком нескольких указанных коммитов.Тай-брейк станет датой совершения.Например:

descendant A1 B2 -> X
descendant A2 B3 -> Y
descendant A1 C1 -> nothing

Коммиты слияния могут иметь более двух родителей.Я нашел много документации о git merge-base, которая выполняет почти противоположную задачу, но не может найти ни одной функции, которая, по крайней мере, возвращала бы список потомков, которые я мог бы отсортировать.

Ответы [ 2 ]

0 голосов
/ 08 октября 2018

Как прокомментировал chepner , Git имеет только обратные указатели. Найти потомков коммита C необходимо преобразовать в новую и другую проблему, которая вместо этого: Найдите предков коммита T, которые сами имеют коммит C в качестве предка. Здесь T - это коммит с советами, или в вашем случае, возможно, много коммитов с советами - все ветви и, возможно, все теги и все другие ссылки.

Команда git rev-list подходит для решения проблемы.В частности, вы можете сделать так, чтобы он проходил по графику от кончиков (потомков) к родителям, но собирал ребра, пройденные во время процесса, а затем переворачивал их, используя --children.Как отмечает документация , это позволяет переписать родительские элементы и упростить историю.

(я думаю, вам нужно будет запустить git rev-list --children на любом начальном коммите, который вы выберете, и проанализировать его вывод самостоятельноприменять дополнительные ограничения. Вы можете использовать родительские элементы коммитов, из которых вы ищете, в качестве точек остановки, используя синтаксис ^<em>hash</em>^@ gitrevisions , чтобы сократить итерацию графа. Обратите внимание, что это действительно приводит ^, который похож на --not, но локальный вместо глобального, применяется к rev^@.)

0 голосов
/ 08 октября 2018

Вот что мне удалось собрать вместе после еще нескольких исследований.Это некрасиво, вероятно очень неэффективно, но похоже, что оно работает.

#!/bin/bash

common_descendants=$(git rev-list --ancestry-path --all $1.. | sort)
shift

while [ $# -ne 0 ]; do
    common_descendants=$(
        echo "$common_descendants"
        | comm -12 --nocheck-order - <(
            git rev-list --ancestry-path --all $1.. | sort
        )
    )
    shift
done

git rev-list --reverse --date-order --no-walk $common_descendants | head -n 1

Он использует git rev-list --ancestry-path --all, чтобы найти всех потомков каждого запрошенного коммита по очереди.
Тезисысписки пересекаются с помощью sort и comm для получения списка коммитов кандидатов.
Наконец, git rev-list --ancestry-path --all упорядочивает их по дате фиксации, а head -n 1 выбирает самый старый.

...