3. témakör · Ágak és összefésülés · 12. fejezet
Az ágakon elkészült munkának egyszer vissza kell kerülnie a fő ágba. Ezt az összefésülés (merge) végzi. Megnézzük a két
alapesetet: a fast-forwardot, amikor elég előretolni a címkét, és a háromutas összefésülést, amely egy
merge commitot hoz létre. Megtanulod azt is, hogyan dönt a Git fájlonként, és mire jók a --no-ff,
--ff-only és --squash kapcsolók.
--no-ff, --ff-only és --squash kapcsolót.Az összefésülés (merge) egy másik ág változásait beépíti abba az ágba, amelyen éppen állsz. A két lépés sorrendje fontos:
PS> git switch main # 1. állj a CÉL ágra (ahová a munka kerüljön) PS> git merge feature/galeria # 2. fésüld bele a FORRÁS ágat
git merge ➜git status), különben a Git megtagadhatja: Your local changes … would be overwritten by merge.feature/galeria ágon állva kiadott git merge main a main-t fésüli a feature ágba, nem fordítva. (Ennek is van értelme: így hozod naprakészre a feature ágat.)Ha a cél ágon az elágazás óta nem készült új commit, akkor a forrás ág története egyszerűen „folytatja” a célét. A Gitnek nem kell
semmit összefésülnie: csak előretolja a main címkét a forrás ág végére. Új commit nem keletkezik.
Előtte
A git merge feature után
PS> git merge feature/galeria Updating 2f6a9c3..9b2e4f1 Fast-forward galeria.html | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 galeria.html
Ha az elágazás óta mindkét ágon készült commit, a történet szétvált, előretolással nem lehet egyesíteni. Ilyenkor a Git három állapotot vet össze:
Ahol csak az egyik oldal változtatott, azt átveszi; az eredményből pedig egy új merge commitot készít, amelynek két szülője van.
Előtte: szétvált ágak
A git merge feature után
PS> git merge feature/galeria Auto-merging index.html Merge made by the 'ort' strategy. galeria.html | 12 ++++++++++++ index.html | 1 + 2 files changed, 13 insertions(+) PS> git log --oneline --graph * c4e18a0 (HEAD -> main) Merge branch 'feature/galeria' |\ | * 9b2e4f1 (feature/galeria) feat: galéria oldal * | 5c7d013 fix: telefonszám javítása |/ * 2f6a9c3 Kezdőlap első változata
--no-edit vagy a -m "…" ezt kihagyja.git show és a git log a merge commitnál kiírja a két szülőt: Merge: 5c7d013 9b2e4f1. Az első szülő a cél ág előző commitja
(HEAD^1), a második a beolvasztott ágé (HEAD^2).Válassz egy kiinduló helyzetet és egy összefésülési módot, és nézd meg, milyen lesz a történet!
git merge feature után?Előtte
Utána
A háromutas összefésülés szabálya egyszerű: a Git minden fájlt (és azon belül minden sort) a közös őshöz hasonlít.
| Közös ős | Mi (main) | Ők (feature) | Eredmény |
|---|---|---|---|
| A | A | A | A: senki nem változtatott |
| A | A | B | B: csak ők változtattak, átvesszük |
| A | B | A | B: csak mi változtattunk, megmarad |
| A | B | B | B: ugyanazt változtattuk |
| A | B | C | ⚡ ütközés: mindketten mást, ugyanott |
Ez soronként is működik: ha ugyanabban a fájlban mi az elejét, ők a végét módosították, a Git mindkét változást automatikusan beépíti (Auto-merging index.html). Ütközés csak akkor van, ha ugyanazt a részt változtattátok meg eltérően, vagy az egyik fél törölt egy fájlt, amelyet a másik módosított. Ennek feloldása a 13. fejezet témája.
A közös őshöz képest ki mit változtatott? Döntsd el, mit tesz a Git!
| Parancs | Mit csinál? | Mikor jó? |
|---|---|---|
git merge feature | ha lehet, fast-forward; ha nem, merge commit | az alapeset |
git merge --no-ff feature | akkor is merge commitot készít, ha fast-forward lehetne | ha a történetben látszódjon, hogy ezek a commitok egy funkcióhoz tartoztak |
git merge --ff-only feature | csak fast-forwardot enged; ha az nem lehetséges, megáll | ha biztosan nem akarsz merge commitot (pl. egy frissítésnél) |
git merge --squash feature | a feature összes változását előkészíti, de nem commitol; utána egyetlen commitot készítesz | ha sok apró „wip” commitot egyetlen tiszta commitként akarsz a main-be tenni |
Egy pull request (20. fejezet) lezárásakor a GitHub ugyanezt a hármat kínálja: Create a merge commit (≈ --no-ff),
Squash and merge (≈ --squash) és Rebase and merge (14. fejezet).
A --squash új commitot készít, a feature ág commitjai nem kerülnek a main történetébe. A git branch -d feature ezért
figyelmeztet (not fully merged), noha a tartalom már bent van. Ilyenkor a -D a helyes választás.
A beolvasztott ág feladata véget ért, a címkéje törölhető. A commitok megmaradnak, hiszen a main története már tartalmazza őket.
PS> git branch --merged # azok az ágak, amelyek már benne vannak a mostaniban feature/galeria fix/telefon * main PS> git branch -d feature/galeria fix/telefon Deleted branch feature/galeria (was 9b2e4f1). Deleted branch fix/telefon (was 5c7d013). PS> git branch --no-merged # amelyek még NINCSENEK beolvasztva (ezeket ne töröld!)
| Helyzet | Megoldás |
|---|---|
| az összefésülés ütközéssel megállt, és inkább kiszállnál | git merge --abort: minden visszaáll a merge előtti állapotra (13. fejezet) |
| a merge elkészült, de még nem töltötted fel | git reset --hard ORIG_HEAD: az ORIG_HEAD a merge előtti helyzetet jegyzi meg (10. fejezet: reset) |
| a merge commit már fent van a GitHubon | git revert -m 1 <merge-hash>: új commit visszafordítja; a -m 1 mondja meg, hogy az első szülő (a main) a „fő” ág |
Az iskolaujsag repóban két ág vár összefésülésre: egy új hírek rovat és egy lábléc-javítás. Fésüld be őket a main-be,
készíts egy --no-ff összefésülést is, végül takarítsd el a beolvasztott ágakat. A gráf élőben mutatja a változást.
⭐ alap · ⭐⭐ haladó · ⭐⭐⭐ kihívás
Hozz létre egy ágat, commitolj rajta kétszer, és fésüld vissza a main-be! Fast-forward vagy merge commit lett? Miért? Ellenőrizd a
git log --oneline --graph --all paranccsal.
Hozz létre két ágat ugyanabból a commitból, mindkettőn módosíts egy-egy különböző fájlt, majd fésüld mindkettőt a main-be. Nézd meg a merge commitot
a git show-val: hol látszik a két szülő?
A Merge-laborban próbáld ki mind a nyolc kombinációt (2 helyzet × 4 parancs), és írd le egy mondatban mindegyik eredményét!
Ugyanabban a fájlban az egyik ágon a fájl elejét, a másikon a végét módosítsd, és fésüld össze őket. Lett ütközés? Mi az Auto-merging sor jelentése?
A GitHub Desktopban fésülj be egy ágat a Merge into current branch… ablakkal, egyszer Create a merge commit, egyszer Squash and merge móddal. Hasonlítsd össze a History fülön az eredményt!
Készíts egy összefésülést, majd vond vissza a git reset --hard ORIG_HEAD paranccsal! Ellenőrizd a git reflog-ban, mi történt.
Egy repóban ne legyen közös ős: hozz létre egy „árva” ágat (git switch --orphan uj), commitolj rajta, és próbáld a main-be fésülni.
Olvasd el a hibaüzenetet (refusing to merge unrelated histories), és nézz utána, mikor lehet szükség az --allow-unrelated-histories kapcsolóra (19. fejezet).
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 |
|---|---|
| összefésülés (merge) | egy másik ág változásainak beépítése az aktuális ágba |
| cél ág · forrás ág | ahol állsz (ide kerül a munka) · amelyet beolvasztasz |
| fast-forward | a cél ág címkéje egyszerűen előrelép, mert közben nem készült rajta új commit; nincs merge commit |
| háromutas összefésülés | a közös ős, a mi és az ő változatunk összevetése szétvált ágaknál |
| közös ős (merge base) | az utolsó commit, amely mindkét ág történetében szerepel |
| merge commit | két szülővel rendelkező commit, amely két ág történetét egyesíti |
| ours · theirs | összefésüléskor: a mi (cél, HEAD) oldalunk · a beolvasztott ág oldala |
--no-ff · --ff-only · --squash | mindig merge commit · csak fast-forward · az összes változás egy új commitba |
ORIG_HEAD | a HEAD helye egy merge vagy reset előtt; git reset --hard ORIG_HEAD visszaállít |
git branch --merged | azok az ágak, amelyek már be vannak olvasztva (biztonságosan törölhetők) |
git switch main, majd git merge feature. Csak a cél ág változik.--no-ff · --ff-only · --squash; takarítás: git branch --merged + -d;
visszavonás: --abort, reset --hard ORIG_HEAD, revert -m 1.A következő fejezetben megnézzük, mi a teendő, ha a Git nem tud dönteni: konfliktusok feloldása.