4. témakör · Távoli tárolók: GitHub · 19. fejezet
Amikor többen dolgoznak ugyanazon a repón, előbb-utóbb jönnek a piros üzenetek: rejected, divergent branches, CONFLICT.
Ezek nem hibák, hanem a Git védekezése: nem enged felülírni mások munkáját. Ebben a fejezetben végigmegyünk a tipikus helyzeteken, megtanulod,
mikor és hogyan használd (és mikor ne) a --force-t, és mit tegyél, ha minden összekuszálódott.
pull.rebase.--force-with-lease, és mikor tilos.| Üzenet | Mi történt? | Megoldás |
|---|---|---|
! [rejected] … (fetch first) | a GitHubon van olyan commit, ami nálad nincs | git pull, majd git push |
! [rejected] … (non-fast-forward) | a GitHubon lévő ág nem őse a tiédnek (pl. amend/rebase után) | git pull; saját ágon esetleg --force-with-lease |
Need to specify how to reconcile divergent branches | mindkét oldalon van új commit, és nincs beállítva, hogyan egyesüljenek | git config pull.rebase false (vagy true), majd újra pull |
CONFLICT (content) pull után | ugyanazt a részt mindketten eltérően módosítottátok | feloldás (13. fejezet), git add, git commit / rebase --continue, push |
would be overwritten by merge | nem commitolt munkád van, amit a pull felülírna | commit, vagy git stash → pull → git stash pop |
refusing to merge unrelated histories | a két történetnek nincs közös őse (pl. README-vel létrehozott repó) | git pull --allow-unrelated-histories (17. fejezet) |
PS> git push To https://github.com/anna-kovacs/osztalyoldal.git ! [rejected] main -> main (fetch first) error: failed to push some refs to 'https://github.com/anna-kovacs/osztalyoldal.git' hint: Updates were rejected because the remote contains work that you do not hint: have locally. …
Péter feltöltött, amíg te dolgoztál. Ha a Git elfogadná a push-t, Péter commitja eltűnne a GitHubról. Ezért a GitHub csak akkor fogad el egy push-t, ha az előretolás (fast-forward): a GitHubon lévő ág a te ágad őse. A megoldás mindig ugyanaz: előbb beépíted a GitHubon lévő munkát, aztán töltesz fel.
PS> git pull # letöltés + beépítés (merge vagy rebase) PS> git push # most már előretolás: sikerül
A git push --force itt „megoldaná” a hibát úgy, hogy törli Péter commitját a GitHubról. Elutasított push-ra a válasz: pull.
Ha nálad is és a GitHubon is van új commit, a két ág szétvált (diverged). Az újabb Git ilyenkor nem dönt helyetted, hanem megáll:
hint: You have divergent branches and need to specify how to reconcile them.
hint: git config pull.rebase false # merge
hint: git config pull.rebase true # rebase
hint: git config pull.ff only # fast-forward only
fatal: Need to specify how to reconcile divergent branches.
| Beállítás / kapcsoló | Mi történik szétváláskor? | Eredmény |
|---|---|---|
pull.rebase false · git pull --no-rebase | merge commit készül | a történet megmutatja az elágazást |
pull.rebase true · git pull --rebase | a helyi commitjaid a GitHub-os ág mögé kerülnek (új hash) | egyenes történet |
pull.ff only · git pull --ff-only | megáll, ha nem lehet előretolni | csak tiszta frissítés |
Kezdőknek jó választás a globális beállítás: git config --global pull.rebase false. Ha a csapat egyenes történetet szeretne, akkor
true. A pull-rebase nyugodtan használható, mert a saját, még fel nem töltött commitjaidat írja át (14. fejezet).
Ha ugyanazt a sort Péter is és te is módosítottátok, a pull beépítő lépése ütközést jelez. A feloldás pontosan olyan, mint a 13. fejezetben:
merge-es pull után
PS> git pull CONFLICT (content): Merge conflict in index.html # … feloldás a fájlban … PS> git add index.html PS> git commit --no-edit PS> git push
rebase-es pull után
PS> git pull --rebase CONFLICT (content): Merge conflict in index.html # … feloldás a fájlban … PS> git add index.html PS> git rebase --continue PS> git push
Kiszállás: git merge --abort, illetve git rebase --abort. A feloldás után ne felejtsd el a push-t:
amíg nem töltöd fel, a GitHubon továbbra is csak Péter változata van.
error: Your local changes to the following files would be overwritten by merge:
index.html
Please commit your changes or stash them before you merge.
Aborting
A pull nem kezd bele, mert felülírná a még nem commitolt munkádat. Két megoldás:
git commit, majd git pull (ekkor a munkád és Péteré egyesül).git stash → git pull → git stash pop (14. fejezet). A pop ütközhet, azt ugyanígy oldod fel.A git push --force a GitHubon lévő ágat felülírja a tiéddel, akkor is, ha ezzel commitok tűnnek el. Van jogos használata: ha a
saját, csak általad használt ágadat írtad át (amend, rebase, 10. és 14. fejezet), a sima push elutasítódik (non-fast-forward), mert a régi commitok fent vannak.
| Parancs | Mit csinál? |
|---|---|
git push --force | vakon felülír: ha közben más is feltöltött, az ő munkája elveszik |
git push --force-with-lease | csak akkor ír felül, ha a GitHubon az ág még ott áll, ahol a legutóbbi fetch-kor látted; ha közben más feltöltött, elutasítja (stale info) |
A main-re és minden ágra, amelyen más is dolgozik, ne force push-olj. Csapatban a main-t érdemes a GitHubon védetté tenni
(branch protection, 24. fejezet): ott a force push be sem engedett. Ha egy közös ágon hibás commit van, arra a git revert való (10. fejezet).
Ha a helyi repód annyira összekeveredett, hogy inkább eldobnád a helyi változásokat, és pontosan a GitHubon lévő állapotot vennéd át:
PS> git fetch PS> git branch mentes # biztonsági címke a mostani állapotra (ha mégis kellene) PS> git reset --hard origin/main # a main pontosan a GitHub-os állapotra áll
A reset --hard a nem commitolt változásokat végleg eldobja, a fel nem töltött commitokat pedig lekapcsolja az ágról (a reflogból még visszahozhatók, 10. fejezet).
Ezért előtte a git branch mentes egy olcsó biztosítás. Az utolsó menedék: egy friss klón egy másik mappába.
Válaszd ki, milyen üzenetet kaptál (vagy mi a helyzet), és a mentőcsapat megmondja a lépéseket!
Melyik a helyes (és biztonságos) lépés?
--force-with-lease; a git.allowForcePush beállítás kell hozzá.Az osztalyoldal repón Péterrel dolgoztok. Amíg te a gépeden dolgoztál, Péter már feltöltött, ugyanabba a sorba. Oldd meg sorban a helyzeteket!
⭐ alap · ⭐⭐ haladó · ⭐⭐⭐ kihívás
Egy saját repódban módosítsd a README-t a GitHub weboldalán, és ugyanazt a sort a gépeden is (commit). Próbálj feltölteni: olvasd el az elutasítást, majd oldd meg pull-lal.
Nézd meg, mi a beállításod: git config --global pull.rebase. Ha nincs, döntsd el a fejezet alapján, mit állítasz be, és indokold egy mondatban.
Menj végig a Szinkron-mentőcsapat összes esetén, és írj egy egyoldalas „piros üzenetek” puskát a saját szavaiddal.
Egy saját feature ágadon, amelyet már feltöltöttél, írd át az utolsó commit üzenetét (--amend). Mit mond a sima git push? Töltsd fel
--force-with-lease-szel.
Párban: mindketten módosítsátok ugyanazt a sort, az egyik töltsön fel, a másik a GitHub Desktopban pull-oljon, oldja fel az ütközést, és töltse fel.
Egy gyakorló repóban szándékosan kuszáld össze a main-t (néhány rossz commit, nem commitolt szemét), majd állítsd a GitHub-os állapotra: git fetch,
git branch mentes, git reset --hard origin/main. Ellenőrizd, hogy a mentes ágon megvan-e a régi állapot.
Mutasd be a --force és a --force-with-lease különbségét két géppel (vagy két klónnal): az egyikről tölts fel, a másikról amendelj és próbáld
mindkét kapcsolóval. Melyik veszítette volna el a másik munkáját?
Az egyválasztós kérdéseknél kattints a válaszra. A többválasztósaknál jelöld be az összes helyeset, majd nyomd meg az Ellenőrzés gombot.
| Fogalom | Jelentés |
|---|---|
| rejected (fetch first) | elutasított push: a GitHubon van olyan commit, ami nálad nincs |
| non-fast-forward | a push nem előretolás: a távoli ág nem őse a helyinek |
| szétvált ágak (diverged) | a helyi és a távoli ágon is van új commit |
pull.rebase / pull.ff | beállítás arról, hogyan egyesítse a pull a szétvált ágakat (merge, rebase, csak előretolás) |
| force push | git push --force: a távoli ág felülírása, akkor is, ha commitok vesznek el |
--force-with-lease | biztonságosabb felülírás: elutasít, ha közben más feltöltött (stale info) |
| védett ág (branch protection) | GitHub-szabály: pl. a main-re tilos a force push és a közvetlen push (24. fejezet) |
git reset --hard origin/main | a helyi ág a letöltött távoli állapotra áll; a helyi munka elvész |
pull.rebase-t (false: merge, true: rebase), vagy használd a --no-rebase / --rebase kapcsolót.git add, git commit (vagy git rebase --continue), és a végén push.--force-with-lease; közös ágra soha. Mentés: git branch mentes + git reset --hard origin/main.Ezzel a szinkronizálás eszköztára teljes. A következő témakörben a GitHub csapatmunka-eszközei jönnek, elsőként a pull request.