Hapus cabang pelacakan tidak lagi di remote

1173

Apakah ada cara sederhana untuk menghapus semua cabang pelacakan yang setara jarak jauh tidak ada lagi?

Contoh:

Cabang (lokal dan jarak jauh)

  • menguasai
  • asal / master
  • origin / bug-fix-a
  • origin / bug-fix-b
  • origin / bug-fix-c

Secara lokal, saya hanya memiliki cabang master. Sekarang saya perlu mengerjakan perbaikan bug , jadi saya memeriksanya, mengerjakannya, dan mendorong perubahan ke remote. Selanjutnya saya melakukan hal yang sama dengan bug-fix-b .

Cabang (lokal dan jarak jauh)

  • menguasai
  • bug-fix-a
  • bug-fix-b
  • asal / master
  • origin / bug-fix-a
  • origin / bug-fix-b
  • origin / bug-fix-c

Sekarang saya memiliki master cabang lokal , bug-fix-a , bug-fix-b . Pemelihara cabang Master akan menggabungkan perubahan saya menjadi master dan menghapus semua cabang yang telah digabung.

Jadi kondisi saat ini sekarang:

Cabang (lokal dan jarak jauh)

  • menguasai
  • bug-fix-a
  • bug-fix-b
  • asal / master
  • origin / bug-fix-c

Sekarang saya ingin memanggil beberapa perintah untuk menghapus cabang (dalam hal ini bug-fix-a , bug-fix-b ), yang tidak lagi terwakili dalam repositori jarak jauh.

Itu akan menjadi sesuatu seperti perintah yang ada git remote prune origin, tetapi lebih seperti git local prune origin.

Mailo Světel
sumber

Jawaban:

1282

git remote prune origin cabang pelacakan cabang tidak pada remote.

git branch --merged daftar cabang yang telah digabung ke cabang saat ini.

xargs git branch -d menghapus cabang yang terdaftar pada input standar.

Hati-hati menghapus cabang yang terdaftar oleh git branch --merged. Daftar tersebut dapat menyertakan masteratau cabang lain yang Anda inginkan untuk tidak dihapus.

Untuk memberi diri Anda kesempatan untuk mengedit daftar sebelum menghapus cabang, Anda dapat melakukan hal berikut dalam satu baris:

git branch --merged >/tmp/merged-branches && \
  vi /tmp/merged-branches && xargs git branch -d </tmp/merged-branches
aubreypwd
sumber
17
Baris pertama dari cabang yang digabung ada * masterdi sistem saya. Perintah berikut bekerja untuk saya:git branch -d $(git branch --merged |tail -n +2)
Trendfischer
99
Jika saya aktif developmaka git branch --mergedtermasuk master! Anda mungkin (pasti!) Tidak ingin menghapus itu. Juga saya pikir itu harus di git branch -dmana huruf kecil -dberarti "hapus aman" misalnya hanya menghapus jika digabungkan.
thom_nic
11
Tampaknya solusi yang lebih baik disediakan di sana .
Sergey Brunov
34
Penggabungan yang dihapus berguna, tetapi tidak sama dengan "menghapus cabang bukan pada jarak jauh."
dlsso
11
Cukup gunakan grep untuk mengecualikan master:git branch --merged | grep -v "master" >/tmp/merged-branches && vi /tmp/merged-branches && xargs git branch -d </tmp/merged-branches
geniass
592

Setelah perintah

git fetch -p

menghapus referensi jarak jauh, saat Anda menjalankan

git branch -vv

itu akan menunjukkan 'hilang' sebagai status jarak jauh. Sebagai contoh,

$ git branch -vv
  master                 b900de9 [origin/master: behind 4] Fixed bug
  release/v3.8           fdd2f4e [origin/release/v3.8: behind 2] Fixed bug
  release/v3.9           0d680d0 [origin/release/v3.9: behind 2] Updated comments
  bug/1234               57379e4 [origin/bug/1234: gone] Fixed bug

Jadi, Anda dapat menulis skrip sederhana untuk menghapus cabang lokal yang menjadi remote:

git fetch -p && for branch in $(git branch -vv | grep ': gone]' | awk '{print $1}'); do git branch -D $branch; done

Perhatikan bahwa di atas menggunakan perintah "porselen" git branchuntuk mendapatkan status upstream.

Cara lain untuk mendapatkan status ini adalah dengan menggunakan perintah "plumbing" git for-each-refdengan variabel interpolasi %(upstream:track), yang akan [gone]seperti di atas.

Pendekatan ini agak lebih aman, karena tidak ada risiko pencocokan secara tidak sengaja pada bagian dari pesan komit.

git fetch -p && for branch in $(git for-each-ref --format '%(refname) %(upstream:track)' refs/heads | awk '$2 == "[gone]" {sub("refs/heads/", "", $1); print $1}'); do git branch -D $branch; done
jason.rickman
sumber
8
@KrzysztofWende - bukan pada Solaris dan beberapa BSD dan beberapa OS X :)
jww
4
Sepertinya ini juga akan menghapus semua cabang yang telah "hilang" di pesan komit terakhir.
dlsso
11
@ dlsso Jika pesan komit terakhir berisi string ": pergi]" maka ya itu akan dihapus juga. Anda dapat membuatnya lebih kuat dengan mengorbankan kesederhanaan dengan memiliki awk / gawk tambahan untuk menghapus pesan komit. git branch -vv | gawk '{print $1,$4}' | grep 'gone]' | gawk '{print $1}'
jason.rickman
2
Sebagai balasan untuk komentar saya sebelumnya (pertanyaan), cabang saat ini memiliki * sebagai bidang pertama. Jika kebetulan juga ada dalam daftar cabang "hilang", $ 1 akan ditetapkan * dan akan ditafsirkan sebagai filespec dengan awk meludah nama file dan folder. Aku menghilangkan ekspresi grep dan telah awk melakukan semua penyaringan: awk '/: gone]/{if ($1!="*") print $1}'. Ini sekarang berfungsi seperti yang diharapkan.
rhaben
5
@ ahmedbhs karena perintah menggunakan tanda kutip tunggal 'Anda perlu menggunakan tanda kutip ganda "untuk mengelilingi seluruh perintah. Juga, git alias yang merupakan perintah shell (seperti ini) memerlukan! di awal. Ini bekerja untuk saya:test = "!git fetch -p && for branch in `git branch -vv | grep ': gone]' | awk '{print $1}'`; do git branch -D $branch; done"
jason.rickman
307

Sebagian besar jawaban ini sebenarnya tidak menjawab pertanyaan awal. Saya melakukan banyak penggalian dan ini adalah solusi terbersih yang saya temukan. Ini adalah versi yang sedikit lebih menyeluruh dari jawaban itu:

  1. Periksa cabang default Anda. Biasanyagit checkout master
  2. Lari git fetch -p && git branch -vv | awk '/: gone]/{print $1}' | xargs git branch -d

Penjelasan:

Bekerja dengan memangkas cabang pelacakan Anda kemudian menghapus yang lokal yang menunjukkan mereka "hilang" git branch -vv.

Catatan:

Jika bahasa Anda diatur ke sesuatu selain bahasa Inggris Anda perlu mengubah goneke kata yang sesuai. Cabang yang bersifat lokal saja tidak akan disentuh. Cabang yang telah dihapus pada jarak jauh tetapi tidak digabung akan menampilkan pemberitahuan tetapi tidak dihapus di lokal. Jika Anda ingin menghapus mereka juga berubah -dke -D.

dlsso
sumber
2
untuk OS Perancis yang hilang harus diubah karena perbedaan
Mohamed EL HABIB
4
harus menambahkan LANG = en_US sebelum git branch untuk memaksa bahasa Inggris: git fetch --prune && LANG = en_US git branch -vv | awk '/: gone] / {print $ 1}' | xargs git branch -d
Mohamed EL HABIB
3
Saya akan menambahkan git checkout master && ...di awal perintah.
iarroyo
2
Ini berbahaya ketika Anda berada di cabang yang seharusnya dihapus - dalam hal ini kolom pertama adalah '*', yang kemudian diteruskan ke xargs. Untuk meningkatkan ini, tambahkan strip karakter '*' sebelum meneruskan output ke awk: sed -e 's / ^ * //'
meeee
6
Cermat! Ada kasus tepi yang akan menghasilkan penghapusan semua cabang lokal Anda: Jika Anda saat ini pada cabang yang dihapus pada jarak jauh, output dari git branch -vvakan mulai dengan tanda bintang yang pada akhirnya akan menghasilkan eksekusi git branch -d *. Berikut adalah versi yang ditambal yang akan mengabaikan garis dengan tanda bintang:git branch -vv | grep ': gone]'| grep -v "\*" | awk '{ print $1; }' | xargs -r git branch -d
kcm
210

Saya biasanya tidak akan menjawab pertanyaan yang sudah memiliki 16 jawaban, tetapi semua jawaban lainnya salah, dan jawaban yang benar sangat sederhana. Pertanyaannya mengatakan, "Apakah ada cara sederhana untuk menghapus semua cabang pelacakan yang setara jarak jauh tidak ada lagi?"

Jika "sederhana" berarti menghapus semuanya sekaligus, tidak rapuh, tidak berbahaya, dan tanpa bergantung pada alat yang tidak dimiliki semua pembaca, maka jawaban yang tepat adalah: tidak.

Beberapa jawaban sederhana, tetapi mereka tidak melakukan apa yang diminta. Yang lain melakukan apa yang diminta, tetapi tidak sederhana: semua bergantung pada penguraian output Git melalui perintah manipulasi teks atau bahasa scripting, yang mungkin tidak ada pada setiap sistem. Selain itu, sebagian besar saran menggunakan perintah porselen, yang outputnya tidak dirancang untuk diuraikan oleh skrip ("porselen" mengacu pada perintah yang dimaksudkan untuk operasi manusia; skrip harus menggunakan perintah "plumbing" tingkat rendah).

Bacaan lebih lanjut:


Jika Anda ingin melakukan ini dengan aman, untuk kasus penggunaan dalam pertanyaan (cabang pelacakan pengumpulan sampah yang telah dihapus di server tetapi masih ada sebagai cabang lokal) dan dengan perintah Git tingkat tinggi saja, Anda harus

  • git fetch --prune(atau git fetch -p, yang merupakan alias, atau git prune remote originyang melakukan hal yang sama tanpa mengambil, dan mungkin bukan yang Anda inginkan sebagian besar waktu).
  • Perhatikan semua cabang jarak jauh yang dilaporkan telah dihapus. Atau, untuk menemukannya nanti, git branch -v(cabang pelacakan yatim mana pun akan ditandai "[hilang]").
  • git branch -d [branch_name] pada setiap cabang pelacakan yatim

(yang mana beberapa jawaban lain usulkan).

Jika Anda ingin membuat skrip solusi, maka for-each-refadalah titik awal Anda, seperti dalam jawaban Mark Longair di sini dan jawaban ini untuk pertanyaan lain , tapi saya tidak bisa melihat cara untuk mengeksploitasinya tanpa menulis loop skrip shell, atau menggunakan xargs atau sesuatu .


Penjelasan latar belakang

Untuk memahami apa yang terjadi, Anda perlu menghargai itu, dalam situasi pelacakan cabang, Anda tidak memiliki satu cabang, tetapi tiga. (Dan ingat bahwa "cabang" berarti hanya penunjuk ke komit.)

Diberikan cabang pelacakan feature/X, repositori jarak jauh (server) akan memiliki cabang ini dan menyebutnya feature/X. Repositori lokal Anda memiliki cabang remotes/origin/feature/Xyang artinya, "Ini adalah remote yang memberi tahu saya fitur / cabang X-nya, terakhir kali kami berbicara," dan akhirnya, repositori lokal memiliki cabang feature/Xyang menunjuk ke komit terbaru Anda, dan dikonfigurasikan ke "lacak" remotes/origin/feature/X, artinya Anda dapat menarik dan mendorong agar tetap selaras.

Pada titik tertentu, seseorang telah menghapus feature/Xdi remote. Sejak saat itu, Anda ditinggalkan dengan lokal Anda feature/X(yang mungkin Anda tidak mau lagi, karena bekerja pada fitur X mungkin selesai), dan Anda remotes/origin/feature/Xyang tentu saja tidak berguna karena satu-satunya tujuan adalah untuk mengingat keadaan cabang server .

Dan Git akan membiarkan Anda secara otomatis membersihkan yang mubazir remotes/origin/feature/X- itulah yang git fetch --pruneterjadi - tetapi untuk beberapa alasan, itu tidak memungkinkan Anda secara otomatis menghapus sendiri feature/X... meskipun Anda feature/Xmasih berisi informasi pelacakan yatim, sehingga ia memiliki informasi untuk mengidentifikasi bekas cabang pelacakan yang telah sepenuhnya digabung. (Lagi pula, itu dapat memberi Anda informasi yang memungkinkan Anda melakukan operasi sendiri.)

Andrew Spencer
sumber
3
Ini adalah jawaban yang jauh lebih aman. Selain itu, ini akan berfungsi jika Anda menggunakan alur kerja "Squash and Merge", tidak seperti jawaban yang dipilih.
Jake Levitt
3
Ini benar-benar hanya menjawab bagian mudah dari pertanyaan "bagaimana menemukan cabang yang hilang" (dan itu dengan perintah yang sama seperti yang sudah diposting oleh jason.rickman pada tahun 2015) tetapi kemudian memberitahu Anda untuk menghapus semua cabang secara manual yang persis seperti apa OP tidak mau melakukan.
Voo
4
@ Voo Itulah inti dari jawabannya: bukan untuk memberi tahu Anda bagaimana melakukannya (itu hanya bonus) tetapi untuk memberi tahu Anda bahwa jawabannya adalah tidak ada cara yang mudah dan sederhana untuk melakukannya. Mana jawaban yang benar untuk pertanyaan seperti yang dirumuskan.
Andrew Spencer
1
"Jika Anda ingin melakukan ini dengan aman, untuk kasus penggunaan dalam pertanyaan .." - yang meniadakan sebagian besar klaim paragraf pertama. "[Git] dapat memberi Anda informasi yang memungkinkan Anda melakukan operasi sendiri" - kami adalah programmer, jadi mengingat informasi itu sebagai daftar (yang diperlihatkan) tugasnya masih sederhana (mis. xargs). Ada juga git aliasuntuk menyederhanakan sejumlah kasus.
user2864740
2
@ user2864740 Beberapa pembaca mungkin menganggap bahwa menulis skrip bash kecil termasuk dalam definisi mereka "sederhana", dan itu posisi yang sangat bisa dipertahankan, tapi saya memberikan interpretasi saya sendiri tentang "sederhana" di paragraf ke-2 dan sisa jawabannya konsisten dengan itu. Dan untuk membela interpretasi saya yang memang terbatas, tidak semua pengguna Git memiliki xargsatau bash, dan mereka mungkin tidak di sini mencari tantangan micro-coding, sebanyak jawaban cepat yang dapat mereka terapkan dengan aman tanpa mengalihkan perhatian mereka lebih jauh dari tujuan sebenarnya. .
Andrew Spencer
52

Saya menemukan jawabannya di sini: Bagaimana saya bisa menghapus semua cabang git yang telah digabung?

git branch --merged | grep -v "\*" | xargs -n 1 git branch -d

Pastikan kita tetap menguasai

Anda dapat memastikan bahwa master, atau cabang lain dalam hal ini, tidak bisa dihapus dengan menambahkan yang lain grepsetelah yang pertama. Dalam hal ini Anda akan pergi:

git branch --merged | grep -v "\*" | grep -v "YOUR_BRANCH_TO_KEEP" | xargs -n 1 git branch -d

Jadi jika kita ingin tetap master, developdan stagingmisalnya, kita akan pergi:

git branch --merged | grep -v "\*" | grep -v "master" | grep -v "develop" | grep -v "staging" | xargs -n 1 git branch -d

Jadikan ini sebagai alias

Karena agak panjang, Anda mungkin ingin menambahkan alias ke .zshrcatau .bashrc. Tambang disebut gbpurge(untuk git branches purge):

alias gbpurge='git branch --merged | grep -v "\*" | grep -v "master" | grep -v "develop" | grep -v "staging" | xargs -n 1 git branch -d'

Kemudian muat ulang .bashrcatau .zshrc:

. ~/.bashrc

atau

. ~/.zshrc
karlingen
sumber
8
Berguna, tetapi tidak sama dengan "menghapus cabang tidak pada jarak jauh"
dlsso
Greate answer @karlingen, saya memiliki ini secara permanen sebagai gbpurge di semua lingkungan dev saya
Peter Dolan
50

Solusi Windows

Untuk Microsoft Windows Powershell:

git checkout master; git remote update origin --prune; git branch -vv | Select-String -Pattern ": gone]" | % { $_.toString().Trim().Split(" ")[0]} | % {git branch -d $_}

Penjelasan

git checkout master beralih ke cabang master

git remote update origin --prune memangkas cabang-cabang terpencil

git branch -vvmendapat output verbose dari semua cabang ( referensi git )

Select-String -Pattern ": gone]" hanya mendapat catatan di mana mereka telah dihapus dari jarak jauh.

% { $_.toString().Trim().Split(" ")[0]} dapatkan nama cabang

% {git branch -d $_} menghapus cabang

chris31389
sumber
3
Terima kasih untuk ini, meskipun saya harus menambahkan .Trim()setelah .toString()untuk menghapus dua spasi sebelum nama cabang.
Matius
2
Terima kasih untuk perintah ini. Saya harus mengubah git branch -dke yang git branch -Dlain saya mendapatkan kesalahan cabang tidak sepenuhnya digabung.
markieo
1
@markieo Anda mungkin tahu ini sudah, tapi untuk orang lain - git branch -Dadalah merusak dan akan menghapus kerja lokal yang belum mendorong. -dselalu aman, hati-hati dengan -D.
Nate Barbettini
33

Pencocokan pola untuk "hilang" di sebagian besar solusi lain agak menakutkan bagi saya. Agar lebih aman, ini menggunakan --formatbendera untuk mengeluarkan status pelacakan hulu masing-masing cabang .

Saya membutuhkan versi Windows-friendly, jadi ini menghapus semua cabang yang terdaftar sebagai "hilang" menggunakan Powershell:

git branch --list --format "%(if:equals=[gone])%(upstream:track)%(then)%(refname:short)%(end)" | 
    ? { $_ -ne "" } | 
    % { git branch -D $_ }

Baris pertama mencantumkan nama cabang lokal yang cabang hulunya "hilang". Baris berikutnya menghapus baris kosong (yang merupakan output untuk cabang yang tidak "hilang"), maka nama cabang diteruskan ke perintah untuk menghapus cabang.

Patrick Quirk
sumber
6
The --formatpilihan tampaknya cukup baru; Saya perlu memperbarui git dari 2.10.sesuatu ke 2.16.3 untuk mendapatkannya. Ini adalah modifikasi saya untuk sistem Linux-ish:git branch --list --format "%(if:equals=[gone])%(upstream:track)%(then)%(refname)%(end)" | sed 's,^refs/heads/,,' | grep . | xargs git branch -D
bxm
2
Ini adalah solusi terbaik sejauh ini. Satu saran adalah menggunakan refname:short. Kemudian Anda dapat menghapus baris% { $_ -replace '^refs/heads/', '' }
ioudas
2
Ini adalah solusi yang bagus untuk windows. Saya menggunakan itu seperti ini menyebabkan lebih mudah dibaca git branch --list --format "%(if:equals=[gone])%(upstream:track)%(then)%(refname:short)%(end)" | where { $_ -ne "" } | foreach { git branch -d $_ }Juga mungkin ide yang baik untuk menggunakan -dbukan -D. Hapus paksa tidak perlu untuk cabang yang tidak lagi di remote.
Rubanov
31

Hapus semua cabang yang telah digabungkan menjadi master, tetapi jangan mencoba untuk menghapus master itu sendiri:

git checkout master && git pull origin master && git fetch -p && git branch -d $(git branch --merged | grep master -v)

atau tambahkan alias:

alias gitcleanlocal="git checkout master && git pull origin master && git fetch -p && git branch -d $(git branch --merged | grep master -v)"

Penjelasan:

git checkout master checkout cabang utama

git pull origin master memastikan cabang lokal memiliki semua perubahan jarak jauh digabungkan

git fetch -p hapus referensi ke cabang jarak jauh yang telah dihapus

git branch -d $(git branch master --merged | grep master -v) hapus semua cabang yang telah digabungkan menjadi master, tetapi jangan mencoba untuk menghapus master itu sendiri

cs01
sumber
3
Satu catatan, ini sangat membantu tetapi juga akan menghapus cabang-cabang yang tidak pernah didorong ke remote. Lebih aman hanya menuliskan perbedaan dan menyalin apa yang Anda ingin hapus ke git branch -Dperintah
Zefiryn
Hanya untuk memperjelas, Zefiryn merujuk menggunakan opsi -D yang bukan bagian dari satu-liner.
cs01
1
Atau juse huruf kecil git branch -dyang seharusnya mengeluarkan peringatan tentang tidak mendorong cabang.
acme
16
git fetch -p

Ini akan memangkas cabang apa pun yang tidak lagi ada di remote.

ckirksey3
sumber
64
ini menghilangkan referensi jarak jauh, tetapi bukan cabang lokal itu sendiri. Meskipun ini adalah perintah yang bermanfaat, saya tidak berpikir ini menjawab pertanyaan OP.
thataustin
Apa? Ini menghapus cabang lokal untuk saya.
Alex Hall
1
@AlexHall Repositori jauh memiliki cabang X; Anda git checkout X; sekarang repositori Anda memiliki cabang pelacakan (lokal) Xdan cabang jarak jauh origin/X; repositori jauh menghapus X; Anda git fetch-p; di repositori lokal Anda, tidak hanya origin/Xtetapi juga Xtelah dihapus. Itukah yang kamu katakan?
Andrew Spencer
16

Namun-jawaban lain untuk tumpukan, menarik banyak dari jawaban Patrick (yang saya suka karena tampaknya menghilangkan ambiguitas tentang di mana gone]akan cocok digit branch output) tetapi menambahkan bengkok * nix.

Dalam bentuknya yang paling sederhana:

git branch --list --format \
  "%(if:equals=[gone])%(upstream:track)%(then)%(refname:short)%(end)" \
  | xargs git branch -D

Saya sudah membungkus git-goneskrip ini di jalur saya:

#!/usr/bin/env bash

action() {
  ${DELETE} && xargs git branch -D || cat
}

get_gone() {
  git branch --list --format \
    "%(if:equals=[gone])%(upstream:track)%(then)%(refname:short)%(end)"
}

main() {
  DELETE=false
  while [ $# -gt 0 ] ; do
    case "${1}" in
      (-[dD] | --delete) DELETE=true ;;
    esac
    shift
  done
  get_gone | action
}

main "${@}"

NB - The --format Opsi ini tampaknya cukup baru; Saya perlu memperbarui git dari 2.10.sesuatu ke 2.16.3 untuk mendapatkannya.

EDIT: tweak untuk memasukkan saran tentang refname:shortdari Benjamin W.

NB2 - Saya hanya diuji bash, maka hashbang, tapi mungkin portabel sh.

bxm
sumber
Tidak bisakah Anda melewati sedbagian dengan menggunakan %(refname:short)di baris pertama?
Benjamin W.
Tampaknya bekerja untuk saya, dan saya memilikinya sebagai Git alias rapi sekarang - solusi terbersih dari semuanya di sini!
Benjamin W.
2.13 diperkenalkan --format. Cara lain untuk melewati sedbagian ini adalah menggunakan git update-ref -d. Perhatikan bahwa ini mungkin agak tidak aman, menggunakan git for-each-reflebih aman di sini (diberikan --shell).
gsnedders
Jawaban yang bagus, dan itu membantu saya menjawab pertanyaan saya sendiri ketika mengalami kesulitan --formatuntuk melakukan ini sendiri. Hanya satu pertanyaan: mengapa #!bash? Semuanya di sini terlihat portabel shuntuk saya.
Toby Speight
Itu hanya pelat ketel normal saya, dan belum diuji di tempat lain.
bxm
15

Mungkin bermanfaat untuk beberapa, satu baris sederhana untuk menghapus semua cabang lokal kecuali menguasai dan mengembangkan

git branch | grep -v "master" | grep -v "develop" | xargs git branch -D
Francois
sumber
Jawaban yang luar biasa! Saya suka bagaimana seseorang dapat dengan mudah bermain dengan 'git branch | grep -v "master" | grep -v "develop"hal-hal seperti itu sebelum berkomitmen untuk menambahkan pada bagian penghapusan dari perintah. 👏😊
finneycanhelp
Tetapi ini tidak menjawab pertanyaan di atas. Ini akan menghapus cabang meskipun jarak jauh masih ada.
Jim.B
13

Ini akan menghapus semua cabang lokal gabungan kecuali referensi master lokal dan yang saat ini sedang digunakan:

git branch --merged | grep -v "*" | grep -v "master" | xargs git branch -d

Dan ini akan menghapus semua cabang yang telah dihapus dari repositori jarak jauh yang dirujuk oleh " asal ", tetapi masih tersedia secara lokal di " remote / asal ".

git remote prune origin
pabloa98
sumber
git branch -vv | grep 'gone]' | grep -v "\*" | awk '{print $1}' | xargs -r git branch -d Penjelasan: Saya lebih suka mengganti git branch --mergedby git branch -vvuntuk menunjukkan status (hilang) karena sebelumnya git branch --mergeddapat menunjukkan juga master
jpmottin
13

Saya tidak berpikir ada perintah bawaan untuk melakukan ini, tetapi aman untuk melakukan hal berikut:

git checkout master
git branch -d bug-fix-a

Saat Anda menggunakan -d, git akan menolak untuk menghapus cabang kecuali jika benar-benar digabungkan ke dalam HEADatau cabang pelacakan jarak jauh hulu. Jadi, Anda selalu dapat mengulangi keluaran git for-each-refdan mencoba menghapus setiap cabang. Masalah dengan pendekatan itu adalah saya menduga Anda mungkin tidak ingin bug-fix-ddihapus hanya karena origin/bug-fix-dberisi riwayatnya. Sebagai gantinya, Anda dapat membuat skrip sesuatu seperti berikut:

#!/bin/sh

git checkout master &&
for r in $(git for-each-ref refs/heads --format='%(refname:short)')
do
  if [ x$(git merge-base master "$r") = x$(git rev-parse --verify "$r") ]
  then
    if [ "$r" != "master" ]
    then
      git branch -d "$r"
    fi
  fi
done

Peringatan: Saya belum menguji skrip ini - hanya gunakan dengan hati-hati ...

Mark Longair
sumber
Saya mengambil kebebasan untuk mengedit naskah. Masih tidak akan memberikan jaminan apa pun, tetapi berjalan dan tampaknya berfungsi sekarang.
fwielstra
13

TL; DR:

Hapus SEMUA cabang lokal yang tidak pada jarak jauh

git fetch -p && git branch -vv | grep ': gone]' | awk '{print $1}' | xargs git branch -D

Hapus SEMUA cabang lokal yang tidak pada remote DAN yang sepenuhnya digabung DAN yang tidak digunakan seperti yang dikatakan dalam banyak jawaban sebelumnya.

git fetch -p && git branch --merged | grep -v '*' | grep -v 'master' | xargs git branch -d

Penjelasan

  • git fetch -p akan memangkas semua cabang yang tidak lagi ada pada jarak jauh
  • git branch -vv akan mencetak cabang lokal dan cabang yang dipangkas akan ditandai gone
  • grep ': gone]' hanya memilih cabang yang hilang
  • awk '{print $1}' filter output untuk hanya menampilkan nama cabang
  • xargs git branch -D akan mengulang semua baris (cabang) dan memaksa menghapus cabang ini

Mengapa git branch -Ddan tidak git branch -dlain yang Anda miliki untuk cabang yang tidak sepenuhnya digabung.

error: The branch 'xxx' is not fully merged.
noraj
sumber
1
apakah Anda ingin mengatakan remote bukan master?
tinos
8

Anda bisa melakukan ini:

git branch -vv | grep 'origin/.*: gone]' | awk '{print $1}' | xargs git branch -d
Sven Dhaens
sumber
7

Berdasarkan info di atas, ini bekerja untuk saya:

git br -d `git br -vv | grep ': gone] ' | awk '{print $1}' | xargs`

Ini menghapus semua cabang lokal dengan berada ': gone] 'di remote.

Joost den Boer
sumber
1
Sepertinya ini juga akan menghapus semua cabang yang telah "hilang" di pesan komit terakhir.
dlsso
Ini juga akan menghapus semua cabang yang memiliki gonenamanya.
bfontaine
3
"git branch -D git branch -vv | grep ': gone]' | awk '{print $ 1}' | xargs`" Ini berhasil bagi saya.
Muthu Ganapathy Nathan
7
grep gone <(git branch -v) | cut -d ' ' -f 3 | xargs git branch -d

Perintah di atas dapat digunakan untuk mengambil cabang yang digabungkan dan dihapus dalam jarak jauh dan menghapus cabang lokal yang tidak lagi tersedia di jarak jauh

haus klasik
sumber
Solusi terbaik sejauh ini, meskipun saya mengubahnya grep gone <(git branch -v) | cut -d ' ' -f 3 | xargs git branch -Duntuk memaksa menghapus semua
Shoaib
Berbahaya jika ada salah satu nama cabang Anda yang mengandung substring gonedi mana saja di dalamnya (mis usingonefunction.).
Toby Speight
7

Tidak ada yang benar-benar cocok untuk saya. Saya menginginkan sesuatu yang akan membersihkan semua cabang lokal yang melacak cabang jarak jauh, pada origin, di mana cabang jarak jauh telah dihapus ( gone). Saya tidak ingin menghapus cabang lokal yang tidak pernah disetel untuk melacak cabang jarak jauh (yaitu: cabang dev lokal saya). Saya juga menginginkan satu baris sederhana yang hanya menggunakan git, atau alat CLI sederhana lainnya, daripada menulis skrip khusus. Saya akhirnya menggunakan sedikit grepdan awkuntuk membuat perintah sederhana ini.

Inilah yang akhirnya berakhir pada ~/.gitconfig:

[alias]
  prune-branches = !git remote prune origin && git branch -vv | grep ': gone]' | awk '{print $1}' | xargs -r git branch -D

Berikut adalah git config --global ...perintah untuk menambahkan ini dengan mudah git prune-branches:

git config --global alias.prune-branches '!git remote prune origin && git branch -vv | grep '"'"': gone]'"'"' | awk '"'"'{print $1}'"'"' | xargs -r git branch -d'

CATATAN: Dalam perintah config, saya menggunakan -dopsi git branchdaripada -D, seperti yang saya lakukan pada konfigurasi aktual saya. Saya menggunakan -Dkarena saya tidak ingin mendengar Git mengeluh tentang ranting-ranting yang tidak terbakar. Anda mungkin menginginkan fungsi ini juga. Jika demikian, cukup gunakan -Dalih-alih -ddi akhir perintah konfigurasi itu.

Karl Wilbur
sumber
Saya suka pendekatan git alias. Pertanyaan cepat: Mengapa melakukan git branch -vvdan mencari : gone]dan tidak melakukan git branch -vdan mencari [gone]?
lalibi
@lalibi, pertanyaan bagus. Saya tidak ingat. Saya menduga ada sesuatu yang tidak muncul hanya dengan satu v. Jika git branch -v | grep '[gone]'berhasil untuk Anda, lakukanlah. Tampaknya lebih bersih.
Karl Wilbur
4

Berdasarkan Tip Git: Menghapus Cabang Lokal Lama , yang terlihat mirip dengan solusi jason.rickman, saya menerapkan perintah khusus untuk tujuan ini yang disebut git menggunakan Bash:

$ git gone
usage: git gone [-pndD] [<branch>=origin]
OPTIONS
  -p  prune remote branch
  -n  dry run: list the gone branches
  -d  delete the gone branches
  -D  delete the gone branches forcefully

EXAMPLES
git gone -pn    prune and dry run
git gone -d     delete the gone branches

git gone -pn menggabungkan pemangkasan dan daftar cabang "hilang":

$ git gone -pn
  bport/fix-server-broadcast         b472d5d2b [origin/bport/fix-server-broadcast: gone] Bump modules
  fport/rangepos                     45c857d15 [origin/fport/rangepos: gone] Bump modules

Kemudian Anda dapat menarik pelatuk menggunakan git gone -datau git gone -D.

Catatan

  • Ekspresi reguler yang saya gunakan adalah di "$BRANCH/.*: gone]"mana $BRANCHbiasanya origin. Ini mungkin tidak akan berfungsi jika output Git Anda dilokalisasi ke bahasa Prancis dll.
  • Sebastian Wiesner juga mengirim portalnya ke Rust untuk pengguna Windows. Yang itu juga disebut git hilang .
Eugene Yokota
sumber
Ini mungkin jawaban yang diterima - git gonesepertinya alias untuk git branch -vv | grep 'origin/.*: gone]' | awk '{print $1}' | xargs git branch -d, yang menyelesaikan masalah OP.
alex
4

Menggambar berat dari sejumlah dari lainnya jawaban di sini, saya sudah berakhir dengan berikut (git 2.13 dan di atas saja, saya percaya), yang harus bekerja pada setiap UNIX-seperti shell:

git for-each-ref --shell --format='ref=%(if:equals=[gone])%(upstream:track)%(then)%(refname)%(end)' refs/heads | while read entry; do eval "$entry"; [ ! -z "$ref" ] && git update-ref -d "$ref" && echo "deleted $ref"; done

Ini terutama menggunakan for-each-refalih-alih branch(seperti branchperintah "porselen" yang dirancang untuk keluaran yang dapat dibaca manusia, bukan pemrosesan mesin) dan menggunakan --shellargumennya untuk mendapatkan keluaran yang keluar dengan benar (ini memungkinkan kita untuk tidak khawatir tentang karakter apa pun dalam nama ref).

gsnedders
sumber
Ini bekerja untuk saya, tetapi akan lebih baik jika Anda bisa menjelaskan apa yang dilakukan langkah-langkah lain dalam perintah. Misalnya saya tidak tahu apa [ ! -z "$ref" ]artinya. Saya pikir multi-liner sudah membantu. Tapi tetap terima kasih atas masukan Anda!
KevinH
4

Namun jawaban lain, karena tidak ada solusi yang sesuai dengan kebutuhan saya tentang keanggunan dan lintas platform:

Perintah untuk menghapus cabang lokal tidak pada jarak jauh:

for b in $(git for-each-ref --format='%(if:equals=[gone])%(upstream:track)%(then)%(refname:short)%(end)' refs/heads); do git branch -d $b; done

Untuk mengintegrasikannya dengan gitconfig sehingga dapat dijalankan dengan git branch-prune :

Pesta

git config --global alias.branch-prune '!git fetch -p && for b in $(git for-each-ref --format='\''%(if:equals=[gone])%(upstream:track)%(then)%(refname:short)%(end)'\'' refs/heads); do git branch -d $b; done'

PowerShell

git config --global alias.branch-prune '!git fetch -p && for b in $(git for-each-ref --format=''%(if:equals=[gone])%(upstream:track)%(then)%(refname:short)%(end)'' refs/heads); do git branch -d $b; done'

(Perlu bantuan dalam menemukan perintah universal untuk PowerShell dan bash)

Mengapa jawaban ini adalah yang terbaik?

  • Menawarkan solusi lengkap: menambahkan a git branch-prune perintah ke git Anda
  • Berfungsi dengan baik dari Windows PowerShell
  • Ide inti @ jason.rickman 's metode antipeluru menggunakangit for-each-ref
  • Parsing dan filtering dilakukan --filtertanpa ketergantungan eksternal

Penjelasan:

  • Menambahkan alias baru ke blog Anda ~\.gitconfig . Setelah menjalankan ini, Anda cukup melakukannyagit branch-prune
  • Di dalam alias ini:
    • Mengambil cabang dengan --prune bendera, yang "memangkas cabang pelacakan jarak jauh tidak lagi di jarak jauh"
    • Kegunaan git for-each-refdan --filter, untuk mendapatkan daftar cabang yang [gone]ada (tidak ada remote)
    • Loop melalui daftar ini dan menghapus cabang dengan aman
Himura
sumber
1
Terima kasih, @ jerry-wu untuk meningkatkan kedahsyatan solusi ini hingga tak terbatas.
Himura
@ jerry-wu dan edit terakhir Anda dari perintah git config tidak berfungsi di PowerShell ((
Himura
1

Saya datang dengan skrip bash ini. Selalu menjaga cabang develop, qa, master.

git-clear() {
  git pull -a > /dev/null

  local branches=$(git branch --merged | grep -v 'develop' | grep -v 'master' | grep -v 'qa' | sed 's/^\s*//')
  branches=(${branches//;/ })

  if [ -z $branches ]; then
    echo 'No branches to delete...'
    return;
  fi

  echo $branches

  echo 'Do you want to delete these merged branches? (y/n)'
  read yn
  case $yn in
      [^Yy]* ) return;;
  esac

  echo 'Deleting...'

  git remote prune origin
  echo $branches | xargs git branch -d
  git branch -vv
}
BrunoLM
sumber
1

Saya menggunakan metode singkat untuk melakukan trik, saya sarankan Anda untuk melakukan hal yang sama karena dapat menghemat beberapa jam & memberi Anda lebih banyak visibilitas

Cukup tambahkan cuplikan berikut ke .bashrc Anda (.bashprofile di macos).

git-cleaner() { git fetch --all --prune && git branch --merged | grep -v -E "\bmaster|preprod|dmz\b" | xargs -n 1 git branch -d ;};
  1. Ambil semua remote
  2. Dapatkan hanya cabang gabungan dari git
  3. Hapus dari daftar ini cabang "dilindungi / penting"
  4. Buang sisanya (mis., Cabang yang bersih dan digabung)

Anda harus mengedit grep regex agar sesuai dengan kebutuhan Anda (di sini, itu mencegah master, preprod dan dmz dari penghapusan)

Ben Cassinat
sumber
git fetch --all --prunemelakukan trik. Terima kasih!
LeOn - Han Li
1

Ini bekerja untuk saya:

git branch -r | awk '{print $1}' | egrep -v -f /dev/fd/0 <(git branch -vv | grep origin) | awk '{print $1}' | xargs git branch -d
Fareed Alnamrouti
sumber
oh, saya gandakan memposting ini pada ... hanya melihat ini ketika meninjau posting. Tapi Anda benar-benar bisa menunjuk ke orang yang memberikan perintah ini alih-alih menganggap ini milik Anda!
Dwza
Saya mendapatkannya dari forum, jangan mencoba untuk pintar, ambil saja jawabannya atau abaikan saja
Fareed Alnamrouti
Bahkan dari yang Anda bisa ... tetap ... tidak datang ke sini untuk membicarakan hal ini dengan Anda. Seperti yang Anda katakan ... ambil komentar saya atau abaikan;)
Dwza
0

Saya tidak yakin untuk berapa lama, tapi saya menggunakan git-up sekarang, yang menangani itu.

Saya lakukan git updan itu mulai melacak cabang baru dan menghapus yang lama.

Hanya untuk membuatnya jelas, itu bukan perintah git out-of-box - https://github.com/aanand/git-up

BTW itu juga menyembunyikan pohon kotor dan membuat rebases masih dengan adil git up.

Semoga bermanfaat bagi seseorang

Mailo Světel
sumber
2
Ini bukan menghapus cabang lokal yang tidak ada di server.
Ashley
0

Inilah solusi yang saya gunakan untuk cangkang ikan. Diuji pada Mac OS X 10.11.5, fish 2.3.0dan git 2.8.3.

function git_clean_branches
  set base_branch develop

  # work from our base branch
  git checkout $base_branch

  # remove local tracking branches where the remote branch is gone
  git fetch -p

  # find all local branches that have been merged into the base branch
  # and delete any without a corresponding remote branch
  set local
  for f in (git branch --merged $base_branch | grep -v "\(master\|$base_branch\|\*\)" | awk '/\s*\w*\s*/ {print $1}')
    set local $local $f
  end

  set remote
  for f in (git branch -r | xargs basename)
    set remote $remote $f
  end

  for f in $local
    echo $remote | grep --quiet "\s$f\s"
    if [ $status -gt 0 ]
      git branch -d $f
    end
  end
end

Beberapa catatan:

Pastikan untuk mengatur yang benar base_branch. Dalam hal ini saya gunakan developsebagai cabang dasar, tetapi bisa jadi apa saja.

Bagian ini sangat penting: grep -v "\(master\|$base_branch\|\*\)". Ini memastikan bahwa Anda tidak menghapus master atau cabang dasar Anda.

Saya menggunakan git branch -d <branch>sebagai tindakan pencegahan ekstra, agar tidak menghapus cabang apa pun yang belum sepenuhnya digabung dengan HEAD hulu atau saat ini.

Cara mudah untuk menguji adalah menggantinya git branch -d $fdengan echo "will delete $f".

Saya kira saya juga harus menambahkan: GUNAKAN RISIKO ANDA SENDIRI!

lps
sumber
0

Saya telah menulis skrip Python menggunakan GitPython untuk menghapus cabang lokal yang tidak ada pada remote.

    import git
    import subprocess
    from git.exc import GitCommandError
    import os

    def delete_merged_branches():
        current_dir = input("Enter repository directory:")
        repo = git.Repo(current_dir)
        git_command = git.Git(current_dir)

        # fetch the remote with prune, this will delete the remote references in local.
        for remote in repo.remotes:
            remote.fetch(prune=True)

        local_branches = [branch.name for branch in repo.branches]
        deleted_branches = []

        # deleted_branches are the branches which are deleted on remote but exists on local.
        for branch in local_branches:
            try:
                remote_name = 'origin/'+ branch
                repo.git.checkout(remote_name)
            except GitCommandError:
            # if the remote reference is not present, it means the branch is deleted on remote.
                deleted_branches.append(branch)

        for branch in deleted_branches:
            print("Deleting branch:"+branch)
            git_command.execute(["git", "branch", "-D",branch])


        # clean up the work flow.
        repo.git.checkout('master')
        repo.git.pull()

    if __name__ == '__main__':
        delete_merged_branches()

Semoga ada yang berguna, silakan tambahkan komentar jika saya melewatkan sesuatu.

raviraja
sumber
0

Jika Anda menggunakan zshshell dengan Oh My Zshinstal maka cara termudah untuk melakukannya dengan aman adalah dengan menggunakan autocomplete bawaan.

Pertama-tama tentukan cabang mana yang ingin Anda hapus dengan:

~ git branch --merged

  branch1
  branch2
  branch3
* master

ini akan menampilkan daftar cabang yang sudah digabung

Setelah Anda tahu beberapa yang ingin Anda hapus lalu ketik:

~ git branch -d 

Yang harus Anda lakukan adalah menekan [tab] dan itu akan menampilkan daftar cabang lokal. Gunakan tab-complete atau tekan saja [tab] lagi dan Anda dapat memutarnya untuk memilih cabang dengan [enter].

Tab Pilih cabang berulang-ulang sampai Anda memiliki daftar cabang yang ingin Anda hapus:

~ git branch -d branch1 branch2 branch3

Sekarang cukup tekan enter untuk menghapus koleksi cabang Anda.

Jika Anda tidak menggunakan zsh di terminal Anda ... Dapatkan di sini.

Noah Gary
sumber
0

Saya suka menggunakan pipa karena membuat perintah lebih mudah dibaca.

Ini solusi saya jika Anda ingin menghapus semua cabang kecuali master.

git branch | grep -v master | xargs -n 1 git branch -D

Untuk menghapus cabang lain yang cocok dengan kriteria Anda, modifikasi blok pertama dan kedua.

git branch --merged | grep feature_name | xargs -n 1 git branch -D
khususnya
sumber
-3

Inilah jawaban sederhana yang bekerja untuk saya menggunakan klien git:

Hapus repositori sama sekali dari mesin Anda kemudian periksa lagi.

Jangan main-main dengan skrip yang berisiko.

Juan Carlos Ospina Gonzalez
sumber
2
Bagaimana dengan cabang yang sedang saya kerjakan: /
Mailo Světel
@ MailoSvětel jika mereka ada di remote Anda maka Anda bisa menariknya lagi (jangan lupa untuk melakukan dan mendorong pekerjaan terbaru Anda ke remote Anda!)
Juan Carlos Ospina Gonzalez
Dalam pertanyaan saya dan di sebagian besar jawaban, kami berusaha menghindari pekerjaan yang tidak perlu. Dengan kata lain: Apa yang perlu saya lakukan hanyalah menghapus cabang, saya tidak akan bekerja lagi. Menghapus repo, mengkloningnya dan mulai melacak cabang lagi, banyak pekerjaan yang tidak perlu bagi saya. Selain itu, beberapa pekerjaan bisa hilang :(
Mailo Světel