Hur tar man bort "Large Files" från en Git Commit?

Permalänk

Hur tar man bort "Large Files" från en Git Commit?

Jag råkade göra en commit på en stor fil över 100 Mb på min Git. Aj då! Då fick jag en varning.
Då testade jag lägga till en .gitignore och lägga till min fil där i, hos Github.com. Sedan gjorde jag en pull.

Okej! Då tänkte jag att detta löser problemet. Nej, det gjorde det inte. Jaha, jag testar Git LFS - Large File Storage. Men problemet är att jag redan har gjort min commit redan.

Hur får jag bort den? Jag har totalt 8 stycken commits, på grund utav att jag har testat och exprimenterat hur jag updatera min GitHub. Jag verkar inte kunna ta bort några commits. Så hur löser jag detta problem?

Jag har kollat på Youtube där man kan lägga till en squash och rebase, men inget av dessa fungerar....för min commit är redan 8 commits borta.

Permalänk
Medlem

Commits som är pushade ändrar du inte på. Det finns sätt att förstöra historiken men hela vitsen med Git är att den ska vara oföränderlig så allt sådant ska bara användas i absolut nödfall.

Permalänk
Skrivet av MrPasty:

Commits som är pushade ändrar du inte på. Det finns sätt att förstöra historiken men hela vitsen med Git är att den ska vara oföränderlig så allt sådant ska bara användas i absolut nödfall.

Jag misstänker detta. På något sätt måste jag kunna säga åt min commit att undvika en stor fil?

Permalänk
Medlem

Vill du bara ta bort stora filen från git repot så kan du köra såhär:

git rm --cached hugefile.txt
git commit -m "Remove large file from repository"
git push origin master

.gitignore hjälper bara till om du inte har commitat själva filen. På detta viset så hålls historiken kvar på allt du gjort, dvs dina 8 commits. Det går att rensa filen och all historik men det är en större huvudvärk.

Visa signatur

Jobbdator: Macbook Pro 16" | M1 Pro | 32GB RAM | 1TB Lagring

Permalänk
Medlem
Skrivet av heretic16:

Jag misstänker detta. På något sätt måste jag kunna säga åt min commit att undvika en stor fil?

Jag skulle säga att enklaste sättet är att organisera sina filer snyggt så att allt som inte ska versionshanteras ligger i andra kataloger än de som hanteras av Git.

Permalänk

Jag löste problemet!

https://docs.github.com/en/authentication/keeping-your-accoun...

java -jar bfg --delete-files YOUR-FILE-WITH-SENSITIVE-DATA

GitHub måste verkligen lägga till en funktion som utför detta. Man ska inte behöva ladda ned något "hack" och "trix" för att få till sådant

Permalänk
Medlem
Skrivet av heretic16:

Jag löste problemet!

https://docs.github.com/en/authentication/keeping-your-accoun...

java -jar bfg --delete-files YOUR-FILE-WITH-SENSITIVE-DATA

GitHub måste verkligen lägga till en funktion som utför detta. Man ska inte behöva ladda ned något "hack" och "trix" för att få till sådant

Det finns flera sätt att göra det med gits inbyggda funktioner, men alla kommer skriva över historiken som flera nämnt ovan.
Github måste verkligen inte fixa något alls, du borde lära dig att inte commita filer du inte vill ha i repot.

Permalänk
Medlem
Skrivet av heretic16:

Jag löste problemet!

https://docs.github.com/en/authentication/keeping-your-accoun...

java -jar bfg --delete-files YOUR-FILE-WITH-SENSITIVE-DATA

GitHub måste verkligen lägga till en funktion som utför detta. Man ska inte behöva ladda ned något "hack" och "trix" för att få till sådant

Rekommenderar att ta ansvar för egna misstag snarare att peka mot andra. Det kommer hjälpa dig i livet.

Permalänk
Medlem
Skrivet av heretic16:

GitHub måste verkligen lägga till en funktion som utför detta. Man ska inte behöva ladda ned något "hack" och "trix" för att få till sådant

Nej, du borde lära dig hur Git fungerar. Är det datalagring du är ute efter så ska du inte använda ett versionshanteringssystem.

Permalänk
Skrivet av izzie:

Rekommenderar att ta ansvar för egna misstag snarare att peka mot andra. Det kommer hjälpa dig i livet.

Ursäkta? Vad är det för kommentar?
Detta är min egen repo på Github.

Skrivet av MrPasty:

Nej, du borde lära dig hur Git fungerar. Är det datalagring du är ute efter så ska du inte använda ett versionshanteringssystem.

Jag använder Visual Studio Community, som har inbyggt Git. Jag använder bara Github som mitt egna moln. Där slänger jag upp massa saker som jag kan plocka ned vid behov.

Skrivet av Xcorp:

Det finns flera sätt att göra det med gits inbyggda funktioner, men alla kommer skriva över historiken som flera nämnt ovan.
Github måste verkligen inte fixa något alls, du borde lära dig att inte commita filer du inte vill ha i repot.

När jag skickar upp saker, så skickar jag upp allt. Det är bara jag som använder det ändå så.

Permalänk
Medlem
Skrivet av heretic16:

Ursäkta? Vad är det för kommentar?
Detta är min egen repo på Github.

Jag använder Visual Studio Community, som har inbyggt Git. Jag använder bara Github som mitt egna moln. Där slänger jag upp massa saker som jag kan plocka ned vid behov.

När jag skickar upp saker, så skickar jag upp allt. Det är bara jag som använder det ändå så.

Du säger att Github bör åtgärda dina personliga problem du själv har skapat genom felaktig användning av tjänsten:

Skrivet av heretic16:

GitHub måste verkligen lägga till en funktion som utför detta. Man ska inte behöva ladda ned något "hack" och "trix" för att få till sådant

Dessutom:
Är det ett personligt repo kan du väl göra vad du vill inom tjänsten användarvillkor. Men om du jobbar med fler utvecklare kommer de inte bli särskilt glada om du börjar fucka med versionshistoriken. Bättre att lära sig rätt från början.

Permalänk
Medlem
Skrivet av heretic16:

När jag skickar upp saker, så skickar jag upp allt. Det är bara jag som använder det ändå så.

Om du insisterar på att vara slarvig med hur du använder git så får du acceptera att problem uppstår som det du startade den här tråden för.

git (och andra versionshanteringssystem) är gjorda så att man normalt inte skall kunna helt ta bort något som checkats in. Så om man inte har oändligt med utrymme och nätverksbandbredd så får man lära sig att inte checka in skräpfiler som inte hör hemma där.

Permalänk
Medlem

Ingen har sagt det explicit, men jag slår ändå ett slag för att Git och GitHub sannerligen inte är samma sak. Nybörjare tenderar att missa detta, eller åtminstone slarva med definitionerna, har jag märkt.

Permalänk
Hedersmedlem

Jag klickade mig in på denna just för att tipsa om BFG men jag såg att TS hittat det själv redan. Github själva rekommenderar just detta verktyg. Jag hittade själv verktyget, när jag behövde det för ett par månader sedan p.g.a. en liknande tabbe, från en av deras hjälpartiklar när jag gjort samma sak. Visst kan man ha synpunkten att Github borde ha ett ännu enklare sätt att fixa detta, men det är inte ett krav på något sätt, när det finns en fungerande lösning som är lätt att använda, som dessutom funkar för alla Git-repos, inte bara de på Github.

Men jag tycker det är en väldigt märklig inställning här i tråden att hoppa på TS. Han har gjort ett misstag, men istället för att visa honom till en lösning så sätter man sig istället på höga hästar och pratar om att "man inte ska göra så", eller att det är "omöjligt". Jag vet inte om det är okunskap eller arrogant. Det är klart att det finns en lösning, och det är klart att det finns nackdelar med denna, men det finns stora nackdelar med att ha ett gitrepo som är för stort också. Vad ska TS göra istället menar ni andra som moraliserar? Börja om på ett nytt repo? Det löser ju inget...

Det är lite som om någon skulle komma in på ett bilforum efter att ha råkat få buckla en panel på bilen och sedan få till svar att "lol lär sig parkera bättre din noob". Det löser liksom inte problemet.

Permalänk
Medlem
Skrivet av pv2b:

Jag klickade mig in på denna just för att tipsa om BFG men jag såg att TS hittat det själv redan. Github själva rekommenderar just detta verktyg. Jag hittade själv verktyget, när jag behövde det för ett par månader sedan p.g.a. en liknande tabbe, från en av deras hjälpartiklar när jag gjort samma sak. Visst kan man ha synpunkten att Github borde ha ett ännu enklare sätt att fixa detta, men det är inte ett krav på något sätt, när det finns en fungerande lösning som är lätt att använda, som dessutom funkar för alla Git-repos, inte bara de på Github.

Men jag tycker det är en väldigt märklig inställning här i tråden att hoppa på TS. Han har gjort ett misstag, men istället för att visa honom till en lösning så sätter man sig istället på höga hästar och pratar om att "man inte ska göra så", eller att det är "omöjligt". Jag vet inte om det är okunskap eller arrogant. Det är klart att det finns en lösning, och det är klart att det finns nackdelar med denna, men det finns stora nackdelar med att ha ett gitrepo som är för stort också. Vad ska TS göra istället menar ni andra som moraliserar? Börja om på ett nytt repo? Det löser ju inget...

Det är lite som om någon skulle komma in på ett bilforum efter att ha råkat få buckla en panel på bilen och sedan få till svar att "lol lär sig parkera bättre din noob". Det löser liksom inte problemet.

Detta är något jag tyvärr märkt i flera trådar på sistone.

Det blir vanligare och vanligare att istället för att hjälpa någon så blir den som råkat göra något galet påhoppad och nästan mobbad istället.

Det är en utveckling jag verkligen inte gillar

Visa signatur
Permalänk
Medlem

Svaren här känns lite onödigt konfrontativa. TS förstår uppenbarligen inte hur Git fungerar men det är inte särskilt hjälpsamt för någon att konstatera det utan att på något sätt hänvisa till vilken kunskap som saknas. Så här kommer jag med det långa svaret som ingen egentligen bad om, men jag känner behövs.

Först måste vi få ett grepp om varför frågan "hur tar jag bort en fil från en commit" inte egentligen är vettig rent tekniskt, för det är i praktiken omöjligt. En commit i Git är "immutable", den går inte att ändra på. Det är en mycket viktig hörnsten i hur Git fungerar.

Git är en form av filsystem, men istället för att vara uppbygt på att du hittar filer baserat på deras namn så hittar du istället filer baserat på deras innehåll. Det är s.k. content-addressable. Detta tar sin form i att namnet på en fil i Gits objektsdatabas (ett Git-objekt) helt enkelt är en hash av innehållet i filen. Det betyder också att innehållet i ett Git-objekt inte kan ändras, för ändrar du innehållet får du en ny hash, och då är det inte längra samma objekt.

De tre mest fundamentala Git-objekten är commit, tree och blob. En commit innehåller bland annat ett meddelande och en referens till det tree (Gits motsvarighet till en mapp) som utgör projektets rot vid det tillfället committen gjordes. Ett tree i sin tur kan referera till andra trees (tänk nästlade mappar) eller till blobbar (Gits motsvarighet till filer). Referenser utgörs av de refererade objektens hashar, och eftersom det finns en obruten kedja av refererande hashar från committen till varenda blob (fil) så går det inte att ändra varken innehåll i filer eller mappar utan att committens hash måste ändras; vilket per definition innebär att det blir en ny commit.

För att förstå detta lite tydligare kan vi ta ett enkelt exempel: ett projekt med filen "README.md" med texten "Hej!" samt samma fil kompilerad till en PDF.

project ├── README.md └── README.pdf

Vi antar att det finns en enstaka commit med meddelandet "Add README.md" där syftet var att lägga till endast README.md, men av misstag lades även README.pdf till. Då får vi en objektsdatabas som kan visualiseras på följande vis:

Det faktiska innehållet i commit och tree är följande (går att få ut med `git cat-file -p <hash>`):

commit:

tree 0f4e1542ed3ee409c58723d8f20fd00adc7c407d author SimpLar <example@example.com> 1689351051 +0200 committer SimpLar <example@example.com> 1689351051 +0200 Add README.md

tree:

100644 blob 3167944bbfb3218d11beb17b4154a8c1488db0a4 README.md 100644 blob a65089c6bea53541e648e04722fa71839e34ef36 README.pdf

Blobbarna är bara innehållet i filerna plus lite metadata.

Så om vi leker med tanken att ta bort README.pdf från denna commit, ja då måste ju den andra raden i trädet gå väck. Men om vi tar bort den raden ändrar vi trädets innehåll, och därmed ändrar vi hashen och det är inte längre samma träd så vi måste skapa ett nytt. Då måste vi referera till ett nytt träd i committen, men då ändrar vi committens innehåll och därmed dess hash, och då är det likväl inte längre samma commit.

Slutsats: det går inte att på något sätt ändra på en commit

Så vad menar folk då egentligen när de säger "ta bort en fil från en commit" eller "ändra en commit"? Kort sagt menar de att skapa en ny commit. Det kan vi exempelvis göra med "git commit --amend". Exempelvis på detta vis:

$ git rm README.pdf $ git commit --amend --no-edit

För det otränade ögat ändrar detta senaste committen så att README.pdf inte längre är en del av den. Men det som i själva verket händer är att vi skapar en ny commit och pekar om branchen på den nya.

Notera att vi nu har en ny commit som refererar till ett nytt tree som endast refererar till README.md. Vi har inte ändrat en existerande commit, utan bara skapat en ny. Detta är inga som helst problem om du bara har ett lokalt repo, men så fort du har en remote någonstans blir det jobbigare för du får endast pusha en branch om den kommit du försöker pusha upp är en strikt efterträdare till den senaste committen som finns på remoten (såvida du inte använder "--force", eller lite säkrare, "--force-with-lease", i vilket fall Git skriver över remote-branchen).

Hur vet man att en commit X är en efterträdare till en commit Y? Bra fråga: en commit refererar alltid till den föregående committen. Vi kan skriva till en rad "Då!" i README.md och committa det.

Den nya committen ser ut såhär:

tree da67510a03ff51cc88d74b5a1af5361eb3e2ca27 parent 85b11b7a4166669814c2c46092026f425d4d999b author SimpLar <example@example.com> 1689351995 +0200 committer SimpLar <example@example.com> 1689351995 +0200 Add new line

Den har en "parent"-referens, den föregående committens hash. Och här har vi ett ännu större krux: om du vill "ändra" i en commit X som ligger flera commits tillbaka, ja då måste du inte bara skapa en ny commit, utan även varje commit som följer. Du har ju effektivt skapat en ny commit X' med en ny hash, och följande commit måste då ha en ny parent-referens vilket givetvis ändrar dennes innehåll och hash, och effekten fortsätter.

Summa summarum ändrar du inte en commit, utan du skriver om historiken. Git tillhandahåller ett gäng kommandon för detta, där de jag själv använder flitigast är "rebase" och "--amend"-flaggan till "commit". Förstår man vad dessa gör kan man göra riktigt snitsiga grejer utan att kliva andra på tårna. Förstår man inte vad de gör kan det gå rätt illa rätt fort.

Det här tog mig typ en timme att skriva. Och jag som skulle ha spelat Gran Turismo ikväll. Hoppas det är till någon hjälp.

Permalänk
Skrivet av pv2b:

Jag klickade mig in på denna just för att tipsa om BFG men jag såg att TS hittat det själv redan. Github själva rekommenderar just detta verktyg. Jag hittade själv verktyget, när jag behövde det för ett par månader sedan p.g.a. en liknande tabbe, från en av deras hjälpartiklar när jag gjort samma sak. Visst kan man ha synpunkten att Github borde ha ett ännu enklare sätt att fixa detta, men det är inte ett krav på något sätt, när det finns en fungerande lösning som är lätt att använda, som dessutom funkar för alla Git-repos, inte bara de på Github.

Men jag tycker det är en väldigt märklig inställning här i tråden att hoppa på TS. Han har gjort ett misstag, men istället för att visa honom till en lösning så sätter man sig istället på höga hästar och pratar om att "man inte ska göra så", eller att det är "omöjligt". Jag vet inte om det är okunskap eller arrogant. Det är klart att det finns en lösning, och det är klart att det finns nackdelar med denna, men det finns stora nackdelar med att ha ett gitrepo som är för stort också. Vad ska TS göra istället menar ni andra som moraliserar? Börja om på ett nytt repo? Det löser ju inget...

Det är lite som om någon skulle komma in på ett bilforum efter att ha råkat få buckla en panel på bilen och sedan få till svar att "lol lär sig parkera bättre din noob". Det löser liksom inte problemet.

Skrivet av immutable:

Detta är något jag tyvärr märkt i flera trådar på sistone.

Det blir vanligare och vanligare att istället för att hjälpa någon så blir den som råkat göra något galet påhoppad och nästan mobbad istället.

Det är en utveckling jag verkligen inte gillar

Det är samma mentalitet på Stackoverflow. Jag menar...vem har inte råkat "commita" en fil som är större än 100 mb? Ska man bli straffad för det, eller ska man ta hjälp från rekommendationer som GitHub själva rekommenderar?

Det finns ju åtgärder och lösningar Men nu får man bara ett finger tillbaka haha

Permalänk
Medlem
Skrivet av heretic16:

Det är samma mentalitet på Stackoverflow. Jag menar...vem har inte råkat "commita" en fil som är större än 100 mb? Ska man bli straffad för det, eller ska man ta hjälp från rekommendationer som GitHub själva rekommenderar?

Det finns ju åtgärder och lösningar Men nu får man bara ett finger tillbaka haha

Du fick en lösning i tredje svaret i tråden. Triggern är väl snarare att du påstår man på flertalet ställen att du använder en tjänst felaktigt ("som ditt personliga moln", "När jag skickar upp saker, så skickar jag upp allt"), och dessutom drar den felaktiga slutsatsen att Github borde ha lösningar på ett problem som inte bör uppstå, då är det väl rimligt att få mothugg?

Permalänk
Skrivet av izzie:

Du fick en lösning i tredje svaret i tråden. Triggern är väl snarare att du påstår man på flertalet ställen att du använder en tjänst felaktigt ("som ditt personliga moln", "När jag skickar upp saker, så skickar jag upp allt"), och dessutom drar den felaktiga slutsatsen att Github borde ha lösningar på ett problem som inte bör uppstå, då är det väl rimligt att få mothugg?

Nej. Github är absolut inte min felaktiga tjänst. Jag använder molnet för att visa andra mina projekt.
Jag tycker att Git borde ge en förfrågan "Vill du inkludera denna fil som är över 100 mb?", innan man inkluderar den. Jag menar, hur svårt ska det vara för Git att ha en sådan förfrågan?

Dom som skapade Git verkar kunna mycket. Men dom glömde bort funktioner som Github rekommenderar...från tredje part. Alltså betyder det att Git har missat några viktiga saker.

Man ska inte behöva ladda ned "trix & fix" för att dra tillbaka en commit som har ej blivit "push".

Permalänk
Medlem
Skrivet av heretic16:

Nej. Github är absolut inte min felaktiga tjänst. Jag använder molnet för att visa andra mina projekt.
Jag tycker att Git borde ge en förfrågan "Vill du inkludera denna fil som är över 100 mb?", innan man inkluderar den. Jag menar, hur svårt ska det vara för Git att ha en sådan förfrågan?

Dom som skapade Git verkar kunna mycket. Men dom glömde bort funktioner som Github rekommenderar...från tredje part. Alltså betyder det att Git har missat några viktiga saker.

Man ska inte behöva ladda ned "trix & fix" för att dra tillbaka en commit som har ej blivit "push".

Git är ett verktyg som ska passa så många som möjligt och ska därför inte bygga in en massa funktionalitet som inte är absolut nödvändig.

Du kan själv bygga hooks som exekverar innan du gör en commit eller push där du kan neka om du lagt till en stor fil eller dylikt.

Visa signatur

AMD Ryzen 7 1700X 3.8 GHz 20MB | ASUS PRIME X370-PRO | MSI GeForce GTX 1080 Gaming X 8GB | G.Skill 16GB DDR4 3200 MHz CL14 Flare X | Corsair RM650x 650W

Permalänk
Datavetare

@heretic16 det är "by design" och i 99,99 % av fallen otroligt skönt och i övriga "WTF, varför tryckte jag på enter och tänkte efter sedan...". I detta fall var det inte hela världen, git har ju "by design" en del rätt vassa verktyg för att skriva om historien!

Visa signatur

Care About Your Craft: Why spend your life developing software unless you care about doing it well? - The Pragmatic Programmer

Permalänk
Medlem
Skrivet av heretic16:

Nej. Github är absolut inte min felaktiga tjänst. Jag använder molnet för att visa andra mina projekt.
Jag tycker att Git borde ge en förfrågan "Vill du inkludera denna fil som är över 100 mb?", innan man inkluderar den. Jag menar, hur svårt ska det vara för Git att ha en sådan förfrågan?

Dom som skapade Git verkar kunna mycket. Men dom glömde bort funktioner som Github rekommenderar...från tredje part. Alltså betyder det att Git har missat några viktiga saker.

Man ska inte behöva ladda ned "trix & fix" för att dra tillbaka en commit som har ej blivit "push".

Bara att bidra! https://github.com/git/git/pulls

Permalänk
Medlem
Skrivet av Paontuus:

Vill du bara ta bort stora filen från git repot så kan du köra såhär:

git rm --cached hugefile.txt
git commit -m "Remove large file from repository"
git push origin master

.gitignore hjälper bara till om du inte har commitat själva filen. På detta viset så hålls historiken kvar på allt du gjort, dvs dina 8 commits. Det går att rensa filen och all historik men det är en större huvudvärk.

Detta tar endast bort filen i efterföljande commits. Historik och repo har fortfarande den stora filen.

Trådskaparen behöver läsa på om git rebase och att skriva om historiken.

Visa signatur

Archlinux, Sway och Rust, vad mer behövs?

Permalänk
Medlem
Skrivet av Gräs-Mannen:

Detta tar endast bort filen i efterföljande commits. Historik och repo har fortfarande den stora filen.

Trådskaparen behöver läsa på om git rebase och att skriva om historiken.

Precis, lite knasigt formulerat av mig bara! Med historik menar jag alla andra commits också och dom har givetvis filen.

Visa signatur

Jobbdator: Macbook Pro 16" | M1 Pro | 32GB RAM | 1TB Lagring

Permalänk
Hedersmedlem
Skrivet av heretic16:

Nej. Github är absolut inte min felaktiga tjänst. Jag använder molnet för att visa andra mina projekt.
Jag tycker att Git borde ge en förfrågan "Vill du inkludera denna fil som är över 100 mb?", innan man inkluderar den. Jag menar, hur svårt ska det vara för Git att ha en sådan förfrågan?

Dom som skapade Git verkar kunna mycket. Men dom glömde bort funktioner som Github rekommenderar...från tredje part. Alltså betyder det att Git har missat några viktiga saker.

Man ska inte behöva ladda ned "trix & fix" för att dra tillbaka en commit som har ej blivit "push".

Nej, funktionerna är inte bortglömda. Du kan göra precis samma sak (och mer) med funktionen git filter-branch. Det är dock inte lika enkelt som att använda BFG Repo Cleaner för det specifika fallet att ta bort stora filer. Exakt hur du gör samma operation med git filter-branch och andra inbyggda git-kommandon finns under rubriken "Checklist for shrinking a repository".

Att Github sedan inte rekommenderar stora filer i repot betyder inte att Git i sig inte kan hantera dem. Det går bra, men repot blir kanske större än man tänkt sig, vilket försvårar när folk ska jobba med repot. Repot för Linux-kerneln är t.ex. cirka 7 GB stort på grund av all historik, för 20 år sedan hade det varit helt otänkbart att folk skulle ha en kopia av detta repo lokalt, men idag är det en bråkdel av ens vad ett normalt dataspel tar på hårddisken. Git som verktyg bör inte ha några åsikter om detta. Däremot har Github och Microsoft absolut åsikter om detta då det är de som betalar för brandbredden och lagringen. (Och även kanske enskilda utvecklare då som ibland kanske sitter med sämre eller dyra anslutningar...)

Sedan är det (enligt mig) en bra grej att det är lite svårt och krångligt att göra detta, det speglar tydligt att det är mot gits natur att ta bort saker som redan ligger i repot. Gör man det för enkelt är det svårare att få folk att inte använda Git på fel sätt.

Permalänk
Avstängd

Git är kraftfullt men komplicerat, så enkelt är det. Jag har jobbat med det som huvudsakligt verktyg för sånt i ett antal år nu och ändå händer det att saker går helt åt skogen fortfarande, med en massa onödigt jobb som följd.

Problemen kommer dock av att jag jobbar med andra främst, för personliga repon som bara jag använder så är det oerhört mycket enklare förstås. Behöver aldrig göra en rebase eller reset head exempelvis. Vi har separata repos för alla backend-servicar men frontenden är ett repo som "alla" är inne och petar i hela tiden, så där blir det jobbigare förstås. Även om jag rebasear på morgonen så kan det ju ha skett ett antal commits innan jag ska pusha vid lunch eller så, och även om jag rebasear precis innan min push så kan ju någon snika in emellan så blir det konflikter ändå, eller om något går fel i vår gate så jag får köra om pipen så kan min commit hamna längre ner i kön och få än fler konflikter. De går förstås att lösa, men att jobba flera parallellt i samma filer är alltid jobbigt hur man än gör.

Gitignore är viktig för att inte commita saker som inte ska commitas, men har man redan gjort det så får man ju göra en ny commit där man tar bort sakerna. Är det känsliga saker, typ nycklar eller certifikat som borde vara privata, så bör man "skriva om historian" förstås, men annars får man leva med att alla kan se ens dumheter.

Permalänk
Medlem

Jag har inte så mycket erfarenhet av just git, men jag har använt andra versionshanteringssystem, och något man snabbt lär sig är att göra en "dry run" innan man gör någon commit, där man kan se vilka filer som kommer att påverkas av commit:en. På det sättet kan man se till att det inte kommer in en massa skräp i repositoriet som tar onödig plats och (minst lika viktigt) gör historien rörigare och mer svårtolkad.

git är, precis som de flesta andra kommandon utvecklade för Unix-system, avsett att kunna användas i script och kommer därför inte att fråga användaren om något i normala fall (eftersom det skulle stoppa upp eventuellt script) - om man inte specifikt säger åt den att göra det naturligtvis.

Permalänk
Medlem
Skrivet av pv2b:

Att Github sedan inte rekommenderar stora filer i repot betyder inte att Git i sig inte kan hantera dem. Det går bra, men repot blir kanske större än man tänkt sig, vilket försvårar när folk ska jobba med repot. Repot för Linux-kerneln är t.ex. cirka 7 GB stort på grund av all historik, för 20 år sedan hade det varit helt otänkbart att folk skulle ha en kopia av detta repo lokalt, men idag är det en bråkdel av ens vad ett normalt dataspel tar på hårddisken. Git som verktyg bör inte ha några åsikter om detta. Däremot har Github och Microsoft absolut åsikter om detta då det är de som betalar för brandbredden och lagringen. (Och även kanske enskilda utvecklare då som ibland kanske sitter med sämre eller dyra anslutningar...)

Detta stämmer faktiskt inte, Git som verktyg har rätt rejäla begränsningar för vissa typer av filer. Ett repo kan bli stort av att ha väldigt lång historik och väldigt mycket källkod, vilket är fallet för Linux-kärnan. Men det är Git fortfarande bra på att hantera på grund av att det byggdes för just detta ändamål. Ordagrant, Torvalds (m.fl.) byggde Git för att versionshantera Linux. Men stora filer är något helt annat.

Man brukar säga att stora filer är lite utav en akilleshäl för Git, men i själva verket är akilleshälen binära filer, dvs filer som inte är menade att läsas som klartext. Stora filer tenderar dock att vara just binära, vilket antagligen är varför begreppen används för samma koncept. Med antagandet att TS 100MB stora fil är binär (vilket känns rätt sannolikt) så skulle jag säga att det var helt rimligt för denne att ta bort den ur historiken, särskilt med tanke på att det är ett privat projekt utan andra medverkande. Och jag ska såklart förklara varför.

På grund av att Git lagrar hela innehållet i en fil som en blob och därmed måste skapa en ny blob för minsta lilla ändring så växer repot snabbt om man har en binär fil som man gör ändringar i. En binär fil på 100 MB som du ändrar minsta lilla sak i och sedan committar, ja då har du ett repo som är 200 MB stort.

Läser man kapitlet i Git-boken som nämner lagring av stora källkodsfiler så kan man tro att detta inte är något större problem eftersom Git packar ihop liknande objekt i packfiles och lagrar deltan mellan dessa. Det som tyvärr inte framgår här är att Git från topp till tå är optimerat för att lagra klartext. Så att lagra flera versioner av en 100 MB binär fil är ett ganska stort problem, medan samma sak fö` en 100 MB stor CSV-fil med något dataset inte kommer att få repot att växa på samma sätt på grund av att den är klartext och deltan därmed kan beräknas från en version till en annan.

Vi kan göra ett litet experiment med en snarlik version av exemplet jag hade ovan, där vi committar PDFen som det står "Hej!" i (som till största del är binärt nonsens). PDFen i sig är ca 24KB, och även i komprimerad blob-form är den ca 24KB (den är faktiskt några hundra byte mindre i blobformen i detta fall).

$ ls -l -h total 28K -rw-r--r-- 1 simplar simplar 5 Jul 16 10:33 README.md -rw-r--r-- 1 simplar simplar 24K Jul 16 10:33 README.pdf $ git hash-object README.pdf # <-- to determine object hash to find it in the database 73d3e81c91e7581f984ba50e311cec4b8744689a $ ls -l -h .git/objects/73/d3e81c91e7581f984ba50e311cec4b8744689a -r--r--r-- 1 simplar simplar 24K Jul 16 10:35 .git/objects/73/d3e81c91e7581f984ba50e311cec4b8744689a

Om vi packar denna i en packfile (Git gör detta automatiskt vid vissa tillfällen) så får vi i praktiken samma storlek som blobben, eftersom en "bas" måste sparas i sin helhet.

$ git repack $ ls -l -h .git/objects/pack/ total 32K -r--r--r-- 1 simplar simplar 1.2K Jul 16 10:49 pack-79c806373a2e0fd3f96a4fea204b8bf04bb6d2c3.idx -r--r--r-- 1 simplar simplar 24K Jul 16 10:49 pack-79c806373a2e0fd3f96a4fea204b8bf04bb6d2c3.pack -r--r--r-- 1 simplar simplar 68 Jul 16 10:49 pack-79c806373a2e0fd3f96a4fea204b8bf04bb6d2c3.rev

Om vi nu ändrar något litet, exempelvis ändrar texten från "Hej!" till "Hej" och kompilerar om PDFen kommer den ha nära identisk storlek och innehåll i praktiken. Comittar vi den får vi som sagt en ny blob som också är 24KB, men det intressanta är att packfilen blir dubbelt så stor, vilket i praktiken gör att repot för all framtid kommer vara dubbelt så stort (om vi inte får en ny algoritm för att packa packfiler).

$ ls -l -h total 28K -rw-r--r-- 1 simplar simplar 4 Jul 16 10:58 README.md -rw-r--r-- 1 simplar simplar 24K Jul 16 10:33 README.pdf $ ls -l -h .git/objects/pack/ total 56K -r--r--r-- 1 simplar simplar 1.4K Jul 16 11:00 pack-6c7d064fa855062137a6c6af6039dcbfe88c77da.idx -r--r--r-- 1 simplar simplar 48K Jul 16 11:00 pack-6c7d064fa855062137a6c6af6039dcbfe88c77da.pack -r--r--r-- 1 simplar simplar 92 Jul 16 11:00 pack-6c7d064fa855062137a6c6af6039dcbfe88c77da.rev

Om jag istället tar en godtycklig källkodsfil från Linux-kärnan på ca 38KB och gör samma sak får jag ett helt annat resultat på grund av att den är klartext.

$ git add arraymap.c $ git commit -m 'Add arraymap.c' $ git repack $ ls -l -h .git/objects/pack/ [...] -r--r--r-- 1 simplar simplar 8.8K Jul 16 11:15 pack-a355016827401876bb13400a4a5e084c8d8e6db5.pack $ echo '// hello there' >> arraymap.c $ git commit -am 'Append greeting' $ git repack $ ls -l -h .git/objects/pack/ [...] -r--r--r-- 1 simplar simplar 9.0K Jul 16 11:17 pack-ca725db684ea1735cae3ddf3055b44c09c19d55e.pack [...]

Inte nog med att den initiala packfilen blev betydligt mindre än källfilen på grund av att komprimeringen (som är zlib) faktiskt hade någon effekt, utan den andra packfilen som innehåller två versioner av filen blev bara ett par hundra byte större! Det är precis detta Git är byggt för, versioner av klartextfiler med små skillnader mellan varje version.

Det finns alltså väldigt goda tekniska anledningar till att inte versionshantera stora binära filer med Git. Det är helt enkelt inte byggt för det. Där har vi istället tillägg såsom Git LFS som får göra grovjobbet med att spara datan, medan Git håller koll på var vardera version hör hemma i historiken.

Permalänk
Hedersmedlem
Skrivet av snajk:

Gitignore är viktig för att inte commita saker som inte ska commitas, men har man redan gjort det så får man ju göra en ny commit där man tar bort sakerna.

En god vana är väl också att inte smutsa ned källkodsmapparna med byggartefakter, testdata, konfigurationsfiler och liknade?

Permalänk
Avstängd
Skrivet av Elgot:

En god vana är väl också att inte smutsa ned källkodsmapparna med byggartefakter, testdata, konfigurationsfiler och liknade?

Jo så klart, där det är möjligt. Men gitignore behöver man ju för annat som man inte vill ha i sitt repo.

Jag jobbar med en applikation som körs i micro services i containers. Konfig ligger mestadels i DB, eller i dockerfiler och liknande. Byggartefakter byggs i en pipeline där också "alla" tester körs (det finns tester som körs manuellt också, högre upp eller närmare kund, men allt från enhetstester upp till ganska omfattande acceptanstest-scenarion körs i pipen). Men det finns alltid saker som behövs i projekten som inte ska pushas, auto-genererade grejer, certifikat, nycklar, översättningar och så vidare.