Kako popraviti pogrešno spajanje i reproducirati vaša dobra urezivanja u fiksno spajanje?

Slučajno sam popravio neželjenu datoteku ( filename.orig pri spajanju riješen) u svom spremištu nekoliko vraćanja, ali još uvijek nisam primijetio. Želim u potpunosti ukloniti datoteku iz povijesti spremišta.

Je li moguće prepisati povijest promjena tako da se filename.orig nikad ne doda u spremište?

385
21 нояб. postavio Grant Limberg 21 nov. 2008-11-21 07:11 '08 u 7:11 am 2008-11-21 07:11
@ 13 odgovora

Nemojte koristiti ovaj recept ako vaša situacija nije opisana u pitanju. Ovaj je recept namijenjen ispravljanju pogrešnog spajanja i ponavljanju dobrih prijenosa na fiksno spajanje.

Iako će filter-branch raditi ono što želite, to je prilično komplicirana naredba i ja bih vjerojatno odlučio to učiniti s git rebase . To je vjerojatno osobna preferencija. filter-branch može to učiniti u jednoj, malo složenijoj naredbi, dok rebase rješenje obavlja jednake logičke operacije korak po korak.

Isprobajte sljedeći recept:

21 нояб. odgovor je dat CB Bailey 21. studenog. 2008-11-21 16:02 '08 u 16:02 2008-11-21 16:02

Uvod: Imate 5 dostupnih rješenja.

Izvorni poster glasi:

Slučajno sam napravio neželjenu datoteku ... u mom spremištu nekoliko povratnih poruka ... Želim potpuno ukloniti datoteku iz povijesti spremišta.

Je li moguće prepisati povijest promjena tako da filename.orig nije dodana u spremište?

Postoji mnogo načina za brisanje cijele povijesti datoteke iz git-a:

  • Promjena se obvezuje.
  • Tvrdi kapi (vjerojatno plus rebase).
  • Ponovno pokretanje bez interaktivnosti.
  • Interaktivne permutacije.
  • Filtracija grana.

U slučaju izvornog postera, fiksiranje urezivanja nije samo po sebi opcija, jer je nakon toga napravio nekoliko dodatnih bodova, ali zbog cjelovitosti, objasnit ću vam kako to učiniti za svakoga tko želi promijeniti prethodnu fiksaciju.

Imajte na umu da sva ova rješenja uključuju promjenu / prepisivanje povijesti / popravljanje u jednom slučaju u drugo, tako da će netko sa starim kopijama urezivanja morati obaviti dodatni posao kako bi svoju sinkronizaciju s novom poviješću ponovno sinkronizirao.


1. rješenje: Promjena se obvezuje

Ako ste slučajno napravili promjene (na primjer, dodavanje datoteke) u prethodnu pohranu, a ne želite da povijest te promjene više postoji, možete jednostavno promijeniti prethodnu pohranu za brisanje datoteke s nje:

 git rm <file> git commit --amend --no-edit 

2. rješenje: Hard Reset (moguće plus rebase)

Kao rješenje # 1, ako se samo želite riješiti svog prethodnog urezivanja, tada također imate mogućnost da jednostavno napravite hard reset za svog roditelja:

 git reset --hard HEAD^ 

Ova će naredba biti teža - resetirajte granu na prethodni roditeljski niz st da se izvrši.

Međutim , ako ste, kao i originalni plakat, napravili nekoliko objava nakon popravljanja, koje želite otkazati, i dalje možete koristiti tvrde kapi da biste ih promijenili, ali to je također povezano s korištenjem rebase. Evo koraka koje možete koristiti za promjenu urezivanja u povijesti:

 # 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} 

4. rješenje: interaktivne ponavljanja

Ovo rješenje će vam omogućiti izvođenje istih zadataka kao rješenja # 2 i # 3, tj. Promjena ili brisanje je dovršena više u povijesti nego u prethodnom obvezu, tako da je odluka koju odlučite koristiti ovisi o vama. Interaktivne permutacije nisu prikladne za ponovno učitavanje stotina urezivanja, za izvedbu, pa bih u takvim situacijama koristio ne-interaktivne ponovne instalacije ili granu filtra (vidi dolje).

Za pokretanje interaktivnog ponovnog pokretanja upotrijebite sljedeće:

border=0
 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) 

Kraj koji želite promijeniti ili izbrisati bit će na vrhu popisa. Da biste je uklonili, jednostavno izbrišite njegovu liniju na popisu. U suprotnom, "pick" zamijenite s "edit" na liniji 1 na primjer:

U ovoj fazi možete izbrisati datoteku i promijeniti urezivanje, a zatim nastaviti s premještanjem:

 git rm <file> git commit --amend --no-edit git rebase --continue 

Što je to? Kao posljednji korak, bez obzira jeste li promijenili popravak ili ste ga u potpunosti izbrisali, uvijek je korisno provjeriti da nije bilo drugih neočekivanih promjena u vašoj podružnici, ako ste promijenili njegovo stanje prije ponovnog pokretanja:

 git diff master@{1} 

5. rješenje: filtracija grana

Konačno, ovo rješenje je najbolje ako želite potpuno uništiti sve tragove postojanja datoteke iz povijesti, a nijedno drugo rješenje nije prikladno za zadatak.

Opet, nakon filter-branch , obično se preporučuje da provjerite da nema drugih neočekivanih promjena ako podijelite podružnicu iz prethodnog stanja prije operacije filtriranja:

 git diff master@{1} 

Alternativni filtar filtra: BFG Repo Cleaner

Čuo sam da je alat BFG Repo Cleaner brži od git filter-branch , tako da to možete provjeriti i kao opciju. Čak se i službeno spominje u dokumentaciji o filtru kao održiva alternativa:

git-filter-branch vam omogućuje stvaranje složenih prepisivih skripti za vašu povijest git-a, ali vjerojatno ne trebate tu fleksibilnost ako jednostavno izbrišete nepotrebne podatke, kao što su velike datoteke ili lozinke. Za ove operacije, možete razmotriti BFG repo-čistač , JVM - baziranu alternativu git filterima, obično najmanje 10-50 puta brže za te slučajeve uporabe i sa potpuno različitim karakteristikama:

  • Svaka specifična verzija datoteke čisti se točno jednom. BFG, za razliku od git-filter-grane, ne dopušta vam da drugačije obradite datoteku ovisno o tome gdje i kada je to učinjeno u vašoj priči. Ovo ograničenje pruža glavnu korist od BFG-a i dobro je prilagođeno zadatku čišćenja loših podataka - vi niste tamo gdje je loš podatak, samo želite da nestane.

  • Prema zadanim postavkama, BFG u potpunosti koristi prednosti strojeva s više jezgri, čiste datoteke datoteka paralelno. Git-filter-grana čisti se uzastopno (to jest, u jednom navoju), iako je moguće pisati filtre, koji uključuju vlastiti paralelizam, u skriptama koje se izvršavaju protiv svakog popravka.

  • Parametri su restriktivniji od git filtera i namijenjeni su samo za zadatak brisanja neželjenih podataka, na primjer: --strip-blobs-bigger-than 1M .

Dodatna sredstva

197
21 апр. odgovor dao user456814 21. travnja 2014-04-21 02:10 '14 u 2:10 2014-04-21 02:10

Ako niste ništa git commit --amend , samo git commit --amend datoteku i git commit --amend .

Ako imaš

 git filter-branch \ --index-filter 'git rm --cached --ignore-unmatch path/to/file/filename.orig' merge-point..HEAD 

će proslijediti svaku promjenu od merge-point do HEAD , izbrisati naziv datoteke. Korištenje --ignore-unmatch znači da naredba nije neuspješna ako iz nekog razloga nedostaje ime datoteke.orig kao rezultat promjene. To se preporučuje iz odjeljka "Primjeri" na stranici git-filterom-granom .

Napomena za korisnike sustava Windows: put datoteke treba koristiti kosu crtu

117
14 марта '09 в 23:44 2009-03-14 23:44 odgovor je dao Schwern 14. ožujka 2009. u 23:44 2009-03-14 23:44

Ovo je najbolji način:
http://github.com/guides/completely-remove-a-file-from-all-revisions

Samo budite sigurni da napravite sigurnosnu kopiju datoteka.

EDIT

Uređivanje Neona, nažalost, odbijeno je tijekom pregleda.
Pogledajte post Neons ispod, može sadržavati korisne informacije!


Na primjer, za brisanje svih *.gz datoteka slučajno *.gz u git repozitoriju:

 $ du -sh .git ==> eg 100M $ git filter-branch --index-filter 'git rm --cached --ignore-unmatch *.gz' HEAD $ git push origin master --force $ rm -rf .git/refs/original/ $ git reflog expire --expire=now --all $ git gc --prune=now $ git gc --aggressive --prune=now 

Još uvijek ne radi za mene? (Sada sam na git verziji 1.7.6.1)

 $ du -sh .git ==> eg 100M 

Ne znam zašto, jer sam imao samo jednu glavnu granu. U svakom slučaju, napokon sam dobio čisto git repozitorij pokretanjem novog praznog i praznog git repozitorija, na primjer

 $ git init --bare /path/to/newcleanrepo.git $ git push /path/to/newcleanrepo.git master $ du -sh /path/to/newcleanrepo.git ==> eg 5M 

(Da!)

Zatim sam ga klonirao u novi direktorij i premjestio mapu.git na ovu. na primjer

 $ mv .git ../large_dot_git $ git clone /path/to/newcleanrepo.git ../tmpdir $ mv ../tmpdir/.git . $ du -sh .git ==> eg 5M 

(da! konačno očistiti!)

Nakon što provjerite je li sve u redu, možete izbrisati ../large_dot_git i ../tmpdir (možda za nekoliko tjedana ili mjesec dana, za svaki slučaj ...)

47
04 февр. Odgovor daje Darren 04. veljače. 2010-02-04 08:52 '10 u 8:52 2010-02-04 08:52

Prepisivanje Git povijesti zahtijeva promjenu svih utjecajnih ID-ova popravaka, tako da će svi koji rade na projektu morati ukloniti svoje stare repo kopije i napraviti novi klon nakon što izbrišete povijest. Što je više ljudi neugodno, to je više razloga za to - vaša dodatna datoteka zapravo ne uzrokuje probleme, ali ako radite samo na projektu, također možete izbrisati Git povijest ako želite!

Da bi bilo što lakše, preporučujem BFG Repo-Cleaner , bržu i bržu alternativu git-filter-branch posebno dizajniranoj za uklanjanje datoteka iz Git povijesti. Jedan od načina kako bi vam olakšao život je to što on zapravo obrađuje sve veze po defaultu (sve oznake, grane, itd.), Ali i 10 - 50x brže.

Trebate pažljivo slijediti ove korake: http://rtyley.github.com/bfg-repo-cleaner/#usage - ali osnovni bit je jednostavan: preuzmite BFG jar (potrebno je Java 6 ili više) i pokrenite sljedeću naredbu:

 $ java -jar bfg.jar --delete-files filename.orig my-repo.git 

Cijela će povijest spremišta biti skenirana, a svaka datoteka pod imenom filename.orig (koja nije u posljednjem urezivanju ) bit će izbrisana. To je mnogo lakše nego koristiti git-filter-branch za isto!

Potpuno otkrivanje: Ja sam autor BFG Repo-Cleanera.

25
31 марта '13 в 15:35 2013-03-31 15:35 odgovor je dao Roberto Tyley 31. ožujka 2013. u 15:35 2013-03-31 15:35
 You should probably clone your repository first. Remove your file from all branches history: git filter-branch --tree-filter 'rm -f filename.orig' -- --all Remove your file just from the current branch: git filter-branch --tree-filter 'rm -f filename.orig' -- --HEAD Lastly you should run to remove empty commits: git filter-branch -f --prune-empty -- --all 
12
10 июня '16 в 9:35 2016-06-10 09:35 odgovor je dat paulalexandru 10. lipnja '16 u 9:35 2016-06-10 09:35

Najlakši način koji sam pronašao bio je predložen od strane leontalbot (kao komentar) koji objavljuje Anoopjohn . Mislim da vrijedi svoj prostor kao odgovor:

(Pretvorio sam ga u bash skriptu)

 #!/bin/bash if [[ $1 == "" ]]; then echo "Usage: $0 FILE_OR_DIR [remote]"; echo "FILE_OR_DIR: the file or directory you want to remove from history" echo "if 'remote' argument is set, it will also push to remote repository." exit; fi FOLDERNAME_OR_FILENAME=$1; #The important part starts here: ------------------------ git filter-branch -f --index-filter "git rm -rf --cached --ignore-unmatch $FOLDERNAME_OR_FILENAME" -- --all rm -rf .git/refs/original/ git reflog expire --expire=now --all git gc --prune=now git gc --aggressive --prune=now if [[ $2 == "remote" ]]; then git push --all --force fi echo "Done." 

Svi krediti se prebacuju na Annopjohn i leontalbot kako bi ga označili.

primjedba

Imajte na umu da skripta ne uključuje provjere, stoga provjerite da niste u zabludi i imate sigurnosnu kopiju ako nešto pođe po zlu. To mi je pomoglo, ali možda neće uspjeti u vašoj situaciji. KORISTITE OVO SA UPOZORENJEM (slijedite vezu ako želite znati što se događa).

4
17 мая '16 в 5:26 2016-05-17 05:26 odgovor dao lepe 17. svibnja '16 u 5:26 2016-05-17 05:26

Da bi to dodao u rješenje Charlesa Baileyja, jednostavno sam koristio git rebase-i da bih uklonio neželjene datoteke iz ranijeg urezivanja i to je djelovalo kao šarm. koraka:

 # Pick your commit with 'e' $ git rebase -i # Perform as many removes as necessary $ git rm project/code/file.txt # amend the commit $ git commit --amend # continue with rebase $ git rebase --continue 
4
16 окт. Odgovor dao Sverrir Sigmundarson 16. listopada 2013-10-16 16:10 '13 u 16:10 2013-10-16 16:10

Definitivno, git filter-branch je način da se ide.

Nažalost, to nije dovoljno da u potpunosti uklonite filename.orig iz repoa, budući da ga još uvijek mogu referencirati oznake, reflog unosi, konzole itd.

Preporučujem uklanjanje svih tih veza i pozivanje sakupljača smeća. Možete koristiti git forget-blob skriptu s ove web-lokacije da biste to učinili u jednom koraku.

git forget-blob filename.orig

3
30 янв. Odgovor daje nachoparker 30. siječnja 2017-01-30 15:54 '17 u 15:54 2017-01-30 15:54

Ako je ovo zadnja objava koju želite izbrisati, pokušao sam koristiti git verziju 2.14.3 (Apple Git-98):

 touch empty git init git add empty git commit -m init # 92K .git du -hs .git dd if=/dev/random of=./random bs=1m count=5 git add random git commit -m mistake # 5.1M .git du -hs .git git reset --hard HEAD^ git reflog expire --expire=now --all git gc --prune=now # 92K .git du -hs .git 
1
29 марта '18 в 18:40 2018-03-29 18:40 Odgovorio Clark 29. ožujka '18 u 18:40 sati 2018-03-29 18:40

morate upotrijebiti granu git filtera, zamislite da želite ukloniti sve ciljne / dirs-ove u prethodnim urezima, možete pokrenuti samo 4 naredbe za ovo:

 $ git filter-branch --tree-filter 'rm -f */target' HEAD $ rm -rf */target (you use this one to delete target/ dirs on current HEAD) $ git commit -am 'delete all target/ dirs' --allow-empty $ git push 
0
10 дек. Odgovor daje Walterwhites 10. prosinca. 2018-12-10 21:41 '18 u 21:41 2018-12-10 21:41

To je ono što je git filter-branch namijenjena.

0
21 нояб. odgovor je dat CesarB 21 nov. 2008-11-21 13:26 '08 u 13:26 2008-11-21 13:26

Također možete koristiti:

git reset HEAD file/path

-1
03 сент. odgovor je dat paolo granada lim 03 Sep. 2009-09-03 07:00 '09 u 7:00 2009-09-03 07:00