bash 스크립트를 사용하여 모든 git 분기를 반복하는 방법 git log –oneline $branch ^remotes/origin/master; done 위와

bash 스크립트를 사용하여 내 저장소의 모든 로컬 분기를 반복하려면 어떻게해야합니까? 반복하고 분기와 일부 원격 분기간에 차이점이 있는지 확인해야합니다. 전의

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

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

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

감사합니다



답변

스크립트를 작성할 때 git 브랜치를 사용해서는 안됩니다 . Git은 스크립팅에 사용하도록 명시 적으로 설계된 “plumbing”인터페이스 를 제공 합니다 (일반 Git 명령의 많은 현재 및 이전 구현 (추가, 체크 아웃, 병합 등)이 동일한 인터페이스를 사용함).

원하는 배관 명령은 git for-each-ref입니다 .

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


참고 : 참조 이름 검색 경로에서 여러 위치를 일치 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-)


답변

이를 위해 bash 내장 기능 mapfile이 빌드되었습니다.

모든 자식 브랜치 : git branch --all --format='%(refname:short)'

모든 로컬 git 브랜치 : git branch --format='%(refname:short)'

모든 원격 git 브랜치 : git branch --remotes --format='%(refname:short)'

모든 git 분기를 반복합니다. 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;


답변

$(git branch|grep -o "[0-9A-Za-z]\+")지역 지점의 이름이 숫자, az 및 / 또는 AZ 문자로만 지정되는 경우 제안
합니다.


답변

받아 들여지는 대답은 정확하고 실제로 사용되는 접근 방식이어야하지만 bash에서 문제를 해결하는 것은 셸 작동 방식을 이해하는 훌륭한 연습입니다. 추가 텍스트 조작을 수행하지 않고 bash를 사용하여이 작업을 수행하는 비결은 git 분기의 출력이 셸에서 실행되는 명령의 일부로 확장되지 않도록하는 것입니다. 이렇게하면 쉘 확장의 파일 이름 확장 (8 단계)에서 별표가 확장되는 것을 방지합니다 ( http://tldp.org/LDP/Bash-Beginners-Guide/html/sect_03_04.html 참조 ).

read 명령과 함께 bash while 구문을 사용하여 git 분기 출력을 줄로 자릅니다. ‘*’는 리터럴 문자로 읽 힙니다. 일치하는 패턴에 특히주의하면서 케이스 문을 사용하여 일치 시키십시오.

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 브랜치 이름에는 공백이나 *가 모두 유효하지 않으므로 추가 문자없이 브랜치 목록을 반환합니다.

수정 : ‘분리 된 헤드’상태 인 경우 현재 항목을 필터링해야합니다.

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