Найти коммит слияния, который включает конкретный коммит - PullRequest
152 голосов
/ 12 декабря 2011

Представьте себе следующую историю:

       c---e---g--- feature
      /         \
-a---b---d---f---h--- master

Как я могу найти, когда коммит "c" был объединен с мастером (т. Е. Найти коммит слияния "h")?

Ответы [ 11 ]

134 голосов
/ 13 декабря 2011

Ваш пример показывает, что ветвь feature все еще доступна.

В этом случае h является последним результатом:

git log master ^feature --ancestry-path

Если ветвь feature больше не доступен, вы можете отобразить коммиты слияния в строке истории между c и master:

git log <SHA-1_for_c>..master --ancestry-path --merges

Однако это также покажет все слияния, которые произошли после h,и между e и g на feature.


Сравнение результата следующих команд:

git rev-list <SHA-1_for_c>..master --ancestry-path

git rev-list <SHA-1_for_c>..master --first-parent

даст вам SHA-1 h как последний ряд общего.

Если он у вас есть, вы можете использовать comm -1 -2 для этих результатов.Если вы используете msysgit, вы можете использовать следующий код perl для сравнения:

perl -ne 'print if ($seen{$_} .= @ARGV) =~ /10$/'  file1 file2

(код perl из http://www.cyberciti.biz/faq/command-to-display-lines-common-in-files/, который был взят у кого-то из группы новостей comp.unix.shell").

См. подстановка процесса , если вы хотите сделать его однострочным.

96 голосов
/ 23 июня 2015

Добавьте это к вашему ~/.gitconfig:

[alias]
    find-merge = "!sh -c 'commit=$0 && branch=${1:-HEAD} && (git rev-list $commit..$branch --ancestry-path | cat -n; git rev-list $commit..$branch --first-parent | cat -n) | sort -k2 -s | uniq -f1 -d | sort -n | tail -1 | cut -f2'"
    show-merge = "!sh -c 'merge=$(git find-merge $0 $1) && [ -n \"$merge\" ] && git show $merge'"

Тогда вы можете использовать псевдонимы, подобные этому:

# current branch
git find-merge <SHA-1>
# specify master
git find-merge <SHA-1> master

Чтобы увидеть сообщение коммита слияния и другие детали, используйте git show-merge с теми же аргументами.

(Основано на ответ Готье . Спасибо Розену Матеву и Джавабрету за исправление проблемы с sort.)

21 голосов
/ 03 марта 2013

git-get-merge найдет и покажет коммит слияния, который вы ищете:

pip install git-get-merge
git get-merge <SHA-1>

Команда следует за дочерними элементами данного коммита до слияния в найдена другая ветвь (предположительно master).

21 голосов
/ 10 апреля 2012

То есть подведем итоги сообщения Готье:

perl -ne 'print if ($seen{$_} .= @ARGV) =~ /10$/' <(git rev-list --ancestry-path <SHA-1_for_c>..master) <(git rev-list --first-parent <SHA-1_for_c>..master) | tail -n 1

РЕДАКТИРОВАТЬ: поскольку здесь используется подстановка процесса"<()", он не совместим с POSIX и может не работать с вашей оболочкой. Это работает с bash или zsh, хотя.

13 голосов
/ 25 апреля 2014

Мне нужно было это сделать, и я каким-то образом нашел git-when-merged (который фактически ссылается на этот SO вопрос, но Майкл Хаггерти никогда не добавлял сюда ссылку на свой очень хороший скрипт на Python).Так что теперь у меня есть.

12 голосов
/ 16 декабря 2013

Опираясь на отличный ответ Готье, нам не нужно использовать comm для сравнения списков.Так как мы ищем последний результат в --ancestry-path, который также находится в --first-parent, мы можем просто воспользоваться последним в выводе первого:

git rev-list <SHA>..master --ancestry-path | grep -f <(git rev-list <SHA>..master --first-parent) | tail -1

Или для чего-то быстрого и многоразового использованиявот функция для ввода в .bashrc:

function git-find-merge() {
  git rev-list $1..master --ancestry-path | grep -f <(git rev-list $1..master --first-parent) | tail -1
}
4 голосов
/ 02 июля 2015

Для толпы Ruby есть git-откуда .Очень просто.

$ gem install git-whence
$ git whence 1234567
234557 Merge pull request #203 from branch/pathway
3 голосов
/ 01 мая 2017

Я использую ниже bash скрипт, который помещаю по пути ~/bin/git-find-merge.Он основан на ответе Готье и ответе злой полоски с несколькими изменениями для обработки угловых случаев.comm бросает, когда входы не отсортированы.grep -f отлично работает.

Угловые случаи:

  • Если коммит - это коммит слияния по первому родительскому пути ветви, то вернуть коммит.
  • Если commit - это фиксация без слияния по перво-родительскому пути ветви, тогда верните ветку.Это либо слияние, либо фиксация только на ветви, и нет хорошего способа определить правильный коммит.
  • Если коммит и ветвь совпадают, то вернуть коммит.

~/bin/git-find-merge скрипт:

#!/bin/bash

commit=$1
if [ -z $commit ]; then
    echo 1>&2 "fatal: commit is required"
    exit 1
fi
commit=$(git rev-parse $commit)
branch=${2-@}

# if branch points to commit (both are same), then return commit
if [ $commit == $(git rev-parse $branch) ]; then
    git log -1 $commit
    exit
fi

# if commit is a merge commit on first-parent path of branch,
# then return commit
# if commit is a NON-merge commit on first-parent path of branch,
# then return branch as it's either a ff merge or commit is only on branch
# and there is not a good way to figure out the right commit
if [[ $(git log --first-parent --pretty='%P' $commit..$branch | \
    cut -d' ' -f1 | \
    grep $commit | wc -l) -eq 1 ]]; then
    if [ $(git show -s --format="%P" $commit | wc -w) -gt 1 ]; then
        # if commit is a merge commit
        git log -1 $commit
    else
        # if commit is a NON-merge commit
        echo 1>&2 ""
        echo 1>&2 "error: returning the branch commit (ff merge or commit only on branch)"
        echo 1>&2 ""
        git log -1 $branch
    fi
    exit
fi

# 1st common commit from bottom of first-parent and ancestry-path
merge=$(grep -f \
    <(git rev-list --first-parent  $commit..$branch) \
    <(git rev-list --ancestry-path $commit..$branch) \
        | tail -1)
if [ ! -z $merge ]; then
    git log -1 $merge
    exit
fi

# merge commit not found
echo 1>&2 "fatal: no merge commit found"
exit 1

Что позволяет мне сделать это:

(master)
$ git find-merge <commit>    # to find when commit merged to current branch
$ git find-merge <branch>    # to find when branch merged to current branch
$ git find-merge <commit> pu # to find when commit merged to pu branch

Этот скрипт также доступен на моем github .

1 голос
/ 01 мая 2016

Моя рубиновая версия идеи @ robinst работает в два раза быстрее (что важно при поиске очень старого коммита).

find-commit.rb

commit = ARGV[0]
master = ARGV[1] || 'origin/master'

unless commit
  puts "Usage: find-commit.rb commit [master-branch]"
  puts "Will show commit that merged <commit> into <master-branch>"
  exit 1
end

parents = `git rev-list #{commit}..#{master} --reverse --first-parent --merges`.split("\n")
ancestry = `git rev-list #{commit}..#{master} --reverse --ancestry-path --merges`.split("\n")
merge = (parents & ancestry)[0]

if merge
  system "git show #{merge}"
else
  puts "#{master} doesn't include #{commit}"
  exit 2
end

Вы можете просто использовать его какэто:

ruby find-commit.rb SHA master
0 голосов
/ 17 марта 2014

Мне пришлось сделать это несколько раз (спасибо всем, кто ответил на этот вопрос!), И в итоге я написал скрипт (используя метод Готье), который я мог бы добавить в свою небольшую коллекцию утилит git.Вы можете найти его здесь: https://github.com/mwoehlke/git-utils/blob/master/bin/git-merge-point.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...