( jokeman | 2025. 01. 07., k – 10:04 )

Ahogy csardij is javasolta, valószínűleg érdemes lenne egy-két doksival vagy videóval kezdeni, lehetőleg olyannal, amiben vizuálisan is szemléltetve vannak egyes dolgok.

De röviden néhány érdemi válasz. A git szempontjából repók vannak, amik technikailag egyenrangúak, és elviekben mindig mindenkinél megvan minden history. (Ez nem teljesen igaz, mert lehet vele trükközni, de alapvetően az elképzelés)

Az, hogy a legtöbb projekt esetében vannak speciálisan kezelt repository-k, csak szervezési kérdés. Amit te "megosztott" repónak hívsz, technikailag az is egy ugyanolyan git repó, mint ami a fejlesztő saját gépén van, az csak egy projektszervezési kérdés, hogy a csapat azt tekinti "a közös munka eredményének. (És emiatt erre vannak ráállítva a CI, deployment stb. automatizmusok.) Ő tehát ilyen "egyenlők között egyenlőbb". :)

Ezek között az "egyenlő" repók között lehet "tologatni" a commitokat tetszés szerint (nyilván jogosultságok alapján, nem ész nélkül). Git esetén amúgy működik az is, hogy te megcsinálsz valamit a helyi gépeden, majd szólsz "a Jóskának", hogy nálad van egy ilyen meg ilyen branch, amire ránézhetne. Na, ő ilyenkor le tudja húzni tőled azt a branchet, tehát nem muszáj neked push-olni. (Nyilván ehhez megfelelő setup kell a te gépeden is, hogy elérje, de nem nagy truváj.)

A fentiekből is következik, hogy ha te a saját fejlesztői példányodat befrissíted egy távoli repó (remote) alapján, akkor nálad is minden meglesz, ami a távoli repóban megvan (szintén lehet vele trükközni, de ez az alapelv). Így tetszőlegesen tudsz a saját gépeden nézelődni, összehasonlítgatni más munkájában/-val is.

Viszont, hogy te épp a repository melyik branchében dolgozol, és melyik commitból kiindulva, az már a te döntésed.

Fontos, hogy amikor egy helyi könyvtárba leklónozol egy távoli repository-t, akkor alapértelmezés szerint neked abba a könyvtárba két dolog is fog kerülni.

  1. A "working tree", azaz a tényleges fájlok, amin tudsz dolgozni, és
  2. egy .git alkönyvtárban a teljes repository, ami a te saját használatú példányod. Innen tudsz checkoutolni, ide tudsz commitolni, innen tudsz távoli repóba mozgatni commitokat, és ide frissül az is, amit a távoli repóból húzol le. (Szét lehet szedni, hogy ne ugyanabban a könyvtárban legyen a working tree és a git repó, de ez a legtöbb esetben nem szükséges.)

Amire neked szükséged lesz kezdetben:

(1) Helyi (.git alkönyvtár) és távoli repó közötti műveletek:

  1. clone: távoli repó alapján üres helyi könyvtárba létrehoz repót, working tree-t
  2. fetch: távoli repóban lévő módosításokat beszinkronizálja a helyi repódba (.git könyvtár)
  3. push: helyi repóban lévő módosításokat átküldi a távoli repóba

(2) Helyi (.git alkönyvtár) repó kezelése:

  1. log: ezzel tudsz nézelődni a teljes history-ban (minden, ami megvan neked már helyileg)
  2. merge: ezzel tudod egy másik branch módosításait behúzni a saját branchedbe (hogy X branchen ki dolgozott, teljesen mindegy, a lényeg, hogy nálad meglegyen pl. fetch után). Tapasztalatom alapján a git elég ügyesen össze tudja merge-elni akár az ugyanazon fájlban lévő módosításokat, de azért nem mindenható, vannak conflictok. (Ezek feloldásához én javaslom valamilyen vizuális git eszköz használatát.)
  3. rebase: egyik branch commitjait egy másik után tudod vele fűzni. Kezdőként kicsit bonyi lehet, de érdemes tudni róla, hogy van ilyen. (Projektmenedzsment szokta eldönteni, hogy szabad-e/kell-e és milyen körülmények között használni, hitviták tárgya. :) )
  4. diff: lényegében a helyi repó két különböző állapotát (pl. két branch között mik változtak) tudod vele összehasonlítani
  5. branch: ezzel tudsz helyi branchet készíteni, branchekről infót lekérni stb.

Sok helyen találkozhatsz a pull paranccsal is, én személy szerint egyáltalán nem használom. Ez gyakorlatilag egy fetch + merge vagy egy fetch + rebase (konfigurációtól és aktuális állapottól függően).

(3) Helyi repó és working tree közötti dolgok:

  1. checkout: working tree fájljait frissíted a helyi repó egy adott commitjának megfelelő állapot alapján
  2. commit: ezzel hozol létre új commitot, amit a helyi repóban (.git) fog tárolni (onnan ugye push-sal tudod továbbküldeni)

Itt ezt egy kicsit leegyszerűsítettem, mert a helyi repó és a working tree "között" vagy egy ún. index is, amibe tudod gyűjtögetni (stage) a módosításokat, mielőtt commitolnál. Tehát pontosítva a commit nem közvetlenül a working tree-ben végzett módosításaidat tolja be a helyi repóba, hanem amit commit előtt betettél az indexbe. Ehhez kell az add parancs.

(4) Working tree-re (és indexre) vonatkozó dolgok:

  1. status: ezzel tudod lekérdezni, hogy a working treeben lévő fájljaid milyen állapotban vannak ahhoz a commithoz képest, ami alapján elkezdtél dolgozni (legutolsó checkout óta)
  2. add: working tree adott módosításait teszi be az indexbe (ahonnan majd megy a commit a helyi repóba)

Nagyjából ez a logikája az egésznek, meg persze egy halom egyéb parancs, opció stb. van, direkt nem mentem bele. Érdemes az egyes parancsok súgóit is olvasni, mert van bennük egy csomó hasznos infó.

A branchekről érdemes még annyit tudni kezdetben, hogy a git nyilván tud tartani megfeleltetéseket a saját lokális brancheid és a távoli branchek között (tracking-nek hívják itt). Ennek a lényege, hogy a távoli brancheken nem közvetlenül dolgozol, hanem "helyi példányokon". Gyakorlatban ez úgy néz ki, hogy ha pl. a "közös" repóban van egy cool-feature nevű branch, akkor az nálad egy clone vagy egy fetch után úgy fog látszódni, hogy remotes/origin/cool-feature. Ha ezt akarod checkoutolni a working tree-dbe, akkor ez úgy fog történni, hogy létrejön egy köztes helyi branch cool-feature néven, és az lesz checkoutolva, azt tudod módosítgatni szükség esetén (tehát közvetlenül a remote brancheket nem piszkálod). (Ezt úgy tudod megtenni amúgy pl., hogy git checkout -t remotes/origin/cool-feature)

Ezt csak azért írtam le, mert fogsz találkozni olyannal, hogy egy adott branch helyi változata és a távoli változat (tehát a cool-feature és a remotes/origin/cool-feature) "el lesz csúszva" egymáshoz képest, attól függően, hogy melyik változott. Ilyenkor a helyit egy merge vagy egy rebase segítségével fel lehet zárkóztatni a távolihoz (vagy ha nem volt helyi módosítás, akkor törlöd a helyi branchet, és újra checkoutolod a távolit), illetve a távolit egy push segítségével fel lehet zárkóztatni a helyihez.

Még valami: git-nél várhatóan fogsz találkozni a pull/merge request fogalmával. Ez technikailag nem a git része, hanem egy out-of-channel mechanizmus arra, hogy X fejlesztő tudja jelezni: "nekem van egy ilyen branchem, ebben ezt meg ezt csináltam, legyetek szívesek ennek a módosításait beintegrálni egy másik repóba" (jellemzően az általad "megosztottnak" nevezett repó a cél ilyenkor). Aztán ezt a requestet meg lehet köpködni minden oldalról, és amikor mindenki elégedett (LOL), akkor vagy Y fejlesztő rányom, hogy "merge", és akkor a célrepóba is bekerül, amit X fejlesztő gyártott, vagy elutasítják, és akkor vagy dolgozik még rajta vagy kuka.

Itt a lényeg, hogy a PR/MR a git szintje felett van, inkább menedzsment jellegű eszköz, mint technikai (persze ennek is van egy csomó technikai vetülete).

Röviden ennyi. :) A "hogy épülnek egymásra a commitok", "mik azok a branchek gitben", "hogyan lehet rámutatni egy branchre/commitra/egyébre" témákat meghagyom a netes doksiknak. ;)