Giriş: 5 Çözümünüz Var
Orijinal afişin belirtileri:
Yanlışlıkla istenmeyen bir dosyayı işledim ... birkaç kez önce depoma ... Dosyayı depo geçmişinden tamamen silmek istiyorum.
Değişiklik geçmişini filename.orig
en başta depoya asla eklenmeyecek şekilde yeniden yazmak mümkün müdür ?
Bir dosyanın geçmişini git'ten tamamen kaldırmanın birçok farklı yolu vardır:
- Değişiklik taahhütleri.
- Sert sıfırlamalar (muhtemelen artı bir rebase).
- Etkileşimli olmayan yeniden taban.
- Etkileşimli referanslar.
- Filtreleme dalları.
Orijinal poster söz konusu olduğunda, taahhütte değişiklik yapmak kendi başına bir seçenek değildir, daha sonra birkaç ek taahhütte bulunduğundan, ancak eksiksizlik uğruna, bunun nasıl yapılacağını açıklayacağım, önceki taahhütlerini değiştirmek için.
Tüm bu çözümlerin geçmişi / taahhütleri bir şekilde değiştirmeyi / yeniden yazmayı içerdiğini unutmayın, bu nedenle taahhütlerin eski kopyalarına sahip olan herkes, tarihlerini yeni tarihle yeniden senkronize etmek için ekstra iş yapmak zorunda kalacaktır.
Çözüm 1: Değişiklik Taahhütleri
Önceki taahhüdünüzde yanlışlıkla bir değişiklik yaptıysanız (dosya eklemek gibi) ve bu değişikliğin geçmişinin artık var olmasını istemiyorsanız, dosyayı kaldırmak için önceki taahhüdünde değişiklik yapabilirsiniz:
git rm <file>
git commit --amend --no-edit
Çözüm 2: Donanımdan Sıfırlama (Muhtemelen Artı Bir Rebase)
Çözüm # 1 gibi, sadece önceki taahhüdünüzden kurtulmak istiyorsanız, aynı zamanda ebeveynine sert bir sıfırlama yapma seçeneğiniz de vardır:
git reset --hard HEAD^
Bu komut önceki 1 için şube sabit sıfırlar st ebeveyn taahhüt.
Bununla birlikte , orijinal poster gibi, değişikliği geri almak istediğiniz taahhütten sonra birkaç taahhütte bulunduysanız, yine de değiştirmek için sert sıfırlamalar kullanabilirsiniz, ancak bunu yapmak bir rebase kullanmayı da içerir. Tarihte bir taahhüdü değiştirmek için kullanabileceğiniz adımlar şunlardır:
# Create a new branch at the commit you want to amend
git checkout -b temp <commit>
# Amend the commit
git rm <file>
git commit --amend --no-edit
# Rebase your previous branch onto this new commit, starting from the old-commit
git rebase --preserve-merges --onto temp <old-commit> master
# Verify your changes
git diff master@{1}
Çözüm 3: Etkileşimli Olmayan Rebase
Bu, yalnızca bir taahhüdü tarihten tamamen kaldırmak istiyorsanız işe yarayacaktır:
# Create a new branch at the parent-commit of the commit that you want to remove
git branch temp <parent-commit>
# Rebase onto the parent-commit, starting from the commit-to-remove
git rebase --preserve-merges --onto temp <commit-to-remove> master
# Or use `-p` insteda of the longer `--preserve-merges`
git rebase -p --onto temp <commit-to-remove> master
# Verify your changes
git diff master@{1}
Çözüm 4: Etkileşimli Rebases
Bu çözüm, # 2 ve # 3 çözümleriyle aynı şeyleri gerçekleştirmenize izin verecektir, yani değişiklikleri önceki önceki taahhüdünüzden daha fazla değiştirebilir veya kaldırabilirsiniz, böylece kullanmayı seçtiğiniz çözüm size bağlıdır. Etkileşimli yeniden basmalar performans nedeniyle yüzlerce taahhüdü yeniden basmaya uygun değildir, bu nedenle bu tür durumlarda etkileşimli olmayan bas basını veya filtre dalı çözümünü (aşağıya bakın) kullanırdım.
Etkileşimli yeniden başlamaya başlamak için aşağıdakileri kullanın:
git rebase --interactive <commit-to-amend-or-remove>~
# Or `-i` instead of the longer `--interactive`
git rebase -i <commit-to-amend-or-remove>~
Bu, git işleminin geçmişini değiştirmek veya kaldırmak istediğiniz işlemin üst öğesine geri sarmasına neden olur. Daha sonra, editör git'in ayarlandığı şekilde geri sarma işlemlerinin bir listesini size sunacaktır (bu varsayılan olarak Vim'dir):
pick 00ddaac Add symlinks for executables
pick 03fa071 Set `push.default` to `simple`
pick 7668f34 Modify Bash config to use Homebrew recommended PATH
pick 475593a Add global .gitignore file for OS X
pick 1b7f496 Add alias for Dr Java to Bash config (OS X)
Değiştirmek veya kaldırmak istediğiniz taahhüt bu listenin en üstünde yer alacaktır. Kaldırmak için listedeki satırını silmeniz yeterlidir. Aksi takdirde, yerine 1 "düzenle" ile "çekme" st hattı, bu yüzden istiyorum:
edit 00ddaac Add symlinks for executables
pick 03fa071 Set `push.default` to `simple`
Sonra girin git rebase --continue
. Taahhütü tamamen kaldırmayı seçtiyseniz, yapmanız gereken tek şey (doğrulama dışında, bu çözüm için son adıma bakın). Öte yandan, taahhüdü değiştirmek isterseniz, git taahhüdü yeniden uygular ve ardından yeniden temeli duraklatır.
Stopped at 00ddaacab0a85d9989217dd9fe9e1b317ed069ac... Add symlinks
You can amend the commit now, with
git commit --amend
Once you are satisfied with your changes, run
git rebase --continue
Bu noktada, dosyayı kaldırabilir ve taahhüdü değiştirebilir, ardından yeniden başlamaya devam edebilirsiniz:
git rm <file>
git commit --amend --no-edit
git rebase --continue
Bu kadar. Son adım olarak, taahhüdü değiştirmiş veya tamamen kaldırmış olsanız da, şubenizde yeniden tabandan önceki durumuna dağıtarak başka hiçbir beklenmedik değişiklik yapılmadığını doğrulamak her zaman iyi bir fikirdir:
git diff master@{1}
Çözüm 5: Dalları Filtreleme
Son olarak, bir dosyanın varlığının tüm izlerini geçmişten tamamen silmek istiyorsanız, bu çözüm en iyisidir ve diğer çözümlerin hiçbiri göreve tamamen uygun değildir.
git filter-branch --index-filter \
'git rm --cached --ignore-unmatch <file>'
Bu <file>
, kök taahhüdünden başlayarak tüm taahhütlerden kaldırılacaktır . Bunun yerine, yalnızca taahhüt aralığını yeniden yazmak istiyorsanız HEAD~5..HEAD
, bunu bu cevaptafilter-branch
belirtildiği gibi
ek bir argüman olarak iletebilirsiniz :
git filter-branch --index-filter \
'git rm --cached --ignore-unmatch <file>' HEAD~5..HEAD
Yine, filter-branch
tamamlandıktan sonra , filtreleme işleminden önce şubenizi önceki durumuyla ayırarak beklenmedik başka değişikliklerin olmadığını doğrulamak genellikle iyi bir fikirdir:
git diff master@{1}
Filtre Dalı Alternatifi: BFG Repo Temizleyici
BFG Repo Temizleyici aracının daha hızlı çalıştığını duydum git filter-branch
, bu yüzden bir seçenek olarak da kontrol etmek isteyebilirsiniz. Filtre dalı belgelerinde geçerli bir alternatif olarak resmen belirtilmiştir :
git-filter-branch, Git geçmişinizin kabuk komut dosyası yeniden yazma işlemlerini yapmanızı sağlar, ancak büyük dosyalar veya parolalar gibi istenmeyen verileri kaldırıyorsanız muhtemelen bu esnekliğe ihtiyacınız yoktur . Bu işlemler için git-filter-branşına JVM tabanlı bir alternatif olan BFG Repo- Cleaner'ı, bu kullanım durumları için tipik olarak en az 10-50x daha hızlı ve oldukça farklı özelliklere sahip olmak isteyebilirsiniz:
Bir dosyanın belirli bir sürümü tam olarak bir kez temizlenir . BFG, git-filter-branch'dan farklı olarak, bir dosyayı geçmişinizde nereye veya ne zaman işlendiğine bağlı olarak farklı şekilde işleme fırsatı vermez. Bu kısıtlama, BFG'nin temel performans avantajını sağlar ve kötü verileri temizleme görevi için çok uygundur - kötü verilerin nerede olduğu umurumda değil , sadece gitmesini istiyorsunuz .
Varsayılan olarak BFG, çok katmanlı makinelerin tüm avantajlarından yararlanır ve işleme dosya ağaçlarını paralel olarak temizler. Git-filtre-dal temizler kaydedilmesini sırayla (yani tek dişli bir tarzda), olsa olan
her karşı yürütülen komut işlemek mümkün kendi paralellik içermektedir filtreleri yazmak için.
Komut seçenekleri sadece örn veriler- istenmeyen kaldırma görevlerine çok daha git-filtre dalından farklı kısıtlayıcı ve adanmış gibidir: --strip-blobs-bigger-than 1M
.
Ek kaynaklar
- Pro Git § 6.4 Git Araçları - Yeniden Yazma Geçmişi .
- git-filter-branch (1) Kılavuz Sayfası .
- git-commit (1) Kılavuz Sayfası .
- git-reset (1) Manuel Sayfa .
- git-rebase (1) Kılavuz Sayfası .
- BFG Repo Temizleyici (ayrıca yaratıcının kendisinden gelen bu cevaba bakınız ).