อะไรคือความแตกต่างระหว่างลูกพรุนทางไกลของคอมไพล์ลูกพรุนคอมไพล์การเรียก git --prune เป็นต้น


358

สถานการณ์ของฉันคือสิ่งนี้ ... ใครบางคนที่ทำงานใน repo เดียวกันได้ลบสาขาจาก repo ในพื้นที่ของเขา & จากระยะไกล ...

คนส่วนใหญ่ที่ถามเกี่ยวกับปัญหาประเภทนี้ใน Stack Overflow หรือเว็บไซต์อื่น ๆ ที่มีปัญหาสาขาต่าง ๆ ยังคงแสดงอยู่ในรายการสาขาการติดตามระยะไกลgit branch -aที่ด้านล่าง:

* master
  develop
  feature_blah
  remotes/origin/master
  remotes/origin/develop
  remotes/origin/feature_blah
  remotes/origin/random_branch_I_want_deleted

อย่างไรก็ตามในสถานการณ์ของฉันสาขาที่ไม่ควรอยู่ที่นั่นอยู่ในท้องถิ่น:

* master
  develop
  feature_blah
  random_branch_I_want_deleted
  remotes/origin/master
  remotes/origin/develop
  remotes/origin/feature_blah

เมื่อฉันทำสิ่งใดสิ่งหนึ่งต่อไปนี้มันจะไม่ถูกลบในเครื่อง:

$ git prune

ฉันก็ลอง:

$ git remote prune origin
$ git fetch --prune

ข้อมูลที่เป็นประโยชน์เพิ่มเติม: เมื่อฉันตรวจสอบgit remote show originสิ่งนี้จะมีลักษณะ:

* remote origin
Fetch URL: utilities:homeconnections_ui.git
Push  URL: utilities:homeconnections_ui.git
HEAD branch: master
Remote branches:
 master                        tracked
 develop                       tracked
 feature_blah                  tracked
 other123                      tracked
 other444                      tracked
 other999                      tracked
Local branches configured for 'git pull':
 develop                      merges with remote develop
 feature_blah                 merges with remote other999
 master                       merges with remote master
 random_branch_I_want_deleted merges with remote random_branch_I_want_deleted
Local refs configured for 'git push':
 develop         pushes to develop     (local out of date)
 master          pushes to master      (up to date)
 feature_blah    pushes to feature_blah(up to date)

โปรดสังเกตว่ามันมีเฉพาะในส่วนที่มีชื่อว่า Local branches configured for 'git pull':

ทำไม?


git branch -d the_local_branch
krsteeve

1
ขอบคุณ แต่ฉันแค่อยากรู้ว่าทำไมมันอาจเกิดขึ้น
gogogadgetinternet

มีความแตกต่างเล็กน้อยเมื่อจัดการกับลำดับชั้นสาขา ( x/y): มันได้รับการแก้ไข (ดูคำตอบของฉันด้านล่าง )
VonC

คำตอบ:


664

ฉันไม่โทษคุณที่ทำให้ผิดหวังเกี่ยวกับเรื่องนี้ วิธีที่ดีที่สุดในการดูคือ อาจมีสามเวอร์ชันของทุกสาขาระยะไกล:

  1. สาขาจริงในที่เก็บระยะไกล
    (เช่น repo ระยะไกลที่https://example.com/repo.git , refs/heads/master)
  2. สแน็ปช็อตของสาขานั้นในเครื่อง (เก็บไว้ที่ใต้refs/remotes/...)
    (เช่น repo ในพื้นที่refs/remotes/origin/master)
  3. และสาขาในพื้นที่ที่อาจติดตามสาขาระยะไกล
    (เช่น repo ในพื้นที่refs/heads/master)

เริ่มgit pruneกันเลย สิ่งนี้จะลบวัตถุที่ไม่มีการอ้างอิงอีกต่อไป แต่จะไม่ลบการอ้างอิง ในกรณีของคุณคุณมีสาขาท้องถิ่น นั่นหมายถึงมีชื่ออ้างอิงrandom_branch_I_want_deletedที่อ้างถึงวัตถุบางอย่างที่แสดงถึงประวัติของสาขานั้น ดังนั้นโดยความหมายจะไม่ลบgit prune random_branch_I_want_deletedจริงๆแล้วgit pruneเป็นวิธีการลบข้อมูลที่สะสมใน Git แต่ไม่ได้อ้างอิงโดยอะไร โดยทั่วไปแล้วจะไม่มีผลกับมุมมองของสาขาใด ๆ

git remote prune originและgit fetch --pruneทั้งสองทำงานกับการอ้างอิงภายใต้refs/remotes/...(ฉันจะอ้างถึงสิ่งเหล่านี้เป็นการอ้างอิงระยะไกล) ไม่ส่งผลกระทบต่อสาขาท้องถิ่น git remoteรุ่นจะเป็นประโยชน์ถ้าคุณต้องการที่จะลบการอ้างอิงระยะไกลภายใต้ระยะไกลโดยเฉพาะอย่างยิ่ง มิฉะนั้นทั้งสองก็ทำสิ่งเดียวกัน ดังนั้นในระยะสั้นgit remote pruneและgit fetch --pruneดำเนินการในข้อ 2 ข้างต้น ตัวอย่างเช่นหากคุณลบสาขาโดยใช้ git web GUI และไม่ต้องการให้แสดงในรายการสาขาท้องถิ่นของคุณอีกต่อไป ( git branch -r) นี่คือคำสั่งที่คุณควรใช้

ในการลบสาขาในพื้นที่คุณควรใช้git branch -d(หรือ-Dไม่รวมสาขาที่ใดก็ได้) FWIW ไม่มีคำสั่ง git ที่จะลบสาขาการติดตามโลคัลโดยอัตโนมัติหากรีโมตสาขาหายไป


22
วิธีนี้จะทำได้ดีกว่าในการตอบคำถามโดยรวมโดยอธิบายความแตกต่างที่เกี่ยวข้อง นอกจากนี้ยังตอบคำถามเพิ่มเติมที่ฉันมีจากคำถามข้างต้น
gogogadgetinternet

14
คำสั่งนี้จะแสดงรายการของสาขาในประเทศทั้งหมดที่ไม่มีสาขาระยะไกลที่เกี่ยวข้อง คุณสามารถท่อนี้xargs git branch -Dแต่ทราบว่าสาขาใหม่ที่คุณได้สร้าง แต่ไม่เคยผลักดันไปยังเซิร์ฟเวอร์จะถูกลบออกเพื่อให้ดอกยางอย่างระมัดระวัง: git branch -r | awk '{print $1}' | egrep -v -f /dev/fd/0 <(git branch -vv | grep origin) | awk '{print $1}'
เจสันวอลตัน

4
@Seed ไม่มันไม่ได้ :-( มันลบการอ้างอิงระยะไกลในพื้นที่เท่านั้นฉันเพิ่งตรวจสอบสิ่งนี้กับรุ่น 2.7.0
John Szakmeister

1
@ BlueRaja-DannyPflughoeft ระวังด้วยวิธีการนั้น ตัวอย่างเช่นขึ้นอยู่กับวิธีที่คุณทำกิ่งมั่นคงของคุณพวกเขาอาจรวมเข้ากับสาขาหลักและคุณจะสิ้นสุดการลบพวกเขา ไม่ใช่การสูญเสียครั้งใหญ่ที่นี่เนื่องจากคุณไม่ได้ลบออกจากเซิร์ฟเวอร์ แต่ถ้าคุณมีการกำหนดค่าพิเศษใด ๆ ที่คุณตั้งไว้มันจะหายไปเมื่อลบสาขา
John Szakmeister

1
@Cloud ไม่จริงทั้งหมด สามารถบรรจุการอ้างอิง (ดูpacked-refsไฟล์ใน.gitพื้นที่) ดังนั้นจึงไม่จำเป็นต้องเป็นเรื่องง่าย ๆ ในการลบไฟล์เหล่านี้ผ่านทาง explorer ของไฟล์ ดีกว่าที่จะใช้คำสั่งเพื่อให้แน่ใจว่าทั้งสองได้รับการดูแลอย่างถูกต้อง
John Szakmeister

55

git remote pruneและgit fetch --pruneทำสิ่งเดียวกัน: ลบการอ้างอิงไปยังกิ่งที่ไม่มีอยู่บนรีโมทดังที่คุณพูด คำสั่งที่สองเชื่อมต่อกับรีโมตและดึงข้อมูลสาขาปัจจุบันก่อนที่จะทำการตัด

อย่างไรก็ตามมันไม่ได้สัมผัสสาขาท้องถิ่นที่คุณเช็คเอาต์ซึ่งคุณสามารถลบได้

git branch -d  random_branch_I_want_deleted

แทนที่-dด้วย-Dหากสาขาไม่ถูกรวมในที่อื่น

git prune ทำสิ่งที่แตกต่างมันกำจัดวัตถุที่ไม่สามารถเข้าถึงได้ผู้ที่กระทำที่ไม่สามารถเข้าถึงได้ในสาขาหรือแท็กใด ๆ และไม่ต้องการอีกต่อไป


1
ฉันรู้ว่ามันดูเหมือนชัดเจน แต่git pruneไม่เพียงแต่มองหากิ่งและแท็กเท่านั้น

ดังนั้นในกรณีของฉันทำไมลูกพรุนจึงไม่ทำงาน เพราะมันไม่สนใจสาขาท้องถิ่น แต่เป็นการอ้างอิงจากระยะไกล? ขอบคุณสำหรับข้อมูลที่กระชับ
gogogadgetinternet

@hvd มีผู้อ้างอิงประเภทใดนอกจากสาขาและแท็ก?
CharlesB

@gogogadgetinternet ใช่แน่นอน (สมมติว่าคุณหมายถึงgit remote prune)
CharlesB

4
IMO ระเบียบการตั้งชื่อ git ของการใช้ "ลูกพรุน" สำหรับทั้งคอลเลกชันวัตถุและการอ้างอิงการล้างข้อมูลเป็นที่ซึ่งความสับสนเกิดขึ้น แต่นั่นเป็นเพียงหนึ่งในหลาย ๆ ปริศนา UI :-)
torek

14

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

หากพวกคุณเห็นปัญหาใด ๆ เกี่ยวกับเรื่องนี้โปรดแจ้งให้เราทราบและฉันจะแก้ไข (ฯลฯ ฯลฯ )

บันทึกในไฟล์ที่เรียกว่าgit-rm-ntb(เรียกมันว่าอะไรก็ตาม) PATHและเปิดใช้งาน:

git-rm-ntb <remote1:optional> <remote2:optional> ...

clean()
{
  REMOTES="$@";
  if [ -z "$REMOTES" ]; then
    REMOTES=$(git remote);
  fi
  REMOTES=$(echo "$REMOTES" | xargs -n1 echo)
  RBRANCHES=()
  while read REMOTE; do
    CURRBRANCHES=($(git ls-remote $REMOTE | awk '{print $2}' | grep 'refs/heads/' | sed 's:refs/heads/::'))
    RBRANCHES=("${CURRBRANCHES[@]}" "${RBRANCHES[@]}")
  done < <(echo "$REMOTES" )
  [[ $RBRANCHES ]] || exit
  LBRANCHES=($(git branch | sed 's:\*::' | awk '{print $1}'))
  for i in "${LBRANCHES[@]}"; do
    skip=
    for j in "${RBRANCHES[@]}"; do
      [[ $i == $j ]] && { skip=1; echo -e "\033[32m Keeping $i \033[0m"; break; }
    done
    [[ -n $skip ]] || { echo -e "\033[31m $(git branch -D $i) \033[0m"; }
  done
}

clean $@

ขอบคุณ! สัมผัสที่ดีกับเอาท์พุตสี ;-)
BVengerov

2
$ (git branch -d $ i) จะปลอดภัยกว่าที่จะลบเฉพาะสาขาที่ผสานหรือไม่
user2012677

มีประโยชน์มากขอบคุณมาก !!!
Robin Hartland

ตัวเลือกที่ปลอดภัยกว่าถูกกล่าวถึงในstackoverflow.com/questions/7726949/…
Michael Freidgeim

13

โปรดทราบว่าความแตกต่างระหว่างgit remote --pruneและgit fetch --pruneกำลังได้รับการแก้ไขโดยคอมมิชชัน 10a6cc8โดยTom Miller ( tmiller) (สำหรับ git 1.9 / 2.0, Q1 2014):

เมื่อเรามีสาขาการติดตามระยะไกลชื่อ " frotz/nitfol" จากการดึงข้อมูลก่อนหน้านี้และอัปสตรีมตอนนี้มีสาขาที่ชื่อว่า "** frotz " ** fetchจะไม่สามารถลบ " frotz/nitfol" ด้วยการgit fetch --pruneออกจากอัปสตรีม "
git จะแจ้งให้ผู้ใช้ใช้ " git remote prune" เพื่อแก้ไขปัญหา

ดังนั้น: เมื่อrepo อัปสตรีมมีสาขา ("frotz") ที่มีชื่อเดียวกันกับลำดับชั้นของสาขา ("frotz / xxx", การตั้งชื่อสาขาที่เป็นไปได้) git remote --pruneก็ประสบความสำเร็จ (ในการทำความสะอาดสาขาการติดตามระยะไกลจาก repo ของคุณ) แต่git fetch --pruneล้มเหลว

ไม่อีกแล้ว:

เปลี่ยนวิธีการfetch --pruneทำงานของ "" โดยการย้ายการดำเนินการการตัดก่อนการดึงข้อมูล
วิธีนี้แทนที่จะเตือนผู้ใช้ถึงข้อขัดแย้งมันจะแก้ไขโดยอัตโนมัติ

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