รายชื่อและการลบ Git กระทำการที่ไม่มีสาขา (dangling?)


146

ฉันมีพื้นที่เก็บข้อมูล Git ที่มีความมุ่งมั่นมากมายที่ไม่มีสาขาใดที่ฉันสามารถทำได้git showแต่เมื่อฉันพยายามที่จะแสดงรายการสาขาที่มีพวกเขามันจะไม่รายงานอะไรเลย

ฉันคิดว่านี่เป็นปัญหาเกี่ยวกับการผูกมัด / ปัญหาต้นไม้ (เนื่องจากสาขา -D) ดังนั้นฉันจึงตัด repo แต่ฉันยังเห็นพฤติกรรมเดิมหลังจากนั้น:

$ git fetch origin

$ git fsck --unreachable
$ git fsck

ไม่มีเอาต์พุตไม่มีอะไรห้อยต่องแต่ง (ใช่ไหม) แต่ความมุ่งมั่นที่มีอยู่

$ git show 793db7f272ba4bbdd1e32f14410a52a412667042
commit 793db7f272ba4bbdd1e32f14410a52a412667042
Author: ...

และไม่สามารถเข้าถึงได้ผ่านสาขาใด ๆ เช่น

$ git branch --contains 793db7f272ba4bbdd1e32f14410a52a412667042

ไม่ให้ผลลัพธ์

สถานะของการกระทำนั้นคืออะไร? ฉันจะแสดงรายการข้อผูกพันทั้งหมดในสถานะที่คล้ายกันได้อย่างไร ฉันจะลบการผูกมัดเช่นนั้นได้อย่างไร


เป็นไปได้ที่ซ้ำกันของวิธีการลบการคอมมิทที่ผิดพลาด?
Josh Lee

คำตอบ:


75

ไม่มีเอาต์พุตไม่มีอะไรห้อยต่องแต่งใช่ไหม

โปรดทราบว่าการส่งข้อความที่อ้างอิงจากการอ้างอิงของคุณนั้นสามารถเข้าถึงได้

สถานะของการกระทำนั้นคืออะไร? ฉันจะแสดงรายการการกระทำทั้งหมดที่มีสถานะคล้ายกันได้อย่างไร

ส่งผ่าน--no-reflogsการโน้มน้าวgit fsckให้แสดงให้คุณเห็น

ฉันจะลบการผูกมัดเช่นนั้นได้อย่างไร

เมื่อรายการ reflog git gcของคุณจะหมดอายุวัตถุเหล่านั้นก็จะได้รับการทำความสะอาดขึ้นโดย

หมดอายุถูกควบคุมโดยgc.pruneexpire, gc.reflogexpireและgc.reflogexpireunreachableการตั้งค่า cf เลย git help config.

ค่าเริ่มต้นค่อนข้างสมเหตุสมผล


2
ดังนั้นโดยพื้นฐานแล้วคุณกำลังบอกว่าการรีโฟลว์สำหรับการผูกห้อยจะถูกลบหลังจากผ่านไประยะหนึ่งโดยอัตโนมัติหรือไม่
MoralCode

2
โดยทั่วไป: ใช่ - ยกเว้นว่าคำถามนั้นสับสนเล็กน้อย ฉันกำลังบอกว่ารายการ reflog ทั้งหมดจะถูกลบออกโดยอัตโนมัติหลังจากผ่านไปครู่หนึ่ง แต่คุณสามารถเปลี่ยนได้ผ่านการตั้งค่าการกำหนดค่า และเนื่องจากความมุ่งมั่นนั้นถูกเรียกว่าdanglingเมื่อไม่มีอะไรที่ชี้ไปยังมันรวมถึงรายการ reflog -, "การเรียกใช้ dangling commits" จึงไม่ใช่เรื่อง พวกเขาจะ“ reflogs สำหรับการกระทำที่ไม่สามารถเข้าถึงได้
อริสโตเติล Pagaltzis

'พวกเขาจะเป็น "reflogs สำหรับการกระทำที่ไม่สามารถเข้าถึงได้" แต่คุณพูดว่า "การส่งข้อความอ้างอิงจากการอ้างอิงของคุณจะถือว่าสามารถเข้าถึงได้" ดังนั้น "reflogs สำหรับการกระทำที่ไม่สามารถเข้าถึงได้" เป็นอย่างไร? ผมงงไปหมดแล้ว.
LarsH

1
ใช่ฉันไม่สอดคล้องกัน โดยปกติผู้คนจะไม่คิดถึงการอ้างอิงและเมื่อพวกเขาพูดว่า "ไม่สามารถเข้าถึงได้" มันก็หมายถึง "จากการอ้างอิง" แม้แต่git help glossaryกำหนดไว้อย่างนั้น ... ในขณะที่คำจำกัดความของคำว่า "เข้าถึงได้" นั้นไม่ได้แคบลงดังนั้นวิธีนี้จึงขัดแย้งกัน ตลก - ดังนั้นสิ่งที่ฉันพูดจริง ๆ แล้วสอดคล้องกับความสับสนในgitglossary... มันไม่ใช่แนวคิดที่สับสน แต่เป็นเพียงคำศัพท์ ประเด็นก็คือ“ การห้อยต่องแต่ง” นั้นเป็นสิ่งที่ไม่มีสิ่งใดชี้ไป มันจะช่วยเหลือถ้าผมบอกว่า“reflogs สำหรับมิฉะนั้นกระทำไม่สามารถเข้าถึง” ... ?
อริสโตเติล Pagaltzis

นี่คือความสับสนมาก มาทำให้มันง่าย เมื่ออยู่บนสาขาmaster, คุณทำและได้รับการกระทำgit commit 000001แล้วคุณจะทำซึ่งจะช่วยให้คุณกระทำgit commit --amend 000002ไม่มีการแท็กหรือสาขาที่ชี้ไปยัง000001อีกต่อไปและคุณไม่สามารถดูได้ในบันทึกของคุณโดยไม่ต้อง--reflogตัวเลือก git checkout 000001แต่ถ้าคุณต้องการคุณอาจจะยังคงได้รับไปด้วย ตอนนี้คำถามคือ000001การกระทำที่ห้อยอยู่หรือกระทำไม่สามารถเข้าถึงได้หรือไม่หรือทั้งสองอย่าง?
chharvey

264

ในการลบการผูกที่ผูกทั้งหมดและที่สามารถเข้าถึงได้จาก reflogs ให้ทำดังนี้:

git reflog expire --expire-unreachable=now --all
git gc --prune=now

แต่ให้แน่ใจว่านี่คือสิ่งที่คุณต้องการ ฉันแนะนำให้คุณอ่าน man pages แต่นี่คือส่วนสำคัญ:

git gcลบออบเจ็กต์ที่ไม่สามารถเข้าถึงได้ (คอมมิต, ต้นไม้, บลู (ไฟล์)) วัตถุไม่สามารถเข้าถึงได้หากไม่ได้เป็นส่วนหนึ่งของประวัติของสาขาบางสาขา จริงๆแล้วมันซับซ้อนกว่าเล็กน้อย:

git gc ทำบางสิ่งอื่น ๆ แต่ไม่เกี่ยวข้องที่นี่และไม่เป็นอันตราย

วัตถุที่เข้าไม่ถึงซึ่งมีอายุน้อยกว่าสองสัปดาห์จะไม่ถูกลบออกดังนั้นเราจึงใช้--prune=nowซึ่งหมายความว่า "ลบวัตถุที่ไม่สามารถเข้าถึงได้ที่สร้างขึ้นก่อนหน้านี้"

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

ดังนั้นเราต้องลบ reflogs เพื่อกำจัดทุกสิ่งที่ไม่สามารถเข้าถึงได้จากสาขา เราทำเช่นนั้นโดยการหมดอายุ--allreflogs อีกครั้งช่วยให้คอมไพล์บิตของ reflogs --expire-unreachable=nowเพื่อปกป้องผู้ใช้เพื่อให้เราอีกครั้งต้องบอกว่าจะไม่ทำเช่น:

เนื่องจากฉันใช้ reflog เป็นหลักในการกู้คืนจากการดำเนินการทำลายล้างฉันมักจะใช้--expire=nowแทนซึ่ง zaps reflogs อย่างสมบูรณ์


1
ฉันบอกคุณว่าคำสั่งที่ใช้ไม่ชัดเจน - ไม่ควร gc เพียงพอหรือไม่ หากคุณไม่เคยใช้ git-reflog มาก่อนคุณจะไม่รู้ ดังนั้นตอนนี้คุณรู้ว่าคำสั่งที่คุณต้องใช้คุณควรค้นหาตัวเลือกที่กล่าวถึงในหน้าคนของพวกเขา แน่นอนฉันจะแทนเพียงแค่คัดลอกข้อมูลที่มาจากที่นั่น ...
Tarsius

1
จริง ๆ แล้วฉันพูดอย่างแน่นอนว่ามันทำอะไร: "ลบทุกความมุ่งมั่นห้อยและผู้ที่สามารถเข้าถึงได้จาก reflogs" หากคุณไม่รู้ว่า reflogs คืออะไร: อ่านคู่มืออีกครั้ง
Tarsius

7
แม้ว่าคำตอบที่ได้รับอาจถูกต้อง @ erikb85 นั้นถูกต้องในการชี้ให้เห็นว่าไม่มีการศึกษาเกี่ยวกับสิ่งที่คุณได้รับคำสั่งให้ทำ การติดตามด้วย RTFM จะมีประโยชน์น้อยกว่า ใช่เราทุกคนควรอ่านเอกสารทั้งหมด ในบางกรณีผู้ที่ทำการค้นหาอาจไม่ได้รวบรวมเอกสารเพียงพอที่จะรู้ว่าเกิดอะไรขึ้น ดังนั้นการศึกษาเพียงเล็กน้อยเกี่ยวกับสิ่งที่คำสั่งกำลังทำอยู่จะเป็นประโยชน์สำหรับทุกคนที่พบคำตอบนี้ในภายหลัง
Lee Saferite

@LeeSaferite หวังว่าคุณทุกคนจะมีความสุขในขณะนี้ :-)
tarsius

12
git reflog expire --expire-unreachable=now --allลดการซ่อนของคุณทั้งหมด!
Vsevolod Golovanov

22

ฉันมีปัญหาเดียวกัน แต่หลังจากทำตามคำแนะนำทั้งหมดในกระทู้นี้:

git reflog expire --expire-unreachable=now --all
git gc --prune=now
git fsck --unreachable --no-reflogs   # no output
git branch -a --contains <commit>     # no output
git show <commit>                     # still shows up

หากไม่ใช่ reflog และไม่ใช่สาขา ... ต้องเป็นแท็ก !

git tag                             # showed several old tags created before the cleanup

ฉันลบแท็กด้วยgit tag -d <tagname>และล้างการล้างข้อมูลใหม่และคอมมิชชันเก่าก็หายไป


มีคำตอบเกี่ยวกับแท็กแล้ว ( stackoverflow.com/a/37335660/450127 ) และดูเหมือนว่านี่จะไม่เป็นการเพิ่มอะไรใหม่ สิ่งนี้ไม่ควรถูกลบออกไปเนื่องจากคำตอบก่อนหน้านี้หรือไม่
Ian Dunn

แน่นอนฉันก็มองข้ามคำตอบนั้น แม้ว่า 4 คนพบว่าคำตอบของฉันเป็นประโยชน์ดังนั้นอาจไม่ใช่เรื่องไร้ประโยชน์ใช่ไหม ฉันยังจัดกลุ่มความเป็นไปได้ทั้งหมดไว้ในคำตอบเดียว
jakub.g

1
แม้ว่าจะมีการทำซ้ำหน้านี้อาจปรากฏในผลการค้นหาของ Google และจะช่วยเหลือผู้ที่มีปัญหาเดียวกันทันทีดีกว่าเพียงแค่เปลี่ยนเส้นทางผู้คนไปเรื่อย ๆ ไปยังลิงค์ที่อาจมีคำตอบที่ถูกต้อง
Alexandre T.

14
git branch --contains 793db7f272ba4bbdd1e32f14410a52a412667042

อาจแค่ต้องเป็น

git branch -a --contains 793db7f272ba4bbdd1e32f14410a52a412667042

เพื่อรายงานสาขาจากรีโมต


ขอบคุณตอนนี้ฉันพบรีโมต / แหล่งกำเนิด / ถัดไปที่ยังคงมีคอมมิทนี้อยู่ วิธีการลบออก? git push -d origin nextไม่ช่วย
iRaS


ขอบคุณ - git fetch --pruneเคล็ดลับไม่ได้ แต่ในคำตอบทั้งหมดฉันไม่มีการตรวจสอบแท็กที่อ้างอิงการกระทำนี้ ฉันยังไม่รู้วิธีตรวจสอบแท็กด้วยการส่ง (ฉันลบทั้งหมด)
iRaS

แต่ ... นี่หมายความว่าการกระทำที่เข้าถึงได้จากสาขาระยะไกลเท่านั้น(และไม่มีสาขาในท้องถิ่น) ที่พิจารณาว่าสามารถเข้าถึงได้และดังนั้นจึงgit fsck --unreachableมีการสื่อสารผ่านเครือข่ายกับเครือข่ายระยะไกลเพื่อค้นหาว่าสามารถเข้าถึงคอมมิชชันใดได้บ้าง
LarsH

1
ตอบคำถามของฉันเอง ... ใช่การกระทำที่เข้าถึงได้จากสาขาที่อยู่ห่างไกลเท่านั้น (และไม่มีสาขาในท้องถิ่น) ที่สามารถเข้าถึงได้ แต่git fsck --unreachableไม่จำเป็นต้องสื่อสารผ่านเครือข่ายกับรีโมตเพื่อค้นหาว่าสาขารีโมตใดที่มีคอมมิต ข้อมูลสาขาระยะไกลจะถูกเก็บไว้ในเครื่องภายใต้เช่น.git/refs/remotes/origin(หรือในpacked-refs)
LarsH

8

ฉันมีปัญหาที่คล้ายกัน ฉันวิ่งgit branch --contains <commit>แล้วก็กลับไม่มีเอาท์พุทเหมือนในคำถาม

แต่แม้หลังจากวิ่ง

git reflog expire --expire-unreachable=now --all
git gc --prune=now

git show <commit>ฉันก็ยังคงกระทำการเข้าถึงการใช้ นี่เป็นเพราะหนึ่งในการกระทำในแท็ก "แยก" ที่ถูกแยกออก / ห้อยอยู่นั้น ฉันลบแท็กออกแล้วรันคำสั่งด้านบนอีกครั้งและฉันก็เป็นสีทอง git show <commit>กลับมาfatal: bad object <commit>- สิ่งที่ฉันต้องการ หวังว่านี่จะช่วยคนอื่นที่ติดอยู่กับฉัน


คุณลบแท็กอย่างไร
bapors

@bapors แสดงรายการแท็กทั้งหมดค้นหาแท็กที่อ้างอิงถึงการมอบหมายในคำถามแล้วลบออก stackoverflow.com/questions/5480258/…
แอนดรูลาร์สสัน

4

ฉันพบสถานการณ์เดียวกันโดยบังเอิญและพบว่าที่เก็บข้อมูลของฉันมีการอ้างอิงถึงการส่งข้อมูลที่ไม่สามารถเข้าถึงได้และทำให้การเข้าถึงที่ไม่สามารถเข้าถึงได้นั้นสันนิษฐานได้ว่าสามารถเข้าถึงได้จากที่เก็บข้อมูล

นี่คือสิ่งที่ฉันทำเพื่อทำให้ไม่สามารถเข้าถึงได้อย่างแท้จริง

git stash clear
git reflog expire --expire-unreachable=now --all
git fsck --unreachable
git gc --prune=now

2

git gc --prune=<date>ค่าเริ่มต้นในการตัดวัตถุที่มีอายุมากกว่าสองสัปดาห์ที่ผ่านมา คุณสามารถกำหนดวันที่ใหม่กว่าได้ แต่คำสั่ง git ที่สร้างวัตถุที่หลวมจะเรียกใช้ git gc - auto (ซึ่งตัดส่วนวัตถุที่หลวมถ้าจำนวนของพวกเขาเกินกว่าค่าตัวแปรกำหนดค่า gc.auto)

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

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