ลบไฟล์. pack ขนาดใหญ่ที่สร้างโดย git


113

ฉันตรวจสอบการโหลดไฟล์ในสาขาและรวมเข้าด้วยกันจากนั้นต้องลบออกและตอนนี้ฉันเหลือไฟล์. pack ขนาดใหญ่ที่ฉันไม่รู้วิธีกำจัด

ฉันลบไฟล์ทั้งหมดโดยใช้git rm -rf xxxxxxและฉันก็เรียกใช้ไฟล์--cachedตัวเลือกนี้เช่นกัน

ใครช่วยบอกทีว่าฉันจะลบไฟล์. pack ขนาดใหญ่ที่อยู่ในไดเร็กทอรีต่อไปนี้ได้อย่างไร:

.git/objects/pack/pack-xxxxxxxxxxxxxxxxx.pack

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

ฉันไม่แน่ใจว่ามันสร้างความแตกต่างได้มากแค่ไหน แต่มันแสดงให้เห็นแม่กุญแจกับไฟล์

ขอบคุณ


แก้ไข

ต่อไปนี้เป็นข้อความที่ตัดตอนมาจาก bash_history ของฉันที่ควรให้ความคิดว่าฉันจัดการเพื่อเข้าสู่สถานะนี้ได้อย่างไร (สมมติว่า ณ จุดนี้ฉันกำลังทำงานกับสาขา git ที่เรียกว่า 'my-branch' และฉันมีโฟลเดอร์ที่มีโฟลเดอร์เพิ่มเติม / ไฟล์):

git add .
git commit -m "Adding my branch changes to master"
git checkout master
git merge my-branch
git rm -rf unwanted_folder/
rm -rf unwanted_folder/     (not sure why I ran this as well but I did)

ฉันคิดว่าฉันวิ่งสิ่งต่อไปนี้ด้วย แต่ไม่ปรากฏใน bash_history กับคนอื่น ๆ :

git rm -rf --cached unwanted_folder/

ฉันยังคิดว่าฉันใช้คำสั่ง git (เช่นgit gc) เพื่อพยายามจัดระเบียบไฟล์แพ็ค แต่ไม่ปรากฏในไฟล์. bash_history เช่นกัน


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

สวัสดี @loganfsmyth ฉันได้เพิ่มสคริปต์ประวัติ bash ที่หวังว่าจะช่วยได้
user1116573

คำตอบ:


202

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

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

GitHub มีคำอธิบายที่ดีเกี่ยวกับปัญหาในไซต์ของตน https://help.github.com/articles/remove-sensitive-data

เพื่อตอบคำถามของคุณให้ตรงยิ่งขึ้นสิ่งที่คุณต้องเรียกใช้โดยทั่วไปคือคำสั่งนี้โดยunwanted_filename_or_folderแทนที่ด้วย:

git filter-branch --index-filter 'git rm -r --cached --ignore-unmatch unwanted_filename_or_folder' --prune-empty

การดำเนินการนี้จะลบการอ้างอิงไฟล์ทั้งหมดออกจากประวัติที่ใช้งานอยู่ของ repo

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

git for-each-ref --format='delete %(refname)' refs/original | git update-ref --stdin
# or, for older git versions (e.g. 1.8.3.1) which don't support --stdin
# git update-ref $(git for-each-ref --format='delete %(refname)' refs/original)
git reflog expire --expire=now --all
git gc --aggressive --prune=now

3
ฉันได้ทำเครื่องหมายว่ายอมรับแล้วหากสิ่งนี้ทำให้ทุกคนที่เข้ามาในคำถามนี้ง่ายขึ้นในอนาคตแม้ว่าฉันจะแก้ปัญหาของฉันในเวลานั้นด้วยการสร้าง git repo ใหม่
user1116573

3
ฉันไม่รู้ว่าคุณคิดเรื่องนี้ได้อย่างไร แต่ ... คุณคือผู้ชาย ขอบคุณ.
Ezekiel Victor

5
คำตอบนี้ชี้ให้ฉันไปในทิศทางที่ถูกต้อง แต่ในการลบไฟล์จริงๆจำเป็นต้องมีอีก 3 คำสั่ง 1) git for-each-ref --format='delete %(refname)' refs/original | git update-ref --stdin2) git reflog expire --expire=now --all3)git gc --prune=now
arod

3
ฉันพบว่าการใช้งานbfgง่ายกว่ามาก นอกจากนี้ยังแนะนำในเอกสาร github อย่างเป็นทางการ: help.github.com/articles/…
Timo

2
@Timo เป็นการดีที่จะเพิ่มคำตอบใหม่หากมีการเปลี่ยนแปลงตลอดเวลา ไปเลย!
loganfsmyth

12

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

git branch -D mybranch
git reflog expire --expire-unreachable=all --all
git gc --prune=all

สถานการณ์ B : อย่างไรก็ตามดูเหมือนว่าตามประวัติทุบตีของคุณที่คุณได้รวมการเปลี่ยนแปลงเป็นหลัก หากคุณยังไม่ได้แชร์การเปลี่ยนแปลงกับใครเลย ( git pushยังไม่มี) สิ่งที่ง่ายที่สุดคือการรีเซ็ตต้นแบบกลับไปก่อนที่จะรวมกับสาขาที่มีไฟล์ขนาดใหญ่ การดำเนินการนี้จะกำจัดการกระทำทั้งหมดจากสาขาของคุณและการกระทำทั้งหมดที่เกิดขึ้นกับผู้เชี่ยวชาญหลังจากการรวม ดังนั้นคุณอาจสูญเสียการเปลี่ยนแปลง - นอกเหนือจากไฟล์ขนาดใหญ่ที่คุณอาจต้องการ:

git checkout master
git log # Find the commit hash just before the merge
git reset --hard <commit hash>

จากนั้นเรียกใช้ขั้นตอนจากสถานการณ์จำลอง A

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

git checkout master
git log # Find the commit hash just before the merge
git rebase -i <commit hash>

ในตัวแก้ไขของคุณลบบรรทัดที่ตรงกับคอมมิตที่เพิ่มไฟล์ขนาดใหญ่ แต่ปล่อยทุกอย่างไว้ตามที่เป็นอยู่ บันทึกและออก สาขาหลักของคุณควรมีเฉพาะสิ่งที่คุณต้องการและไม่มีไฟล์ขนาดใหญ่ โปรดทราบว่าgit rebaseหากไม่มี-pจะกำจัดการผสานรวมดังนั้นคุณจะเหลือประวัติเชิงเส้นสำหรับต้นแบบหลังจาก<commit hash>นั้น นี่อาจจะโอเคสำหรับคุณ แต่ถ้าไม่คุณสามารถลอง-pได้ แต่git help rebaseพูดcombining -p with the -i option explicitly is generally not a good idea unless you know what you are doingพูดว่า

จากนั้นรันคำสั่งจากสถานการณ์ A


อย่างไรก็ตามมีสถานการณ์จำลอง A ที่แตกต่างกันไปพร้อมกับปัญหาที่ไม่คาดคิดเพิ่มเติม

สถานการณ์จำลอง A แก้ไขปัญหาของฉันเพื่อลบไฟล์แพ็คชั่วคราวจำนวนมาก ที่เก็บถูกจัดการโดยบิลด์เซิร์ฟเวอร์และทำให้เกิดการสร้างไฟล์ที่ไม่ต้องการภายในโฟลเดอร์. git / objects / pack ฉันสามารถเพิ่ม GB ที่มีค่าจากดิสก์ของฉันได้
xrissz

7

ตามที่ loganfsmyth ระบุไว้ในคำตอบของเขาคุณต้องล้างประวัติ git เนื่องจากไฟล์ยังคงอยู่ที่นั่นแม้ว่าจะลบออกจาก repo แล้วก็ตาม เอกสาร GitHub อย่างเป็นทางการแนะนำ BFGซึ่งฉันพบว่าใช้งานง่ายกว่าfilter-branch:

การลบไฟล์จากประวัติ

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

git clone --mirror git://example.com/some-big-repo.git
java -jar bfg.jar --delete-files YOUR_FILE_NAME some-big-repo.git
cd some-big-repo.git
git reflog expire --expire=now --all && git gc --prune=now --aggressive
git push

ลบโฟลเดอร์

เหมือนกับข้างบน แต่ใช้ --delete-folders

java -jar bfg.jar --delete-folders YOUR_FOLDER_NAME some-big-repo.git

ตัวเลือกอื่น

BFG ยังอนุญาตให้มีตัวเลือกที่น่าสนใจยิ่งขึ้น (ดูเอกสาร ) เช่นนี้:

ลบไฟล์ทั้งหมดที่มีขนาดใหญ่กว่า 100M ออกจากประวัติ:

java -jar bfg.jar --strip-blobs-bigger-than 100M some-big-repo.git

สำคัญ!

เมื่อเรียกใช้ BFG โปรดระวังว่าทั้งสองYOUR_FILE_NAMEและYOUR_FOLDER_NAMEเป็นเพียงชื่อไฟล์ / โฟลเดอร์เท่านั้น มันไม่ใช่เส้นทางดังนั้นสิ่งที่ชอบfoo/bar.jpgจะไม่ทำงาน! ไฟล์ / โฟลเดอร์ทั้งหมดที่มีชื่อที่ระบุจะถูกลบออกจากประวัติ repo ไม่ว่าจะมีเส้นทางใดหรือสาขาใดก็ตาม


ฉันสงสัยว่าฉันต้องการใช้bfgเครื่องมือนี้กับ git repo ในเครื่องคำสั่งควรมีลักษณะอย่างไร?
Angel Todorov

5

ทางเลือกหนึ่ง:

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

อีกทางเลือกหนึ่งคือบันทึกรหัสและ. git ไว้ที่ไหนสักแห่งแล้วลบ. git และเริ่มต้นใหม่อีกครั้งโดยใช้รหัสที่มีอยู่นี้สร้างที่เก็บ git ใหม่ ( git init)


สวัสดี Michael ฉันลองใช้งานgit gcและลงไฟล์แพ็คเพียงไม่กี่ไฟล์ แต่ไฟล์ขนาดใหญ่ยังคงเป็นหนึ่งในนั้นและฉันแค่อยากจะกำจัดมันเพื่อที่ฉันจะได้สำรองโฟลเดอร์จากภายนอกได้ง่ายขึ้น (zip ก่อนหน้าคือ 1 -2Mb ตอนนี้ 55Mb) ถ้าไม่มีใครสามารถแนะนำสิ่งอื่นได้ฉันคิดว่าฉันอาจต้องสร้างคอมไพล์ใหม่ ฉันคิดว่านี่หมายความว่าฉันจะไม่สามารถเข้าถึงสาขาที่ฉันมีอยู่ได้ ฯลฯ ... ?
user1116573

2
ฉันล้มเลิกความพยายามและเพิ่งลบโฟลเดอร์. git และสร้างที่เก็บ git ใหม่ตามที่คุณพูด ฉันจะถือว่ามันเป็นบทเรียน ขอบคุณ Michael
user1116573

4
สิ่งนี้ไม่สมเหตุสมผลเท่าไหร่ ทำไมคุณไม่สามารถบอก git ให้รวมที่เก็บปัจจุบันและลบไฟล์แพ็คในกระบวนการได้?
jml

4

รันคำสั่งต่อไปนี้แทนที่PATH-TO-YOUR-FILE-WITH-SENSITIVE-DATAด้วยพา ธ ไปยังไฟล์ที่คุณต้องการลบไม่ใช่แค่ชื่อไฟล์ ข้อโต้แย้งเหล่านี้จะ:

  1. บังคับให้ Git ประมวลผล แต่ไม่ตรวจสอบประวัติทั้งหมดของทุกสาขาและแท็ก
  2. ลบไฟล์ที่ระบุรวมทั้งคอมมิตว่างที่สร้างขึ้นด้วยผลลัพธ์
  3. เขียนทับแท็กที่คุณมีอยู่
git filter-branch --force --index-filter "git rm --cached --ignore-unmatch PATH-TO-YOUR-FILE-WITH-SENSITIVE-DATA" --prune-empty --tag-name-filter cat -- --all

การดำเนินการนี้จะลบการอ้างอิงไฟล์ทั้งหมดออกจากประวัติที่ใช้งานอยู่ของ repo

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

git update-ref -d refs/original/refs/remotes/origin/master
git for-each-ref --format='delete %(refname)' refs/original | git update-ref --stdin
git reflog expire --expire=now --all
git gc --aggressive --prune=now

ในที่สุดจากส่วนที่ 2 ฉันได้รับ repo 28G ลงมาที่ 158M แทบจะไม่มีอะไรอื่นใน Google ที่ใช้งานได้ ขอบคุณ.
Sridhar Sarnobat

ฉันทำตามขั้นตอนข้างต้นและพุชเป็น "git push origin --force --all" และยังคงเป็นสาขาระยะไกลของฉัน (ต้นแบบการพัฒนาและคุณลักษณะ / ASD-1010) เมื่อฉันโคลนใหม่จาก repo ระยะไกลไฟล์. pack ยังคงอยู่ ฉันจะสะท้อนการทำความสะอาดนี้ไปยังสาขา git ระยะไกลทั้งหมดได้อย่างไร?
Sambit Swain

1

ฉันมาสายเล็กน้อยสำหรับการแสดง แต่ในกรณีที่คำตอบข้างต้นไม่สามารถแก้ปัญหาคำถามได้ฉันจึงพบวิธีอื่น เพียงแค่ลบไฟล์ขนาดใหญ่ที่ต้องการออกจาก. pack ฉันมีปัญหานี้ที่ฉันตรวจสอบในไฟล์ขนาดใหญ่ 2GB โดยบังเอิญ ฉันทำตามขั้นตอนที่อธิบายไว้ในลิงค์นี้: http://www.ducea.com/2012/02/07/howto-completely-remove-a-file-from-git-history/


หลังจากทำวิธีนี้แล้วจะลบประวัติทั้งหมดของโครงการออกทั้งหมดหรือจะลบไฟล์ที่ระบุออกไป
Samim Aftab Ahmed

-3

นี่เป็นวิธีแก้ปัญหาที่มีประโยชน์มากกว่าการเข้ารหัส zip ไฟล์ เปิดไฟล์ zip ในรูปแบบมุมมองไฟล์ (แตกต่างจากการแตกไฟล์) ลบไฟล์. pack คลายซิปและเปลี่ยนโฟลเดอร์ ใช้งานได้เหมือนมีเสน่ห์!

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