Come posso controllare in uno script Bash se il mio repository Git locale ha delle modifiche?


176

Ci sono alcuni script che non funzionano correttamente se controllano le modifiche.

L'ho provato in questo modo:

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

Esiste una sorta di controllo booleano se sono state apportate modifiche dall'ultimo commit o come posso davvero verificare se ci sono nuove modifiche nel mio repository locale?

Sto facendo tutto questo per uno script di creazione della versione (che ho trovato da qualche parte qui).


3
Cosa c'è che non va git status?
karlphillip,

4
@karlphillip: esegue molte elaborazioni di cui non hai davvero bisogno.
Cascabel,

1
@karlphillip è un comando "di porcellana", che significa: non appropriato per l'uso in script perché l'output è progettato per essere letto dagli umani e può cambiare (tra versioni o a causa della localizzazione)
Andrew Spencer,

Risposte:


201

Quello che stai facendo funzionerà quasi: dovresti citare $CHANGEDnel caso in cui sia vuoto e -ztestare per vuoto, il che significa che non ci sono cambiamenti. Quello che intendevi era:

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

Una citazione da Git GIT-VERSION-GEN:

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

Sembra che tu lo stia copiando, ma hai appena dimenticato quel dettaglio della citazione.

Certo, potresti anche fare questo:

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

O se ti interessa solo il caso "qualcosa è cambiato":

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

L'utilizzo --quietha il vantaggio che Git può interrompere l'elaborazione non appena incontra un singolo diff, quindi potrebbe non essere necessario controllare l'intero albero di lavoro.


2
Ciao, è stata una delle migliori risposte a una domanda, mi hai appena dato tutte le informazioni di cui avevo bisogno e che anche le altre mie necessità :). Ho solo bisogno dell'ultimo, "qualcosa è cambiato" :) e avevi ragione, l'ho copiato.
kmindi,

9
Il fantastico script di completamento bash sembra usare git diff --no-ext-diff --quiet --exit-codeper determinare lo stato sporco.
mjs

3
@mjs: è davvero un ottimo posto per cercare cose come questa! L' --no-ext-diffopzione è buona per la sicurezza (nel caso in cui qualcuno abbia configurato un driver diff esterno), anche --exit-codese non dovrebbe essere necessario, poiché è implicito da --quiet.
Cascabel,

4
Questo non funziona per me in quanto non segnala file non monitorati
Cookie

1
git diff-indexsegnala le modifiche anche se sono cambiati solo i tempi di modifica dei file (e non il loro contenuto). Se si è touchun file, si segnalerà la modifica che git statusverrà ripristinata in esecuzione . Usare git statuscome di seguito è meglio.
Sampo

303

Utilizzando git status:

cd /git/directory
if [[ `git status --porcelain` ]]; then
  # Changes
else
  # No changes
fi

15
La risposta migliore, peccato che le risposte degli "architetti shell e git" siano più votate.
jwg,

4
Questo è ottimo in quanto tiene conto dei file non controllati e anche usando la porcellana, dovrebbe essere più compatibile con diverse versioni di git.
Jayd,

25
Per ignorare i file non tracciati: if [[ git status --porcelain --untracked-files=no]]; quindi
storm_m2138

4
Per verificare le modifiche locali -> if [[ $(git status --porcelain | wc -l) -gt 0 ]]; then echo CHANGED else echo NOT CHANGED locally fi
Carlos Saltos,

3
Cosa fa questo codice: esegui git status --porcelainvedere se l'output non è vuoto. In tal caso ciò significa che sono presenti modifiche.
Bhathiya-Perera,

18

Sebbene la risposta di Jefromi sia buona, sto pubblicando questo solo come riferimento.

Dal codice sorgente di Git c'è uno shscript che include quanto segue.

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
}

Per riferimento, e se ho letto bene, $1è una stringa che nomina un'attività che si desidera eseguire ed $2è una stringa che facoltativamente contiene un messaggio di errore personalizzato in caso di errore. Ad esempio, chiamalo comerequire_clean_work_tree deploy "Skipping deploy, clean up your work tree or run dev-push"
Umbrella

6

Ho avuto un problema simile, ma ho dovuto controllare anche i file aggiunti. Quindi ho fatto quanto segue:

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

5

git status È tuo amico

Passare alla directory Git per git statusfunzionare:

cd c:/path/to/.git

Impostare una variabile per impostare l'albero di lavoro in modo da non visualizzare l'errore "Questa operazione deve essere eseguita in un albero di lavoro":

WORKTREE=c:/path/to/worktree

Cattura il git status output in una variabile Bash

Utilizzare --porcelainquale garanzia di essere in un formato standard e analizzabile:

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

Se -n (non null), abbiamo delle modifiche.

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

else
  echo 'not changed';
fi

1
Ciò ha il vantaggio di rilevare anche file non tracciati.
Luiz C.,

2

Funziona anche questo:

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

1

Funziona bene. Elencherà anche i file interessati:

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;

1
se non vuoi vedere il diff git diff --no-ext-diff --quiet --exit-codefa anche il lavoro.
Alex

1

Ecco un bel set di funzioni di script Bash che controllano la presenza di un diff, lo stampano per l'utente e chiedono all'utente se vorrebbero eseguire il commit delle modifiche prima della distribuzione. È costruito per un'applicazione Heroku e Python, ma necessita di poche modifiche per qualsiasi altra applicazione.

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
}

Puoi copiare da Gists su: https://gist.github.com/sshadmand/f33afe7c9071bb725105


1

La domanda del PO ha ormai più di 9 anni. Non so cosa abbia man git-statusdetto allora, ma ecco cosa dice ora:

--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.  

Ciò suggerisce che l' --porcelainargomento è adatto per testare lo stato di un repository per le modifiche.

Ha scritto la domanda del PO: "Esiste una sorta di controllo booleano se sono state apportate modifiche dall'ultimo commit o come posso davvero verificare se sono state apportate nuove modifiche al mio repository locale?"

Non penso che bashabbia di per sé tipi di dati booleani , ma questo potrebbe essere abbastanza vicino:

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

Questo può essere rilanciato come if-then-elsemodulo per uno script o eseguito come è nella CLI mentre si trova nella cartella git repo . Altrimenti, utilizzare l' -Copzione con una specifica del percorso per il repository di interesse:

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

Addendum:

  1. Alcuni consigliano di utilizzare l' -u, --untracked-fileopzione per evitare di segnalare lo stato dei file che si desidera ignorare. Nota che questo ha uno sfortunato effetto collaterale : i file appena aggiunti non hanno nemmeno uno stato. L'opzione è utile in alcune situazioni , ma considerala attentamente prima dell'uso.

0

Ecco come lo faccio ...

CHANGES=`git status | grep "working directory clean"`
if [ ! CHANGES -eq "" ] then
    # do stuff here
else
    echo "You have uncommitted changes..."
fi

3
Mi piace usare lo stato git, ma è meglio usare --porcelain negli script e confrontare il risultato con una stringa vuota per nessuna modifica, poiché è garantito che non cambierà in modo incompatibile tra le versioni.
Paul Chernoch,

0
nano checker_git.sh

incolla questo

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

correre sh checker_git.sh gitpath


0

Basato sul commento di @ storm_m2138 alla risposta di @ RyanMoon ( link ) Sto usando il seguente 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" }
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.