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 1과 git log 086c9ce..HEAD --ancestry-path --merges --oneline --color | tail -n 1명령은 무엇입니까?
— Eugen Konkov

물론 SHA는 명령이 실행될 때마다 변경되므로 명령을 새로 작성하기 위해 HEAD ^ 1 및 HEAD ^ 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-name와 branch-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.