Git 커밋에서 나온 브랜치 찾기


649

SHA-1 해시 값이 주어지면 커밋이 어떤 브랜치에서 나오는지 알 수있는 방법이 있습니까?

Ruby Grit을 사용하여이 작업을 수행하는 방법을 알려 주면 보너스 포인트입니다.


4
아래의 다른 방법 은 가능한 대답 을 유추 하는 실용적이고 유용하며 작동 가능한 방법 이지만 git에서 질문 자체는 오해이며 커밋은 지점에서 나오지 않습니다. 지점은왔다 갔다하고 움직이며 커밋 만 실제 레포 기록을 나타냅니다. 그런 다음 아래의 해결책이 나쁘다는 것을 말하는 방법이 아닙니다. 그냥 알고 아무도 그들이 자식 디자인에 의해 구할 수있는 완전히의 trustable 대답을 제공하지 않습니다. (단순한 사례는 지사를 삭제합니다. 분기, 두 번 커밋, 다른 분기로 병합, 첫 분기를 삭제합니다. 커밋은 어디에서 왔습니까?
RomainValeri

1
태그에서 깊이 1 얕은 복제본을 명시 적으로 가져 오는 경우가 있습니다. 싸고 쉽고 효율적입니다 ... 지금까지 내가 원하는 모든 것을 아름답게했습니다. 이제 태그가 어느 브랜치에 있는지 알고 싶습니다. 적어도 그 세부 사항에 대해서는 호스입니다. 당신은 항상 집에 가서 롤 없다
폴 스에게

답변:


864

Dav는 정보가 직접 저장되지 않았다는 것이 맞지만 이것이 결코 찾을 수 없다는 것을 의미하지는 않습니다. 할 수있는 몇 가지가 있습니다.

커밋이있는 지점 찾기

git branch -a --contains <commit>

이것은 당신에게 주어진 커밋을 가진 모든 브랜치를 알려줄 것입니다. 커밋이 이미 병합 된 경우 분명히 유용하지 않습니다.

Reflogs 검색

커밋이 수행 된 리포지토리에서 작업중인 경우 해당 커밋에 대한 행의 reflog를 검색 할 수 있습니다. 90 일이 지난 Reflog는 git-gc에 의해 제거되므로 커밋이 너무 오래된 경우 찾을 수 없습니다. 즉, 당신은 이것을 할 수 있습니다 :

git reflog show --all | grep a871742

커밋 a871742를 찾으십시오. 커밋의 약어 7 첫 번째 숫자를 사용해야합니다. 출력은 다음과 같아야합니다.

a871742 refs/heads/completion@{0}: commit (amend): mpc-completion: total rewrite

커밋이 "완료"분기에서 수행되었음을 나타냅니다. 기본 출력에는 약식 커밋 해시가 표시되므로 전체 해시를 검색하지 마십시오. 그렇지 않으면 아무것도 찾지 않습니다.

git reflog show실제로는에 대한 별칭 git log -g --abbrev-commit --pretty=oneline이므로 출력 형식을 사용하여 grep 할 수있는 다양한 항목을 만들고 싶다면 이것이 시작점입니다!

커밋이 이루어진 리포지토리에서 작업하지 않는 경우이 경우에 수행 할 수있는 최선의 방법은 reflog를 검사하고 커밋이 리포지토리에 처음 도입 된 시점을 찾는 것입니다. 운이 좋으면 커밋 된 지점을 가져 왔습니다. 커밋 트리와 reflog를 동시에 걸을 수 없기 때문에 조금 더 복잡합니다. reflog 출력을 구문 분석하여 각 해시에 원하는 커밋이 포함되어 있는지 확인하십시오.

후속 병합 커밋 찾기

이는 워크 플로우에 따라 다르지만 워크 플로우가 양호하면 개발 브랜치에서 커밋되어 병합됩니다. 다음과 같이 할 수 있습니다.

git log --merges <commit>..

주어진 커밋을 조상으로 갖는 병합 커밋을 볼 수 있습니다. (커밋이 한 번만 병합 된 경우 첫 번째 병합은 이후의 병합이어야합니다. 그렇지 않으면 몇 가지를 조사해야합니다.) 병합 커밋 메시지에는 병합 된 분기 이름이 포함되어야합니다.

이 작업을 의지하고 싶을 경우, 빠른 경우에도 병합 커밋 생성을 강제 실행 하는 --no-ff옵션을 사용할 수 있습니다 git merge. (너무 열심하지 마십시오. 과도하게 사용하면 혼란 스러워 질 수 있습니다.) 관련 질문에 대한 VonC의 답변 이이 주제에 도움이됩니다.


5
+1. 특정 문제에 대한 정보가 부족하면 실제로 문제가 있는지 궁금해합니까? 지점은 언제든지 변경, 이름 변경 또는 삭제할 수 있습니다. 수 있음 git describe(주석) 태그 지점보다 더 중요하게 볼 수 있습니다에 대한 충분하다.
VonC

9
나는 분명히 동의합니다-가지는 가볍고 유연해야합니다. 해당 정보가 중요 해지는 워크 플로우를 채택하는 경우 --no-ff옵션을 사용하여 항상 병합 커밋이 있는지 확인할 수 있으므로 마스터로 병합 될 때 항상 지정된 커밋의 경로를 추적 할 수 있습니다.
Cascabel

32
참고로, 원격에만 존재하는 커밋을 찾으려면 -a첫 번째 명령에 플래그를 추가하십시오.git branch -a --contains <commit>
Jonathan Day

8
@JonathanDay : 아니요, 어느 지점에서나 커밋을 찾을 수 있습니다. 리모컨에서 하나만 원하면을 사용하십시오 -r.
Cascabel

7
@SimonTewsi 내가 말했듯이, 실제로 문제가된다면 merge --no-ff병합 할 때 분기 이름을 안정적으로 기록하는 데 사용 하십시오. 그러나 그렇지 않으면, 분기 이름을 임시 짧은 레이블로 생각하고 설명을 영구 레이블로 확약하십시오. "개발 중에 어떤 짧은 이름을 언급 했습니까?" "이 커밋이하는 일"만큼 중요한 질문이되어서는 안됩니다.
Cascabel

154

이 간단한 명령은 매력처럼 작동합니다.

git name-rev <SHA>

예를 들어, test-branch 는 지점 이름입니다.

git name-rev 651ad3a
251ad3a remotes/origin/test-branch

이조 차도 다음과 같은 복잡한 시나리오에서 작동합니다.

origin/branchA/
              /branchB
                      /commit<SHA1>
                                   /commit<SHA2>

여기 git name-rev commit<SHA2>에서 branchB를 반환합니다 .


3
당신은 내 하루를 구했습니다. 이것은 완벽한 솔루션입니다.
Taco

7
그리고이 완벽한 솔루션을 얻는 데 8 년 밖에 걸리지 않았습니다. 감사!
S1J0

6
git name-rev --name-only <SHA>지점 이름 만 얻는 데 더 유용한 것으로 나타났습니다 . 내 질문은 ... 어떤 상황에서도 하나 이상의 지점을 반환 할 수 있습니까?
Dean Kayton

1
이것이 가장 좋은 대답이어야합니다.
JCollier

1
친절한 말을 해주신 @JCollier에게 감사드립니다.
khichar.anil

47

2013 년 12 월 업데이트 :

슈베르트 코멘트

git-what-branch(펄 스크립트, 아래 참조)는 더 이상 유지되지 않는 것 같습니다. git-when-merged파이썬으로 작성된 대안으로 저에게 매우 효과적입니다.

" 특정 커밋을 포함하는 병합 커밋 찾기 "를 기반으로 합니다.

git when-merged [OPTIONS] COMMIT [BRANCH...]

커밋이 하나 이상의 분기로 병합 된시기를 찾으십시오. 지정된 지점으로
가져온 병합 커밋을 찾으십시오 COMMIT.

특히 조상으로 BRANCH포함 된 첫 번째 상위 히스토리에서 가장 오래된 커밋을 찾으십시오 COMMIT.


원래 답변 2010 년 9 월 :

Sebastien Douche 는 다음과 같이 트위트했습니다 (SO 답변 16 분 전).

git-what-branch : 커밋이 어떤 브랜치인지 또는 어떻게 지명 된 브랜치에 도달했는지 알아 봅니다.

이것은 세스 로버트슨펄 스크립트 입니다 .

개요

git-what-branch [--allref] [--all] [--topo-order | --date-order ]
[--quiet] [--reference-branch=branchname] [--reference=reference]
<commit-hash/tag>...

개요

요청 된 커밋을 명명 된 브랜치에 가져 오기 위해 커밋 및 병합의 가장 빠른 인과 경로를 기본적으로 알려주십시오. 명명 된 브랜치에서 커밋을 직접 수행 한 경우 가장 빠른 경로입니다.

가장 빠른 인과 경로는 커밋 시간에 의해 ( --topo-order지정 되지 않은 한 ) 가장 이른 지명 된 브랜치로 병합 된 경로를 의미합니다 .

공연

많은 브랜치 (예 : 수백)에 커밋이 포함 된 경우 시스템에서 시간이 오래 걸릴 수 있습니다 (Linux 트리의 특정 커밋의 경우 브랜치를 탐색하는 데 8 초가 걸렸지 만 후보 브랜치가 200 개가 넘음). 각 커밋에. 검사 할
특정 항목의 선택 --reference-branch --reference tag은 수백 개의 후보 분기가있는 경우 수백 배 더 빠릅니다.

실시 예

 # git-what-branch --all 1f9c381fa3e0b9b9042e310c69df87eaf9b46ea4
 1f9c381fa3e0b9b9042e310c69df87eaf9b46ea4 first merged onto master using the following minimal temporal path:
   v2.6.12-rc3-450-g1f9c381 merged up at v2.6.12-rc3-590-gbfd4bda (Thu May  5 08:59:37 2005)
   v2.6.12-rc3-590-gbfd4bda merged up at v2.6.12-rc3-461-g84e48b6 (Tue May  3 18:27:24 2005)
   v2.6.12-rc3-461-g84e48b6 is on master
   v2.6.12-rc3-461-g84e48b6 is on v2.6.12-n
   [...]

이 프로그램은 관심있는 커밋의 체리 피킹 효과를 고려하지 않고 병합 작업 만 수행합니다.


4
git-what-branch더 이상 유지되지 않는 것 같습니다. git-when-merged 는 Python으로 작성된 대안으로 저에게 매우 효과적입니다.
sschuberth

@sschuberth이 업데이트에 감사드립니다. 더 많은 가시성을 제공하기 위해 귀하의 의견을 답변에 포함 시켰습니다.
VonC

37

예를 들어, c0118fa커밋 을 찾으려면 redesign_interactions다음 을 수행하십시오 .

* ccfd449 (HEAD -> develop) Require to return undef if no digits found
*   93dd5ff Merge pull request #4 from KES777/clean_api
|\
| * 39d82d1 Fix tc0118faests for debugging debugger internals
| * ed67179 Move &push_frame out of core
| * 2fd84b5 Do not lose info about call point
| * 3ab09a2 Improve debugger output: Show info about emitted events
| *   a435005 Merge branch 'redesign_interactions' into clean_api
| |\
| | * a06cc29 Code comments
| | * d5d6266 Remove copy/paste code
| | * c0118fa Allow command to choose how continue interaction
| | * 19cb534 Emit &interact event

다음을 실행해야합니다.

git log c0118fa..HEAD --ancestry-path --merges

그리고 아래로 스크롤하여 마지막 병합 커밋 을 찾으십시오 . 어느 것이 :

commit a435005445a6752dfe788b8d994e155b3cd9778f
Merge: 0953cac a06cc29
Author: Eugen Konkov
Date:   Sat Oct 1 00:54:18 2016 +0300

    Merge branch 'redesign_interactions' into clean_api

최신 정보

또는 하나의 명령 만 :

git log c0118fa..HEAD --ancestry-path --merges --oneline --color | tail -n 1

4
이것이 나에게 원하는 결과를 준 유일한 솔루션이었습니다. 나는 나머지를 시도했다.
crafter

병합 커밋 요약에 기본적으로 일반적으로 사용되는 병합에 사용 된 분기 이름이 포함 된 경우에만 작동합니다. 그러나 git merge -m"Any String Here"소스 및 대상 분기 정보가 모호해집니다.
qneill

@qneill : 아니요, 병합에는 항상 병합 된 분기에 대한 정보가 Merge: f6b70fa d58bdcb있습니다. 병합 커밋의 이름을 지정할 수 있습니다. 나는 중요하지 않다
Eugen Konkov

1
@EugenKonkov는 브랜치가 병합을 통과하면 그래프에서 어떤 경로의 경로에 대한 기록이 ref 객체 데이터베이스에는 없지만 reflog에는 남아 있습니다. 나는 내가 말하는 것을 설명하려고 답을 게시했다
qneill

UPD 버전은 저에게 효과적입니다. 원래 커밋을 찾는 간단한 명령
vpalmu

9

git branch --contains <ref>가장 확실한 "porcelain"명령입니다. "배관"명령만으로 비슷한 작업을 수행하려는 경우 :

COMMIT=$(git rev-parse <ref>) # expands hash if needed
for BRANCH in $(git for-each-ref --format "%(refname)" refs/heads); do
  if $(git rev-list $BRANCH | fgrep -q $COMMIT); then
    echo $BRANCH
  fi
done

( 이 SO 답변의 교차점 )


6

khichar.anil 은 그의 답변에서 대부분을 다루었습니다 .

개정 이름 목록에서 태그를 제거하는 플래그를 추가하고 있습니다. 이것은 우리에게 :

git name-rev --name-only --exclude=tags/* $SHA

두 번째 문장에서 뭔가 빠진 것 같습니다.
피터 Mortensen

설명을 업데이트했습니다. 피드백을위한 Thx.
phyatt

4

가난한 사람의 옵션은 도구 tig1 on 을 사용 하고HEAD 커밋을 검색 한 다음 병합 커밋이 보일 때까지 해당 커밋의 라인을 시각적으로 따르는 것입니다. 기본 병합 메시지는 어떤 브랜치가 어디에 병합되는지 지정해야합니다. :)

1 Tig는 Git 용 ncurses 기반 텍스트 모드 인터페이스입니다. 주로 Git 리포지토리 브라우저로 작동하지만 청크 수준에서 커밋에 대한 변경 사항을 준비하고 다양한 Git 명령의 출력을위한 호출기로 작동 할 수도 있습니다.


3

실험으로, 커밋 메타 데이터에 현재 체크 아웃 된 분기에 대한 정보를 저장하는 커밋 후 후크를 만들었습니다. 또한 정보를 표시하기 위해 gitk를 약간 수정했습니다.

https://github.com/pajp/branch-info-commits 에서 확인할 수 있습니다.


1
그러나 메타 데이터를 추가하려면 커밋 헤더를 엉망으로 만드는 대신 git note를 사용하지 않는 이유는 무엇입니까? 참조 stackoverflow.com/questions/5212957/... , stackoverflow.com/questions/7298749/... 또는 stackoverflow.com/questions/7101158/...
VonC

솔직히 말해서, 나는 그것을 쓸 때 자식 노트가 있다는 것을 몰랐다. 예, git note를 사용하여 동일한 것을 달성하는 것이 더 좋습니다.
pajp

3

나는 동일한 문제 ( Jenkins multibranch pipeline)를 처리합니다. 정보를 커밋 하고이 커밋이 처음 시작된 지점 이름을 찾으려고합니다. 원격 브랜치에서 작동해야하며 로컬 사본을 사용할 수 없습니다.

이것이 내가 함께하는 일입니다.

git rev-parse HEAD | xargs git name-rev

선택적으로 출력을 제거 할 수 있습니다.

git rev-parse HEAD | xargs git name-rev | cut -d' ' -f2 | sed 's/remotes\/origin\///g'

0

실제로 지점 하나에 존재하지만 지점을 찾을 수없는 동일한 문제에 직면해야한다고 생각합니다.

먼저 모든 것을 당기는 것이 좋습니다.

git pull --all

그런 다음 지점 검색을 수행하십시오.

git name-rev <SHA>

또는:

git branch --contains <SHA>

0

영업 이익이 결정하려고하는 경우 역사 특정 제작 한 커밋 지점에 의해 통과 된 후 reflog없이이 없습니다 ( "어떤 지점 커밋하는 것은 주어진 자사의 SHA-1 해시 값에서 유래 알아") 어떤 Git 객체 데이터베이스의 레코드는 커밋 히스토리에 바인딩 된 명명 된 분기를 표시합니다.

(댓글에 대한 답변으로 이것을 답변으로 게시했습니다.)

바라건대이 스크립트는 내 요점을 보여줍니다.

rm -rf /tmp/r1 /tmp/r2; mkdir /tmp/r1; cd /tmp/r1
git init; git config user.name n; git config user.email e@x.io
git commit -m"empty" --allow-empty; git branch -m b1; git branch b2
git checkout b1; touch f1; git add f1; git commit -m"Add f1"
git checkout b2; touch f2; git add f2; git commit -m"Add f2"
git merge -m"merge branches" b1; git checkout b1; git merge b2
git clone /tmp/r1 /tmp/r2; cd /tmp/r2; git fetch origin b2:b2
set -x;
cd /tmp/r1; git log --oneline --graph --decorate; git reflog b1; git reflog b2;
cd /tmp/r2; git log --oneline --graph --decorate; git reflog b1; git reflog b2;

출력은 'Add f1'이있는 커밋이 원격 클론 / tmp / r2의 브랜치 b1 또는 b2에서 온 것인지 알 수있는 방법이 없음을 보여줍니다.

(여기서 출력의 마지막 줄)

+ cd /tmp/r1
+ git log --oneline --graph --decorate
*   f0c707d (HEAD, b2, b1) merge branches
|\
| * 086c9ce Add f1
* | 80c10e5 Add f2
|/
* 18feb84 empty
+ git reflog b1
f0c707d b1@{0}: merge b2: Fast-forward
086c9ce b1@{1}: commit: Add f1
18feb84 b1@{2}: Branch: renamed refs/heads/master to refs/heads/b1
18feb84 b1@{3}: commit (initial): empty
+ git reflog b2
f0c707d b2@{0}: merge b1: Merge made by the 'recursive' strategy.
80c10e5 b2@{1}: commit: Add f2
18feb84 b2@{2}: branch: Created from b1
+ cd /tmp/r2
+ git log --oneline --graph --decorate
*   f0c707d (HEAD, origin/b2, origin/b1, origin/HEAD, b2, b1) merge branches
|\
| * 086c9ce Add f1
* | 80c10e5 Add f2
|/
* 18feb84 empty
+ git reflog b1
f0c707d b1@{0}: clone: from /tmp/r1
+ git reflog b2
f0c707d b2@{0}: fetch origin b2:b2: storing head

그리고 두 경우 의 출력 git log 80c10e5..HEAD --ancestry-path --merges --oneline --color | tail -n 1git log 086c9ce..HEAD --ancestry-path --merges --oneline --color | tail -n 1명령은 무엇입니까?
Eugen Konkov

물론 SHA는 명령이 실행될 때마다 변경되므로 명령을 새로 작성하기 위해 HEAD ^ 1HEAD ^ 2 를 사용했습니다. 명령 및 출력은 다음과 같습니다. $ git log HEAD^1..HEAD --ancestry-path --merges --oneline --color | tail -n 1수율 376142d merge branches$ git log HEAD^2..HEAD --ancestry-path --merges --oneline --color | tail -n 1수율 376142d merge branches -병합 커밋 요약을 보여줍니다. 병합이 생성 될 때 덮어 쓸 수 있으며 병합의 분기 기록을 혼란스럽게 할 수 있습니다.
qneill

0

TL; DR :

쉘 종료 상태에 관심이있는 경우 아래를 사용하십시오.

  • branch-current -현재 지점의 이름
  • branch-names -깨끗한 분기 이름 (한 줄에 하나씩)
  • branch-name -하나의 지점 만 반환해야합니다. branch-names

모두 branch-namebranch-namesA는 인수로 투입하고, 기본적 동의 HEAD아무 것도 주어지지 않는 경우.


스크립팅에 유용한 별칭

branch-current = "symbolic-ref --short HEAD"  # https://stackoverflow.com/a/19585361/5353461
branch-names = !"[ -z \"$1\" ] && git branch-current 2>/dev/null || git branch --format='%(refname:short)' --contains \"${1:-HEAD}\" #"  # https://stackoverflow.com/a/19585361/5353461
branch-name = !"br=$(git branch-names \"$1\") && case \"$br\" in *$'\\n'*) printf \"Multiple branches:\\n%s\" \"$br\">&2; exit 1;; esac; echo \"$br\" #"

한 지점에서만 도달 할 수있는 커밋

% git branch-name eae13ea
master
% echo $?
0
  • 출력은 STDOUT
  • 종료 값은 0입니다.

여러 지점에서 접근 가능

% git branch-name 4bc6188
Multiple branches:
attempt-extract
master%
% echo $?
1
  • 출력은 STDERR로
  • 종료 값은 1입니다.

종료 상태로 인해 안전하게 구축 할 수 있습니다. 예를 들어, 가져 오기에 사용되는 리모콘을 가져 오려면 다음을 수행하십시오.

remote-fetch = !"branch=$(git branch-name \"$1\") && git config branch.\"$branch\".remote || echo origin #"

-1

지역 지점을 찾으려면

grep -lR YOUR_COMMIT .git/refs/heads | sed 's/.git\/refs\/heads\///g'

원격 지점을 찾으려면

grep -lR $commit .git/refs/remotes | sed 's/.git\/refs\/remotes\///g'

1
귀하의 사례에 대한 설명은 훌륭 할 것입니다
Eugen Konkov

-4

일치하는 해시를 찾을 때까지 모든 트리를 검색하는 것 외에는 없습니다.


7
엄밀히 말하면 git이 해당 정보를 영구적으로 저장하지 않는다는 것이 사실이지만 그럼에도 불구하고 매우 자주 알아볼 수 있기 때문에 나는 이것을 하향 투표하고 싶지 않습니다. 내 대답을 참조하십시오.
Cascabel
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.