Bagaimana cara memeriksa apakah tidak ada yang harus dilakukan di cabang saat ini?

172

Tujuannya adalah untuk mendapatkan status tidak ambigu yang dapat dievaluasi dalam perintah shell.

Saya mencoba git statustetapi selalu mengembalikan 0, bahkan jika ada item yang dikomit.

git status
echo $?  #this is always 0

Saya punya ide tapi saya pikir itu ide yang buruk.

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

ada cara lain?


perbarui dengan pemecahan berikut, lihat posting Mark Longair

Saya mencoba ini tetapi menyebabkan masalah.

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

Saya mendapatkan kesalahan berikut [: ??: binary operator expected

sekarang, saya melihat pria itu dan mencoba git diff.

=================== kode untuk harapan saya, dan berharap jawaban yang lebih baik ======================

#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
sumber
4
Di bagian yang diperbarui, tampaknya Anda tidak benar-benar melakukan apa yang disarankan burung unta dalam jawabannya - seperti katanya, Anda perlu menempatkan tanda kutip ganda di sekitar $(git status --porcelain). Juga, jika Anda ingin menempatkan tanda seru dalam pesan Anda, Anda harus menggunakan tanda kutip tunggal daripada tanda kutip ganda - yaitu harus echo 'PLEASE COMMIT YOUR CHANGE FIRST!!!'sebaliknya
Mark Longair
4
seperti yang dikatakan Mark: Anda perlu menempatkan tanda kutip ganda di sekitar$(git status --porcelain) , seperti yang saya katakan!
eckes
1
Pertanyaan-pertanyaan ini akan jauh lebih bermanfaat, jika tidak termasuk bagian dari jawaban.
Oberlies
@ 9nix00 lakukan apa yang diperintahkan kepada Anda dan edit dan perbaiki bug di skrip shell Anda di atas: BUG: if [-z $ (perintah tertentu)] FIX: if [-z "$ (perintah tertentu)"]
MarcH

Jawaban:

232

Alternatif untuk menguji apakah output git status --porcelainkosong adalah dengan menguji setiap kondisi yang Anda pedulikan secara terpisah. Seseorang mungkin tidak selalu peduli, misalnya, jika ada file yang tidak terlacak dalam output dari git status.

Misalnya, untuk melihat apakah ada perubahan lokal yang tidak dipentaskan, Anda dapat melihat kode pengembalian:

git diff --exit-code

Untuk memeriksa apakah ada perubahan yang dilakukan tetapi tidak dilakukan, Anda dapat menggunakan kode pengembalian:

git diff --cached --exit-code

Akhirnya, jika Anda ingin tahu tentang apakah ada file yang tidak dilacak di pohon kerja Anda yang tidak diabaikan, Anda dapat menguji apakah output dari perintah berikut ini kosong:

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

Pembaruan: Anda bertanya di bawah ini apakah Anda dapat mengubah perintah itu untuk mengecualikan direktori dalam output. Anda dapat mengecualikan direktori kosong dengan menambahkan --no-empty-directory, tetapi untuk mengecualikan semua direktori dalam output itu saya pikir Anda harus memfilter output, seperti dengan:

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

The -vuntuk egrepsarana untuk hanya output baris yang tidak cocok dengan pola, dan pola cocok setiap baris yang berakhir dengan /.

Mark Longair
sumber
Saya bersandar pada tips ini dan memiliki masalah. yaitu, gunakan git ls-files --lain --exclude-standard --directory dapatkan daftar sertakan direktori. apakah ada cara mengecualikan direktori ini?
9nix00
ya, ini yang saya inginkan. dan saya memperbarui posting saya untuk kode-skrip baru. Saya pikir saran Anda lebih logis ketat meskipun lebih banyak kode lol ... dan Semoga jawaban yang lebih baik muncul.
9nix00
3
@albfan: ada di halaman manual git-diff : "Buat program keluar dengan kode yang mirip dengan diff (1). Artinya, ia keluar dengan 1 jika ada perbedaan dan 0 berarti tidak ada perbedaan."
Mark Longair
Hanya untuk menunjukkan, Sudah ada setidaknya sejak 2007 13da0fc0 , sangat berguna untuk skrip shell, dan sepenuhnya kompatibel dengan versi git yang lebih lama
albfan
10
--quiet(yang menyiratkan --exit-code) juga membisukan output, bagi mereka yang hanya ingin kode keluar.
phs
113

Nilai balik git statushanya memberi tahu Anda kode keluar git status, bukan jika ada modifikasi yang harus dilakukan.

Jika Anda ingin versi yang lebih mudah dibaca dari komputer git status, coba

git status --porcelain

Lihat deskripsi git statusuntuk informasi lebih lanjut tentang itu.

Penggunaan sampel (skrip hanya menguji jika git status --porcelainmemberikan output apa pun, tidak perlu penguraian):

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

Harap dicatat bahwa Anda harus mengutip string untuk diuji, yaitu output dari git status --porcelain. Untuk petunjuk lebih lanjut tentang konstruksi tes, lihat Panduan Script Bash Lanjutan ( perbandingan string Bagian ).

eek
sumber
hai, Anda memberikan saran yang baik, saya mencobanya, tetapi dalam skrip, itu menyebabkan beberapa masalah, saya memperbaikinya, jika kita menggunakan ini jika [-z $ (git status --porcelain)]; itu akan mendapatkan beberapa kesalahan, [: ??: operator biner diharapkan saya menemukan manual dan menggunakan ini jika [-z $ (git status --short)]; ini bisa berhasil, terima kasih!
9nix00
maaf, masih ada masalah. ketika komit bersih. gunakan porselen dan pendek keduanya ok tetapi ketika komit tidak bersih. itu akan menyebabkan kesalahan. [: ??: operator biner diharapkan. Saya pikir mungkin kita harus mencoba menggunakan base64 untuk menyandikannya. biarkan aku mencoba! mengunduh alat perintah base64 .... lol
9nix00
itu menyebabkan masalah ketika komit tidak bersih.
9nix00
1
Solusi bagus Untuk menambah ketahanan Anda bisa menambahkan || echo nosubstitusi perintah sehingga ruang kerja tidak salah dilaporkan bersih jika git statusgagal secara mendasar. Juga, kode Anda (terpuji) kompatibel dengan POSIX, tetapi karena Anda menautkan ke panduan bash, izinkan saya menambahkan bahwa jika Anda menggunakan bash, [[ ... ]]bukan yang kompatibel dengan POSIX [ ... ], Anda tidak perlu membuat penawaran kutip ganda substitusi perintah (meskipun tidak ada salahnya): [[ -z $(git status --porcelain) ]].
mklement0
@ cek saya mulai repo baru beberapa hari yang lalu, saya menambahkan komit, saya mencoba untuk menulis beberapa pra-komit-kait dan memeriksa apa yang harus dilakukan dan apa yang Anda katakan tidak bekerja pada kasus saya.
alinsoar
33

Jika Anda seperti saya, Anda ingin tahu apakah ada:

1) perubahan pada file yang ada 2) file yang baru ditambahkan 3) file yang dihapus

dan secara khusus tidak ingin tahu tentang 4) file yang tidak terlacak.

Ini harus dilakukan:

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

Inilah kode bash saya untuk keluar dari skrip jika repo bersih. Ini menggunakan versi pendek dari opsi file yang tidak dilacak:

[[ -z $(git status -uno --porcelain) ]] && echo "this branch is clean, no need to push..." && kill -SIGINT $$;
moodboom
sumber
4
+1 untuk —untracked-files=no; Saya pikir tes Anda dapat disederhanakan [[ -z $(git status --untracked-files=no --porcelain) ]]. git statusseharusnya tidak menulis ke stderr, kecuali sesuatu yang fundamental beres - dan kemudian Anda tidak ingin melihat output itu. (Jika Anda menginginkan perilaku yang lebih kuat dalam peristiwa itu, tambahkan || echo nosubstitusi perintah sehingga pengujian kebersihan masih gagal). Perbandingan string / -zoperator dapat menangani string multi-line - tidak perlu tail.
mklement0
2
terima kasih @ mklement0, bahkan sedikit lebih pendek:[[ -z $(git status -u no --porcelain) ]]
moodboom
1
koreksi: versi saya yang lebih pendek sebenarnya hanya memeriksa status pada file bernama "tidak"! Bzzt. Seharusnya: [[ -z $(git status -uno --porcelain) ]]
moodboom
2
Saya menghargai tindak lanjutnya; itu bug halus - pelajarannya adalah bahwa opsi pendek dengan argumen opsional harus memiliki argumen ditambahkan secara langsung , tanpa spasi putih di antaranya. Bagaimana dengan memasukkan versi pendek yang diperbaiki langsung ke jawaban Anda?
mklement0
9

Sangat mungkin untuk menggabungkan git status --porcelaindengan sederhana grepuntuk melakukan tes.

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

Saya menggunakan ini sebagai kalimat sederhana:

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

Tambahkan -qske perintah grep Anda untuk membuatnya diam.

Steve Prentice
sumber
2
+1 untuk keanggunan; peringatan kecil: harus git statusgagal fatal (misalnya, repo rusak), tes Anda akan keliru melaporkan ruang kerja yang bersih . Salah satu opsi adalah menggunakan git status --porcelain 2>&1, tetapi itu akan 'memakan' pesan kesalahan jika Anda menggunakan grep with -q. (Berurusan dengan yang akan kehilangan keanggunan: (git status --porcelain || echo err) | grep -q .)
mklement0
sebagai alternatif, seseorang dapat menulis:test -z "$(git status --porcelain)" || git pull origin master
VasiliNovikov
5

Dari kode sumber git ada skrip sh yang mencakup yang berikut.

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
}

Cuplikan ini menunjukkan bagaimana kemungkinannya untuk menggunakan git diff-filesdan git diff-indexuntuk mengetahui apakah ada perubahan pada file yang diketahui sebelumnya. Namun itu tidak memungkinkan Anda untuk mengetahui apakah file baru yang tidak dikenal telah ditambahkan ke pohon kerja.

Arrowmaster
sumber
ini berfungsi dengan baik kecuali untuk file baru. kita bisa menambahkan ini. jika! git ls-files --other --exclude-standard --directory | grep -c -v '/ $' lalu keluar dari 0 echo lagi "silakan komit file baru Anda, jika Anda tidak ingin menambahkannya, silakan tambahkan dalam file git-diabaikan." keluar 1 fi
9nix00
Hanya if [ -n "$(git ls-files --others --exclude-standard)" ]tanpa ada pemipaan atau penyapuan tambahan harus cukup untuk mendeteksi file yang tidak terlacak.
Arrowmaster
5

Saya akan melakukan tes ini:

git diff --quiet --cached

atau ini menjadi eksplisit:

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

dimana:

--exit-code

Buat program keluar dengan kode yang mirip dengan diff (1). Artinya, ia keluar dengan 1 jika ada perbedaan dan 0 berarti tidak ada perbedaan.

--diam

Nonaktifkan semua output program. Menyiratkan --exit-code

Archf
sumber
3

Saya agak terlambat dalam diskusi, tetapi jika hanya Anda perlu memiliki kode keluar 0 jika git status --porcelaintidak mengembalikan apa pun dan! = 0 lainnya, coba ini:

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

Ini akan membuat jumlah baris menjadi kode keluar, dengan risiko mendapatkan masalah ketika ada lebih dari 255 baris. Begitu

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

akan menjelaskan hal itu;)

Skeeve
sumber
1
Ini pada dasarnya tidak akan ditentukan jika ada lebih dari 255 baris output.
tripleee
Terlihat dengan baik, Terima kasih!
Skeeve
2

Saya menggunakan ini dalam skrip untuk memiliki:

  • 0 saat semuanya bersih
  • 1 ketika ada file yang berbeda atau tidak terlacak

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

lebih kotor
sumber
menggunakan if ! git diff --quiet; thenlebih bersih dan lebih banyak performant (saya pikir). Dengan kata lain, gunakan kode keluar, bukan stdout.
Alexander Mills
1
@AlexanderMills git diff --quietberperilaku berbeda dari git status --porcelainuntuk perubahan yang di-cache.
Martin von Wittich
0

Tidak cantik, tetapi bekerja:

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

Tidak yakin apakah pesan itu tergantung pada lokal, jadi mungkin letakkan LANG=Cdi depan.

Tilman Vogel
sumber