Membersihkan cabang git remote lama

694

Saya bekerja dari dua komputer yang berbeda (A dan B) dan menyimpan remote git yang umum di direktori dropbox.

Katakanlah saya memiliki dua cabang, master dan devel. Keduanya melacak rekan jarak jauh mereka asal / master dan asal / devel.

Sekarang saat di komputer A, saya menghapus devel cabang, di lokal dan jarak jauh.

git push origin :heads/devel
git branch -d devel

Berjalan git branch -adi komputer A, saya mendapatkan daftar cabang berikut.

  • menguasai
  • asal / KEPALA
  • asal / master

Berjalan git fetchdi komputer B, saya bisa menghapus cabang devel lokal dengan git branch -d devel, tapi saya tidak bisa menghapus cabang devel jarak jauh.

git push origin :heads/devel mengembalikan pesan kesalahan berikut.

galat: tidak dapat mendorong ke tujuan yang tidak memenuhi syarat: kepala / proxy3d
Tujuan refspec tidak cocok dengan referensi yang ada pada remote atau dimulai dengan referensi /, dan kami tidak dapat menebak awalan berdasarkan referensi sumber.
fatal: Ujung yang jauh menutup secara tak terduga

git branch -a masih daftar asal / berkembang di cabang jauh.

Bagaimana saya bisa membersihkan cabang jarak jauh dari komputer B?

Jayesh
sumber
4
Saya telah diberitahu oleh orang yang mencobanya, bahwa repositori git di folder Dropbox agak rapuh (tetapi tanpa detail tambahan).
Thorbjørn Ravn Andersen
5
@ ThorbjørnRavnAndersen mungkin karena Anda harus menunggu untuk memastikan sinkronisasi sepenuhnya setiap kali Anda melakukan, sebelum Anda dapat yakin itu aman untuk digunakan pada mesin lain (dan sinkronisasi lain diperlukan bahkan kemudian).
ataulm

Jawaban:

1239

Pertama, apa hasil dari git branch -apada mesin B?

Kedua, Anda telah dihapus heads/develpada origin, sehingga ini mengapa Anda tidak dapat menghapusnya dari mesin B.

Mencoba

git branch -r -d origin/devel

atau

git remote prune origin

atau

git fetch origin --prune

dan jangan ragu untuk menambahkan --dry-rundi akhir gitpernyataan Anda untuk melihat hasil menjalankannya tanpa benar-benar menjalankannya.

Documents untuk git remote prunedan git branch.

Jakub Narębski
sumber
50
git remote prune originbekerja untuk saya => * [pruned] origin/my-old-branch
Hari Karam Singh
126
git remote prune origin --dry-runmenunjukkan kepada Anda apa yang akan dihapus tanpa benar-benar melakukannya.
Wolfram Arnold
30
git fetch origin --prunesempurna untuk menghapus cabang yang dihapus
Sébastien Barbieri
10
Jika Anda memiliki cabang lokal yang melacak remote yang hilang, ini tidak akan menghapus apa pun. Bagi mereka, tampaknya git branch -vvdiikuti oleh git branch -D branchnamedan akhirnya pangkas adalah cara terbaik.
Roman Starkov
7
Anda dapat mengonfigurasi pemangkasan agar terjadi secara otomatis saat tarik / ambil dengan menetapkan opsi berikut:git config remote.origin.prune true
Patrick James McDougle
100

Pertimbangkan untuk menjalankan:

git fetch --prune

Secara teratur di setiap repo untuk menghapus cabang lokal yang telah melacak cabang jauh yang dihapus (tidak lagi ada di repo GIT jarak jauh).

Ini dapat disederhanakan dengan

git config remote.origin.prune true

ini adalah per-repopengaturan yang akan membuat masa depan apa pun dipangkasgit fetch or git pull secara otomatis .

Untuk mengatur ini untuk pengguna Anda, Anda juga dapat mengedit .gitconfig global dan menambahkan

[fetch]
    prune = true

Namun, disarankan agar ini dilakukan menggunakan perintah berikut:

git config --global fetch.prune true

atau untuk menerapkannya secara luas (tidak hanya untuk pengguna)

git config --system fetch.prune true
Arif
sumber
14

Berikut ini skrip bash yang dapat melakukannya untuk Anda. Ini versi modifikasi dari http://snippets.freerobby.com/post/491644841/remove-merged-branches-in-git script. Modifikasi saya memungkinkannya untuk mendukung lokasi terpencil yang berbeda.

#!/bin/bash

current_branch=$(git branch --no-color 2> /dev/null | sed -e '/^[^*]/d' -e 's/* \(.*\)/\1/')
if [ "$current_branch" != "master" ]; then
  echo "WARNING: You are on branch $current_branch, NOT master."
fi
echo -e "Fetching merged branches...\n"

git remote update --prune
remote_branches=$(git branch -r --merged | grep -v '/master$' | grep -v "/$current_branch$")
local_branches=$(git branch --merged | grep -v 'master$' | grep -v "$current_branch$")
if [ -z "$remote_branches" ] && [ -z "$local_branches" ]; then
  echo "No existing branches have been merged into $current_branch."
else
  echo "This will remove the following branches:"
  if [ -n "$remote_branches" ]; then
echo "$remote_branches"
  fi
  if [ -n "$local_branches" ]; then
echo "$local_branches"
  fi
  read -p "Continue? (y/n): " -n 1 choice
  echo
  if [ "$choice" == "y" ] || [ "$choice" == "Y" ]; then
    remotes=`echo "$remote_branches" | sed 's/\(.*\)\/\(.*\)/\1/g' | sort -u`
# Remove remote branches
for remote in $remotes
do
        branches=`echo "$remote_branches" | grep "$remote/" | sed 's/\(.*\)\/\(.*\)/:\2 /g' | tr -d '\n'`
        git push $remote $branches 
done

# Remove local branches
git branch -d `git branch --merged | grep -v 'master$' | grep -v "$current_branch$" | sed 's/origin\///g' | tr -d '\n'`
  else
echo "No branches removed."
  fi
fi
Alex Amiryan
sumber
1
Ini pecah pada cabang yang disebut "asal / fitur / mybranch", saya tidak yakin mengapa.
Stavros Korokithakis
Masalahnya adalah dalam dua seds. Ganti sed 's/\(.*\)\/\(.*\)/\1/g'olehsed 's/\([^/]*\)\/\(.*\)/\1/g'
Benoît Latinier
14

Perintah ini akan "dry run" menghapus semua origincabang yang jauh ( ) digabung, selain master. Anda bisa mengubahnya, atau, tambahkan cabang tambahan setelah master:grep -v for-example-your-branch-here |

git branch -r --merged | 
  grep origin | 
  grep -v '>' | 
  grep -v master | 
  xargs -L1 | 
  awk '{sub(/origin\//,"");print}'| 
  xargs git push origin --delete --dry-run

Jika terlihat bagus, hapus --dry-run. Selain itu, Anda mungkin ingin menguji ini menggunakan garpu terlebih dahulu.

weston
sumber
Bagus. Tweak saya menggunakan perl bukan xargs pertama + awk: git branch -r --merged | asal grep | grep -v '>' | grep -v master | perl -lpe '($ junk, $ _) = split (/ \ //, $ _, 2)' | xargs git push origin --delete
Andrew
6

Jika git branch -rmenunjukkan banyak cabang pelacakan jarak jauh yang tidak Anda minati dan Anda ingin menghapusnya hanya dari lokal, gunakan perintah berikut:

git branch -r | grep -Ev 'HEAD|master|develop'  | xargs -r git branch -rd

Versi yang lebih aman hanya dengan menghapus yang digabungkan:

git branch -r --merged | grep -Ev 'HEAD|master|develop'  | xargs -r git branch -rd

Ini mungkin berguna untuk proyek-proyek besar, di mana Anda tidak memerlukan cabang fitur dari rekan tim lain tetapi ada banyak cabang pelacakan jarak jauh diambil pada klon awal.

Namun, langkah ini saja tidak cukup, karena cabang-cabang pelacakan jarak jauh yang dihapus akan kembali berikutnya git fetch .

Untuk berhenti mengambil cabang-cabang pelacakan jarak jauh Anda perlu secara eksplisit menentukan referensi untuk mengambil. Git / config :

[remote "origin"]
  # fetch = +refs/heads/*:refs/remotes/origin/*    ### don't fetch everything
  fetch = +refs/heads/master:refs/remotes/origin/master
  fetch = +refs/heads/develop:refs/remotes/origin/develop
  fetch = +refs/heads/release/*:refs/remotes/origin/release/*

Dalam contoh di atas kami hanya mengambil master, developdan melepaskan cabang, merasa bebas untuk beradaptasi sesuai kebutuhan.

ryenus
sumber
1
Terima kasih, perintah pertama berhasil untuk saya. Anda juga dapat mengambil hanya satu cabang dengan git fetch origin branchnameatau membuat alias ingin ft = "!f() { git fetch origin $(git rev-parse --abbrev-ref HEAD);}; f"mengambil hanya cabang saat ini (favorit pribadi saya). Bersulang.
GiovanyMoreno
Mungkin PL tetapi apa artinya -rbendera itu? Saya melihat xargsmemiliki -Rargumen tetapi tidak menemukan apa pun tentang -r. Maksud saya, secara teori jika saya ingat betul cara xargskerjanya, bahkan tanpanya -rharus bekerja.
Aldo 'xoen' Giambelluca
Saya suka jawaban ini. Beberapa catatan (menyatakan hal yang sangat jelas). Dimungkinkan untuk "melihat dulu" cabang mana yang akan dihapus dengan menghapus pipa terakhir dan perintah terakhir | xargs git branch -d. Juga, dengan menghapus -ropsi ( --remotes) dari git branch -dkami hanya membersihkan cabang lokal (yang mungkin cukup mengingat bahwa secara default git branchtidak menunjukkan cabang jarak jauh).
Aldo 'xoen' Giambelluca
Terima kasih! Ini persis apa yang saya butuhkan. Solusi lain menyarankan mendorong cabang lokal yang sudah dipangkas ke remote untuk menghilangkannya di sana, tetapi itu tidak membantu ketika remote telah dilepas atau tidak ada lagi. Pendekatan ini menghapus referensi lokal ke cabang-cabang terpencil yang tidak lagi saya akses.
Hati
@aldo, tentang xargs -r, yakni --no-run-if-emptyekstensi GNU artinya, inilah penjelasan yang bagus .
ryenus
4

Penghapusan selalu merupakan tugas yang menantang dan bisa berbahaya !!! Karena itu, pertama jalankan perintah berikut untuk melihat apa yang akan terjadi:

git push --all --prune --dry-run

Dengan melakukan seperti di atas, git akan memberi Anda daftar apa yang akan terjadi jika perintah di bawah ini dijalankan.

Kemudian jalankan perintah berikut untuk menghapus semua cabang dari repo jarak jauh yang tidak ada dalam repo lokal Anda:

git push --all --prune
Timothy LJ Stewart
sumber
10
Perintah ini tampaknya berbahaya ... Berhasil menghapus apa yang saya inginkan (dan tidak dapat melakukan dengan setidaknya empat jawaban di atas). Tetapi itu juga menghapus empat cabang dev lainnya. Git benar-benar menyebalkan ...
jww
2
Cabang-cabang itu pasti belum ada di daerah Anda. Namun semuanya tidak hilang. Git commit, Git reflog dan kemudian git reset --hard <checksum>. Anda dapat secara harfiah melakukan komit (alias simpan) dan orang lain dengan ini. Cabang hanyalah sebuah label, menghapus label tidak menghapus save ... itu akan selamanya memiliki sebuah checksum. Beri tahu saya jika saya bisa membantu
Timothy LJ Stewart
3
Tentu saja, Anda ingin memulihkan ini dengan cukup cepat karena pengumpul sampah git pada akhirnya akan menghapus komit yang tidak dirujuk oleh cabang.
Andrew
1
Baik untuk menambahkan -n(dry run) ke perintah ini sehingga Anda dapat melihat perubahan dan kemudian jika semuanya baik-baik saja panggil lagi tanpa -n.
mati865
1
Setuju dengan @GuiWeinmann - Ini terlalu berbahaya, terutama tanpa info khusus untuk setidaknya menjalankan ini dalam dry-run terlebih dahulu.
Vivek M. Chawla
2

Berikut adalah cara melakukannya dengan SourceTree (v2.3.1):
1. Klik Ambil
2. Periksa "Cabang pelacakan prune ..."
3. Tekan OK
4. 😀

masukkan deskripsi gambar di sini

kelapa
sumber
1

Saya harus menambahkan jawaban di sini, karena jawaban yang lain tidak mencakup kasus saya atau rumit. Saya menggunakan github dengan pengembang lain dan saya hanya ingin semua cabang lokal yang remote (mungkin digabung dan) dihapus dari PR github yang akan dihapus sekaligus dari mesin saya. Tidak, hal-hal sepertigit branch -r --merged tidak mencakup cabang-cabang yang tidak digabungkan secara lokal, atau yang tidak bergabung sama sekali (ditinggalkan) dll, jadi diperlukan solusi yang berbeda.

Bagaimanapun, langkah pertama yang saya dapatkan dari jawaban lain:

git fetch --prune

Lari kering git remote prune origin sepertinya akan melakukan hal yang sama dalam kasus saya, jadi saya pergi dengan versi terpendek untuk membuatnya tetap sederhana.

Sekarang, git branch -vharus menandai cabang yang remote-nya dihapus [gone]. Karena itu, yang perlu saya lakukan adalah:

git branch -v|grep \\[gone\\]|awk '{print $1}'|xargs -I{} git branch -D {}

Sesederhana itu, menghapus semua yang saya inginkan untuk skenario di atas.

xargsSintaks yang kurang umum adalah agar ia juga berfungsi di Mac & BSD di samping Linux. Hati-hati, perintah ini bukan lari kering sehingga akan menghapus paksa semua cabang yang ditandai [gone]. Jelas, ini git tidak ada yang hilang selamanya, jika Anda melihat cabang dihapus yang Anda inginkan disimpan Anda selalu dapat membatalkan penghapusan mereka (perintah di atas akan mendaftarkan hash mereka pada penghapusan, jadi sederhana git checkout -b <branch> <hash>.

Ekuador
sumber
0
# First use prune --dry-run to filter+delete the local branches
git remote prune origin --dry-run \
  | grep origin/ \
  | sed 's,.*origin/,,g' \
  | xargs git branch -D

# Second delete the remote refs without --dry-run
git remote prune origin

Pangkas cabang yang sama dari referensi lokal dan jarak jauh (dalam contoh saya dari origin).

Jan Winter
sumber