bash 펼쳐보기를 사용하여 모든 git 분기를 반복하는 방법
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)'
모든 자식 분기를 반복합니다. 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 참조 ).
읽기 명령과 함께 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
내가 한 일을 귀하의 질문에 적용했습니다 (& ccpizza 언급에서 영감을 얻었습니다 tr
).
git branch | tr -d ' *' | while IFS='' read -r line; do git log --oneline "$line" ^remotes/origin/master; done
(나는 while 루프를 많이 사용합니다. 특정한 일에 대해서는 분명히 뾰족한 변수 이름 [ "branch", 예를 들어]을 사용하고 싶겠지 만, 대부분의 경우 저는 각 입력 라인 으로 무언가를하는 것에 만 관심이 있습니다. 여기서 '가지'대신 '줄'은 재사용 성 / 근육 기억 / 효율성에 대한 고개를 끄덕입니다.)
@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 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
간단하게
bash 스크립트를 사용하여 루프에서 분기 이름을 얻는 간단한 방법입니다.
#!/bin/bash
for branch in $(git for-each-ref --format='%(refname)' refs/heads/); do
echo "${branch/'refs/heads/'/''}"
done
산출:
master
other
Googlian의 대답하지만, 사용하지 않고 에 대한
git for-each-ref --format='%(refname:lstrip=-1)' refs/heads/
for branch in "$(git for-each-ref --format='%(refname:short)' refs/heads)"; do
...
done
이것은 스크립팅을 위해 설계된 git plumbing 명령을 사용합니다. 또한 간단하고 표준 적입니다.
참조 : Git의 Bash 완성
'IT' 카테고리의 다른 글
마크 다운의 MIME 유형은 무엇입니까? (0) | 2020.08.29 |
---|---|
여러 파일을 선택하는 방법 (0) | 2020.08.29 |
jQuery : 필드 값이 null (비어 있음)인지 확인 (0) | 2020.08.29 |
불완전한 유형은 허용되지 않는 언어 : stringstream (0) | 2020.08.29 |
Intellij 컴파일러에 더 많은 힙 공간을 제공해야합니까? (0) | 2020.08.29 |