Setup and Config
Getting and Creating Projects
Basic Snapshotting
Branching and Merging
Sharing and Updating Projects
Inspection and Comparison
Patching
Debugging
External Systems
Server Admin
Guides
- gitattributes
- Command-line interface conventions
- Everyday Git
- Frequently Asked Questions (FAQ)
- Glossary
- Hooks
- gitignore
- gitmodules
- Revisions
- Submodules
- Tutorial
- Workflows
- All guides...
Administration
Plumbing Commands
- 2.44.1 â 2.54.0 no changes
-
2.44.0
2024-02-23
- 2.29.3 â 2.43.7 no changes
-
2.29.2
2020-10-29
- 2.25.2 â 2.29.1 no changes
-
2.25.1
2020-02-17
-
2.25.0
2020-01-13
- 2.24.1 â 2.24.4 no changes
-
2.24.0
2019-11-04
- 2.22.1 â 2.23.4 no changes
-
2.22.0
2019-06-07
- 2.18.1 â 2.21.4 no changes
-
2.18.0
2018-06-21
- 2.16.6 â 2.17.6 no changes
-
2.15.4
2019-12-06
-
2.14.6
2019-12-06
-
2.13.7
2018-05-22
-
2.12.5
2017-09-22
- 2.10.5 â 2.11.4 no changes
-
2.9.5
2017-07-30
-
2.8.6
2017-07-30
- 2.3.10 â 2.7.6 no changes
-
2.2.3
2015-09-04
- 2.1.4 no changes
-
2.0.5
2014-12-17
SYNOPSIS
git filter-branch [--setup <kommando>] [--subdirectory-filter <katalog>] [--env-filter <kommando>] [--tree-filter <kommando>] [--index-filter <kommando>] [--parent-filter <kommando>] [--msg-filter <kommando>] [--commit-filter <kommando>] [--tag-name-filter <kommando>] [--prune-empty] [--original <namnrymd>] [-d <katalog>] [-f | --force] [--state-branch <gren>] [--] [<rev-list-alternativ>âŠâ]
VARNING
git filter-branch har mÄnga fallgropar som kan ge svÄrupptÀckta fel i den avsedda historikomskrivningen (och lÀmnar ofta lite tid för felsökning eftersom prestandan Àr mycket dÄlig). SÀkerhets- och prestandaproblemen gÄr inte att ÄtgÀrda bakÄtkompatibelt, och dÀrför rekommenderas inte verktyget. AnvÀnd i stÀllet ett alternativt verktyg för historikfiltrering, till exempel git filter-repo. Om git filter-branch ÀndÄ mÄste anvÀndas, lÀs noggrant SAFETY (och PRESTANDA) för att förstÄ riskerna, och undvik sedan sÄ mÄnga av de listade farorna som möjligt.
BESKRIVNING
Gör det möjligt att skriva om Gits revisionshistorik genom att skriva om grenarna som nÀmns i <rev-list-options> och tillÀmpa anpassade filter pÄ varje revision. Filtren kan modifiera varje trÀd (t.ex. ta bort en fil eller köra en perl-omskrivning pÄ alla filer) eller information om varje incheckning. Annars bevaras all information (inklusive ursprungliga incheckningstider och sammanslagningsinformation).
Kommandot skriver bara om de positiva referenser som nÀmns pÄ kommandoraden (t.ex. om a..b anges skrivs endast b om). Om inga filter anges kommer incheckningarna att checkas in igen utan nÄgra Àndringar, vilket normalt inte skulle ha nÄgon effekt. Detta kan ÀndÄ vara anvÀndbart i framtiden för att kompensera för vissa Git-programfel eller liknande, dÀrför Àr sÄdan anvÀndning tillÄten.
OBS: Kommandot respekterar filen .git/info/grafts och referenser i namnrymden refs/replace/. Om grafts eller ersÀttningsreferenser Àr definierade kommer körning av detta kommando att göra dem permanenta.
VARNING! Den omskrivna historiken kommer att ha olika objektnamn för alla objekt och kommer inte att konvergera med den ursprungliga grenen. Den omskrivna grenen kan inte enkelt pushas och distribueras ovanpĂ„ den ursprungliga grenen. Kommandot bör inte anvĂ€ndas om de fullstĂ€ndiga konsekvenserna inte Ă€r kĂ€nda, och det bör undvikas Ă€ndĂ„ om en enkel incheckning skulle rĂ€cka för att lösa problemet. (Se avsnittet "Ă TERSTĂLLA FRĂ N UPSTRĂMS-OMBASERING" i git-rebase[1] för mer information om att skriva om publicerad historik.)
Kontrollera alltid att den omskrivna versionen Àr korrekt: De ursprungliga referenserna, om de skiljer sig frÄn de omskrivna, kommer att lagras i namnrymden refs/original/.
Observera att eftersom den hÀr operationen Àr mycket I/O-intensiv, kan det vara en bra idé att omdirigera den temporÀra katalogen utanför-disken med alternativet -d, t.ex. pÄ tmpfs. Hastighetsökningen ska enligt uppgift vara mycket mÀrkbar.
Filter
Filtren tillÀmpas i den ordning som anges nedan. Argumentet <kommando> utvÀrderas alltid i shell-kontexten med hjÀlp av kommandot eval (med det anmÀrkningsvÀrda undantaget för incheckningsfiltret, av tekniska skÀl). Innan dess kommer miljövariabeln $GIT_COMMIT att stÀllas in för att innehÄlla ID:t för den incheckning som skrivs om. Dessutom tas GIT_AUTHOR_NAME, GIT_AUTHOR_EMAIL, GIT_AUTHOR_DATE, GIT_COMMITTER_NAME, GIT_COMMITTER_EMAIL och GIT_COMMITTER_DATE frÄn den aktuella incheckningen och exporteras till miljön för att pÄverka författar- och incheckare-identiteterna för den ersÀttningsincheckning som skapats av git-commit-tree[1] efter att filtren har körts.
Om nÄgon utvÀrdering av <kommando> returnerar en avslutningsstatus som inte Àr noll, kommer hela operationen att avbrytas.
En map-funktion Àr tillgÀnglig som tar argumentet "original sha1 id" och matar ut ett "rewritten sha1 id" om incheckningen redan har skrivits om, och annars "original sha1 id". map-funktionen kan returnera flera id:n pÄ separata rader om ditt inchecknings-filter genererade flera incheckningar.
ALTERNATIV
- --setup <kommando>
-
Det Àr inte ett riktigt filter som körs för varje incheckning utan en engÄngsinstÀllning precis före loopen. DÀrför Àr inga incheckningsspecifika variabler definierade Ànnu. Funktioner eller variabler som definieras hÀr kan anvÀndas eller modifieras i följande filtersteg förutom incheckningsfiltret, av tekniska skÀl.
- --subdirectory-filter <katalog>
-
Only look at the history which touches the given subdirectory. The result will contain that directory (and only that) as its project root. Implies Ommappa till förfader.
- --env-filter <kommando>
-
Filtret kan anvÀndas om bara miljön dÀr incheckningen ska utföras behöver Àndras. Mer specifikt kan det vara aktuellt att skriva om miljövariablerna för författare/incheckare-namn/e-postadress/tid (se git-commit-tree[1] för mer information).
- --tree-filter <kommando>
-
Det Àr filtret för att skriva om trÀdet och dess innehÄll. Argumentet utvÀrderas i skal med arbetskatalogen satt till roten av det utcheckade trÀdet. Det nya trÀdet anvÀnds sedan som det Àr (nya filer lÀggs till automatiskt, försvunna filer tas bort automatiskt - varken .gitignore-filer eller nÄgra andra ignoreringsregler HAR Nà GON EFFEKT!).
- --index-filter <kommando>
-
Det Àr filtret för att skriva om indexet. Det liknar trÀdfiltret men kontrollerar inte trÀdet, vilket gör det mycket snabbare. AnvÀnds ofta med
gitrm--cached--ignore-unmatch..., se EXEMPEL nedan. För svÄra fall, se git-update-index[1]. - --parent-filter <kommando>
-
Det Ă€r filtret för att skriva om incheckningens förĂ€ldralista. Den kommer att ta emot förĂ€ldrastrĂ€ngen pĂ„ stdin och ska mata ut den nya förĂ€ldrastrĂ€ngen pĂ„ stdout. FörĂ€ldrastrĂ€ngen har formatet som beskrivs i git-commit-tree[1]: tom för den initiala incheckningen, "-p parent" för en normal incheckning och "-p parent1 -p parent2 -p parent3 âŠâ" för en sammanslagningsincheckning.
- --msg-filter <kommando>
-
Det Àr filtret för att skriva om incheckningsmeddelandena. Argumentet utvÀrderas i skalet med det ursprungliga incheckningsmeddelandet som standardindata; dess standardutdata anvÀnds som det nya incheckningsmeddelandet.
- --commit-filter <kommando>
-
Det Ă€r filtret för att utföra incheckningen. Om detta filter anges kommer det att anropas i stĂ€llet för kommandot git commit-tree, med argument av formen "<TREE_ID> [(-p <PARENT_COMMIT_ID>)âŠâ]" och loggmeddelandet pĂ„ stdin. Incheckning-ID förvĂ€ntas pĂ„ stdout.
Som ett speciellt tillÀgg, kan incheckningsfiltret generera flera inchecknings-id:n; i sÄ fall kommer de omskrivna under-ID:na till den ursprungliga incheckningen att ha alla som förÀldrar.
Du kan anvÀnda bekvÀmlighetsfunktionen map i det hÀr filtret, och Àven andra bekvÀmlighetsfunktioner. Om du till exempel anropar skip_commit "$@" kommer den aktuella incheckningen att utelÀmnas (men inte dess Àndringar! Om du vill ha det, anvÀnd git rebase i stÀllet).
Du kan ocksÄ anvÀnda
git_commit_non_empty_tree"$@"i stÀllet förgitcommit-tree"$@"om du inte vill behÄlla incheckningar hos en enda förÀlder och det inte gör nÄgon Àndring av trÀdet. - --tag-name-filter <kommando>
-
Det Àr filtret för att skriva om taggnamn. NÀr det skickas kommer det att anropas för varje taggreferens som pekar pÄ ett omskrivet objekt (eller pÄ ett taggobjekt som pekar pÄ ett omskrivet objekt). Det ursprungliga taggnamnet skickas via standardindata, och det nya taggnamnet förvÀntas pÄ standardutdata.
De ursprungliga taggarna tas inte bort, men kan skrivas över; anvÀnd "--tag-name-filter cat" för att helt enkelt uppdatera taggarna. Var i det hÀr fallet mycket försiktig och se till att du har sÀkerhetskopierat de gamla taggarna ifall konverteringen skulle misslyckas.
NÀstan korrekt omskrivning av taggobjekt stöds. Om taggen har ett bifogat meddelande skapas ett nytt taggobjekt med samma meddelande, författare och tidsstÀmpel. Om taggen har en signatur bifogad, tas signaturen bort. Det Àr per definition omöjligt att bevara signaturer. Anledningen till att detta Àr "nÀstan" korrekt, Àr att om taggen helst inte Àndras (pekar pÄ samma objekt, har samma namn, etc.) borde den behÄlla eventuella signaturer. SÄ Àr inte fallet, signaturer kommer alltid att tas bort, anvÀndning pÄ egen risk. Det finns inte heller stöd för att Àndra författare eller tidsstÀmpel (eller taggmeddelandet för den delen). Taggar som pekar pÄ andra taggar kommer att skrivas om för att peka pÄ den underliggande incheckning.
- --prune-empty
-
Vissa filter genererar tomma incheckningar som lÀmnar trÀdet orört. Flaggan instruerar git-filter-branch att ta bort sÄdana incheckningar om de har exakt en eller noll icke-beskÀrda förÀldrar; sammanslagningsincheckningar kommer dÀrför att förbli intakta. Flaggan kan inte anvÀndas tillsammans med
--commit-filter, Àven om samma effekt kan uppnÄs genom att anvÀnda den angivna funktionengit_commit_non_empty_treei ett incheckningsfilter. - --original <namn-utrymme>
-
AnvÀnd det hÀr alternativet för att ange namnrymden dÀr de ursprungliga incheckningar ska lagras. StandardvÀrdet Àr refs/original.
- -d <katalog>
-
AnvÀnd det hÀr alternativet för att ange sökvÀgen till den temporÀra katalogen som anvÀnds för omskrivning. NÀr ett trÀdfilter tillÀmpas mÄste kommandot tillfÀlligt checka ut trÀdet till nÄgon katalog, vilket kan ta upp avsevÀrt utrymme vid stora projekt. Som standard görs detta i katalogen
.git-rewrite/, men du kan ÄsidosÀtta det valet med den hÀr parametern. - -f
- --force
-
git filter-branch vÀgrar att starta med en befintlig temporÀr katalog eller nÀr det redan finns referenser som börjar med refs/original/, om inte tvingad.
- --state-branch <gren>
-
Det hÀr alternativet gör att mappningen frÄn gamla till nya objekt laddas frÄn den namngivna grenen vid start och sparas som en ny incheckning till den grenen vid avslutning, vilket möjliggör stegvis administration av stora trÀd. Om <gren> inte finns kommer den att skapas.
- <rev-list alternativ>âŠâ
-
Arguments for git rev-list. All positive refs included by these options are rewritten. You may also specify options such as
--all, but you must use--to separate them from the git filter-branch options. Implies Ommappa till förfader.
Ommappa till förfader
Genom att anvÀnda argument i git-rev-list[1], t.ex. sökvÀgsbegrÀnsare, kan du begrÀnsa mÀngden revisioner som skrivs om. Positiva referenser pÄ kommandoraden sÀrskiljs dock: vi lÄter dem inte exkluderas av sÄdana begrÀnsare. För detta ÀndamÄl skrivs de i stÀllet om för att peka pÄ den nÀrmaste förfadern som inte exkluderades.
UTGĂ NGSSTATUS
Vid lyckat resultat, Àr avslutningsstatusen 0. Om filtret inte hittar nÄgra incheckningar att skriva om Àr avslutningsstatusen 2. Vid alla andra fel kan avslutningsstatusen vara vilket annat vÀrde som helst som inte Àr noll.
EXEMPEL
Anta att du vill ta bort en fil (som innehÄller konfidentiell information eller upphovsrÀttsintrÄng) frÄn alla incheckningar:
git filter-branch --tree-filter 'rm filename' HEAD
DÀremot, om filen saknas i trÀdet för nÄgon incheckning, kommer ett enkelt rm filename att misslyckas för det trÀdet och incheckningen. DÀrför kan du i stÀllet vilja anvÀnda rm -f filename som skript.
Att anvÀnda --index-filter med git rm ger en betydligt snabbare version. Precis som med rm filename kommer git rm --cached filename att misslyckas om filen saknas i trÀdet för en incheckning. Om du vill "glömma bort" en fil helt spelar det ingen roll nÀr den gick in i historiken, sÄ vi lÀgger ocksÄ till --ignore-unmatch:
git filter-branch --index-filter 'git rm --cached --ignore-unmatch filename' HEAD
Nu, fÄr du den omskrivna historiken sparad i HEAD.
För att skriva om kodförrÄdet sÄ att det ser ut som om foodir/ hade varit dess projektrot och ta bort all annan historik:
git filter-branch --subdirectory-filter foodir -- --all
SÄledes kan du t.ex. göra om en biblioteksunderkatalog till ett eget kodförrÄd. Observera -- som separerar filter-branch-alternativ frÄn revisionsalternativ, och --all för att skriva om alla grenar och taggar.
För att stÀlla in en incheckning (som vanligtvis ligger i början av en annan historik) som förÀlder till den aktuella initiala incheckningen, för att klistra in den andra historiken bakom den aktuella historiken:
git filter-branch --parent-filter 'sed "s/^\$/-p <graft-id>/"' HEAD
(om förĂ€lderstrĂ€ngen Ă€r tom â vilket hĂ€nder nĂ€r vi har att göra med den initiala incheckningen â lĂ€gg till graftincheckning som förĂ€lder). Observera att detta förutsĂ€tter historik med en enda rot (det vill sĂ€ga att ingen sammanslagning utan gemensamma förfĂ€der har skett). Om sĂ„ inte Ă€r fallet, anvĂ€nd:
git filter-branch --parent-filter \ 'test $GIT_COMMIT = <commit-id> && echo "-p <graft-id>" || cat' HEAD
eller Ànnu enklare:
git replace --graft $commit-id $graft-id git filter-branch $graft-id..HEAD
För att ta bort incheckningar skrivna av "Darl McBride" frÄn historiken:
git filter-branch --commit-filter ' if [ "$GIT_AUTHOR_NAME" = "Darl McBribe" ]; then skip_commit "$@"; else git commit-tree "$@"; fi' HEAD
Funktionen skip_commit definieras enligt följande:
skip_commit()
{
shift;
while [ -n "$1" ];
do
shift;
map "$1";
shift;
done;
}
Shift-magin kastar först bort trÀd-idn och sedan -p parametrarna. Observera att detta hanterar sammanslagningar korrekt! Om Darl genomförde en sammanslagning mellan P1 och P2 kommer den att propageras korrekt och alla underordnade attribut till sammanslagningen blir sammanslagningsincheckningar med P1 och P2 som sina förÀldrar i stÀllet för med sammanslagningsincheckningen som förÀlder.
OBS Àndringarna som introduceras av incheckningar, och som inte ÄterstÀlls av efterföljande incheckningar, kommer fortfarande att finnas i den omskrivna grenen. Om förÀndringar ocksÄ ska slÀngas tillsammans med incheckningar, bör det interaktiva lÀget i git rebase anvÀndas.
Incheckningsloggmeddelandena kan skrivas om med hjÀlp av --msg-filter. Till exempel kan git svn-id-strÀngar i ett kodförrÄd skapat av git svn tas bort pÄ följande sÀtt:
git filter-branch --msg-filter ' sed -e "/^git-svn-id:/d" '
Om Acked-by-rader behöver lÀggas till i, sÀg, de sista 10 incheckningarna (av vilka ingen Àr en sammanslagning), anvÀnd kommandot:
git filter-branch --msg-filter ' cat && echo "Acked-by: Bugs Bunny <bunny@bugzilla.org>" ' HEAD~10..HEAD
Alternativet --env-filter kan anvÀndas för att Àndra incheckare- och/eller författaridentitet. Om du till exempel upptÀcker att dina incheckningar har fel identitet pÄ grund av en felkonfigurerad user.email, kan du göra en korrigering innan du publicerar projektet, sÄ hÀr:
git filter-branch --env-filter ' if test "$GIT_AUTHOR_EMAIL" = "root@localhost" then GIT_AUTHOR_EMAIL=john@example.com fi if test "$GIT_COMMITTER_EMAIL" = "root@localhost" then GIT_COMMITTER_EMAIL=john@example.com fi ' -- --all
För att begrÀnsa omskrivningen till endast en del av historiken, ange ett revisionsintervall utöver det nya grennamnet. Det nya grennamnet kommer att peka pÄ den översta revisionen som en git rev-list för detta intervall kommer att skriva ut.
Beakta pÄ denna historia:
D--E--F--G--H
/ /
A--B-----C
För att bara skriva om incheckningar D, E, F, G, H, men lÀmna A, B och C oberörda, anvÀnd:
git filter-branch ... C..H
För att skriva om incheckningar E, F, G, H, anvÀnd en av dessa:
git filter-branch ... C..H --not D git filter-branch ... D..H --not C
För att flytta hela trÀdet till en underkatalog, eller ta bort det dÀrifrÄn:
git filter-branch --index-filter \ 'git ls-files -s | sed "s-\t\"*-&newsubdir/-" | GIT_INDEX_FILE=$GIT_INDEX_FILE.new \ git update-index --index-info && mv "$GIT_INDEX_FILE.new" "$GIT_INDEX_FILE"' HEAD
CHECKLISTA FĂR ATT KRYMPA ETT KODFĂRRĂ D
git-filter-branch kan anvÀndas för att bli av med en delmÀngd av filer, vanligtvis med nÄgon kombination av --index-filter och --subdirectory-filter. Folk förvÀntar sig att det resulterande kodförrÄdet ska vara mindre Àn originalet, men du behöver nÄgra fler steg för att faktiskt göra det mindre, eftersom Git försöker hÄrt att inte förlora dina objekt förrÀn du sÀger Ät det att göra det. Se först till att:
-
Du tog verkligen bort alla varianter av ett filnamn om en blob flyttades under sin livstid.
gitlog--name-only--follow--all--filenamekan hjÀlpa dig att hitta namnbyten. -
Du filtrerade verkligen alla referenser: anvÀnd
--tag-name-filtercat----allnÀr du anropar git-filter-branch.
Sedan finns det tvÄ sÀtt att fÄ ett mindre kodförrÄd. Ett sÀkrare sÀtt Àr att klona, vilket behÄller originalet intakt.
-
Klona den med git clone file:///sökvÀg/till/kodförrÄd. Klonen kommer inte att ha de borttagna objekten. Se git-clone[1]. (Observera att kloning med en vanlig sökvÀg bara hÄrdlÀnkar allt!)
Om du verkligen inte vill klona den, oavsett anledning, kontrollera följande punkter i stÀllet (i denna ordning). Detta Àr en mycket destruktiv metod, sÄ gör en sÀkerhetskopia eller ÄtergÄ till att klona den. Du har blivit varnad.
-
Ta bort de ursprungliga referenserna som sÀkerhetskopieras av git-filter-branch: sÀg
gitfor-each-ref--format="%(refname)"refs/original/|xargs-n1gitupdate-ref-d. -
LÄt alla referensloggar upphöra med
gitreflogexpire--expire=now--all. -
SkrÀpsamla alla orefererade objekt med
gitgc--prune=now(eller om din git-gc inte Àr tillrÀckligt ny för att stödja argument till--prune, anvÀnd git repack -ad; git prune i stÀllet).
PRESTANDA
Prestandan för git-filter-branch Àr glacialt lÄngsam; dess design gör det omöjligt för en bakÄtkompatibel implementering att nÄgonsin vara snabb:
-
Vid redigering av filer kontrollerar git-filter-branch avsiktligt varje incheckning som den fanns i det ursprungliga kodförrÄdet. Om ett kodförrÄd har
10^5filer och10^5incheckningar, men varje incheckning bara modifierar fem filer, kommer git-filter-branch att krÀva10^10modifieringar, trots att det bara finns (högst)5*10^5unika blobbar. -
Om du försöker fuska och försöker fÄ git-filter-branch att bara fungera pÄ filer som modifierats i en incheckning, sÄ hÀnder tvÄ saker
-
problem uppstÄr med borttagningar nÀr anvÀndaren helt enkelt försöker byta namn pÄ filer (eftersom det verkar vara en icke-operation att försöka ta bort filer som inte finns; det krÀvs en del trick för att mappa om borttagningar över filnamn nÀr omdöpningarna sker via godtyckliga anvÀndardefinierade skal)
-
Àven om du lyckas med map-deletes-for-renames-chikanen, bryter du fortfarande tekniskt sett mot bakÄtkompatibilitet eftersom anvÀndare tillÄts filtrera filer pÄ sÀtt som beror pÄ incheckningarnas topologi i stÀllet för att filtrera enbart baserat pÄ filinnehÄll eller namn (Àven om detta inte har observerats i verkligheten).
-
-
Ăven om det inte finns behov av att redigera filer utan bara att t.ex. byta namn pĂ„ eller ta bort nĂ„gra och dĂ€rmed undvika att checka ut varje fil (dvs. --index-filter kan anvĂ€ndas), skickas fortfarande skalkodsnuttar för filtren. Det betyder att det för varje incheckning mĂ„ste finnas ett förberett Git-kodförrĂ„d dĂ€r filtren kan köras. Det Ă€r en omfattande förberedelse.
-
Dessutom, skapas eller uppdateras flera ytterligare filer per incheckning av git-filter-branch. NÄgra av dessa Àr till för att stödja de bekvÀmlighetsfunktioner som tillhandahÄlls av git-filter-branch (som map()), medan andra Àr till för att hÄlla reda pÄ internt tillstÄnd (men kunde ocksÄ ha nÄts av anvÀndarfilter; ett av git-filter-branchs regressionstester gör det). Detta innebÀr i huvudsak att man anvÀnder filsystemet som en IPC-mekanism mellan git-filter-branch och de anvÀndardefinierade filtren. Diskar tenderar att vara en lÄngsam IPC-mekanism, och att skriva dessa filer representerar ocksÄ effektivt en pÄtvingad synkroniseringspunkt mellan separata processer som vi trÀffar vid varje incheckning.
-
De anvÀndardefinierade skal-kommandona kommer sannolikt att involvera en pipeline av kommandon, vilket resulterar i att mÄnga processer per incheckning skapas. Att skapa och köra en annan process tar en mycket varierande tid mellan operativsystem, men pÄ alla plattformar Àr det mycket lÄngsamt i förhÄllande till att anropa en funktion.
-
SjÀlva git-filter-branch Àr skrivet i skal (sh), vilket Àr ganska lÄngsamt. Detta Àr det enda prestandaproblemet som skulle kunna ÄtgÀrdas bakÄtkompatibelt, men jÀmfört med ovanstÄende problem som Àr inneboende i designen av git-filter-branch, Àr sjÀlva verktygets sprÄk ett relativt litet problem.
-
Sidoanteckning: TyvÀrr tenderar folk att fixera sig vid det som Àr skrivet i skalet och frÄgar regelbundet om git-filter-branch kan skrivas om till ett annat sprÄk för att ÄtgÀrda prestandaproblemen. Det ignorerar inte bara de större inneboende problemen med designen, det skulle ocksÄ hjÀlpa mindre Àn man skulle kunna förvÀnta sig: om git-filter-branch i sig inte vore skal, skulle bekvÀmlighetsfunktionerna (map(), skip_commit(), etc.) och argumentet
--setupinte lÀngre kunna köras en gÄng i början av programmet utan skulle i stÀllet behöva lÀggas till i varje anvÀndarfilter (och dÀrmed köras om med varje incheckning).
-
Verktyget git filter-repo Àr ett alternativ till git-filter-branch som inte har sÄdana prestanda- eller sÀkerhetsproblem (se nedan). För den som redan har verktygskedjor som bygger pÄ git-filter-branch erbjuder git filter-repo Àven filter-lamely, en drop-in-ersÀttning för git-filter-branch (med vissa förbehÄll). filter-lamely har samma sÀkerhetsproblem som git-filter-branch, men förbÀttrar Ätminstone prestandan nÄgot.
SAFETY
git-filter-branch Àr full av missöden, vilket resulterar i olika sÀtt att enkelt korrumpera kodförrÄd eller sluta med en röra som Àr vÀrre Àn vad du började med:
-
NÄgon kan ha en uppsÀttning "fungerande och testade filter" som de dokumenterar eller tillhandahÄller till en kollega, som sedan kör dem pÄ ett annat operativsystem dÀr samma kommandon inte fungerar/testas (nÄgra exempel pÄ git-filter-branch manualsidan pÄverkas ocksÄ av detta). Skillnader mellan BSD och GNU-anvÀndarland kan verkligen bita. Med tur dyker felmeddelanden upp. Men lika troligt Àr det att kommandona antingen inte utför den filtrering som begÀrs, eller sÄ korrumperar de tyst genom att göra nÄgon oönskad Àndring. Den oönskade Àndringen kan bara pÄverka ett fÄtal incheckningar, sÄ det Àr inte nödvÀndigtvis uppenbart heller. (Det faktum att problem inte nödvÀndigtvis Àr uppenbara innebÀr att de sannolikt kommer att gÄ obemÀrkta förbi förrÀn den omskrivna historiken har anvÀnts ett bra tag, och dÄ Àr det verkligen svÄrt att rÀttfÀrdiga ytterligare en flaggdag för ytterligare en omskrivning.)
-
Filnamn med mellanslag hanteras ofta fel av shell-kodavsnitt eftersom de orsakar problem för shell-pipelines. Inte alla Ă€r bekanta med find -print0, xargs -0, git-ls-files -z, etc. Ăven personer som Ă€r bekanta med dem kan anta att sĂ„dana flaggor inte Ă€r relevanta eftersom nĂ„gon annan döpte om sĂ„dana filer i sitt kodförrĂ„d innan personen som utförde filtreringen gick med i projektet. Och ofta kanske inte ens de som Ă€r bekanta med att hantera argument med mellanslag gör det bara för att de inte Ă€r i tankesĂ€ttet att tĂ€nka pĂ„ allt som kan gĂ„ fel.
-
Filnamn som inte Àr ascii kan tas bort i tysthet trots att de finns i en önskad katalog. Att bara behÄlla önskade sökvÀgar görs ofta med hjÀlp av pipelines som
gitls-files|grep-v^WANTED_DIR/|xargsgitrm. ls-files citerar bara filnamn om det behövs, sÄ folk kanske inte mÀrker att en av filerna inte matchade regex (Ätminstone inte förrÀn det Àr alldeles för sent). Ja, nÄgon som kÀnner till core.quotePath kan undvika detta (sÄvida de inte har andra specialtecken som \t, \n eller "), och personer som anvÀnder ls-files -z med nÄgot annat Àn grep kan undvika detta, men det betyder inte att de kommer att göra det. -
PÄ liknande sÀtt, nÀr man flyttar filer, kan man upptÀcka att filnamn med tecken som icke-ascii eller specialtecken hamnar i en annan katalog, en som innehÄller ett dubbelt citattecken. (Detta Àr tekniskt sett samma problem som ovan med citattecken, men kanske ett intressant annorlunda sÀtt som det kan och har manifesterats som ett problem.)
-
Det Àr alldeles för lÀtt att av misstag blanda ihop gammal och ny historik. Det Àr fortfarande möjligt med vilket verktyg som helst, men git-filter-branch inbjuder nÀstan till det. Om man har tur Àr den enda nackdelen att anvÀndarna blir frustrerade över att de inte vet hur de ska krympa sitt kodförrÄd och ta bort det gamla. Om de har otur slÄr de ihop gammal och ny historik och fÄr flera "kopior" av varje incheckning, av vilka vissa innehÄller oönskade eller kÀnsliga filer och andra inte. Detta sker pÄ flera olika sÀtt:
-
standardinstÀllningen Àr att bara göra en partiell omskrivning av historiken (--all Àr inte standardinstÀllningen och fÄ exempel visar det)
-
det faktum att det inte finns nÄgon automatisk rengöring efter körning
-
det faktum att --tag-name-filter (nÀr det anvÀnds för att byta namn pÄ taggar) inte tar bort de gamla taggarna utan bara lÀgger till nya med det nya namnet
-
det faktum att vÀldigt lite vÀgledande information ges för att hjÀlpa anvÀndare att förstÄ följderna av en omskrivning och hur man undviker att blanda gammal och ny historik. Manualsidan beskriver till exempel att anvÀndare behöver förstÄ att de mÄste ombasera sina Àndringar pÄ alla sina grenar ovanpÄ den nya historiken (eller ta bort och klona om), men det Àr bara en av flera aspekter att ta hÀnsyn till. Se avsnittet "DISCUSSION" i manualen för git filter-repo för mer detaljer.
-
-
Annoterade taggar kan av misstag konverteras till lÀttviktstaggar pÄ grund av ett av tvÄ problem:
-
NÄgon kan skriva om historiken, inse att de har gjort fel, ÄterstÀlla frÄn sÀkerhetskopiorna i refs/original/ och sedan göra om sitt git-filter-branch-kommando. (SÀkerhetskopieringen i refs/original/ Àr inte en riktig sÀkerhetskopia; den avreferenserar taggar först.)
-
Kör git-filter-branch med antingen --tags eller --all i din <rev-list-alternativ>. För att behÄlla kommenterade taggar som kommenterade mÄste du anvÀnda --tag-name-filter (och fÄr inte ha ÄterstÀllt frÄn refs/original/ i en tidigare misslyckad omskrivning).
-
-
Alla incheckningsmeddelanden som anger en kodning kommer att bli korrupta av omskrivningen; git-filter-branch ignorerar kodningen, tar de ursprungliga bytena och matar den till commit-tree utan att ange rÀtt kodning. (Detta hÀnder oavsett om --msg-filter anvÀnds eller inte.)
-
Incheckningsmeddelanden (Ă€ven om de alla Ă€r i UTF-8) blir som standard korrupta pĂ„ grund av att de inte uppdaterasâââalla referenser till andra incheckningshashar i incheckningsmeddelanden kommer nu att referera till incheckningar som inte lĂ€ngre finns.
-
Det finns inga funktioner som hjÀlper anvÀndare att hitta vilket oönskat skrÀp de ska ta bort, vilket innebÀr att de Àr mycket mer benÀgna att ha ofullstÀndiga eller partiella rensningar som ibland leder till förvirring och att folk slösar tid pÄ att försöka förstÄ. (Till exempel tenderar folk att bara leta efter stora filer att ta bort i stÀllet för stora kataloger eller tillÀgg, och nÀr de vÀl gör det, kommer personer som anvÀnder det nya kodförrÄdet och gÄr igenom historiken nÄgon gÄng senare att mÀrka en katalog för bygg-artefakter som innehÄller vissa filer men inte andra, eller en cache av beroenden (node_modules eller liknande) som aldrig kunde ha fungerat eftersom den saknar vissa filer.)
-
Om --prune-empty inte anges kan filtreringsprocessen skapa massor av förvirrande tomma incheckningar
-
Om --prune-empty anges, sÄ beskÀrs Àven avsiktligt placerade tomma incheckningar frÄn tiden före filtreringsÄtgÀrden, i stÀllet för att bara beskÀra incheckningar som blev tomma pÄ grund av filtreringsregler.
-
Om --prune-empty anges, missas ibland tomma incheckningar och lĂ€mnas kvar Ă€ndĂ„ (ett nĂ„got ovanligt programfel, men det hĂ€nderâŠâ)
-
Ett mindre problem, men anvÀndare som har som mÄl att uppdatera alla namn och e-postadresser i ett förar kan ledas till --env-filter som bara uppdaterar författare och incheckare, och saknar taggare.
-
Om anvÀndaren anger ett --tag-name-filter som mappar flera taggar till samma namn, visas ingen varning eller fel; git-filter-branch skriver helt enkelt över varje tagg i nÄgon odokumenterad fördefinierad ordning vilket resulterar i endast en tagg i slutet. (Ett regressionstest av git-filter-branch krÀver detta överraskande beteende.)
Dessutom, leder den dÄliga prestandan hos git-filter-branch ofta till sÀkerhetsproblem:
-
Att komma pĂ„ rĂ€tt shell-kodsavsnitt för att utföra den filtrering man vill ha Ă€r ibland svĂ„rt om man inte bara gör en trivial modifiering, som att ta bort ett par filer. TyvĂ€rr lĂ€r sig folk ofta om kodavsnittet Ă€r rĂ€tt eller fel genom att prova sig fram, men om det Ă€r rĂ€tt eller fel kan variera beroende pĂ„ speciella omstĂ€ndigheter (mellanslag i filnamn, non-ascii filnamn, roliga författarnamn eller e-postadresser, ogiltiga tidszoner, förekomst av grafts eller ersĂ€ttningsobjekt, etc.), vilket innebĂ€r att de kan behöva vĂ€nta lĂ€nge, stöta pĂ„ ett fel och sedan starta om. Prestandan för git-filter-branch Ă€r sĂ„ dĂ„lig att denna cykel Ă€r smĂ€rtsam, vilket minskar tiden som finns tillgĂ€nglig för att noggrant kontrollera om (för att inte tala om vad det gör med tĂ„lamodet hos den person som gör omskrivningen Ă€ven om de tekniskt sett har mer tid tillgĂ€nglig). Detta problem förvĂ€rras ytterligare eftersom fel frĂ„n trasiga filter kanske inte visas pĂ„ lĂ€nge och/eller gĂ„r vilse i ett hav av utdata. Ănnu vĂ€rre Ă€r att trasiga filter ofta bara resulterar i tysta felaktiga omskrivningar.
-
Som grÀdde pÄ moset, Àven nÀr anvÀndare Àntligen hittar fungerande kommandon, vill de naturligtvis dela med sig av dem. Men de kanske inte Àr medvetna om att deras kodförrÄd inte hade vissa specialfall som nÄgon annans har. SÄ nÀr nÄgon annan med ett annat kodförrÄd kör samma kommandon, drabbas de av problemen ovan. Eller sÄ kör anvÀndaren bara kommandon som egentligen granskades för specialfall, men de kör dem pÄ ett annat operativsystem dÀr det inte fungerar, som nÀmnts ovan.
GIT
En del av git[1]-sviten