4.7 Tipikus Git hibák

← 4. Git és verziókezelés a gyakorlatban

4.7 Tipikus Git hibák junioroknál – és hogyan kerüld el

Áttekintő

Mindenki követ el hibákat Git-tel. A kérdés nem az, hogy elköveted-e, hanem az, hogy tudod-e megoldani. Ez az alfejezet a leggyakoribb Git-baleseteket mutatja be, amelyeket szinte minden junior fejlesztő átél az első hónapokban – és ami fontosabb: megmutatja, hogyan javítsd ki őket pánik nélkül.

A jó hír: a Git ritka kivételtől eltekintve visszafordítható. A rossz hír: van az a néhány kivétel, ami komoly bajt okoz, ha nem vigyázol (force push mainre, szenzitív adat a history-ban). Ezeket a kivételeket fogjuk alaposan körbejárni.

Amit tanulni fogsz:

  • Hogyan vonj vissza commitot biztonságosan – revert vs. reset vs. amend
  • Mi történik, ha véletlenül mainre commitolsz
  • Miért veszélyes a git push --force és mikor szabad mégis használni
  • Hogyan kezeld, ha jelszó vagy API kulcs bekerült a history-ba
  • A .gitignore helyes használata és tipikus hibái

Részletes leírás

1. Accidental commit mainre – főágra commitoltál véletlenül

Ez az egyik leggyakoribb junior hiba: elfelejtesz branch-et váltani, és egyenesen a main-re (vagy master-re) commitolsz.

Hogyan ismered fel:

git log --oneline -5
# bf3a1c2 (HEAD -> main) WIP: authentication draft  ← ez nem kellett volna ide
# a7f9e01 Merge pull request #42 from feature/login

Megoldás – ha még nem pusholtak mások:

Ha a commit csak a te lokális főágadon van, egyszerűen létre tudsz hozni belőle egy új branch-et, majd visszavonni a main-en:

# 1. Hozz létre új branch-et a jelenlegi állapotból
git branch feature/authentication

# 2. Vond vissza a commitot main-en (de ne töröld a változtatásokat!)
git reset HEAD~1

# 3. Ellenőrzés
git log --oneline -3  # a commit eltűnt a mainről
git status           # a változtatások staged állapotban maradnak

A git reset HEAD~1 visszaállítja a HEAD-et egy committal korábbra, de a változtatásokat megtartja a working directorydban (ez az alapértelmezett --mixed mód).

Ha már pusholták mások is:

Ha a commit már a remote main-en van és mások is lehúzták, NE használj reset-et. Helyette revert:

git revert bf3a1c2

A revert egy új commitot hoz létre, ami visszavonja a változtatásokat – nem módosítja a history-t, így mások munkáját nem zavarja meg.


2. Commit szenzitív adattal – jelszó, API kulcs a kódban

Ez a legkomolyabb hiba, amit lehet elkövetni Git-tel. Ha egy API kulcs, jelszó, vagy titkos token bekerült a commitba, az adat kompromittálódott – még akkor is, ha utána törlöd.

Miért?

  • A Git history megőrzi az összes korábbi állapotot
  • Ha pusholsz GitHubra, bárki láthatja a history-t
  • Automatizált botok folyamatosan pásztázzák a GitHub-ot ilyen adatok után
  • Még privát repo esetén is: ha a repot klónozzák, az adat átkerül

Azonnali teendők, ha megtörtént:

  1. Azonnal érvénytelenítsd az érintett kulcsot/jelszót – ne várd meg, amíg kiveszed a history-ból
  2. Generálj új kulcsot
  3. Csak ezután foglalkozz a Git history-val

A history megtisztítása:

Ha még nem pusholtak mások, és csak az utolsó commitban van a probléma:

# Módosítsd az utolsó commitot (amend)
# 1. Vedd ki a szenzitív fájlt a staged területről
git rm --cached .env

# 2. Add hozzá a .gitignore-hoz
echo ".env" >> .gitignore
git add .gitignore

# 3. Módosítsd az utolsó commitot
git commit --amend

Ha már több commit régen van benne, vagy már pusholva van, a git filter-branch vagy a BFG Repo Cleaner eszközre lesz szükség – ez haladó téma, és ilyenkor kérj senior segítséget.

Megelőzés – ez a lényeg:

# .gitignore – ezek mindig legyenek benne
.env
.env.local
.env.production
*.key
*.pem
config/secrets.yml

A .env.example fájlba kerüljenek a szükséges változók üresen – ez mutatja, milyen változókra van szükség, de nem tartalmaz valódi értékeket:

# .env.example (ezt IGEN commitolod)
DATABASE_URL=
SECRET_KEY=
API_KEY=

3. Force push – és mikor okoz katasztrófát

A git push --force felülírja a remote history-t a te lokális history-dddal. Ez hatékony eszköz, de csapatban használva komoly bajt okozhat.

Mi történik force push esetén:

Remote main: A → B → C → D
Te lokálisan: A → B → C' (reset után)

git push --force
Remote main: A → B → C' ← D (D eltűnt!)

Ha valaki D-t alapul véve dolgozott, a változtatásai "elvesznek" (pontosabban: a history-ból kiesnek).

Mikor NEM szabad force push-t használni:

  • Megosztott branch-ekre (main, develop, staging)
  • Ha mások is lehúzták már az adott branch-et
  • Production ágakra soha, semmilyen körülmények között

Mikor szabad (óvatosan) force push-t használni:

  • Saját feature branch-edre, amit senki más nem használ
  • Ilyenkor a biztonságosabb verzió: git push --force-with-lease
# Biztonságosabb: csak akkor push-ol, ha senki más nem módosított
git push --force-with-lease origin feature/my-branch

A --force-with-lease ellenőrzi, hogy a remote branch megegyezik-e azzal, amit te utoljára lehúztál. Ha valaki közben változtatott, a push megtagadja.


4. Elveszett változtatások – és hogyan találd meg őket

Úgy érzed, elveszett valami? Valószínűleg nem.

A git reflog a mentőöv:

A Git minden HEAD-módosítást naplóz a reflog-ban – még akkor is, ha azok más parancsokkal "eltűnnek":

git reflog
# 3c5a819 HEAD@{0}: reset: moving to HEAD~2
# bf3a1c2 HEAD@{1}: commit: Add payment integration
# a7f9e01 HEAD@{2}: commit: Fix validation bug

Ha véletlenül reset-eltél valamit, a régi commit hash-e megvan a reflog-ban:

# Visszaállítás a "elveszett" commitra
git checkout bf3a1c2
# vagy
git reset --hard bf3a1c2

Fontos: a reflog lokális, és kb. 90 napig tartja meg az adatokat. Ha pusholva sem volt és töröltük lokálisan is, és 90 nap telt el – akkor valóban elveszett.


5. git reset – a három mód különbsége

A reset az egyik legfélreértettebb Git parancs. Három módja van, és fontos, melyiket mikor használod:

ParancsCommit historyStaged (index)Working directory
git reset --soft HEAD~1VisszalépVáltozatlan (staged marad)Változatlan
git reset HEAD~1 (vagy --mixed)VisszalépTörli a stage-etVáltozatlan
git reset --hard HEAD~1VisszalépTörli a stage-etTörli a változtatásokat

Ökölszabály:

  • --soft: újra akarom commitolni ugyanazt, csak a commit üzenetét változtatom
  • --mixed (alapértelmezett): újra akarom nézni és stage-elni a változtatásokat
  • --hard: tényleg el akarom dobni mindent – visszafordíthatatlan a lokális változtatásokra nézve

6. git revert vs. git reset – melyiket mikor

Egyszerű szabály:

git revert – ha a commit már megosztott (pusholva van, mások is látják):

git revert abc1234
# Új commitot hoz létre, ami visszavonja az abc1234-et
# Biztonságos megosztott branch-eken

git reset – ha a commit csak lokálisan van, még nem pusholták:

git reset HEAD~1
# Visszavon lokálisan, módosítja a history-t
# NE használd pusholva lévő commitokon

7. .gitignore tipikus hibái

Hiba: utólag adtad hozzá, de a fájl már tracked állapotban van

Ha egy fájl már be van commitolva, a .gitignore-ba való felvétel nem elég – a Git tovább követi:

# Kiveszi a tracking-ből, de a fájlt nem törli
git rm --cached filename.log

# Vagy könyvtárra:
git rm -r --cached node_modules/

# Ezután commitolj
git add .gitignore
git commit -m "chore: remove tracked files that should be ignored"

Hiba: globális .gitignore hiánya

Az IDE által generált fájlok (.idea/, .vscode/, *.DS_Store) nem valók a projekt .gitignore-jába – mások más IDE-t használnak. Ezek a globális .gitignore-ba valók:

# Globális gitignore beállítása
git config --global core.excludesfile ~/.gitignore_global

# ~/.gitignore_global tartalma például:
.DS_Store
.idea/
*.swp
Thumbs.db

Életszerű példák

1. példa: A hétfő reggeli pánik

Szituáció: Péter hétfőn reggel megnyitja a terminált, git status-t futtat, és látja, hogy a múlt pénteken mainre commitolt két félkész commitot. Közben a kolléga is lehúzta a mainet.

Mi a teendő:

# 1. Ellenőrzés – hol vagyunk, mi a helyzet
git log --oneline -5
git log --oneline origin/main -5

# 2. Ha a kollégánál is ott vannak a commitok, revert-et alkalmazunk
git revert HEAD~1  # a legutóbbi commit visszafordítása
git revert HEAD~1  # az eggyel korábbi (most már ez a legutóbbi)

# 3. Push
git push origin main

A revert után a Péter commitjai ott maradnak a history-ban (látható, hogy mi történt), de az általuk hozott változtatások visszavonódnak. A kollégánál nem törik el semmi.


2. példa: „Ó nem, belecommitoltam az API kulcsot"

Szituáció: Anna push előtt veszi észre, hogy az utolsó commitjában ott van a config.js fájl az éles Stripe API kulccsal.

# 1. Azonnal: invalidálja a kulcsot a Stripe dashboard-on
# (ez a legfontosabb lépés, ezt ELŐSZÖR)

# 2. Elveszi a fájlt a commitból, de megtartja lokálisan
git rm --cached config.js

# 3. .gitignore-ba felveszi
echo "config.js" >> .gitignore
git add .gitignore

# 4. Módosítja az utolsó commitot
git commit --amend --no-edit
# (--no-edit: nem kell újra megadni a commit üzenetet)

# 5. Ezután pusholja az új kulccsal konfigurált változatot

Mivel a push még nem történt meg, az amend megoldja a helyzetet.


3. példa: A feature branch elveszett reset után

Szituáció: Béla dühösen git reset --hard-ot futtatott, majd rájött, hogy az utolsó 3 commitja fontos munkát tartalmazott.

# reflog megmutatja, hol volt a HEAD
git reflog
# 5d3b2a1 HEAD@{0}: reset: moving to HEAD~3
# c8f1e09 HEAD@{1}: commit: Add export functionality
# b2a4d7f HEAD@{2}: commit: Fix calculation bug
# a9e3c01 HEAD@{3}: commit: Refactor data processing

# Az elveszett munkát tartalmazza a HEAD@{1} állapot (c8f1e09)
# Visszaállítás:
git reset --hard c8f1e09

# Vagy ha csak megtekinteni szeretnénk:
git checkout c8f1e09

Tesztfeladatok

1. Mi a különbség a git reset --soft HEAD~1 és a git reset --hard HEAD~1 parancsok között?

a) Nincs különbség, mindkettő visszavonja a commitot
b) A --soft megtartja a változtatásokat staged állapotban, a --hard visszafordíthatatlanul törli a lokális változtatásokat is
c) A --soft csak a commit üzenetet módosítja
d) A --hard pusholja is a változtatásokat

(Helyes: b)


2. Kollégád már lehúzta azt a commitot, amit véletlenül a main-re tettél. Mi a helyes megközelítés a visszavonáshoz?

a) git reset --hard HEAD~1, majd git push --force
b) git revert <commit-hash>, majd git push
c) A commitot egyszerűen töröljük a GitHub UI-n
d) Nem lehet visszavonni, ha mások már lehúzták

(Helyes: b)


3. API kulcsot commitoltál, és már pusholva is van. Mi az ELSŐ teendő?

a) git push --force az érintett commit törlésével
b) BFG Repo Cleaner futtatása a history megtisztítására
c) Az érintett API kulcs azonnali érvénytelenítése a szolgáltatónál
d) A repository törlése és újra létrehozása

(Helyes: c – a kulcs kompromittálódott, az a legfontosabb lépés)


4. Mikor biztonságos a git push --force használata?

a) Sosem
b) Csak a main branch-en
c) Saját feature branch-eden, amelyet senki más nem használ
d) Bármikor, ha gyorsabb megoldást kínál

(Helyes: c)


5. .gitignore-ba felvettél egy fájlt, de a Git továbbra is követi a változtatásait. Mi a valószínű ok?

a) A .gitignore szintaxisa hibás
b) A fájl már korábban be lett commitolva, ezért tracked állapotban van
c) A .gitignore csak az új klónozásoknál működik
d) Git 2.0 felett már nem működik a .gitignore

(Helyes: b)


6. Mi a git reflog parancscélja?

a) A remote repository log-jait mutatja
b) A HEAD korábbi állapotait naplózza, beleértve a "elveszett" commitokat is
c) Csak a merge commitokat listázza
d) A .git könyvtár fájljainak listáját jeleníti meg

(Helyes: b)


7. Mi a git push --force-with-lease előnye a sima --force-szal szemben?

a) Gyorsabban fut
b) Tömöríti a history-t
c) Csak akkor hajtja végre a force push-t, ha senki más nem módosította a remote branch-et a legutóbbi lehúzásod óta
d) Automatikusan backup-olja a remote állapotot

(Helyes: c)


8. Melyik parancsra van szükség ahhoz, hogy egy már tracked fájlt eltávolíts a Git tracking alól (de ne törölj a fájlrendszerről)?

a) git ignore <fájlnév>
b) git rm <fájlnév>
c) git rm --cached <fájlnév>
d) git untrack <fájlnév>

(Helyes: c)


9. Szituáció: Éppen reset --hard-ot futtatottál és rájöttél, hogy kellett volna az a commit. Milyen paranccsal találod meg a "elveszett" commit hash-ét?

a) git log --all
b) git stash list
c) git reflog
d) git status --verbose

(Helyes: c)


10. Melyik állítás igaz a .gitignore és a globális gitignore kapcsolatáról?

a) A globális gitignore felülírja a projekt .gitignore-ját
b) IDE-specifikus fájlok (pl. .idea/, .DS_Store) inkább a globális gitignore-ba valók, hogy ne terheljük a projekt .gitignore-ját mások IDE-beállításaival
c) Globális gitignore nem létezik, csak projekt szintű
d) A projekt .gitignore nem működik, ha van globális is beállítva

(Helyes: b)

Scroll to Top