วิธีลบ blobs ที่ไม่ได้อ้างอิงจาก git repo ของฉัน


124

ฉันมี repo GitHub ที่มีสองสาขา - master & release

สาขาการเผยแพร่มีไฟล์การแจกจ่ายไบนารีที่มีส่วนทำให้มีขนาด repo ที่ใหญ่มาก (> 250MB) ดังนั้นฉันจึงตัดสินใจที่จะล้างสิ่งต่างๆ

ก่อนอื่นฉันลบสาขาการเผยแพร่ระยะไกลผ่านทาง git push origin :release

จากนั้นฉันลบสาขาการเผยแพร่ในเครื่อง ก่อนอื่นฉันลองgit branch -d releaseแต่คอมไพล์แจ้งว่า"error:" release "branch ไม่ใช่บรรพบุรุษของ HEAD ปัจจุบันของคุณ" ซึ่งเป็นความจริงดังนั้นฉันจึงgit branch -D releaseบังคับให้ลบ

แต่ขนาดพื้นที่เก็บข้อมูลของฉันทั้งในเครื่องและบน GitHub ก็ยังใหญ่มาก จากนั้นฉันก็วิ่งผ่านรายการคำสั่ง git ตามปกติเช่นgit gc --prune=today --aggressiveไม่มีโชค

การทำตามคำแนะนำของ Charles Bailey ที่SO 1029969ฉันสามารถรับรายชื่อ SHA1 สำหรับกลุ่มที่ใหญ่ที่สุดได้ จากนั้นฉันใช้สคริปต์จากSO 460331 เพื่อค้นหา blobs ... และห้าที่ใหญ่ที่สุดไม่มีอยู่แม้ว่าจะพบ blobs ที่เล็กกว่าดังนั้นฉันจึงรู้ว่าสคริปต์ทำงานอยู่

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


คุณใช้ Git เวอร์ชันใด แล้วคุณลองstackoverflow.com/questions/1106529/…ไหม
VonC

git เวอร์ชัน 1.6.2.3 ฉันลอง gc และ prune w / ข้อโต้แย้งต่างๆ ฉันไม่ได้ลอง repack -a -d -l วิ่งมันไม่มีการเปลี่ยนแปลง
kkrugler

2
ข้อมูลใหม่ - โคลนใหม่จาก GitHub ไม่มี Blobs ที่ไม่ได้อ้างอิงอีกต่อไปและมีขนาดเหลือเพียง 84MB จาก 250MB
kkrugler

คำตอบ:


219

... และโดยไม่ต้องกังวลใจอีกต่อไปฉันขอเสนอคำสั่งที่เป็นประโยชน์นี้แก่คุณ "git-gc-all" ซึ่งรับประกันว่าจะลบขยะคอมไพล์ทั้งหมดของคุณจนกว่าจะมีตัวแปรกำหนดค่าเพิ่มเติม:

git -c gc.reflogExpire=0 -c gc.reflogExpireUnreachable=0 -c gc.rerereresolved=0 -c gc.rerereunresolved=0 -c gc.pruneExpire=now gc

คุณอาจต้องเรียกใช้สิ่งเหล่านี้ก่อนโอ้ที่รักคอมไพล์ซับซ้อน !!

git remote rm origin
rm -rf .git/refs/original/ .git/refs/remotes/ .git/*_HEAD .git/logs/
git for-each-ref --format="%(refname)" refs/original/ | xargs -n1 --no-run-if-empty git update-ref -d

คุณอาจต้องลบบางแท็กด้วยขอบคุณ Zitrax:

git tag | xargs git tag -d

ฉันใส่ทั้งหมดนี้ในสคริปต์: Git-GC-ทั้งหมดดุร้าย


1
น่าสนใจ ทางเลือกที่ดีสำหรับคำตอบทั่วไปของฉัน +1
VonC

10
สิ่งนี้สมควรได้รับการโหวตมากขึ้น ในที่สุดมันก็กำจัดวัตถุคอมไพล์จำนวนมากด้วยวิธีการอื่น ๆ ขอบคุณ!
Jean-Philippe Pellet

1
upvoted ว้าวฉันไม่รู้ว่าฉันเพิ่งทำอะไรไป แต่ดูเหมือนว่าจะสะอาดขึ้นมาก คุณช่วยอธิบายอย่างละเอียดได้ไหมว่ามันทำอะไร? objectsผมมีความรู้สึกว่ามันล้างออกทั้งหมดของฉัน สิ่งเหล่านี้คืออะไรและทำไม (ดูเหมือน) ไม่เกี่ยวข้อง?
Redsandro

2
ตามที่ฉันเข้าใจคำสั่ง "git rm origin", "rm" และ "git update-ref -d" จะลบการอ้างอิงไปยังคอมมิตเก่าสำหรับรีโมตซึ่งอาจป้องกันการรวบรวมขยะ ตัวเลือกในการ "git gc" บอกว่าอย่ายึดมั่นกับข้อผูกมัดเก่า ๆ หลาย ๆ อย่างมิฉะนั้นมันจะค้างไว้สักพัก เช่น gc.rerereresolved มีไว้สำหรับ "บันทึกการผสานที่ขัดแย้งที่คุณแก้ไขก่อนหน้านี้" โดยค่าเริ่มต้นจะเก็บไว้เป็นเวลา 60 วัน ตัวเลือกเหล่านี้อยู่ใน manpage git-gc ฉันไม่ใช่ผู้เชี่ยวชาญด้านคอมไพล์และไม่รู้ว่าสิ่งเหล่านี้ทำอย่างไร ฉันพบพวกเขาจากการจัดการและ grepping .git สำหรับการอ้างอิงการกระทำ
Sam Watkins

1
git object คือไฟล์หรือโครงสร้างที่บีบอัดหรือคอมมิตใน git repo ของคุณรวมถึงของเก่าจากประวัติ git gc ล้างวัตถุที่ไม่จำเป็นออก มันเก็บออบเจ็กต์ที่ยังจำเป็นสำหรับ repo ปัจจุบันของคุณและประวัติของมัน
Sam Watkins

81

ตามที่อธิบายไว้ที่นี่ , ถ้าคุณต้องการที่จะลบทุกอย่างแค่อ้างอิงทาง reflog ถาวรใช้เพียง

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

git reflog expire --expire-unreachable=now --allreflogลบข้อมูลทั้งหมดของการกระทำที่เข้าไม่ถึงใน

git gc --prune=now ลบคอมมิตตัวเอง

ข้อควรสนใจ : การใช้เท่านั้นgit gc --prune=nowจะไม่ทำงานเนื่องจากการคอมมิตเหล่านั้นยังคงถูกอ้างอิงใน reflog ดังนั้นการล้าง reflog จึงมีผลบังคับใช้ โปรดทราบว่าหากคุณใช้rerereมีการอ้างอิงเพิ่มเติมที่ไม่ได้ล้างโดยคำสั่งเหล่านี้ ดูgit help rerereรายละเอียดเพิ่มเติม นอกจากนี้การคอมมิตใด ๆ ที่อ้างถึงโดยสาขาหรือแท็กในพื้นที่หรือระยะไกลจะไม่ถูกลบออกเนื่องจาก git ถือเป็นข้อมูลที่มีค่า


14
มันใช้งานได้ แต่อย่างใดฉันก็ทำหายที่บันทึกไว้ในกระบวนการ (ไม่มีอะไรสำคัญในกรณีของฉันเป็นเพียงข้อควรระวังสำหรับคนอื่น)
Amro

1
ทำไมไม่ - ก้าวร้าว?
JoelFan

3
ฉันคิดว่าคำตอบนี้ต้องการคำเตือนที่ชัดเจนโดยเฉพาะอย่างยิ่งที่ด้านบน คำแนะนำในการแก้ไขของฉันถูกปฏิเสธเพราะฉันคิดว่าฉันควรจะแนะนำให้ผู้เขียนแสดงความคิดเห็น? โปรดยอมรับการแก้ไขstackoverflow.com/review/suggested-edits/26023988หรือเพิ่มคำเตือนในแบบของคุณเอง นอกจากนี้ลดลง stashes ที่ควรจำไว้ในคำเตือนด้วย!
Inigo

ฉันทดสอบด้วย git เวอร์ชัน 2.17 และคอมมิตที่ซ่อนไว้จะไม่ถูกลบออกโดยคำสั่งข้างต้น แน่ใจหรือไม่ว่าคุณไม่ได้เรียกใช้คำสั่งเพิ่มเติมใด ๆ
Mikko Rantalainen

1
git fetch --pruneลดขนาดเพิ่มเติมเนื่องจากการลบ blobs ในเครื่อง
hectorpal

33

ตามที่ระบุไว้ในคำตอบดังนั้นนี้ ,git gcจริงสามารถเพิ่มขนาดของธุรกรรมซื้อคืนที่!

ดูกระทู้นี้ด้วย

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

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

อย่างไรก็ตาม ... ในการแก้ปัญหาของคุณคุณเพียงแค่เรียกใช้ ' git gc' ด้วย--prune=nowอาร์กิวเมนต์เพื่อปิดใช้งานช่วงเวลาผ่อนผันนั้นและกำจัดวัตถุที่ไม่ได้อ้างอิงเหล่านั้นทันที (ปลอดภัยเฉพาะในกรณีที่ไม่มีกิจกรรมคอมไพล์อื่น ๆ เกิดขึ้นในเวลาเดียวกันซึ่งควร มั่นใจได้ง่ายบนเวิร์กสเตชัน)

และ BTW โดยใช้ ' git gc --aggressive' กับ git เวอร์ชันที่ใหม่กว่า (หรือ ' git repack -a -f -d --window=250 --depth=250')

หัวข้อเดียวกันกล่าวถึง :

 git config pack.deltaCacheSize 1

ซึ่ง จำกัด ขนาดเดลต้าแคชไว้ที่หนึ่งไบต์ (ปิดใช้งานได้อย่างมีประสิทธิภาพ) แทนที่จะเป็นค่าเริ่มต้นของ 0 ซึ่งหมายถึงไม่ จำกัด ด้วยเหตุนี้ฉันจึงสามารถบรรจุที่เก็บใหม่ได้โดยใช้git repackคำสั่งด้านบนบนระบบ x86-64 ที่มี RAM 4GB และใช้ 4 เธรด (นี่คือ Quad Core) การใช้หน่วยความจำของผู้อยู่อาศัยเพิ่มขึ้นเป็นเกือบ 3.3GB

หากเครื่องของคุณเป็น SMP และคุณมี RAM ไม่เพียงพอคุณสามารถลดจำนวนเธรดให้เหลือเพียงเธรดเดียว:

git config pack.threads 1

นอกจากนี้คุณสามารถ จำกัด การใช้งานหน่วยความจำเพิ่มเติมได้ด้วยการ--window-memory argument" git repack"
ตัวอย่างเช่นการใช้--window-memory=128Mควรให้ขอบเขตบนที่เหมาะสมกับการใช้หน่วยความจำการค้นหาเดลต้าแม้ว่าจะทำให้การจับคู่เดลต้าที่เหมาะสมน้อยลงหาก repo มีไฟล์ขนาดใหญ่จำนวนมาก


ที่ด้านหน้าสาขาตัวกรองคุณสามารถพิจารณา (ด้วยความระมัดระวัง) สคริปต์นี้

#!/bin/bash
set -o errexit

# Author: David Underhill
# Script to permanently delete files/folders from your git repository.  To use 
# it, cd to your repository's root and then run the script with a list of paths
# you want to delete, e.g., git-delete-history path1 path2

if [ $# -eq 0 ]; then
    exit 0
fi

# make sure we're at the root of git repo
if [ ! -d .git ]; then
    echo "Error: must run this script from the root of a git repository"
    exit 1
fi

# remove all paths passed as arguments from the history of the repo
files=$@
git filter-branch --index-filter "git rm -rf --cached --ignore-unmatch $files" HEAD

# remove the temporary history git-filter-branch otherwise leaves behind for a long time
rm -rf .git/refs/original/ && git reflog expire --all &&  git gc --aggressive --prune

stackoverflow.com/questions/359424/…ยังเป็นการเริ่มต้นที่ดีสำหรับการfilter-branchใช้งานคำสั่ง
VonC

สวัสดี VonC - NI ได้ลอง git gc prune = ตอนนี้ไม่มีโชค ดูเหมือนว่าเป็นข้อผิดพลาดของคอมไพล์เนื่องจากฉันได้รับ blobs ที่ไม่ได้อ้างอิงในเครื่องหลังจากการลบสาขา แต่สิ่งเหล่านี้ไม่ได้อยู่ที่นั่นด้วยโคลนใหม่ของ repo GitHub ... ดังนั้นจึงเป็นเพียงปัญหา repo ในท้องถิ่น แต่ฉันมีไฟล์เพิ่มเติมที่ต้องการล้างดังนั้นสคริปต์ที่คุณอ้างถึงข้างต้นจึงดีมาก - ขอบคุณ!
kkrugler


12

ทุกครั้งที่ HEAD ของคุณเคลื่อนที่คอมไพล์ติดตามสิ่งนี้ในไฟล์reflog. หากคุณลบคอมมิทออกคุณจะยังคงมี "การคอมมิชแบบห้อย" เนื่องจากยังคงถูกอ้างอิงภายในreflogเวลา ~ 30 วัน นี่คือตาข่ายนิรภัยเมื่อคุณลบการกระทำโดยไม่ได้ตั้งใจ

คุณสามารถใช้git reflogคำสั่งลบคอมมิตเฉพาะรีแพค ฯลฯ .. หรือแค่คำสั่งระดับสูง:

git gc --prune=now

5

คุณสามารถใช้git forget-blob.

git forget-blob file-to-forgetการใช้งานสวยเรียบง่าย คุณสามารถรับข้อมูลเพิ่มเติมได้ที่นี่

https://ownyourbits.com/2017/01/18/completely-remove-a-file-from-a-git-repository-with-git-forget-blob/

มันจะหายไปจากการกระทำทั้งหมดในประวัติ reflog แท็กและอื่น ๆ ของคุณ

ฉันพบปัญหาเดิม ๆ ทุกครั้งและทุกครั้งที่ฉันต้องกลับมาที่โพสต์นี้และอื่น ๆ นั่นคือเหตุผลที่ฉันดำเนินการโดยอัตโนมัติ

ให้เครดิตกับผู้ร่วมให้ข้อมูลเช่น Sam Watkins


2

พยายามใช้git-filter-branch - ไม่ได้ลบ blobs ขนาดใหญ่ แต่สามารถลบไฟล์ขนาดใหญ่ที่คุณระบุจาก repo ทั้งหมดได้ สำหรับฉันแล้วมันลดขนาด repo จากหลายร้อย MB เป็น 12 MB


6
ตอนนี้ว่าเป็นคำสั่งที่น่ากลัว :) ฉันจะต้องให้มันลองเมื่อ Git-Fu ของฉันรู้สึกแข็งแกร่ง
kkrugler

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

1

ในบางครั้งสาเหตุที่ "gc" ทำได้ไม่ดีนักก็คือมีการ rebase หรือ stash ที่ยังไม่เสร็จสมบูรณ์ตามการกระทำเก่า


หรือคอมมิตเก่าถูกอ้างอิงโดย HEAD, ORIG_HEAD, FETCH_HEAD, reflog หรือสิ่งอื่น ๆ ที่คอมไพล์โดยอัตโนมัติพยายามทำให้แน่ใจว่าจะไม่สูญเสียสิ่งที่มีค่าไป หากคุณต้องการสูญเสียสิ่งเหล่านี้ทั้งหมดจริงๆคุณต้องไปให้ไกลกว่านั้นเพื่อทำเช่นนั้น
Mikko Rantalainen

1

หากต้องการเพิ่มเคล็ดลับอื่นอย่าลืมใช้git remote pruneเพื่อลบสาขาที่ล้าสมัยของรีโมตของคุณก่อนใช้git gc

คุณสามารถดูได้ด้วยgit branch -a

มักมีประโยชน์เมื่อคุณดึงข้อมูลจาก github และที่เก็บแบบแยก ...


1

ก่อนดำเนินการgit filter-branchและgit gcคุณควรตรวจสอบแท็กที่มีอยู่ใน repo ของคุณ ระบบจริงใด ๆ ที่มีการติดแท็กอัตโนมัติสำหรับสิ่งต่างๆเช่นการรวมและการปรับใช้อย่างต่อเนื่องจะทำให้วัตถุที่ไม่ต้องการยังคงอ้างอิงโดยแท็กเหล่านี้ด้วยเหตุนี้gcไม่สามารถลบออกได้และคุณจะยังคงสงสัยว่าทำไมขนาดของ repo ถึงยังใหญ่ขนาดนี้

วิธีที่ดีที่สุดในการกำจัดสิ่งที่ไม่ต้องการคือเรียกใช้git-filter& git gcจากนั้นผลักดันต้นแบบไปยัง repo เปล่าใหม่ repo เปล่าใหม่จะมีการทำความสะอาดต้นไม้

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