Jak sprawdzić, czy w bieżącej branży nie ma nic do zatwierdzenia?

172

Celem jest uzyskanie jednoznacznego statusu, który można ocenić za pomocą polecenia powłoki.

Próbowałem, git statusale zawsze zwraca 0, nawet jeśli są elementy do zatwierdzenia.

git status
echo $?  #this is always 0

Mam pomysł, ale myślę, że to raczej zły pomysł.

if [ git status | grep -i -c "[a-z]"> 2 ];
then
 code for change...
else
  code for nothing change...
fi

jakikolwiek inny sposób?


aktualizacja z następującym rozwiązaniem, patrz post Marka Longaira

Próbowałem tego, ale powoduje to problem.

if [ -z $(git status --porcelain) ];
then
    echo "IT IS CLEAN"
else
    echo "PLEASE COMMIT YOUR CHANGE FIRST!!!"
    echo git status
fi

Otrzymuję następujący błąd [: ??: binary operator expected

teraz patrzę na mężczyznę i wypróbowuję różnicę git.

=================== Kod dla mojej nadziei i miej nadzieję, że lepsza odpowiedź ======================

#if [ `git status | grep -i -c "$"` -lt 3 ];
# change to below code,although the above code is simple, but I think it is not strict logical
if [ `git diff --cached --exit-code HEAD^ > /dev/null && (git ls-files --other --exclude-standard --directory | grep -c -v '/$')` ];
then
        echo "PLEASE COMMIT YOUR CHANGE FIRST!!!"
    exit 1

else
    exit 0
fi
9nix00
źródło
4
W zaktualizowanej sekcji wydaje się, że tak naprawdę nie robisz tego, co sugeruje eckes w swojej odpowiedzi - jak mówi, musisz umieścić podwójne cudzysłowy wokół $(git status --porcelain). Ponadto, jeśli chcesz umieścić wykrzykniki w swojej wiadomości, musisz użyć pojedynczych cudzysłowów zamiast podwójnych cudzysłowów - czyli echo 'PLEASE COMMIT YOUR CHANGE FIRST!!!'zamiast tego powinno być
Mark Longair
4
jak mówi Mark: musisz umieścić podwójne cudzysłowy wokół$(git status --porcelain) , tak jak powiedziałem!
eckes
1
Te pytania byłyby o wiele bardziej przydatne, gdyby nie zawierały części odpowiedzi.
oberlies
@ 9nix00 rób to, co ci powiedziano, edytuj i napraw błąd w powyższym skrypcie powłoki: BŁĄD: if [-z $ (jakieś polecenie)] NAPRAW: if [-z "$ (jakieś polecenie)"]
MarcH

Odpowiedzi:

232

Alternatywą dla sprawdzenia, czy wyjście git status --porcelainjest puste, jest osobne przetestowanie każdego warunku, na którym Ci zależy. Na przykład nie zawsze można przejmować się tym, czy w danych wyjściowych programu git status.

Na przykład, aby sprawdzić, czy są jakieś lokalne zmiany niestacjonarne, możesz spojrzeć na kod powrotu:

git diff --exit-code

Aby sprawdzić, czy są jakieś zmiany, które są tymczasowo, ale nie zostały zatwierdzone, możesz użyć kodu powrotu:

git diff --cached --exit-code

Na koniec, jeśli chcesz wiedzieć, czy w drzewie roboczym znajdują się nieśledzone pliki, które nie są ignorowane, możesz sprawdzić, czy dane wyjściowe następującego polecenia są puste:

git ls-files --other --exclude-standard --directory

Aktualizacja: Pytasz poniżej, czy możesz zmienić to polecenie, aby wykluczyć katalogi w danych wyjściowych. Możesz wykluczyć puste katalogi, dodając --no-empty-directory, ale myślę, że aby wykluczyć wszystkie katalogi w tym wyjściu, będziesz musiał przefiltrować dane wyjściowe, na przykład za pomocą:

git ls-files --other --exclude-standard --directory | egrep -v '/$'

-vNa egrepdrodze do wyjścia tylko linie, które nie pasują do wzorca, a wzór pasuje do każdego wiersza, który kończy się /.

Mark Longair
źródło
Oparłem się na tych wskazówkach i mam problem. to znaczy użyj git ls-files --other --exclude-standard --directory pobierz listę zawierającą katalogi. czy jest jakiś sposób wykluczyć ten katalog?
9nix00
tak, tego chcę. i aktualizuję swój post o nowy kod skryptu. Myślę, że twoja sugestia jest bardziej logiczna, chociaż więcej kodu lol ... i mam nadzieję, że pojawiają się lepsze odpowiedzi.
9nix00
3
@albfan: jest na stronie podręcznika git-diff : "Spraw, aby program zakończył pracę z kodami podobnymi do diff (1). Oznacza to, że wychodzi z 1, jeśli były różnice, a 0 oznacza brak różnic."
Mark Longair
Wystarczy zaznaczyć, że istnieje co najmniej od 2007 r. 13da0fc0 , bardzo przydatne dla skryptów powłoki i w pełni kompatybilne ze starszymi wersjami git
albfan
10
--quiet(co implikuje --exit-code) również wycisza wyjście, dla tych, którzy chcą tylko kodu zakończenia.
phs
113

Wartość zwracana po git statusprostu informuje cię o kodzie zakończenia programu git status, a nie, czy są jakieś modyfikacje do zatwierdzenia .

Jeśli chcesz uzyskać wersję git statuswyjściową bardziej czytelną dla komputera , spróbuj

git status --porcelain

Zobacz opis, git statusaby uzyskać więcej informacji na ten temat.

Przykładowe użycie (skrypt po prostu sprawdza, czy git status --porcelaindaje jakieś wyjście, nie jest wymagana analiza):

if [ -n "$(git status --porcelain)" ]; then
  echo "there are changes";
else
  echo "no changes";
fi

Zwróć uwagę, że musisz zacytować łańcuch do przetestowania, czyli wyjście git status --porcelain. Aby uzyskać więcej wskazówek dotyczących konstrukcji testowych, zapoznaj się z Przewodnikiem po zaawansowanych skryptach Bash ( Porównanie ciągów w sekcji ).

eckes
źródło
cześć, dajesz dobrą sugestię, próbowałem, ale w skrypcie powoduje to jakiś problem, poprawiłem go, jeśli użyjemy tego if [-z $ (git status --porcelain)]; dostanie jakiś błąd, [: ??: oczekiwano operatora binarnego, znajduję instrukcję i używam jej, jeśli [-z $ (stan git --short)]; to może zadziałać, dzięki!
9nix00
przepraszam, nadal występuje problem. kiedy zatwierdzenie jest czyste. użyj porcelany i krótkich obu ok. ale kiedy zatwierdzenie nie jest czyste. spowoduje to błąd. [: ??: oczekiwano operatora binarnego. Myślę, że może powinniśmy spróbować użyć base64 do zakodowania. pozwól mi spróbować! pobieranie narzędzi poleceń base64 .... lol
9nix00
powoduje problem, gdy zatwierdzenie nie jest czyste.
9nix00
1
Świetne rozwiązanie. Aby zwiększyć niezawodność, można dołączyć || echo nodo zastępowania poleceń, aby obszar roboczy nie był omyłkowo zgłaszany jako czysty, jeśli git statuszasadniczo zawiedzie. Ponadto, twój kod jest (godne pochwały) zgodny z POSIX, ale skoro łączysz się z przewodnikiem po bashu, pozwól mi dodać, że jeśli używasz basha [[ ... ]]zamiast zgodnego z POSIX [ ... ], nie musisz podwójnie cytować podstawiania poleceń (chociaż nie zaszkodzi) [[ -z $(git status --porcelain) ]].
mklement0
@eckes Zacząłem nowe repozytorium kilka dni temu, dodałem zatwierdzenie, próbowałem napisać kilka haków przed zatwierdzeniem i sprawdzić, co ma zostać popełnione, a to, co mówisz, nie działa w mojej sprawie.
alinsoar
33

Jeśli jesteś podobny do mnie, chcesz wiedzieć, czy są:

1) zmiany w istniejących plikach 2) nowo dodane pliki 3) usunięte pliki

a konkretnie nie chcę wiedzieć o 4) nieśledzonych plikach.

To powinno wystarczyć:

git status --untracked-files=no --porcelain

Oto mój kod bash do wyjścia ze skryptu, jeśli repozytorium jest czyste. Używa krótkiej wersji opcji nieśledzonych plików:

[[ -z $(git status -uno --porcelain) ]] && echo "this branch is clean, no need to push..." && kill -SIGINT $$;
nastrój
źródło
4
+1 za —untracked-files=no; Myślę, że twój test można uprościć do [[ -z $(git status --untracked-files=no --porcelain) ]]. git statusNie należy pisać na stderr, chyba że coś pójdzie nie tak fundamentalne - a potem nie chcą zobaczyć, że wyjście. (Jeśli chcesz bardziej niezawodnego zachowania w tym przypadku, dołącz || echo nodo podstawienia polecenia, aby test czystości nadal kończył się niepowodzeniem). Porównania ciągów / -zoperator może obsługiwać ciągi wieloliniowe - nie ma potrzeby tail.
mklement0
2
dzięki @ mklement0, nawet trochę krócej:[[ -z $(git status -u no --porcelain) ]]
moodboom
1
poprawka: moja krótsza wersja właściwie tylko sprawdza status pliku o nazwie „nie”! Bzzt. Powinno być: [[ -z $(git status -uno --porcelain) ]]
moodboom
2
Doceniam kontynuację; to subtelny błąd - lekcja jest taka, że krótkie opcje z opcjonalnymi argumentami muszą mieć argument dołączany bezpośrednio , bez spacji między nimi. Co powiesz na włączenie poprawionej krótkiej wersji bezpośrednio do odpowiedzi?
mklement0
9

Możliwe jest połączenie git status --porcelainz prostym greptestem.

if git status --porcelain | grep .; then
    echo Repo is dirty
else
    echo Repo is clean
fi

Czasami używam tego jako prostego linijka:

# pull from origin if our repo is clean
git status --porcelain | grep . || git pull origin master

Dodaj -qsdo polecenia grep, aby było ciche.

Steve Prentice
źródło
2
+1 za elegancję; niewielkie zastrzeżenie: powinno git statuszakończyć się niepowodzeniem (np. uszkodzone repozytorium), Twój test omyłkowo zgłosi czysty obszar roboczy. Jedną z opcji jest użycie git status --porcelain 2>&1, ale to spowodowałoby `` zjedzenie '' komunikatu o błędzie, gdybyś użył grep z -q. (Zajmujące się że straci elegancję: (git status --porcelain || echo err) | grep -q .)
mklement0
alternatywnie można napisać:test -z "$(git status --porcelain)" || git pull origin master
VasiliNovikov
5

Z kodu źródłowego git jest skrypt sh, który zawiera następujące elementy.

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
}

Ten sniplet pokazuje, jak można go używać git diff-filesi git diff-indexdowiedzieć się, czy są jakieś zmiany w znanych wcześniej plikach. Nie pozwala jednak dowiedzieć się, czy nowy nieznany plik został dodany do drzewa roboczego.

Arrowmaster
źródło
działa to dobrze, z wyjątkiem nowych plików. możemy to dodać. Jeśli ! git ls-files --other --exclude-standard --directory | grep -c -v '/ $' then exit 0 else echo "Zatwierdź nowy plik, jeśli nie chcesz go dodać, dodaj go do pliku git-ignore." zjazd 1 fi
9nix00
Samo if [ -n "$(git ls-files --others --exclude-standard)" ]bez dodatkowego pipingu lub grepingu powinno wystarczyć do wykrycia niezatwierdzonych plików.
Arrowmaster
5

zrobiłbym test na tym:

git diff --quiet --cached

lub to jest wyraźne:

git diff --quiet --exit-code --cached

gdzie:

- kod-wyjścia

Zakończ program używając kodów podobnych do diff (1). Oznacza to, że wychodzi z 1, jeśli były różnice, a 0 oznacza brak różnic.

--cichy

Wyłącz wszystkie wyjścia programu. Implikuje - kod-zakończenia

archf
źródło
3

Trochę się spóźniłem w dyskusji, ale jeśli tylko potrzebujesz kodu zakończenia o wartości 0, jeśli git status --porcelainnic nie zwraca i! = 0, spróbuj tego:

exit $( git status --porcelain | wc -l )

Spowoduje to, że liczba wierszy będzie kodem zakończenia, z ryzykiem wystąpienia problemów, gdy jest ich więcej niż 255. Więc

exit $( git status --porcelain | head -255 | wc -l )

rozważy to;)

Skeeve
źródło
1
Zasadniczo będzie to niezdefiniowane, jeśli będzie więcej niż 255 wierszy danych wyjściowych.
tripleee
Dobrze zauważony, dzięki!
Skeeve
2

Używam tego w skrypcie, aby mieć:

  • 0 kiedy wszystko jest czyste
  • 1, gdy istnieje różnica lub nieśledzone pliki

    [-z "$ (stan git --porcelain)"]

grubszy
źródło
używanie if ! git diff --quiet; thenjest czystsze i wydajniejsze (myślę). Innymi słowy, użyj kodu zakończenia, a nie standardowego wyjścia.
Alexander Mills
1
@AlexanderMills git diff --quietzachowuje się inaczej niż w git status --porcelainprzypadku zmian w pamięci podręcznej.
Martin von Wittich
0

Niezbyt ładne, ale działa:

git status | grep -qF 'working directory clean' || echo "DIRTY"

Nie jestem pewien, czy wiadomość jest zależna od ustawień regionalnych, więc może wstaw na LANG=Cpoczątku.

Tilman Vogel
źródło