Представьте следующую историю:
c---e---g--- feature
/ \
-a---b---d---f---h--- master
Как я могу найти, когда commit "c" был объединен в master (т.е. найти слияние commit "h" )?
Представьте следующую историю:
c---e---g--- feature
/ \
-a---b---d---f---h--- master
Как я могу найти, когда commit "c" был объединен в master (т.е. найти слияние commit "h" )?
В вашем примере показано, что ветвь 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).
Смотрите замещение процесса, если вы хотите сделать его однострочным.
Добавьте это в свой ~/.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
с теми же аргументами.
(На основе Ответ Готье. Розен Матев и javabrett для исправления проблемы с sort
.)
git-get-merge найдет и покажет слияние, которое вы ищете:
pip install git-get-merge
git get-merge <SHA-1>
Команда следует за дочерними элементами данного фиксации до тех пор, пока не будет найдено слияние в другую ветвь (предположительно мастер).
То есть, чтобы суммировать сообщение Готье:
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
EDIT: потому что это использует замещение процесса "<()
", оно не совместимо с POSIX, и может не работать с вашей оболочки. Он работает с bash
или zsh
.Суб >
Мне нужно было это сделать и каким-то образом нашел git-when-merged
(который фактически ссылается на этот вопрос SO, но Майкл Хаггерти никогда не добавлял ссылку на его очень хороший Python script здесь). Итак, теперь у меня есть.
Основываясь на великом ответе Готье, нам не нужно использовать comm
для сравнения списков. Поскольку мы ищем последний результат в --ancestry-path
, который также находится в --first-parent
, мы можем просто grep для последнего в выводе первого:
git rev-list <SHA>..master --ancestry-path | grep -f <(git rev-list <SHA>..master --first-parent) | tail -1
Или для чего-то быстрого и многоразового использования, здесь функция pop в .bashrc
:
function git-find-merge() {
git rev-list $1..master --ancestry-path | grep -f <(git rev-list $1..master --first-parent) | tail -1
}
Для толпы Ruby, git-whence. Очень легко.
$ gem install git-whence
$ git whence 1234567
234557 Merge pull request #203 from branch/pathway
Я использую ниже скрипт bash, который я ~/bin/git-find-merge
по пути ~/bin/git-find-merge
. Это основано на ответе Готье и ответе злой черты с несколькими хитростями для обработки угловых случаев. comm
когда входы не отсортированы. grep -f
работает отлично.
Угловые чехлы:
~/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=${[email protected]}
# 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 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.
Моя рубиновая версия идеи @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
git log --topo-order
Затем найдите первое слияние перед фиксацией.
Вы можете попробовать что-то вроде этого. Идея состоит в том, чтобы выполнить итерацию через все комминирование слияния и посмотреть, доступна ли коммит "c" из одного из них:
$ git log --merges --format='%h' master | while read mergecommit; do
if git log --format='%h' $mergecommit|grep -q $c; then
echo $mergecommit;
break
fi
done
Мне приходилось делать это несколько раз (спасибо всем, кто ответил на этот вопрос!), и закончил писать script (используя метод Готье), который я мог бы добавить в свою небольшую коллекцию утилит git. Вы можете найти его здесь: https://github.com/mwoehlke/git-utils/blob/master/bin/git-merge-point.