a tidy, linear Git history

az egyik dolog, hogy figyelmen kívül hagyják sok Git alapú projektek értéke lineáris elkövetni történelem. Valójában sok eszköz és iránymutatás elriasztja a lineáris előzményeket célzó Git munkafolyamatokat. Ezt szomorúnak találom, mivel a rendezett történelem nagyon értékes, és van egy egyenes munkafolyamat, amely biztosítja a lineáris történelmet.

lineáris vs nemlineáris történelem

a lineáris történelem egyszerűen egy Git történelem, amelyben minden elkövetés egymás után következik. Azaz. nem fog találni olyan egyesülések ágak független elkövetni történetét.

1 - nemlineáris-vs-lineáris

miért akarsz lineáris történelmet?

amellett, hogy rendezett és logikus, a lineáris történelem jól jön, ha:

  • nézzük a történelmet. A nemlineáris történelmet nagyon nehéz követni-néha odáig – hogy a történelem egyszerűen érthetetlen.
  • visszalépési változások. Például: “a B hibajavítás előtt vagy után bemutatták-e a funkciót?”.
  • a hibák nyomon követése. A Git-nek van egy nagyon ügyes funkciója, az úgynevezett Git bisect, amely felhasználható arra, hogy gyorsan megtalálja, melyik elkövetés vezetett be hibát vagy regressziót. Nemlineáris történelemmel azonban a Git bisect nehezen vagy akár lehetetlenné válik.
  • a változások visszaállítása. Mondja el, hogy talált egy olyan elkötelezettséget, amely regressziót okozott, vagy el akar távolítani egy olyan funkciót, amelynek nem kellett volna megjelennie egy adott kiadásban. Némi szerencsével(ha a kód nem változott túl sokat) egyszerűen visszaállíthatja a nem kívánt elkövetést a Git revert használatával. Ha azonban nemlineáris története van, talán sok elágazási összeolvadással, ez lényegesen nehezebb lesz.

valószínűleg van még néhány olyan helyzet, amelyben a lineáris történelem nagyon értékes, attól függően, hogy hogyan használja a Git-t.

a lényeg: minél kevésbé lineáris a története, annál kevésbé értékes.

nemlineáris előzmények okai

röviden, minden egyes egyesítés elkövetése egy nemlineáris történelem potenciális forrása. Vannak azonban különböző típusú egyesítési kötelezettségvállalások.

egyesítés egy témaágból a mesterbe

ha végzett a témaággal, és integrálni szeretné a mesterbe, általános módszer a témaág egyesítése a mesterbe. Talán valami a vonalak mentén:

git checkout mastergit pullgit merge --no-ff my-topic-branch

ennek a módszernek az a jó tulajdonsága, hogy megőrzi azokat az információkat, amelyekről a kötelezettségvállalások a témaág részét képezték (alternatív megoldás az lenne, ha kihagyná a “–no-ff”-t, amely lehetővé tenné a Git számára, hogy egyesítés helyett gyors előretekerést hajtson végre, ebben az esetben nem biztos, hogy olyan világos, hogy a kötelezettségvállalások közül melyik tartozik valójában a témaághoz).

a mesterrel való egyesülés problémája akkor merül fel, amikor a témaág egy régi mesterre épül, nem pedig a mester legújabb tippjére. Ebben az esetben elkerülhetetlenül nemlineáris történelmet kap.

2 - merging-old-branch

az, hogy ez gyakori probléma lesz-e vagy sem, nagyban függ attól, hogy a Git repository mennyire aktív, hány fejlesztő dolgozik egyidejűleg stb.

egyesítés a mesterből egy témaágba

néha frissíteni szeretné az ágat, hogy megfeleljen a legújabb mesternek (pl. van néhány új funkció a master – en, amelyet be szeretne lépni a téma ágába, vagy úgy találja, hogy nem tudja egyesíteni a téma ágát a master-be, mert konfliktusok vannak).

általános módszer, amelyet egyesek még javasolnak is, a mester hegyének egyesítése a témaágba. Ez a nemlineáris történelem egyik fő forrása!

3 - összevonása-master-into-topic

a megoldás: Rebase!

a Git rebase egy nagyon hasznos funkció, amelyet akkor kell használni, ha lineáris előzményeket szeretne. Egyesek kínosnak találják az újratervezés fogalmát, de ez valóban nagyon egyszerű: replay a változások (elköveti) a fióktelep tetején egy új elkövetni.

például a GIT rebase használatával megváltoztathatja a témaág gyökerét egy régi mesterről a legújabb mester csúcsára. Feltételezve, hogy ellenőrizte a téma ágát, megteheti:

git fetch origingit rebase origin/master

4 - rebasing

vegye figyelembe, hogy a megfelelő egyesítési művelet az lenne, ha a mester hegyét egyesítené a témaágba (az előző ábrán látható módon). A témaágban lévő fájlok tartalma ugyanaz lenne, függetlenül attól, hogy újrabázist vagy egyesítést hajt végre. A történelem azonban más (lineáris vs nemlineáris!).

ez jól hangzik. Van azonban néhány figyelmeztetés a rebase-szel kapcsolatban, amelyekről tisztában kell lennie.

1.figyelmeztetés: Az újraindítás új elkötelezettségeket hoz létre

egy ág újratervezése valójában új elkötelezettségeket hoz létre. Az új elkötelezettségek eltérő SHA-val rendelkeznek:s mint a régi elkötelezett. Ez általában nem jelent problémát, de bajba kerül, ha újraindít egy olyan ágat, amely a helyi adattáron kívül létezik (például ha az ág már létezik az origin-en).

ha egy újrabázisolt ágat egy távoli adattárba helyezne, amely már tartalmazza ugyanazt az ágat (de a régi előzményekkel), akkor:

  1. git push --force-with-lease), mivel a Git nem teszi lehetővé, hogy új előzményeket toljon egy meglévő ágra. Ez hatékonyan helyettesíti az adott távoli ág előzményeit egy új előzményekkel.
  2. esetleg valaki mást nagyon boldogtalanná tesz, mivel az adott ág helyi verziója már nem egyezik a távvezérlőn lévő ággal, ami mindenféle bajhoz vezethet.

általában kerülje a távvezérlőn lévő ágak előzményeinek felülírását (az egyetlen kivétel a kódellenőrzés alatt álló ágak előzményeinek átírása – attól függően, hogy a kódellenőrző rendszer hogyan működik–, de ez egy másik vita).

ha egy távvezérlőn másokkal megosztott ágat kell újraalapoznia, egy egyszerű munkafolyamat az eredeti ág újrabázisozása helyett egy új ág létrehozása. Feltételezve, hogy my-topic-branch kijelentkezett, megteheti:

git checkout -b my-topic-branch-2git fetch origingit rebase origin/mastergit push -u origin my-topic-branch-2

…ezután mondja meg a my-topic-branch – on dolgozó embereknek, hogy folytassák a my-topic-branch-2 – et. A régi ág ekkor gyakorlatilag elavult, ezért nem szabad újra egyesíteni a mesterrel.

2.figyelmeztetés: a konfliktusok feloldása egy újrabázisban több munka lehet, mint egy egyesítés során

ha ütközést kap egy egyesítési műveletben, akkor az összes ütközést az egyesítési elkötelezettség részeként oldja meg.

azonban egy rebase műveletben potenciálisan ütközést kaphat az ág minden olyan elkötelezettségéért, amelyet újraindít.

valójában sokszor azt fogja tapasztalni, hogy ha konfliktust kap egy elkötelezettségben, akkor kapcsolódó (nagyon hasonló) konfliktusokkal találkozik a későbbi elkötelezettségekben az ágában, egyszerűen azért, mert a téma ágában elkövetett elkötelezettségek általában kapcsolatban állnak (pl. a kód ugyanazon részeinek módosítása).

a konfliktusok minimalizálásának legjobb módja az, ha nyomon követjük, mi történik a masterben, és elkerüljük, hogy egy témaág túl sokáig fusson újracsatolás nélkül. Kezelése kis konfliktusok elöl hébe-hóba könnyebb, mint kezelni őket egy nagy boldog konfliktus rendetlenség a végén.

néhány figyelmeztetés A GitHub felhasználók számára

a GitHub sok mindenben nagyszerű. Fantasztikus a Git hosting számára, és csodálatos webes felülettel rendelkezik kódböngészéssel, szép Markdown funkcióval, lényeggel stb.

a Pull requests viszont rendelkezik néhány funkcióval, amelyek aktívan meghiúsítják a lineáris Git előzményeket. Nagyon örvendetes lenne, ha a GitHub valóban megoldaná ezeket a kérdéseket, de addig tisztában kell lennie a hiányosságokkal:

a”Merge pull request” lehetővé teszi a nemlineáris fúziókat a mester

csábító lehet A zöld, barátságos megjelenésű “Merge pull request” gomb megnyomása, hogy egy téma ágat egyesítsen a mesterbe. Különösen azért, mert így szól: “ez az ág naprakész az alapággal. Az egyesítés automatikusan végrehajtható”.

GitHub merge pull request

a GitHub valójában azt mondja itt, hogy az ág konfliktus nélkül egyesíthető a mesterbe. Nem ellenőrzi, hogy a pull request ág a legújabb mesteren alapul-e vagy sem.

más szavakkal, ha lineáris előzményeket szeretne, meg kell győződnie arról, hogy a pull request ágat a legújabb mester tetejére alapozzák. Amennyire meg tudom mondani, ilyen információ nem érhető el a GitHub webes felületén keresztül (kivéve, ha “Védett ágakat” használ – lásd alább), ezért ezt a helyi Git klienstől kell megtennie.

még akkor is, ha a lekérési kérelem megfelelően újra van állítva, nincs garancia arra, hogy a GitHub webes felületén az egyesítési művelet atomi (azaz. lehet, hogy valaki a változtatásokat a master – re tolja, mielőtt az egyesítési művelet átmegy-és a GitHub nem fog panaszkodni).

tehát tényleg, az egyetlen módja annak, hogy megbizonyosodjon arról, hogy az ágak megfelelően újraalapozták tetején a legújabb mester, hogy nem a merge művelet helyben, és nyomja meg a kapott mester kézzel. Valami a vonalak mentén:

git checkout mastergit pullgit checkout my-pullrequest-branchgit rebase mastergit checkout mastergit merge --no-ff my-pullrequest-branchgit push origin master

ha szerencsétlen vagy, és valakinek sikerül a változtatásokat a mesterre tolni a pull és a push műveletek között, akkor a push művelet megtagadható. Ez azonban jó dolog, mivel garantálja, hogy működése atomi. Csak git reset --hard origin/master és ismételje meg a fenti lépéseket, amíg át nem megy.

Megjegyzés: tartsa be a projekt irányelveit w. r. t.kód felülvizsgálata és tesztelése. Például ha automatikus teszteket (buildek, statikus elemzés, egységtesztek, …) futtat egy lekérési kérelem részeként, akkor valószínűleg újra be kell nyújtania az átdolgozott ágat (akár a git push-f használatával, akár egy új PR megnyitásával), ahelyett, hogy csak manuálisan frissítené a fő ágat.

a Védett ágak funkcionalitása ösztönzi az egyesítéseket a masterből

ha Védett ágakat és állapotellenőrzéseket használ a GitHub projektben, akkor valójában védelmet kap a lekérési kérelem ágának a masterbe történő összevonásával szemben, kivéve, ha az a legújabb mesteren alapul (azt hiszem, az indoklás az, hogy a PR ágon végrehajtott állapotellenőrzéseknek továbbra is érvényesnek kell lenniük a masterbe történő összevonás után).

azonban… ha a pull request ág nem a legújabb mesteren alapul, akkor megjelenik egy barátságos gomb, az “Update branch”, a következő szöveggel: “ez az ág elavult az alapággal. Egyesítse a master legújabb változásait ebbe az ágba”.

github-update-branch

ezen a ponton a legjobb megoldás az, ha helyben újraindítja az ágat, és erő-nyomja meg a húzási kérelemhez. Feltételezve, hogy my-pullrequest-branch kijelentkezett, tegye:

git fetch origingit rebase origin/mastergit push -f

sajnos a GitHub pull kérések nem játszanak jól az erőnyomásokkal, így a kód áttekintési információinak egy része elveszhet a folyamat során. Ha ez nem elfogadható, fontolja meg egy új lekérési kérelem létrehozását (azaz helyezze át az újrabázisos ágat egy új távoli elágba, és hozzon létre egy lekérési kérelmet az új ágból).

következtetés

ha érdekel egy lineáris történelem:

  • indítsa újra a témaágat a legújabb mester tetején, mielőtt egyesítené a masterbe.
  • ne egyesítse a mestert a témaágba. Rebase helyett.
  • amikor megosztja a témakör ágát másokkal, hozzon létre egy új ágat, amikor újra kell alapoznia (my-topic-branch-2, my-topic-branch-3, …).
  • ha GitHub lekérési kérelmeket használ, vegye figyelembe:
    • az “egyesítés” gomb nem garantálja, hogy a PR-ág a legújabb mesterre épül. Szükség esetén manuálisan indítsa újra.
    • ha Védett ágakat használ állapotellenőrzéssel, soha ne nyomja meg az “ág frissítése” gombot. Ehelyett manuálisan indítsa újra.

ha nem érdekel túl sokat a lineáris Git történelem-boldog egyesülés!

Github kívánságlistája

a Githubon dolgozó finom embereknek: kérjük, adjon támogatást az újrabázisos munkafolyamatokhoz a pull kérésekben (ezek lehetnek opt-in repository opciók).

  • adja hozzá az egyesítés gomb/művelet letiltásának lehetőségét a lekérési kérésekben, ha az ág nem a legújabb mesteren alapul (ez nem igényel állapotellenőrzést).
  • adjon hozzá egy “Rebase rá legújabb mester” gombot. Sok esetben ennek konfliktusmentes műveletnek kell lennie, amely könnyen elvégezhető a webes felületen keresztül.
  • őrizze meg a lekérési előzményeket (commit, comments, …) egy újraindítás / kényszerítés után.

Leave a Reply