Rezolvarea Profesionistă a Conflictelor Git: Merge 3-Way, Rebase Interactiv și Mecanismul rerere în Git

Ramuri și îmbinare Standard Git

Ghid complet de depanare și rezolvare a conflictelor de cod în Git: înțelegerea algoritmului Three-Way Merge, configurarea zdiff3, tehnici de rebase interactiv și automatizarea conflictelor recurente cu git rerere.

Sintaxă comandă
git config --global merge.conflictstyle zdiff3 | git mergetool | git rerere

Conflictele de fuziune apar atunci când doi dezvoltatori modifică aceleași linii dintr-un fișier sau când unul redenumește/șterge un fișier pe care celălalt îl modifică. În ciuda reputației de a fi frustrante, conflictele sunt modul prin care Git refuză să șteargă sau să suprascrie silențios munca unei persoane, protejând integritatea bazei de cod.

1. Anatomia unui Conflict și Algoritmul Three-Way Merge

Git nu compară doar două fișiere (versiunea ta și versiunea colegului), ci folosește un algoritm 3-Way Merge ce implică trei puncte cheie:

  1. Baza comună (Base): Cel mai recent strămoș comun al celor două ramuri (identificat automat prin git merge-base ramura-A ramura-B).
  2. Versiunea noastră (Ours / Current change): Starea fișierului pe ramura pe care vă aflați în momentul fuziunii (HEAD).
  3. Versiunea lor (Theirs / Incoming change): Starea fișierului de pe ramura pe care încercați să o integrați.

Dacă linia 40 a fost modificată doar de o parte față de baza comună, Git o integrează automat. Doar dacă ambele părți au modificat diferit linia 40 față de baza comună, Git oprește procesul și semnalează un conflict.

2. Îmbunătățirea Vizibilității Markerilor: Setarea zdiff3

În mod implicit, Git arată doar ce aveți voi și ce vine din cealaltă ramură, ascunzând codul original din strămoșul comun. Activarea stilului zdiff3 adaugă secțiunea ||||||| base, făcând decizia de rezolvare de zece ori mai ușoară:

Activare stil avansat de afișare a conflictelor
# Activare la nivel global în Git:
git config --global merge.conflictstyle zdiff3

Iată cum arată un fișier în conflict cu zdiff3:

<<<<<<< HEAD (Modificarea voastră curentă)
const MAX_ATTEMPTS = 5;
||||||| 3f8b1a9 (Codul original din strămoșul comun)
const MAX_ATTEMPTS = 3;
=======
const MAX_ATTEMPTS = Config.get('login_limit', 10);
>>>>>>> feature/dynamic-config (Modificarea colegului)

Văzând codul din mijloc (|||||||), înțelegeți imediat că valoarea inițială a fost 3, voi ați mărit-o la 5, iar colegul a refactorizat-o să citească dintr-o configurație. Rezoluția logică este combinarea ambelor idei: păstrarea configurației dinamice cu valoarea implicită 5.

3. Tehnici Rapide de Rezolvare în Terminal

Scenarii comune de rezolvare a conflictelor
# SCENARIUL 1: Vreți să abandonați complet încercarea de fuziune și să reveniți la starea curată:
git merge --abort
# sau în caz de rebase:
git rebase --abort

# SCENARIUL 2: Știți sigur că versiunea voastră este cea 100% corectă:
git checkout --ours cale/catre/fisier.json
git add cale/catre/fisier.json

# SCENARIUL 3: Știți sigur că fișierul venit din cealaltă ramură este cel dorit:
git checkout --theirs cale/catre/fisier.json
git add cale/catre/fisier.json

# SCENARIUL 4: Lansarea utilitarului grafic de mediere (VS Code, Meld sau KDiff3):
git mergetool

4. Rebase Interactiv și Curățarea Istoriei

Atunci când faceți rebase pe o ramură activă (git rebase origin/main), fiecare comitere din ramura voastră este reluată una câte una peste noul vârf al ramurii main. Dacă apare un conflict:

  1. Git întrerupe procesul la comiterea exactă care cauzează conflictul.
  2. Editați fișierul și eliminați markerii de conflict.
  3. Salvați și adăugați fișierul în staging: git add fisier.txt (Important: NU rulați git commit!).
  4. Continuați procesul cu: git rebase --continue.

5. Automatizarea Re-Rezolvării Conflictelor cu git rerere

Dacă mențineți o ramură de lungă durată pe care faceți rebase frecvent, sau dacă fuzionați periodic o ramură de test, este extrem de obositor să rezolvați manual exact aceleași conflicte de fiecare dată. Mecanismul rerere (Reuse Recorded Resolution) învață decizia luată o dată și o aplică automat în viitor:

Activarea și utilizarea rerere
# Activare globală permanentă:
git config --global rerere.enabled true

# La primul conflict:
# 1. Rezolvați conflictul în fișier și rulați git add.
# 2. La rularea comenzii git commit sau git rebase --continue,
#    Git salvează automat o amprentă (hash) a conflictului și rezoluția aleasă în .git/rr-cache/

# La următorul rebase sau merge unde apare același conflict:
# Git afișează: "Resolved 'fisier.txt' using previous resolution."
# Conflictul este rezolvat instantaneu și fără efort manual!

6. Bune Practici pentru Minimizarea Conflictelor

  • Sincronizare continuă (Rebase frecvent): Rulați în fiecare dimineață git pull --rebase origin main pe ramura activă de lucru. Rezolvarea unui conflict de 2 linii este mult mai ușoară decât rezolvarea a 50 de conflicte la sfârșitul sprintului.
  • Evitați reformatele cosmetice masive în PR-uri de logică: Nu rulați Prettier / PHP-CS-Fixer / Black pe întreg proiectul în timp ce schimbați logica de business. Schimbările de formatare trebuie izolate în comiteri separate dedicate.
  • Modularizare: Împărțiți fișierele gigantice monolitice în componente mici și independente. Două persoane care lucrează pe fișiere diferite nu vor genera niciodată conflicte.