Git 브랜치의 가장 가까운 부모를 찾는 방법은 무엇입니까?


419

다음과 같은 커밋 트리가있는 다음 로컬 저장소가 있다고 가정 해 봅시다.

master --> a
            \
             \
      develop c --> d
               \
                \
         feature f --> g --> h

master내 인 이 최신 안정 릴리스 코드가되고 , develop이가 '다음'릴리스 코드 , 및 feature입니다 준비중인 새로운 기능develop .

후크를 사용하여 원격 리포지토리에서 수행 할 수있는 것은 feature커밋 fdevelopHEAD 의 직접적인 자손이 아닌 한 푸시 가 거부되는 것 입니다. 즉, 기능이 git rebase켜져 있기 때문에 커밋 트리는 다음과 같습니다 d.

master --> a
            \
             \
      develop c --> d
                     \
                      \
               feature f --> g --> h

따라서 다음이 가능합니다.

  • feature? 의 부모 분기를 식별하십시오 .
  • f자손 인 부모 브랜치에서 커밋을 식별 합니까?

거기에서 상위 브랜치의 HEAD가 무엇인지 확인하고 f이전 모델이 상위 브랜치 HEAD와 일치하는지 확인하여 기능을 리베이스해야하는지 결정합니다.


이 질문은 부모의 부모를 찾기 위해 표현해야합니다.
Tim Boland

답변:


347

원격 저장소에 개발 브랜치 의 사본이 있다고 가정하면 (초기 설명에서 로컬 저장소에 설명하지만 원격에도 존재하는 것처럼 들린다) 원하는 생각을 얻을 수 있지만 접근 방식은 당신이 상상 한 것과는 조금 다릅니다.

Git의 역사는 커밋 의 DAG 를 기반으로합니다 . 분기 (및 일반적으로 "참조")는 지속적으로 커밋되는 커밋 DAG에서 특정 커밋을 가리키는 일시적 레이블입니다. 따라서 지점 간의 관계는 시간이 지남에 따라 달라질 수 있지만 커밋 간의 관계는 그렇지 않습니다.

    ---o---1                foo
            \
             2---3---o      bar
                  \
                   4
                    \
                     5---6  baz

그것은 baz(이전 버전)을 기반으로하는 것 같습니다 bar. 그러나 우리가 삭제하면 어떻게 bar될까요?

    ---o---1                foo
            \
             2---3
                  \
                   4
                    \
                     5---6  baz

이제는 baz에 기반한 것 같습니다 foo. 그러나의 조상은 baz바뀌지 않았습니다. 우리는 레이블 (및 결과 매달려있는 커밋)을 제거했습니다. 에 새 라벨을 추가하면 4어떻게 되나요?

    ---o---1                foo
            \
             2---3
                  \
                   4        quux
                    \
                     5---6  baz

이제는 baz에 기반한 것 같습니다 quux. 그럼에도 불구하고 조상은 바뀌지 않았고 라벨 만 바뀌 었습니다.

그러나 우리가“커밋 6의 자손을 커밋 3합니까?” (가정 36여부, 다음 대답은 "예"가 될 것입니다 SHA-1은 이름을 커밋 가득) barquux라벨이 존재하거나하지 않습니다.

따라서 "푸시 된 커밋은 개발 브랜치 의 현재 팁의 후손 입니까?"와 같은 질문을 할 수 있지만 "푸시 된 커밋의 부모 분기는 무엇입니까?"라고 확실하게 요청할 수는 없습니다.

당신이 원하는 것에 가장 가까운 것으로 보이는 가장 신뢰할만한 질문은 다음과 같습니다.

모두를 위해 (현재의 팁을 제외한의 조상 커밋 밀어 개발 의 현재 끝이 있고, 그 조상) 개발을 부모로를 :

  • 그러한 커밋이 하나 이상 존재합니까?
  • 그러한 모든 커밋은 단일 부모 커밋입니까?

다음과 같이 구현할 수 있습니다.

pushedrev=...
basename=develop
if ! baserev="$(git rev-parse --verify refs/heads/"$basename" 2>/dev/null)"; then
    echo "'$basename' is missing, call for help!"
    exit 1
fi
parents_of_children_of_base="$(
  git rev-list --pretty=tformat:%P "$pushedrev" --not "$baserev" |
  grep -F "$baserev"
)"
case ",$parents_of_children_of_base" in
    ,)     echo "must descend from tip of '$basename'"
           exit 1 ;;
    ,*\ *) echo "must not merge tip of '$basename' (rebase instead)"
           exit 1 ;;
    ,*)    exit 0 ;;
esac

이것은 당신이 제한하고 싶은 것의 일부를 다룰 것이지만, 전부는 아닙니다.

참고로 다음은 확장 된 예제 기록입니다.

    A                                   master
     \
      \                    o-----J
       \                  /       \
        \                | o---K---L
         \               |/
          C--------------D              develop
           \             |\
            F---G---H    | F'--G'--H'
                    |    |\
                    |    | o---o---o---N
                     \   \      \       \
                      \   \      o---o---P
                       \   \   
                        R---S

위의 코드는 거부하는 데 사용할 수 있습니다 HS수용하면서 H', J, K, 또는 N, 그러나 또한 받아 들일 LP(그들은 병합을 포함, 그러나 끝 병합하지 않는 개발을 ).

또한 거부 L하고 P, 당신은 질문을 변경 요청할 수 있습니다

푸시 된 커밋의 조상 (현재 개발 팁 및 조상 제외 ) :

  • 두 부모와의 약속이 있습니까?
  • 그렇지 않다면, 그러한 커밋 중 하나 이상이 현재 유일한 부모 를 개발 하고 있습니까?
pushedrev=...
basename=develop
if ! baserev="$(git rev-parse --verify refs/heads/"$basename" 2>/dev/null)"; then
    echo "'$basename' is missing, call for help!"
    exit 1
fi
parents_of_commits_beyond_base="$(
  git rev-list --pretty=tformat:%P "$pushedrev" --not "$baserev" |
  grep -v '^commit '
)"
case "$parents_of_commits_beyond_base" in
    *\ *)          echo "must not push merge commits (rebase instead)"
                   exit 1 ;;
    *"$baserev"*)  exit 0 ;;
    *)             echo "must descend from tip of '$basename'"
                   exit 1 ;;
esac

나는 이것을 얻는다 : git : fatal : 모호한 인수 '...': 개정과 파일 이름. 트리플 도트 의도는 무엇입니까?
Jack Ukleja

1
@Schneider 나는이 예제에서 '...'이 자리 표시자가 될 것이라고 확신합니다. 커밋을 SHA로 바꾸면이 검사를 수행하려고합니다 (예 : 지점의 HEAD 당신은 현재), 모든 것이 잘 작동합니다.
Daniel Brady

이 정교한 답변에 감사드립니다! 매우 유용합니다. 비슷한 고리를 만들고 싶지만 개발 지점의 이름을 하드 코딩하고 싶지 않습니다. 의미 나는 부모 브랜치 이외의 브랜치로의 리베이스를 막기위한 후크를 원한다. 당신의 대답을 잘 이해한다면 (나는 bash와 물건을 처음 사용합니다) 이것은 당신의 대답에 포함되지 않습니다. 이것을 할 수있는 방법이 있습니까?
Kemeia

관련 질문에 기꺼이 답변 하시겠습니까? REMOTE 리포지토리에서 코드를 작동시킬 수 없었습니다. 다음은 REMOTE 리포지토리에서 작업하기 위해 접근 방식을 조정하는 방법에 대한 후속 질문 링크입니다. stackoverflow.com/questions/49619492/…
CodeMed

이것은 내가있을 때 나에게 효과가 없었습니다 develop > release > feature. 나는 다시 개발할 것이고 부모를 알아야합니다. 내 문제에 대한 해결책은 stackoverflow.com/a/56673640/2366390
verdverm

240

찬사

질문을 표현하는 또 다른 방법은 "현재 분기 이외의 분기에 상주하는 가장 가까운 커밋은 무엇이며 어떤 분기입니까?"입니다.

해결책

약간의 커맨드 라인 마술로 찾을 수 있습니다.

git show-branch \
| sed "s/].*//" \
| grep "\*" \
| grep -v "$(git rev-parse --abbrev-ref HEAD)" \
| head -n1 \
| sed "s/^.*\[//" 

AWK :

git show-branch -a \
| grep '\*' \
| grep -v `git rev-parse --abbrev-ref HEAD` \
| head -n1 \
| sed 's/[^\[]*//' \
| awk 'match($0, /\[[a-zA-Z0-9\/-]+\]/) { print substr( $0, RSTART+1, RLENGTH-2 )}'

작동 방식은 다음과 같습니다.

  1. 원격 브랜치를 포함하여 모든 커밋의 텍스트 기록을 표시합니다.
  2. 현재 커밋의 조상은 별표로 표시됩니다. 다른 모든 것을 걸러 내십시오.
  3. 현재 분기의 모든 커밋을 무시하십시오.
  4. 첫 번째 결과는 가장 가까운 조상 지점입니다. 다른 결과는 무시하십시오.
  5. 지점 이름은 괄호 안에 표시됩니다. 대괄호와 대괄호 외부의 모든 것을 무시하십시오.
  6. 때로는 분기 이름에 ~ # 또는 ^ #이 포함되어 참조 된 커밋과 분기 팁 사이의 커밋 수를 나타냅니다. 우리는 상관하지 않습니다. 그들을 무시하라.

그리고 결과

위의 코드를 실행

 A---B---D <-master
      \
       \
        C---E---I <-develop
             \
              \
               F---G---H <-topic

당신을 줄 것이다 develop당신이 H에서 실행한다면 master당신은 I.에서 실행하는 경우

코드는 요점으로 제공됩니다


24
오류를 일으킨 후행 백틱을 제거했습니다. 이 명령을 실행할 때 각 지점에 대해 불평하는 많은 경고가 표시됩니다.cannot handle more than 25 refs
Jon L.

1
@JoeChrysler 당신은 당신이 그것을 2 대신 한 줄로 만들 ack수 있고 Mac에서 사용할 수없는 Mac에서 작동하도록 만들 수 있다고 생각합니다 (누군가로 대체 ack하는 것이 좋습니다 grep)
nonopolarity

53
죄송합니다. 잘못된 것입니다. 나를 위해 일한 올바른 것이 여기 있습니다 :git show-branch | grep '*' | grep -v "$(git rev-parse --abbrev-ref HEAD)" | head -n1 | sed 's/.*\[\(.*\)\].*/\1/' | sed 's/[\^~].*//'
droidbot

15
@droidbot 멋지지만 grep -v catch commit 메시지이거나 분기 이름이 다른 분기 이름의 일부인 경우 참조 제거를 피하기 위해 파이핑 순서가 필요합니다. git show-branch | sed "s/].*//" | grep "\*" | grep -v "$(git rev-parse --abbrev-ref HEAD)" | head -n1 | sed "s/^.*\[//"
gaal

3
@OlegAbrazhaev 질문에 대한 답변을 얻었는지 모르겠습니다. 자식 별칭 사용 : parent = "!git show-branch | grep '*' | grep -v \"$(git rev-parse --abbrev-ref HEAD)\" | head -n1 | sed 's/.*\\[\\(.*\\)\\].*/\\1/' | sed 's/[\\^~].*//' #"저에게
효과적

111

시도해 볼 수도 있습니다 :

git log --graph --decorate

5
git log --graph --decorate --simplify-by-decoration여기서 --graph선택 사항입니다.
Na13-c 2019

1
git log --graph --decorate --simplify-by-decoration --oneline
anishtain4

106

자식 부모

당신은 명령을 실행할 수 있습니다

git parent

@Joe Chrysler 의 답변을 자식 별칭 으로 추가하면 분기의 부모를 찾습니다 . 사용법을 단순화합니다.

"~/.gitconfig"텍스트 편집기를 사용하여 위치한 gitconfig 파일을 엽니 다 . (리눅스의 경우). Windows의 경우 ".gitconfig"경로는 일반적으로 다음 위치에 있습니다.c:\users\your-user\.gitconfig

vim  ~/.gitconfig

파일에 다음 별명 명령을 추가하십시오.

[alias]
            parent = "!git show-branch | grep '*' | grep -v \"$(git rev-parse --abbrev-ref HEAD)\" | head -n1 | sed 's/.*\\[\\(.*\\)\\].*/\\1/' | sed 's/[\\^~].*//' #"

편집기를 저장하고 종료하십시오.

명령을 실행 git parent

그게 다야!


5
이것은 훌륭한 솔루션입니다. 예상 결과를 보장하기 위해 일부 샘플 출력을 추가하는 것도 도움이됩니다. 내가 그것을 실행할 때, 나는 마지막 지점 앞에 부모 지점의 이름이라고 생각하는 몇 가지 경고를 받았습니다.
ttemple

4
매력처럼 작동합니다! 윈도우 사용자를위한 .gitconfig은 일반적으로 C에 위치 : \ 사용자 \ 사용자의 사용자 \ .gitconfig
시온

12
얻기 cannot handle more than 25 refs예외.
shajin

누군가 경고를 처리하기 위해 이것을 편집 할 수 있습니까? @ttemple, 당신은 할 수 있습니까?
NIKHIL CM

@NIKHILCM은 챔피언처럼 작동합니다. 그러나 부모가 지점이 어디에서 만들어 졌는지 또는 다른 것을 나타내는 지 여부에 대한 질문이 있습니까?
Hariprasath

52

전반적인 문제에 대한 해결책이 있지만 ( feature의 끝에서 내려진 경우 결정 develop), 설명 한 방법으로는 작동하지 않습니다.

git branch --contains의 끝에서 내려온 모든 분기를 나열 하는 데 사용할 수 있으며 develop그 사이에 grep있는지 확인하는 데 사용할 수 feature있습니다.

git branch --contains develop | grep "^ *feature$"

그 중 하나 인 경우 " feature"표준 출력으로 인쇄 하고 리턴 코드는 0입니다. 그렇지 않으면 아무것도 인쇄하지 않고 리턴 코드는 1입니다.


1
이것은 작동하지만 많은 참조가있는 저장소에서는 시간이 오래 걸릴 수 있습니다. 예를 들어 사전 수신 후크에서 실행하기에 이상적이지 않습니다.
ebneter 2016 년

나는 지점, 우리가 전화 할게 찾고 있었다 <branch>: 내가 수행 git checkout -b <branch-2>에서 ...이 답이다! 정말 grep 필요가 없습니다. git branch --contains <branch>
Poopy McFartnoise 님이

44

이것은 나를 위해 잘 작동합니다.

git show-branch | grep '*' | grep -v "$(git rev-parse --abbrev-ref HEAD)" | head -n1 | sed 's/.*\[\(.*\)\].*/\1/' | sed 's/[\^~].*//'

@droidbot 및 @Jistanidiot의 답변


네,하지만 가끔은 grep에서 "파손 된 파이프"를 얻습니다.
Vladislav Rastrusny

1
*grep에 전달하기에 적합한 정규식이 아닙니다. grep -F '*'또는 grep '\*'대신 사용해야 합니다. 그렇지 않으면 좋은 해결책입니다.
arielf

출력이 없습니다.
Sandip Subedi

나를 위해 작동합니다 ....
roottraveller

11

위의 답변 중 어느 것도 우리 저장소에서 작동하지 않았으므로 최신 병합을 사용하여 내 방식을 공유하고 싶습니다 git log.

#!/bin/bash
git log --oneline --merges "$@" | grep into | sed 's/.* into //g' | uniq --count | head -n 10

라는 스크립트에 넣으십시오.이 스크립트 git-last-merges는 분기 이름을 현재 분기 대신 git log인수 및 다른 인수로 허용합니다.

출력에서 자체 분기 규칙과 각 분기의 병합 수를 기반으로 상위 분기를 수동으로 감지 할 수 있습니다.

편집 :git rebase 자식 분기에서 자주 사용 하고 병합이 자주 전달되므로 병합 커밋이 너무 많지 않으면이 답변이 제대로 작동하지 않으므로 미리 커밋을 계산하는 스크립트를 작성했습니다 (정상 및 병합) 현재 브랜치와 비교하여 모든 브랜치에서, 및 커밋 뒤 (부모 브랜치에는 뒤 병합이 없어야 함)가 있습니다. 이 스크립트를 실행하면 효과가 있는지 알려주세요.

#!/bin/bash
HEAD="`git rev-parse --abbrev-ref HEAD`"
echo "Comparing to $HEAD"
printf "%12s  %12s   %10s     %s\n" "Behind" "BehindMerge" "Ahead" "Branch"
git branch | grep -v '^*' | sed 's/^\* //g' | while read branch ; do
    ahead_merge_count=`git log --oneline --merges $branch ^$HEAD | wc -l`
    if [[ $ahead_merge_count != 0 ]] ; then
        continue
    fi
    ahead_count=`git log --oneline --no-merges $branch ^$HEAD | wc -l`
    behind_count=`git log --oneline --no-merges ^$branch $HEAD | wc -l`
    behind_merge_count=`git log --oneline --merges ^$branch $HEAD | wc -l`
    behind="-$behind_count"
    behind_merge="-M$behind_merge_count"
    ahead="+$ahead_count"
    printf "%12s  %12s   %10s     %s\n" "$behind" "$behind_merge" "$ahead" "$branch"
done | sort -n

감사. rebase자주 사용하면 병합이 잘되지 않을 수 있지만 병합은 fast-forward자주 수행됩니다. 더 나은 해결책을 찾으면 답변을 편집하겠습니다.
saeedgnu

1
유일한? 현재 지점이 마스터 인 경우 지금까지 현명하게 작동했습니다. 대부분의 다른 솔루션은 실제 상위 브랜치가없는이 경우가 간헐적으로 발생하는 임의의 (그리고 분명히 부정확 한) 결과를 제공했습니다.
arielf

이것은 나를 위해 일한 유일한 대답입니다. 처음 10 개의 목록 대신 첫 번째 부모를 얻으려면 다음을 사용할 수 있습니다. git log --oneline --merges "$@" | grep into | sed 's/.* into //g' | uniq --count | head -n 1 | cut -d ' ' -f 8
lots0logs

10

해결책

이 솔루션 에 기반git show-branch 나는 하나를 결합했습니다, 그래서 내가 (아래 참조) 잘 작동하지 않았다 기반으로git log 이 함께 결국 :

git log --decorate --simplify-by-decoration --oneline \ # selects only commits with a branch or tag
      | grep -v "(HEAD" \                               # removes current head (and branch)
      | head -n1 \                                      # selects only the closest decoration
      | sed 's/.* (\(.*\)) .*/\1/' \                    # filters out everything but decorations
      | sed 's/\(.*\), .*/\1/' \                        # picks only the first decoration
      | sed 's/origin\///'                              # strips "origin/" from the decoration

한계와 경고

  • HEAD를 분리 할 수 ​​있지만 (많은 CI 도구는 지정된 분기에서 올바른 커밋을 빌드하기 위해 그렇게합니다), 원래 분기 및 로컬 분기 는 현재 HEAD 와 동등하거나 "위"에 있어야합니다.
  • 방해 가 되지 않는 태그 가 없어야합니다 . (나는 가정합니다; 자식과 부모 브랜치 사이의 태그를 사용하여 커밋에서 스크립트를 테스트하지 않았습니다)
  • 스크립트는 사실에 의존 "HEAD" 항상 최초의 장식으로 나열 바이 log명령
  • 실행 스크립트 masterdevelop 결과 (주로)에서<SHA> Initial commit

결과

 A---B---D---E---F <-origin/master, master
      \      \
       \      \
        \      G---H---I <- origin/hotfix, hotfix
         \
          \
           J---K---L <-origin/develop, develop
                \
                 \
                  M---N---O <-origin/feature/a, feature/a
                       \   \
                        \   \
                         \   P---Q---R <-origin/feature/b, feature/b
                          \
                           \
                            S---T---U <-origin/feature/c, feature/c

로컬 브랜치 존재에도 불구하고 (예 : SHA가 origin/topic커밋 O을 직접 체크 아웃 한 이후 에만 존재 ) 스크립트는 다음과 같이 인쇄해야합니다.

  • 커밋의 경우 G, H,I (지점 hotfix) →master
  • 커밋의 경우 M, N,O (지점 feature/a) →develop
  • 커밋의 경우 S, T,U (지점 feature/c) →develop
  • 커밋의 경우 P, Q,R (지점 feature/b) →feature/a
  • 커밋의 경우 J, K, L(지점 develop) → <sha> Initial commit*
  • 커밋의 경우 B, D, E, F(지점 master) →<sha> Initial commit

*-또는 '커밋이 마스터의 HEAD보다 위에있는 master경우 develop(~ 마스터는 개발하기가 빠릅니다)


왜 나를 위해 가지를 보여주지 않았습니까?

다음과 같은 상황에서는 기반git show-branch 솔루션 이 신뢰할 수 없음이 입증되었습니다.

  • 분리 된 헤드 – 분리 된 헤드 케이스를 포함 grep '\*' \하면`grep '을 교체 할 수 있습니다! – – 그리고 그것은 모든 문제의 시작일뿐입니다
  • 스크립트 masterdevelop실행 하고 결과는 develop각각``
  • 에 지점master 지점 ( hotfix/지점)이와 끝까지 develop자신의 가장 가까운 때문에 부모로서 master분기 부모가 표시되었다 !대신의 *이유.

2
git 별칭으로 작동 한 답변 만 :"!git log --decorate --simplify-by-decoration --oneline | grep -v '(HEAD' | head -n1 | sed 's/.* (\\(.*\\)) .*/\\1/' | sed 's/\\(.*\\), .*/\\1/' | sed 's/origin\\///'"
Ian Kemp

8

"Git : 커밋이 시작된 분기 찾기"에 설명 된대로 git branch --contains <commit>시작 이더라도 커밋이 이루어진 분기를 쉽게 찾아 낼 수 없습니다 (분기의 이름을 바꾸거나, 이동하거나, 삭제할 수 있습니다 ...) .

  • 분기 및 목록 분기를 git branch --contains <commit>나열하지 않을 때까지 커밋에서 커밋으로 돌아갈 수 있습니다 .featuredevelop
  • 그 커밋 SHA1과 비교 /refs/heads/develop

두 커밋 id가 일치하면 가야합니다 ( feature분기가 HEAD에 원점이 있음을 의미합니다 develop).


6

JoeChrysler의 명령 줄 마술을 단순화 할 수 있습니다. Joe의 논리는 다음과 같습니다. 간결하게하기 위해 cur_branch명령 대체 대신 이름이 지정된 매개 변수 `git rev-parse --abbrev-ref HEAD`를 두 버전으로 모두 소개했습니다 . 다음과 같이 초기화 할 수 있습니다.

cur_branch=$(git rev-parse --abbrev-ref HEAD)

다음은 Joe의 파이프 라인입니다.

git show-branch -a           |
  grep '\*'                  | # we want only lines that contain an asterisk
  grep -v "$cur_branch"      | # but also don't contain the current branch
  head -n1                   | # and only the first such line
  sed 's/.*\[\(.*\)\].*/\1/' | # really, just the part of the line between []
  sed 's/[\^~].*//'            # and with any relative refs (^, ~n) removed

상대적으로 간단한 awk명령 으로 5 개의 개별 명령 필터와 동일한 작업을 수행 할 수 있습니다 .

git show-branch -a |
  awk -F'[]^~[]' '/\*/ && !/'"$cur_branch"'/ {print $2;exit}'  

다음과 같이 분류됩니다.

-F'[]^~[]' 

에서 필드에 선을 분할 ], ^, ~, 및 [문자.

/\*/                      

별표가 포함 된 줄 찾기

&& !/'"$cur_branch"'/

...하지만 현재 지점 이름이 아닙니다

{ print $2;               

그런 줄을 찾으면 두 번째 필드, 즉 첫 번째와 두 번째 필드 구분 문자 사이의 부분을 인쇄하십시오. 간단한 브랜치 이름의 경우 대괄호 사이에있는 것입니다. 상대 점프가있는 심판의 경우 수정자가없는 이름 일뿐입니다. 따라서 필드 구분 기호 세트는 두 sed명령 의 의도를 처리 합니다.

  exit }

그런 다음 즉시 종료하십시오. 즉, 첫 번째 일치하는 줄만 처리하므로 출력을 통해 파이프 할 필요가 없습니다 head -n 1.


3
너무 많은 참조로 인해 출력에서 ​​일부 분기가 누락 될 수 있습니다. 대신 stderr에 경고로 표시됩니다.
Zitrax

5

Mark Reed 솔루션의 PowerShell 구현은 다음과 같습니다.

git show-branch -a | where-object { $_.Contains('*') -eq $true} | Where-object {$_.Contains($branchName) -ne $true } | select -first 1 | % {$_ -replace('.*\[(.*)\].*','$1')} | % { $_ -replace('[\^~].*','') }

5

나는 이것이이 문제를 해결하는 좋은 방법이라고 말하지는 않지만 이것이 효과가있는 것처럼 보입니다.

git branch --contains $(cat .git/ORIG_HEAD) 문제는 파일을 cating하는 것이 git의 내부 작업을 엿보기 때문에 반드시 순방향 호환 (또는 역 호환)되는 것은 아닙니다.


3

Ant를 사용한 크로스 플랫폼 구현

    <exec executable="git" outputproperty="currentBranch">
        <arg value="rev-parse" />  
        <arg value="--abbrev-ref" />  
        <arg value="HEAD" />  
    </exec>

    <exec executable="git" outputproperty="showBranchOutput">
        <arg value="show-branch" />  
        <arg value="-a" />  
    </exec>

    <loadresource property="baseBranch">
      <propertyresource name="showBranchOutput"/>
          <filterchain>
            <linecontains>
              <contains value="*"/>
            </linecontains>
            <linecontains negate="true">
              <contains value="${currentBranch}"/>
            </linecontains>
            <headfilter lines="1"/>
            <tokenfilter>
                <replaceregex pattern=".*\[(.*)\].*" replace="\1"/>
                <replaceregex pattern="[\^~].*" replace=""/>
            </tokenfilter>
          </filterchain>
    </loadresource>

    <echo message="${currentBranch} ${baseBranch}" />

2

@Mark Reed : 커밋 라인에는 별표가 포함될뿐만 아니라 별표로 시작해야한다고 덧붙여 야합니다! 그렇지 않으면 별표가 포함 된 커밋 메시지도 일치하는 행에 포함됩니다. 따라서 다음과 같아야합니다.

git show-branch -a | awk -F'[]^~[]' '/^\*/ && !/'"$current_branch"'/ {print $2;exit}'

또는 긴 버전 :

git show-branch -a           |
  awk '^\*'                  | # we want only lines that contain an asterisk
  awk -v "$current_branch"   | # but also don't contain the current branch
  head -n1                   | # and only the first such line
  sed 's/.*\[\(.*\)\].*/\1/' | # really, just the part of the line between []
  sed 's/[\^~].*//'            # and with any relative refs (^, ~n) removed`

2
vbc=$(git rev-parse --abbrev-ref HEAD)
vbc_col=$(( $(git show-branch | grep '^[^\[]*\*' | head -1 | cut -d* -f1 | wc -c) - 1 )) 
swimming_lane_start_row=$(( $(git show-branch | grep -n "^[\-]*$" | cut -d: -f1) + 1 )) 
git show-branch | tail -n +$swimming_lane_start_row | grep -v "^[^\[]*\[$vbc" | grep "^.\{$vbc_col\}[^ ]" | head -n1 | sed 's/.*\[\(.*\)\].*/\1/' | sed 's/[\^~].*//'

Mark Reed의 답변과 같은 목적을 달성하지만 여러 시나리오에서 오작동하지 않는 훨씬 안전한 접근 방식을 사용합니다.

  1. 부모 브랜치의 마지막 커밋은 병합이므로 열이 표시 - 되지 않습니다.*
  2. 커밋 메시지에 지점 이름이 포함됨
  3. 커밋 메시지 포함 *

0

요즘이 일을하고 싶은 사람-Atlassian의 SourceTree 애플리케이션은 브랜치가 서로 관련되는 방식, 즉 시작 지점과 현재 커밋 순서 (예 : HEAD 또는 4 개의 커밋 등)를 시각적으로 잘 보여줍니다. .


0

소스 트리를 사용하면 커밋 세부 정보> 부모>를 보면 커밋 번호에 밑줄이 나타납니다 (링크)


0

대안: git rev-list master | grep "$(git rev-list HEAD)" | head -1

내 지점과 master(또는 지정하려는 지점) 모두 마지막 커밋을 가져옵니다.


0

이 같은 일을했을 때 나에게 효과가 없었습니다. develop > release-v1.0.0 > feature-foo개발하기 위해 다시 돌아갈 것입니다.

다음은 올바른 커밋 해시를 제공했습니다.

git log --decorate \
  | grep 'commit' \
  | grep 'origin/' \
  | head -n 2 \
  | tail -n 1 \
  | awk '{ print $2 }' \
  | tr -d "\n"
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.