Kaip išspręsti blogą sujungimą ir atkurti savo gerą įsipareigojimą fiksuotam susiliejimui?

Aš atsitiktinai fiksavau nepageidaujamą failą ( filename.orig Kai susijungiau išsprendžiau) mano saugykloje kelis įsipareigojimus, bet aš vis dar to nepastebėjau. Noriu visiškai pašalinti failą iš saugyklos istorijos.

Ar galima perrašyti pakeitimų istoriją, kad filename.orig niekada nebūtų įtrauktas į saugyklą?

385
21 нояб. įkūrė Grant Limberg 21 nov. 2008-11-21 07:11 '08, 07:11 am 2008-11-21 07:11
@ 13 atsakymų

Nenaudokite šio recepto, jei jūsų situacija nėra tokia, kokia aprašyta klausime. Šis receptas skirtas blogam susiliejimui ištaisyti ir pakartoti savo gerą įsipareigojimą fiksuotam susiliejimui.

Nors filter-branch darys tai, ko norite, tai yra gana sudėtinga komanda, ir aš tikriausiai nuspręsiu tai padaryti su git rebase . Tai tikriausiai yra asmeninis pasirinkimas. filter-branch gali tai padaryti vienoje, šiek tiek sudėtingesnėje komandoje, o rebase sprendimas atlieka lygiaverčius loginius veiksmus vienu žingsniu.

Išbandykite šį receptą:

288
21 нояб. atsakymas pateikiamas CB Bailey 21 lapkričio. 2008-11-21 16:02 '08 4:02 pm 2008-11-21 16:02

Įvadas: Turite 5 sprendimus.

Originalus plakatas:

Aš atsitiktinai padariau nepageidaujamą failą ... mano saugykloje keletas sugrįžta ... Noriu visiškai pašalinti failą iš saugyklos istorijos.

Ar galima perrašyti pakeitimų istoriją taip, kad filename.orig niekada nebūtų įtrauktas į saugyklą?

Yra daug būdų, kaip ištrinti visą failo istoriją iš „git“:

  • Pasikeičia įsipareigojimas.
  • Sunkūs lašai (galbūt plius grįžimas).
  • Neaktyvus perkėlimas iš naujo.
  • Interaktyvios permutacijos.
  • Filialų filtravimas.

Pradinio plakato atveju įsipareigojimo nustatymas nėra savaiminis variantas, nes po to jis padarė keletą papildomų taškų, tačiau išsamumo sumetimais taip pat paaiškinsiu, kaip tai padaryti visiems, kurie tiesiog nori pakeisti savo ankstesnę fiksaciją.

Atkreipkite dėmesį, kad visi šie sprendimai apima istorijos keitimą / perrašymą vienu atveju į kitą, taigi kažkas, turintis senų kopijų, turės atlikti papildomus darbus, kad jų istorija būtų suderinta su nauja istorija.


1 sprendimas

Jei netyčia padarėte pakeitimus (pvz., Pridėjote failą) prie ankstesnio įsipareigojimo, ir nenorite, kad šio pakeitimo istorija būtų daugiau, galite tiesiog pakeisti ankstesnį įsipareigojimą ištrinti failą iš jo:

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

2 sprendimas. Kietasis atstatymas (galimas pliusas)

Kaip 1-asis sprendimas, jei norite tiesiog atsikratyti ankstesnio įsipareigojimo, jūs taip pat turite galimybę paprasčiausiai atkurti savo tėvą:

 git reset --hard HEAD^ 

Ši komanda bus sunkesnė - atkurkite savo filialą į ankstesnę tėvų eilutę st .

Tačiau , jei, kaip ir originalus plakatas, padarėte keletą įsipareigojimų, kuriuos norite atšaukti, jūs vis tiek galite naudoti sunkius lašus, kad juos pakeistumėte, tačiau tai taip pat yra susijusi su rebase naudojimu. Čia rasite veiksmus, kuriuos galite naudoti norint pakeisti įvykio istoriją:

 # 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 sprendimas. Interaktyvios perkrovos

Šis sprendimas leis jums atlikti tuos pačius uždavinius kaip ir # 2 ir # 3 sprendimai, t. Pokytis ar ištrynimas istorijoje yra baigtas daugiau nei jūsų ankstesnis įsipareigojimas, todėl sprendimas, kurį nuspręsite naudoti, priklauso nuo jūsų. Interaktyviosios permutacijos nėra labai tinkamos perkrauti šimtus įsipareigojimų, kad galėčiau atlikti tokius įvykius, todėl tokiose situacijose aš naudoju neinteraktyvius pakartotinius diegimus arba filtrų šaką (žr. Žemiau).

Jei norite pradėti interaktyvų perkėlimą, naudokite šiuos veiksmus:

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) 

Galutinis, kurį norite pakeisti arba ištrinti, bus šio sąrašo viršuje. Jei norite ją pašalinti, tiesiog ištrinkite jo eilutę sąraše. Priešingu atveju, pakeiskite "pick" su "redaguoti" 1 eilutės eilutėje:

Šiame etape galite ištrinti failą ir pakeisti įsipareigojimą, o tada tęsti perkėlimą:

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

Kas tai yra. Kaip paskutinį žingsnį, nesvarbu, ar pakeitėte įrašą, ar jį ištrynėte, visada naudinga patikrinti, ar jūsų filialas nepadarė jokių kitų netikėtų pakeitimų, jei pakeitėte savo būseną prieš perkėlimą:

 git diff master@{1} 

5 sprendimas: filialų filtravimas

Galiausiai, šis sprendimas yra geriausias, jei norite visiškai sunaikinti visus istorijos egzistavimo pėdsakus ir nė vienas iš kitų sprendimų nėra tinkamas užduočiai.

 git filter-branch --index-filter \ 'git rm --cached --ignore-unmatch <file>' HEAD~5..HEAD 

Vėlgi, pasibaigus filter-branch padalijimui, paprastai rekomenduojama patikrinti, ar nėra kitų netikėtų pakeitimų, jei padalysite filialą iš ankstesnės būsenos prieš filtravimo operaciją:

 git diff master@{1} 

Alternatyvus filtrų filtras: BFG Repo Cleaner

Aš girdėjau, kad „ BFG Repo Cleaner“ įrankis yra greitesnis už „ git filter-branch , todėl taip pat galite tai patikrinti. Jis netgi buvo oficialiai paminėtas filtro dokumentuose kaip perspektyvi alternatyva:

„git -filter-branch“ leidžia sukurti sudėtingus perrašomus scenarijus, skirtus jūsų git istorijai, tačiau jums tikriausiai nereikia šio lankstumo, jei paprasčiausiai ištrinate nereikalingus duomenis, pvz., didelius failus ar slaptažodžius. Šių operacijų atveju galite apsvarstyti „BFG Repo-Cleaner“ , „JVM“ pagrįstą alternatyvą „git“ filtrams, paprastai mažiausiai 10-50 kartų greičiau šiais naudojimo atvejais ir visiškai skirtingomis charakteristikomis:

  • Bet kokia konkreti failo versija išvaloma tiksliai vieną kartą. BFG, skirtingai nuo git -filter-filialo, neleidžia apdoroti failo kitaip, priklausomai nuo to, kur ir kada tai buvo padaryta jūsų istorijoje. Šis apribojimas suteikia pagrindinę BFG naudą ir yra tinkamas netinkamų duomenų išvalymui - nesate, kur yra blogi duomenys, tiesiog norite, kad jis išnyktų.

  • Pagal numatytuosius nustatymus BFG visapusiškai naudoja daugiašalius įrenginius, lygiagrečiai valo failų failus. Git-filter-filialas išsiskiria nuosekliai (tai yra vieno sriegio režimu), nors galima užrašyti filtrus, kuriuose yra jų pačių lygiagretumas, scenarijuose, vykdomuose prieš kiekvieną pataisymą.

  • Parametrai yra griežtesni nei git-filter filialas ir yra skirti tik užduotims ištrinti nepageidaujamus duomenis, pavyzdžiui: - --strip-blobs-bigger-than 1M .

Papildomi ištekliai

197
21 апр. atsakymas, kurį pateikė user456814 Apr 21 2014-04-21 02:10 '14, 2:10, 2014-04-21 02:10

Jei nieko nepadarėte, tiesiog git rm failą ir git commit --amend .

Jei turite

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

perkelia kiekvieną pakeitimą iš merge-point į HEAD , ištrins failo pavadinimą.irig ir perrašys pakeitimą. Naudojant --ignore-unmatch reiškia, kad komanda nepavyksta, jei dėl kokios nors priežasties dėl pakeitimo failo vardas yra. Tai rekomenduojama „ Git -filter-branch“ puslapio skiltyje „Pavyzdžiai“.

Pastaba „Windows“ naudotojams: failo kelias turi naudoti brūkšnelius

117
14 марта '09 в 23:44 2009-03-14 23:44 atsakymą pateikė Schwern , kovo 14 d. , 09:44 , 2009-03-14 23:44

Tai geriausias būdas:
http://github.com/guides/completely-remove-a-file-from-all-revisions

Tiesiog įsitikinkite, kad atsargines failų kopijas.

EDIT

Deja, „ Neon“ redagavimas buvo atmestas peržiūros metu.
Žr. Toliau pateiktą „Neons“ įrašą, jame gali būti naudingos informacijos!


Pavyzdžiui, jei norite netyčia ištrinti visus *.gz failus *.gz

 $ 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 

Ar tai vis dar neveikia? (Dabar esu „git“ versijoje 1.7.6.1)

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

Nežinau, kodėl, nes turėjau tik vieną pagrindinį filialą. Bet kokiu atveju, aš galiausiai gavau švarų „git“ saugyklą, pavyzdžiui, paleisdamas naują tuščią ir tuščią „git“ saugyklą

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

(taip!)

Tada aš jį klonuosiu į naują katalogą ir perkelsiu aplanką.git. Pavyzdžiui

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

(taip! pagaliau išvalykite!)

Įsitikinę, kad viskas yra tvarkinga, galite ištrinti ../large_dot_git ir ../tmpdir (galbūt per kelias savaites ar mėnesį, tik tuo atveju, jei ...)

47
04 февр. Atsakymą pateikė Darren vasario 4 d. 2010-02-04 08:52 '10 at 8:52 2010-02-04 08:52

Perrašant „Git“ istoriją reikia pakeisti visus paveiktus fiksavimo ID, todėl kiekvienas, kuris dirba su projektu, turės ištrinti senas repo kopijas ir po to, kai pašalinsite istoriją. Kuo daugiau žmonių yra nepatogūs, tuo daugiau reikia to padaryti - jūsų papildomas failas tikrai nesukelia problemų, tačiau jei dirbate tik su projektu, taip pat galite išvalyti „Git“ istoriją, jei norite!

Kad tai būtų kuo lengviau, rekomenduoju naudoti „ BFG Repo-Cleaner“ , greitesnę ir greitesnę alternatyvą „ git-filter-branch , skirtą pašalinti failus iš „Git“ istorijos. Vienas iš būdų, kaip palengvinti savo gyvenimą, yra tai, kad ji iš tikrųjų apdoroja visas nuorodas pagal nutylėjimą (visos žymos, filialai ir tt), bet taip pat 10 - 50 kartų greičiau.

Turėtumėte atidžiai sekti čia nurodytus veiksmus: http://rtyley.github.com/bfg-repo-cleaner/#usage - bet paprastas bitas yra paprastas: atsisiųskite „ BFG“ stiklainį (reikia „Java 6“ ar naujesnės versijos) ir paleiskite šią komandą:

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

Visa jūsų saugyklos istorija bus nuskaityta ir bet koks failas, pavadintas filename.orig (kuris nėra paskutiniame įraše ) bus ištrintas. Tai yra daug lengviau nei naudojant git-filter-branch daryti tą patį!

Visiškas atskleidimas: esu BFG Repo-Cleaner autorius.

25
31 марта '13 в 15:35 2013-03-31 15:35 atsakymą pateikė Roberto Tyley, kovo 31 d., 13 val. 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 atsakymas pateikiamas paulalexandru birželio 10 d. 16 val. 9:35 2016-06-10 09:35

Lengviausias būdas, kurį radau, buvo pasiūlytas „ leontalbot (kaip komentaras), kurį paskelbė „Anoopjohn“ . Manau, kad verta savo vietos kaip atsakymą:

(Konvertuoju jį į bash scenarijų)

 #!/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." 

Visi kreditai perduodami Annopjohn ir leontalbot kad jis būtų nurodytas.

Pastaba

Turėkite omenyje, kad scenarijuje nėra patikrinimų, todėl įsitikinkite, kad neklysta ir turite atsarginę kopiją, jei kažkas negerai. Jis dirbo man, bet jis gali neveikti jūsų situacijoje. NAUDOTI ŠIS SU ĮSPĖJIMU (jei norite sužinoti, kas vyksta), vadovaukitės nuoroda.

4
17 мая '16 в 5:26 2016-05-17 05:26 atsakymas, kurį davė lepė gegužės 17 d., 16 d., 5:26 2016-05-17 05:26

Norėdami tai pridėti prie Charleso Bailey sprendimo, aš paprasčiausiai naudoju git rebase -i, kad pašalintumėte nepageidaujamus failus iš ankstesnio įsipareigojimo, ir jis veikė kaip žavesys. Žingsniai:

 # 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 окт. Sverrir Sigmundarson atsakymas spalio 16 d 2013-10-16 16:10 '13, 16:10, 2013-10-16 16:10

Tikrai, git filter-branch yra kelias.

Deja, to nepakanka, kad visiškai pašalintumėte filename.orig jūsų repo, nes jis vis tiek gali būti susijęs su žymėmis, refloginiais įrašais, konsolėmis ir pan.

Aš rekomenduoju pašalinti visas šias nuorodas ir paskambinti į šiukšlių surinkėją. Šį tinklalapį galite naudoti git forget-blob scenarijų, kad tai atliktumėte vienu žingsniu.

git forget-blob filename.orig

3
30 янв. Atsakymą pateikė nachoparker sausio 30 d 2017-01-30 15:54 '17 at 15:54 2017-01-30 15:54

Jei tai paskutinis įvykis, kurį norite išvalyti, bandžiau naudoti git versiją 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 Clarkas atsakė kovo 29 d. 18 val. 18.40 2018-03-29 18:40

turite naudoti „git“ filtravimo šaką, įsivaizduokite, kad norite pašalinti visus ankstesnius įsipareigojimus, galite paleisti tik 4 komandas:

 $ 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 дек. Atsakymą pateikė Walterwhites 10 gruodis. 2018-12-10 21:41 '18, 21:41 2018-12-10 21:41

Tai yra git filter-branch .

0
21 нояб. atsakymas pateikiamas CesarB 21 nov. 2008-11-21 13:26 '08 13:26 pm 2008-11-21 13:26

Taip pat galite naudoti:

git reset HEAD file/path

-1
03 сент. atsakymas pateikiamas paolo granada lim 03 Sep. 2009-09-03 07:00 '09 7:00 val. 2009-09-03 07:00