Buat daftar semua cabang lokal tanpa remote

91

Masalah: Saya ingin cara menghapus semua cabang lokal yang saya miliki yang tidak memiliki remote. Cukup mudah untuk menyalurkan nama-nama cabang menjadi a git branch -D {branch_name}, tetapi bagaimana cara mendapatkan daftar itu?

Sebagai contoh:

Saya membuat cabang baru tanpa remote:

$ git co -b no_upstream

Saya mendaftar semua cabang saya, dan hanya ada satu dengan remote

$ git branch -a
master
* no_upstream
remotes/origin/HEAD -> origin/master
remotes/origin/master

Perintah apa yang bisa saya jalankan untuk mendapatkan no_upstreamjawaban?

Saya dapat menjalankan git rev-parse --abbrev-ref --symbolic-full-name @{u}dan itu akan menunjukkan bahwa tidak ada remote:

$ git rev-parse --abbrev-ref --symbolic-full-name @{u}
error: No upstream configured for branch 'no_upstream'
error: No upstream configured for branch 'no_upstream'
fatal: ambiguous argument '@{u}': unknown revision or path not in the working tree.
Use '--' to separate paths from revisions, like this:
'git <command> [<revision>...] -- [<file>...]'

Tetapi karena ini adalah kesalahan, itu tidak akan membiarkan saya menggunakannya atau menyalurkannya ke perintah lain. Saya bermaksud untuk menggunakan ini baik sebagai skrip shell alias untuk git-delete-unbranchedatau mungkin membuat Permata yang sangat sederhanagit-branch-delete-orphans

JC Denton
sumber
1
Kemungkinan duplikat Hapus cabang lokal tidak lagi di remote
ks1322

Jawaban:

103

Saya baru-baru ini menemukan git branch -vvversi git branchperintah yang "sangat bertele-tele" .

Ini mengeluarkan cabang bersama dengan cabang jarak jauh jika ada, dalam format berikut:

  25-timeout-error-with-many-targets    206a5fa WIP: batch insert
  31-target-suggestions                 f5bdce6 [origin/31-target-suggestions] Create target suggestion for team and list on save
* 54-feedback-link                      b98e97c [origin/54-feedback-link] WIP: Feedback link in mail
  65-digest-double-publish              2de4150 WIP: publishing-state

Setelah Anda memiliki keluaran yang diformat dengan baik ini, semudah menyalurkannya cutdan awkmendapatkan daftar Anda:

git branch -vv | cut -c 3- | awk '$3 !~/\[/ { print $1 }'

Menghasilkan keluaran sebagai berikut:

25-timeout-error-with-many-targets
65-digest-double-publish

The cutporsi hanya menormalkan data dengan menghapus dua pertama karakter (termasuk *) dari output sebelum diteruskan ke awk.

The awkporsi mencetak kolom pertama jika tidak ada braket persegi di kolom ketiga.

Bonus: Buat alias

Permudah untuk dijalankan dengan membuat alias di .gitconfigfile global Anda (atau di mana pun):

[alias]
  local-branches = !git branch -vv | cut -c 3- | awk '$3 !~/\\[/ { print $1 }'

Penting: Garis miring terbalik harus di-escape dalam alias atau Anda akan mendapatkan file gitconfig yang tidak valid.

Bonus: Pemfilteran Jarak Jauh

Jika karena alasan tertentu Anda memiliki beberapa remote pelacakan untuk cabang yang berbeda, cukup mudah untuk menentukan remote mana yang ingin Anda periksa. Cukup tambahkan nama remote ke pola awk. Dalam kasus saya, originsaya bisa melakukan ini:

git branch -vv | cut -c 3- | awk '$3 !~/\[origin/ { print $1 }'
Jeremy Baker
sumber
apa itu WIP:sih ..? bukankah itu yang dibuat oleh perintah simpanan ..?
igrek
@igrek Itu hanya awalan yang saya gunakan dalam pesan komit. Tidak ada yang khusus untuk git.
Jeremy Baker
ketika saya melakukannya git branch -vv, bahkan jika cabang jarak jauh ada dan cocok dengan cabang lokal saya, saya tidak akan melihat di [origin/branch-name]samping hasilnya. Saya harus ke diffdua daftar cabang untuk benar-benar mencari tahu apa yang hanya lokal.
ryantuck
git branch -vv | grep -v origin/cukup bagi saya
jangan panik
2
Bukankah ini melewatkan cabang-cabang terpencil yang ditandai gone?
Reid
36

git branch (tanpa opsi apa pun) hanya mencantumkan cabang lokal, tetapi Anda tidak tahu apakah mereka melacak cabang jauh atau tidak.

Biasanya cabang-cabang lokal itu harus dihapus setelah digabungkan master(seperti yang terlihat dalam edisi git-sweep ini ):

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

Ini tidak selengkap yang Anda inginkan, tetapi ini adalah permulaan.

Dengan --merged, hanya cabang yang digabungkan ke dalam komit bernama (yaitu cabang yang ujung komitnya dapat dijangkau dari komit bernama) akan dicantumkan.

VonC
sumber
1
Untuk juga menyertakan cabang jarak jauh tanpa cabang lokal, gunakan git branch -a --merged.
Acumenus
21

Saya memiliki masalah serupa. Saya ingin menghapus semua cabang lokal yang melacak cabang jauh yang sekarang dihapus. Saya menemukan bahwa git remote prune origintidak cukup untuk menghilangkan cabang yang ingin saya hilangkan. Setelah remote dihapus, saya ingin lokal juga pergi. Inilah yang berhasil untuk saya:

Dari saya ~/.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 sebagai 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 : Saya mengubah -dke -Ddalam konfigurasi saya yang sebenarnya, karena saya tidak ingin mendengar Git mengeluh tentang cabang yang tidak digabungkan. Anda mungkin menginginkan fungsionalitas ini juga. Jika demikian, cukup gunakan -Dalih-alih -ddi akhir perintah itu.

Juga, FWIW, file konfigurasi global Anda akan selalu seperti itu ~/.gitconfig.

(Perbaikan OS X)

Seperti yang tertulis, ini tidak berfungsi di OS X karena penggunaan xargs -r(terima kasih, Korny ).

Ini -runtuk mencegah xargsberjalan git branch -dtanpa nama cabang, yang akan menghasilkan pesan kesalahan " fatal: branch name required". Jika Anda tidak keberatan dengan pesan kesalahan, Anda cukup menghapus -rargumen ke xargsdan Anda sudah siap.

Namun, jika Anda tidak ingin melihat pesan kesalahan (dan sungguh, siapa yang dapat menyalahkan Anda) maka Anda memerlukan sesuatu yang lain yang memeriksa pipa kosong. Jika Anda mungkin bisa menggunakan ifne dari moreutils . Anda akan memasukkan ifnesebelumnya xargs, yang akan berhenti xargsberjalan dengan data kosong. CATATAN : ifnemenganggap segala sesuatu tidak kosong, ini termasuk baris kosong, jadi Anda mungkin masih melihat pesan kesalahan itu. Saya belum menguji ini di OS X.

Inilah git configbaris itu dengan ifne:

git config --global alias.prune-branches '!git remote prune origin && git branch -vv | grep '"'"': gone]'"'"' | awk '"'"'{print $1}'"'"' | ifne xargs git branch -d'
Karl Wilbur
sumber
1
Apakah mungkin untuk mengubahnya menjadi perintah "git config --global ..."? Dari sudut pandang instruksi / cara-ke-wiki-untuk-dummies, mudah untuk menyampaikan alih-alih mengatakan "Temukan file konfigurasi git Anda, gunakan editor untuk mengeditnya lalu jalankan perintah"
Kannan Ekanath
Perhatikan bahwa xargs -r tidak berfungsi di OSX
Korny
Senang mendengarnya. Saya tidak tahu apa pilihan "no run if empty" untuk OSX.
Karl Wilbur
18

Pengeditan terlambat:

Lebih baik

git for-each-ref  --format='%(refname:short) %(upstream)'  refs/heads \
| awk '$2 !~/^refs\/remotes/'

Tentang GNU / apapun

for b in `git branch|sed s,..,,`; do
    git config --get branch.$b.remote|sed Q1 && echo git branch -D $b
done

Jika lebih dari segelintir cabang mungkin, akan ada cara yang lebih baik, menggunakan comm -23output dari git branch|sed|sortdan git config -l|sed|sort.

jthill
sumber
1
@nmr s / git. * Q1 / test $ (git config --get branch. $ b.remote | sed q | wc -1) = 1 /
jthill
15

Ini bekerja untuk saya:

git branch -vv | grep -v origin

(jika remote Anda bernama selain origin, gantikan).

Ini akan mencantumkan semua cabang yang tidak melacak remote, yang terdengar seperti apa yang Anda cari.

ebr
sumber
2
Ini akan mencantumkan cabang yang dulunya memiliki remote tetapi sekarang tidak lagi bahkan jika Anda menjalankan git fetch --prune.
RusinaRange
2
IMO, lebih baik mencari ": pergi]" daripada memfilter "asal"
fiorentinoing
4

Saya mensintesis perintah Git saya sendiri untuk mendapatkan origin/***: gonecabang:

git remote prune origin && git branch -vv | cut -c 3- | grep ': gone]' | awk '{print $1}' | xargs -n1 -r echo git branch -d

git remote prune origin && git branch -vv akan mencetak cabang dalam mode verbose.

cut -c 3- akan menghapus karakter pertama.

grep ': gone]'hanya akan mencetak cabang-cabang terpencil yang hilang .

awk '{print $1}' akan mencetak nama cabang.

xargs -n1 -r echo git branch -dakan mencetak git branch -dperintah untuk menghapus cabang (-n1 akan mengatur satu perintah per waktu, -r untuk menghindari mengeluarkan perintah jika tidak ada cabang).

PETUNJUK: hapus perintah "echo" untuk menjalankan perintah alih-alih hanya mencetak, saya meninggalkan ini di perintah untuk memeriksa perintah sebelum mengeluarkan ke git.

PETUNJUK 2: masalah git branch -Djika dan hanya jika Anda yakin ingin menghapus cabang yang tidak digabungkan

fiorentinoing
sumber
dari ini saya melakukan git
fiorentinoing
1
Sejauh ini, ini adalah solusi terbersih yang saya temukan, bagus! Saya tidak pernah menghabiskan waktu belajar awk, saya tidak tahu Anda bisa melakukan itu.
adamjc
2

Ini adalah sesuatu yang saya gunakan di PowerShell dengan komentar untuk menjelaskan apa yang dilakukannya. Dalam upaya untuk memperjelas apa yang terjadi, saya belum menggunakan perintah PowerShell yang disingkat (alias). Jangan ragu untuk mengompresnya ke tingkat crypticness yang Anda inginkan :)

$verboseList = @(git branch -vv)
foreach ($line in $verboseList)
{
    # Get the branch name
    $branch = [regex]::Match($line, "\s(\S+)\s").Captures.Groups[1].Value
    # Check if the line contains text to indicate if the remote is deleted
    $remoteGone = $line.Contains(": gone]")
    # Check if the line does not contain text to indicate it is a tracking branch (i.e., it's local)
    $isLocal = !($line.Contains("[origin/"))
    if ($remoteGone -or $isLocal)
    {
        # Print the branch name
        $branch
    }
}
grahamesd
sumber
0

Menggabungkan beberapa jawaban yang ada:

[alias]
        branch-local = !git branch -vv | cut -c 3- | egrep '([0-9a-f]{7} [^[])|(: gone\\])' | sed -E 's/(^.+[0-9a-f]{7} (\\[.+\\])?).*$/\\1/'

Misalnya:

$ git branch-local
autogen_autoreconf      fcfb1c6 [github/autogen_autoreconf: gone]
autotools_documentation 72dc477 [github/autotools_documentation: gone]
cray-mpich-messy        2196f4b
epel-sphinx             cfda770
lammps                  07d96a7 [github/lammps: gone]
lark-error              9ab5d6c [github/lark-error: gone]
no-root2                c3894d1
openmpi-cray            69326cf [github/openmpi-cray: gone]
shellcheck-cleanup      40d90ec
travis-python36         cde072e
update_vagrant_default  4f69f47 [github/update_vagrant_default: gone]
web-docs                e73b4a8
Reid
sumber