Уявіть таку історію:
c---e---g--- feature
/ \
-a---b---d---f---h--- master
Як я можу знайти, коли команда "c" була об'єднана в master (тобто знайти злиття "s")?
Уявіть таку історію:
c---e---g--- feature
/ \
-a---b---d---f---h--- master
Як я можу знайти, коли команда "c" була об'єднана в master (тобто знайти злиття "s")?
Відповіді:
Ваш приклад показує, що філія 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
(перл-код від http://www.cyberciti.biz/faq/command-to-display-lines-common-in-files/ , який взяв його з "когось із групи новин comp.unix.shell").
Дивіться заміну процесу, якщо ви хочете зробити його однолінійним.
master
було об'єднано feature
, а потім відразу feature
об'єднується master
як швидкий вперед (підказка feature
замінює master
). Чи це призведе --first-parent
до повернення неправильного батька?
comm -1 -2
але не вийшло. comm
працює лише на відсортованих лініях. (Perl однолінійний працює, хоча я не міг його прочитати.)
git find-merge h master
(не повертає нічого, а повертається h), git find-merge d master
(повертає f, але повинен повертати d), git find-merge c feature
(повертає e, але повинен повертати g).
Додайте це до свого ~/.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
.)
sort -k2 | uniq -f1 -d | sort -n | tail -1 | cut -f2
не знайти правильного останнього рядка спільно. Ось приклад, коли це не вдається.
16db9fef5c581ab0c56137d04ef08ef1bf82b0b7
тут, коли я запускаю його на вашій пасті, це не очікується? На якій ОС ви працюєте?
29c40c3a3b33196d4e79793bd8e503a03753bad1
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
хоча.
<()
не сумісний з POSIX. Ви повинні використовувати bash
, zsh
або оболонка підтримує заміну процесу . Я відповідно відредагував свою відповідь.
Мені потрібно було це зробити, і я якось знайшов git-when-merged
(що насправді посилається на це питання ТАК, але Майкл Хаггерті ніколи не додав сюди посилання на свій дуже приємний сценарій Python). Отож тепер маю.
Спираючись на чудову відповідь Готьє, нам не потрібно використовувати 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
}
comm
не працювало, коли входи не були відсортовані.
Нижче я використовую скрипт bash, який розміщую на шляху ~/bin/git-find-merge
. Він заснований на відповідь Готьє і відповідь evilstreak в с декількома налаштуваннями для обробки кутових випадків. 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=${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 .
Моя рубінова версія ідеї @ 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
Можна спробувати щось подібне. Ідея полягає в тому, щоб повторити всі комісії злиття і побачити, чи доступ "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
git rev-list <SHA-1_for_c>..master --ancestry-path --merges
Мені довелося це зробити кілька разів (спасибі всім, хто відповів на це запитання!), І закінчив писати сценарій (використовуючи метод Готьє), який я міг би додати до своєї невеликої колекції утиліт Git. Ви можете знайти його тут: https://github.com/mwoehlke/git-utils/blob/master/bin/git-merge-point .