Frage

Wie kann ich durchlaufen alle lokalen Niederlassungen in meinem Repository mit Bash-Skript. Ich brauche zu durchlaufen und die Prüfung gibt es einen Unterschied zwischen der Branche und einigen abgelegenen Filialen. Ex

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

Ich brauche oben wie gegeben, etwas zu tun, aber das Problem, das ich mit Blick auf bin ist $ (git branch) gibt mir die Ordner im Repository-Ordnern zusammen mit den Zweigen präsentieren im Repository.

Ist dies der richtige Weg, um dieses Problem zu lösen? Oder gibt es eine andere Möglichkeit, es zu tun?

Danke

War es hilfreich?

Lösung

Sie sollten verwenden nicht git branch , wenn Schreiben von Skripts. Git bietet einen „Sanitär“ Schnittstelle , die ist explizit für den Einsatz in scripting (vielen aktuellen und historischen Implementierungen von normalen Git-Befehlen (add, Kasse, merge, etc.) dieselbe Schnittstelle verwenden).

Die sanitären Anlagen Befehl Sie wollen, ist git for-each-ref :

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

Hinweis: Sie müssen nicht den remotes/ Präfix auf der Fernbedienung ref, wenn Sie andere Refs haben, dass Ursache origin/master mehrere Orte in dem ref Suchpfad anzupassen (siehe unter die Spezifizierungs Revisions Abschnitt des GIT-rev-parse (1) ). Wenn Sie explictly versuchen, Unklarheiten zu vermeiden, dann mit der vollen ref gehen: refs/remotes/origin/master.

Sie Ausgabe wie diese:

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

Sie können über die Pipeline diese Ausgabe in sh .

Wenn Sie die Erzeugung des Shell-Code nicht, wie die Idee zu tun, könnten Sie ein bisschen Robustheit aufgeben * und dies tun:

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

* Ref Namen sollten sicher sein, von der Shell-Wort Spaltung (siehe git-Check-ref-Format (1) ). Persönlich würde ich mit der früheren Version Stick (erzeugen Shell-Code); Ich bin zuversichtlich, dass nichts unangebracht damit passieren kann.

Da Sie angegeben bash und unterstützt Arrays, Sie Sicherheit behaupten können und vermeiden noch den Mut Ihrer Schleife zu erzeugen:

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

Sie könnten etwas ähnliches mit $@ tun, wenn Sie nicht eine Shell verwenden, dass Stützen Arrays (set -- zu initialisieren und set -- "$@" %(refname) Elemente hinzuzufügen).

Andere Tipps

Das ist, weil git branch markiert den aktuellen Zweig mit einem Stern, z.

$ git branch
* master
  mybranch
$ 

so $(git branch) ERWEITERT z.B. * master mybranch, und dann werden die * expandiert in die Liste der Dateien im aktuellen Verzeichnis.

Ich habe keine offensichtliche Option sehen Sie nicht den Druck der Stern an erster Stelle; aber man kann es abhacken:

$(git branch | cut -c 3-)

Die bash builtin, mapfile, wird für diesen

gebaut

alle git Zweige: git branch --all --format='%(refname:short)'

alle lokalen git Zweige: git branch --format='%(refname:short)'

alle Remote-git Zweige: git branch --remotes --format='%(refname:short)'

iterate durch alle git Zweige: mapfile -t -C my_callback -c 1 < <( get_branches )

Beispiel:

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 )

für die spezifische Situation der 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}"

Quelle: Liste alle lokalen git Zweige ohne Sternchen

I Iterierte, wie es zum Beispiel:

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;

Ich würde vorschlagen $(git branch|grep -o "[0-9A-Za-z]\+") wenn Ihre lokalen Niederlassungen von Ziffern genannt werden, a-z und / oder A-Z Buchstaben nur

Die akzeptierte Antwort ist richtig und wirklich der Ansatz verwendet werden soll, aber das Problem in bash Lösung ist eine großartige Übung zu verstehen, wie Muscheln Arbeit. Der Trick zu tun dies mit bash ohne zusätzliche Textmanipulation durchgeführt wird, ist die Ausgabe von git Zweig, um sicherzustellen, nie als Teil eines Befehls erweitert wird von der Shell ausgeführt werden. Dies verhindert, dass der Stern von je im Dateinamen Expansion (Schritt 8) von Shell-Erweiterung seiner Erweiterung (siehe http://tldp.org/LDP/Bash-Beginners-Guide/html/sect_03_04.html )

Mit der bash während Konstrukt mit einem Lesebefehl der Verzweigungs git Ausgang in Linien zerhacken. Der ‚*‘ wird in als Literalzeichen gelesen werden. Verwenden Sie eine Case-Anweisung, es zu entsprechen, wobei besonderes Augenmerk auf die passenden Muster.

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

Die Sternchen in sowohl der bash Fall Konstrukt und im Parametersubstitution werden müssen, mit umgekehrten Schrägstrichen entkommen die Schale zu verhindern, dass sie als Musteranpassung Zeichen zu interpretieren. Die Räume sind auch entkam (tokenization zu verhindern), weil man buchstäblich passen ‚*‘.

Die einfachste Option meiner Meinung nach erinnern:

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

Ausgabe:

bamboo
develop
master

grep -o Option (--only-Matching) begrenzt die Ausgabe auf nur die passenden Teile des Eingangs.

Da weder Raum noch * gültig sind in Git-Zweigs Namen, diese gibt die Liste der Filialen ohne die zusätzlichen Zeichen.

Edit: Wenn Sie in 'abgelöst Kopf' Zustand , müssen Sie aus dem aktuellen Eintrag zu Filter:

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

Was ich am Ende tun, angewandt auf Ihre Frage (und inspiriert von ccpizza erwähnen tr):

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

(ich benutze While-Schleifen viel. Während für bestimmte Dinge würden Sie auf jeden Fall wollen einen spitzen Variablennamen verwenden, [ „Zweig“, zum Beispiel], die meisten der Zeit, die ich nur mit etwas zu tun, besorgt bin mit jede Zeile der Eingabe. Mit 'line' hier statt 'Zweigniederlassung' ist eine Anspielung auf Wiederverwertbarkeit / Muskelgedächtnis / Effizienz.)

Die Ausweitung auf von @ finn Antwort (danke!), Die folgende lassen Sie Iterierte über die Zweige ohne einen dazwischenliegenden Shell-Skript zu erstellen. Es ist robust genug, solange es keine Zeilenumbrüche in der Branche Namen:)

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

Die while-Schleife läuft in einer Sub-Shell, die in der Regel in Ordnung ist, es sei denn du bist Einstellung Shell-Variablen, die Sie in der aktuellen Shell zugreifen möchten. In diesem Fall verwenden Sie Prozess Substitution das Rohr umgekehrt:

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

Wenn Sie in diesem Zustand sind:

git branch -a

* master

  remotes/origin/HEAD -> origin/master

  remotes/origin/branch1

  remotes/origin/branch2

  remotes/origin/branch3

  remotes/origin/master

Und Sie diesen Code ausführen:

git branch -a | grep remotes/origin/*

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

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

done        

Sie werden dieses Ergebnis erhalten:

branch1

branch2

branch3

master

Keep it simple

Der einfache Weg, um Zweignamen in Schleife Bash-Skript verwendet wird.

#!/bin/bash

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

Ausgabe:

master
other

Googlian Antwort, jedoch ohne Verwendung von für

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

Diese verwendet git Sanitär Befehle, die für Scripting ausgelegt sind. Es ist auch einfach und Standard.

Referenz: Git Bash Abschluss

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top