การยุบประวัติของที่เก็บ git


85

เรามีโครงการคอมไพล์ซึ่งมีประวัติอันยิ่งใหญ่

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

อย่างไรก็ตามขนาดของพื้นที่เก็บข้อมูลของเราคือ> 200MB (ขณะนี้การชำระเงินทั้งหมดอยู่ที่ ~ 20MB) เนื่องจากมีไฟล์เหล่านี้ก่อนหน้านี้

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

1-----2-----3-----4-----+---+---+
                   \       /
                    +-----+---+---+
  1. สร้างที่เก็บแล้ว
  2. เพิ่มไฟล์ไบนารีชุดใหญ่
  3. ไฟล์ไบนารีชุดใหญ่ถูกลบออก
  4. 'เริ่มต้น' ที่ตั้งใจไว้ใหม่ของที่เก็บ

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

เป็นไปได้หรือเราถึงวาระที่จะมีพื้นที่เก็บข้อมูลที่ป่องตลอดไป?

คำตอบ:


89

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

$ git log --stat       # list all commits and commit messages 

ค้นหานี้กระทำที่เพิ่มและลบไฟล์ไบนารีของคุณและทราบ SHA1s ของพวกเขาพูดและ2bcdef3cdef3

จากนั้นในการแก้ไขประวัติ repo ให้ใช้rebase -iคำสั่งที่มีตัวเลือกแบบโต้ตอบเริ่มต้นด้วยพาเรนต์ของคอมมิตที่คุณเพิ่มไบนารีของคุณ มันจะเปิดตัว $ EDITOR ของคุณและคุณจะเห็นรายการคอมมิตโดยเริ่มจาก2bcdef:

$ git rebase -i 2bcdef^    # generate a pick list of all commits starting with 2bcdef
# Rebasing zzzzzz onto yyyyyyy 
# 
# Commands: 
#  pick = use commit 
#  edit = use commit, but stop for amending 
#  squash = use commit, but meld into previous commit 
# 
# If you remove a line here THAT COMMIT WILL BE LOST.
#
pick 2bcdef   Add binary files and other edits
pick xxxxxx   Another change
  .
  .
pick 3cdef3   Remove binary files; link to them as external resources
  .
  .

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

$ git rebase --continue

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

$ git reflog expire --expire=1.minute refs/heads/master
      #all deletions up to 1 minute  ago available to be garbage-collected
$ git fsck --unreachable      # lists all the blobs(files) that will be garbage-collected
$ git prune
$ git gc                      

ตอนนี้คุณได้ลบส่วนที่ขยายออกไปแล้ว แต่เก็บประวัติที่เหลือ


7
คุณต้องจำไว้ว่าถ้ามีคนอื่นดึงออกจากที่เก็บนั้นไปแล้วการเขียนประวัติใหม่จะทำให้พวกเขาสับสน คู่มือ git-rebase จะอธิบายวิธีการกู้คืน repos อื่น ๆ เหล่านั้น kernel.org/pub/software/scm/git/docs/git-rebase.html
Otto

นี่เป็นคำตอบที่ดีสำหรับปัญหาเฉพาะของผู้ใช้ แต่ไม่ใช่สำหรับคำถามจริง! คำตอบของ davitenio เป็นคำตอบที่ดีสำหรับคำถามจริง
Sam Watkins

27

คุณสามารถใช้git filter-branchกับกราฟต์เพื่อทำให้จำนวนคอมมิต 4 เป็นรูทคอมมิตใหม่ของสาขาของคุณ เพียงสร้างไฟล์.git/info/graftsด้วยบรรทัดเดียวในไฟล์ที่มี SHA1 ของคอมมิตหมายเลข 4

ถ้าตอนนี้คุณทำ git logหรือgitkคุณจะเห็นว่าคำสั่งเหล่านั้นจะแสดงหมายเลข 4 เป็นรูทของสาขาของคุณ แต่จะไม่มีอะไรเปลี่ยนแปลงในที่เก็บของคุณ คุณสามารถลบ.git/info/graftsและผลลัพธ์ของgit logหรือgitkจะเป็นเหมือนเดิม ในการทำให้หมายเลข 4 เป็นรูทใหม่คุณจะต้องเรียกใช้git filter-branchโดยไม่มีข้อโต้แย้ง


สิ่งนี้ดีกว่า rebase มากเนื่องจากไม่มีปัญหาในการรักษาการผสานรวมและไม่ทำให้การประทับเวลาเปลี่ยนแปลง ง่ายและเร็วกว่าวิธีการ rebase ทั้งหมดด้วย
mmrobins

จริงๆแล้วมีวิธีลบคอมมิตทั้งหมดที่ไม่ได้เป็นส่วนหนึ่งของสาขานั้นหรือไม่? git gc --prune=0ดูเหมือนจะไม่ได้ทำความสะอาด
Verhogen

1
@verhogen git gc --prune=nowชำระล้างการกระทำทั้งหมดที่ไม่ได้อ้างอิงอีกต่อไป หากวิธีนี้ไม่ได้ผลสำหรับคุณแสดงว่าคุณอาจมีสาขาการติดตามระยะไกลซึ่งยังคงอ้างอิงถึงรูทเก่า แสดงรายการด้วยgit branch -rจากนั้นนำสาขาระยะไกลออกเช่นด้วยgit branch -rd origin/masterแล้วเรียกใช้git gc --prune=nowอีกครั้ง
kayahr

20

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

สมมติว่าคุณต้องการลบไฟล์ (ที่มีข้อมูลที่เป็นความลับหรือการละเมิดลิขสิทธิ์) จากการกระทำทั้งหมด:

git filter-branch --tree-filter 'rm filename' HEAD

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


2
ตรวจสอบลิงก์ของ github ... มีตัวเลือกที่มีประสิทธิภาพพร้อมคำสั่ง git-filter-branch: help.github.com/articles/remove-sensitive-data
ricosrealm

5

คือgit-fast-exportสิ่งที่คุณกำลังมองหา?

NAME
   git-fast-export - Git data exporter

SYNOPSIS
   git-fast-export [options] | git-fast-import

DESCRIPTION
   This program dumps the given revisions in a form suitable to be piped into git-fast-
   import(1).

   You can use it as a human readable bundle replacement (see git-bundle(1)), or as a kind
   of an interactive git-filter-branch(1).
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.