Указание, является ли коммит Git коммитом Merge/Revert

Я пишу скрипт, который требует проверки того, является ли конкретный коммит фиксацией слияния / возврата или нет, и мне интересно, есть ли для этого мерзавец.

То, что я до сих пор придумал (и я определенно не хочу зависеть от сообщения коммита здесь), это проверить HASH^2 и посмотреть, если я не получаю ошибку, есть ли лучший способ?

9 ответов

Решение

Выяснить, является ли что-то слиянием, легко. Это все совершает с более чем одним родителем. Чтобы проверить это, вы можете сделать, например,

$ git cat-file -p $commit_id

Если в выводе есть более одной родительской строки, вы нашли слияние.

Для возврата это не так просто. Обычно возвраты - это просто обычные коммиты, которые применяют разность предыдущего коммита в обратном порядке, эффективно удаляя внесенные изменения. Там нет ничего особенного.

Если возврат был создан с git revert $commit, затем git обычно генерирует сообщение о фиксации, указывающее, что возвращение и какой фиксация были отменены. Однако вполне возможно сделать возврат другими способами или просто изменить сообщение коммита коммита, сгенерированного git revert,

Поиск этих сгенерированных сообщений возврата может быть уже достаточно эвристическим для того, чего вы пытаетесь достичь. Если нет, вам бы пришлось на самом деле просматривать другие коммиты, сравнивая их различия друг с другом, поиск одного - это точная обратная операция другого. Но даже это не очень хорошее решение. Достаточно часто возвраты немного отличаются от реверсирования коммита, который они отменяют, например, чтобы учесть изменения кода, произошедшие между коммитом и возвратом.

Следующая инструкция выведет только родительские хеши. Требуется меньше фильтрации...

git show --no-patch --format="%P" <commit hash>

Ответ с помощью git cat-file использует команду git "plumbing", которая, как правило, лучше подходит для создания сценариев, поскольку выходной формат вряд ли изменится. Те, которые используют git show а также git rev-parse может потребоваться изменить со временем, так как они используют команды фарфора.

Функция bash, которую я использовал долгое время, использует git rev-list:

gitismerge () {
    local sha="$1"
    msha=$(git rev-list -1 --merges ${sha}~1..${sha})
    [ -z "$msha" ] && return 1
    return 0
}

Список команд фарфора / сантехники можно найти в документации к команде git верхнего уровня.

Этот код использует git-rev-list с конкретным запросом gitrevisions ${sha}~1..${sha} таким образом, что печатается второй родительский элемент SHA, если он существует, или ничего, если он отсутствует, что является точным определением фиксации слияния.

В частности, SHA~1..SHA означает включать коммиты, которые достижимы из SHA, но исключают коммиты, которые достижимы SHA~1, который является первым родителем SHA.

Результаты сохраняются в $msha и проверяются на пустоту с помощью bash [ -z "$msha" ] терпит неудачу (возвращает 1), если пусто, или передает (возвращает 0), если не пусто.

Я нахожу все ответы сложными, а некоторые даже ненадежными.
Особенно, если вы хотите выполнять разные действия для слияния и обычного коммита.

Лучшее решение ИМО - позвонить git rev-parse с использованием второго родительского выражения ^2 а затем проверьте наличие ошибок:

git rev-parse HEAD^2 >/dev/null 2>/dev/null && echo "is merge" || echo "regular commit" 

У меня это отлично работает. Большая часть приведенного выше примера - это просто украшение, которое просто отбрасывает нежелательный вывод.

И для windows cmd это тоже хорошо работает:

git rev-parse "HEAD^2" >nul 2>nul && echo is merge || echo regular commit

примечания цитаты символы

Один из способов проверить коммит слияния:

$ test -z $(git rev-parse --verify $commit^2 2> /dev/null) || echo MERGE COMMIT

Что касается git revert rafl, я согласен с rafl, что наиболее реалистичным подходом является поиск шаблона возврата сообщения в сообщении commit; если бы кто-то изменил это, обнаружение было бы очень сложным.

Еще один способ найти родителей комита:

git show -s --pretty=%p <commit>

использование %P для полного хэша. Это печатает, сколько родителей HEAD имеет:

git show -s --pretty=%p HEAD | wc -w

Простой способ проверить коммит слияния:

git show --summary HEAD | grep -q ^Merge:

Это вернет 0 для коммитов слияния, 1 для коммитов без слияния. Замените HEAD на желаемый коммит для тестирования.

Пример использования:

if git show --summary some-branch | grep -q ^Merge: ; then
    echo "some-branch is a merge"
fi

Если вывод следующей команды равен 1, это будет означать, что это отдельная фиксация. Если нет, это фиксация слияния

      git cat-file -p $commitID | grep -o -i parent | wc -l

Чтобы проверить, является ли это фиксацией слияния,

      # Use the FULL commit hash because -q checks if the entire line is matched.
git rev-list --merges --all | grep -qx <FULL_commit_hash>
echo $?    # 0 if it's a merge commit and non-zero otherwise

Чтобы проверить, является ли фиксация откатом, вам нужно будет просмотреть другие ответы.

Другие вопросы по тегам