source

Git 분기의 가장 가까운 부모를 찾는 방법

lovecheck 2023. 4. 17. 21:58
반응형

Git 분기의 가장 가까운 부모를 찾는 방법

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

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

master이게 최신 안정 릴리즈 코드라는 거죠develop이것이 '다음' 릴리즈 코드입니다.feature는 에 준비되어 있는 신기능입니다.

훅을하여 크크에 대한 할 수 .feature커밋하지 한 저장소로 합니다.fdevelop과 같습니다. 이 HEAD이기 입니다. 아,아,아,아,아,아,아,아,아,아,아,아,아,아,아,아,아,아,아.기능이git rebased.

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

다음과 같은 일이 가능합니까?

  • 합니다.feature
  • 합니다.f★★★★★★★★★★★★★★★★★?

하고, 「HEAD」가 되어 있는지 합니다.f합니다.

리모트 저장소에 develope branch의 복사본이 있다고 가정하면(초기 설명에서는 로컬 저장소에 있는 것처럼 보이지만 리모트에도 존재하는 것처럼 들립니다), 원하는 것을 달성할 수 있을 것입니다만, 어프로치는 상상과는 조금 다릅니다.

Git의 역사는 DAG의 커밋에 기초하고 있다.브랜치(및 일반적으로 「ref」)는, 계속 증가하는 커밋 DAG 의 특정 커밋을 나타내는 일시적인 라벨입니다.따라서 브랜치 간의 관계는 시간에 따라 달라질 수 있지만 커밋 간의 관계는 변하지 않습니다.

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

★★★★★★★★★★★★★★★★★★.baz는 (옛을 으로 하고 있습니다.barbar

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

보면 ★★★★★★★★★★★★★★★★★★★.baz으로 하고 있습니다.foo지지 of of baz변경되지 않았습니다.라벨(및 그 결과 행잉 커밋)을 삭제했습니다. 새로운 될까요?4

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

보면 ★★★★★★★★★★★★★★★★★★★.baz으로 하고 있습니다.quux그래도 조상은 변하지 않고 라벨만 바뀌었다.

「commit 」라고 하는 「commit」라고 합니다63 (? (예)3 ★★★★★★★★★★★★★★★★★」6의 경우, 「SHA-1」의 이든, 「Yesbar ★★★★★★★★★★★★★★★★★」quux라벨의 유무

따라서 "pushed commit은 개발 브랜치의 현재 팁의 후예입니까?"와 같은 질문을 할 수 있지만 "pushed commit의 부모 브랜치는 무엇입니까?"와 같은 질문은 신뢰할 수 없습니다.

가장 신뢰할 수 있는 질문은 다음과 같습니다.

부모로서 현재 개발의 힌트를 가지고 있는 모든 푸시 커밋의 조상(현재 개발의 힌트 및 그 조상 제외):

  • 이러한 커밋이 적어도1개 존재합니까?
  • 이러한 커밋은 모두 한부모 커밋입니까?

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

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

하여 거부 할 수 있습니다.H ★★★★★★★★★★★★★★★★★」S 들이면서H',J,K , 「」N, 「」, 「」도 사용할 수 L ★★★★★★★★★★★★★★★★★」P(이것들은 머지를 수반하지만, 개발의 팁은 머지하지 않습니다).

L ★★★★★★★★★★★★★★★★★」P

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

  • 부모님 두 분과의 약속이라도 있나요?
  • 그렇지 않은 경우, 이러한 커밋 중 적어도 1개는 부모(유일한)를 육성하기 위한 최신 팁을 가지고 있습니까?
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 show-branch -a \
| 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에서 masterI-I-I-I-I-I-I-I-I-I-I-I-I-I-I-

코드는 요지로 사용할 수 있습니다.

Git 부모

명령어를 실행하면 됩니다.

git parent

크라이슬러의 답변Git 별칭으로 추가하면 지점의 부모를 찾을 수 있습니다.사용이 간단해집니다.

다음 위치에 있는 gitconfig 파일을 엽니다."~/.gitconfig"(Linux의 경우) 임의의 텍스트에디터를 사용합니다.의 경우, 「. 의 「.gitconfig」에 있습니다.C:\users\your-user\.gitconfig.

vim  ~/.gitconfig

파일에 다음 alias 명령을 추가합니다.

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

저장하고 에디터를 종료합니다.

합니다.git parent.

바로 그거야!

다음의 조작도 가능합니다.

git log --graph --decorate

이 작업은 정상적으로 작동합니다.

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

드로이드봇과 @Jistanidiot의 인사말과 답변.

는 당신의 대한 .featuredevelop) 。단, 설명한 방법으로는 동작하지 않습니다.

하시면 됩니다.git branch --contains의 을 모두 develop , 을 사용합니다.grep 하다feature그 중에 있어요.

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

그 중 하나일 경우 인쇄합니다." feature"0으로 하다그렇지 않으면 아무것도 인쇄되지 않고 반환 코드가 1이 됩니다.

왜 집에 부모가 없는 거죠?

이하에 나타내는 것

리스트:

왜 이 긴 글을 읽고 싶어 하겠어?왜냐하면 앞의 답변은 원래 질문의 문제를 명확하게 이해하지만, 정답/의미 있는 결과에 미치지 못하거나 다른 문제를 정확하게 해결하기 때문입니다.

첫 번째 섹션만 확인해도 됩니다.이 섹션은 '뭔가 발견' 문제를 해결하고 문제의 범위를 강조합니다.어떤 사람들에게는, 그것으로 충분할지도 모른다.

이것은 git에서 정확하고 의미 있는 결과를 추출하는 방법(마음에 들지 않을 수 있음)을 보여 줍니다.또, 이러한 결과에 대해서, 통념의 지식을 적용해, 정말로 찾고 있는 것을 추출하는 방법을 나타냅니다.

아래 섹션은 다음과 같습니다.

  • 편견 없는 질문과 솔루션:
    • 을 사용한 가장 git show-branch.
    • 예상되는 결과는 어떤 모습이어야 하는지
  • 그래프와 결과의 예시
  • Batching Branchs: 제한에 대한 대처git show-branch
  • 편향된 질문과 솔루션: 결과 개선을 위한 (이름 붙이기) 규칙 도입

질문의 문제

앞서 말한 바와 같이 git은 브랜치 간의 관계를 추적하지 않습니다. 브랜치는 커밋을 참조하는 이름일 뿐입니다.공식 git 문서 및 기타 소스에서는 다음과 같은 다소 오해의 소지가 있는 그림을 자주 볼 수 있습니다.

A---B---C---D    <- master branch
     \
      E---F      <- work branch

다이어그램의 형식과 계층적으로 시사적인 이름을 변경하여 동등한 그래프를 표시하도록 하겠습니다.

      E---F   <- jack
     /
A---B
     \
      C---D   <- jill

그래프(그리고 git)는 어떤 브랜치가 먼저 생성되었는지에 대해 전혀 알 수 없습니다(따라서 다른 브랜치로부터 분기되었습니다).

★★★master입니다.work첫 번째 그래프는 관습의 문제이다.

그러므로

  • 단순한 툴링은 편향을 무시하는 반응을 생성합니다.
  • 보다 복잡한 툴링에는 규칙(표준)이 포함되어 있습니다.

편견 없는 질문

우선, 저는 Joe Chrysler의 답변, 여기에서의 다른 답변, 그리고 주변의 많은 코멘트/제안들을 주로 인정해야 합니다.그것들은 저에게 영감을 주고 길을 제시해 주었습니다!

Joe의 표현을 바꿔서 가장 가까운 커밋과 관련된 여러 지점을 고려하겠습니다(실현).

현재 브랜치 이외의 브랜치에 존재하는 가장 가까운 커밋은 무엇입니까?또, 어느 브랜치입니까?

즉, 다음과 같습니다.

문제 1

된 브랜치 「」B합니다: " " "C 곳에B'HEAD )C"" " " " " " " " " " 가 될 수 .B'HEAD "하다" 이외의 지점: " "어느 지점",B 가지다C기상????

편견 없는 솔루션

먼저 사과드립니다. 사람들은 한 줄만 하는 것을 선호하는 것 같습니다.(읽을 수 있는/유지관리 가능한) 개선점을 자유롭게 제안해 주십시오!

#!/usr/local/bin/bash

# git show-branch supports 29 branches; reserve 1 for current branch
GIT_SHOW_BRANCH_MAX=28

CURRENT_BRANCH="$(git rev-parse --abbrev-ref HEAD)"
if (( $? != 0 )); then
    echo "Failed to determine git branch; is this a git repo?" >&2
    exit 1
fi


##
# Given Params:
#   EXCEPT : $1
#   VALUES : $2..N
#
# Return all values except EXCEPT, in order.
#
function valuesExcept() {
    local except=$1 ; shift
    for value in "$@"; do
        if [[ "$value" != "$except" ]]; then
            echo $value
        fi
    done
}


##
# Given Params:
#   BASE_BRANCH : $1           : base branch; default is current branch
#   BRANCHES    : [ $2 .. $N ] : list of unique branch names (no duplicates);
#                                perhaps possible parents.
#                                Default is all branches except base branch.
#
# For the most recent commit in the commit history for BASE_BRANCH that is
# also in the commit history of at least one branch in BRANCHES: output all
# BRANCHES that share that commit in their commit history.
#
function nearestCommonBranches() {
    local BASE_BRANCH
    if [[ -z "${1+x}" || "$1" == '.' ]]; then
        BASE_BRANCH="$CURRENT_BRANCH"
    else
        BASE_BRANCH="$1"
    fi

    shift
    local -a CANDIDATES
    if [[ -z "${1+x}" ]]; then
        CANDIDATES=( $(git rev-parse --symbolic --branches) )
    else
        CANDIDATES=("$@")
    fi
    local BRANCHES=( $(valuesExcept "$BASE_BRANCH" "${CANDIDATES[@]}") )

    local BRANCH_COUNT=${#BRANCHES[@]}
    if (( $BRANCH_COUNT > $GIT_SHOW_BRANCH_MAX )); then
        echo "Too many branches: limit $GIT_SHOW_BRANCH_MAX" >&2
        exit 1
    fi

    local MAP=( $(git show-branch --topo-order "${BRANCHES[@]}" "$BASE_BRANCH" \
                    | tail -n +$(($BRANCH_COUNT+3)) \
                    | sed "s/ \[.*$//" \
                    | sed "s/ /_/g" \
                    | sed "s/*/+/g" \
                    | egrep '^_*[^_].*[^_]$' \
                    | head -n1 \
                    | sed 's/\(.\)/\1\n/g'
          ) )

    for idx in "${!BRANCHES[@]}"; do
        ## to include "merge", symbolized by '-', use
        ## ALT: if [[ "${MAP[$idx]}" != "_" ]]
        if [[ "${MAP[$idx]}" == "+" ]]; then
            echo "${BRANCHES[$idx]}"
        fi
    done
}

# Usage: gitr [ baseBranch [branchToConsider]* ]
#   baseBranch: '.' (no quotes needed) corresponds to default current branch
#   branchToConsider* : list of unique branch names (no duplicates);
#                        perhaps possible (bias?) parents.
#                        Default is all branches except base branch.
nearestCommonBranches "${@}"

구조

고려:git show-branch

★★★의 git show-branch --topo-order feature/g hotfix master release/2 release/3 feature/d을 사용하다

! [feature/g] TEAM-12345: create X
 * [hotfix] TEAM-12345: create G
  ! [master] TEAM-12345: create E
   ! [release/2] TEAM-12345: create C
    ! [release/3] TEAM-12345: create C
     ! [feature/d] TEAM-12345: create S
------
+      [feature/g] TEAM-12345: create X
+      [feature/g^] TEAM-12345: create W
     + [feature/d] TEAM-12345: create S
     + [feature/d^] TEAM-12345: create R
     + [feature/d~2] TEAM-12345: create Q
        ...
  +    [master] TEAM-12345: create E
 *     [hotfix] TEAM-12345: create G
 *     [hotfix^] TEAM-12345: create F
 *+    [master^] TEAM-12345: create D
+*+++  [release/2] TEAM-12345: create C
+*++++ [feature/d~8] TEAM-12345: create B

몇 가지 포인트:

  • 명령줄에 N(6)개의 브랜치 이름을 나열한 원래 명령어
  • 이러한 브랜치명은 출력의 첫 번째 N 행으로 순서대로 표시됩니다.
  • 헤더 뒤의 행은 커밋을 나타냅니다.
  • 커밋 행의 첫 번째 N개의 열은 (전체적으로) "브런치/커밋 매트릭스"를 나타냅니다.여기서 컬럼에1개의 문자가 있습니다.X)의 관계를.X현재 커밋을 나타냅니다.

주요 절차

  1. 「」가 됩니다.BASE_BRANCH
  2. 가됩니다.BRANCHES에 포함되지 않습니다.BASE_BRANCH
  3. 말하면, 「 」로 해 .NBRANCH_COUNT , , , size size size size size size 의 크기입니다.BRANCHES ;은되지 않습니다;;는 포함되지 않습니다.BASE_BRANCH
  4. git show-branch --topo-order $BRANCHES $BASE_BRANCH다음과 같습니다.
    • ★★BRANCHES에는 하나의 이름(유효하다고 가정)만 포함되어 있습니다.이 이름은 출력의 헤더 행과 1-1로 매핑되며 브랜치/커밋 매트릭스의 첫 번째 N개의 열에 대응합니다.
    • ★★BASE_BRANCH 없다BRANCHES헤더 행의 마지막이 되어 마지막 컬럼브런치/커밋 매트릭스에 대응합니다.
  5. tail : : : 시 、 : 、 합 、 : 、 : 、N+3 번째를 N+2브랜치 + 브랜치 + 행 ": N" + " " " + " " " "---...
  6. sed: 이 : : : : : : : : : : : : : : : : : 。단, 명확성을 위해 분리되어 있습니다.명확성을 위해 분리되어 있습니다.
    • 분기/커밋 매트릭스 뒤에 있는 모든 항목 제거
    • 공백은 밑줄 '_'로 바꿉니다.주요 이유는 잠재적인 IFS 해석 해시를 피하고 디버깅/가독성을 위해서입니다.
    • *+; base branch (베이스 브랜치)그냥 한, 자, 자, 혼, 혼, 혼, 혼, also, also, also, also, also, 을 거칩니다.bash 확장, 확장, 패스네임 확장, 패스네임 확장, 패스네임 확장, 패스네임 확장, 패스네임 확장, 패스네임 확장, 패스네임 확장, , 확장, 패스네임 확장, 패스네임 확장*
  7. egrep: [^_]BASE_BRANCHBASE_BRANCH( )에[^_]$기본 분기 패턴은 다음과 같습니다.\+$
  8. head -n1첫 커밋을 합니다.
  9. sed: 분기/커밋 매트릭스의 각 문자를 행별로 구분합니다.
  10. 합니다.MAP2년 전하다
    • BRANCHES : 이길N
    • MAP : 이길N+1 : 첫 : :N('1-1')BRANCHES에 하는 BASE_BRANCH.
  11. BRANCHES더) (그것보다 짧습니다.)에서 해당 합니다.MAP : 출출BRANCH[$idx]MAP[$idx]+.

그래프와 결과의 예시

다음 다소 조작된 그래프에 대해 생각해 보겠습니다.

  • 편향된 이름이 사용될 것이다. 왜냐하면 그것들은 (내가) 결과를 평가하고 고려하는 데 도움이 되기 때문이다.
  • 병합이 존재하며 무시되고 있다고 가정합니다.
  • 를 강조 표시합니다.도 브런치입니다. 아이러니하게도master내가 이걸 다 하고 나면 눈에 띄지.
                         J                   <- feature/b
                        /
                       H
                      / \ 
                     /   I                   <- feature/a
                    /
                   D---E                     <- master
                  / \ 
                 /   F---G                   <- hotfix
                /
       A---B---C                             <- feature/f, release/2, release/3
            \   \ 
             \   W--X                        <- feature/g
              \ 
               \       M                     <- support/1
                \     /
                 K---L                       <- release/4
                      \ 
                       \       T---U---V     <- feature/e
                        \     /
                         N---O
                              \ 
                               P             <- feature/c
                                \ 
                                 Q---R---S   <- feature/d

치우치지 않은 결과 예제 그래프

안에 있다고 합니다.gitr , , , , , ㄹ 수 있다 ㄹ 수 있다.

gitr <baseBranch>

마다 B을 사용하다

소정의 B 공유 커밋 C 브런치! 브런치! 브런치 역사에 C가 있나요?
기능/a H 기능/b
기능/b H 기능/a
기능/c P 기능/d
기능/d P 기능/c
기능/e O feature/c, feature/d
기능/f C feature/a, feature/b, feature/g, 핫픽스, 마스터, 릴리스/2, 릴리스/3
기능/g C feature/a, feature/b, feature/f, 핫픽스, 마스터, 릴리스/2, 릴리스/3
핫픽스 D 기능/a, 기능/b, 마스터
마스터. D feature/a, feature/b, 핫픽스
릴리스/2 C feature/a, feature/b, feature/f, feature/g, 핫픽스, 마스터, 릴리즈/3
릴리스/3 C feature/a, feature/b, feature/f, feature/g, 핫픽스, 마스터, 릴리즈/2
릴리스 / 4 L feature/c, feature/d, feature/e, support/1
서포트/1 L feature/c, feature/d, feature/e, release/4

배치 브런치

[최종 스크립트에 가장 적합하기 때문에 이 단계에서 제시]이 섹션은 필수가 아닙니다.앞으로 건너뛰어도 됩니다.]

git show-branch29일그것은 아마 어떤 사람들에게는 방해가 될 것이다(판단 없이, 그냥 말해!)

브랜치를 배치로 그룹화함으로써 결과를 개선할 수 있습니다.

  • BASE_BRANCH는 각 브랜치와 함께 제출해야 합니다.
  • repo에 브랜치 수가 많은 경우 그 자체로 제한된 값을 가질 수 있습니다.
  • 브런치를 제한할 다른 방법을 찾으면 더 많은 가치를 제공할 수 있습니다(배치됩니다).
  • 이전 포인트는 내 사용 사례에 적합하므로 미리 충전하십시오!

이 메커니즘은 완벽하지 않습니다.결과 사이즈가 최대(29)에 가까워지면 장애가 발생할 것으로 예상합니다.상세내용:

배치 솔루션

#
# Remove/comment-out the function call at the end of script,
# and append this to the end.
##

##
# Given:
#   BASE_BRANCH : $1           : first param on every batch
#   BRANCHES    : [ $2 .. $N ] : list of unique branch names (no duplicates);
#                                perhaps possible parents
#                                Default is all branches except base branch.
#
# Output all BRANCHES that share that commit in their commit history.
#
function repeatBatchingUntilStableResults() {
    local BASE_BRANCH="$1"

    shift
    local -a CANDIDATES
    if [[ -z "${1+x}" ]]; then
        CANDIDATES=( $(git rev-parse --symbolic --branches) )
    else
        CANDIDATES=("$@")
    fi
    local BRANCHES=( $(valuesExcept "$BASE_BRANCH" "${CANDIDATES[@]}") )

    local SIZE=$GIT_SHOW_BRANCH_MAX
    local COUNT=${#BRANCHES[@]}
    local LAST_COUNT=$(( $COUNT + 1 ))

    local NOT_DONE=1
    while (( $NOT_DONE && $COUNT < $LAST_COUNT )); do
        NOT_DONE=$(( $SIZE < $COUNT ))
        LAST_COUNT=$COUNT

        local -a BRANCHES_TO_BATCH=( "${BRANCHES[@]}" )
        local -a AGGREGATE=()
        while (( ${#BRANCHES_TO_BATCH[@]} > 0 )); do
            local -a BATCH=( "${BRANCHES_TO_BATCH[@]:0:$SIZE}" )
            AGGREGATE+=( $(nearestCommonBranches "$BASE_BRANCH" "${BATCH[@]}") )
            BRANCHES_TO_BATCH=( "${BRANCHES_TO_BATCH[@]:$SIZE}" )
        done
        BRANCHES=( "${AGGREGATE[@]}" )
        COUNT=${#BRANCHES[@]}
    done
    if (( ${#BRANCHES[@]} > $SIZE )); then
        echo "Unable to reduce candidate branches below MAX for git-show-branch" >&2
        echo "  Base Branch : $BASE_BRANCH" >&2
        echo "  MAX Branches: $SIZE" >&2
        echo "  Candidates  : ${BRANCHES[@]}" >&2
        exit 1
    fi
    echo "${BRANCHES[@]}"
}

repeatBatchingUntilStableResults "$@"
exit 0

구조

결과가 안정될 때까지 반복합니다.

  1. 를 꺾다.BRANCHES 묶음으로GIT_SHOW_BRANCH_MAX 명kaka (SIZE) 소 ★
  2. nearestCommonBranches BASE_BRANCH BATCH
  3. 새로운 (더 작은?)브런치 세트로 결과 집약

실패하는 방법

SIZE추가 배치/처리는 이 수치를 줄일 수 없습니다.

  • 이지만, 통합 is is is is, is is is is the the the the the the the the the the the the the the the the the the the the the the the the 로 확인할 수 없습니다git show-branch 「」
  • 각 배지는 감소하지 않습니다.한 배치로부터의 브랜치가 다른 배치(diff merge base)를 줄이는 데 도움이 될 수 있습니다.현재 algo는 패배와 실패를 인정하고 있습니다.

대체 방안 검토

베이스 브랜치를 다른 모든 대상 브랜치와 개별적으로 페어링하여 각 쌍의 커밋노드(머지 베이스)를 결정합니다.커밋 이력 순서로 Marge 베이스 세트를 정렬하고 가장 가까운 노드를 선택하여 해당 노드에 관련된 모든 브랜치를 결정합니다.

나는 그것을 나중에 생각해 본 입장에서 제시한다.그게 정말 옳은 길일 거예요.저는 앞으로 나아가고 있습니다.아마도 이 주제에서 벗어난 가치가 있을 것입니다.

편향된 질문

, 핵심기능이 있다라는 .nearestCommonBranches이전 스크립트에서는 Q1의 질문보다 더 많은 답변이 있었습니다.실제로 이 함수는 보다 일반적인 질문에 답합니다.

문제 2

된 브랜치 「」B 순서부 없음)는, 「」(복제 없음)입니다.PB 없다P합니다.): "commit"C 곳에B'HEAD )C"" " " " " " " " " " 가 될 수 .B'HEAD는 )입니다P P의 순서별로 커밋 이력에 C가 있는 브랜치는 무엇입니까?

[ ] 를 합니다.P는 편견을 제공하거나 (제한된) 표기법을 설명합니다.편견/관습의 모든 특성을 일치시키려면 추가 도구가 필요할 수 있으며, 이 설명에서는 범위를 벗어납니다.

단순 바이어스/관례 모델링

편견은 조직이나 프랙티스에 따라 다르며, 다음 사항은 고객님의 조직에 적합하지 않을 수 있습니다.다른 것은 없습니다만, 여기 있는 아이디어 중 몇 가지는 요구에 대한 해결책을 찾는 데 도움이 될 수 있습니다.

편향된 솔루션; 지점 이름 지정 규칙에 의한 편향

아마도 편향은 사용 중인 명명 규칙에 매핑되고 추출될 수 있습니다.

이이에 의한 P ('기타 지점명)

다음 단계에서는 이것이 필요하므로 regex로 지점 이름을 필터링하여 무엇을 할 수 있는지 알아보겠습니다.

이전 코드와 아래의 새로운 코드를 조합하여 gitr을 사용할 수 있습니다.

#
# Remove/comment-out the function call at the end of script,
# and append this to the end.
##

##
# Given Params:
#   BASE_BRANCH : $1           : base branch
#   REGEXs      : $2 [ .. $N ] : regex(s)
#
# Output:
#   - git branches matching at least one of the regex params
#   - base branch is excluded from result
#   - order: branches matching the Nth regex will appear before
#            branches matching the (N+1)th regex.
#   - no duplicates in output
#
function expandUniqGitBranches() {
    local -A BSET[$1]=1
    shift

    local ALL_BRANCHES=$(git rev-parse --symbolic --branches)
    for regex in "$@"; do
        for branch in $ALL_BRANCHES; do
            ## RE: -z ${BSET[$branch]+x ...  ; presumes ENV 'x' is not defined
            if [[ $branch =~ $regex && -z "${BSET[$branch]+x}" ]]; then
                echo "$branch"
                BSET[$branch]=1
            fi
        done
    done
}


##
# Params:
#   BASE_BRANCH: $1    : "." equates to the current branch;
#   REGEXS     : $2..N : regex(es) corresponding to other to include
#
function findBranchesSharingFirstCommonCommit() {
    if [[ -z "$1" ]]; then
        echo "Usage: findBranchesSharingFirstCommonCommit ( . | baseBranch ) [ regex [ ... ] ]" >&2
        exit 1
    fi

    local BASE_BRANCH
    if [[ -z "${1+x}" || "$1" == '.' ]]; then
        BASE_BRANCH="$CURRENT_BRANCH"
    else
        BASE_BRANCH="$1"
    fi

    shift
    local REGEXS
    if [[ -z "$1" ]]; then
        REGEXS=(".*")
    else
        REGEXS=("$@")
    fi

    local BRANCHES=( $(expandUniqGitBranches "$BASE_BRANCH" "${REGEXS[@]}") )

## nearestCommonBranches  can also be used here, if batching not used.
    repeatBatchingUntilStableResults "$BASE_BRANCH" "${BRANCHES[@]}"
}

findBranchesSharingFirstCommonCommit "$@"

예제 그래프에 대한 치우친 결과

순서 세트를 생각해 봅시다.

P = { ^release/.*$ ^support/.*$ ^master$ }

부분가 실행 안에 있다고 합니다.gitr , , , , , ㄹ 수 있다 ㄹ 수 있다.

gitr <baseBranch> '^release/.*$' '^support/.*$' '^master$'

마다 B을 사용하다

소정의 B 공유 커밋 C 브런치 P와 C의 이력(순서대로)
기능/a D 마스터.
기능/b D 마스터.
기능/c L 릴리스/4, 지원/1
기능/d L 릴리스/4, 지원/1
기능/e L 릴리스/4, 지원/1
기능/f C release/2, release/3, 마스터
기능/g C release/2, release/3, 마스터
핫픽스 D 마스터.
마스터. C 릴리스/2, 릴리스/3
릴리스/2 C 릴리스/3, 마스터
릴리스/3 C 릴리스/2, 마스터
릴리스 / 4 L 서포트/1
서포트/1 L 릴리스 / 4

최종적인 답변에 가까워지고 있습니다.릴리스 브랜치에 대한 대응은 이상적이지 않습니다.한 걸음 더 나아가자.

이이에 의한 BASE_NAME ★★★★★★★★★★★★★★★★★」P

중 는 다른 것을 입니다.P하다그것을 위한 디자인을 만들어 봅시다.

관습

면책사항: git flow purist가 아닙니다. 양해 부탁드립니다.

  • 서포트 브랜치는 마스터를 분기해야 한다.
    • 공통의 커밋을 공유하는 2개의 지원 브랜치는 존재하지 않습니다.
  • 핫픽스 브랜치는 서포트 브랜치 또는 마스터를 분기합니다.
  • 릴리스 브랜치는 서포트 브랜치 또는 마스터를 분기해야 합니다.
    • 하나의 공통 커밋을 공유하는 여러 릴리스 브랜치가 있을 수 있습니다.즉, 동시에 마스터에서 분기하는 것입니다.
  • Bugfix 브랜치는 릴리스 브랜치를 분기해야 합니다.
  • 기능 브랜치는 기능, 릴리스, 지원 또는 마스터를 분기할 수 있습니다.
    • 「부모」의 목적상, 기능 브랜치는 다른 것에 대해서 부모로서 확립할 수 없습니다(초기 설명 참조).
    • 따라서 기능 브랜치를 건너뛰고 릴리스, 지원, 마스터 브랜치 중 하나 또는 둘 다에서 "부모"를 찾습니다.
  • 기능 브랜치와 같은 규약을 가진 동작 브랜치로 간주되는 기타 브랜치명.

까지 가는지 git뭇매를 맞다

기본 분기 패턴 상위 브랜치, 주문 완료 코멘트
^master$ 없음 부모 없음
^지원/*$ ^master$
^핫픽스/*$ ^지원/*$^master$ 마스터보다 서포트 브랜치를 우선하다(스탠다드라이버전보다 우선시하다
^release /*$ ^지원/*$^master$ 마스터보다 서포트 브랜치를 우선하다(스탠다드라이버전보다 우선시하다
^bugfix /*$ ^release /*$
^closs/ ^closs/*$ ^release /*$^지원/*$^master$
^.*$ ^release /*$^지원/*$^master$ 용장성이지만 설계상의 문제를 분리할 수 있습니다.

대본

이전 코드와 아래의 새로운 코드를 조합하여 gitp를 사용할 수 있습니다.

#
# Remove/comment-out the function call at the end of script,
# and append this to the end.
##

# bash associative arrays maintain key/entry order.
# So, use two maps, values correlated by index:
declare -a MAP_BASE_BRANCH_REGEX=( "^master$" \
                                       "^support/.*$" \
                                       "^hotfix/.*$" \
                                       "^release/.*$" \
                                       "^bugfix/.*$" \
                                       "^feature/.*$" \
                                       "^.*$" )

declare -a MAP_BRANCHES_REGEXS=("" \
                                    "^master$" \
                                    "^support/.*$ ^master$" \
                                    "^support/.*$ ^master$" \
                                    "^release/.*$" \
                                    "^release/.*$ ^support/.*$ ^master$" \
                                    "^release/.*$ ^support/.*$ ^master$" )

function findBranchesByBaseBranch() {
    local BASE_BRANCH
    if [[ -z "${1+x}" || "$1" == '.' ]]; then
        BASE_BRANCH="$CURRENT_BRANCH"
    else
        BASE_BRANCH="$1"
    fi

    for idx in "${!MAP_BASE_BRANCH_REGEX[@]}"; do
        local BASE_BRANCH_REGEX=${MAP_BASE_BRANCH_REGEX[$idx]}
        if [[ "$BASE_BRANCH" =~ $BASE_BRANCH_REGEX ]]; then
            local BRANCHES_REGEXS=( ${MAP_BRANCHES_REGEXS[$idx]} )
            if (( ${#BRANCHES_REGEXS[@]} > 0 )); then
                findBranchesSharingFirstCommonCommit $BASE_BRANCH "${BRANCHES_REGEXS[@]}"
            fi
            break
        fi
    done
}

findBranchesByBaseBranch "$1"
예제 그래프에 대한 치우친 결과

부분가 실행 안에 있다고 합니다.gitr , , , , , ㄹ 수 있다 ㄹ 수 있다.

gitr <baseBranch>

마다 B을 사용하다

소정의 B 공유 커밋 C 브런치 P와 C의 이력(순서대로)
기능/a D 마스터.
기능/b D 마스터.
기능/c L 릴리스/4, 지원/1
기능/d L 릴리스/4, 지원/1
기능/e L 릴리스/4, 지원/1
기능/f C release/2, release/3, 마스터
기능/g C release/2, release/3, 마스터
핫픽스 D 마스터.
마스터. (공백, 값 없음)
릴리스/2 C 마스터.
릴리스/3 C 마스터.
릴리스 / 4 L 서포트/1
서포트/1 L 마스터.
리팩터 더 윈!

기회!

이 마지막 예에서는 릴리스 브랜치가 릴리스 브랜치, 지원 브랜치 또는 마스터 브랜치와 공통 커밋을 공유합니다.

사용 중인 규약을 "리팩터" 또는 재평가하고 좀 더 엄격히 합시다.

점을 고려하다git용용: :

새로운 릴리스 브랜치를 작성하는 경우: 즉시 새로운 커밋을 작성합니다.버전 또는 README 파일을 갱신할 수 있습니다.이것에 의해, 릴리스의 기능/워크 브랜치(릴리스로부터 분기)는, 기반이 되는 서포트 또는 마스터 브랜치의 커밋보다 릴리스 브랜치와의 커밋을 공유(공유하지 않음)하게 됩니다.

예를 들어 다음과 같습니다.

        G---H   <- feature/z
       /
      E         <- release/1
     /
A---B---C---D   <- master
     \
      F         <- release/2

릴리스/1에서 분기된 기능은 릴리스/1(부모) 및 마스터 또는 릴리스/2를 포함하는 공통 커밋을 가질 수 없습니다.

그 결과 각 브랜치마다 부모라는 하나의 결과를 얻을 수 있습니다.이러한 표기법이 있습니다.

DONE! 툴과 컨벤션으로 OCD 친화적인 구조 git 세계에서 살 수 있습니다.

마일리지가 다를 수 있습니다!

이별의 생각

  1. 동작
  1. 우선:결론에 도달했습니다.여기서 설명한 것 외에, 어느 시점에서는, 복수의 지점이 취급하고 있는 것을 받아들일 필요가 있습니다.

    • 검증은 "최소한 1개" 또는 "모두" 또는 ?의 모든 브런치에서 실행할 수 있습니다.규칙이 적용될 수 있습니다.
  2. Python을 배워야 할 때가 된 것 같은 몇 주일이면 Python을 배울 때가 된 것 같아요.

해결 방법

기반으로 한 솔루션이 제대로 작동하지 않았기 때문에(아래 참조), 을 기반으로 한 솔루션과 결합하여 다음과 같은 결과를 얻었습니다.

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
  • 에서 스크립트 실행 및 결과(실행)<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

존재해도(를 들어, 「」만)origin/topic OSHA에 되었습니다).는 다음과됩니다.스크립트는 다음과 같이 출력됩니다.

  • commits , (브런치)의 경우hotfix) →
  • commits , (브런치)의 경우feature/a) →
  • commits , (브런치)의 경우feature/c) →
  • commits , (브런치)의 경우feature/b) →
  • 의 경우J,K,L (비밀(이행)develop→ ) →<sha> Initial commit*
  • 의 경우B,D,E,F (비밀(이행)master→ ) →<sha> Initial commit

- * - 는 *masterdevelop의 HEAD 할 수 ).


왜 쇼브런치가 통하지 않았지?

기반으로 한 솔루션은 다음과 같은 상황에서 신뢰할 수 없는 것으로 판명되었습니다.

  • 분리 헤드 – 분리 헤드 케이스를 포함하여 교체grep '\*' \ 뿐!'에 대해서는, 「의 시작일 입니다.'라고 .
  • 에서 스크립트를 실행하여develop'과 '각각'은 '각각'
  • 브런치(hotfix/는 「Branches」, 「Branches」, 「Branches」로.develop 가까운 지내다master에게는 「지부 부모」라고 하는 있었습니다.!*이유가 있어서.

하지 않았기 에, 「Mattern Mattern Martes」를 하고, 해 나가고 싶다고 생각하고 .git log:

#!/bin/bash

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

에 넣어주세요.git-last-merges의 브랜치.git log★★★★★★★★★★★★★★★★★★.

출력으로부터, 독자적인 브랜치 규칙과 각 브랜치로부터의 Marge의 수에 근거해, 부모 브랜치를 수동으로 검출할 수 있습니다.

「 」를 사용하고 git rebase하위 브랜치에서는 종종 (그리고 Marge는 너무 많은 Marge 커밋이 없기 때문에) 이 답변은 잘 작동하지 않습니다.따라서 저는 현재 브랜치보다 모든 브랜치에서 미리 커밋(일반 및 Marge)과 behind commit(부모 브랜치에서는 marge 뒤에 marge가 없어야 함)을 카운트하는 스크립트를 작성했습니다.

#!/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
git log - 2 --pretty= format : '%d' --timev-commit | tail -n 1 | sed 's/\s(/g; s///\n/g)';

(parent/parent-name, parent-name)

git log - 2 --pretty= format : '%d' --timev-commit | tail -n 1 | sed 's/\s(/g; s///\n/g)';

발신기지/부모명

git log - 2 -- pretty = format : '%d' --tailv-commit | tail - n 1 | sed 's/(./g; s/)/';

부모 이름

「Git: 커밋의 발신원 브랜치 검색에 기재되어 있듯이, 커밋이 행해진 브랜치를 간단하게 특정할 수 없습니다(브런치 이름을 변경, 이동, 삭제할 수 있습니다).git branch --contains <commit>작입니니다다

  • 수 .git branch --contains <commit>가 되어 있지 않다feature list " " " 。develop 링크,
  • 을 「SHA1」과 비교하다/refs/heads/develop

일치하는 즉, 2개의 커밋 ID, 2개의 커밋 ID, 2개의 커밋 ID, 2개의 커밋 ID가 일치하면,feature(branch)는(HEAD of branch치는 branch branch)에서 합니다.develop를 참조해 주세요.

이것이 이 문제를 해결하는 좋은 방법이라고는 할 수 없지만, 저는 이 방법이 효과가 있는 것 같습니다.

git branch --contains $(cat .git/ORIG_HEAD)

문제는 파일을 캐팅하는 것이 Git의 내부 작업을 훔쳐보는 것이기 때문에 반드시 정방향 호환(또는 역방향 호환)은 아니라는 것입니다.

크라이슬러의 명령줄 마법은 단순화할 수 있습니다.Joe의 논리는 다음과 같습니다.간단히 하기 위해 다음과 같은 파라미터를 도입했습니다.cur_branch substitution(치환) `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

모두 비교적 5개의 명령어필터 를 할 수 .awk★★★★★★★★★★★★★★★★★★:

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

그것은 다음과 같이 분류된다.

-F'[]^~[]'

],^,~ , , , , 입니다.[★★★★★★ 。

/\*/

별표 포함 행 찾기

&& !/'"$cur_branch"'/

...하지만 현재 브랜치 이름은 아닙니다.

{ print $2;

이러한 행이 발견되면 두 번째 필드(즉, 첫 번째 필드 구분 문자와 두 번째 필드 구분 문자 사이의 부분)를 인쇄합니다.단순한 지점 이름의 경우 대괄호 사이에 있는 이름만 해당되며, 상대 점프가 있는 참조의 경우 수정자가 없는 이름만 해당됩니다. 이 는 두 필드 구분자 의 의도를 .sed명령어를 지정합니다.

  exit }

그럼 즉시 종료합니다., 첫 을 파이프로 head -n 1.

다음은 Mark Reed 솔루션의 PowerShell 구현입니다.

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

용도:

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. 에 "Marge"가 표시됩니다.- 아니라, 이에요.*
  2. 커밋 메시지에 지점 이름이 포함되어 있습니다.
  3. 에 " " " 가 포함되어 .*

PowerShell 버전은 다음과 같습니다.

function Get-GHAParentBranch {
    [CmdletBinding()]
    param(
        $Name = (git branch --show-current)
    )
    git show-branch |
      Select-String '^[^\[]*\*' |
      Select-String -NotMatch -Pattern "\[$([Regex]::Escape($Name)).*?\]" |
      Select-Object -First 1 |
      Foreach-Object {$PSItem -replace '^.+?\[(.+)\].+$','$1'}
}

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`

반구조화 텍스트 출력 구문 분석과 관련된 안전하지 않은 가정이 마음에 들지 않았기 때문에 다음과 같은 가정이 적은 보다 강력한 솔루션을 원했습니다.

# Search backwards in history for the first commit that is in a branch other than $1
# and output that branch's name.
parent_branch() {
    local result rev child_branch=$1
    rev=$(git rev-parse --revs-only $child_branch)
    while [[ -n $rev ]]; do
        result=$(git branch --contains $rev | grep -v " $child_branch$")
        if [[ -n $result ]]; then
            echo $result
            return 0
        fi
        rev=$(git rev-parse --revs-only $rev^)
    done
    return 1
}

에, 「」와는 을 찾기 위한 각 합니다.「 」$1지점이 길어질수록 비용이 더 많이 듭니다.하지만 어차피 지점은 수명이 비교적 짧기 때문에 큰 문제는 없을 것입니다.

저는 지금 ,, 용, 용, 용, 의, 의, 의, alsogit branch --contains따라서 공통 기반을 공유하지만 이미 그 이상으로 발전한 브랜치도 찾을 수 있습니다.베이스를 , 「」를 합니다.git branch --points-at.

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}" />

Git에는 이를 시각화하는 데 도움이 되는 몇 가지 GUI 클라이언트가 포함되어 있습니다.GitGUI를 열고 Repository → Visualize All Branch History 메뉴로 이동합니다.

「 」에:git show-branch -a또한 일부 필터에는 다음과 같은 단점이 있습니다.Git git git git은 git git git git git git git git git git git 。

만약 당신이 관심을 가지고 있는 몇 명의 부모가 있다면, 당신은 다음과 같은 비슷한 질문을 스스로에게 할 수 있습니다(그리고 아마도 OP가 알고 싶어했던 질문일 것입니다).

모든 브랜치의 특정 서브셋에서 git 브랜치의 가장 가까운 부모는 무엇입니까?

말하면, 「 branch라고 하는 것은, 「git branch」라고입니다.HEAD(예: 재 ( 、 ( ( ( ( ( ().

다음과 같은 브런치가 있다고 가정합니다.

HEAD
important/a
important/b
spam/a
spam/b

「 」에:git show-branch -a는 + 의 가장 에게 + 의 필터를 할 수 .HEADspam/a하지만 그런 건 신경 안 써요

인지 important/a ★★★★★★★★★★★★★★★★★」important/b입니다.HEAD, 하다, 하다, 를 실행할 수 .

for b in $(git branch -a -l "important/*" | sed -E -e "s/\*//"); do
    d1=$(git rev-list --first-parent ^${b} HEAD | wc -l);
    d2=$(git rev-list --first-parent ^HEAD ${b} | wc -l);
    echo "${b} ${d1} ${d2}";
done \
| sort -n -k2 -k3 \
| head -n1 \
| awk '{print $1}';

기능:

) 1) 1) 1)$(git branch -a -l "important/*" | sed -E -e "s/\*//"): 모든 브랜치 리스트를 패턴으로 인쇄합니다("important/*")important/* '브런치',git branch에는 현재의 브랜치를 나타내는* 가 포함됩니다. 치환 " " "$()그러면 현재 디렉토리의 콘텐츠로 확장됩니다.sed합니다.*git branch

) 2) 2)d=$(git rev-list --first-parent ^${b} HEAD | wc -l);각( : 각브 ( ( )$b )를$d1의 커밋 수, 은, 「」( 「」)입니다.HEAD에서 가장 합니다.$b(점에서 선까지의 거리를 계산할 때와 유사합니다).거리를 다르게 . 즉, 거리를 사용하지 않는 도 모릅니다.--first-parent를 원하는 "${b}"...HEAD ), ...

2.2)d2=$(git rev-list --first-parent ^HEAD ${b} | wc -l);각( : 각브 ( ( )$b )를$d2 가까운 HEAD이 거리를 사용하여 두 가지 분기 중 하나를 선택합니다.$d1았습니니다다

) 3.echo "${b} ${d1} ${d2}";: 각 지점의 이름을 인쇄한 후 나중에 정렬할 수 있는 거리를 인쇄합니다(먼저).$d1 , , 을 누릅니다.$d2를 참조해 주세요.

4.| sort -n -k2 -k3: 의 : : : : : : : : : : 。그러면 모든 브랜치의 정렬된 (거리별) 리스트와 그 후의 거리(둘 다)가 표시됩니다.

5.| head -n1: 첫는 거리가 더 지점이 이전 단계의 첫 번째 결과는 거리가 더 작은 지점, 즉 가장 가까운 부모 지점이 됩니다.그러니 다른 모든 가지를 버리세요.

6.| awk '{print $1}'; 쓰지 첫 필드인 지점 이름만 신경쓰고 거리는 신경 쓰지 않으므로 첫 번째 필드인 부모 이름을 추출합니다.있다 :) 기기!!! here!!! :)

여러 브랜치에서 첫 번째 커밋을 찾는 셸 함수:

# Get the first commit hash of a given branch.
# Uses `git branch --contains` to backward (starts from HEAD) check each commits
# and output that branch's name.
first_commit_of_branch() {
    if [ $# -ne 1 ] || [ -z "${1}" ] ; then
        (>&2 echo "Error: Missing or empty branch name.")
        (>&2 echo "Usage: $0 branch_to_test")
        return 2
    fi
    local branch_to_test="${1}"; shift
    local commit_index_to_test
    local maximum_number_of_commit_to_test
    local branch_count_having_tested_commit

    git rev-parse --verify --quiet "${branch_to_test}" 2>&1 > /dev/null || {
        (>&2 echo "Error: Branch \"${branch_to_test}\" does not exists.")
        return 2
    }

    commit_index_to_test=0
    maximum_number_of_commit_to_test=$(git rev-list --count "${branch_to_test}")

    while [ ${commit_index_to_test} -le ${maximum_number_of_commit_to_test} ] ; do
        # Testing commit $branch_to_test~$commit_index_to_test…

        # If it fails, it means we tested all commits from the most recent of
        # branch $branch_to_test to the very first of the git DAG. So it must be it.
        git rev-parse --verify --quiet ${branch_to_test}~${commit_index_to_test} 2>&1 > /dev/null || {
            git rev-list --max-parents=0 "${branch_to_test}"
            return 0
        }

        branch_count_having_tested_commit="$( \
            git --no-pager branch --no-abbrev --verbose \
                --contains ${branch_to_test}~${commit_index_to_test} \
            | cut -c 3- \
            | cut -d ' ' -f 2 \
            | wc -l \
        )"

        # Tested commit found in more than one branch
        if [ ${branch_count_having_tested_commit} -gt 1 ] ; then
            if [ ${commit_index_to_test} -eq 0 ]; then
                (>&2 echo "Error: The most recent commit of branch \"${branch_to_test}\" (${branch_to_test}~${commit_index_to_test}) is already in more than one branch. This is likely a new branch without any commit (yet). Cannot continue.")
                return 1
            else
                # Commit $branch_to_test~$commit_index_to_test is in more than
                # one branch, stopping there…
                git rev-parse ${branch_to_test}~$((commit_index_to_test-1))
                return 0
            fi
        fi
        # else: Commit $branch_to_test~$commit_index_to_test is still only in
        #       branch ${branch_to_test} continuing…"
        commit_index_to_test=$((commit_index_to_test+1))
    done
}

주의: 서브브런치가 있는 브랜치에서 실행해도 새로운 커밋이 없는 경우 실패합니다.

A---B---C---D      <- "main" branch
 \   \
  \   E---F        <- "work1" branch
   \       \
    \       G---H  <- "work1-b" branch
     \
      I---J        <- "work2" branch
first_commit_of_branch main # C
first_commit_of_branch work1 # (Fails)
first_commit_of_branch work1-b # G
first_commit_of_branch work2 # I

Atlassian의 Sourcetree 어플리케이션에서는 각 브랜치가 어떻게 서로 관련되어 있는지, 즉 어디에서 시작되었는지, 현재 커밋 순서(HEAD 또는 4개의 커밋 등)를 시각적으로 잘 나타내고 있습니다.

Sourcetree를 사용하는 경우 커밋 세부 정보 → Parents를 확인하십시오.그러면 밑줄 친 커밋 번호(링크)가 표시됩니다.

release-v1.0.0feature-foo와 같은 작업을 수행했을 때는 이 작업이 작동하지 않았습니다.개발까지 거슬러 올라갈 수 있습니다.베이스 변경에 관여하고 있는 것에 주의해 주세요.그것이 제 문제를 복잡하게 하고 있는지는 잘 모르겠습니다.

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

git log --decorate \
  | grep 'commit' \
  | grep 'origin/' \
  | head -n 2 \
  | tail -n 1 \
  | awk '{ print $2 }' \
  | tr -d "\n"

이 경우 "feature" 브랜치의 "parent"는 분기이며, "feature" 브랜치의 풀 요청에서 "base"로 명시적으로 표시했습니다.GitHub CLI를 사용하여 검색할 수 있습니다.

gh pr list --head "feature" --json baseRefName --jq '.[].baseRefName'

이전 답변이 도움이 되었습니다.https://stackoverflow.com/a/37159240/1009693 단,git show-branch에서는 찾고 있는 상위 브랜치가 로컬저장소에 이미 복제되어 있다고 가정합니다.게아 ??

로컬 저장소에서 하나의 분기가 복제되어 그 부모를 찾고 싶다고 가정합니다.대부분 리모트분기가 있는 경우 리모트분기가 될 수 있습니다.여기가 바로 그 장소입니다git show-branch --remotes도움이 됩니다.다만, 다른 출력을 처리할 필요가 있습니다.'*' 문자는 사용할 수 없습니다. 이름도, 해요?만약 리모트 이름이 추출되지 않으면 어떻게 해야 합니까?origin

그 모든 것을 이하에 나타냅니다.


vbc=$(git rev-parse --abbrev-ref @{u})
remote=$(echo $vbc | sed 's|\(.*\)/.*|\1|')
vbc_col=$(( $(git show-branch --remotes | grep '^\s*\!' | wc -l) )) 
swimming_lane_start_row=$(( $(git show-branch --remotes | grep -n "\s\[$vbc" | tail -1 | cut -d: -f1) + 1 )) 
git show-branch --remotes | tail -n +$swimming_lane_start_row | head -n1 | sed 's/.*\[\(.*\)\].*/\1/' | sed 's/[\^~].*//' | sed -e "s|$remote/||"

다른 방법:

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

마지막 커밋은 제 브랜치이며,master( ( ( ( ( ( ( ( ( ( ( 。

언급URL : https://stackoverflow.com/questions/3161204/how-to-find-the-nearest-parent-of-a-git-branch

반응형