Domanda

Come faccio a scorrere tutti i rami locali nel mio repository può utilizzare script bash. Devo iterare e controllo v'è alcuna differenza tra il ramo e alcuni rami remoti. Ex

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

Ho bisogno di fare qualcosa di simile di cui sopra, ma il problema che sto affrontando è $ (git branch) mi dà le cartelle all'interno della cartella del repository con i rami presentare nel repository.

E 'questo il modo corretto per risolvere questo problema? O c'è un altro modo per farlo?

Grazie

È stato utile?

Soluzione

Non dovrebbe usare filiali git gli script durante la scrittura. Git fornisce un “idraulico” interfaccia che è esplicitamente progettato per l'uso in scripting (molti attuale e implementazioni storiche di normali comandi Git (add, checkout, merge, etc.) utilizzare questa stessa interfaccia).

Il comando idraulico che si desidera è git for-each-ref :

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

Nota: non è necessario il prefisso remotes/ sul ref remota a meno che non si dispone di altri arbitri che causano origin/master per abbinare più punti del percorso del nome ref di ricerca (vedere in sezione Specifica revisioni di git-rev-parse (1) ). Se si sta cercando di evitare esplicitamente l'ambiguità, poi andare con il nome completo ref: refs/remotes/origin/master.

Si otterrà un output simile a questo:

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

È possibile reindirizzare questo output in sh .

Se non ti piace l'idea di generare il codice shell, si potrebbe dare un po 'di robustezza * e fare questo:

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

* nomi Ref dovrebbero essere al sicuro dalla suddivisione delle parole della shell (si veda git-check-ref-formato (1) ). Personalmente bastone con la versione precedente (codice shell generato); Sono più fiducioso che niente di inappropriato può accadere con esso.

Dal momento che si è specificato bash e supporta gli array, si potrebbe mantenere la sicurezza ed evitare di generare ancora il coraggio del vostro ciclo:

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

Si potrebbe fare qualcosa di simile con $@ se non si utilizza un guscio che supporta array (set -- per inizializzare e set -- "$@" %(refname) per aggiungere elementi).

Altri suggerimenti

Questo perché segna git branch il ramo corrente con un asterisco, per esempio:.

$ git branch
* master
  mybranch
$ 

quindi espande $(git branch) per esempio * master mybranch, e poi le si espande * alla lista dei file nella directory corrente.

Non vedo una scelta ovvia per non stampare l'asterisco, in primo luogo; ma si potrebbe tagliare fuori:

$(git branch | cut -c 3-)

Il builtin bash, mapfile, è costruito per questo

tutti i rami git: git branch --all --format='%(refname:short)'

tutti i rami Git locali: git branch --format='%(refname:short)'

tutti i rami Git remoti: git branch --remotes --format='%(refname:short)'

scorrere tutti i rami git: mapfile -t -C my_callback -c 1 < <( get_branches )

Esempio:

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 )

per la situazione specifica del PO:

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

fonte: Lista tutti i locali rami Git senza un asterisco

I iterata come ad esempio:

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;

vorrei suggerire $(git branch|grep -o "[0-9A-Za-z]\+") se i vostri filiali locali sono chiamati da cifre, a-z, lettere e / o A-Z solo

La risposta accettata è corretta e in realtà dovrebbe essere l'approccio utilizzato, ma la soluzione del problema in bash è un grande esercizio per capire come opera conchiglie. Il trucco per fare questo usando bash senza eseguire manipolazioni testo aggiuntivo, è quello di garantire l'uscita del ramo git non viene mai espansa come parte di un comando da eseguire dalla shell. Questo impedisce l'asterisco mai essere espansione nell'espansione nome di file (fase 8) di espansione shell (vedi http://tldp.org/LDP/Bash-Beginners-Guide/html/sect_03_04.html )

Utilizza la bash mentre costrutto con un comando di lettura per tagliare l'output ramo git in linee. Il '*' sarà letto come un carattere letterale. Utilizzare un'istruzione caso di abbinarlo, con particolare attenzione ai modelli corrispondenti.

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

Gli asterischi sia bash caso costrutto e nella necessità sostituzione di parametro di escape backslash per impedire il guscio interpretarli come caratteri pattern matching. Gli spazi sono anche fuggiti (per prevenire la tokenizzazione) perché si sono letteralmente Matching '*'.

opzione più semplice da ricordare, a mio parere:

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

Output:

bamboo
develop
master

opzione -o di Grep (--only-matching) limita l'output solo le parti corrispondenti dell'ingresso.

Poiché né spazio né * sono validi nei nomi ramo Git, questo restituisce la lista dei rami, senza i caratteri extra.

Edit: Se siete in 'staccato la testa' stato , avrete bisogno per filtrare la voce corrente:

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

Quello che ho finito per fare, applicato alla tua domanda (e ispirato ccpizza menzionando tr):

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

(io uso while molto. Mentre per cose particolari che ci si sicuramente desidera utilizzare un nome di variabile punte [ "succursale", ad esempio], il più delle volte mi riguarda solo fare qualcosa con ogni riga di ingresso. Usando 'linea' qui invece di 'ramo' è un cenno alla riutilizzabilità / memoria muscolare / efficienza.)

Estendendosi su da @ di Finn risposta (grazie!), Di seguito vi permetterà di eseguire iterazioni sui rami senza creare uno script di shell intervenire. E 'abbastanza robusto, a patto che non ci sono a capo del nome del ramo:)

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

il ciclo while viene eseguito in una subshell, che di solito è bene a meno che non si sta impostando le variabili di shell che si desidera accedere nella shell corrente. In questo caso si utilizza la sostituzione di processo per invertire il tubo:

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

Se siete in questo stato:

git branch -a

* master

  remotes/origin/HEAD -> origin/master

  remotes/origin/branch1

  remotes/origin/branch2

  remotes/origin/branch3

  remotes/origin/master

E si esegue questo codice:

git branch -a | grep remotes/origin/*

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

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

done        

Si otterrà questo risultato:

branch1

branch2

branch3

master

Keep it simple

Il modo più semplice di ottenere nome del ramo in loop utilizzando script bash.

#!/bin/bash

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

Output:

master
other

La risposta di Googlian, ma senza l'utilizzo di per

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

Questo utilizza git comandi idraulico sanitari, che sono progettati per gli script. E 'anche semplice e standard.

Riferimento: completamento Bash di Git

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top