source

bash 스크립트를 사용하여 모든 git 브랜치를 반복하는 방법

gigabyte 2023. 4. 14. 21:46
반응형

bash 스크립트를 사용하여 모든 git 브랜치를 반복하는 방법

bash 스크립트를 사용하여 저장소 내의 모든 로컬 브랜치를 반복하려면 어떻게 해야 합니까?지점과 원격지점에 차이가 있는지 다시 한 번 확인해 봐야 합니다.

for branch in $(git branch); 
do
    git log --oneline $branch ^remotes/origin/master;
done

위와 같은 작업을 수행해야 하는데, 현재 직면한 문제는 $(git branch)가 저장소에 있는 분기와 함께 저장소 폴더 내의 폴더를 제공한다는 것입니다.

이것이 이 문제를 해결하는 올바른 방법입니까?아니면 다른 방법이 있을까요?

감사해요.

스크립트를 작성할 때 git branch를 사용하면 안 됩니다.Git은 스크립팅에 사용하도록 명시적으로 설계된 "플럼핑" 인터페이스를 제공합니다(일반 Git 명령어(추가, 체크아웃, 병합 등)의 현재 및 과거 구현된 많은 것들이 이 동일한 인터페이스를 사용합니다).

필요한 배관 명령어는 git for each-ref 입니다.

git for-each-ref --shell \
  --format='git log --oneline %(refname) ^origin/master' \
  refs/heads/

의: 다음음음음음 note note note note note note note note note note 는 필요 없습니다.remotes/(다른 한에 프레픽스).origin/master참조 이름 검색 경로에서 여러 위치를 일치시키려면 "심볼릭 참조 이름"을 참조하십시오...."는 git-rev-parse(1)의 "수정사항 지정" 섹션에 있습니다.애매함을 명확하게 회피하려면 , 완전한 참조명을 사용합니다.refs/remotes/origin/master

다음과 같은 출력이 표시됩니다.

git log --oneline 'refs/heads/master' ^origin/master
git log --oneline 'refs/heads/other' ^origin/master
git log --oneline 'refs/heads/pu' ^origin/master

이 출력을 sh로 파이핑할 수 있습니다.

셸 코드를 생성하는 것이 마음에 들지 않는 경우는, 조금의* 견고성을 포기하고, 다음과 같이 할 수 있습니다.

for branch in $(git for-each-ref --format='%(refname)' refs/heads/); do
    git log --oneline "$branch" ^origin/master
done

* 참조명은 셸의 단어 분할로부터 안전해야 합니다(git-check-ref-format(1) 참조).개인적으로 나는 이전 버전(생성된 셸 코드)을 고수하고 싶다.나는 그것으로는 부적절한 일이 일어날 수 없다는 것을 더 확신한다.

bash를 지정하고 어레이를 지원하므로 안전을 유지하면서 루프의 내장이 생성되지 않도록 할 수 있습니다.

branches=()
eval "$(git for-each-ref --shell --format='branches+=(%(refname))' refs/heads/)"
for branch in "${branches[@]}"; do
    # …
done

해서 이렇게 할 도 있어요.$@하지 않는 (어레이를 지원하지 않는 경우).set --set -- "$@" %(refname)요소를 추가합니다).

그 이유는git branch는 현재 브랜치에 아스타리스크 마크를 붙입니다.하다

$ git branch
* master
  mybranch
$ 

$(git branch)장됩니니다다* master mybranch그에 , 이에요.*현재 디렉토리의 파일 목록으로 확장됩니다.

애초에 아스타리스크를 인쇄하지 않는 방법은 잘 모르겠습니다만, 잘라내도 괜찮습니다.

$(git branch | cut -c 3-)

빌트인 " " " "mapfile되어 있습니다.

브랜치: "git git" :git branch --all --format='%(refname:short)'

브랜치: "GIT 브랜치: " "GIT 브랜치"git branch --format='%(refname:short)'

브런치: branches든 all GIT 브 branches :git branch --remotes --format='%(refname:short)'

브랜치를 합니다.mapfile -t -C my_callback -c 1 < <( get_branches )

예:

my_callback () {
  INDEX=${1}
  BRANCH=${2}
  echo "${INDEX} ${BRANCH}"
}
get_branches () {
  git branch --all --format='%(refname:short)'
}
# mapfile -t -C my_callback -c 1 BRANCHES < <( get_branches ) # if you want the branches that were sent to mapfile in a new array as well
# echo "${BRANCHES[@]}"
mapfile -t -C my_callback -c 1 < <( get_branches )

OP의 특정 상황:

#!/usr/bin/env bash


_map () {
  ARRAY=${1?}
  CALLBACK=${2?}
  mapfile -t -C "${CALLBACK}" -c 1 <<< "${ARRAY[@]}"
}


get_history_differences () {
  REF1=${1?}
  REF2=${2?}
  shift
  shift
  git log --oneline "${REF1}" ^"${REF2}" "${@}"
}


has_different_history () {
  REF1=${1?}
  REF2=${2?}
  HIST_DIFF=$( get_history_differences "${REF1}" "${REF2}" )
  return $( test -n "${HIST_DIFF}" )
}


print_different_branches () {
  read -r -a ARGS <<< "${@}"
  LOCAL=${ARGS[-1]?}
  for REMOTE in "${SOME_REMOTE_BRANCHES[@]}"; do
    if has_different_history "${LOCAL}" "${REMOTE}"; then
      # { echo; echo; get_history_differences "${LOCAL}" "${REMOTE}" --color=always; } # show differences
      echo local branch "${LOCAL}" is different than remote branch "${REMOTE}";
    fi
  done
}


get_local_branches () {
  git branch --format='%(refname:short)'
}


get_different_branches () {
  _map "$( get_local_branches )" print_different_branches
}


# read -r -a SOME_REMOTE_BRANCHES <<< "${@}" # use this instead for command line input
declare -a SOME_REMOTE_BRANCHES
SOME_REMOTE_BRANCHES=( origin/master remotes/origin/another-branch another-remote/another-interesting-branch )
DIFFERENT_BRANCHES=$( get_different_branches )

echo "${DIFFERENT_BRANCHES}"

출처: 별표 없이 모든 로컬 git 브랜치를 나열합니다.

예를 들어 다음과 같이 반복합니다.

for BRANCH in `git branch --list|sed 's/\*//g'`;
  do 
    git checkout $BRANCH
    git fetch
    git branch --set-upstream-to=origin/$BRANCH $BRANCH
  done
git checkout master;
for branch in $(git for-each-ref --format='%(refname:short)' refs/heads); do
    ...
done

이것은 스크립트용으로 설계된 git compensing 명령을 사용합니다.또한 심플하고 표준적입니다.

레퍼런스:Git의 Bash 완료

단순하게 받아들여라.

bash 스크립트를 사용하여 분기 이름을 루프로 가져오는 간단한 방법입니다.

#!/bin/bash

for branch in $(git for-each-ref --format='%(refname)' refs/heads/); do
    echo "${branch/'refs/heads/'/''}" 
done

출력:

master
other

$(git branch|grep -o "[0-9A-Za-z]\+")가 숫자, A-Z 로만 명명된 , a-z "/" A-Z " " "

인정된 답변은 정확하고 실제로 사용되는 접근법이어야 하지만, bash에서 문제를 해결하는 것은 셸이 어떻게 작동하는지 이해하는 데 있어 훌륭한 연습입니다.추가 텍스트 조작을 수행하지 않고 bash를 사용하여 이를 수행하는 비결은 셸에 의해 실행되는 명령의 일부로 git 분기의 출력이 확장되지 않도록 하는 것입니다.이것에 의해, 셸 확장의 파일명 전개(스텝 8)로 아스타리스크가 전개되는 것을 막을 수 있습니다(http://tldp.org/LDP/Bash-Beginners-Guide/html/sect_03_04.html) 참조).

git 브랜치 출력을 행으로 자르려면 read 명령을 사용하여 bash while constructure를 사용합니다.'*'는 리터럴 문자로 읽힙니다.일치하는 패턴에 특히 주의하면서 대/소문자를 사용하여 일치시킵니다.

git branch | while read line ; do                                                                                                        
    case $line in
        \*\ *) branch=${line#\*\ } ;;  # match the current branch
        *) branch=$line ;;             # match all the other branches
    esac
    git log --oneline $branch ^remotes/origin/master
done

bash 케이스 구성 및 파라미터 치환 양쪽의 아스타리스크는 백슬래시로 이스케이프하여 셸이 패턴 매칭 문자로 해석하지 않도록 해야 합니다.문자 그대로 '*'와 일치하기 때문에 (토큰화를 방지하기 위해) 공백도 이스케이프됩니다.

내 생각에 가장 기억하기 쉬운 방법:

git branch | grep "[^* ]+" -Eo

출력:

bamboo
develop
master

Grep의 -o 옵션(--only-matching)은 출력을 입력과 일치하는 부분만 제한합니다.

Git 브랜치 이름에는 공백과 *가 모두 유효하지 않기 때문에 추가 문자가 없는 브랜치 목록이 반환됩니다.

편집: 'detached head' 상태인 경우 현재 항목을 필터링해야 합니다.

git branch --list | grep -v "HEAD detached" | grep "[^* ]+" -oE

결국 가 하게 된 것은 ccpizza가 ccpizza에서 ).tr):

git branch | tr -d ' *' | while IFS='' read -r line; do git log --oneline "$line" ^remotes/origin/master; done

(루프를 많이 하는 편입니다.특정 사항에는 반드시 포인트 변수 이름 [예를 들어 분기]를 사용해야 하지만 대부분의 경우 저는 각 입력 행에 대해 무언가를 수행하는 데만 관심이 있습니다.여기서 '브런치'가 아닌 '라인'을 사용하는 것은 재사용 가능성/근육 기억력/효율성에 동의하는 것입니다.)

Googlian의 답변, 하지만 다음 질문에 대해서는 사용하지 않습니다.

git for-each-ref --format='%(refname:lstrip=-1)' refs/heads/

이 상태일 경우:

git branch -a

* master

  remotes/origin/HEAD -> origin/master

  remotes/origin/branch1

  remotes/origin/branch2

  remotes/origin/branch3

  remotes/origin/master

이 코드를 실행합니다.

git branch -a | grep remotes/origin/*

for BRANCH in `git branch -a | grep remotes/origin/*` ;

do
    A="$(cut -d'/' -f3 <<<"$BRANCH")"
    echo $A

done        

다음과 같은 결과를 얻을 수 있습니다.

branch1

branch2

branch3

master

로컬 브랜치명을 간단하게 반복하는 올바른 방법은for-each-ref에 걸쳐서refs/heads/. 예:

for branch in $(git for-each-ref --format='%(refname:short)' refs/heads/); do
  echo branch="${branch}"
done

이것은 다음 표준/기본값으로 동작합니다.IFSgit의 지점 이름에는 공백이 불법이기 때문입니다.

드디어 출력 방법을 확정했습니다.git branch별표도 없고 마법도 없이git for-each-ref인수:

$ git branch --format="%(refname:short)"

이게 왜 가치 있는 거죠? git branch명령어에는 다음과 같은 추가 필터가 있습니다.--merged를 사용하여 구현하기가 쉽지 않습니다.git for-each-ref(적어도 내가 보기엔)

@finn의 답변(감사합니다!)에서 확장하면, 다음은 개입하는 셸 스크립트를 작성하지 않고 브랜치상에서 반복할 수 있습니다.브랜치명에 새로운 행이 없는 한, 충분히 견고합니다. : )

git for-each-ref --format='%(refname)' refs/heads  | while read x ; do echo === $x === ; done

while 루프는 서브셸에서 실행됩니다.이는 현재 셸에서 액세스하려는 셸 변수를 설정하지 않는 한 일반적으로 문제가 없습니다.이 경우 프로세스 치환을 사용하여 파이프를 반전시킵니다.

while read x ; do echo === $x === ; done < <( git for-each-ref --format='%(refname)' refs/heads )

로컬 저장소에 헤드(브런치) 나열

git show-ref --heads
  • git show-ref - 로컬 저장소에 참조 목록 표시
    • --heads 유일한 리스트heads(태그 없음)

이렇게 하면 앞면이 표시됩니다.

682e47c01dc8d0f4e4102f183190a48aaf34a3f0 refs/heads/main
....

그래서 이름에만 관심이 있다면 이런 걸 쓸 수 있어요.sed원하는 결과를 얻기 위해

git show-ref --heads | sed 's/.*refs\/heads\///'

나뭇가지 사이를 반복하다

이 출력으로 쉽게 반복할 수 있습니다. 예를 들어 배쉬 루프, xargs 등 보트가 뜨는 모든 것을 사용할 수 있습니다.

for SHA in $(git show-ref --heads | awk '{ print $1 }'); do
 echo "magic! $SHA"
done
  • git show-ref --heads위와 같이 가지를 받다
  • awk '{ print $1 }'SHA를 취득하다
  • echo "magic! $SHA"여기가 마법을 부릴 곳이야

물론 이론적으로는 Git이 스크립팅할 때 실제로 사용하는 특별한 인터페이스를 사용해야 한다.하지만 종종 오넬라이너에게 편리한 심플한 을 원합니다.git for each-ref --format … refs … amen 등의 내용을 기억하도록 재촉하지 않는 것.결국 UNIX가 되었습니다.그 후, 다음과 같이 됩니다.

  1. 마지막 칼럼을 인쇄하는 방법은 모호하지만 간결하기로 널리 알려진 유틸리티가 있습니다.
  2. git branch는 지점명 앞에 아스타리스크를 붙입니다.그 말은 우리가 항상 마지막 칼럼에 정확히 관심이 있다는 뜻이죠

결과:

git branch | awk '{print $NF}'

것은 '아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 맞다.'awk 변수가 .NF마지막 필드의 번호입니다.을 붙입니다.$그 들 마녀의 내용물이 바로 여기에 필요한 것이다.

#/bin/bash
for branch in $(git branch -r); 
do
    echo $branch
done

언급URL : https://stackoverflow.com/questions/3846380/how-to-iterate-through-all-git-branches-using-bash-script

반응형