특정 커밋이 포함 된 병합 커밋 찾기


183

다음과 같은 역사를 상상해보십시오.

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

커밋 "c"가 마스터에 병합되었을 때 어떻게 찾을 수 있습니까 (즉, 찾기 커밋 "h"를 찾으십니까)?

답변:


158

귀하의 예는 브랜치 feature를 여전히 사용할 수 있음을 보여줍니다 .

이 경우 h마지막 결과는 다음과 같습니다.

git log master ^feature --ancestry-path

feature더 이상 지점을 사용할 수없는 경우 c및 사이의 내역 행에 병합 커밋을 표시 할 수 있습니다 master.

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

그러나 이것은 또한 이후에 일어난 모든 병합 표시됩니다 h, 사이 eg에가 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 -ne 'print if ($seen{$_} .= @ARGV) =~ /10$/'  file1 file2

( http://www.cyberciti.biz/faq/command-to-display-lines-common-in-files/의 펄 코드 . "comp.unix.shell 뉴스 그룹의 누군가"에서 가져온 것입니다).

하나의 라이너로 만들려면 프로세스 대체를 참조하십시오 .


4
comm이 있어도 "git rev-list"명령의 출력이 사전 순으로 정렬되지 않으므로 사용할 수 없습니다. 물론 공통 행을 찾기 전에 각 명령의 출력을 정렬 할 수 있지만 원하는 커밋이 반드시 마지막 커밋 일 필요는 없습니다. 그래서 나는 perl 명령과 같은 것이 (모호하지만) 필요하다고 생각합니다.
mhagger

12
방금이 제안을 구현하는 git-merged 스크립트를 작성했습니다 (몇 가지 다른 기능 포함). 참조 github.com/mhagger/git-when-merged
mhagger

2
어떤 점에서 가정 master에 병합 된 feature후 즉시 feature로 병합 master빨리 감기 (의 설명으로 feature대체합니다 master). 그로 인해 --first-parent잘못된 부모가 반환됩니까?
Kelvin

4
시도 comm -1 -2했지만 작동하지 않았습니다. comm정렬 된 줄에서만 작동합니다. (Perl one-liner는 읽을 수는 없지만 작동합니다.)
Domon

2
이것은 조금 늦었지만 git이 기본적으로 제공하지 않기 때문에 사람들이 유용하게 사용할 수 있습니다. 이 답변으로 처리 할 수없는 코너 사례가 있습니다 (대부분의 코너 사례를 처리하는 stackoverflow.com/a/43716029/58678 아래의 답변 참조 ). 모퉁이의 경우는 다음과 같습니다. git find-merge h master(h는 반환하지만 아무것도 반환하지 않아야 함), git find-merge d master(f는 반환하지만 d git find-merge c feature는 반환해야 함)
hiPyPy

133

이것을 다음에 추가하십시오 ~/.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동일한 인수와 함께 사용하십시오 .

( Gauthier의 답변을 기반으로합니다 . 로 문제를 해결 한 Rosen Matevjavabrett 에게 감사드립니다 sort.)


6
아름다운! 이것이 최고의 드롭 인 솔루션입니다.
N Jones

1
sort -k2 | uniq -f1 -d | sort -n | tail -1 | cut -f2마지막 행을 올바르게 찾지 못하는 것에 주의하십시오 . 다음은 실패한 예입니다.
Rosen Matev

1
@RosenMatev 16db9fef5c581ab0c56137d04ef08ef1bf82b0b7붙여 넣기에서 실행할 때 여기에서 발견 됩니다. 어떤 OS를 사용하고 있습니까?
robinst

1
@ Robinst, 당신의 말이 맞습니다. 나는 "(GNU coreutils) 8.4"를 얻었고 나를 위해 그것을 발견했다29c40c3a3b33196d4e79793bd8e503a03753bad1
Rosen Matev

2
@powlo : 아무것도 아닙니다. 편의상 두 개가 아닌 하나의 명령 일뿐입니다.
robinst

28

git-get-merge 는 찾고있는 병합 커밋을 찾아서 보여줍니다 :

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

명령은 다른 분기 (아마도 마스터) 로의 병합 이 발견 될 때까지 지정된 커밋의 자식을 따릅니다 .


22

즉, Gauthier의 게시물을 요약하면 다음과 같습니다.

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불구하고.


4
인터넷에서 코드를 자주 복사 / 붙여 넣기하지는 않지만 완벽하게 작동합니다! 생각하지 못하게 해준 토터에게 감사합니다.
Ben

2
@ TheodoreR.Smith 불행히도, 구문 <()은 POSIX 호환되지 않습니다. 당신은 사용할 필요가 bash, zsh또는 쉘은 지원 과정 대체를 . 그에 따라 답변을 편집했습니다.
토토

나를 위해 작동하지 않았다. 기능 지점이 마스터에 병합되기 전에 다른 지점으로 먼저 병합 된 것 같습니다. 명령이 "병합 지점 'feature_branch'"가 아닌 "병합 지점 'release_branch'"가되는 이유를 설명 할 수 있습니다.
Tim Kuipers

14

나는 이것을해야했고 어떻게 든 발견했다 git-when-merged(실제로이 SO 질문을 참조하지만 Michael Haggerty는 그의 멋진 Python 스크립트에 대한 참조를 여기에 추가하지 않았다). 그래서 지금 가지고 있습니다.


나는 실제로 그의 페이지 에서이 질문에 왔습니다.
Flavius

12

Gauthier의 훌륭한 답변을 바탕으로 comm목록을 비교하는 데 사용할 필요는 없습니다 . 우리 --ancestry-path는 또한에 있는 마지막 결과를 찾고 있기 때문에 --first-parent전자의 출력에서 ​​후자를 grep 할 수 있습니다.

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입력이 정렬되지 않은 경우 작동하지 않았습니다.
hiPy4

4

Ruby 사용자에게는 git-whence가 있습니다. 아주 쉽게.

$ gem install git-whence
$ git whence 1234567
234557 Merge pull request #203 from branch/pathway

4

나는 path에 배치하는 bash 스크립트를 사용합니다 ~/bin/git-find-merge. 그것은 코너 케이스를 처리하기 위해 약간의 조정 으로 Gauthier의 답변evilstreak의 답변 을 기반으로 합니다. comm입력이 정렬되지 않은 경우 발생합니다. grep -f완벽하게 작동합니다.

코너 케이스 :

  • commit이 브랜치의 첫 번째 상위 경로에 대한 병합 커밋이면 커밋을 반환합니다.
  • commit이 브랜치의 첫 번째 상위 경로에서 비 병합 커밋 인 경우 브랜치를 반환합니다. ff merge 또는 commit은 브랜치에만 있고 올바른 commit을 알아내는 좋은 방법은 없습니다.
  • commit과 branch가 동일하면 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 에서도 사용할 수 있습니다 .


2
git log --topo-order

그런 다음 커밋 전에 첫 번째 병합을 찾으십시오.


1

@ 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

이런 식으로 시도해 볼 수 있습니다. 아이디어는 모든 병합 커밋을 반복하고 커밋 "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
오이겐 Konkov

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.