Wie kann ich ein Bash-Skript einchecken, wenn sich in meinem lokalen Git-Repository Änderungen ergeben?

175

Es gibt einige Skripte, die nicht richtig funktionieren, wenn sie nach Änderungen suchen.

Ich habe es so versucht:

VN=$(git describe --abbrev=7 HEAD 2>/dev/null)

git update-index -q --refresh
CHANGED=$(git diff-index --name-only HEAD --)
if [ ! -z $CHANGED ];
    then VN="$VN-mod"
fi

Gibt es eine Art boolesche Prüfung, ob seit dem letzten Commit Änderungen vorgenommen wurden, oder wie kann ich wirklich testen, ob neue Änderungen an meinem lokalen Repository vorgenommen wurden?

Ich mache das alles für ein Skript zur Versionserstellung (das ich irgendwo hier gefunden habe).

kmindi
quelle
3
Was ist los mit git status?
Karlphillip
4
@karlphillip: Es macht eine Menge Verarbeitung, die Sie nicht wirklich brauchen.
Cascabel
1
@karlphillip es ist ein "Porzellan" -Befehl, das heißt: nicht für die Verwendung in Skripten geeignet, da die Ausgabe für das Lesen durch Menschen ausgelegt ist und sich ändern kann (zwischen Versionen oder aufgrund von Lokalisierung)
Andrew Spencer

Antworten:

199

Was Sie tun, wird fast funktionieren: Sie sollten zitieren, $CHANGEDfalls es leer ist, und -zauf leer testen, was bedeutet, dass keine Änderungen vorgenommen werden. Was Sie meinten war:

if [ -n "$CHANGED" ]; then
    VN="$VN-mod"
fi

Ein Zitat von Git GIT-VERSION-GEN:

git update-index -q --refresh
test -z "$(git diff-index --name-only HEAD --)" ||
VN="$VN-dirty"

Es sieht so aus, als hätten Sie das kopiert, aber Sie haben dieses Detail des Zitierens einfach vergessen.

Natürlich können Sie dies auch einfach tun:

if git diff-index --quiet HEAD --; then
    # No changes
else
    # Changes
fi

Oder wenn Sie sich nur für den Fall "etwas hat sich geändert" interessieren:

if ! git diff-index --quiet HEAD --; then
    VN="$VN-mod"
fi

Die Verwendung --quiethat den Vorteil, dass Git die Verarbeitung stoppen kann, sobald es auf einen einzelnen Unterschied stößt, sodass möglicherweise nicht der gesamte Arbeitsbaum überprüft werden muss.

Cascabel
quelle
2
Hallo, das war eine der besten Antworten auf eine Frage, du hast mir nur alle Informationen gegeben, die ich brauchte und die andere auch meine Bedürfnisse :). Ich brauche nur den letzten, "etwas hat sich geändert" :) und du hattest Recht, ich habe es kopiert.
kmindi
9
Das erstaunliche Bash-Vervollständigungsskript scheint zu verwenden git diff --no-ext-diff --quiet --exit-code, um den schmutzigen Zustand zu bestimmen.
mjs
3
@mjs: Das ist in der Tat ein großartiger Ort, um nach solchen Dingen zu suchen! Die --no-ext-diffOption ist gut für die Sicherheit (falls jemand einen externen Diff-Treiber konfiguriert hat), obwohl dies --exit-codenicht erforderlich sein sollte, da dies impliziert ist --quiet.
Cascabel
4
Dies funktioniert nicht für mich, da es keine nicht verfolgten Dateien meldet
Cookie
1
git diff-indexmeldet Änderungen, auch wenn sich nur die Änderungszeiten der Dateien geändert haben (und nicht deren Inhalt). Wenn Sie toucheine Datei haben, wird eine Änderung gemeldet, die beim Ausführen git statuszurückgesetzt wird. Die Verwendung git statuswie unten ist besser.
Sampo
302

Verwenden von git status:

cd /git/directory
if [[ `git status --porcelain` ]]; then
  # Changes
else
  # No changes
fi
Ryanmoon
quelle
15
Die beste Antwort, schade, dass die Antworten der 'Shell and Git Architects' höher bewertet werden.
JWG
4
Dies ist großartig, da es nicht versionierte Dateien berücksichtigt und auch Porzellan verwendet. Es sollte besser mit verschiedenen Git-Versionen kompatibel sein.
Jayd
25
So ignorieren Sie nicht verfolgte Dateien: if [[ git status --porcelain --untracked-files=no]]; dann
Storm_M2138
4
Zur Überprüfung lokaler Änderungen -> if [[ $(git status --porcelain | wc -l) -gt 0 ]]; then echo CHANGED else echo NOT CHANGED locally fi
Carlos Saltos
3
Was dieser Code bewirkt: Führen git status --porcelainSie aus, ob die Ausgabe nicht leer ist. Wenn ja, bedeutet dies, dass Änderungen vorhanden sind.
Bhathiya-Perera
18

Obwohl Jefromis Antwort gut ist, poste ich dies nur als Referenz.

Aus dem Git-Quellcode gibt es ein shSkript, das Folgendes enthält.

require_clean_work_tree () {
    git rev-parse --verify HEAD >/dev/null || exit 1
    git update-index -q --ignore-submodules --refresh
    err=0

    if ! git diff-files --quiet --ignore-submodules
    then
        echo >&2 "Cannot $1: You have unstaged changes."
        err=1
    fi

    if ! git diff-index --cached --quiet --ignore-submodules HEAD --
    then
        if [ $err = 0 ]
        then
            echo >&2 "Cannot $1: Your index contains uncommitted changes."
        else
            echo >&2 "Additionally, your index contains uncommitted changes."
        fi
        err=1
    fi

    if [ $err = 1 ]
    then
        test -n "$2" && echo >&2 "$2"
        exit 1
    fi
}
Pfeilmeister
quelle
Als Referenz und wenn ich dies richtig lese, $1handelt es sich um eine Zeichenfolge, die eine Aufgabe benennt, die Sie ausführen möchten, und $2eine Zeichenfolge, die optional eine benutzerdefinierte Fehlermeldung bei einem Fehler enthält. Nennen Sie es zum Beispielrequire_clean_work_tree deploy "Skipping deploy, clean up your work tree or run dev-push"
Umbrella
6

Ich hatte ein ähnliches Problem, musste aber auch nach hinzugefügten Dateien suchen. Also habe ich folgendes gemacht:

cd /local/repo
RUN=0
git diff --no-ext-diff --quiet --exit-code || RUN=1
if [ $RUN = 0 ]; then
    RUN=`git ls-files --exclude-standard --others| wc -l`
fi

if [ $RUN = 0 ]; then
    exit 0
fi
Leon Waldman
quelle
5

git status ist dein Freund

Wechseln Sie in das Git-Verzeichnis, damit git statuses funktioniert:

cd c:/path/to/.git

Legen Sie eine Variable fest, um den Arbeitsbaum festzulegen, damit der Fehler "Diese Operation muss in einem Arbeitsbaum ausgeführt werden" nicht angezeigt wird:

WORKTREE=c:/path/to/worktree

Erfassen Sie die git statusAusgabe in einer Bash-Variablen

Verwendung, --porcelaindie garantiert, dass sie in einem Standardformat vorliegt und analysiert werden kann:

CHANGED=$(git --work-tree=${WORKTREE} status --porcelain)

Wenn -n (nicht null), haben wir Änderungen.

if [ -n "${CHANGED}" ]; then
  echo 'changed';

else
  echo 'not changed';
fi
AndrewD
quelle
1
Dies hat den Vorteil, dass auch nicht verfolgte Dateien erkannt werden.
Luiz C.
2

Das funktioniert auch:

if [ $(git status --porcelain | wc -l) -eq "0" ]; then
  echo "  🟢 Git repo is clean."
else
  echo "  🔴 Git repo dirty. Quit."
  exit 1
fi
blackjacx
quelle
1

Das funktioniert gut. Außerdem werden die betroffenen Dateien aufgelistet:

if git diff-index --name-status --exit-code HEAD;
then
    echo Git working copy is clean...;
else
    echo ;
    echo ERROR: Git working copy is dirty!;
    echo Commit your changes and try again.;
fi;
Robertberrington
quelle
1
Wenn Sie den Diff nicht sehen wollen, git diff --no-ext-diff --quiet --exit-codeerledigt er auch die Arbeit.
Alex
1

Hier finden Sie eine Reihe nützlicher Bash-Skriptfunktionen, mit denen überprüft wird, ob ein Unterschied vorliegt, der an den Benutzer gedruckt und der Benutzer aufgefordert wird, Änderungen vor der Bereitstellung festzuschreiben. Es wurde für eine Heroku- und Python-Anwendung entwickelt, muss jedoch für keine andere Anwendung geändert werden.

commit(){
    echo "Please enter a commit message..."
    read msg
    git add . --all
    git commit -am $msg
}

check_commit(){
    echo ========== CHECKING FOR CHANGES ========
    changes=$(git diff)
    if [ -n "$changes" ]; then
        echo ""
        echo "*** CHANGES FOUND ***"
        echo "$changes"
        echo ""
        echo "You have uncomitted changes."
        echo "Would you like to commit them (y/n)?"
        read n
        case $n in
            "y") commit;;
            "n") echo "Changes will not be included...";;
            *) echo "invalid option";;
        esac
    else
        echo "... No changes found"
    fi
}

deploy(){
    check_commit
    echo ========== DEPLOYING TO HEROKU ========
    git push heroku master
    heroku run python manage.py syncdb
}

Sie können von Gists unter folgender Adresse kopieren: https://gist.github.com/sshadmand/f33afe7c9071bb725105

Sean
quelle
1

Die Frage des OP ist jetzt mehr als 9 Jahre alt. Ich weiß nicht, was damals man git-statusgesagt wurde, aber hier ist, was es jetzt sagt:

--porcelain[=<version>]  
Give the output in an easy-to-parse format for scripts. This is similar to the 
short output, but will remain stable across Git versions and regardless of user 
configuration. See below for details.  

The version parameter is used to specify the format version. This is optional and 
defaults to the original version v1 format.  

Dies deutet darauf hin, dass die --porcelain Argument gut geeignet ist, den Status eines Repos auf Änderungen zu testen.

In Bezug auf die Frage des OP: "Gibt es eine Art boolesche Prüfung, ob seit dem letzten Festschreiben Änderungen vorgenommen wurden, oder wie kann ich wirklich testen, ob neue Änderungen an meinem lokalen Repository vorgenommen wurden?"

Ich glaube nicht, dass bashdas per se boolesche Datentypen hat , aber das mag nah genug sein:

[ -z "`git status --porcelain`" ] && echo "NULL-NO DIFFS" || echo "DIFFS EXIST"

Dies kann als if-then-elseFormular für ein Skript neu umgewandelt oder unverändert von der CLI im git repo-Ordner ausgeführt werden . Verwenden Sie andernfalls die -COption mit einer Pfadangabe zum interessierenden Repo:

git -C ~/path/to/MyGitRepo status --porcelain 

Nachtrag:

  1. Einige empfehlen, die -u, --untracked-fileOption zu verwenden, um zu vermeiden, dass der Status von Dateien gemeldet wird, die ignoriert werden sollen. Beachten Sie, dass dies einen unglücklichen Nebeneffekt hat : Dateien, die neu hinzugefügt wurden, werden ebenfalls nicht angezeigt. Die Option ist in einigen Situationen nützlich , sollte jedoch vor der Verwendung sorgfältig geprüft werden.
Seamus
quelle
0

So mache ich das ...

CHANGES=`git status | grep "working directory clean"`
if [ ! CHANGES -eq "" ] then
    # do stuff here
else
    echo "You have uncommitted changes..."
fi
Jader Feijo
quelle
3
Ich verwende gerne den Git-Status, aber es ist besser, --porcelain in Skripten zu verwenden und das Ergebnis ohne Änderungen mit einer leeren Zeichenfolge zu vergleichen, da es garantiert nicht inkompatibel zwischen den Versionen geändert wird.
Paul Chernoch
0
nano checker_git.sh

füge dies ein

#!/bin/bash

echo "First arg: $1"

cd $1

bob="Already up-to-date."
echo $bob

echo $(git pull) > s.txt
cat s.txt
if [ "$(cat s.txt)" == "$bob" ]
then
echo "up"
else
echo "not up"

fi
rm -rf st.txt

Lauf sh checker_git.sh gitpath

Robert A.
quelle
0

Basierend auf dem Kommentar von @ Storm_m2138 zur Antwort von @ RyanMoon ( Link ) verwende ich Folgendes in Powershell.

function hasChanges($dir="."){ $null -ne (iex "git -C $dir status --porcelain --untracked-files=no") }

gci -Directory | ?{ hasChanges $_ } | %{ Write-Host "$_ has changes" }
gci -Directory | ?{ hasChanges $_ } | %{ iex "git -C $_ add -u"; iex "git -C $_ commit -m"Somemthing" }
Dennis
quelle