Pertanyaan Cara iterasi melalui semua cabang git menggunakan skrip bash


Bagaimana saya bisa melakukan iterasi melalui semua cabang lokal di repositori saya menggunakan skrip bash. Saya perlu iterasi dan memeriksa apakah ada perbedaan antara cabang dan beberapa cabang jarak jauh. Ex

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

Saya perlu melakukan sesuatu seperti yang diberikan di atas, tetapi masalah yang saya hadapi adalah $ (git branch) memberi saya folder di dalam folder repositori bersama dengan cabang-cabang yang ada dalam repositori.

Apakah ini cara yang benar untuk menyelesaikan masalah ini? Atau adakah cara lain untuk melakukannya?

Terima kasih


75
2017-10-02 15:33


asal


Jawaban:


Anda seharusnya tidak menggunakan cabang git saat menulis skrip. Git menyediakan a Antarmuka "pipa" yang secara eksplisit dirancang untuk digunakan dalam scripting (banyak implementasi saat ini dan historis dari perintah Git biasa (tambahkan, checkout, gabung, dll.) gunakan antarmuka yang sama ini).

Perintah pipa yang Anda inginkan adalah git untuk-masing-masing-ref:

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

Catatan: Anda tidak membutuhkan remotes/ awalan pada remote ref kecuali Anda memiliki referensi lain yang menyebabkan origin/master untuk mencocokkan beberapa tempat di jalur pencarian nama ref (lihat “Nama referensi simbolis.…” di bagian Menentukan Revisi dari git-rev-parse (1)). Jika Anda mencoba untuk secara eksplisit menghindari ambiguitas, maka gunakan nama ref lengkap: refs/remotes/origin/master.

Anda akan mendapatkan hasil seperti ini:

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

Anda dapat menyalurkan output ini ke SH.

Jika Anda tidak menyukai gagasan menghasilkan kode shell, Anda bisa menyerah sedikit kekokohan* dan lakukan ini:

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

* Nama ref harus aman dari pembagian kata shell (lihat git-check-ref-format (1)). Secara pribadi saya akan tetap dengan versi sebelumnya (dihasilkan kode shell); Saya lebih percaya diri bahwa tidak ada sesuatu yang tidak pantas yang dapat terjadi dengannya.

Karena Anda ditentukan pesta dan ini mendukung array, Anda dapat menjaga keamanan dan masih menghindari menghasilkan keberanian loop Anda:

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

Anda bisa melakukan sesuatu yang mirip dengan $@ jika Anda tidak menggunakan shell yang mendukung arrayset -- untuk menginisialisasi dan set -- "$@" %(refname) untuk menambahkan elemen).


123
2017-10-02 21:24



Hal ini karena git branch menandai cabang saat ini dengan tanda bintang, misalnya:

$ git branch
* master
  mybranch
$ 

begitu $(git branch) meluas ke misalnya * master mybranch, dan kemudian * memperluas ke daftar file di direktori saat ini.

Saya tidak melihat opsi yang jelas untuk tidak mencetak tanda bintang di tempat pertama; tetapi Anda dapat memotongnya:

$(git branch | cut -c 3-)

39
2017-10-02 15:49



saya akan menyarankan $(git branch|grep -o "[0-9A-Za-z]\+") jika cabang lokal Anda dinamai dengan digit, a-z, dan / atau huruf A-Z saja


4
2017-07-20 03:43



Jawaban yang diterima adalah benar dan benar-benar harus menjadi pendekatan yang digunakan, tetapi memecahkan masalah dalam bash adalah latihan yang bagus dalam memahami bagaimana cangkang bekerja. Trik untuk melakukan ini menggunakan bash tanpa melakukan manipulasi teks tambahan, adalah untuk memastikan output dari git branch tidak pernah diperluas sebagai bagian dari perintah yang akan dieksekusi oleh shell. Ini mencegah tanda bintang dari yang pernah berkembang dalam ekspansi nama file (langkah 8) dari ekspansi shell (lihat http://tldp.org/LDP/Bash-Beginners-Guide/html/sect_03_04.html)

Gunakan bash sementara membangun dengan perintah baca untuk memotong keluaran cabang git menjadi garis. The '*' akan dibaca sebagai karakter literal. Gunakan pernyataan kasus untuk mencocokkannya, berikan perhatian khusus pada pola yang cocok.

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

Tanda bintang di kedua bash kasus membangun dan di substitusi parameter harus lolos dengan backslashes untuk mencegah shell menafsirkannya sebagai karakter pencocokan pola. Ruang-ruang tersebut juga lolos (untuk mencegah tokenisasi) karena Anda benar-benar cocok dengan '*'.


4
2018-01-30 08:32



Saya mengulanginya misalnya:

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;

4
2018-03-21 11:40



Pilihan termudah untuk diingat menurut saya:

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

Keluaran:

bamboo
develop
master

Grep's -o option (--only-matching) membatasi output hanya ke bagian yang cocok dari input.

Karena tidak ada spasi atau * yang valid dalam nama-nama cabang Git, ini mengembalikan daftar cabang tanpa karakter tambahan.

Edit: Jika Anda masuk 'kepala terpisah' negara, Anda perlu memfilter entri saat ini:

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


1
2017-08-01 14:00



Memperluas dari jawaban @ finn (terima kasih!), Berikut ini akan membiarkan Anda beralih ke cabang tanpa membuat skrip shell intervening. Ini cukup kuat, asalkan tidak ada baris baru di nama cabang :)

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

Loop sementara berjalan dalam subkulit, yang biasanya baik-baik saja kecuali Anda mengatur variabel shell yang ingin Anda akses di shell saat ini. Dalam hal ini Anda menggunakan substitusi proses untuk membalikkan pipa:

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

1
2017-10-23 22:31