Dọn dẹp cành git từ xa cũ


694

Tôi làm việc từ hai máy tính khác nhau (A và B) và lưu trữ một git từ xa chung trong thư mục dropbox.

Hãy nói rằng tôi có hai nhánh, chủ và phát. Cả hai đều đang theo dõi đối tác từ xa gốc / chủ và gốc / phát.

Bây giờ trong khi trên máy tính A, tôi xóa chi nhánh, trên cục bộ và từ xa.

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

Chạy git branch -atrên máy tính A, tôi nhận được danh sách các nhánh sau.

  • bậc thầy
  • nguồn gốc / TRỤ
  • nguồn gốc / chủ

Chạy git fetchtrên máy tính B, tôi có thể xóa chi nhánh phát cục bộ git branch -d devel, nhưng tôi không thể xóa chi nhánh phát từ xa.

git push origin :heads/devel trả về các thông báo lỗi sau.

lỗi: không thể đẩy đến đích không đủ tiêu chuẩn: Heads / proxy3d Refspec
đích không khớp với một ref hiện có trên điều khiển từ xa cũng không bắt đầu bằng ref / và chúng tôi không thể đoán được tiền tố dựa trên ref nguồn.
gây tử vong: Kết thúc từ xa treo lên bất ngờ

git branch -a vẫn liệt kê nguồn gốc / phát trong các nhánh từ xa.

Làm thế nào tôi có thể dọn sạch các chi nhánh từ xa từ máy tính B?


4
Tôi đã được thông báo bởi một người đã thử nó, rằng kho git trong các thư mục Dropbox hơi mỏng manh (nhưng không có thêm chi tiết).
Thorbjørn Ravn Andersen

5
@ ThorbjørnRavnAndersen có lẽ vì bạn phải chờ để đảm bảo nó đồng bộ hóa hoàn toàn bất cứ khi nào bạn cam kết, trước khi bạn có thể chắc chắn rằng nó an toàn khi sử dụng trên máy kia (và cần phải đồng bộ hóa khác ngay cả sau đó).
ataulm

Câu trả lời:


1239

Đầu tiên, kết quả của git branch -amáy B là gì?

Thứ hai, bạn đã xóa heads/develtrên origin, vì vậy đó là lý do bạn không thể xóa nó khỏi máy B.

Thử

git branch -r -d origin/devel

hoặc là

git remote prune origin

hoặc là

git fetch origin --prune

và thoải mái thêm --dry-runvào cuối gitcâu lệnh của bạn để xem kết quả của việc chạy nó mà không thực sự chạy nó.

Tài liệu cho git remote prunegit branch.


50
git remote prune originlàm việc cho tôi => * [pruned] origin/my-old-branch
Hari Karam Singh

126
git remote prune origin --dry-runcho bạn thấy những gì sẽ bị xóa với thực tế làm điều đó.
Wolfram Arnold

30
git fetch origin --prunelà hoàn hảo để loại bỏ các chi nhánh đã bị xóa
Sébastien Barbieri

10
Nếu bạn có một chi nhánh địa phương theo dõi một điều khiển từ xa đã biến mất, điều này sẽ không xóa bất cứ điều gì. Đối với những người, nó xuất hiện git branch -vvtheo sau git branch -D branchnamevà cuối cùng cắt tỉa là cách tốt nhất.
Roman Starkov

7
Bạn có thể định cấu hình cắt tỉa để tự động xảy ra khi kéo / tìm nạp bằng cách đặt tùy chọn sau:git config remote.origin.prune true
Patrick James McDougle

99

Xem xét để chạy:

git fetch --prune

Trên cơ sở thường xuyên trong mỗi repo để loại bỏ các nhánh cục bộ đã theo dõi một nhánh từ xa đã bị xóa (không còn tồn tại trong repo GIT từ xa).

Điều này có thể được đơn giản hóa hơn nữa bởi

git config remote.origin.prune true

đây là một per-repothiết lập sẽ làm cho bất kỳ tương lai nào git fetch or git pullsẽ tự động cắt tỉa .

Để thiết lập điều này cho người dùng của bạn, bạn cũng có thể chỉnh sửa .gitconfig toàn cầu và thêm

[fetch]
    prune = true

Tuy nhiên, chúng tôi khuyên bạn nên thực hiện bằng lệnh sau:

git config --global fetch.prune true

hoặc để áp dụng hệ thống rộng rãi (không chỉ cho người dùng)

git config --system fetch.prune true

14

Đây là bash script có thể làm điều đó cho bạn. Đây là phiên bản sửa đổi của http://snippets.freerulk.com/post/491644841/remove-merged-branches-in-git script. Sửa đổi của tôi cho phép nó hỗ trợ các địa điểm từ xa khác nhau.

#!/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

1
Điều này đã phá vỡ một nhánh gọi là "origin / Feature / mybranch", tôi không chắc tại sao.
Stavros Korokithakis

Vấn đề là trong hai seds. Thay thế sed 's/\(.*\)\/\(.*\)/\1/g'bằngsed 's/\([^/]*\)\/\(.*\)/\1/g'
Benoît Latinier

14

Lệnh này sẽ "chạy khô" xóa tất cả các originnhánh được hợp nhất từ xa ( ) master. Bạn có thể thay đổi điều đó, hoặc, thêm các nhánh bổ sung sau chủ: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

Nếu nó trông tốt, loại bỏ --dry-run. Ngoài ra, bạn có thể muốn kiểm tra điều này trên một ngã ba trước.


Đẹp. Tinh chỉnh của tôi bằng cách sử dụng perl thay vì xargs + awk: git Branch -r --merged | nguồn gốc grep | grep -v '>' | grep -v chủ | perl -lpe '($ rác, $ _) = split (/ \ //, $ _, 2)' | xargs git đẩy nguồn gốc --delete
Andrew

6

Nếu git branch -rhiển thị nhiều nhánh theo dõi từ xa mà bạn không quan tâm và bạn chỉ muốn xóa chúng khỏi cục bộ, hãy sử dụng lệnh sau:

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

Một phiên bản an toàn hơn sẽ chỉ loại bỏ những cái đã hợp nhất:

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

Điều này có thể hữu ích cho các dự án lớn, nơi bạn không cần các nhánh tính năng của các đồng đội khác nhưng có rất nhiều nhánh theo dõi từ xa được tìm thấy trên bản sao ban đầu.

Tuy nhiên, chỉ riêng bước này là không đủ, bởi vì những nhánh theo dõi từ xa đã bị xóa sẽ quay trở lại tiếp theo git fetch.

Để dừng tìm nạp các nhánh theo dõi từ xa đó, bạn cần chỉ định rõ ràng các ref để tìm nạp trong .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/*

Trong ví dụ trên chúng ta chỉ lấy master, developphát hành các chi nhánh, cảm thấy tự do để thích ứng như bạn cần.


1
Cảm ơn, lệnh đầu tiên làm việc cho tôi. Bạn cũng có thể chỉ tìm nạp một nhánh với git fetch origin branchnamehoặc tạo bí danh ft = "!f() { git fetch origin $(git rev-parse --abbrev-ref HEAD);}; f"để chỉ tìm nạp nhánh hiện tại (sở thích cá nhân của tôi). Chúc mừng.
GiovanyMoreno

Có thể OT nhưng -rcờ có nghĩa là gì? Tôi thấy xargscó một -Rcuộc tranh cãi nhưng không tìm thấy bất cứ điều gì về -r. Ý tôi là, về lý thuyết nếu tôi nhớ chính xác cách thức xargshoạt động, ngay cả khi không có -rnó sẽ hoạt động.
Aldo 'xoen' Giambelluca

Tôi thích câu trả lời này. Một vài ghi chú (nêu rõ thực sự). Có thể "xem trước" những nhánh nào sẽ bị xóa bằng cách xóa ống cuối cùng và lệnh cuối cùng | xargs git branch -d. Ngoài ra, bằng cách xóa -rtùy chọn ( --remotes) khỏi git branch -dchúng tôi, chúng tôi chỉ xóa các nhánh cục bộ (có thể đủ xem xét rằng theo mặc định git branchkhông hiển thị các nhánh từ xa).
Aldo 'xoen' Giambelluca

Cảm ơn! Đây chính xác là những gì tôi cần. Các giải pháp khác đề nghị đẩy các nhánh địa phương được cắt tỉa vào điều khiển từ xa để loại bỏ chúng ở đó, nhưng điều đó không giúp ích gì khi điều khiển từ xa đã bị xóa hoặc không còn tồn tại. Cách tiếp cận này đã loại bỏ các tham chiếu cục bộ đến các nhánh từ xa mà tôi không còn có quyền truy cập.
cảnh báo

@aldo, về xargs -r, cụ thể --no-run-if-empty, đó là một phần mở rộng GNU, đây là một lời giải thích hay .
ryenus

4

Xóa luôn là một nhiệm vụ đầy thách thức và có thể nguy hiểm !!! Do đó, trước tiên hãy thực hiện lệnh sau để xem điều gì sẽ xảy ra:

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

Bằng cách làm như trên, gitsẽ cung cấp cho bạn một danh sách những gì sẽ xảy ra nếu lệnh dưới đây được thực thi.

Sau đó chạy lệnh sau để xóa tất cả các nhánh khỏi repo từ xa không có trong repo cục bộ của bạn:

git push --all --prune

10
Lệnh này có vẻ nguy hiểm ... Nó quản lý để xóa những gì tôi muốn (và không thể thực hiện với ít nhất bốn câu trả lời ở trên). Nhưng nó cũng xóa bốn nhánh dev khác. Git hoàn toàn sucks ...
jww

2
Những chi nhánh phải không có trên địa phương của bạn. Tuy nhiên, tất cả là không bị mất. Git commit, Git reflog và sau đó git reset --hard <checksum>. Bạn có thể theo nghĩa đen đối với bất kỳ cam kết nào (còn gọi là lưu) và những người khác với điều này. Chi nhánh chỉ là một nhãn, xóa nhãn không xóa lưu ... nó sẽ mãi mãi có một tổng kiểm tra. Hãy cho tôi biết nếu tôi có thể giúp
Timothy LJ Stewart

3
Tất nhiên, bạn sẽ muốn khôi phục những thứ này khá nhanh vì trình thu gom rác của git cuối cùng sẽ xóa các xác nhận không được tham chiếu bởi các chi nhánh.
Andrew

1
Thật tốt khi thêm -n(chạy khô) vào lệnh này để bạn có thể xem trước các thay đổi và sau đó nếu mọi thứ đều ổn, hãy gọi lại mà không cần -n.
mati865

1
Đồng ý với @GuiWeinmann - Điều này quá nguy hiểm, đặc biệt là không có chú thích cụ thể để ít nhất chạy cái này trong chạy khô trước.
Vivek M. Chawla

2

Dưới đây là cách thực hiện với SourceTree (v2.3.1):
1. Nhấp vào Tìm nạp
2. Kiểm tra "Chi nhánh theo dõi cắt tỉa ..."
3. Nhấn OK
4.

nhập mô tả hình ảnh ở đây


1

Tôi sẽ phải thêm một câu trả lời ở đây, bởi vì các câu trả lời khác không bao gồm trường hợp của tôi hoặc rất phức tạp. Tôi sử dụng github với các nhà phát triển khác và tôi chỉ muốn tất cả các chi nhánh địa phương có điều khiển từ xa (có thể được hợp nhất và) bị xóa khỏi github PR sẽ bị xóa trong một lần khỏi máy của tôi. Không, những thứ như git branch -r --mergedkhông bao gồm các nhánh không được sáp nhập cục bộ hoặc những nhánh không được hợp nhất hoàn toàn (bị bỏ rơi), do đó, cần một giải pháp khác.

Dù sao, bước đầu tiên tôi đã nhận được nó từ các câu trả lời khác:

git fetch --prune

Một sự khô khan git remote prune origincó vẻ như nó sẽ làm điều tương tự trong trường hợp của tôi, vì vậy tôi đã đi với phiên bản ngắn nhất để giữ cho nó đơn giản.

Bây giờ, git branch -vnên đánh dấu các nhánh có điều khiển từ xa bị xóa là [gone]. Do đó, tất cả những gì tôi cần làm là:

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

Đơn giản như vậy, nó xóa mọi thứ tôi muốn cho kịch bản trên.

xargsCú pháp ít phổ biến hơn là nó cũng hoạt động trên Mac & BSD ngoài Linux. Cẩn thận, lệnh này không phải là chạy khô nên nó sẽ buộc xóa tất cả các nhánh được đánh dấu là [gone]. Rõ ràng, điều này không có gì là mãi mãi, nếu bạn thấy các nhánh bị xóa mà bạn nhớ bạn muốn giữ, bạn luôn có thể phục hồi chúng (lệnh trên sẽ liệt kê hàm băm của chúng khi xóa, vì vậy rất đơn giản git checkout -b <branch> <hash>.


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

Cắt tỉa các nhánh giống nhau từ ref địa phương và từ xa (trong ví dụ của tôi từ origin).

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.