ทำความสะอาดกิ่งก้านสาขาระยะไกลเก่า


696

ฉันทำงานจากคอมพิวเตอร์สองเครื่อง (A และ B) และเก็บรีโมทคอมไพล์ทั่วไปในไดเรกทอรีดรอปบ็อกซ์

สมมติว่าฉันมีสองสาขาหลักและ devel ทั้งคู่กำลังติดตามต้นกำเนิด / ต้นแบบระยะไกลและต้นกำเนิด / devel

ขณะนี้ในคอมพิวเตอร์ A ฉันจะลบสาขา devel บนโลคัลและรีโมต

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

ทำงานgit branch -aบนคอมพิวเตอร์ A ฉันได้รับรายการสาขาดังต่อไปนี้

  • เจ้านาย
  • ต้นกำเนิด / HEAD
  • ต้นกำเนิด / Master

ทำงานgit fetchบนคอมพิวเตอร์ B ฉันสามารถลบสาขา devel ภายในgit branch -d develเครื่องได้ แต่ฉันไม่สามารถลบสาขา devel ระยะไกลได้

git push origin :heads/devel ส่งคืนข้อความแสดงข้อผิดพลาดต่อไปนี้

ข้อผิดพลาด: ไม่สามารถผลักดันไปยังปลายทางที่ไม่มีเงื่อนไข: หัว / proxy3d refspec
ปลายทางไม่ตรงกับการอ้างอิงที่มีอยู่บนรีโมตหรือเริ่มต้นด้วยการอ้างอิง / และเราไม่สามารถเดาคำนำหน้าตามแหล่งอ้างอิง
ร้ายแรง: ปลายระยะไกลวางสายโดยไม่คาดคิด

git branch -a ยังคงแสดงรายการ Origin / Devel ในกิ่งที่อยู่ห่างไกล

ฉันจะล้างสาขาระยะไกลจากคอมพิวเตอร์ B ได้อย่างไร


4
ฉันได้รับการบอกเล่าจากผู้ที่ลองใช้งานที่เก็บคอมไพล์ในโฟลเดอร์ Dropbox นั้นค่อนข้างบอบบาง (แต่ไม่มีรายละเอียดเพิ่มเติม)
Thorbjørn Ravn Andersen

5
@ ThorbjørnRavnAndersenอาจเป็นเพราะคุณต้องรอเพื่อให้แน่ใจว่าจะซิงค์อย่างสมบูรณ์ทุกครั้งที่คุณส่งก่อนที่คุณจะแน่ใจได้ว่าจะปลอดภัยในการใช้กับเครื่องอื่น (และต้องซิงค์อีกครั้ง)
ataulm

คำตอบ:


1240

ครั้งแรกสิ่งที่เป็นผลมาจากgit branch -aในเครื่อง B?

ประการที่สองคุณได้ลบไปแล้วheads/develในoriginเพื่อที่ว่าทำไมคุณไม่สามารถลบออกจากเครื่องบี

ลอง

git branch -r -d origin/devel

หรือ

git remote prune origin

หรือ

git fetch origin --prune

และรู้สึกอิสระที่จะเพิ่ม--dry-runในตอนท้ายของgitคำสั่งของคุณเพื่อดูผลลัพธ์ของการเรียกใช้โดยไม่ต้องเรียกใช้จริง

เอกสารสำหรับและgit remote prunegit branch


50
git remote prune originทำงานให้ฉัน => * [pruned] origin/my-old-branch
Hari Karam Singh

126
git remote prune origin --dry-runแสดงให้คุณเห็นสิ่งที่จะถูกลบโดยไม่ต้องทำจริง
Wolfram Arnold

31
git fetch origin --pruneสมบูรณ์แบบในการลบสาขาที่ถูกลบ
Sébastien Barbieri

10
หากคุณมีสาขาท้องถิ่นติดตามระยะไกลที่หายไปสิ่งนี้จะไม่ลบอะไรเลย สำหรับพวกมันปรากฏขึ้นgit branch -vvตามมาgit branch -D branchnameและในที่สุดลูกพรุนก็เป็นวิธีที่ดีที่สุด
Roman Starkov

7
คุณสามารถกำหนดค่าการตัดให้เกิดขึ้นโดยอัตโนมัติเมื่อดึง / ดึงข้อมูลโดยการตั้งค่าตัวเลือกต่อไปนี้:git config remote.origin.prune true
Patrick James McDougle

101

พิจารณาที่จะเรียกใช้:

git fetch --prune

เป็นประจำในแต่ละ repo เพื่อลบสาขาในพื้นที่ที่ติดตามสาขาระยะไกลที่ถูกลบ (ไม่มีอยู่ใน repo GIT ระยะไกล)

สิ่งนี้สามารถทำให้ง่ายขึ้นโดย

git config remote.origin.prune true

นี่คือการper-repoตั้งค่าที่จะทำให้ในอนาคตgit fetch or git pullโดยอัตโนมัติพรุน

ในการตั้งค่านี้สำหรับผู้ใช้ของคุณคุณอาจแก้ไข. gitconfig และเพิ่มทั่วโลก

[fetch]
    prune = true

อย่างไรก็ตามขอแนะนำให้ทำสิ่งนี้โดยใช้คำสั่งต่อไปนี้:

git config --global fetch.prune true

หรือนำไปใช้กับทั้งระบบ (ไม่ใช่สำหรับผู้ใช้เท่านั้น)

git config --system fetch.prune true

14

นี่คือ bash script ที่สามารถทำเพื่อคุณ มันเป็นรุ่นที่ได้รับการแก้ไขของสคริปต์http://snippets.freerobby.com/post/491644841/remove-merged-branches-in-git การดัดแปลงของฉันช่วยให้สามารถรองรับตำแหน่งระยะไกลที่แตกต่างกันได้

#!/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
สิ่งนี้แตกสาขาที่เรียกว่า "ต้นกำเนิด / คุณสมบัติ / mybranch" ฉันไม่แน่ใจว่าทำไม
Stavros Korokithakis

ปัญหาอยู่ในสองseds แทนที่sed 's/\(.*\)\/\(.*\)/\1/g'โดยsed 's/\([^/]*\)\/\(.*\)/\1/g'
Benoît Latinier

14

คำสั่งนี้จะ "dry run" ลบการoriginรวมสาขา( ) จากระยะไกลทั้งหมดออกจาก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

--dry-runถ้ามันดูดีเอา นอกจากนี้คุณอาจต้องการทดสอบทางแยกนี้ก่อน


ดี ปรับแต่งของฉันใช้ Perl แทน xargs 1 + awk: git branch -r --merged | แหล่งกำเนิด grep grep -v '>' | grep -v master | perl -lpe '($ junk, $ _) = split (/ \ //, $ _, 2)' | xargs git push origin --delete
Andrew

6

หากgit branch -rแสดงสาขาติดตามระยะไกลจำนวนมากที่คุณไม่สนใจและคุณต้องการลบสาขาเหล่านั้นออกจากท้องถิ่นให้ใช้คำสั่งต่อไปนี้:

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

เวอร์ชันที่ปลอดภัยกว่าคือการลบเฉพาะสิ่งที่รวมกันเท่านั้น:

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

สิ่งนี้อาจเป็นประโยชน์สำหรับโครงการขนาดใหญ่ที่คุณไม่ต้องการสาขาฟีเจอร์ของเพื่อนร่วมทีมคนอื่น ๆ แต่มีสาขาการติดตามระยะไกลจำนวนมากที่ดึงมาจากการโคลนครั้งแรก

git fetchอย่างไรก็ตามขั้นตอนนี้เพียงอย่างเดียวไม่เพียงพอเพราะผู้ที่ถูกลบจากระยะไกลติดตามสาขาจะกลับมาเมื่อต่อไป

หากต้องการหยุดดึงสาขาการติดตามระยะไกลคุณต้องระบุการอ้างอิงเพื่อดึงข้อมูลใน. 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/*

ในตัวอย่างข้างต้นเราจะสามารถดึงข้อมูลmaster, developและปล่อยสาขารู้สึกอิสระที่จะปรับตัวตามที่คุณต้องการ


1
ขอบคุณคำสั่งแรกใช้ได้สำหรับฉัน นอกจากนี้คุณยังสามารถดึงสาขาเดียวด้วยgit fetch origin branchnameหรือสร้างชื่อแทนต้องการft = "!f() { git fetch origin $(git rev-parse --abbrev-ref HEAD);}; f"ดึงเฉพาะสาขาปัจจุบัน (รายการโปรดส่วนตัวของฉัน) ไชโย
GiovanyMoreno

อาจจะเป็น OT แต่-rธงหมายความว่าอย่างไร ฉันเห็นxargsมี-Rข้อโต้แย้ง แต่ไม่พบอะไร-rเลย ฉันหมายถึงในทางทฤษฎีถ้าฉันจำได้อย่างถูกต้องว่าxargsทำงานอย่างไรแม้จะไม่-rทำงานก็ตาม
อัลโด 'xoen' Giambelluca

ฉันชอบคำตอบนี้ คู่ของบันทึกย่อ (ระบุชัดเจนจริงๆ) มันเป็นไปได้ที่ "แสดงตัวอย่าง" | xargs git branch -dซึ่งสาขาจะถูกลบออกโดยการเอาท่อที่ผ่านมาและคำสั่งสุดท้าย นอกจากนี้โดยการลบ-rตัวเลือก ( --remotes) จากgit branch -dเราทำความสะอาดเฉพาะสาขาในพื้นที่ (ซึ่งอาจเพียงพอที่จะพิจารณาว่าโดยค่าเริ่มต้นgit branchจะไม่แสดงสาขาระยะไกล)
อัลโด 'xoen' Giambelluca

ขอบคุณ! นี่คือสิ่งที่ฉันต้องการ โซลูชันอื่น ๆ แนะนำให้ผลักดันกิ่งก้านสาขาที่ตัดทิ้งแล้วไปยังรีโมตเพื่อลบออกที่นั่นเช่นกัน แต่นั่นก็ไม่ได้ช่วยอะไรเมื่อรีโมตถูกลบหรือไม่มีอยู่อีกต่อไป วิธีนี้ลบการอ้างอิงในพื้นที่ไปยังสาขาระยะไกลฉันไม่สามารถเข้าถึงได้อีกต่อไป
ข้อควรระวังug

@aldo ประมาณxargs -rคือ--no-run-if-emptyมันเป็นส่วนขยายของ GNU หมายความว่านี่คือคำอธิบายที่ดี
ryenus

4

การลบเป็นงานที่ท้าทายเสมอและอาจเป็นอันตรายได้ !!! ดังนั้นก่อนดำเนินการคำสั่งต่อไปนี้เพื่อดูว่าจะเกิดอะไรขึ้น:

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

การทำเช่นนี้gitจะทำให้คุณมีรายการของสิ่งที่จะเกิดขึ้นหากมีการดำเนินการคำสั่งด้านล่าง

จากนั้นเรียกใช้คำสั่งต่อไปนี้เพื่อลบสาขาทั้งหมดออกจาก repo ระยะไกลที่ไม่ได้อยู่ใน repo ท้องถิ่นของคุณ:

git push --all --prune

10
คำสั่งนี้ดูเหมือนว่าจะเป็นอันตราย ... มันสามารถลบสิ่งที่ฉันต้องการได้ (และไม่สามารถทำอย่างน้อยสี่คำตอบข้างต้น) แต่มันก็ลบ dev-branch อื่นอีกสี่ตัว Git แย่แล้ว ...
jww

2
สาขาเหล่านั้นต้องไม่อยู่ในพื้นที่ของคุณ อย่างไรก็ตามทั้งหมดจะไม่สูญหาย Git คอมมิชชัน Git reflog จากนั้น git reset - ฮาร์ด <checksum> คุณสามารถกระทำใด ๆ (หรือที่เรียกว่าบันทึก) และอื่น ๆ ด้วยสิ่งนี้ สาขาเป็นเพียงป้ายกำกับการลบป้ายกำกับไม่ได้ลบบันทึก ... มันจะมีการตรวจสอบตลอดไป แจ้งให้เราทราบหากฉันสามารถช่วยได้
ทิโมธี LJ Stewart

3
แน่นอนคุณจะต้องกู้คืนสิ่งเหล่านี้อย่างรวดเร็วเนื่องจากตัวกำจัดขยะของคอมไพล์จะลบการกระทำที่ไม่ได้อ้างอิงโดยสาขา
แอนดรู

1
เป็นการดีที่จะเพิ่ม-n(เรียกใช้แบบแห้ง) ลงในคำสั่งนี้เพื่อให้คุณสามารถดูตัวอย่างการเปลี่ยนแปลงได้แล้วถ้าทุกอย่างไม่เป็น-nปัญหา
mati865

1
เห็นด้วยกับ @GuiWeinmann - สิ่งนี้อันตรายเกินไปโดยเฉพาะอย่างยิ่งหากไม่มีคำบรรยายพิเศษให้เรียกใช้ในระยะแห้งก่อน
Vivek M. Chawla

2

นี่คือวิธีการทำกับ SourceTree (v2.3.1):
1. คลิกดึงข้อมูล
2. ตรวจสอบ "กิ่งติดตามลูกพรุน ... "
3. กดตกลง
4. 😀

ป้อนคำอธิบายรูปภาพที่นี่


1

ฉันจะต้องเพิ่มคำตอบที่นี่เพราะคำตอบอื่นไม่ครอบคลุมกรณีของฉันหรือมีความซับซ้อนโดยไม่จำเป็น ฉันใช้ GitHub กับนักพัฒนาคนอื่นและฉันต้องการให้สาขาในพื้นที่ทั้งหมดที่มีการลบรีโมต (อาจรวมและ) จาก Github PR เพื่อลบออกจากเครื่องของฉันในครั้งเดียว ไม่สิ่งต่าง ๆgit branch -r --mergedไม่ครอบคลุมสาขาที่ไม่ได้รวมอยู่ภายในเครื่องหรือสาขาที่ไม่ได้รวมอยู่ (ถูกทอดทิ้ง) ฯลฯ ดังนั้นจึงจำเป็นต้องใช้โซลูชันที่แตกต่างกัน

อย่างไรก็ตามขั้นตอนแรกที่ฉันได้รับมาจากคำตอบอื่น ๆ :

git fetch --prune

แห้งวิ่งgit remote prune originดูเหมือนว่ามันจะทำสิ่งเดียวกันในกรณีของฉันดังนั้นฉันไปกับรุ่นสั้นที่สุดที่จะให้มันง่าย

ตอนนี้ควรทำเครื่องหมายสาขาที่มีรีโมทจะถูกลบออกเป็นgit branch -v [gone]ดังนั้นสิ่งที่ฉันต้องทำคือ:

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

ง่ายเหมือนที่มันจะลบทุกอย่างที่ฉันต้องการสำหรับสถานการณ์ข้างต้น

xargsไวยากรณ์ที่พบได้น้อยคือเพื่อให้ทำงานบน Mac & BSD นอกเหนือจาก Linux [gone]ระวังคำสั่งนี้ไม่ได้เป็นแห้งจึงจะบังคับให้ลบทุกสาขาที่มีเครื่องหมายเป็น เห็นได้ชัดว่านี่เป็นอะไรที่คอมไพล์ไปตลอดกาลถ้าคุณเห็นสาขาลบที่คุณจำไว้ว่าคุณต้องการเก็บไว้คุณก็สามารถยกเลิกการลบพวกเขา 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

ตัดกิ่งสาขาเดียวกันจากผู้อ้างอิงในพื้นที่และจากระยะไกล (ในตัวอย่างของฉันorigin)

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.