Kaip pašalinti / ištrinti didelį failą iš įsipareigojimo istorijos „Git“ saugykloje?

Kartais ištrinau „DVD“ repliką į svetainės projektą, tada atsitiktinai git commit -a -m ... ir „zap“. Kitą kartą, kai padariau pakeitimus, ištrinau vaizdo failą ir nustatiau viską, bet suspaustas failas vis dar yra istorijos saugykloje.

Žinau, kad galiu pradėti filialus iš šių įvykių ir pertvarkyti vieną šaką į kitą. Bet ką turėčiau daryti, kad sujungti 2 įsipareigojimus, kad istorijoje nebūtų rodomas didelis failas ir kad jis buvo pašalintas šiukšlių surinkimo proceso metu?

508
20 янв. nustatė culebrón sausio 20 2010-01-20 14:18 '10, 14:18, 2010-01-20 14:18
@ 14 atsakymų

Naudokite „ BFG Repo-Cleaner“ , greitesnę ir greitesnę „ git-filter-branch alternatyvą, specialiai skirtą pašalinti nepageidaujamus failus iš „Git“ istorijos.

Atsargiai laikykitės nurodymų, pagrindinė dalis yra:

 $ java -jar bfg.jar --strip-blobs-bigger-than 100M my-repo.git 

Visi failai, didesni nei 100 MB (kurie nėra paskutiniame įraše), bus ištrinti iš „Git“ saugyklos istorijos. Tada galite naudoti git gc kad pašalintumėte mirusius duomenis:

 $ git gc --prune=now --aggressive 

BFG dažniausiai yra mažiausiai 10–50 kartų greitesnis, nei veikia „ git-filter-branch ir paprastai yra lengviau naudoti.

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

440
26 июля '13 в 23:15 2013-07-26 23:15 atsakymą davė Roberto Tyley , liepos 26 d. 13, 23:15 2013-07-26 23:15

Ką norite padaryti, yra labai žalinga, jei publikuojate istoriją kitiems kūrėjams. Žr. „Atkurti iš kylančiosios bazės“ git rebase dokumentuose , kad git rebase reikiamus veiksmus po to, kai git rebase istoriją.

Turite bent dvi parinktis: git filter-branch ir interaktyvų permutaciją, kaip aprašyta toliau.

git filter-branch

Turėjau panašią problemą su dideliais dvejetainiais bandymų duomenimis iš „Subversion“ importavimo ir jis parašytas apie duomenų ištrynimą iš git saugyklos .

Pasakykite man, ką git istorija yra:

 $ git lola --name-status * f772d66 (HEAD, master) Login page | A login.html * cb14efd Remove DVD-rip | D oops.iso * ce36c98 Careless | A oops.iso | A other.html * 5af4522 Admin page | A admin.html * e738b63 Index A index.html 

Atkreipkite dėmesį, kad git lola yra nestandartinis, bet labai naudingas slapyvardis. Naudodami „ --name-status jungiklį, matome medžio pakeitimus, susijusius su kiekvienu --name-status .

„Careless“ įsipareigojimas (kurio SHA1 objekto pavadinimas yra ce36c98), oops.iso failas yra DVD diskas, pridėtas atsitiktinai ir ištrintas sekančiame įvykyje, cb14efd. Naudojant aukščiau pateiktame tinklaraštyje aprašytą metodą, atlikite komandą:

/dev/shm sukels greitesnį vykdymą . 
  • --index-filter yra pagrindinis įvykis ir veikia prieš indeksą kiekviename istorijos etape. Jūs norite ištrinti oops.iso kur jis randamas, bet visuose įsipareigojimuose jis nėra. git rm --cached -f --ignore-unmatch oops.iso ištrina DVD diską, kai jis yra, ir neveikia kitaip.
  • --tag-name-filter aprašo, kaip perrašyti žymų pavadinimus. cat filtras yra identifikavimo operacija. Jūsų saugykloje, kaip ir aukščiau pateiktame pavyzdyje, gali būti, kad nėra jokių žymių, bet aš įgalinau šią parinktį visiškam bendrumui.
  • -- nurodo „ git filter-branch parinkčių pabaigą
  • -- po to -- yra visų nuorodų santrumpa. Savo saugykloje, kaip ir aukščiau pateiktame pavyzdyje, gali būti tik vienas ref (master), bet aš įgalinau šią parinktį visiškam bendrumui.
  • Po to, kai po to, kai drebėsite istoriją:

     $ git lola --name-status * 8e0a11c (HEAD, master) Login page | A login.html * e45ac59 Careless | A other.html | * f772d66 (refs/original/refs/heads/master) Login page | | A login.html | * cb14efd Remove DVD-rip | | D oops.iso | * ce36c98 Careless |/ | A oops.iso | A other.html * 5af4522 Admin page | A admin.html * e738b63 Index A index.html 

    Atkreipkite dėmesį, kad naujas „nerūpestingas“ įsipareigojimas prideda tik „ other.html ir kad „Pašalinti DVD other.html “ įsipareigojimas nebėra pagrindiniame filiale. Filialas, pažymėtas refs/original/refs/heads/master apima jūsų pradinius įrašus, jei padarote klaidą. Norėdami jį pašalinti, atlikite kontroliniame sąraše nurodytus veiksmus, kad sumažintumėte saugojimą.

     $ git update-ref -d refs/original/refs/heads/master $ git reflog expire --expire=now --all $ git gc --prune=now 

    Paprastesnė alternatyva - klonuokite saugyklą, kad pašalintumėte nepageidaujamus bitus.

     $ cd ~/src $ mv repo repo.old $ git clone file:///home/user/src/repo.old repo 

    Naudojant file:///... klonas URL nukopijuoja objektus ir nesukuria tik kietų nuorodų.

    Dabar jūsų istorija:

    border=0
     $ git lola --name-status * 8e0a11c (HEAD, master) Login page | A login.html * e45ac59 Careless | A other.html * 5af4522 Admin page | A admin.html * e738b63 Index A index.html 

    Pirmųjų dviejų įvykių SHA1 objektų pavadinimai („Index“ ir „Admin Page“) išlieka tokie patys, nes filtravimo operacija šių pakeitimų nepasikeitė. „Carelessly“ prarastas oops.iso ir „Login Page“ gavo naują tėvą, todėl jų SHA1 pasikeitė.

    Interaktyvus peradresavimas

    Su istorija:

     $ git lola --name-status * f772d66 (HEAD, master) Login page | A login.html * cb14efd Remove DVD-rip | D oops.iso * ce36c98 Careless | A oops.iso | A other.html * 5af4522 Admin page | A admin.html * e738b63 Index A index.html 

    Norite pašalinti „ oops.iso iš „Careless“, tarsi jūs to dar nepridėjote, ir tada yra nenaudinga pašalinti DVD diską. Taigi, mūsų planas, kuriame yra interaktyvus įdiegimas, yra išsaugoti „administratoriaus puslapį“, pakeisti „nerūpestingai“ ir atmesti „Pašalinti DVD rip“.

    Paleidžiant $ git rebase -i 5af4522 prasideda redaktorius su tokiu turiniu.

     pick ce36c98 Careless pick cb14efd Remove DVD-rip pick f772d66 Login page # Rebase 5af4522..f772d66 onto 5af4522 # # Commands: # p, pick = use commit # r, reword = use commit, but edit the commit message # e, edit = use commit, but stop for amending # s, squash = use commit, but meld into previous commit # f, fixup = like "squash", but discard this commit log message # x, exec = run command (the rest of the line) using shell # # If you remove a line here THAT COMMIT WILL BE LOST. # However, if you remove everything, the rebase will be aborted. # 

    Atlikdami savo planą mes jį pakeisime

     edit ce36c98 Careless pick f772d66 Login page # Rebase 5af4522..f772d66 onto 5af4522 # ... 

    Tai reiškia, kad mes ištrinsime eilutę su „Delete DVD rip“ ir pakeiskite operaciją „Carelessly“ kaip edit , o ne pick .

    „Save-Shutdown Editor“ („Išsaugoti išjungimą“) redaktorius mums nurodys komandinę eilutę su šiuo pranešimu.

     Stopped at ce36c98... Careless You can amend the commit now, with git commit --amend Once you are satisfied with your changes, run git rebase --continue 

    Kaip nurodyta pranešime, mes esame „Careless“ komandoje, kurią norime pakeisti, todėl mes vadovaujame dviem komandoms.

     $ git rm --cached oops.iso $ git commit --amend -C HEAD $ git rebase --continue 

    Pirmasis pašalina piktnaudžiavimo failą iš indekso. Antrasis modifikuoja arba modifikuoja „nerūpestingai“ kaip atnaujintą indeksą, o -C HEAD nurodo git pakartotinai naudoti senąjį įvykio pranešimą. Galiausiai, „ git rebase --continue atlieka likusios pakartotinės operacijos vykdymą.

    Jis suteikia istoriją:

     $ git lola --name-status * 93174be (HEAD, master) Login page | A login.html * a570198 Careless | A other.html * 5af4522 Admin page | A admin.html * e738b63 Index A index.html 

    ką norite.

    481
    29 янв. Glanas Baconas atsakė į sausio 29 d 2010-01-29 00:55 '10 ne 0:55 2010-01-29 00:55

    Kodėl gi ne naudoti šią paprastą, bet galingą komandą?

     git filter-branch --tree-filter 'rm -f DVD-rip' HEAD 

    Parametras --tree-filter parametras atlieka nurodytą komandą po kiekvieno projekto patikrinimo ir patvirtina rezultatus. Tokiu atveju iš kiekvienos momentinės nuotraukos ištrinate failą, pavadintą „DVD-rip“, neatsižvelgiant į tai, ar jis yra ar ne.

    Žr. Šią nuorodą .

    120
    16 мая '15 в 12:44 2015-05-16 12:44 atsakė Gary Gauh gegužės 16, 15, 12: 44 2015-05-16 12:44

    Šios komandos dirbo mano atveju:

     git filter-branch --force --index-filter 'git rm --cached -r --ignore-unmatch oops.iso' --prune-empty --tag-name-filter cat -- --all rm -rf .git/refs/original/ git reflog expire --expire=now --all git gc --prune=now git gc --aggressive --prune=now 

    Tai šiek tiek skiriasi nuo pirmiau pateiktų versijų.

    Tiems, kuriems reikia paspausti „github“ / „bitbucket“ (tik jį išbandžiau naudojant bitų paketą):

     # WARNING!!! # this will rewrite completely your bitbucket refs # will delete all branches that you didn't have in your local git push --all --prune --force # Once you pushed, all your teammates need to clone repository again # git pull will not work 
    27
    14 июня '13 в 5:35 2013-06-14 05:35 atsakymą įteikė Kostanosas birželio 13 d. 13 d. 5:35 2013-06-14 05:35

    (Geriausias atsakymas, kurį pamačiau šioje problemoje: čia kopijuojama ngn-wiki.ru.site/questions/8406 / ... , nes šis srautas „Google“ paieškos reitinguose yra didelis, tačiau kitas „t“

    🚀 Greitas, greitas, vieno sluoksnio įvyniojimas aplink korpusą 🚀

    Šiame scenarijaus įvyniotuve rodomi visi bloko objektai saugykloje, surūšiuoti nuo mažiausio iki didžiausio.

    Mano repo repo atveju ji dirbo apie 100 kartų greičiau nei kiti čia.
    Mano patikimame „Athlon II X4“ operacijoje „Linux“ branduolių saugykla apdorojama per 5,622,155 objektus per minutę.

    Scenarijaus bazė

     git filter-branch --index-filter 'git rm --cached --ignore-unmatch ab' HEAD 
    26
    07 окт. atsakymą pateikė Sridhar-Sarnobat 07 spalis 2017-10-07 03:37 '17 at 3:37 2017-10-07 03:37

    Baigę beveik kiekvieną atsakymą į SO, pagaliau rado šį brangakmenį, kuris greitai ištrino ir ištrino didelius failus mano saugykloje ir galėjau dar kartą sinchronizuoti: http://www.zyxware.com/articles/4027/how -į-ištrinti failus - visam laikui-nuo-vietos-ir nuotolinio-git-saugyklos

    CD į vietinį darbo aplanką ir paleiskite šią komandą:

     git filter-branch -f --index-filter "git rm -rf --cached --ignore-unmatch FOLDERNAME" -- --all 

    pakeiskite FOLDERNAME failą ar aplanką, kurį norite pašalinti iš šio git saugyklos.

    Kai tai atliksite, paleiskite šias komandas, kad išvalytumėte vietinę saugyklą:

     rm -rf .git/refs/original/ git reflog expire --expire=now --all git gc --prune=now git gc --aggressive --prune=now 

    Dabar spustelėkite visus nuotolinio saugyklos pakeitimus:

     git push --all --force 

    Tai pašalins nuotolinį saugyklą.

    18
    26 апр. Justinas paskelbtas balandžio 26 d 2017-04-26 20:35 '17 ne 8:35 2017-04-26 20:35

    Atminkite, kad šios komandos gali būti labai žalingos. Jei daugiau repo dirba daugiau žmonių, jie visi turės ištraukti naują medį. Trys vidutinės komandos nėra reikalingos, jei jūsų tikslas yra ne sumažinti dydį. Kadangi filtro filialas sukuria ištrinto failo atsarginę kopiją ir gali būti ten ilgą laiką.

     $ git filter-branch --index-filter "git rm -rf --cached --ignore-unmatch YOURFILENAME" HEAD $ rm -rf .git/refs/original/ $ git reflog expire --all $ git gc --aggressive --prune $ git push origin master --force 
    9
    14 июня '12 в 14:53 2012-06-14 14:53 atsakymą mkljun davė birželio 12 d . 12 val. 14.55 val. 2012-06-14 14:53

    git filter-branch --tree-filter 'rm -f path/to/file' HEAD man labai gerai dirbo, nors git filter-branch --tree-filter 'rm -f path/to/file' HEAD į tą pačią čia aprašytą problemą, kurią išsprendžiau paleisdamas šį sakinį .

    „Pro git“ knygoje perrašymo istorijoje yra visas skyrius - pažvelgti į filter-branch / ištrinti failą iš kiekvienos komandos .

    9
    25 окт. Thorsten Lorenz atsakymas, pateiktas spalio 25 d 2012-10-25 15:24 '12, 15:24, 2012-10-25 15:24

    Jei žinote, kad jūsų įsipareigojimas buvo paskutinis, o ne per visą medį, atlikite šiuos veiksmus: git filter-branch --tree-filter 'rm LARGE_FILE.zip' HEAD~10..HEAD

    7
    01 янв. atsakymą pateikė soheil 01 jan. 2016-01-01 09:21 '16 at 9:21 AM 2016-01-01 09:21

    Į šią vietą bėgau su bitumine paskyra, kurioje atsitiktinai įrašiau ginormines * .jpa atsargines kopijas.

    git filter-branch --prune-empty --index-filter 'git rm -rf --cached --ignore-unmatch MY-BIG-DIRECTORY-OR-FILE' --tag-name-filter cat -- --all

    Perkelkite MY-BIG-DIRECTORY su atitinkamu aplanku, kad perrašytumėte istoriją (įskaitant žymes).

    šaltinis: http://naleid.com/blog/2012/01/17/finding-and-purging-big-files-from-git-history

    5
    31 авг. atsakymas pateikiamas lfender6445 31 rug . 2014-08-31 22:33 '14, 10:33 pm 2014-08-31 22:33

    Tai galite padaryti naudodami branch filter komandą:

    git filter-branch --tree-filter 'rm -rf path/to/your/file' HEAD

    3
    06 апр. John Foley atsakymas, pateiktas 06 Bal 2017-04-06 02:28 '17 at 2:28 2017-04-06 02:28

    Naudokite „ Git Extensions“ - tai vartotojo sąsajos įrankis. Jame yra įskiepis, vadinamas „Rasti didelius failus“, kuriame saugomi failai saugyklose ir leidžia juos ištrinti.

    Nenaudokite „git filter-branch“ prieš naudodamiesi šiuo įrankiu, nes jis negalės rasti failų, ištrintų naudojant „filter-branch“ („Altough“ „filter-branch“) ne visiškai pašalina failus iš saugyklos paketo failų).

    1
    31 дек. Atsakymas pateikiamas Nir gruodžio 31 d. 2016-12-31 16:22 '17, 16:22 pm 2016-12-31 16:22

    Kai susiduriate su šia problema, git rm nepakaks, nes git prisimena, kad failas egzistavo vieną kartą mūsų istorijoje ir todėl bus nuoroda į jį.

    Kad padėtis dar blogiau, perkrovimas taip pat nėra lengvas, nes bet kokios nuorodos į blobą neleidžia valyti šiukšlių surinkėjui. Tai apima ištrintas nuorodas ir nuorodų nuorodas.

    Aš sukaupiau „ git forget-blob , šiek tiek scenarijų, kuris bando pašalinti visas šias nuorodas, ir tada naudoja „git filter-branch“, kad perrašytų kiekvieną filialo įsipareigojimą.

    Kai tik jūsų plyšys bus visiškai surastas, git gc atsikratys.

    Naudojant „ git forget-blob file-to-forget gana lengva. Daugiau informacijos galite rasti čia.

    https://ownyourbits.com/2017/01/18/completely-remove-a-file-from-a-git-repository-with-git-forget-blob/

    Aš kartu su ngn-wiki.ru ir kai kurių dienoraščių atsakymais jį sudėjau. Kreditai jiems!

    1
    23 янв. Atsakymą pateikė nachoparker, sausio 23 d 2017-01-23 15:21 '17 at 15:21 2017-01-23 15:21

    Iš esmės aš padariau tai, kas buvo šiame atsakyme: ngn-wiki.ru.site/questions/8976 / ...

    (už istoriją aš jį nukopijuosiu čia)

     $ git filter-branch --index-filter "git rm -rf --cached --ignore-unmatch YOURFILENAME" HEAD $ rm -rf .git/refs/original/ $ git reflog expire --all $ git gc --aggressive --prune $ git push origin master --force 

    Jis neveikė, nes tikrai norėčiau pervardyti ir perkelti daiktus. Todėl kai kurie dideli failai buvo aplankuose, kurie buvo pervadinti, ir manau, kad gc nepavyko pašalinti nuorodos į šiuos failus dėl to, kad tree objektuose rodoma nuoroda į šiuos failus. Mano galutinis sprendimas tikrai jį nužudyti buvo:

     # First, apply what in the answer linked in the front # and before doing the gc --prune --aggressive, do: # Go back at the origin of the repository git checkout -b newinit <sha1 of first commit> # Create a parallel initial commit git commit --amend # go back on the master branch that has big file # still referenced in history, even though # we thought we removed them. git checkout master # rebase on the newinit created earlier. By reapply patches, # it will really forget about the references to hidden big files. git rebase newinit # Do the previous part (checkout + rebase) for each branch # still connected to the original initial commit, # so we remove all the references. # Remove the .git/logs folder, also containing references # to commits that could make git gc not remove them. rm -rf .git/logs/ # Then you can do a garbage collection, # and the hidden files really will get gc'ed git gc --prune --aggressive 

    Mano repo ( .git ) pasikeitė nuo 32 MB iki 388 KB, kurią netgi filtro atšaka negali išvalyti.

    1
    05 июня '17 в 13:21 2017-06-05 13:21 atsakymas duotas Dolanor birželio 17 d. 17 val. 13:21 2017-06-05 13:21