Kaip kartoti per visus git filialus naudojant bash scenarijų

Kaip aš galiu pasikartoti per visus vietinius filialus mano saugykloje naudojant „bash“ scenarijų. Turiu pakartoti ir patikrinti, ar yra filialo ir kai kurių nuotolinių filialų skirtumas. Ex

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

Turiu daryti kažką panašaus į pirmiau minėtą, bet problema, su kuria susidūriau, yra $ (git filialas), suteikia man aplankus saugyklos aplanke kartu su saugykloje esančiais filialais.

Ar tai tinkamas būdas išspręsti šią problemą? Ar tai yra dar vienas būdas tai padaryti?

Ačiū

79
02 окт. Arun P Johny rinkinys 02 okt. 2010-10-02 18:33 '10, 18:33, 2010-10-02 18:33
@ 9 atsakymai

Rašydami scenarijus neturėtumėte naudoti git filialo. „git“ suteikia „vandentiekio“ sąsają, kuri yra aiškiai skirta naudoti scenarijuose (daugelis dabartinių ir istorinių bendrų git komandų (pridėti, išsiregistruoti, sujungti ir tt) naudoja tą pačią sąsają).

Vandentiekio komanda, kurią norite, yra git for-every-ref:

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

Pastaba: jums nereikia nuotolinio ryšio nuorodos remotes/ prefikso, nebent turite kitų nuorodų, kurios skambina origin/master kad atitiktų kelias vietas nuorodos pavadinimo paieškos kelyje (žr. „Simbolinis pavadinimo pavadinimas ...“ skyriuje „Pakeitimų nurodymas „git -rev-parse (1) ) skyriuje . Jei bandote aiškiai išvengti dviprasmybės, eikite į visą pavadinimą ref: refs/remotes/origin/master .

Rezultatą gausite taip:

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

Šią išvestį galite perduoti į sh.

Jei jums nepatinka idėja generuoti korpuso kodą, galite atsisakyti tam tikro patikimumo * ir atlikite šiuos veiksmus:

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

* Nuorodų pavadinimai turi būti saugūs nuo žodžių įvyniojimo (žr. Git -check-ref-format (1) ). Asmeniškai norėčiau laikytis ankstesnės versijos (sukurtas kodo kodas); Esu tikras, kad jam nieko negali atsitikti.

Kadangi nurodėte „bash“ ir ji palaiko masyvus, galite išsaugoti saugumą ir vis tiek vengti kurti ciklą:

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

Galite naudoti kažką panašaus su $@ jei nenaudojate korpuso, kuris palaiko masyvus ( set -- inicijuoti ir set -- "$@" %(refname) elementams pridėti).

132
03 окт. Chris Johnsen atsakymas 03 d 2010-10-03 00:24 '10 - 0:24 2010-10-03 00:24

Taip yra dėl to, kad git branch žymi dabartinį filialą žvaigždute, pavyzdžiui:

 $ git branch * master mybranch $ 

taip $(git branch) plečiasi, pavyzdžiui, * master mybranch , o tada * plečiasi į failų sąrašą dabartiniame kataloge.

border=0

Aš nematau akivaizdžios parinkties, kad pirmiausia nebūtų spausdinama žvaigždutė; bet galite jį išjungti:

 $(git branch | cut -c 3-) 
43
02 окт. Matthew Slattery atsakymas 02 okt. 2010-10-02 18:49 '10, 18:49 PM 2010-10-02 18:49

Pavyzdžiui, kartoju:

 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; 
5
21 марта '16 в 14:40 2016-03-21 14:40 atsakymą pateikė Djory Krache kovo 21 d. , 16:40 2016-03-21 14:40

Priimtas atsakymas yra teisingas ir turėtų būti naudojamas kaip požiūris, tačiau problemos sprendimas bash yra puikus pratimas suprasti, kaip veikia kriauklės. Trenksmas, naudojant bash be papildomo teksto manipuliavimo, yra užtikrinti, kad git filialo išvestis niekada nebūtų išplėsta kaip komandos, kurią turi atlikti korpusas, dalis. Tai neleidžia žvaigždutei išplėsti, kai išplėsta korpuso plėtinio failo pavadinimas (8 veiksmas) (žr. Http://tldp.org/LDP/Bash-Beginners-Guide/html/sect_03_04.html )

Naudokite bash konstrukciją su skaitymo komanda, kad nutrauktumėte git šakų išvestį linijose. "*" Bus laikomas abėcėlės ženklu. Naudokite atvejo argumentą, kad jis atitiktų, ypatingą dėmesį skiriant atitinkamiems modeliams.

 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 

Bazinės konstrukcijos žvaigždutėmis ir parametrų pakeitimu turėtų būti išvengta backslashes taip, kad apvalkalas jų nepripažintų kaip modelio atitikimo simbolių. Erdvės taip pat išvengiamos (kad būtų išvengta tokenizacijos), nes tiesiogine prasme sutinkate su „*“.

4
30 янв. atsakymas pateikiamas BitByteDog 30 sausis 2016-01-30 11:32 '16 at 11:32 2016-01-30 11:32

mapfile bash, mapfile , sukurta tam

visi git šakos: git branch --all --format='%(refname:short)'

visos vietinės git šakos: git branch --format='%(refname:short)'

visi ištrinti git filialai: git branch --remotes --format='%(refname:short)'

eikite per visus git filialus: mapfile -t -c my_callback -c 1 < <( get_branches )

pavyzdys:

 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 ) 

konkrečiai situacijai 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}" 

šaltinis: visų vietinių git filialų sąrašas be žvaigždės

4
13 нояб. Atsakymą pateikė Andrew Miller lapkričio 13 d. 2018-11-13 01:30 '18, 1:30 2018-11-13 01:30

Norėčiau pasiūlyti $(git branch|grep -o "[0-9A-Za-z]\+") jei jūsų vietiniai filialai vadinami tik skaičiais, az ir / arba raidėmis AZ

4
20 июля '12 в 6:43 2012-07-20 06:43 atsakymą pateikė Xin Guo liepos 20 d., 12 val., 06:43, 2012-07-20 06:43

Ką aš galiausiai pritaikiau jūsų klausimui (ir įkvėpė cpp, paminėdamas tr ):

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

(Aš dažnai naudoju, o kilpos. Nors tam tikrus dalykus, kuriuos tikrai norite naudoti nurodytu kintamuoju, naudodami pavadinimą [pavyzdžiui, filialas “), dažniausiai tai darau tik su kiekviena įvesties eilute . „Linija“ yra čia, o ne „filialas“ - pakartotinio naudojimo / raumenų atminties / efektyvumo ženklas.)

3
30 янв. atsakymas pateikiamas Jan Kyu Peblik sausio 30 d 2018-01-30 21:36 '18, 21:36 2018-01-30 21:36

Lengviausias būdas prisiminti, mano nuomone:

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

Išvada:

 bamboo develop master 

Grep -o (- tik suderinamas) parametras riboja išėjimą tik į atitinkamas įvesties dalis.

Kadangi nei „Space“, nei „*“ negalioja „Git“ filialų pavadinimuose, tai grąžina filialų sąrašą be papildomų simbolių.

Redaguoti: jei esate „atjungtos galvutės“ būsenoje , turite filtruoti dabartinį įrašą:

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

2
01 авг. atsakymas duotas staafl 01 rug . 2017-08-01 17:00 „17, 17 val. 2017-08-01 17:00

Išplėsti atsakymą @finn (ačiū!), Toliau bus galima kartoti per filialus nesukuriant tarpinio scenarijaus apvalkalo. Tai pakankamai stiprus, jei filialo pavadinime nėra naujų eilučių :)

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

Kai ciklas veikia subshell, kuris paprastai yra gerai, jei nenustatote kintamų korpusų, kuriuos norite pasiekti dabartiniame apvalkale. Tokiu atveju jūs naudojate atvirkštinio transformavimo proceso pakeitimą:

 while read x ; do echo === $x === ; done < <( git for-each-ref --format='%(refname)' refs/heads ) 
1
24 окт. Chris Cogdon atsakymas, pateiktas spalio 24 d 2017-10-24 01:31 '17 at 1:31 2017-10-24 01:31

Kiti klausimai apie žymes arba Užduoti klausimą