Bir git deposunun geçmişini daraltma


85

Oldukça büyük bir geçmişi olan bir git projemiz var.

Spesifik olarak, projenin başlarında projede oldukça fazla ikili kaynak dosyası vardı, bunlar etkin bir şekilde harici kaynaklar oldukları için artık kaldırıldı.

Ancak, bu dosyaların önceden kaydedilmiş olması nedeniyle depomuzun boyutu> 200MB'dir (toplam ödeme şu anda ~ 20MB'dir).

Yapmak istediğimiz şey, arşivin daha sonraki bir revizyondan oluşturulmuş gibi görünmesi için geçmişi "daraltmak". Örneğin

1-----2-----3-----4-----+---+---+
                   \       /
                    +-----+---+---+
  1. Kod deposu oluşturuldu
  2. Büyük ikili dosya seti eklendi
  3. Büyük ikili dosya kümesi kaldırıldı
  4. Deponun yeni amaçlanan 'başlangıcı'

O kadar etkili bir şekilde belirli bir noktadan önce proje geçmişini kaybetmek istiyoruz. Bu noktada sadece bir dal var, bu yüzden birden fazla başlangıç ​​noktası vb. İle uğraşmaya çalışmakla ilgili bir zorluk yok. Ancak tüm geçmişi kaybetmek ve mevcut sürümle yeni bir depo başlatmak istemiyoruz.

Bu mümkün mü yoksa sonsuza kadar şişirilmiş bir depoya mı mahkumuz?

Yanıtlar:


89

İkili şişkinliği kaldırabilir ve geçmişinizin geri kalanını saklayabilirsiniz. Git, önceden kaydetme işlemlerini yeniden sıralamanıza ve 'ezmenize' izin verir, böylece yalnızca büyük ikili dosyalarınızı ekleyen ve kaldıran işlemleri birleştirebilirsiniz. Eklemelerin tümü bir işlemede ve kaldırmalar başka bir işlemde yapıldıysa, bu her dosya ile uğraşmaktan çok daha kolay olacaktır.

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

İkili dosyalarınızı ekleyen ve silen commit'leri arayın ve SHA1'lerini not edin, örneğin 2bcdefve 3cdef3.

Ardından deponun geçmişini düzenlemek için rebase -i, ikili dosyalarınızı eklediğiniz commit'in üst öğesinden başlayarak etkileşimli seçeneği ile command kullanın . $ EDITOR'unuzu başlatacak ve şunlardan başlayarak bir işlem listesi göreceksiniz 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İkinci satır olarak ekleyin ve yazan satırı pick 3cdef3listeden kaldırın . Artık etkileşimli için, rebaseikili dosyalarınızı ekleyen ve silen commit'leri, farkları sadece bu kayıtlardaki diğer değişiklikler olan bir kayıtta birleştirecek bir eylemler listesine sahipsiniz . Ardından, tamamlamasını söylediğinizde sonraki tüm taahhütleri sırayla yeniden uygulayacaktır:

$ git rebase --continue

Bu bir veya iki dakika sürer.
Artık ikili dosyaların gelip gitmediği bir deponuz var. Ancak yine de yer kaplayacaklar çünkü varsayılan olarak Git değişiklikleri çöp olarak toplanmadan önce 30 gün boyunca saklar, böylece fikrinizi değiştirebilirsiniz. Onları şimdi kaldırmak istiyorsanız:

$ 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                      

Şimdi şişkinliği kaldırdınız ama geçmişinizin geri kalanını sakladınız.


7
Sadece başkalarının o depodan zaten çekip çekmediğini hatırlamanız gerekir, tarihin yeniden yazılması çekişlerini karıştırır. Git-rebase kılavuzu bu diğer depoların nasıl kurtarılacağını açıklar. kernel.org/pub/software/scm/git/docs/git-rebase.html
Otto

bu, kullanıcının özel sorunu için harika bir cevaptır, ancak asıl soru için değil! davitenio'nun cevabı gerçek soru için harika bir cevap.
Sam Watkins

27

git filter-branch4 numaralı commit'i dalınızın yeni kök commit'i yapmak için greftlerle birlikte kullanabilirsiniz . .git/info/grafts4 numaralı işlemin SHA1'ini içeren yalnızca bir satır içeren dosyayı oluşturun .

Şimdi bir yaparsanız git logveya gitkbu komutların dalınızın kökü olarak commit numarası 4'ü göstereceğini göreceksiniz. Ancak deponuzda gerçekte hiçbir şey değişmeyecek. Sen silebilir .git/info/graftsve çıkış git logya gitkeskisi gibi olacaktır. 4 numaralı commit'i gerçekten yeni kök yapmak için git filter-branchargüman olmadan çalıştırmanız gerekecek .


Bu, bir yeniden ödemeden çok daha iyidir, çünkü birleştirme işlemlerini koruma konusunda sorunları yoktur ve zaman damgalarının değişmesine neden olmaz. Tüm geri ödeme yöntemlerinden daha kolay ve daha hızlı.
mmrobins

Aslında, artık o dalın parçası olmayan tüm taahhütleri fiziksel olarak silmenin bir yolu var mı? git gc --prune=0onları temizlemiyor gibi görünüyor.
Verhogen

1
@verhogen git gc --prune=nowartık referans verilmeyen tüm işlemleri fiziksel olarak temizler. Bu sizin için işe yaramazsa, hala eski kökü referans alan bir uzaktan izleme şubeniz olabilir. İle listeleyin git branch -r, ardından uzak dalı örneğin ile kaldırın git branch -rd origin/masterve ardından git gc --prune=nowtekrar çalıştırın .
kayahr

20

JesperE'nin araştırdığım gönderisi sayesinde git-filter-branch- aslında istediğiniz şey bu olabilir. Görünüşe göre, Büyük Dosyalarınız kaldırıldıktan sonra değiştirilecekler dışında, önceki işlemlerinizi de saklayabileceksiniz. Gönderen git-filtre-dal adam sayfası :

Bir dosyayı (gizli bilgiler veya telif hakkı ihlali içeren) tüm taahhütlerden kaldırmak istediğinizi varsayalım:

git filter-branch --tree-filter 'rm dosya adı' HEAD

Bu kılavuz sayfasını okuduğunuzdan emin olun ... açıkçası bunu, beklendiği gibi çalıştığından emin olmak için deponuzun yedek bir klonunda yapmak isteyeceksiniz.


2
Github'ın bağlantısına göz atın ... git-filter-branch komutuyla bazı güçlü seçeneklere sahip: help.github.com/articles/remove-sensitive-data
ricosrealm

5

Aradığınız git-fast-exportşey mi?

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).
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.