Pro Git ⬇ PDF
Pro Git · Eduspaces ·
https://eduspaces.ro/s/pro-git/exercitii/

Exerciții practice

60 exerciții pe capitole. Fiecare are întrebări pentru AI care te ajută să-l rezolvi singur, fără să-ți dea soluția.

🚀 1. Getting Started

de făcut

Configurează-ți identitatea și editorul

nivel 1

Ai nevoie de: Git instalat și un terminal. 1. Verifică versiunea (pentru init.defaultBranch ai nevoie de cel puțin 2.28):

git --version
  1. Setează identitatea și ramura implicită, la nivel global (pentru utilizatorul tău):
git config --global user.name "Prenume Nume"
git config --global user.email "adresa@exemplu.ro"
git config --global init.defaultBranch main
git config --global core.editor "nano"     # sau "code --wait", "vim"
  1. Afișează toate setările și fișierul din care vine fiecare: git config --list --show-origin.
  2. Creează un depozit de test (mkdir test-config && cd test-config && git init) și setează doar aici un alt e-mail: git config user.email "student@facultate.ro".
  3. Rulează în acest depozit git config --show-origin user.email, apoi ieși din el (cd ..) și rulează din nou.

Ce trebuie să obții: identitatea globală salvată și înțelegerea ordinii în care Git citește nivelurile --system, --global și --local.

Cum îți verifici singur rezultatul
  • git config --list --show-origin arată liniile user.name=…, user.email=…, init.defaultbranch=main cu sursa file:/Users/<tu>/.gitconfig (pe Windows C:/Users/<tu>/.gitconfig).
  • În depozitul de test, git config --show-origin user.email afișează file:.git/config student@facultate.ro: nivelul local îl suprascrie pe cel global. În afara depozitului vezi din nou adresa globală.
  • cat .git/config în depozitul de test conține o secțiune [user] cu e-mailul local.

Întreabă AI-ul ca să înveți

Copiază o întrebare într-un asistent AI. Sunt scrise ca AI-ul să te pună să gândești și să-ți dea indicii, nu răspunsul gata făcut.

Ce nivel câștigăprezici prioritatea setărilor înainte de pasul 5

Lucrez la exercițiul „Configurează-ți identitatea și editorul” din capitolul „1. Getting Started”, la Pro Git. Enunțul: Ai nevoie de: Git instalat și un terminal. 1. Verifică versiunea (pentru `init.defaultBranch` ai nevoie de cel puțin 2.28): ```bash git --version ``` 2. Setează identitatea și ramura implicită, la nivel global (pentru utilizatorul tău): ```bash git config --global user.name "Prenume Nume" git config --global user.email "adresa@exemplu.ro" git config --global init.defaultBranch main git config --global core.editor "nano" # sau "code --wait", "vim" ``` 3. Afișează toate setările și fișierul din care vine fiecare: `git config --list --show-origin`. 4. Creează un depozit de test (`mkdir test-config && cd test-config && git init`) și setează **doar aici** un alt e-mail: `git config user.email… Înainte de pasul 5, întreabă-mă ce valoare cred că va afișa `git config user.email` în depozitul de test și în afara lui și de ce. Nu-mi spune răspunsul; după ce rulez comenzile, ajută-mă să explic ordinea system → global → local cu propriile cuvinte.

Deschide în Claude ↗
Indicii dacă ceva nu mergedepanezi o configurare greșită

Lucrez la exercițiul „Configurează-ți identitatea și editorul” din capitolul „1. Getting Started”, la Pro Git. Enunțul: Ai nevoie de: Git instalat și un terminal. 1. Verifică versiunea (pentru `init.defaultBranch` ai nevoie de cel puțin 2.28): ```bash git --version ``` 2. Setează identitatea și ramura implicită, la nivel global (pentru utilizatorul tău): ```bash git config --global user.name "Prenume Nume" git config --global user.email "adresa@exemplu.ro" git config --global init.defaultBranch main git config --global core.editor "nano" # sau "code --wait", "vim" ``` 3. Afișează toate setările și fișierul din care vine fiecare: `git config --list --show-origin`. 4. Creează un depozit de test (`mkdir test-config && cd test-config && git init`) și setează **doar aici** un alt e-mail: `git config user.email… Îți lipesc ce afișează `git config --list --show-origin`. Verifică-mi dacă identitatea și ramura implicită sunt setate corect și, dacă găsești o problemă (dublură, greșeală de tipar, nivel greșit), dă-mi un indiciu despre ce comandă să folosesc, fără să-mi scrii direct comanda corectă.

Deschide în Claude ↗
de făcut

Primul depozit și ce se află în .git

nivel 1
  1. Creează un depozit gol și uită-te în directorul Git:
mkdir -p ~/git-exercitii/primul && cd ~/git-exercitii/primul
git init
ls -A .git
cat .git/HEAD
git status
  1. Creează un fișier, apoi rulează git status după fiecare pas:
echo "# Primul meu proiect" > README.md
git status
git add README.md
git status
git commit -m "Adaug README"
git status
git log
  1. Numără obiectele salvate de Git: find .git/objects -type f.

Ce urmărești: ce creează git init, cum se schimbă mesajul lui git status și câte obiecte apar în baza de date după primul commit cu un singur fișier.

Cum îți verifici singur rezultatul
  • ls -A .git arată cel puțin HEAD config description hooks info objects refs; cat .git/HEAD → ref: refs/heads/main.
  • Înainte de commit: No commits yet, apoi Untracked files: README.md, apoi Changes to be committed: new file: README.md.
  • După commit: nothing to commit, working tree clean, iar git log arată un commit cu numele tău.
  • find .git/objects -type f listează 3 obiecte: un blob (conținutul README), un tree (directorul) și un commit.

Întreabă AI-ul ca să înveți

Copiază o întrebare într-un asistent AI. Sunt scrise ca AI-ul să te pună să gândești și să-ți dea indicii, nu răspunsul gata făcut.

Ce conține .gitînțelegi rolul fiecărui element din .git

Lucrez la exercițiul „Primul depozit și ce se află în .git” din capitolul „1. Getting Started”, la Pro Git. Enunțul: 1. Creează un depozit gol și uită-te în directorul Git: ```bash mkdir -p ~/git-exercitii/primul && cd ~/git-exercitii/primul git init ls -A .git cat .git/HEAD git status ``` 2. Creează un fișier, apoi rulează `git status` după fiecare pas: ```bash echo "# Primul meu proiect" > README.md git status git add README.md git status git commit -m "Adaug README" git status git log ``` 3. Numără obiectele salvate de Git: `find .git/objects -type f`. **Ce urmărești:** ce creează `git init`, cum se schimbă mesajul lui `git status` și câte obiecte apar în baza de date după primul commit cu un singur fișier. Îți lipesc ce afișează `ls -A .git`. Întreabă-mă, pe rând, ce cred că face fiecare element (HEAD, config, objects, refs) și corectează-mă doar după ce încerc să răspund. Dă-mi indicii din capitolul despre directorul Git, nu explicația completă de la început.

Deschide în Claude ↗
De ce trei obiecteexplici obiectele create de primul commit

Lucrez la exercițiul „Primul depozit și ce se află în .git” din capitolul „1. Getting Started”, la Pro Git. Enunțul: 1. Creează un depozit gol și uită-te în directorul Git: ```bash mkdir -p ~/git-exercitii/primul && cd ~/git-exercitii/primul git init ls -A .git cat .git/HEAD git status ``` 2. Creează un fișier, apoi rulează `git status` după fiecare pas: ```bash echo "# Primul meu proiect" > README.md git status git add README.md git status git commit -m "Adaug README" git status git log ``` 3. Numără obiectele salvate de Git: `find .git/objects -type f`. **Ce urmărești:** ce creează `git init`, cum se schimbă mesajul lui `git status` și câte obiecte apar în baza de date după primul commit cu un singur fișier. După primul commit am găsit trei fișiere în .git/objects. Lasă-mă să ghicesc ce reprezintă fiecare și pune-mi întrebări ajutătoare (ce salvează Git pentru conținut, pentru director, pentru commit) până ajung singur la răspuns. Nu-mi spune direct.

Deschide în Claude ↗
întrebare de gândit

Unde se află fiecare versiune a fișierului?

nivel 2

Pentru secvența de mai jos, scrie pe hârtie, înainte să rulezi, pentru fiecare pas: ce versiune a lui nota.txt este în directorul de lucru, ce versiune este în staging area și ce versiune este în ultimul commit, precum și ce va afișa git status -s.

git init stari && cd stari
echo "v1" > nota.txt          # pasul 1
git add nota.txt              # pasul 2
echo "v2" >> nota.txt         # pasul 3
git commit -m "Prima notă"    # pasul 4
git add nota.txt              # pasul 5
git commit -m "A doua notă"   # pasul 6

Apoi rulează pașii unul câte unul, cu git status -s și git show HEAD:nota.txt după fiecare, și compară. Răspunde la final: ce a intrat în commitul de la pasul 4 și de ce? Ce înseamnă că Git salvează instantanee (snapshots), nu diferențe?

Cum îți verifici singur rezultatul
  • Pasul 1: ?? nota.txt; pasul 2: A nota.txt; pasul 3: AM nota.txt (în staging e v1, în lucru v1+v2); pasul 4: M nota.txt; pasul 5: M nota.txt; pasul 6: nimic (curat).
  • Commitul de la pasul 4 conține doar linia v1: git commit salvează ce este în staging area, nu ce este în directorul de lucru.
  • Fiecare commit indică un instantaneu complet al proiectului; fișierele nemodificate sunt doar legături către blob-ul deja salvat.

Întreabă AI-ul ca să înveți

Copiază o întrebare într-un asistent AI. Sunt scrise ca AI-ul să te pună să gândești și să-ți dea indicii, nu răspunsul gata făcut.

Verifică-mi predicțiilecompari tabelul tău cu ce afișează Git

Lucrez la exercițiul „Unde se află fiecare versiune a fișierului?” din capitolul „1. Getting Started”, la Pro Git. Enunțul: Pentru secvența de mai jos, scrie pe hârtie, **înainte să rulezi**, pentru fiecare pas: ce versiune a lui `nota.txt` este în directorul de lucru, ce versiune este în staging area și ce versiune este în ultimul commit, precum și ce va afișa `git status -s`. ```bash git init stari && cd stari echo "v1" > nota.txt # pasul 1 git add nota.txt # pasul 2 echo "v2" >> nota.txt # pasul 3 git commit -m "Prima notă" # pasul 4 git add nota.txt # pasul 5 git commit -m "A doua notă" # pasul 6 ``` Apoi rulează pașii unul câte unul, cu `git status -s` și `git show HEAD:nota.txt` după fiecare, și compară. Răspunde la final: ce a intrat în commitul de la pasul 4 și de ce? Ce înseamnă că Git salvează… Îți scriu predicțiile mele pentru fiecare pas (director de lucru, staging, commit, `git status -s`). Verifică unde am greșit și, pentru fiecare greșeală, pune-mi o întrebare care să mă facă să-mi dau seama singur, în loc să-mi dai răspunsul corect.

Deschide în Claude ↗
Instantanee sau diferențeexplici diferența dintre modelul Git și cel cu delte

Lucrez la exercițiul „Unde se află fiecare versiune a fișierului?” din capitolul „1. Getting Started”, la Pro Git. Enunțul: Pentru secvența de mai jos, scrie pe hârtie, **înainte să rulezi**, pentru fiecare pas: ce versiune a lui `nota.txt` este în directorul de lucru, ce versiune este în staging area și ce versiune este în ultimul commit, precum și ce va afișa `git status -s`. ```bash git init stari && cd stari echo "v1" > nota.txt # pasul 1 git add nota.txt # pasul 2 echo "v2" >> nota.txt # pasul 3 git commit -m "Prima notă" # pasul 4 git add nota.txt # pasul 5 git commit -m "A doua notă" # pasul 6 ``` Apoi rulează pașii unul câte unul, cu `git status -s` și `git show HEAD:nota.txt` după fiecare, și compară. Răspunde la final: ce a intrat în commitul de la pasul 4 și de ce? Ce înseamnă că Git salvează… Vreau să explic cu cuvintele mele de ce Git e descris ca un sistem cu instantanee, nu cu diferențe. Întreabă-mă cum aș desena trei commituri în ambele modele și dă-mi indicii dacă amestec ideile; nu scrie tu explicația.

Deschide în Claude ↗
de făcut

Fiecare clonă e o copie completă

nivel 2

Demonstrează practic de ce un sistem distribuit nu are un single point of failure. 1. Creează un depozit „server” cu câteva commituri:

mkdir -p ~/git-exercitii/distribuit && cd ~/git-exercitii/distribuit
git init server && cd server
for i in 1 2 3; do echo "pas $i" >> jurnal.txt; git add .; git commit -m "Pasul $i"; done
cd ..
  1. Clonează-l: git clone server laptop.
  2. „Serverul a ars”: rm -rf server.
  3. În laptop verifică istoria (git log --oneline) și refă serverul dintr-o clonă: cd .. && git clone --bare laptop/.git server-nou.git.
  4. Clonează serverul nou într-un al treilea loc și verifică din nou istoria.

Întrebare: ce s-ar fi pierdut dacă proiectul era într-un sistem centralizat (de ex. Subversion) și serverul dispărea, iar pe laptop aveai doar o copie de lucru (checkout)?

Cum îți verifici singur rezultatul
  • După ștergerea serverului, git log --oneline în laptop arată toate cele trei commituri (Pasul 3, Pasul 2, Pasul 1).
  • Clona făcută din server-nou.git are aceeași istorie, cu aceleași hash-uri.
  • Într-un sistem centralizat clientul are doar ultima versiune a fișierelor; istoria completă trăiește pe server, deci s-ar fi pierdut.

Întreabă AI-ul ca să înveți

Copiază o întrebare într-un asistent AI. Sunt scrise ca AI-ul să te pună să gândești și să-ți dea indicii, nu răspunsul gata făcut.

Prezic ce rămâneprezici efectul ștergerii serverului

Lucrez la exercițiul „Fiecare clonă e o copie completă” din capitolul „1. Getting Started”, la Pro Git. Enunțul: Demonstrează practic de ce un sistem distribuit nu are un *single point of failure*. 1. Creează un depozit „server” cu câteva commituri: ```bash mkdir -p ~/git-exercitii/distribuit && cd ~/git-exercitii/distribuit git init server && cd server for i in 1 2 3; do echo "pas $i" >> jurnal.txt; git add .; git commit -m "Pasul $i"; done cd .. ``` 2. Clonează-l: `git clone server laptop`. 3. „Serverul a ars”: `rm -rf server`. 4. În `laptop` verifică istoria (`git log --oneline`) și refă serverul dintr-o clonă: `cd .. && git clone --bare laptop/.git server-nou.git`. 5. Clonează serverul nou într-un al treilea loc și verifică din nou istoria. **Întrebare:** ce s-ar fi pierdut dacă proiectul era… Înainte de pasul 3, întreabă-mă ce cred că va mai afișa `git log` în `laptop` după ce șterg serverul și ce s-ar întâmpla în cazul unui sistem centralizat. Nu-mi confirma nimic până nu rulez comenzile; apoi verifică-mi explicația.

Deschide în Claude ↗
Compar cele trei modelecompari VCS local, centralizat și distribuit

Lucrez la exercițiul „Fiecare clonă e o copie completă” din capitolul „1. Getting Started”, la Pro Git. Enunțul: Demonstrează practic de ce un sistem distribuit nu are un *single point of failure*. 1. Creează un depozit „server” cu câteva commituri: ```bash mkdir -p ~/git-exercitii/distribuit && cd ~/git-exercitii/distribuit git init server && cd server for i in 1 2 3; do echo "pas $i" >> jurnal.txt; git add .; git commit -m "Pasul $i"; done cd .. ``` 2. Clonează-l: `git clone server laptop`. 3. „Serverul a ars”: `rm -rf server`. 4. În `laptop` verifică istoria (`git log --oneline`) și refă serverul dintr-o clonă: `cd .. && git clone --bare laptop/.git server-nou.git`. 5. Clonează serverul nou într-un al treilea loc și verifică din nou istoria. **Întrebare:** ce s-ar fi pierdut dacă proiectul era… Ajută-mă să fac un tabel cu sistemele locale (RCS), centralizate și distribuite: unde se află istoria, ce se întâmplă dacă pică serverul, cum lucrezi offline. Pune-mi întrebări pentru fiecare celulă și corectează-mă cu indicii, nu completa tu tabelul.

Deschide în Claude ↗

🧱 2. Git Basics

de făcut

Ciclul de viață al fișierelor, văzut cu git status -s

nivel 1

Scrie înainte de fiecare git status -s ce crezi că va afișa, apoi rulează.

git init ciclu && cd ciclu
echo "# Proiect" > README.md
echo a > a.txt
git status -s                 # 1
git add README.md
git status -s                 # 2
echo b >> README.md
git status -s                 # 3
git add .
git commit -m "Primul commit"
echo c >> a.txt
git status -s                 # 4
git add a.txt
git status -s                 # 5
echo d >> a.txt
git status -s                 # 6
git diff                      # 7
git diff --staged             # 8

Ce trebuie să obții: să poți citi cele două coloane ale formatului scurt (staging / director de lucru) și să știi ce compară git diff față de git diff --staged.

Cum îți verifici singur rezultatul

1: ?? README.md și ?? a.txt; 2: A README.md; 3: AM README.md; 4: M a.txt; 5: M a.txt; 6: MM a.txt. 7: git diff arată doar +d (lucru față de staging); 8: git diff --staged arată doar +c (staging față de ultimul commit).

Întreabă AI-ul ca să înveți

Copiază o întrebare într-un asistent AI. Sunt scrise ca AI-ul să te pună să gândești și să-ți dea indicii, nu răspunsul gata făcut.

Citesc coloaneleinterpretezi codurile din git status -s

Lucrez la exercițiul „Ciclul de viață al fișierelor, văzut cu git status -s” din capitolul „2. Git Basics”, la Pro Git. Enunțul: Scrie înainte de fiecare `git status -s` ce crezi că va afișa, apoi rulează. ```bash git init ciclu && cd ciclu echo "# Proiect" > README.md echo a > a.txt git status -s # 1 git add README.md git status -s # 2 echo b >> README.md git status -s # 3 git add . git commit -m "Primul commit" echo c >> a.txt git status -s # 4 git add a.txt git status -s # 5 echo d >> a.txt git status -s # 6 git diff # 7 git diff --staged # 8 ``` **Ce trebuie să obții:** să poți citi cele două coloane ale formatului scurt (staging / director de lucru) și să știi ce compară `git diff` față de `git diff --staged`. Îți dau rezultatele mele pentru `git status -s` la pașii 1–6. Întreabă-mă ce înseamnă fiecare coloană și fiecare literă și corectează-mă cu indicii, fără să-mi explici tu de la început tabelul complet.

Deschide în Claude ↗
diff sau diff --stageddeosebești cele două comparații

Lucrez la exercițiul „Ciclul de viață al fișierelor, văzut cu git status -s” din capitolul „2. Git Basics”, la Pro Git. Enunțul: Scrie înainte de fiecare `git status -s` ce crezi că va afișa, apoi rulează. ```bash git init ciclu && cd ciclu echo "# Proiect" > README.md echo a > a.txt git status -s # 1 git add README.md git status -s # 2 echo b >> README.md git status -s # 3 git add . git commit -m "Primul commit" echo c >> a.txt git status -s # 4 git add a.txt git status -s # 5 echo d >> a.txt git status -s # 6 git diff # 7 git diff --staged # 8 ``` **Ce trebuie să obții:** să poți citi cele două coloane ale formatului scurt (staging / director de lucru) și să știi ce compară `git diff` față de `git diff --staged`. Nu înțeleg de ce `git diff` și `git diff --staged` afișează linii diferite la pașii 7 și 8. Pune-mi întrebări despre cele trei locuri (director de lucru, staging, commit) până îmi dau seama singur ce compară fiecare.

Deschide în Claude ↗
de făcut

.gitignore, git rm --cached și git mv

nivel 1

Continuă în depozitul ciclu (sau în orice depozit de test cu un commit). 1. Creează fișiere care nu trebuie urmărite și un .gitignore:

printf '*.log\nbuild/\n!important.log\n' > .gitignore
touch eroare.log important.log
mkdir build && touch build/out.o
git status -s
git status -s --ignored
git check-ignore -v eroare.log build/out.o
  1. Fă commit cu .gitignore și important.log.
  2. Redenumește un fișier cu Git și scoate un fișier de sub urmărire fără să-l ștergi de pe disc:
git mv a.txt b.txt
git rm --cached important.log
git status -s
git commit -m "Redenumesc a.txt; nu mai urmăresc important.log"
ls
Cum îți verifici singur rezultatul
  • Pasul 1: git status -s arată doar ?? .gitignore și ?? important.log; cu --ignored apar și !! build/ și !! eroare.log. check-ignore -v indică regula: .gitignore:1:*.log eroare.log și .gitignore:2:build/ build/out.o.
  • Pasul 3: R a.txt -> b.txt, D important.log și ?? important.log (fișierul e încă pe disc, dar nu mai e urmărit; ls îl arată).

Întreabă AI-ul ca să înveți

Copiază o întrebare într-un asistent AI. Sunt scrise ca AI-ul să te pună să gândești și să-ți dea indicii, nu răspunsul gata făcut.

Șabloane globîți verifici regulile din .gitignore

Lucrez la exercițiul „.gitignore, git rm --cached și git mv” din capitolul „2. Git Basics”, la Pro Git. Enunțul: Continuă în depozitul `ciclu` (sau în orice depozit de test cu un commit). 1. Creează fișiere care nu trebuie urmărite și un `.gitignore`: ```bash printf '*.log\nbuild/\n!important.log\n' > .gitignore touch eroare.log important.log mkdir build && touch build/out.o git status -s git status -s --ignored git check-ignore -v eroare.log build/out.o ``` 2. Fă commit cu `.gitignore` și `important.log`. 3. Redenumește un fișier cu Git și scoate un fișier de sub urmărire fără să-l ștergi de pe disc: ```bash git mv a.txt b.txt git rm --cached important.log git status -s git commit -m "Redenumesc a.txt; nu mai urmăresc important.log" ls ``` Vreau să scriu un .gitignore pentru un proiect cu fișiere `*.tmp`, un director `node_modules/` și un singur fișier `config.example.tmp` care trebuie păstrat. Lasă-mă să încerc singur regulile, apoi verifică-le și dă-mi indicii dacă vreuna nu face ce cred.

Deschide în Claude ↗
rm sau rm --cacheddeosebești cele două forme

Lucrez la exercițiul „.gitignore, git rm --cached și git mv” din capitolul „2. Git Basics”, la Pro Git. Enunțul: Continuă în depozitul `ciclu` (sau în orice depozit de test cu un commit). 1. Creează fișiere care nu trebuie urmărite și un `.gitignore`: ```bash printf '*.log\nbuild/\n!important.log\n' > .gitignore touch eroare.log important.log mkdir build && touch build/out.o git status -s git status -s --ignored git check-ignore -v eroare.log build/out.o ``` 2. Fă commit cu `.gitignore` și `important.log`. 3. Redenumește un fișier cu Git și scoate un fișier de sub urmărire fără să-l ștergi de pe disc: ```bash git mv a.txt b.txt git rm --cached important.log git status -s git commit -m "Redenumesc a.txt; nu mai urmăresc important.log" ls ``` Întreabă-mă ce cred că se întâmplă cu fișierul pe disc și în următorul commit la `git rm` și la `git rm --cached`. Corectează-mă pe baza rezultatelor mele din `git status -s`, fără să-mi dai direct definițiile.

Deschide în Claude ↗
de făcut

Repară un commit și anulează modificări

nivel 2

Într-un depozit de test cu cel puțin un commit: 1. Ai uitat un fișier în ultimul commit:

echo "linie" > note.txt
git add note.txt
git commit -m "Adaug notițe"
echo "uitat" > uitat.txt
git add uitat.txt
git commit --amend -m "Adaug notițe și fișierul uitat"
git log --oneline -2
git show --stat HEAD
  1. Ai pus în staging ceva greșit:
echo "greșit" >> README.md
git add README.md
git status -s
git restore --staged README.md
git status -s
  1. Renunță complet la modificare: git restore README.md, apoi git status -s.

Atenție: git restore <fișier> șterge definitiv modificările necomise din acel fișier.

Cum îți verifici singur rezultatul
  • După --amend există un singur commit „Adaug notițe și fișierul uitat” (nu două), iar git show --stat listează note.txt și uitat.txt. Hash-ul s-a schimbat față de commitul inițial.
  • Pasul 2: întâi M README.md, după restore --staged devine M README.md.
  • Pasul 3: README.md nu mai apare în git status -s; cat README.md nu mai conține „greșit”.

Întreabă AI-ul ca să înveți

Copiază o întrebare într-un asistent AI. Sunt scrise ca AI-ul să te pună să gândești și să-ți dea indicii, nu răspunsul gata făcut.

Ce face --amend de faptînțelegi că amend înlocuiește commitul

Lucrez la exercițiul „Repară un commit și anulează modificări” din capitolul „2. Git Basics”, la Pro Git. Enunțul: Într-un depozit de test cu cel puțin un commit: 1. Ai uitat un fișier în ultimul commit: ```bash echo "linie" > note.txt git add note.txt git commit -m "Adaug notițe" echo "uitat" > uitat.txt git add uitat.txt git commit --amend -m "Adaug notițe și fișierul uitat" git log --oneline -2 git show --stat HEAD ``` 2. Ai pus în staging ceva greșit: ```bash echo "greșit" >> README.md git add README.md git status -s git restore --staged README.md git status -s ``` 3. Renunță complet la modificare: `git restore README.md`, apoi `git status -s`. **Atenție:** `git restore ` șterge definitiv modificările necomise din acel fișier. Am observat că după `git commit --amend` hash-ul ultimului commit s-a schimbat. Întreabă-mă ce cred că s-a întâmplat cu vechiul commit și de ce nu e bine să fac amend la un commit deja trimis pe server. Dă-mi indicii, nu răspunsul.

Deschide în Claude ↗
Alege comanda potrivităalegi între restore, restore --staged și amend

Lucrez la exercițiul „Repară un commit și anulează modificări” din capitolul „2. Git Basics”, la Pro Git. Enunțul: Într-un depozit de test cu cel puțin un commit: 1. Ai uitat un fișier în ultimul commit: ```bash echo "linie" > note.txt git add note.txt git commit -m "Adaug notițe" echo "uitat" > uitat.txt git add uitat.txt git commit --amend -m "Adaug notițe și fișierul uitat" git log --oneline -2 git show --stat HEAD ``` 2. Ai pus în staging ceva greșit: ```bash echo "greșit" >> README.md git add README.md git status -s git restore --staged README.md git status -s ``` 3. Renunță complet la modificare: `git restore README.md`, apoi `git status -s`. **Atenție:** `git restore ` șterge definitiv modificările necomise din acel fișier. Dă-mi pe rând 4 situații scurte (fișier pus greșit în staging, modificare de aruncat, mesaj de commit greșit, fișier uitat) și lasă-mă să aleg comanda. Verifică-mi alegerea și explică-mi doar după ce încerc.

Deschide în Claude ↗
de făcut

Caută în istorie cu git log

nivel 2

Folosește un depozit cu mai multe commituri (de ex. ciclu). Fă încă două-trei commituri, într-unul adăugând textul parola_temporara într-un fișier, iar în următorul ștergându-l. 1. Formate de afișare:

git log --oneline
git log -p -1
git log --stat
git log --pretty=format:"%h - %an, %ar : %s"
  1. Filtre: git log --since="1 hour ago", git log --author="<numele tău>", git log -- README.md.
  2. Găsește commiturile care au adăugat sau au șters textul: git log -S parola_temporara --oneline.
  3. Creează un alias și folosește-l:
git config --global alias.lg "log --oneline --graph --all --decorate"
git lg

Ce trebuie să obții: comanda care îți arată exact commiturile ce au introdus și au eliminat textul.

Cum îți verifici singur rezultatul
  • --pretty=format afișează câte o linie de forma a1b2c3d - Prenume Nume, 5 minutes ago : mesaj.
  • git log -S parola_temporara --oneline afișează exact două commituri: cel care a adăugat textul și cel care l-a șters.
  • git lg afișează graful, cu (HEAD -> main) lângă ultimul commit; aliasul apare în git config --global --list.

Întreabă AI-ul ca să înveți

Copiază o întrebare într-un asistent AI. Sunt scrise ca AI-ul să te pună să gândești și să-ți dea indicii, nu răspunsul gata făcut.

Construiesc filtrulcompui singur o comandă git log

Lucrez la exercițiul „Caută în istorie cu git log” din capitolul „2. Git Basics”, la Pro Git. Enunțul: Folosește un depozit cu mai multe commituri (de ex. `ciclu`). Fă încă două-trei commituri, într-unul adăugând textul `parola_temporara` într-un fișier, iar în următorul ștergându-l. 1. Formate de afișare: ```bash git log --oneline git log -p -1 git log --stat git log --pretty=format:"%h - %an, %ar : %s" ``` 2. Filtre: `git log --since="1 hour ago"`, `git log --author=""`, `git log -- README.md`. 3. Găsește commiturile care au adăugat sau au șters textul: `git log -S parola_temporara --oneline`. 4. Creează un alias și folosește-l: ```bash git config --global alias.lg "log --oneline --graph --all --decorate" git lg ``` **Ce trebuie să obții:** comanda care îți arată exact commiturile ce au… Vreau să găsesc commiturile mele din ultima săptămână care au modificat un anumit fișier. Întreabă-mă ce opțiuni cred că trebuie combinate și lasă-mă să încerc; dă-mi indicii din `git help log` dacă mă blochez.

Deschide în Claude ↗
-S față de grepdeosebești căutarea în conținut de căutarea în mesaje

Lucrez la exercițiul „Caută în istorie cu git log” din capitolul „2. Git Basics”, la Pro Git. Enunțul: Folosește un depozit cu mai multe commituri (de ex. `ciclu`). Fă încă două-trei commituri, într-unul adăugând textul `parola_temporara` într-un fișier, iar în următorul ștergându-l. 1. Formate de afișare: ```bash git log --oneline git log -p -1 git log --stat git log --pretty=format:"%h - %an, %ar : %s" ``` 2. Filtre: `git log --since="1 hour ago"`, `git log --author=""`, `git log -- README.md`. 3. Găsește commiturile care au adăugat sau au șters textul: `git log -S parola_temporara --oneline`. 4. Creează un alias și folosește-l: ```bash git config --global alias.lg "log --oneline --graph --all --decorate" git lg ``` **Ce trebuie să obții:** comanda care îți arată exact commiturile ce au… Pune-mi întrebări ca să-mi dau seama singur care e diferența dintre `git log -S text` și `git log --grep=text`. Verifică-mi apoi răspunsul cu un exemplu pe care îl rulez eu.

Deschide în Claude ↗
de făcut

Taguri și un remote local, fără cont online

nivel 2

Într-un depozit de test cu cel puțin 3 commituri: 1. Creează un tag ușor pe un commit mai vechi și unul adnotat pe ultimul:

git tag v0.1 HEAD~2
git tag -a v1.0 -m "Versiunea 1.0"
git tag
git cat-file -t v0.1
git cat-file -t v1.0
git show v1.0 --no-patch
  1. Creează un „server” local (un depozit bare) și adaugă-l ca remote:
git init --bare ../server.git
git remote add origin ../server.git
git remote -v
git push -u origin main
git ls-remote origin
  1. Trimite și tagurile: git push origin --tags, apoi git ls-remote origin din nou.
  2. Clonează serverul în alt director (git clone ../server.git ../coleg) și verifică git tag acolo.
Cum îți verifici singur rezultatul
  • git cat-file -t v0.1 → commit (tagul ușor e doar un pointer); git cat-file -t v1.0 → tag (obiect separat, cu Tagger:, dată și mesaj, vizibile în git show).
  • După git push -u origin main: branch 'main' set up to track 'origin/main'; ls-remote arată doar HEAD și refs/heads/main — tagurile nu pleacă implicit.
  • După --tags: apar refs/tags/v0.1, refs/tags/v1.0 și refs/tags/v1.0^{} (commitul spre care arată tagul adnotat).
  • În clona coleg, git tag listează v0.1 și v1.0.

Întreabă AI-ul ca să înveți

Copiază o întrebare într-un asistent AI. Sunt scrise ca AI-ul să te pună să gândești și să-ți dea indicii, nu răspunsul gata făcut.

Tag ușor sau adnotatalegi tipul de tag potrivit

Lucrez la exercițiul „Taguri și un remote local, fără cont online” din capitolul „2. Git Basics”, la Pro Git. Enunțul: Într-un depozit de test cu cel puțin 3 commituri: 1. Creează un tag ușor pe un commit mai vechi și unul adnotat pe ultimul: ```bash git tag v0.1 HEAD~2 git tag -a v1.0 -m "Versiunea 1.0" git tag git cat-file -t v0.1 git cat-file -t v1.0 git show v1.0 --no-patch ``` 2. Creează un „server” local (un depozit bare) și adaugă-l ca remote: ```bash git init --bare ../server.git git remote add origin ../server.git git remote -v git push -u origin main git ls-remote origin ``` 3. Trimite și tagurile: `git push origin --tags`, apoi `git ls-remote origin` din nou. 4. Clonează serverul în alt director (`git clone ../server.git ../coleg`) și verifică `git tag` acolo. Întreabă-mă ce diferențe am observat între `v0.1` și `v1.0` la `git cat-file -t` și `git show`, apoi pune-mi o situație (lansarea unei versiuni publice, un semn de carte personal) și lasă-mă să aleg tipul de tag. Verifică-mi alegerea.

Deschide în Claude ↗
De ce nu apar tagurileînțelegi ce trimite git push implicit

Lucrez la exercițiul „Taguri și un remote local, fără cont online” din capitolul „2. Git Basics”, la Pro Git. Enunțul: Într-un depozit de test cu cel puțin 3 commituri: 1. Creează un tag ușor pe un commit mai vechi și unul adnotat pe ultimul: ```bash git tag v0.1 HEAD~2 git tag -a v1.0 -m "Versiunea 1.0" git tag git cat-file -t v0.1 git cat-file -t v1.0 git show v1.0 --no-patch ``` 2. Creează un „server” local (un depozit bare) și adaugă-l ca remote: ```bash git init --bare ../server.git git remote add origin ../server.git git remote -v git push -u origin main git ls-remote origin ``` 3. Trimite și tagurile: `git push origin --tags`, apoi `git ls-remote origin` din nou. 4. Clonează serverul în alt director (`git clone ../server.git ../coleg`) și verifică `git tag` acolo. După primul push, tagurile nu apăreau pe server. Nu-mi spune direct de ce; dă-mi indicii despre ce trimite `git push origin main` și ce înseamnă linia cu `^{}` din `git ls-remote`.

Deschide în Claude ↗

🌿 3. Git Branching

de făcut

O ramură hotfix și un merge fast-forward

nivel 1
git init ramuri && cd ramuri
echo "Salut" > index.html; git add .; git commit -m "C0: pagina"
echo "<p>meniu</p>" >> index.html; git commit -am "C1: meniu"
git switch -c hotfix
echo "footer" > footer.html; git add .; git commit -m "C2: footer"
git log --oneline --decorate --all
git switch main
ls
git merge hotfix
git branch -d hotfix
git log --oneline --graph

Răspunde: unde arată HEAD înainte și după git switch main? De ce footer.html dispare din director după switch și reapare după merge? De ce merge-ul nu creează un commit nou?

Cum îți verifici singur rezultatul
  • Înainte de switch main: C2: footer are (HEAD -> hotfix), iar C1: meniu are (main).
  • După switch main, ls nu mai arată footer.html (directorul reflectă commitul C1).
  • git merge hotfix afișează Updating … și Fast-forward; main doar avansează până la C2.
  • git branch -d hotfix → Deleted branch hotfix (was …); graful final e o linie: C2, C1, C0.

Întreabă AI-ul ca să înveți

Copiază o întrebare într-un asistent AI. Sunt scrise ca AI-ul să te pună să gândești și să-ți dea indicii, nu răspunsul gata făcut.

Desenez pointeriiurmărești HEAD și ramurile pas cu pas

Lucrez la exercițiul „O ramură hotfix și un merge fast-forward” din capitolul „3. Git Branching”, la Pro Git. Enunțul: ```bash git init ramuri && cd ramuri echo "Salut" > index.html; git add .; git commit -m "C0: pagina" echo "meniu" >> index.html; git commit -am "C1: meniu" git switch -c hotfix echo "footer" > footer.html; git add .; git commit -m "C2: footer" git log --oneline --decorate --all git switch main ls git merge hotfix git branch -d hotfix git log --oneline --graph ``` Răspunde: unde arată `HEAD` înainte și după `git switch main`? De ce `footer.html` dispare din director după `switch` și reapare după `merge`? De ce merge-ul nu creează un commit nou? Vreau să desenez pe hârtie commiturile și pointerii `main`, `hotfix` și `HEAD` după fiecare comandă. Întreabă-mă unde arată fiecare pointer după fiecare pas și corectează-mă cu indicii când greșesc.

Deschide în Claude ↗
Când e fast-forwardînțelegi condiția pentru fast-forward

Lucrez la exercițiul „O ramură hotfix și un merge fast-forward” din capitolul „3. Git Branching”, la Pro Git. Enunțul: ```bash git init ramuri && cd ramuri echo "Salut" > index.html; git add .; git commit -m "C0: pagina" echo "meniu" >> index.html; git commit -am "C1: meniu" git switch -c hotfix echo "footer" > footer.html; git add .; git commit -m "C2: footer" git log --oneline --decorate --all git switch main ls git merge hotfix git branch -d hotfix git log --oneline --graph ``` Răspunde: unde arată `HEAD` înainte și după `git switch main`? De ce `footer.html` dispare din director după `switch` și reapare după `merge`? De ce merge-ul nu creează un commit nou? Pune-mi întrebări care să mă ducă singur la condiția în care un merge e fast-forward și la ce s-ar fi întâmplat dacă făceam un commit nou pe `main` înainte de merge. Nu-mi da răspunsul direct.

Deschide în Claude ↗
de făcut

Provoacă și rezolvă un conflict de merge

nivel 2

În depozitul ramuri (sau unul nou cu un commit):

printf 'titlu: Magazin\nculoare: alb\n' > config.txt
git add .; git commit -m "C3: config"
git switch -c tema
printf 'titlu: Magazin\nculoare: negru\n' > config.txt
git commit -am "C4: tema neagră"
git switch main
printf 'titlu: Magazin\nculoare: albastru\n' > config.txt
git commit -am "C5: tema albastră"
git merge tema
  1. Citește mesajul, apoi git status -s și cat config.txt.
  2. Rezolvă conflictul în editor: păstrează o singură linie culoare: albastru-închis și șterge marcajele.
  3. Încheie merge-ul: git add config.txt și git commit (acceptă mesajul propus).
  4. Afișează git log --oneline --graph.
Cum îți verifici singur rezultatul
  • Merge-ul se oprește cu CONFLICT (content): Merge conflict in config.txt; git status -s → UU config.txt.
  • Fișierul conține marcajele <<<<<<< HEAD, culoare: albastru, =======, culoare: negru, >>>>>>> tema; linia titlu: Magazin nu e în conflict (Git a combinat-o singur).
  • După commit, graful arată un romb:
*   … Merge branch 'tema'
|\
| * … C4: tema neagră
* | … C5: tema albastră
|/
* … C3: config

Întreabă AI-ul ca să înveți

Copiază o întrebare într-un asistent AI. Sunt scrise ca AI-ul să te pună să gândești și să-ți dea indicii, nu răspunsul gata făcut.

Prezic conflictulprezici unde apare conflictul

Lucrez la exercițiul „Provoacă și rezolvă un conflict de merge” din capitolul „3. Git Branching”, la Pro Git. Enunțul: În depozitul `ramuri` (sau unul nou cu un commit): ```bash printf 'titlu: Magazin\nculoare: alb\n' > config.txt git add .; git commit -m "C3: config" git switch -c tema printf 'titlu: Magazin\nculoare: negru\n' > config.txt git commit -am "C4: tema neagră" git switch main printf 'titlu: Magazin\nculoare: albastru\n' > config.txt git commit -am "C5: tema albastră" git merge tema ``` 1. Citește mesajul, apoi `git status -s` și `cat config.txt`. 2. Rezolvă conflictul în editor: păstrează o singură linie `culoare: albastru-închis` și șterge marcajele. 3. Încheie merge-ul: `git add config.txt` și `git commit` (acceptă mesajul propus). 4. Afișează `git log --oneline --graph`. Înainte de `git merge tema`, întreabă-mă ce linii cred că vor intra în conflict și care se vor combina automat și de ce. După ce rulez, verifică-mi predicția și ajută-mă să explic rolul strămoșului comun în three-way merge.

Deschide în Claude ↗
Am rămas blocat în mergeprimești indicii pentru a ieși dintr-un merge

Lucrez la exercițiul „Provoacă și rezolvă un conflict de merge” din capitolul „3. Git Branching”, la Pro Git. Enunțul: În depozitul `ramuri` (sau unul nou cu un commit): ```bash printf 'titlu: Magazin\nculoare: alb\n' > config.txt git add .; git commit -m "C3: config" git switch -c tema printf 'titlu: Magazin\nculoare: negru\n' > config.txt git commit -am "C4: tema neagră" git switch main printf 'titlu: Magazin\nculoare: albastru\n' > config.txt git commit -am "C5: tema albastră" git merge tema ``` 1. Citește mesajul, apoi `git status -s` și `cat config.txt`. 2. Rezolvă conflictul în editor: păstrează o singură linie `culoare: albastru-închis` și șterge marcajele. 3. Încheie merge-ul: `git add config.txt` și `git commit` (acceptă mesajul propus). 4. Afișează `git log --oneline --graph`. Sunt în mijlocul unui merge cu conflict și nu știu cum să continui sau cum să renunț. Îți lipesc `git status`. Dă-mi indicii pas cu pas (ce citesc în mesaj, ce comandă abandonează merge-ul), fără să-mi scrii toată secvența.

Deschide în Claude ↗
de făcut

Rebase pentru un istoric liniar

nivel 2
git init rb && cd rb
echo base > base.txt; git add .; git commit -m "C1"
echo 2 > m2.txt; git add .; git commit -m "C2"
git switch -c experiment
echo e > e.txt; git add .; git commit -m "C4: experiment"
git switch main
echo 3 > m3.txt; git add .; git commit -m "C3: main"
git log --oneline --graph --all     # (a)
git switch experiment
git rebase main
git log --oneline --graph --all     # (b)
git switch main
git merge experiment                # (c)

Compară hash-ul lui „C4: experiment” la (a) și la (b). Apoi refă exercițiul de la zero, dar cu git merge experiment direct (fără rebase) și compară cele două grafuri finale.

Cum îți verifici singur rezultatul
  • (a): istorie divergentă — C4 și C3 pornesc amândouă din C2.
  • (b): Successfully rebased and updated refs/heads/experiment; C4 are alt hash și stă acum deasupra lui C3.
  • (c): Fast-forward; graful final e liniar: C4, C3, C2, C1.
  • Varianta cu merge are un commit de merge și un romb; conținutul fișierelor e identic în ambele variante.

Întreabă AI-ul ca să înveți

Copiază o întrebare într-un asistent AI. Sunt scrise ca AI-ul să te pună să gândești și să-ți dea indicii, nu răspunsul gata făcut.

De ce s-a schimbat hash-ulînțelegi că rebase creează commituri noi

Lucrez la exercițiul „Rebase pentru un istoric liniar” din capitolul „3. Git Branching”, la Pro Git. Enunțul: ```bash git init rb && cd rb echo base > base.txt; git add .; git commit -m "C1" echo 2 > m2.txt; git add .; git commit -m "C2" git switch -c experiment echo e > e.txt; git add .; git commit -m "C4: experiment" git switch main echo 3 > m3.txt; git add .; git commit -m "C3: main" git log --oneline --graph --all # (a) git switch experiment git rebase main git log --oneline --graph --all # (b) git switch main git merge experiment # (c) ``` Compară hash-ul lui „C4: experiment” la (a) și la (b). Apoi refă exercițiul de la zero, dar cu `git merge experiment` direct (fără rebase) și compară cele două grafuri finale. Am observat că „C4: experiment” are alt hash după rebase. Întreabă-mă ce conține un commit (părinte, tree, autor) și lasă-mă să deduc singur de ce hash-ul trebuie să se schimbe. Nu-mi spune direct.

Deschide în Claude ↗
Merge sau rebaseargumentezi alegerea dintre merge și rebase

Lucrez la exercițiul „Rebase pentru un istoric liniar” din capitolul „3. Git Branching”, la Pro Git. Enunțul: ```bash git init rb && cd rb echo base > base.txt; git add .; git commit -m "C1" echo 2 > m2.txt; git add .; git commit -m "C2" git switch -c experiment echo e > e.txt; git add .; git commit -m "C4: experiment" git switch main echo 3 > m3.txt; git add .; git commit -m "C3: main" git log --oneline --graph --all # (a) git switch experiment git rebase main git log --oneline --graph --all # (b) git switch main git merge experiment # (c) ``` Compară hash-ul lui „C4: experiment” la (a) și la (b). Apoi refă exercițiul de la zero, dar cu `git merge experiment` direct (fără rebase) și compară cele două grafuri finale. Vreau să-mi formez o părere despre când folosesc merge și când rebase. Pune-mi 3 situații concrete dintr-o echipă și lasă-mă să aleg și să argumentez; verifică-mi argumentele pe baza regulii din carte despre commiturile publicate.

Deschide în Claude ↗
de făcut

Doi colegi, un server bare și un push respins

nivel 2

Simulezi doi colegi pe același calculator.

mkdir echipa && cd echipa
git init --bare server.git
git clone server.git ana && cd ana
echo a > a.txt; git add .; git commit -m "Ana 1"; git push -u origin main
cd .. && git clone server.git bogdan && cd bogdan
echo x > x.txt; git add .; git commit -m "Bogdan 1"; git push
git switch -c functie
echo f > f.txt; git add .; git commit -m "Bogdan: funcție"; git push -u origin functie
cd ../ana
echo a2 >> a.txt; git commit -am "Ana 2"
git push                        # (1)
git fetch                       # (2)
git branch -vv                  # (3)
git branch -a
git merge origin/main           # (4) acceptă mesajul
git push
git switch functie              # (5)
git branch -vv
git log --oneline --graph --all

La final șterge ramura de pe server: git push origin --delete functie.

Cum îți verifici singur rezultatul
  • (1) push respins: ! [rejected] main -> main (fetch first).
  • (2) apar origin/main actualizat și * [new branch] functie -> origin/functie.
  • (3) * main … [origin/main: ahead 1, behind 1] Ana 2; git branch -a arată remotes/origin/functie.
  • (4) se creează un commit de merge; push-ul reușește.
  • (5) branch 'functie' set up to track 'origin/functie' — Git creează automat ramura locală care o urmărește pe cea de pe server.
  • Ștergerea afișează - [deleted] functie.

Întreabă AI-ul ca să înveți

Copiază o întrebare într-un asistent AI. Sunt scrise ca AI-ul să te pună să gândești și să-ți dea indicii, nu răspunsul gata făcut.

ahead și behindinterpretezi git branch -vv

Lucrez la exercițiul „Doi colegi, un server bare și un push respins” din capitolul „3. Git Branching”, la Pro Git. Enunțul: Simulezi doi colegi pe același calculator. ```bash mkdir echipa && cd echipa git init --bare server.git git clone server.git ana && cd ana echo a > a.txt; git add .; git commit -m "Ana 1"; git push -u origin main cd .. && git clone server.git bogdan && cd bogdan echo x > x.txt; git add .; git commit -m "Bogdan 1"; git push git switch -c functie echo f > f.txt; git add .; git commit -m "Bogdan: funcție"; git push -u origin functie cd ../ana echo a2 >> a.txt; git commit -am "Ana 2" git push # (1) git fetch # (2) git branch -vv # (3) git branch -a git merge origin/main # (4) acceptă mesajul git push git switch functie # (5) git branch -vv git log --oneline --graph --all ``` La final șterge… Îți lipesc ce afișează `git branch -vv` la pasul 3. Întreabă-mă ce înseamnă „ahead 1” și „behind 1” și ce commit corespunde fiecăruia; corectează-mă cu indicii până pot explica de ce push-ul a fost respins.

Deschide în Claude ↗
fetch față de pulldeosebești fetch, merge și pull

Lucrez la exercițiul „Doi colegi, un server bare și un push respins” din capitolul „3. Git Branching”, la Pro Git. Enunțul: Simulezi doi colegi pe același calculator. ```bash mkdir echipa && cd echipa git init --bare server.git git clone server.git ana && cd ana echo a > a.txt; git add .; git commit -m "Ana 1"; git push -u origin main cd .. && git clone server.git bogdan && cd bogdan echo x > x.txt; git add .; git commit -m "Bogdan 1"; git push git switch -c functie echo f > f.txt; git add .; git commit -m "Bogdan: funcție"; git push -u origin functie cd ../ana echo a2 >> a.txt; git commit -am "Ana 2" git push # (1) git fetch # (2) git branch -vv # (3) git branch -a git merge origin/main # (4) acceptă mesajul git push git switch functie # (5) git branch -vv git log --oneline --graph --all ``` La final șterge… Pune-mi întrebări ca să ajung singur la diferența dintre `git fetch`, `git merge origin/main` și `git pull`. După ce încerc o explicație, verific-o și spune-mi ce am omis, fără să rescrii tu totul.

Deschide în Claude ↗
de făcut

git rebase --onto cu ramurile server și client

nivel 3

Reproduci exemplul din carte: o ramură client pornită din server; vrei să integrezi doar client în main.

git init onto && cd onto
echo b > base.txt; git add .; git commit -m "C1"
git switch -c server
echo s1 > s.txt; git add .; git commit -m "C3: server"
git switch -c client
echo c1 > c.txt; git add .; git commit -m "C8: client"
echo c2 >> c.txt; git commit -am "C9: client"
git switch server
echo s2 >> s.txt; git commit -am "C4: server"
git switch main
echo m >> base.txt; git commit -am "C5: main"
git log --oneline --graph --all
  1. Mută doar commiturile din client care nu sunt în server peste main, cu git rebase --onto.
  2. Adu main la zi cu client (fast-forward).
  3. Rebazează server peste main, adu main la zi și șterge ramurile client și server. Desenează graful înainte de fiecare pas și compară-l cu git log --oneline --graph --all.
Cum îți verifici singur rezultatul
  • Pasul 1 este git rebase --onto main server client: după el, C8 și C9 (cu hash-uri noi) stau peste C5, iar C3 și C4 rămân pe server.
  • Pasul 3: git rebase main server, apoi git switch main && git merge server și git branch -d client server.
  • Graful final e liniar: C4, C3, C9, C8, C5, C1 (de sus în jos), fără commituri de merge.
  • C3 nu apare de două ori: --onto a luat doar commiturile dintre server și client.

Întreabă AI-ul ca să înveți

Copiază o întrebare într-un asistent AI. Sunt scrise ca AI-ul să te pună să gândești și să-ți dea indicii, nu răspunsul gata făcut.

Ce commituri se mutăidentifici intervalul mutat de --onto

Lucrez la exercițiul „git rebase --onto cu ramurile server și client” din capitolul „3. Git Branching”, la Pro Git. Enunțul: Reproduci exemplul din carte: o ramură `client` pornită din `server`; vrei să integrezi doar `client` în `main`. ```bash git init onto && cd onto echo b > base.txt; git add .; git commit -m "C1" git switch -c server echo s1 > s.txt; git add .; git commit -m "C3: server" git switch -c client echo c1 > c.txt; git add .; git commit -m "C8: client" echo c2 >> c.txt; git commit -am "C9: client" git switch server echo s2 >> s.txt; git commit -am "C4: server" git switch main echo m >> base.txt; git commit -am "C5: main" git log --oneline --graph --all ``` 1. Mută doar commiturile din `client` care nu sunt în `server` peste `main`, cu `git rebase --onto`. 2. Adu `main` la zi cu `client`… Înainte să rulez `git rebase --onto`, întreabă-mă ce commituri cred că vor fi mutate și pe ce bază. Lasă-mă să le enumăr; corectează-mă cu indicii despre rolul fiecăruia dintre cele trei argumente.

Deschide în Claude ↗
Pericolele rebase-uluiexplici regula despre commiturile publicate

Lucrez la exercițiul „git rebase --onto cu ramurile server și client” din capitolul „3. Git Branching”, la Pro Git. Enunțul: Reproduci exemplul din carte: o ramură `client` pornită din `server`; vrei să integrezi doar `client` în `main`. ```bash git init onto && cd onto echo b > base.txt; git add .; git commit -m "C1" git switch -c server echo s1 > s.txt; git add .; git commit -m "C3: server" git switch -c client echo c1 > c.txt; git add .; git commit -m "C8: client" echo c2 >> c.txt; git commit -am "C9: client" git switch server echo s2 >> s.txt; git commit -am "C4: server" git switch main echo m >> base.txt; git commit -am "C5: main" git log --oneline --graph --all ``` 1. Mută doar commiturile din `client` care nu sunt în `server` peste `main`, cu `git rebase --onto`. 2. Adu `main` la zi cu `client`… Dacă ramura `server` ar fi fost deja trimisă pe un server comun, ce probleme ar fi apărut pentru colegi după rebase? Întreabă-mă pas cu pas ce ar vedea un coleg la următorul pull și verifică-mi raționamentul.

Deschide în Claude ↗

🖥️ 4. Git on the Server

de făcut

Un depozit bare și protocolul local

nivel 1
mkdir server-local && cd server-local
git init proiect && cd proiect
echo a > a.txt; git add .; git commit -m "init"; cd ..
git clone --bare proiect proiect.git
ls proiect.git
git config -f proiect.git/config core.bare
git clone proiect.git c1                     # cale simplă
git clone file://$PWD/proiect.git c2         # URL file://
ls c1/.git/objects c2/.git/objects/pack
ls -l proiect.git/objects/*/* c1/.git/objects/*/* | head

Răspunde: ce lipsește dintr-un depozit bare față de unul obișnuit? Ce diferență vezi între c1 și c2 în objects și în coloana a doua (numărul de legături) a lui ls -l? De ce un server ține de obicei depozite bare?

Cum îți verifici singur rezultatul
  • proiect.git conține direct HEAD config hooks info objects refs …, fără director de lucru; core.bare → true.
  • c1 (cale simplă) are obiectele ca fișiere separate, cu numărul de legături mai mare decât 1: Git a făcut hard links sau copii directe. c2 (file://) are un packfile în objects/pack/ — a folosit procesul de transfer prin rețea, mai lent, dar curat.
  • Pe server nimeni nu editează fișiere, așa că directorul de lucru nu e necesar; în plus, push-ul într-o ramură activă a unui depozit cu director de lucru e refuzat implicit.

Întreabă AI-ul ca să înveți

Copiază o întrebare într-un asistent AI. Sunt scrise ca AI-ul să te pună să gândești și să-ți dea indicii, nu răspunsul gata făcut.

Cale sau file://explici diferența dintre cele două forme ale protocolului local

Lucrez la exercițiul „Un depozit bare și protocolul local” din capitolul „4. Git on the Server”, la Pro Git. Enunțul: ```bash mkdir server-local && cd server-local git init proiect && cd proiect echo a > a.txt; git add .; git commit -m "init"; cd .. git clone --bare proiect proiect.git ls proiect.git git config -f proiect.git/config core.bare git clone proiect.git c1 # cale simplă git clone file://$PWD/proiect.git c2 # URL file:// ls c1/.git/objects c2/.git/objects/pack ls -l proiect.git/objects/*/* c1/.git/objects/*/* | head ``` Răspunde: ce lipsește dintr-un depozit bare față de unul obișnuit? Ce diferență vezi între `c1` și `c2` în `objects` și în coloana a doua (numărul de legături) a lui `ls -l`? De ce un server ține de obicei depozite bare? Întreabă-mă ce am observat diferit în `c1` și `c2` și ajută-mă cu indicii să leg observația de explicația din carte despre protocolul local. Nu-mi spune direct ce face Git în fiecare caz.

Deschide în Claude ↗
Când e util protocolul localevaluezi avantajele și dezavantajele

Lucrez la exercițiul „Un depozit bare și protocolul local” din capitolul „4. Git on the Server”, la Pro Git. Enunțul: ```bash mkdir server-local && cd server-local git init proiect && cd proiect echo a > a.txt; git add .; git commit -m "init"; cd .. git clone --bare proiect proiect.git ls proiect.git git config -f proiect.git/config core.bare git clone proiect.git c1 # cale simplă git clone file://$PWD/proiect.git c2 # URL file:// ls c1/.git/objects c2/.git/objects/pack ls -l proiect.git/objects/*/* c1/.git/objects/*/* | head ``` Răspunde: ce lipsește dintr-un depozit bare față de unul obișnuit? Ce diferență vezi între `c1` și `c2` în `objects` și în coloana a doua (numărul de legături) a lui `ls -l`? De ce un server ține de obicei depozite bare? Vreau să judec dacă o echipă mică ar putea folosi un director partajat în rețea (NFS) ca server Git. Pune-mi întrebări despre viteză, acces și riscuri și verifică-mi concluzia.

Deschide în Claude ↗
de făcut

Servește un depozit cu git daemon

nivel 2

Continuă în directorul server-local de la exercițiul anterior. 1. Marchează depozitul ca exportabil și pornește daemonul (rămâne deschis în acest terminal):

touch proiect.git/git-daemon-export-ok
git daemon --reuseaddr --base-path=$PWD --port=9419 $PWD
  1. Într-un al doilea terminal, în același director:
git ls-remote git://localhost:9419/proiect.git
git clone git://localhost:9419/proiect.git c3
cd c3
echo z > z.txt; git add .; git commit -m "z"
git push
  1. Oprește daemonul cu Ctrl+C. Ce se întâmplă dacă ștergi git-daemon-export-ok și repornești daemonul?

Portul implicit e 9418; aici folosim 9419 ca să nu intrăm în conflict cu alt serviciu.

Cum îți verifici singur rezultatul
  • git ls-remote listează HEAD și refs/heads/main; clona reușește fără parolă.
  • git push e refuzat (access denied or repository not exported): protocolul Git e implicit doar pentru citire și nu are autentificare.
  • Fără git-daemon-export-ok (și fără --export-all), daemonul refuză și clonarea.

Întreabă AI-ul ca să înveți

Copiază o întrebare într-un asistent AI. Sunt scrise ca AI-ul să te pună să gândești și să-ți dea indicii, nu răspunsul gata făcut.

De ce fără autentificareînțelegi limitele protocolului Git

Lucrez la exercițiul „Servește un depozit cu git daemon” din capitolul „4. Git on the Server”, la Pro Git. Enunțul: Continuă în directorul `server-local` de la exercițiul anterior. 1. Marchează depozitul ca exportabil și pornește daemonul (rămâne deschis în acest terminal): ```bash touch proiect.git/git-daemon-export-ok git daemon --reuseaddr --base-path=$PWD --port=9419 $PWD ``` 2. Într-un **al doilea terminal**, în același director: ```bash git ls-remote git://localhost:9419/proiect.git git clone git://localhost:9419/proiect.git c3 cd c3 echo z > z.txt; git add .; git commit -m "z" git push ``` 3. Oprește daemonul cu Ctrl+C. Ce se întâmplă dacă ștergi `git-daemon-export-ok` și repornești daemonul? Portul implicit e 9418; aici folosim 9419 ca să nu intrăm în conflict cu alt serviciu. Întreabă-mă ce am observat când am încercat push-ul și de ce cred că protocolul Git nu are autentificare. Dă-mi indicii despre situațiile în care un astfel de server e totuși util, fără să-mi dai lista gata făcută.

Deschide în Claude ↗
Depanez conexiuneaprimești indicii când clonarea nu merge

Lucrez la exercițiul „Servește un depozit cu git daemon” din capitolul „4. Git on the Server”, la Pro Git. Enunțul: Continuă în directorul `server-local` de la exercițiul anterior. 1. Marchează depozitul ca exportabil și pornește daemonul (rămâne deschis în acest terminal): ```bash touch proiect.git/git-daemon-export-ok git daemon --reuseaddr --base-path=$PWD --port=9419 $PWD ``` 2. Într-un **al doilea terminal**, în același director: ```bash git ls-remote git://localhost:9419/proiect.git git clone git://localhost:9419/proiect.git c3 cd c3 echo z > z.txt; git add .; git commit -m "z" git push ``` 3. Oprește daemonul cu Ctrl+C. Ce se întâmplă dacă ștergi `git-daemon-export-ok` și repornești daemonul? Portul implicit e 9418; aici folosim 9419 ca să nu intrăm în conflict cu alt serviciu. Îți lipesc eroarea primită la `git clone git://localhost:9419/...`. Pune-mi întrebări de verificare (rulează daemonul? portul? base-path? fișierul de export?) și lasă-mă să găsesc singur cauza.

Deschide în Claude ↗
de făcut

Clonează prin HTTP „prost” de pe un server static

nivel 3

Ai nevoie de Python 3 (pentru un server web static). Continuă în server-local. 1. Pregătește depozitul pentru HTTP-ul „prost” (dumb):

cd proiect.git
git update-server-info
mv hooks/post-update.sample hooks/post-update
ls info
cat info/refs
cd ..
  1. Pornește un server web static în acest director (rămâne deschis): python3 -m http.server 8765.
  2. În al doilea terminal: git clone http://localhost:8765/proiect.git c4, apoi git log --oneline în c4.
  3. Uită-te în primul terminal la cererile GET făcute de Git. Oprește serverul cu Ctrl+C.

Răspunde: de ce e nevoie de git update-server-info și ce rol are hook-ul post-update? Prin ce diferă de Smart HTTP?

Cum îți verifici singur rezultatul
  • info/refs conține câte o linie <hash> refs/heads/main; clona reușește, iar git log arată commitul „init”.
  • În jurnalul serverului vezi cereri GET /proiect.git/info/refs, HEAD, apoi obiecte sau packfile-uri — Git descarcă fișiere statice, fără un proces Git pe server.
  • update-server-info scrie lista de referințe pe care serverul static nu o poate calcula; hook-ul o actualizează după fiecare push. Smart HTTP rulează Git pe server (negociază ce obiecte lipsesc), permite push și autentificare.

Întreabă AI-ul ca să înveți

Copiază o întrebare într-un asistent AI. Sunt scrise ca AI-ul să te pună să gândești și să-ți dea indicii, nu răspunsul gata făcut.

Citesc jurnalul serveruluiinterpretezi cererile HTTP făcute de Git

Lucrez la exercițiul „Clonează prin HTTP „prost” de pe un server static” din capitolul „4. Git on the Server”, la Pro Git. Enunțul: Ai nevoie de Python 3 (pentru un server web static). Continuă în `server-local`. 1. Pregătește depozitul pentru HTTP-ul „prost” (dumb): ```bash cd proiect.git git update-server-info mv hooks/post-update.sample hooks/post-update ls info cat info/refs cd .. ``` 2. Pornește un server web static în acest director (rămâne deschis): `python3 -m http.server 8765`. 3. În al doilea terminal: `git clone http://localhost:8765/proiect.git c4`, apoi `git log --oneline` în `c4`. 4. Uită-te în primul terminal la cererile GET făcute de Git. Oprește serverul cu Ctrl+C. Răspunde: de ce e nevoie de `git update-server-info` și ce rol are hook-ul `post-update`? Prin ce diferă de Smart HTTP? Îți lipesc liniile GET din jurnalul serverului Python. Întreabă-mă ce cred că cere Git la fiecare pas și de ce în ordinea aceea; corectează-mă cu indicii din secțiunea despre protocoalele de transfer.

Deschide în Claude ↗
Dumb sau Smartcompari cele două variante HTTP

Lucrez la exercițiul „Clonează prin HTTP „prost” de pe un server static” din capitolul „4. Git on the Server”, la Pro Git. Enunțul: Ai nevoie de Python 3 (pentru un server web static). Continuă în `server-local`. 1. Pregătește depozitul pentru HTTP-ul „prost” (dumb): ```bash cd proiect.git git update-server-info mv hooks/post-update.sample hooks/post-update ls info cat info/refs cd .. ``` 2. Pornește un server web static în acest director (rămâne deschis): `python3 -m http.server 8765`. 3. În al doilea terminal: `git clone http://localhost:8765/proiect.git c4`, apoi `git log --oneline` în `c4`. 4. Uită-te în primul terminal la cererile GET făcute de Git. Oprește serverul cu Ctrl+C. Răspunde: de ce e nevoie de `git update-server-info` și ce rol are hook-ul `post-update`? Prin ce diferă de Smart HTTP? Pune-mi întrebări ca să construiesc singur o comparație între HTTP „prost” și Smart HTTP (ce rulează pe server, push, eficiență). Verifică-mi comparația și spune-mi doar ce lipsește.

Deschide în Claude ↗
de făcut

Generează o pereche de chei SSH de test

nivel 1

Lucrezi într-un director de test, ca să nu atingi cheile tale reale din ~/.ssh.

mkdir chei-test && cd chei-test
ssh-keygen -t ed25519 -C "student@test" -f ./cheie_test -N ""
ls -l
cat cheie_test.pub
ssh-keygen -lf cheie_test.pub

Răspunde: 1. Care dintre cele două fișiere se trimite administratorului serverului (sau se pune pe GitHub/GitLab) și care nu trebuie să plece niciodată de pe calculatorul tău? 2. În ce fișier de pe server ajunge cheia publică pentru utilizatorul git (vezi „Setting Up the Server”)? 3. De ce e SSH o alegere bună pentru push, comparat cu protocolul Git?

La final poți șterge directorul chei-test. Pentru o cheie reală, rulează comanda fără -f și pune o parolă.

Cum îți verifici singur rezultatul
  • Apar cheie_test (privată, permisiuni -rw-------) și cheie_test.pub (publică), care începe cu ssh-ed25519 AAAA… și se termină cu comentariul student@test.
  • ssh-keygen -lf afișează amprenta 256 SHA256:… student@test (ED25519).
  • Se trimite doar .pub; pe server ea se adaugă ca linie nouă în ~git/.ssh/authorized_keys.
  • SSH oferă autentificare și criptare și e ușor de configurat; dezavantajul e că nu permite acces anonim.

Întreabă AI-ul ca să înveți

Copiază o întrebare într-un asistent AI. Sunt scrise ca AI-ul să te pună să gândești și să-ți dea indicii, nu răspunsul gata făcut.

Publică sau privatăverifici că ai înțeles rolul fiecărei chei

Lucrez la exercițiul „Generează o pereche de chei SSH de test” din capitolul „4. Git on the Server”, la Pro Git. Enunțul: Lucrezi într-un director de test, ca să nu atingi cheile tale reale din `~/.ssh`. ```bash mkdir chei-test && cd chei-test ssh-keygen -t ed25519 -C "student@test" -f ./cheie_test -N "" ls -l cat cheie_test.pub ssh-keygen -lf cheie_test.pub ``` Răspunde: 1. Care dintre cele două fișiere se trimite administratorului serverului (sau se pune pe GitHub/GitLab) și care nu trebuie să plece niciodată de pe calculatorul tău? 2. În ce fișier de pe server ajunge cheia publică pentru utilizatorul `git` (vezi „Setting Up the Server”)? 3. De ce e SSH o alegere bună pentru push, comparat cu protocolul Git? La final poți șterge directorul `chei-test`. Pentru o cheie reală, rulează comanda fără `-f` și pune… Întreabă-mă ce fișier aș trimite unui administrator și de ce, apoi ce s-ar întâmpla dacă aș trimite greșit cheia privată. Corectează-mă cu indicii, fără să-mi explici tu de la început criptografia cu chei publice.

Deschide în Claude ↗
Pașii pe un server realîți planifici configurarea unui server SSH

Lucrez la exercițiul „Generează o pereche de chei SSH de test” din capitolul „4. Git on the Server”, la Pro Git. Enunțul: Lucrezi într-un director de test, ca să nu atingi cheile tale reale din `~/.ssh`. ```bash mkdir chei-test && cd chei-test ssh-keygen -t ed25519 -C "student@test" -f ./cheie_test -N "" ls -l cat cheie_test.pub ssh-keygen -lf cheie_test.pub ``` Răspunde: 1. Care dintre cele două fișiere se trimite administratorului serverului (sau se pune pe GitHub/GitLab) și care nu trebuie să plece niciodată de pe calculatorul tău? 2. În ce fișier de pe server ajunge cheia publică pentru utilizatorul `git` (vezi „Setting Up the Server”)? 3. De ce e SSH o alegere bună pentru push, comparat cu protocolul Git? La final poți șterge directorul `chei-test`. Pentru o cheie reală, rulează comanda fără `-f` și pune… Vreau să descriu pașii pentru a da acces prin SSH unui coleg la un server Git (utilizatorul git, authorized_keys, depozit bare). Lasă-mă să scriu eu pașii, apoi verifică-i după carte și spune-mi ce am omis.

Deschide în Claude ↗
întrebare de gândit

Ce protocol și ce server alegi?

nivel 2

Pentru fiecare situație alege protocolul (local, HTTP, SSH, Git) și, unde e cazul, tipul de găzduire (server propriu cu git daemon/GitWeb, GitLab instalat, serviciu găzduit). Justifică în 2–3 propoziții. 1. Trei colegi de laborator care au toți acces la același director partajat de rețea. 2. Un proiect open-source care vrea clonare anonimă rapidă, iar push doar pentru mentenanți. 3. O firmă cu 40 de programatori, cod confidențial, care vrea interfață web, issues și permisiuni pe grupuri, dar nu vrea ca codul să plece pe un server extern. 4. Un student care vrea să-și publice tema și să o arate profesorului, fără să administreze un server. 5. O rețea de firmă în care doar portul 443 e deschis spre exterior.

Cum îți verifici singur rezultatul

Răspunsuri orientative: 1 — protocolul local (simplu, folosește permisiunile existente, dar mai lent și fără protecție la ștergeri accidentale); 2 — Smart HTTP sau protocolul Git pentru citire anonimă și SSH/HTTPS cu autentificare pentru push; 3 — GitLab instalat pe server propriu (utilizatori, grupuri, issues), acces prin SSH/HTTPS; 4 — un serviciu găzduit (GitHub, GitLab.com); 5 — Smart HTTP(S), care trece prin firewall-uri ca orice trafic web.

Întreabă AI-ul ca să înveți

Copiază o întrebare într-un asistent AI. Sunt scrise ca AI-ul să te pună să gândești și să-ți dea indicii, nu răspunsul gata făcut.

Argumentează cu mineîți testezi argumentele pentru fiecare scenariu

Lucrez la exercițiul „Ce protocol și ce server alegi?” din capitolul „4. Git on the Server”, la Pro Git. Enunțul: Pentru fiecare situație alege protocolul (local, HTTP, SSH, Git) și, unde e cazul, tipul de găzduire (server propriu cu `git daemon`/GitWeb, GitLab instalat, serviciu găzduit). Justifică în 2–3 propoziții. 1. Trei colegi de laborator care au toți acces la același director partajat de rețea. 2. Un proiect open-source care vrea clonare anonimă rapidă, iar push doar pentru mentenanți. 3. O firmă cu 40 de programatori, cod confidențial, care vrea interfață web, issues și permisiuni pe grupuri, dar nu vrea ca codul să plece pe un server extern. 4. Un student care vrea să-și publice tema și să o arate profesorului, fără să administreze un server. 5. O rețea de firmă în care doar portul 443 e… Îți scriu alegerile mele pentru cele 5 scenarii. Pentru fiecare, pune-mi o întrebare-capcană (securitate, firewall, acces anonim, administrare) care să-mi verifice argumentul. Nu-mi spune răspunsul tău până nu-mi apăr alegerea.

Deschide în Claude ↗
Tabelul protocoalelorrezumi avantajele și dezavantajele protocoalelor

Lucrez la exercițiul „Ce protocol și ce server alegi?” din capitolul „4. Git on the Server”, la Pro Git. Enunțul: Pentru fiecare situație alege protocolul (local, HTTP, SSH, Git) și, unde e cazul, tipul de găzduire (server propriu cu `git daemon`/GitWeb, GitLab instalat, serviciu găzduit). Justifică în 2–3 propoziții. 1. Trei colegi de laborator care au toți acces la același director partajat de rețea. 2. Un proiect open-source care vrea clonare anonimă rapidă, iar push doar pentru mentenanți. 3. O firmă cu 40 de programatori, cod confidențial, care vrea interfață web, issues și permisiuni pe grupuri, dar nu vrea ca codul să plece pe un server extern. 4. Un student care vrea să-și publice tema și să o arate profesorului, fără să administreze un server. 5. O rețea de firmă în care doar portul 443 e… Ajută-mă să construiesc singur un tabel cu cele patru protocoale (local, HTTP, SSH, Git) și coloanele: autentificare, acces anonim, viteză, configurare. Întreabă-mă celulă cu celulă și dă-mi indicii unde greșesc.

Deschide în Claude ↗

🤝 5. Distributed Git

de făcut

Contribuție prin patch-uri, ca pe o listă de e-mail

nivel 2
mkdir patchuri && cd patchuri
git init proiect && cd proiect
echo "# Lib" > README.md; git add .; git commit -m "Inițial"; cd ..
git clone proiect contrib && cd contrib
git config user.name "Dan Ionescu"; git config user.email dan@example.com
git switch -c docs
echo "Instalare: make" >> README.md; git commit -am "Adaug instrucțiuni de instalare"
echo "Licență: MIT" > LICENSE; git add .; git commit -m "Adaug licența"
git format-patch origin/main -o ../patch
ls ../patch
head -5 ../patch/0001-*
cd ../proiect
git switch -c dan-docs
git am ../patch/*.patch
git log --format="%h | autor: %an | committer: %cn | %s"

Răspunde: de ce patch-urile generate cu format-patch sunt mai bune decât un simplu git diff > fișier? Ce rămâne din identitatea lui Dan după git am?

Cum îți verifici singur rezultatul
  • format-patch creează două fișiere, 0001-Adaug-instruc-iuni-de-instalare.patch și 0002-Adaug-licen-a.patch; antetul are From: Dan Ionescu <dan@example.com>, Date: și Subject: [PATCH 1/2] ….
  • git am afișează Applying: Adaug instrucțiuni de instalare și Applying: Adaug licența.
  • În log, cele două commituri au autor Dan Ionescu și committer tu (cel care a aplicat). Mesajul și data autorului se păstrează; un git diff simplu nu ar fi păstrat nici autorul, nici mesajul.

Întreabă AI-ul ca să înveți

Copiază o întrebare într-un asistent AI. Sunt scrise ca AI-ul să te pună să gândești și să-ți dea indicii, nu răspunsul gata făcut.

Autor și committerdeosebești cele două roluri

Lucrez la exercițiul „Contribuție prin patch-uri, ca pe o listă de e-mail” din capitolul „5. Distributed Git”, la Pro Git. Enunțul: ```bash mkdir patchuri && cd patchuri git init proiect && cd proiect echo "# Lib" > README.md; git add .; git commit -m "Inițial"; cd .. git clone proiect contrib && cd contrib git config user.name "Dan Ionescu"; git config user.email dan@example.com git switch -c docs echo "Instalare: make" >> README.md; git commit -am "Adaug instrucțiuni de instalare" echo "Licență: MIT" > LICENSE; git add .; git commit -m "Adaug licența" git format-patch origin/main -o ../patch ls ../patch head -5 ../patch/0001-* cd ../proiect git switch -c dan-docs git am ../patch/*.patch git log --format="%h | autor: %an | committer: %cn | %s" ``` Răspunde: de ce patch-urile generate cu `format-patch` sunt mai bune… Întreabă-mă ce am văzut în coloanele autor și committer după `git am` și de ce cred că Git le ține separat. Dă-mi indicii dacă nu-mi dau seama în ce flux de lucru contează diferența.

Deschide în Claude ↗
Patch care nu se aplicăprimești indicii pentru un git am eșuat

Lucrez la exercițiul „Contribuție prin patch-uri, ca pe o listă de e-mail” din capitolul „5. Distributed Git”, la Pro Git. Enunțul: ```bash mkdir patchuri && cd patchuri git init proiect && cd proiect echo "# Lib" > README.md; git add .; git commit -m "Inițial"; cd .. git clone proiect contrib && cd contrib git config user.name "Dan Ionescu"; git config user.email dan@example.com git switch -c docs echo "Instalare: make" >> README.md; git commit -am "Adaug instrucțiuni de instalare" echo "Licență: MIT" > LICENSE; git add .; git commit -m "Adaug licența" git format-patch origin/main -o ../patch ls ../patch head -5 ../patch/0001-* cd ../proiect git switch -c dan-docs git am ../patch/*.patch git log --format="%h | autor: %an | committer: %cn | %s" ``` Răspunde: de ce patch-urile generate cu `format-patch` sunt mai bune… Dacă `git am` s-ar opri cu un conflict, ce aș face? Nu-mi da secvența completă; pune-mi întrebări despre ce opțiuni are `git am` (de ex. pentru a continua, a sări sau a renunța) și lasă-mă să le găsesc în `git am --help`.

Deschide în Claude ↗
de făcut

Fluxul cu integration manager, cu fork-uri locale

nivel 2

Simulezi un depozit „oficial”, fork-ul unui contribuitor și mentenantul.

mkdir integrare && cd integrare
git init proiect && cd proiect
echo "# Lib" > README.md; git add .; git commit -m "Inițial"; cd ..
git clone --bare proiect oficial.git        # depozitul public oficial
git clone --bare oficial.git fork.git       # fork-ul public al lui Dan
git clone fork.git dan && cd dan
git remote add upstream ../oficial.git
git switch -c docs
echo doc > DOC.md; git add .; git commit -m "Adaug DOC.md"
git push -u origin docs
git fetch upstream
git request-pull upstream/main ../fork.git docs

Acum ești mentenantul, în proiect (copia ta de lucru): 1. Adaugă fork-ul ca remote (git remote add dan ../fork.git) și fă git fetch dan. 2. Vezi ce aduce contribuția: git log --oneline main..dan/docs și git diff main...dan/docs. 3. Integreaz-o cu un commit de merge explicit: git merge --no-ff dan/docs. 4. Publică rezultatul în depozitul oficial (adaugă-l ca remote și fă push).

Cum îți verifici singur rezultatul
  • git request-pull afișează textul unei cereri: „The following changes since commit … are available in the Git repository at: ../fork.git docs”, apoi lista commiturilor (Adaug DOC.md) și statistica fișierelor.
  • git log main..dan/docs arată doar Adaug DOC.md.
  • După --no-ff, git log --oneline --graph arată Merge remote-tracking branch 'dan/docs' cu un romb.
  • În oficial.git, git --git-dir=oficial.git log --oneline include commitul de merge.

Întreabă AI-ul ca să înveți

Copiază o întrebare într-un asistent AI. Sunt scrise ca AI-ul să te pună să gândești și să-ți dea indicii, nu răspunsul gata făcut.

Desenez fluxulînțelegi cine scrie în ce depozit

Lucrez la exercițiul „Fluxul cu integration manager, cu fork-uri locale” din capitolul „5. Distributed Git”, la Pro Git. Enunțul: Simulezi un depozit „oficial”, fork-ul unui contribuitor și mentenantul. ```bash mkdir integrare && cd integrare git init proiect && cd proiect echo "# Lib" > README.md; git add .; git commit -m "Inițial"; cd .. git clone --bare proiect oficial.git # depozitul public oficial git clone --bare oficial.git fork.git # fork-ul public al lui Dan git clone fork.git dan && cd dan git remote add upstream ../oficial.git git switch -c docs echo doc > DOC.md; git add .; git commit -m "Adaug DOC.md" git push -u origin docs git fetch upstream git request-pull upstream/main ../fork.git docs ``` Acum ești mentenantul, în `proiect` (copia ta de lucru): 1. Adaugă fork-ul ca remote (`git remote add dan… Vreau să desenez cele trei depozite (oficial, fork, copia mentenantului) și săgețile de push/fetch. Întreabă-mă, pentru fiecare pas al exercițiului, cine scrie unde și corectează-mă cu indicii.

Deschide în Claude ↗
Două puncte sau treideosebești main..dan/docs de main...dan/docs

Lucrez la exercițiul „Fluxul cu integration manager, cu fork-uri locale” din capitolul „5. Distributed Git”, la Pro Git. Enunțul: Simulezi un depozit „oficial”, fork-ul unui contribuitor și mentenantul. ```bash mkdir integrare && cd integrare git init proiect && cd proiect echo "# Lib" > README.md; git add .; git commit -m "Inițial"; cd .. git clone --bare proiect oficial.git # depozitul public oficial git clone --bare oficial.git fork.git # fork-ul public al lui Dan git clone fork.git dan && cd dan git remote add upstream ../oficial.git git switch -c docs echo doc > DOC.md; git add .; git commit -m "Adaug DOC.md" git push -u origin docs git fetch upstream git request-pull upstream/main ../fork.git docs ``` Acum ești mentenantul, în `proiect` (copia ta de lucru): 1. Adaugă fork-ul ca remote (`git remote add dan… Pune-mi întrebări care să mă ducă singur la diferența dintre `git log main..dan/docs` și `git diff main...dan/docs` și la de ce mentenantul vrea diferența față de strămoșul comun. Verifică-mi explicația.

Deschide în Claude ↗
de făcut

Commituri curate - spații și mesaje bune

nivel 1
  1. Într-un depozit de test, adaugă o linie cu spații la final și verifică-o înainte de commit:
echo "linie cu spații la final   " >> README.md
git diff --check

Corectează linia, apoi rulează din nou git diff --check. 2. Scrie un mesaj de commit după regulile din carte, cu editorul (git commit -a, fără -m): un rând de rezumat de cel mult ~50 de caractere, la imperativ, un rând gol, apoi un paragraf care explică de ce. 3. Rescrie mai bine aceste mesaje reale (doar pe hârtie): „fix”, „am modificat niste chestii la login si am sters fisierul vechi si am rezolvat si bugul de la parola”, „WIP!!!”. 4. Verifică cum arată mesajul tău cu git log -1 și git log --oneline -1.

Cum îți verifici singur rezultatul
  • git diff --check afișează README.md:<n>: trailing whitespace. și linia problemă; după corectare nu afișează nimic.
  • git log --oneline -1 arată doar rândul de rezumat; git log -1 arată și paragraful, separat printr-un rând gol.
  • Al doilea mesaj de la pasul 3 descrie trei schimbări diferite: semn că ar trebui să fie trei commituri separate.

Întreabă AI-ul ca să înveți

Copiază o întrebare într-un asistent AI. Sunt scrise ca AI-ul să te pună să gândești și să-ți dea indicii, nu răspunsul gata făcut.

Feedback la mesajele meleprimești feedback pe mesajele rescrise

Lucrez la exercițiul „Commituri curate - spații și mesaje bune” din capitolul „5. Distributed Git”, la Pro Git. Enunțul: 1. Într-un depozit de test, adaugă o linie cu spații la final și verifică-o înainte de commit: ```bash echo "linie cu spații la final " >> README.md git diff --check ``` Corectează linia, apoi rulează din nou `git diff --check`. 2. Scrie un mesaj de commit după regulile din carte, cu editorul (`git commit -a`, fără `-m`): un rând de rezumat de cel mult ~50 de caractere, la imperativ, un rând gol, apoi un paragraf care explică *de ce*. 3. Rescrie mai bine aceste mesaje reale (doar pe hârtie): „fix”, „am modificat niste chestii la login si am sters fisierul vechi si am rezolvat si bugul de la parola”, „WIP!!!”. 4. Verifică cum arată mesajul tău cu `git log -1` și `git log --oneline -1`. Îți lipesc cum am rescris cele trei mesaje de commit. Verifică-le după regulile din Pro Git (lungime, imperativ, rând gol, de ce/nu ce) și pune-mi întrebări acolo unde nu respect o regulă, fără să le rescrii tu.

Deschide în Claude ↗
Un commit sau mai multedecizi cum împarți modificările în commituri

Lucrez la exercițiul „Commituri curate - spații și mesaje bune” din capitolul „5. Distributed Git”, la Pro Git. Enunțul: 1. Într-un depozit de test, adaugă o linie cu spații la final și verifică-o înainte de commit: ```bash echo "linie cu spații la final " >> README.md git diff --check ``` Corectează linia, apoi rulează din nou `git diff --check`. 2. Scrie un mesaj de commit după regulile din carte, cu editorul (`git commit -a`, fără `-m`): un rând de rezumat de cel mult ~50 de caractere, la imperativ, un rând gol, apoi un paragraf care explică *de ce*. 3. Rescrie mai bine aceste mesaje reale (doar pe hârtie): „fix”, „am modificat niste chestii la login si am sters fisierul vechi si am rezolvat si bugul de la parola”, „WIP!!!”. 4. Verifică cum arată mesajul tău cu `git log -1` și `git log --oneline -1`. Întreabă-mă ce modificări am în directorul de lucru și ajută-mă cu întrebări să decid cum le împart în commituri logice. Dă-mi un indiciu despre `git add -p` dacă am mai multe schimbări în același fișier.

Deschide în Claude ↗
de făcut

Integrare cu merge --squash și cherry-pick

nivel 2

Folosește depozitul patchuri/proiect din exercițiul cu patch-uri (are ramura dan-docs cu două commituri). 1. Integrează toată ramura ca un singur commit:

git switch main
git merge --squash dan-docs
git status -s
git commit -m "Documentație (squash de la Dan)"
git log --oneline --graph --all
  1. Preia un singur commit de pe altă ramură:
git switch -c remediere main~1
echo fix > fix.txt; git add .; git commit -m "Fix important"
git switch main
git cherry-pick remediere
git log --oneline -3

Răspunde: de ce, după squash, Git nu consideră ramura dan-docs „integrată” (git branch --merged)? Ce hash are commitul preluat cu cherry-pick față de cel original?

Cum îți verifici singur rezultatul
  • merge --squash afișează Squash commit -- not updating HEAD; git status -s arată A LICENSE, M README.md (modificări în staging, încă necomise).
  • Graful arată pe main un singur commit nou, fără romb; dan-docs rămâne o ramură separată, iar git branch --merged nu o listează (commitul de squash nu are două părinți).
  • git cherry-pick creează pe main un commit „Fix important” cu alt hash decât cel de pe remediere (alt părinte), dar cu aceeași modificare.

Întreabă AI-ul ca să înveți

Copiază o întrebare într-un asistent AI. Sunt scrise ca AI-ul să te pună să gândești și să-ți dea indicii, nu răspunsul gata făcut.

Când aleg squashalegi între merge, squash și cherry-pick

Lucrez la exercițiul „Integrare cu merge --squash și cherry-pick” din capitolul „5. Distributed Git”, la Pro Git. Enunțul: Folosește depozitul `patchuri/proiect` din exercițiul cu patch-uri (are ramura `dan-docs` cu două commituri). 1. Integrează toată ramura ca **un singur** commit: ```bash git switch main git merge --squash dan-docs git status -s git commit -m "Documentație (squash de la Dan)" git log --oneline --graph --all ``` 2. Preia un singur commit de pe altă ramură: ```bash git switch -c remediere main~1 echo fix > fix.txt; git add .; git commit -m "Fix important" git switch main git cherry-pick remediere git log --oneline -3 ``` Răspunde: de ce, după squash, Git nu consideră ramura `dan-docs` „integrată” (`git branch --merged`)? Ce hash are commitul preluat cu cherry-pick față de cel original? Pune-mi trei situații de mentenant (o ramură cu 15 commituri de tipul „typo”, un singur bugfix util dintr-o ramură abandonată, o funcționalitate mare cu istorie curată) și lasă-mă să aleg metoda. Verifică-mi alegerea.

Deschide în Claude ↗
De ce alt hashexplici ce se schimbă la cherry-pick

Lucrez la exercițiul „Integrare cu merge --squash și cherry-pick” din capitolul „5. Distributed Git”, la Pro Git. Enunțul: Folosește depozitul `patchuri/proiect` din exercițiul cu patch-uri (are ramura `dan-docs` cu două commituri). 1. Integrează toată ramura ca **un singur** commit: ```bash git switch main git merge --squash dan-docs git status -s git commit -m "Documentație (squash de la Dan)" git log --oneline --graph --all ``` 2. Preia un singur commit de pe altă ramură: ```bash git switch -c remediere main~1 echo fix > fix.txt; git add .; git commit -m "Fix important" git switch main git cherry-pick remediere git log --oneline -3 ``` Răspunde: de ce, după squash, Git nu consideră ramura `dan-docs` „integrată” (`git branch --merged`)? Ce hash are commitul preluat cu cherry-pick față de cel original? Întreabă-mă ce conține un obiect commit și lasă-mă să deduc singur de ce cherry-pick produce un hash nou. Dă-mi indicii doar dacă mă blochez.

Deschide în Claude ↗
de făcut

Pregătește o lansare - describe, shortlog, archive

nivel 1

Într-un depozit de test cu un tag adnotat v1.0 și cel puțin două commituri după el (de exemplu patchuri/proiect după exercițiul cu squash și cherry-pick, dacă ai pus tagul pe commitul „Inițial”: git tag -a v1.0 -m "v1.0" <hash-Inițial>):

git describe
git shortlog --no-merges main --not v1.0
git archive main --prefix=lib/ --format=tar.gz > ../lib.tar.gz
tar tzf ../lib.tar.gz

Apoi creează tagul noii versiuni (git tag -a v1.1 -m "Versiunea 1.1") și rulează din nou git describe.

Răspunde: ce înseamnă fiecare parte din rezultatul lui git describe? La ce i-ar folosi unui mentenant rezultatul lui shortlog când anunță o versiune?

Cum îți verifici singur rezultatul
  • git describe afișează ceva de forma v1.0-2-gf65ce45: ultimul tag, numărul de commituri de după el și g + hash-ul scurt al commitului curent. După tagul nou: v1.1.
  • git shortlog grupează pe autori commiturile de după v1.0, de ex. Ana Pop (2): urmat de mesaje.
  • Arhiva conține fișierele sub prefixul lib/ (lib/README.md, lib/LICENSE …), fără directorul .git.

Întreabă AI-ul ca să înveți

Copiază o întrebare într-un asistent AI. Sunt scrise ca AI-ul să te pună să gândești și să-ți dea indicii, nu răspunsul gata făcut.

Descifrez describeinterpretezi rezultatul lui git describe

Lucrez la exercițiul „Pregătește o lansare - describe, shortlog, archive” din capitolul „5. Distributed Git”, la Pro Git. Enunțul: Într-un depozit de test cu un tag adnotat `v1.0` și cel puțin două commituri după el (de exemplu `patchuri/proiect` după exercițiul cu squash și cherry-pick, dacă ai pus tagul pe commitul „Inițial”: `git tag -a v1.0 -m "v1.0" `): ```bash git describe git shortlog --no-merges main --not v1.0 git archive main --prefix=lib/ --format=tar.gz > ../lib.tar.gz tar tzf ../lib.tar.gz ``` Apoi creează tagul noii versiuni (`git tag -a v1.1 -m "Versiunea 1.1"`) și rulează din nou `git describe`. Răspunde: ce înseamnă fiecare parte din rezultatul lui `git describe`? La ce i-ar folosi unui mentenant rezultatul lui `shortlog` când anunță o versiune? Îți lipesc ce afișează `git describe`. Întreabă-mă ce cred că înseamnă fiecare bucată, separată prin cratime, și corectează-mă cu indicii. Apoi întreabă-mă de ce comanda cere un tag adnotat.

Deschide în Claude ↗
Anunțul de lansarescrii un anunț de versiune pe baza istoriei

Lucrez la exercițiul „Pregătește o lansare - describe, shortlog, archive” din capitolul „5. Distributed Git”, la Pro Git. Enunțul: Într-un depozit de test cu un tag adnotat `v1.0` și cel puțin două commituri după el (de exemplu `patchuri/proiect` după exercițiul cu squash și cherry-pick, dacă ai pus tagul pe commitul „Inițial”: `git tag -a v1.0 -m "v1.0" `): ```bash git describe git shortlog --no-merges main --not v1.0 git archive main --prefix=lib/ --format=tar.gz > ../lib.tar.gz tar tzf ../lib.tar.gz ``` Apoi creează tagul noii versiuni (`git tag -a v1.1 -m "Versiunea 1.1"`) și rulează din nou `git describe`. Răspunde: ce înseamnă fiecare parte din rezultatul lui `git describe`? La ce i-ar folosi unui mentenant rezultatul lui `shortlog` când anunță o versiune? Vreau să scriu un scurt anunț pentru versiunea nouă folosind `git shortlog`. Lasă-mă să-l scriu eu și verifică-mi dacă am folosit corect intervalul de commituri; dă-mi sugestii, nu textul gata făcut.

Deschide în Claude ↗

🐙 6. GitHub

de făcut

Un README în GitHub Flavored Markdown

nivel 1

Scrie un README.md pentru un proiect imaginar care să conțină: 1. un titlu și o descriere scurtă; 2. o listă de sarcini cu căsuțe (- [x] gata, - [ ] de făcut); 3. un bloc de cod cu evidențiere de limbaj (de ex. ```bash); 4. un tabel cu cel puțin două coloane; 5. o trimitere la un issue (#1), o mențiune (@utilizator) și un emoji (:tada:).

Previzualizează-l fără cont: în VS Code (Markdown Preview) sau în orice editor cu previzualizare Markdown. Dacă ai cont GitHub: deschide un issue nou într-un depozit propriu și lipește textul în tabul Preview (nu e nevoie să-l trimiți) sau pune fișierul într-un depozit al tău.

Notează ce elemente arată la fel în ambele locuri și care doar pe GitHub.

Cum îți verifici singur rezultatul
  • Lista de sarcini apare cu căsuțe bifate / nebifate; codul e evidențiat; tabelul are antet.
  • #1, @utilizator și :tada: devin link-uri / emoji doar pe GitHub (sunt extensii GFM legate de platformă); un editor local le poate afișa ca text simplu.
  • Ca verificare a sintaxei: tabelul are o linie de separare de forma |---|---| sub antet.

Întreabă AI-ul ca să înveți

Copiază o întrebare într-un asistent AI. Sunt scrise ca AI-ul să te pună să gândești și să-ți dea indicii, nu răspunsul gata făcut.

Verifică-mi Markdown-ulprimești feedback pe README

Lucrez la exercițiul „Un README în GitHub Flavored Markdown” din capitolul „6. GitHub”, la Pro Git. Enunțul: Scrie un `README.md` pentru un proiect imaginar care să conțină: 1. un titlu și o descriere scurtă; 2. o listă de sarcini cu căsuțe (`- [x] gata`, `- [ ] de făcut`); 3. un bloc de cod cu evidențiere de limbaj (de ex. ```` ```bash ````); 4. un tabel cu cel puțin două coloane; 5. o trimitere la un issue (`#1`), o mențiune (`@utilizator`) și un emoji (`:tada:`). Previzualizează-l fără cont: în VS Code (Markdown Preview) sau în orice editor cu previzualizare Markdown. **Dacă ai cont GitHub:** deschide un issue nou într-un depozit propriu și lipește textul în tabul *Preview* (nu e nevoie să-l trimiți) sau pune fișierul într-un depozit al tău. Notează ce elemente arată la fel în ambele locuri și… Îți lipesc README-ul meu. Verifică dacă folosesc corect elementele GFM cerute (task list, cod, tabel, trimiteri, emoji) și, unde greșesc, pune-mi o întrebare sau dă-mi un indiciu, fără să-mi rescrii fișierul.

Deschide în Claude ↗
Ce e specific GitHubdeosebești Markdown standard de extensiile GFM

Lucrez la exercițiul „Un README în GitHub Flavored Markdown” din capitolul „6. GitHub”, la Pro Git. Enunțul: Scrie un `README.md` pentru un proiect imaginar care să conțină: 1. un titlu și o descriere scurtă; 2. o listă de sarcini cu căsuțe (`- [x] gata`, `- [ ] de făcut`); 3. un bloc de cod cu evidențiere de limbaj (de ex. ```` ```bash ````); 4. un tabel cu cel puțin două coloane; 5. o trimitere la un issue (`#1`), o mențiune (`@utilizator`) și un emoji (`:tada:`). Previzualizează-l fără cont: în VS Code (Markdown Preview) sau în orice editor cu previzualizare Markdown. **Dacă ai cont GitHub:** deschide un issue nou într-un depozit propriu și lipește textul în tabul *Preview* (nu e nevoie să-l trimiți) sau pune fișierul într-un depozit al tău. Notează ce elemente arată la fel în ambele locuri și… Întreabă-mă ce elemente din README-ul meu cred că sunt Markdown standard și care sunt extensii GitHub, apoi corectează-mă cu indicii despre ce face GitHub cu trimiterile la issues și mențiuni.

Deschide în Claude ↗
de făcut

Pull request-urile ca referințe, fără cont

nivel 2

Ai nevoie doar de internet (depozitul public octocat/Hello-World e foarte mic).

git clone https://github.com/octocat/Hello-World hw && cd hw
git ls-remote origin | head
git ls-remote origin | grep -c refs/pull
git ls-remote origin 'refs/pull/1/*'
git fetch origin refs/pull/1/head:pr-1
git log --oneline --graph --all
git diff master...pr-1

Apoi adaugă un refspec ca să aduci automat toate PR-urile ca ramuri de remote:

git config --add remote.origin.fetch '+refs/pull/*/head:refs/remotes/origin/pr/*'
git fetch
git branch -r | head

Răspunde: ce diferență e între refs/pull/1/head și refs/pull/1/merge? De ce nu apar aceste referințe la un git clone obișnuit?

Cum îți verifici singur rezultatul
  • ls-remote listează, pe lângă HEAD și refs/heads/…, mii de linii refs/pull/<n>/head (și unele …/merge).
  • refs/pull/1/* arată două referințe: head (ultimul commit al ramurii din PR) și merge (commitul pe care GitHub l-ar crea dacă ai integra PR-ul acum).
  • După fetch, graful arată ramura pr-1 cu commitul „Edited README via GitHub” pornit din „first commit”.
  • Cu refspec-ul nou, git branch -r arată origin/pr/1, origin/pr/10 …; clonarea obișnuită aduce doar refs/heads/*, după refspec-ul implicit +refs/heads/*:refs/remotes/origin/*.

Întreabă AI-ul ca să înveți

Copiază o întrebare într-un asistent AI. Sunt scrise ca AI-ul să te pună să gândești și să-ți dea indicii, nu răspunsul gata făcut.

Citesc refspec-ulînțelegi fiecare parte a unui refspec

Lucrez la exercițiul „Pull request-urile ca referințe, fără cont” din capitolul „6. GitHub”, la Pro Git. Enunțul: Ai nevoie doar de internet (depozitul public `octocat/Hello-World` e foarte mic). ```bash git clone https://github.com/octocat/Hello-World hw && cd hw git ls-remote origin | head git ls-remote origin | grep -c refs/pull git ls-remote origin 'refs/pull/1/*' git fetch origin refs/pull/1/head:pr-1 git log --oneline --graph --all git diff master...pr-1 ``` Apoi adaugă un refspec ca să aduci automat toate PR-urile ca ramuri de remote: ```bash git config --add remote.origin.fetch '+refs/pull/*/head:refs/remotes/origin/pr/*' git fetch git branch -r | head ``` Răspunde: ce diferență e între `refs/pull/1/head` și `refs/pull/1/merge`? De ce nu apar aceste referințe la un `git clone` obișnuit? Întreabă-mă ce înseamnă fiecare parte din `+refs/pull/*/head:refs/remotes/origin/pr/*` (plusul, sursa, destinația, asteriscul) și corectează-mă cu indicii până pot explica singur ce face `git fetch` cu el.

Deschide în Claude ↗
Verific un PR localîți planifici verificarea unui PR fără interfața web

Lucrez la exercițiul „Pull request-urile ca referințe, fără cont” din capitolul „6. GitHub”, la Pro Git. Enunțul: Ai nevoie doar de internet (depozitul public `octocat/Hello-World` e foarte mic). ```bash git clone https://github.com/octocat/Hello-World hw && cd hw git ls-remote origin | head git ls-remote origin | grep -c refs/pull git ls-remote origin 'refs/pull/1/*' git fetch origin refs/pull/1/head:pr-1 git log --oneline --graph --all git diff master...pr-1 ``` Apoi adaugă un refspec ca să aduci automat toate PR-urile ca ramuri de remote: ```bash git config --add remote.origin.fetch '+refs/pull/*/head:refs/remotes/origin/pr/*' git fetch git branch -r | head ``` Răspunde: ce diferență e între `refs/pull/1/head` și `refs/pull/1/merge`? De ce nu apar aceste referințe la un `git clone` obișnuit? Vreau să știu cum aș testa local un pull request înainte să-l aprob. Lasă-mă să propun pașii (fetch, ramură, teste, diff) și verifică-i; spune-mi ce am omis, fără să-mi dai lista completă.

Deschide în Claude ↗
de făcut

Interoghează API-ul GitHub fără autentificare

nivel 2

Ai nevoie de curl și internet; nu e nevoie de cont.

curl https://api.github.com/users/octocat
curl -s https://api.github.com/repos/progit/progit2 | grep -E '"(full_name|default_branch|stargazers_count|forks_count)"'
curl -s 'https://api.github.com/repos/progit/progit2/pulls?state=closed&per_page=2' | grep -E '"(number|title)"'
curl -sI https://api.github.com/users/octocat | grep -i '^x-ratelimit'
  1. Ce format au răspunsurile? Ce câmpuri găsești pentru un utilizator?
  2. Câte cereri pe oră îți permite API-ul fără autentificare și câte mai ai?
  3. Citește în carte cum s-ar adăuga un comentariu la un issue prin API: ce metodă HTTP și ce tip de autentificare ar fi necesare? Dacă ai cont, poți crea un token personal cu drepturi minime și repeta o cerere de citire cu antetul Authorization: token <token> ca să vezi cum se schimbă limita (nu publica tokenul nicăieri).
Cum îți verifici singur rezultatul
  • Răspunsurile sunt JSON ("login": "octocat", "public_repos", "followers" …).
  • Pentru progit/progit2: "full_name": "progit/progit2", "default_branch": "main" și numerele de stele și fork-uri.
  • Antetele arată x-ratelimit-limit: 60 și x-ratelimit-remaining: <cât a rămas>; cu token limita crește (5000 pe oră).
  • Comentariul se adaugă cu POST /repos/<proprietar>/<depozit>/issues/<n>/comments, cu un token de acces.

Întreabă AI-ul ca să înveți

Copiază o întrebare într-un asistent AI. Sunt scrise ca AI-ul să te pună să gândești și să-ți dea indicii, nu răspunsul gata făcut.

Citesc JSON-ulinterpretezi răspunsul API-ului

Lucrez la exercițiul „Interoghează API-ul GitHub fără autentificare” din capitolul „6. GitHub”, la Pro Git. Enunțul: Ai nevoie de `curl` și internet; nu e nevoie de cont. ```bash curl https://api.github.com/users/octocat curl -s https://api.github.com/repos/progit/progit2 | grep -E '"(full_name|default_branch|stargazers_count|forks_count)"' curl -s 'https://api.github.com/repos/progit/progit2/pulls?state=closed&per;_page=2' | grep -E '"(number|title)"' curl -sI https://api.github.com/users/octocat | grep -i '^x-ratelimit' ``` 1. Ce format au răspunsurile? Ce câmpuri găsești pentru un utilizator? 2. Câte cereri pe oră îți permite API-ul fără autentificare și câte mai ai? 3. Citește în carte cum s-ar adăuga un comentariu la un issue prin API: ce metodă HTTP și ce tip de autentificare ar fi necesare? **Dacă… Îți lipesc o bucată din răspunsul JSON pentru un depozit. Întreabă-mă ce cred că înseamnă câteva câmpuri și cum aș extrage doar unul dintre ele în linia de comandă; dă-mi indicii, nu comanda gata făcută.

Deschide în Claude ↗
Un mic scriptscrii singur un script care folosește API-ul

Lucrez la exercițiul „Interoghează API-ul GitHub fără autentificare” din capitolul „6. GitHub”, la Pro Git. Enunțul: Ai nevoie de `curl` și internet; nu e nevoie de cont. ```bash curl https://api.github.com/users/octocat curl -s https://api.github.com/repos/progit/progit2 | grep -E '"(full_name|default_branch|stargazers_count|forks_count)"' curl -s 'https://api.github.com/repos/progit/progit2/pulls?state=closed&per;_page=2' | grep -E '"(number|title)"' curl -sI https://api.github.com/users/octocat | grep -i '^x-ratelimit' ``` 1. Ce format au răspunsurile? Ce câmpuri găsești pentru un utilizator? 2. Câte cereri pe oră îți permite API-ul fără autentificare și câte mai ai? 3. Citește în carte cum s-ar adăuga un comentariu la un issue prin API: ce metodă HTTP și ce tip de autentificare ar fi necesare? **Dacă… Vreau să scriu un script care afișează titlurile ultimelor 5 pull request-uri închise ale unui depozit. Lasă-mă să-l scriu eu, apoi verifică-l și spune-mi ce trebuie corectat, fără să-l rescrii.

Deschide în Claude ↗
de făcut

Parcurge GitHub Flow (cu cont sau simulat local)

nivel 2

Dacă ai deja cont GitHub (nu-ți crea unul doar pentru exercițiu dacă nu vrei): 1. Verifică în setări că ai activat autentificarea în doi pași și adaugă o cheie SSH publică (vezi capitolul 4). 2. Creează un depozit nou al tău, cu un README, și clonează-l. 3. Deschide un issue „Adaugă licența” (va primi numărul #1). 4. Local: git switch -c licenta, adaugă un fișier LICENSE, commit cu mesajul „Adaug licența, fixes #1”, git push -u origin licenta. 5. Deschide un pull request din licenta în main, lasă-ți un comentariu pe o linie din diff, apoi fă încă un commit și push pe aceeași ramură. Fă merge din interfață. 6. Local: git switch main && git pull, apoi git branch -d licenta.

Fără cont: simulează aceiași pași cu un depozit bare local ca „GitHub” (git init --bare github.git), o clonă ca a ta, o ramură de funcționalitate, push, git request-pull în loc de PR și un merge --no-ff făcut din altă clonă.

Cum îți verifici singur rezultatul
  • Cu cont: PR-ul arată ambele commituri (al doilea push actualizează automat PR-ul); după merge, issue-ul #1 se închide singur datorită cuvântului „fixes #1”; pe main apare commitul de merge.
  • Fără cont: git log --oneline --graph pe main arată un romb cu ramura de funcționalitate integrată, iar ramura e ștearsă după integrare (git push origin --delete <ramură>).
  • În ambele variante: main rămâne mereu într-o stare bună; munca se face pe ramuri scurte.

Întreabă AI-ul ca să înveți

Copiază o întrebare într-un asistent AI. Sunt scrise ca AI-ul să te pună să gândești și să-ți dea indicii, nu răspunsul gata făcut.

Planific pașiiîți faci planul înainte să începi

Lucrez la exercițiul „Parcurge GitHub Flow (cu cont sau simulat local)” din capitolul „6. GitHub”, la Pro Git. Enunțul: **Dacă ai deja cont GitHub** (nu-ți crea unul doar pentru exercițiu dacă nu vrei): 1. Verifică în setări că ai activat autentificarea în doi pași și adaugă o cheie SSH publică (vezi capitolul 4). 2. Creează un depozit nou al tău, cu un README, și clonează-l. 3. Deschide un issue „Adaugă licența” (va primi numărul `#1`). 4. Local: `git switch -c licenta`, adaugă un fișier `LICENSE`, commit cu mesajul „Adaug licența, fixes #1”, `git push -u origin licenta`. 5. Deschide un pull request din `licenta` în `main`, lasă-ți un comentariu pe o linie din diff, apoi fă încă un commit și push pe aceeași ramură. Fă merge din interfață. 6. Local: `git switch main && git pull`, apoi `git branch -d… Înainte să încep, întreabă-mă ce cred că se întâmplă cu PR-ul când fac push pe aceeași ramură după ce l-am deschis și ce face „fixes #1”. Nu-mi confirma nimic; după ce termin, verifică-mi observațiile.

Deschide în Claude ↗
Securitatea contuluiînțelegi rolul 2FA și al cheilor SSH

Lucrez la exercițiul „Parcurge GitHub Flow (cu cont sau simulat local)” din capitolul „6. GitHub”, la Pro Git. Enunțul: **Dacă ai deja cont GitHub** (nu-ți crea unul doar pentru exercițiu dacă nu vrei): 1. Verifică în setări că ai activat autentificarea în doi pași și adaugă o cheie SSH publică (vezi capitolul 4). 2. Creează un depozit nou al tău, cu un README, și clonează-l. 3. Deschide un issue „Adaugă licența” (va primi numărul `#1`). 4. Local: `git switch -c licenta`, adaugă un fișier `LICENSE`, commit cu mesajul „Adaug licența, fixes #1”, `git push -u origin licenta`. 5. Deschide un pull request din `licenta` în `main`, lasă-ți un comentariu pe o linie din diff, apoi fă încă un commit și push pe aceeași ramură. Fă merge din interfață. 6. Local: `git switch main && git pull`, apoi `git branch -d… Pune-mi întrebări despre ce protejează autentificarea în doi pași și ce rol are cheia SSH față de parolă, până pot explica singur de ce sunt recomandate amândouă. Corectează-mă cu indicii.

Deschide în Claude ↗
întrebare de gândit

Fork, colaborator sau organizație?

nivel 1

Răspunde pe scurt, folosind capitolul despre GitHub: 1. Vrei să repari o greșeală de tipar în documentația unui proiect open-source la care nu ai drept de scriere. Ce pași urmezi pe GitHub? 2. Ce diferență este între a fi colaborator la un depozit și a lucra dintr-un fork? 3. Un PR poate fi deschis între două ramuri ale aceluiași depozit? Când ar avea sens? 4. Ce aduce o organizație față de un cont personal (proprietari, echipe, permisiuni)? 5. De ce un pull request e mai mult decât o cerere de merge (discuție, comentarii pe linii, verificări automate)?

Cum îți verifici singur rezultatul

1 — fork, clonezi fork-ul, faci o ramură, commit, push în fork, deschizi PR spre depozitul original. 2 — colaboratorul are drept de push direct în depozit; din fork contribui fără drepturi, prin PR. 3 — da; e fluxul obișnuit într-o echipă cu drept de scriere (GitHub Flow), ca să discuți codul înainte de integrare. 4 — conturi partajate pentru proiecte, cu proprietari și echipe care primesc drepturi pe depozite. 5 — PR-ul e locul de revizuire: comentarii, commituri noi pe aceeași ramură, rezultatul testelor automate.

Întreabă AI-ul ca să înveți

Copiază o întrebare într-un asistent AI. Sunt scrise ca AI-ul să te pună să gândești și să-ți dea indicii, nu răspunsul gata făcut.

Verifică-mi răspunsurileîți verifici răspunsurile cu feedback

Lucrez la exercițiul „Fork, colaborator sau organizație?” din capitolul „6. GitHub”, la Pro Git. Enunțul: Răspunde pe scurt, folosind capitolul despre GitHub: 1. Vrei să repari o greșeală de tipar în documentația unui proiect open-source la care nu ai drept de scriere. Ce pași urmezi pe GitHub? 2. Ce diferență este între a fi *colaborator* la un depozit și a lucra dintr-un *fork*? 3. Un PR poate fi deschis între două ramuri ale aceluiași depozit? Când ar avea sens? 4. Ce aduce o *organizație* față de un cont personal (proprietari, echipe, permisiuni)? 5. De ce un pull request e mai mult decât o cerere de merge (discuție, comentarii pe linii, verificări automate)? Îți scriu răspunsurile mele la cele 5 întrebări. Verifică-le pe rând și, unde sunt incomplete, pune-mi o întrebare care să mă facă să le completez singur. Nu-mi da răspunsul corect direct.

Deschide în Claude ↗
Joc de rolexersezi alegerea fluxului potrivit

Lucrez la exercițiul „Fork, colaborator sau organizație?” din capitolul „6. GitHub”, la Pro Git. Enunțul: Răspunde pe scurt, folosind capitolul despre GitHub: 1. Vrei să repari o greșeală de tipar în documentația unui proiect open-source la care nu ai drept de scriere. Ce pași urmezi pe GitHub? 2. Ce diferență este între a fi *colaborator* la un depozit și a lucra dintr-un *fork*? 3. Un PR poate fi deschis între două ramuri ale aceluiași depozit? Când ar avea sens? 4. Ce aduce o *organizație* față de un cont personal (proprietari, echipe, permisiuni)? 5. De ce un pull request e mai mult decât o cerere de merge (discuție, comentarii pe linii, verificări automate)? Joacă rolul unui coleg care îmi descrie situații de pe GitHub (contribuție externă, echipă internă, o firmă cu mai multe echipe). Lasă-mă să-i recomand fork, colaborare sau organizație și întreabă-mă de ce.

Deschide în Claude ↗

🧰 7. Git Tools

de făcut

HEAD^, HEAD~2, .. și ... pe un istoric cu merge

nivel 1
git init revizii && cd revizii
for i in 1 2 3; do echo $i > m$i.txt; git add .; git commit -m "M$i"; done
git switch -c topic HEAD~1
for i in 1 2; do echo $i > t$i.txt; git add .; git commit -m "T$i"; done
git switch main
git log --oneline main..topic          # (a)
git log --oneline topic..main          # (b)
git log --oneline --left-right main...topic   # (c)
git merge --no-edit topic
git log --oneline --graph

Acum, înainte să rulezi, scrie ce commit crezi că indică fiecare expresie, apoi verifică cu git log --oneline -1 <expresie>: HEAD^, HEAD^2, HEAD~2, HEAD^2~1, HEAD@{1}. La final: git reflog | head -5 și git rev-parse --short HEAD~2.

Cum îți verifici singur rezultatul
  • (a) T2, T1; (b) M3; (c) < M3, > T2, > T1.
  • După merge: HEAD^ = M3 (primul părinte, ramura pe care erai), HEAD^2 = T2 (al doilea părinte, ramura integrată), HEAD~2 = M2, HEAD^2~1 = T1, HEAD@{1} = M3 (unde era HEAD înainte de merge, după reflog).
  • git reflog arată pe primul rând merge topic: Merge made by ….

Întreabă AI-ul ca să înveți

Copiază o întrebare într-un asistent AI. Sunt scrise ca AI-ul să te pună să gândești și să-ți dea indicii, nu răspunsul gata făcut.

Prezic expresiileîți verifici predicțiile pentru ^ și ~

Lucrez la exercițiul „HEAD^, HEAD~2, .. și ... pe un istoric cu merge” din capitolul „7. Git Tools”, la Pro Git. Enunțul: ```bash git init revizii && cd revizii for i in 1 2 3; do echo $i > m$i.txt; git add .; git commit -m "M$i"; done git switch -c topic HEAD~1 for i in 1 2; do echo $i > t$i.txt; git add .; git commit -m "T$i"; done git switch main git log --oneline main..topic # (a) git log --oneline topic..main # (b) git log --oneline --left-right main...topic # (c) git merge --no-edit topic git log --oneline --graph ``` Acum, **înainte să rulezi**, scrie ce commit crezi că indică fiecare expresie, apoi verifică cu `git log --oneline -1 `: `HEAD^`, `HEAD^2`, `HEAD~2`, `HEAD^2~1`, `HEAD@{1}`. La final: `git reflog | head -5` și `git rev-parse --short HEAD~2`. Îți scriu ce cred că indică fiecare dintre cele cinci expresii. Verifică-mi predicțiile și, la cele greșite, întreabă-mă ce înseamnă „primul părinte” într-un commit de merge, fără să-mi dai răspunsul.

Deschide în Claude ↗
Două sau trei puncteînțelegi intervalele de commituri

Lucrez la exercițiul „HEAD^, HEAD~2, .. și ... pe un istoric cu merge” din capitolul „7. Git Tools”, la Pro Git. Enunțul: ```bash git init revizii && cd revizii for i in 1 2 3; do echo $i > m$i.txt; git add .; git commit -m "M$i"; done git switch -c topic HEAD~1 for i in 1 2; do echo $i > t$i.txt; git add .; git commit -m "T$i"; done git switch main git log --oneline main..topic # (a) git log --oneline topic..main # (b) git log --oneline --left-right main...topic # (c) git merge --no-edit topic git log --oneline --graph ``` Acum, **înainte să rulezi**, scrie ce commit crezi că indică fiecare expresie, apoi verifică cu `git log --oneline -1 `: `HEAD^`, `HEAD^2`, `HEAD~2`, `HEAD^2~1`, `HEAD@{1}`. La final: `git reflog | head -5` și `git rev-parse --short HEAD~2`. Pune-mi întrebări cu diagrame mici (desenate cu text) ca să ajung singur să explic diferența dintre `A..B`, `B..A` și `A...B`. Corectează-mă cu indicii.

Deschide în Claude ↗
de făcut

Pune deoparte lucrul cu stash și curăță cu clean

nivel 1
git init sertar && cd sertar
echo a > index.html; echo b > lib.js; printf '*.o\n' > .gitignore
git add .; git commit -m "init"
echo a2 >> index.html; git add index.html
echo b2 >> lib.js
echo nou > nou.txt
git status -s                 # (1)
git stash
git status -s                 # (2)
git stash list
git stash apply --index
git status -s                 # (3)
git stash drop
git stash -u
git status -s                 # (4)
git stash pop --index

Apoi curățenie (folosește întâi -n, care doar arată ce s-ar șterge):

git stash -u
mkdir tmp; touch tmp/x.txt y.o z.txt
git clean -n
git clean -n -d
git clean -n -d -x
git clean -f -d
git status -s --ignored
git stash pop --index
Cum îți verifici singur rezultatul
  • (1) M index.html, M lib.js, ?? nou.txt. (2) doar ?? nou.txt: stash-ul simplu nu ia fișierele neurmărite.
  • (3) cu --index revine și starea din staging: M index.html, M lib.js. (4) după stash -u, nimic.
  • clean -n → Would remove z.txt; cu -d și Would remove tmp/; cu -x și Would remove y.o (ignorat). După clean -f -d rămâne doar !! y.o. Ultimul pop îți aduce înapoi lucrul.

Întreabă AI-ul ca să înveți

Copiază o întrebare într-un asistent AI. Sunt scrise ca AI-ul să te pună să gândești și să-ți dea indicii, nu răspunsul gata făcut.

Ce ia stash-ulprezici ce pune stash deoparte

Lucrez la exercițiul „Pune deoparte lucrul cu stash și curăță cu clean” din capitolul „7. Git Tools”, la Pro Git. Enunțul: ```bash git init sertar && cd sertar echo a > index.html; echo b > lib.js; printf '*.o\n' > .gitignore git add .; git commit -m "init" echo a2 >> index.html; git add index.html echo b2 >> lib.js echo nou > nou.txt git status -s # (1) git stash git status -s # (2) git stash list git stash apply --index git status -s # (3) git stash drop git stash -u git status -s # (4) git stash pop --index ``` Apoi curățenie (folosește **întâi** `-n`, care doar arată ce s-ar șterge): ```bash git stash -u mkdir tmp; touch tmp/x.txt y.o z.txt git clean -n git clean -n -d git clean -n -d -x git clean -f -d git status -s --ignored git stash pop --index ``` Înainte de pașii (2) și (4), întreabă-mă ce fișiere cred că vor dispărea din `git status -s` și de ce. Verifică-mi predicțiile după ce rulez și dă-mi indicii despre opțiunile `-u` și `--index`.

Deschide în Claude ↗
clean în siguranțăîți faci un obicei sigur cu git clean

Lucrez la exercițiul „Pune deoparte lucrul cu stash și curăță cu clean” din capitolul „7. Git Tools”, la Pro Git. Enunțul: ```bash git init sertar && cd sertar echo a > index.html; echo b > lib.js; printf '*.o\n' > .gitignore git add .; git commit -m "init" echo a2 >> index.html; git add index.html echo b2 >> lib.js echo nou > nou.txt git status -s # (1) git stash git status -s # (2) git stash list git stash apply --index git status -s # (3) git stash drop git stash -u git status -s # (4) git stash pop --index ``` Apoi curățenie (folosește **întâi** `-n`, care doar arată ce s-ar șterge): ```bash git stash -u mkdir tmp; touch tmp/x.txt y.o z.txt git clean -n git clean -n -d git clean -n -d -x git clean -f -d git status -s --ignored git stash pop --index ``` Ajută-mă să-mi fac o regulă de lucru sigură cu `git clean`. Pune-mi întrebări despre ce șterge fiecare opțiune (`-n`, `-d`, `-x`, `-f`) și lasă-mă să formulez eu regula; verific-o apoi.

Deschide în Claude ↗
de făcut

Cele trei moduri ale lui git reset

nivel 2
git init reset3 && cd reset3
echo v1 > file.txt; git add .; git commit -m v1
echo v2 > file.txt; git commit -am v2
echo v3 > file.txt; git commit -am v3

Pentru fiecare pas, notează înainte ce crezi că vor arăta git log --oneline, git status -s și cat file.txt: 1. git reset --soft HEAD~1, apoi verifică; refă commitul: git commit -m "v3 din nou". 2. git reset HEAD~1 (mixed, implicit), verifică; refă: git commit -am "v3 iar". 3. git reset --hard HEAD~1, verifică. 4. Recuperează commitul „pierdut”: git reflog | head -4, apoi git reset --hard HEAD@{1}. 5. Comasează ultimele două commituri într-unul: git reset --soft HEAD~2 și git commit -m "v2+v3 comasate".

Pentru fiecare mod, spune care dintre cei trei „arbori” (HEAD, index, directorul de lucru) se schimbă.

Cum îți verifici singur rezultatul
  • --soft: log până la v2, M file.txt (în staging), fișierul conține v3 — se mută doar HEAD.
  • mixed: log până la v2, M file.txt (nestaged), fișierul conține v3 — se mută HEAD și indexul.
  • --hard: log până la v2, status curat, fișierul conține v2 — se schimbă și directorul de lucru.
  • Reflogul arată HEAD@{1}: commit: v3 iar; după reset revii la v3 iar și fișierul conține v3.
  • Pasul 5: git log --oneline arată doar v2+v3 comasate și v1.

Întreabă AI-ul ca să înveți

Copiază o întrebare într-un asistent AI. Sunt scrise ca AI-ul să te pună să gândești și să-ți dea indicii, nu răspunsul gata făcut.

Tabelul celor trei arboriconstruiești singur tabelul HEAD / index / lucru

Lucrez la exercițiul „Cele trei moduri ale lui git reset” din capitolul „7. Git Tools”, la Pro Git. Enunțul: ```bash git init reset3 && cd reset3 echo v1 > file.txt; git add .; git commit -m v1 echo v2 > file.txt; git commit -am v2 echo v3 > file.txt; git commit -am v3 ``` Pentru fiecare pas, notează **înainte** ce crezi că vor arăta `git log --oneline`, `git status -s` și `cat file.txt`: 1. `git reset --soft HEAD~1`, apoi verifică; refă commitul: `git commit -m "v3 din nou"`. 2. `git reset HEAD~1` (mixed, implicit), verifică; refă: `git commit -am "v3 iar"`. 3. `git reset --hard HEAD~1`, verifică. 4. Recuperează commitul „pierdut”: `git reflog | head -4`, apoi `git reset --hard HEAD@{1}`. 5. Comasează ultimele două commituri într-unul: `git reset --soft HEAD~2` și `git commit -m "v2+v3… Vreau să fac un tabel cu cele trei moduri de reset și cei trei arbori. Întreabă-mă pentru fiecare celulă ce cred că se schimbă, pe baza a ce am văzut în terminal, și corectează-mă cu indicii.

Deschide în Claude ↗
Am pierdut un commitprimești indicii pentru recuperare

Lucrez la exercițiul „Cele trei moduri ale lui git reset” din capitolul „7. Git Tools”, la Pro Git. Enunțul: ```bash git init reset3 && cd reset3 echo v1 > file.txt; git add .; git commit -m v1 echo v2 > file.txt; git commit -am v2 echo v3 > file.txt; git commit -am v3 ``` Pentru fiecare pas, notează **înainte** ce crezi că vor arăta `git log --oneline`, `git status -s` și `cat file.txt`: 1. `git reset --soft HEAD~1`, apoi verifică; refă commitul: `git commit -m "v3 din nou"`. 2. `git reset HEAD~1` (mixed, implicit), verifică; refă: `git commit -am "v3 iar"`. 3. `git reset --hard HEAD~1`, verifică. 4. Recuperează commitul „pierdut”: `git reflog | head -4`, apoi `git reset --hard HEAD@{1}`. 5. Comasează ultimele două commituri într-unul: `git reset --soft HEAD~2` și `git commit -m "v2+v3… Am făcut `git reset --hard` și cred că am pierdut munca. Nu-mi da comanda direct; întreabă-mă ce am încercat și ghidează-mă spre reflog cu întrebări. Spune-mi și ce NU se poate recupera (modificările necomise).

Deschide în Claude ↗
de făcut

Curăță istoria cu git rebase -i

nivel 2
git init curatenie && cd curatenie
echo base > a.txt; git add .; git commit -m "Inițial"
echo 1 > f.txt; git add .; git commit -m "Adaug funcția"
echo 2 >> f.txt; git commit -am "typo"
echo 3 >> f.txt; git commit -am "încă un typo"
echo d > doc.txt; git add .; git commit -m "Documentaţie"
git log --oneline
git rebase -i HEAD~4

În editor apare lista celor 4 commituri, de la cel mai vechi la cel mai nou. Scopul: - „typo” și „încă un typo” se contopesc în „Adaug funcția”, fără să le păstrezi mesajele; - mesajul ultimului commit se corectează în „Documentație pentru funcție” (cu ț corect). Salvează și închide editorul; la cererea de mesaj nou, scrie-l și salvează.

Regula de aur: nu rescrie astfel commituri deja trimise pe un server comun.

Cum îți verifici singur rezultatul
  • În listă se folosesc fixup (sau squash) pe liniile 2 și 3 și reword pe linia 4.
  • git log --oneline arată exact trei commituri: „Documentație pentru funcție”, „Adaug funcția”, „Inițial”.
  • git show --stat HEAD~1 arată că „Adaug funcția” conține acum toate cele 3 linii din f.txt.
  • Dacă greșești ceva: git rebase --abort în timpul rebase-ului sau git reset --hard ORIG_HEAD imediat după.

Întreabă AI-ul ca să înveți

Copiază o întrebare într-un asistent AI. Sunt scrise ca AI-ul să te pună să gândești și să-ți dea indicii, nu răspunsul gata făcut.

Ce scriu în listăalegi comenzile potrivite din lista de rebase

Lucrez la exercițiul „Curăță istoria cu git rebase -i” din capitolul „7. Git Tools”, la Pro Git. Enunțul: ```bash git init curatenie && cd curatenie echo base > a.txt; git add .; git commit -m "Inițial" echo 1 > f.txt; git add .; git commit -m "Adaug funcția" echo 2 >> f.txt; git commit -am "typo" echo 3 >> f.txt; git commit -am "încă un typo" echo d > doc.txt; git add .; git commit -m "Documentaţie" git log --oneline git rebase -i HEAD~4 ``` În editor apare lista celor 4 commituri, **de la cel mai vechi la cel mai nou**. Scopul: - „typo” și „încă un typo” se contopesc în „Adaug funcția”, fără să le păstrezi mesajele; - mesajul ultimului commit se corectează în „Documentație pentru funcție” (cu ț corect). Salvează și închide editorul; la cererea de mesaj nou, scrie-l și salvează. **Regula de… Îți lipesc lista pe care o văd în editor. Lasă-mă să propun ce cuvânt pun pe fiecare linie, apoi verifică-mi propunerea și dă-mi indicii despre diferența dintre `squash` și `fixup`, fără să-mi scrii lista finală.

Deschide în Claude ↗
Ceva a mers prostprimești indicii pentru un rebase blocat

Lucrez la exercițiul „Curăță istoria cu git rebase -i” din capitolul „7. Git Tools”, la Pro Git. Enunțul: ```bash git init curatenie && cd curatenie echo base > a.txt; git add .; git commit -m "Inițial" echo 1 > f.txt; git add .; git commit -m "Adaug funcția" echo 2 >> f.txt; git commit -am "typo" echo 3 >> f.txt; git commit -am "încă un typo" echo d > doc.txt; git add .; git commit -m "Documentaţie" git log --oneline git rebase -i HEAD~4 ``` În editor apare lista celor 4 commituri, **de la cel mai vechi la cel mai nou**. Scopul: - „typo” și „încă un typo” se contopesc în „Adaug funcția”, fără să le păstrezi mesajele; - mesajul ultimului commit se corectează în „Documentație pentru funcție” (cu ț corect). Salvează și închide editorul; la cererea de mesaj nou, scrie-l și salvează. **Regula de… Rebase-ul s-a oprit sau am obținut alt istoric decât voiam. Îți lipesc `git status` și `git log --oneline`. Pune-mi întrebări ca să înțeleg unde sunt și dă-mi indicii pentru a continua sau a reveni.

Deschide în Claude ↗
de făcut

Găsește commitul vinovat cu git bisect

nivel 3

Generează un istoric cu 20 de commituri în care, la un moment dat, calc.txt se strică (total=10 devine total=11). Fă-te că nu știi la ce pas.

git init bisect && cd bisect
for i in $(seq 1 20); do
  if [ $i -lt 13 ]; then echo "total=10" > calc.txt; else echo "total=11" > calc.txt; fi
  echo "pas $i" > pas.txt; git add .; git commit -q -m "Pasul $i"
done
  1. Căutare manuală: git bisect start, git bisect bad (HEAD e stricat), git bisect good HEAD~19. La fiecare pas rulează cat calc.txt și răspunde cu git bisect good sau git bisect bad. Numără pașii. Încheie cu git bisect reset.
  2. Căutare automată: același start, apoi git bisect run grep -q "total=10" calc.txt, apoi git bisect reset.
  3. Confirmă cu alte unelte: git blame -L 1,1 calc.txt și git log -S total=11 --oneline.
Cum îți verifici singur rezultatul
  • Ambele căutări se termină cu <hash> is the first bad commit și commitul Pasul 13.
  • Căutarea manuală durează în jur de 4–5 pași (log₂ 20 ≈ 4,3), nu 20.
  • git bisect run folosește codul de ieșire: 0 = good, altceva = bad; grep -q iese cu 1 când nu găsește textul.
  • git blame arată linia total=11 atribuită commitului „Pasul 13”; git log -S afișează același commit.

Întreabă AI-ul ca să înveți

Copiază o întrebare într-un asistent AI. Sunt scrise ca AI-ul să te pună să gândești și să-ți dea indicii, nu răspunsul gata făcut.

Câți pași vor fiestimezi numărul de pași al căutării binare

Lucrez la exercițiul „Găsește commitul vinovat cu git bisect” din capitolul „7. Git Tools”, la Pro Git. Enunțul: Generează un istoric cu 20 de commituri în care, la un moment dat, `calc.txt` se strică (`total=10` devine `total=11`). Fă-te că nu știi la ce pas. ```bash git init bisect && cd bisect for i in $(seq 1 20); do if [ $i -lt 13 ]; then echo "total=10" > calc.txt; else echo "total=11" > calc.txt; fi echo "pas $i" > pas.txt; git add .; git commit -q -m "Pasul $i" done ``` 1. Căutare manuală: `git bisect start`, `git bisect bad` (HEAD e stricat), `git bisect good HEAD~19`. La fiecare pas rulează `cat calc.txt` și răspunde cu `git bisect good` sau `git bisect bad`. Numără pașii. Încheie cu `git bisect reset`. 2. Căutare automată: același start, apoi `git bisect run grep -q "total=10" calc.txt`,… Înainte să încep, întreabă-mă câți pași cred că va avea căutarea pentru 20 de commituri și de ce. După ce termin, verifică-mi estimarea și întreabă-mă cum s-ar schimba pentru 1000 de commituri.

Deschide în Claude ↗
Scriptul pentru bisect runscrii un script de test pentru bisect run

Lucrez la exercițiul „Găsește commitul vinovat cu git bisect” din capitolul „7. Git Tools”, la Pro Git. Enunțul: Generează un istoric cu 20 de commituri în care, la un moment dat, `calc.txt` se strică (`total=10` devine `total=11`). Fă-te că nu știi la ce pas. ```bash git init bisect && cd bisect for i in $(seq 1 20); do if [ $i -lt 13 ]; then echo "total=10" > calc.txt; else echo "total=11" > calc.txt; fi echo "pas $i" > pas.txt; git add .; git commit -q -m "Pasul $i" done ``` 1. Căutare manuală: `git bisect start`, `git bisect bad` (HEAD e stricat), `git bisect good HEAD~19`. La fiecare pas rulează `cat calc.txt` și răspunde cu `git bisect good` sau `git bisect bad`. Numără pașii. Încheie cu `git bisect reset`. 2. Căutare automată: același start, apoi `git bisect run grep -q "total=10" calc.txt`,… Vreau să scriu un mic script de test pentru `git bisect run` într-un proiect real (de ex. compilează și rulează testele). Lasă-mă să-l scriu, apoi verifică-mi dacă întoarce codurile de ieșire corecte; dă-mi indicii, nu scriptul.

Deschide în Claude ↗

⚙️ 8. Customizing Git

de făcut

Niveluri de configurare, alias-uri și șablon de commit

nivel 1

Într-un depozit de test: 1. Suprascrie numele doar local și vezi de unde vine fiecare valoare:

git config user.name "Nume (local)"
git config --show-origin --get-all user.name
git config --show-scope user.name
git config --unset user.name
  1. Creează un șablon pentru mesajele de commit și activează-l doar în acest depozit:
printf 'Rezumat (max. 50 de caractere)\n\nDe ce:\n\n[ref: ]\n' > .git/sablon.txt
git config commit.template .git/sablon.txt
git commit --allow-empty      # se deschide editorul cu șablonul
  1. Adaugă două alias-uri utile (de ex. st pentru status -s și ultimul pentru log -1 HEAD) și unul care rulează o comandă externă, cu ! (de ex. git config alias.vizual '!gitk' sau orice alt program).
  2. Setează core.autocrlf după sistemul tău (input pe macOS/Linux, true pe Windows) și explică de ce.
Cum îți verifici singur rezultatul
  • La pasul 1, --get-all arată două linii: întâi valoarea globală (file:…/.gitconfig), apoi cea locală (file:.git/config) — ultima citită câștigă; --show-scope → local Nume (local).
  • Editorul se deschide cu textul șablonului; liniile lăsate neschimbate devin mesajul (dacă salvezi fără să modifici, Git anulează commitul cu Aborting commit; you did not edit the message.).
  • git st afișează formatul scurt; git config --get-regexp alias listează alias-urile.

Întreabă AI-ul ca să înveți

Copiază o întrebare într-un asistent AI. Sunt scrise ca AI-ul să te pună să gândești și să-ți dea indicii, nu răspunsul gata făcut.

Aleg setările meleîți alegi configurarea personală

Lucrez la exercițiul „Niveluri de configurare, alias-uri și șablon de commit” din capitolul „8. Customizing Git”, la Pro Git. Enunțul: Într-un depozit de test: 1. Suprascrie numele doar local și vezi de unde vine fiecare valoare: ```bash git config user.name "Nume (local)" git config --show-origin --get-all user.name git config --show-scope user.name git config --unset user.name ``` 2. Creează un șablon pentru mesajele de commit și activează-l doar în acest depozit: ```bash printf 'Rezumat (max. 50 de caractere)\n\nDe ce:\n\n[ref: ]\n' > .git/sablon.txt git config commit.template .git/sablon.txt git commit --allow-empty # se deschide editorul cu șablonul ``` 3. Adaugă două alias-uri utile (de ex. `st` pentru `status -s` și `ultimul` pentru `log -1 HEAD`) și unul care rulează o comandă externă, cu `!` (de ex. `git config… Vreau să-mi aleg 5 setări de configurare utile pentru lucrul zilnic. Întreabă-mă cum lucrez (editor, sistem de operare, cât de des fac commit) și lasă-mă să propun setările; verifică-le după capitolul 8.

Deschide în Claude ↗
autocrlfînțelegi problema sfârșiturilor de linie

Lucrez la exercițiul „Niveluri de configurare, alias-uri și șablon de commit” din capitolul „8. Customizing Git”, la Pro Git. Enunțul: Într-un depozit de test: 1. Suprascrie numele doar local și vezi de unde vine fiecare valoare: ```bash git config user.name "Nume (local)" git config --show-origin --get-all user.name git config --show-scope user.name git config --unset user.name ``` 2. Creează un șablon pentru mesajele de commit și activează-l doar în acest depozit: ```bash printf 'Rezumat (max. 50 de caractere)\n\nDe ce:\n\n[ref: ]\n' > .git/sablon.txt git config commit.template .git/sablon.txt git commit --allow-empty # se deschide editorul cu șablonul ``` 3. Adaugă două alias-uri utile (de ex. `st` pentru `status -s` și `ultimul` pentru `log -1 HEAD`) și unul care rulează o comandă externă, cu `!` (de ex. `git config… Pune-mi întrebări despre ce se întâmplă cu sfârșiturile de linie când lucrez cu un coleg pe Windows, până pot explica singur valorile `true`, `input` și `false` ale lui `core.autocrlf`.

Deschide în Claude ↗
de făcut

Atribute Git - export-ignore, filtre și textconv

nivel 2
git init atribute && cd atribute
mkdir test; echo t > test/t.txt; echo cod > app.txt
printf 'test/ export-ignore\n*.txt filter=majuscule\n' > .gitattributes
git config filter.majuscule.clean "tr '[:lower:]' '[:upper:]'"
git config filter.majuscule.smudge cat
echo "salut lume" > nota.txt
git add .; git commit -m "init"
cat nota.txt
git show HEAD:nota.txt
git status -s
git archive --format=tar HEAD | tar t

Apoi un diff lizibil pentru fișiere binare (are nevoie de xxd, prezent pe macOS și pe majoritatea Linux):

printf '*.hex diff=hexa\n' >> .gitattributes
git config diff.hexa.textconv xxd
printf '\x00\x01AB' > d.hex; git add .; git commit -m "binar"
printf '\x00\x02AB' > d.hex
git diff d.hex

Răspunde: când rulează filtrul clean și când smudge? De ce git status nu arată nota.txt modificat, deși pe disc și în depozit textul diferă?

Cum îți verifici singur rezultatul
  • cat nota.txt → salut lume, dar git show HEAD:nota.txt → SALUT LUME: clean a rulat la git add (spre depozit), smudge (aici cat) la checkout (spre directorul de lucru).
  • git status -s nu afișează nimic: Git compară fișierul după trecerea prin clean.
  • Arhiva conține .gitattributes, app.txt, nota.txt, dar nu test/.
  • git diff d.hex arată linii xxd: -00000000: 0001 4142 ..AB și +00000000: 0002 4142 ..AB, în loc de Binary files differ.

Întreabă AI-ul ca să înveți

Copiază o întrebare într-un asistent AI. Sunt scrise ca AI-ul să te pună să gândești și să-ți dea indicii, nu răspunsul gata făcut.

Unde rulează filtreleurmărești drumul unui fișier prin clean și smudge

Lucrez la exercițiul „Atribute Git - export-ignore, filtre și textconv” din capitolul „8. Customizing Git”, la Pro Git. Enunțul: ```bash git init atribute && cd atribute mkdir test; echo t > test/t.txt; echo cod > app.txt printf 'test/ export-ignore\n*.txt filter=majuscule\n' > .gitattributes git config filter.majuscule.clean "tr '[:lower:]' '[:upper:]'" git config filter.majuscule.smudge cat echo "salut lume" > nota.txt git add .; git commit -m "init" cat nota.txt git show HEAD:nota.txt git status -s git archive --format=tar HEAD | tar t ``` Apoi un diff lizibil pentru fișiere binare (are nevoie de `xxd`, prezent pe macOS și pe majoritatea Linux): ```bash printf '*.hex diff=hexa\n' >> .gitattributes git config diff.hexa.textconv xxd printf '\x00\x01AB' > d.hex; git add .; git commit -m "binar" printf '\x00\x02AB' >… Întreabă-mă pe ce drum merge un fișier la `git add` și la `git checkout` și unde se aplică fiecare filtru. Lasă-mă să desenez schema și verifică-mi-o cu indicii.

Deschide în Claude ↗
Un filtru utilîți proiectezi propriul filtru

Lucrez la exercițiul „Atribute Git - export-ignore, filtre și textconv” din capitolul „8. Customizing Git”, la Pro Git. Enunțul: ```bash git init atribute && cd atribute mkdir test; echo t > test/t.txt; echo cod > app.txt printf 'test/ export-ignore\n*.txt filter=majuscule\n' > .gitattributes git config filter.majuscule.clean "tr '[:lower:]' '[:upper:]'" git config filter.majuscule.smudge cat echo "salut lume" > nota.txt git add .; git commit -m "init" cat nota.txt git show HEAD:nota.txt git status -s git archive --format=tar HEAD | tar t ``` Apoi un diff lizibil pentru fișiere binare (are nevoie de `xxd`, prezent pe macOS și pe majoritatea Linux): ```bash printf '*.hex diff=hexa\n' >> .gitattributes git config diff.hexa.textconv xxd printf '\x00\x01AB' > d.hex; git add .; git commit -m "binar" printf '\x00\x02AB' >… Vreau să folosesc un filtru real (de ex. pentru a scoate o parolă dintr-un fișier de configurare înainte de commit). Lasă-mă să propun regulile din `.gitattributes` și comenzile clean / smudge, apoi verifică-le și spune-mi ce riscuri am omis.

Deschide în Claude ↗
de făcut

Un hook pre-commit care oprește TODO-urile

nivel 2

Într-un depozit de test, creează fișierul .git/hooks/pre-commit:

#!/bin/sh
if git diff --cached | grep -q '^+.*TODO'; then
  echo "pre-commit: ai lăsat un TODO în modificările din staging" >&2
  exit 1
fi
chmod +x .git/hooks/pre-commit
echo "x = 1  # TODO" > a.py
git add a.py
git commit -m "cu TODO"; echo "cod de ieșire: $?"
git commit --no-verify -m "forțat"; echo "cod de ieșire: $?"
git log --oneline

Apoi modifică hook-ul ca să oprească și liniile cu spații la final (indiciu: git diff --cached --check întoarce un cod de ieșire diferit de 0 când găsește probleme) și testează-l.

Răspunde: de ce hook-urile din .git/hooks nu ajung la colegi când fac git clone?

Cum îți verifici singur rezultatul
  • Primul commit e oprit: apare mesajul hook-ului și cod de ieșire: 1; git log nu are commitul.
  • Cu --no-verify commitul trece (cod de ieșire: 0): hook-urile client se pot ocoli, deci nu sunt o politică sigură.
  • Varianta extinsă poate adăuga, de ex., git diff --cached --check || exit 1; un fișier cu spații la final e oprit.
  • .git/hooks nu face parte din depozit (nu e versionat), deci nu se clonează.

Întreabă AI-ul ca să înveți

Copiază o întrebare într-un asistent AI. Sunt scrise ca AI-ul să te pună să gândești și să-ți dea indicii, nu răspunsul gata făcut.

Verifică-mi hook-ulprimești feedback pe scriptul tău

Lucrez la exercițiul „Un hook pre-commit care oprește TODO-urile” din capitolul „8. Customizing Git”, la Pro Git. Enunțul: Într-un depozit de test, creează fișierul `.git/hooks/pre-commit`: ```sh #!/bin/sh if git diff --cached | grep -q '^+.*TODO'; then echo "pre-commit: ai lăsat un TODO în modificările din staging" >&2 exit 1 fi ``` ```bash chmod +x .git/hooks/pre-commit echo "x = 1 # TODO" > a.py git add a.py git commit -m "cu TODO"; echo "cod de ieșire: $?" git commit --no-verify -m "forțat"; echo "cod de ieșire: $?" git log --oneline ``` Apoi modifică hook-ul ca să oprească și liniile cu spații la final (indiciu: `git diff --cached --check` întoarce un cod de ieșire diferit de 0 când găsește probleme) și testează-l. Răspunde: de ce hook-urile din `.git/hooks` nu ajung la colegi când fac `git clone`? Îți lipesc varianta mea extinsă a hook-ului pre-commit. Verifică dacă face ce trebuie și dacă întoarce codurile de ieșire corecte; dacă găsești o greșeală, dă-mi un indiciu, nu scriptul corectat.

Deschide în Claude ↗
Client sau serverdeosebești hook-urile client de cele server

Lucrez la exercițiul „Un hook pre-commit care oprește TODO-urile” din capitolul „8. Customizing Git”, la Pro Git. Enunțul: Într-un depozit de test, creează fișierul `.git/hooks/pre-commit`: ```sh #!/bin/sh if git diff --cached | grep -q '^+.*TODO'; then echo "pre-commit: ai lăsat un TODO în modificările din staging" >&2 exit 1 fi ``` ```bash chmod +x .git/hooks/pre-commit echo "x = 1 # TODO" > a.py git add a.py git commit -m "cu TODO"; echo "cod de ieșire: $?" git commit --no-verify -m "forțat"; echo "cod de ieșire: $?" git log --oneline ``` Apoi modifică hook-ul ca să oprească și liniile cu spații la final (indiciu: `git diff --cached --check` întoarce un cod de ieșire diferit de 0 când găsește probleme) și testează-l. Răspunde: de ce hook-urile din `.git/hooks` nu ajung la colegi când fac `git clone`? Pune-mi întrebări ca să ajung singur la concluzia de ce o regulă importantă a echipei trebuie verificată pe server, nu doar într-un hook client. Corectează-mă cu indicii.

Deschide în Claude ↗
de făcut

Un hook commit-msg care cere o referință

nivel 2

Echipa vrea ca fiecare mesaj de commit să conțină o referință la o sarcină, de forma [ref: 123]. 1. Scrie hook-ul .git/hooks/commit-msg. Indicii: primește ca prim argument ($1) calea către fișierul cu mesajul; dacă iese cu un cod diferit de 0, commitul se anulează; grep -qE '\[ref: [0-9]+\]' caută tiparul. 2. Fă-l executabil (chmod +x) și testează:

echo y > b.txt; git add b.txt
git commit -m "Fără referință"; echo "cod: $?"
git commit -m "Adaug b [ref: 42]"; echo "cod: $?"
git log --oneline -2
  1. Bonus: modifică hook-ul prepare-commit-msg astfel încât mesajul propus să înceapă automat cu [ref: ] (citește în carte ce argumente primește).
Cum îți verifici singur rezultatul
  • Primul commit e oprit (mesajul tău de eroare, cod: 1); al doilea trece (cod: 0) și apare în log ca … Adaug b [ref: 42].
  • O soluție minimă: if ! grep -qE '\[ref: [0-9]+\]' "$1"; then echo "…" >&2; exit 1; fi.
  • Hook-ul nu rulează la git commit --no-verify.

Întreabă AI-ul ca să înveți

Copiază o întrebare într-un asistent AI. Sunt scrise ca AI-ul să te pună să gândești și să-ți dea indicii, nu răspunsul gata făcut.

Indicii pentru scriptscrii singur hook-ul cu ajutor minim

Lucrez la exercițiul „Un hook commit-msg care cere o referință” din capitolul „8. Customizing Git”, la Pro Git. Enunțul: Echipa vrea ca fiecare mesaj de commit să conțină o referință la o sarcină, de forma `[ref: 123]`. 1. Scrie hook-ul `.git/hooks/commit-msg`. Indicii: primește ca prim argument (`$1`) calea către fișierul cu mesajul; dacă iese cu un cod diferit de 0, commitul se anulează; `grep -qE '\[ref: [0-9]+\]'` caută tiparul. 2. Fă-l executabil (`chmod +x`) și testează: ```bash echo y > b.txt; git add b.txt git commit -m "Fără referință"; echo "cod: $?" git commit -m "Adaug b [ref: 42]"; echo "cod: $?" git log --oneline -2 ``` 3. Bonus: modifică hook-ul `prepare-commit-msg` astfel încât mesajul propus să înceapă automat cu `[ref: ]` (citește în carte ce argumente primește). Vreau să scriu singur hook-ul commit-msg. Întreabă-mă ce primește scriptul și ce trebuie să întoarcă, apoi lasă-mă să scriu codul. Dacă nu merge, dă-mi un singur indiciu odată, nu soluția.

Deschide în Claude ↗
Testez cazurile limităverifici hook-ul pe cazuri neobișnuite

Lucrez la exercițiul „Un hook commit-msg care cere o referință” din capitolul „8. Customizing Git”, la Pro Git. Enunțul: Echipa vrea ca fiecare mesaj de commit să conțină o referință la o sarcină, de forma `[ref: 123]`. 1. Scrie hook-ul `.git/hooks/commit-msg`. Indicii: primește ca prim argument (`$1`) calea către fișierul cu mesajul; dacă iese cu un cod diferit de 0, commitul se anulează; `grep -qE '\[ref: [0-9]+\]'` caută tiparul. 2. Fă-l executabil (`chmod +x`) și testează: ```bash echo y > b.txt; git add b.txt git commit -m "Fără referință"; echo "cod: $?" git commit -m "Adaug b [ref: 42]"; echo "cod: $?" git log --oneline -2 ``` 3. Bonus: modifică hook-ul `prepare-commit-msg` astfel încât mesajul propus să înceapă automat cu `[ref: ]` (citește în carte ce argumente primește). Ajută-mă să găsesc cazuri limită pentru hook (`[ref:42]` fără spațiu, `[REF: 1]`, referința în corpul mesajului, commit de merge). Întreabă-mă ce cred că se întâmplă în fiecare caz înainte să testez și verifică-mi concluziile.

Deschide în Claude ↗
de făcut

Politica echipei impusă pe server cu hook-ul update

nivel 3

Hook-urile client se pot ocoli; pe server, hook-ul update poate respinge un push. Creează un depozit bare și hook-ul server.git/hooks/update (primește: numele referinței, hash-ul vechi, hash-ul nou):

#!/bin/sh
refname="$1"; oldrev="$2"; newrev="$3"
zero=0000000000000000000000000000000000000000
if [ "$oldrev" = "$zero" ]; then range="$newrev"; else range="$oldrev..$newrev"; fi
for rev in $(git rev-list "$range"); do
  if ! git log -1 --format=%B "$rev" | grep -qE '\[ref: [0-9]+\]'; then
    echo "[POLITICĂ] commit-ul $(git rev-parse --short $rev) nu are [ref: <număr>]"
    exit 1
  fi
done
exit 0
git init --bare server.git          # apoi creează hook-ul de mai sus și: chmod +x server.git/hooks/update
git clone server.git client && cd client
echo a > a; git add .; git commit -m "Inițial [ref: 1]"; git push origin main
echo b > b; git add .; git commit -m "Fără ref"; git push origin main
git commit --amend -m "Cu ref [ref: 2]"; git push origin main
git ls-remote origin

Răspunde: de ce --no-verify nu mai ajută aici? Ce ar trebui adăugat ca serverul să refuze și push-urile forțate?

Cum îți verifici singur rezultatul
  • Primul push reușește. Al doilea afișează remote: [POLITICĂ] commit-ul … nu are [ref: <număr>], remote: error: hook declined to update refs/heads/main și ! [remote rejected] main -> main (hook declined).
  • După --amend, push-ul reușește; ls-remote arată noul hash pentru refs/heads/main.
  • --no-verify sare doar hook-urile locale; update rulează pe server.
  • Pentru push forțat: hook-ul poate verifica dacă oldrev e strămoș al lui newrev (git merge-base --is-ancestor) sau se setează receive.denyNonFastForwards true pe server.

Întreabă AI-ul ca să înveți

Copiază o întrebare într-un asistent AI. Sunt scrise ca AI-ul să te pună să gândești și să-ți dea indicii, nu răspunsul gata făcut.

Urmăresc argumenteleînțelegi ce primește hook-ul update

Lucrez la exercițiul „Politica echipei impusă pe server cu hook-ul update” din capitolul „8. Customizing Git”, la Pro Git. Enunțul: Hook-urile client se pot ocoli; pe server, hook-ul `update` poate respinge un push. Creează un depozit bare și hook-ul `server.git/hooks/update` (primește: numele referinței, hash-ul vechi, hash-ul nou): ```sh #!/bin/sh refname="$1"; oldrev="$2"; newrev="$3" zero=0000000000000000000000000000000000000000 if [ "$oldrev" = "$zero" ]; then range="$newrev"; else range="$oldrev..$newrev"; fi for rev in $(git rev-list "$range"); do if ! git log -1 --format=%B "$rev" | grep -qE '\[ref: [0-9]+\]'; then echo "[POLITICĂ] commit-ul $(git rev-parse --short $rev) nu are [ref: ]" exit 1 fi done exit 0 ``` ```bash git init --bare server.git # apoi creează hook-ul de mai sus și: chmod +x… Întreabă-mă ce valori cred că primește hook-ul la primul push și la al doilea (referința, hash-ul vechi, hash-ul nou) și de ce scriptul tratează separat hash-ul plin de zerouri. Corectează-mă cu indicii.

Deschide în Claude ↗
Extind politicaadaugi singur o regulă nouă

Lucrez la exercițiul „Politica echipei impusă pe server cu hook-ul update” din capitolul „8. Customizing Git”, la Pro Git. Enunțul: Hook-urile client se pot ocoli; pe server, hook-ul `update` poate respinge un push. Creează un depozit bare și hook-ul `server.git/hooks/update` (primește: numele referinței, hash-ul vechi, hash-ul nou): ```sh #!/bin/sh refname="$1"; oldrev="$2"; newrev="$3" zero=0000000000000000000000000000000000000000 if [ "$oldrev" = "$zero" ]; then range="$newrev"; else range="$oldrev..$newrev"; fi for rev in $(git rev-list "$range"); do if ! git log -1 --format=%B "$rev" | grep -qE '\[ref: [0-9]+\]'; then echo "[POLITICĂ] commit-ul $(git rev-parse --short $rev) nu are [ref: ]" exit 1 fi done exit 0 ``` ```bash git init --bare server.git # apoi creează hook-ul de mai sus și: chmod +x… Vreau să adaug în hook o regulă care refuză push-urile non-fast-forward. Lasă-mă să o scriu eu, apoi verifică-mi codul și testul pe care îl propun, fără să-mi dai varianta corectă.

Deschide în Claude ↗

🔄 9. Git and Other Systems

de făcut

Migrează copii de rezervă datate într-un istoric Git

nivel 2

Cartea descrie importul unui proiect ținut ca directoare back_AAAA_LL_ZZ. Faci același lucru cu comenzi obișnuite. 1. Simulează copiile vechi:

mkdir migrare && cd migrare
mkdir -p snap/back_2014_01_02 snap/back_2014_01_07 snap/back_2014_01_15
echo v1 > snap/back_2014_01_02/index.html
echo v2 > snap/back_2014_01_07/index.html; echo css > snap/back_2014_01_07/stil.css
echo v3 > snap/back_2014_01_15/index.html
  1. Creează depozitul și importă fiecare director ca un commit, în ordine, cu data copiei:
git init mig && cd mig
for d in ../snap/back_*; do
  data=$(basename $d | sed 's/back_//; s/_/-/g')
  git rm -rq --ignore-unmatch .
  cp -R $d/. .
  git add -A
  GIT_AUTHOR_DATE="$data 12:00" GIT_COMMITTER_DATE="$data 12:00" \
    git commit -q -m "Importat din $(basename $d)"
done
git log --format='%ad %s' --date=short --stat

Răspunde: de ce e nevoie de git rm -rq . înainte de copiere? Ce s-ar fi întâmplat cu stil.css fără el?

Cum îți verifici singur rezultatul
  • Trei commituri, cu datele 2014-01-02, 2014-01-07, 2014-01-15 și mesajele „Importat din back_…”.
  • --stat arată: primul commit adaugă index.html; al doilea modifică index.html și adaugă stil.css; al treilea modifică index.html și șterge stil.css.
  • Fără git rm, stil.css ar fi rămas în ultimul commit, deși nu exista în ultima copie: fiecare commit trebuie să fie instantaneul exact al directorului.

Întreabă AI-ul ca să înveți

Copiază o întrebare într-un asistent AI. Sunt scrise ca AI-ul să te pună să gândești și să-ți dea indicii, nu răspunsul gata făcut.

Înțeleg scriptulexplici fiecare linie a buclei de import

Lucrez la exercițiul „Migrează copii de rezervă datate într-un istoric Git” din capitolul „9. Git and Other Systems”, la Pro Git. Enunțul: Cartea descrie importul unui proiect ținut ca directoare `back_AAAA_LL_ZZ`. Faci același lucru cu comenzi obișnuite. 1. Simulează copiile vechi: ```bash mkdir migrare && cd migrare mkdir -p snap/back_2014_01_02 snap/back_2014_01_07 snap/back_2014_01_15 echo v1 > snap/back_2014_01_02/index.html echo v2 > snap/back_2014_01_07/index.html; echo css > snap/back_2014_01_07/stil.css echo v3 > snap/back_2014_01_15/index.html ``` 2. Creează depozitul și importă fiecare director ca un commit, în ordine, cu data copiei: ```bash git init mig && cd mig for d in ../snap/back_*; do data=$(basename $d | sed 's/back_//; s/_/-/g') git rm -rq --ignore-unmatch . cp -R $d/. . git add -A GIT_AUTHOR_DATE="$data… Întreabă-mă, linie cu linie, ce face bucla de import (calculul datei, `git rm`, `cp`, `git add -A`, variabilele de mediu). Lasă-mă să explic eu și dă-mi indicii unde nu sunt sigur.

Deschide în Claude ↗
Migrarea unui proiect realîți planifici o migrare reală

Lucrez la exercițiul „Migrează copii de rezervă datate într-un istoric Git” din capitolul „9. Git and Other Systems”, la Pro Git. Enunțul: Cartea descrie importul unui proiect ținut ca directoare `back_AAAA_LL_ZZ`. Faci același lucru cu comenzi obișnuite. 1. Simulează copiile vechi: ```bash mkdir migrare && cd migrare mkdir -p snap/back_2014_01_02 snap/back_2014_01_07 snap/back_2014_01_15 echo v1 > snap/back_2014_01_02/index.html echo v2 > snap/back_2014_01_07/index.html; echo css > snap/back_2014_01_07/stil.css echo v3 > snap/back_2014_01_15/index.html ``` 2. Creează depozitul și importă fiecare director ca un commit, în ordine, cu data copiei: ```bash git init mig && cd mig for d in ../snap/back_*; do data=$(basename $d | sed 's/back_//; s/_/-/g') git rm -rq --ignore-unmatch . cp -R $d/. . git add -A GIT_AUTHOR_DATE="$data… Am un proiect vechi ținut în arhive zip cu date în nume. Ajută-mă să-mi planific migrarea cu întrebări (ordine, autori, fișiere de ignorat, verificare la final), fără să-mi dai scriptul complet.

Deschide în Claude ↗
de făcut

Scrie de mână un flux pentru git fast-import

nivel 3

git fast-import primește la intrare un text care descrie commituri. Creează fișierul import.txt (forma data <<END … END te scutește de numărarea octeților):

commit refs/heads/main
mark :1
committer Ion Vechi <ion@example.com> 1388664000 +0200
data <<END
Importat: 2014-01-02
END
M 644 inline README.md
data <<END
Versiune veche
END
M 644 inline note.txt
data <<END
prima
END

commit refs/heads/main
mark :2
committer Ion Vechi <ion@example.com> 1389096000 +0200
data <<END
Importat: 2014-01-07
END
from :1
M 644 inline note.txt
data <<END
prima
a doua
END
D README.md

git init imp && cd imp
git fast-import < ../import.txt
git log --format='%h %ad %an %s' --date=short
git show --stat HEAD
git status -s
git reset --hard
ls; cat note.txt

Apoi adaugă un al treilea commit (cu from :2) care creează noutati.txt, și reimportă într-un depozit nou.

Cum îți verifici singur rezultatul
  • fast-import afișează statistici (2 commituri); log-ul arată f0a0c52 2014-01-07 Ion Vechi Importat: 2014-01-07 și 050c9d9 2014-01-02 Ion Vechi Importat: 2014-01-02. Hash-urile sunt aceleași pe orice calculator, pentru că autorul, data și conținutul sunt fixate în flux.
  • git show --stat HEAD: README.md șters, note.txt cu o linie adăugată.
  • Imediat după import, git status -s arată fișiere ca șterse (directorul de lucru e gol); după git reset --hard apar note.txt cu „prima / a doua”.

Întreabă AI-ul ca să înveți

Copiază o întrebare într-un asistent AI. Sunt scrise ca AI-ul să te pună să gândești și să-ți dea indicii, nu răspunsul gata făcut.

Citesc fluxulînțelegi fiecare comandă din flux

Lucrez la exercițiul „Scrie de mână un flux pentru git fast-import” din capitolul „9. Git and Other Systems”, la Pro Git. Enunțul: `git fast-import` primește la intrare un text care descrie commituri. Creează fișierul `import.txt` (forma `data < 1388664000 +0200 data < 1389096000 +0200 data < Întreabă-mă ce înseamnă fiecare linie din flux (`mark`, `committer` cu timestamp, `from`, `M 644 inline`, `D`) și lasă-mă să explic. Dă-mi indicii dacă nu știu de ce al doilea commit are nevoie de `from :1`.

Deschide în Claude ↗
Depanez importulprimești indicii când fast-import eșuează

Lucrez la exercițiul „Scrie de mână un flux pentru git fast-import” din capitolul „9. Git and Other Systems”, la Pro Git. Enunțul: `git fast-import` primește la intrare un text care descrie commituri. Creează fișierul `import.txt` (forma `data < 1388664000 +0200 data < 1389096000 +0200 data < Îți lipesc eroarea primită de la `git fast-import` și fluxul meu. Nu-mi corecta fișierul; pune-mi întrebări și dă-mi indicii (lungimea datelor, linii goale, ordinea comenzilor) până găsesc singur problema.

Deschide în Claude ↗
de făcut

Unifică autorii după o migrare cu .mailmap

nivel 2

La migrare, același om apare adesea sub mai multe identități (de ex. utilizatorul din SVN și adresa reală — de aceea git svn și importatoarele folosesc un fișier de autori). Într-un depozit de test:

git commit --allow-empty --author="ion <ion@old-server>" -m "commit vechi"
git commit --allow-empty --author="Ion Vechi <ion@example.com>" -m "commit nou"
git shortlog -sne HEAD
printf 'Ion Vechi <ion@example.com> ion <ion@old-server>\n' > .mailmap
git shortlog -sne HEAD
git log -2 --format='%an | %aN'

Atenție: dă întotdeauna o revizie (HEAD) lui git shortlog într-un script; fără ea, comanda citește de la intrarea standard când nu rulează într-un terminal.

Răspunde: rescrie .mailmap istoria? Ce diferență este față de un fișier de autori folosit la import?

Cum îți verifici singur rezultatul
  • Înainte: shortlog arată două linii separate, Ion Vechi <ion@example.com> și ion <ion@old-server>.
  • După .mailmap: o singură linie 2 Ion Vechi <ion@example.com> (plus ceilalți autori ai depozitului).
  • %an arată numele original (ion), %aN numele după mailmap (Ion Vechi): istoria (și hash-urile) nu se schimbă.
  • Un fișier de autori folosit la import scrie direct numele corecte în commituri, deci schimbă hash-urile pentru totdeauna.

Întreabă AI-ul ca să înveți

Copiază o întrebare într-un asistent AI. Sunt scrise ca AI-ul să te pună să gândești și să-ți dea indicii, nu răspunsul gata făcut.

Rescriere sau afișaredeosebești mailmap de rescrierea istoriei

Lucrez la exercițiul „Unifică autorii după o migrare cu .mailmap” din capitolul „9. Git and Other Systems”, la Pro Git. Enunțul: La migrare, același om apare adesea sub mai multe identități (de ex. utilizatorul din SVN și adresa reală — de aceea `git svn` și importatoarele folosesc un fișier de autori). Într-un depozit de test: ```bash git commit --allow-empty --author="ion " -m "commit vechi" git commit --allow-empty --author="Ion Vechi " -m "commit nou" git shortlog -sne HEAD printf 'Ion Vechi ion \n' > .mailmap git shortlog -sne HEAD git log -2 --format='%an | %aN' ``` **Atenție:** dă întotdeauna o revizie (`HEAD`) lui `git shortlog` într-un script; fără ea, comanda citește de la intrarea standard când nu rulează într-un terminal. Răspunde: rescrie `.mailmap` istoria? Ce diferență este față de un fișier de autori… Întreabă-mă ce cred că se întâmplă cu hash-urile după ce adaug `.mailmap` și ce s-ar întâmpla dacă aș corecta autorii cu un import nou. Lasă-mă să verific singur cu `git log` și confirmă-mi doar după aceea.

Deschide în Claude ↗
Formatul mailmapîți verifici liniile din .mailmap

Lucrez la exercițiul „Unifică autorii după o migrare cu .mailmap” din capitolul „9. Git and Other Systems”, la Pro Git. Enunțul: La migrare, același om apare adesea sub mai multe identități (de ex. utilizatorul din SVN și adresa reală — de aceea `git svn` și importatoarele folosesc un fișier de autori). Într-un depozit de test: ```bash git commit --allow-empty --author="ion " -m "commit vechi" git commit --allow-empty --author="Ion Vechi " -m "commit nou" git shortlog -sne HEAD printf 'Ion Vechi ion \n' > .mailmap git shortlog -sne HEAD git log -2 --format='%an | %aN' ``` **Atenție:** dă întotdeauna o revizie (`HEAD`) lui `git shortlog` într-un script; fără ea, comanda citește de la intrarea standard când nu rulează într-un terminal. Răspunde: rescrie `.mailmap` istoria? Ce diferență este față de un fișier de autori… Îți lipesc fișierul meu `.mailmap` pentru trei identități ale aceleiași persoane. Verifică-l și, dacă o linie nu face ce vreau, dă-mi un indiciu despre ordinea numelui canonic și a celui vechi.

Deschide în Claude ↗
întrebare de gândit

Git ca client pentru Subversion - ce și de ce

nivel 2

Răspunde pe baza secțiunii „Git as a Client” (nu ai nevoie de un server Subversion): 1. De ce git svn dcommit rescrie commiturile tale locale (îți schimbă hash-urile)? 2. De ce cartea recomandă ca istoria trimisă cu git svn să fie liniară și să eviți git merge între ramuri care ajung în Subversion? Ce face git svn rebase în locul lui git pull? 3. De ce nu e bine să lucrezi în paralel cu colegi care folosesc Git, prin push direct între voi, pe ramuri care merg și în Subversion? 4. Ce aduce în plus o migrare completă la Git față de folosirea lui git svn ca punte? 5. Ce informație trebuie pregătită la migrare ca autorii din Subversion să devină identități Git corecte?

Cum îți verifici singur rezultatul

1 — fiecare commit trimis devine o revizie SVN, iar Git îl rescrie cu identificatorul de revizie (git-svn-id). 2 — Subversion nu înțelege commiturile cu doi părinți; git svn rebase aduce reviziile noi și îți mută commiturile locale deasupra lor (istorie liniară). 3 — commiturile rescrise la dcommit ar intra în conflict cu copiile colegilor (problema rebase-ului pe commituri publicate). 4 — ramuri, merge-uri și tot fluxul distribuit nativ. 5 — un fișier de autori care leagă utilizatorii SVN de nume și e-mailuri (--authors-file).

Întreabă AI-ul ca să înveți

Copiază o întrebare într-un asistent AI. Sunt scrise ca AI-ul să te pună să gândești și să-ți dea indicii, nu răspunsul gata făcut.

Explic cu un desenexplici de ce dcommit rescrie commiturile

Lucrez la exercițiul „Git ca client pentru Subversion - ce și de ce” din capitolul „9. Git and Other Systems”, la Pro Git. Enunțul: Răspunde pe baza secțiunii „Git as a Client” (nu ai nevoie de un server Subversion): 1. De ce `git svn dcommit` rescrie commiturile tale locale (îți schimbă hash-urile)? 2. De ce cartea recomandă ca istoria trimisă cu `git svn` să fie liniară și să eviți `git merge` între ramuri care ajung în Subversion? Ce face `git svn rebase` în locul lui `git pull`? 3. De ce nu e bine să lucrezi în paralel cu colegi care folosesc Git, prin push direct între voi, pe ramuri care merg și în Subversion? 4. Ce aduce în plus o migrare completă la Git față de folosirea lui `git svn` ca punte? 5. Ce informație trebuie pregătită la migrare ca autorii din Subversion să devină identități Git corecte? Vreau să explic cu un desen de commituri ce se întâmplă la `git svn dcommit`. Întreabă-mă pas cu pas ce devine fiecare commit local și verifică-mi desenul cu indicii, fără să-l faci tu.

Deschide în Claude ↗
Leg de capitolul 3legi git svn de pericolele rebase-ului

Lucrez la exercițiul „Git ca client pentru Subversion - ce și de ce” din capitolul „9. Git and Other Systems”, la Pro Git. Enunțul: Răspunde pe baza secțiunii „Git as a Client” (nu ai nevoie de un server Subversion): 1. De ce `git svn dcommit` rescrie commiturile tale locale (îți schimbă hash-urile)? 2. De ce cartea recomandă ca istoria trimisă cu `git svn` să fie liniară și să eviți `git merge` între ramuri care ajung în Subversion? Ce face `git svn rebase` în locul lui `git pull`? 3. De ce nu e bine să lucrezi în paralel cu colegi care folosesc Git, prin push direct între voi, pe ramuri care merg și în Subversion? 4. Ce aduce în plus o migrare completă la Git față de folosirea lui `git svn` ca punte? 5. Ce informație trebuie pregătită la migrare ca autorii din Subversion să devină identități Git corecte? Pune-mi întrebări care să mă facă să leg recomandările pentru `git svn` de regula din capitolul 3 despre rebase pe commituri publicate. Verifică-mi apoi răspunsul la întrebarea 3.

Deschide în Claude ↗

🔩 10. Git Internals

de făcut

Git ca bază de date cheie-valoare - blob-uri

nivel 1
git init interne && cd interne
find .git/objects -type f
echo 'test content' | git hash-object --stdin
echo 'test content' | git hash-object -w --stdin
find .git/objects -type f
git cat-file -t d670460b
git cat-file -s d670460b
git cat-file -p d670460b4b4aece5915caf5c68d12f560a9fe3e4
echo 'version 1' > test.txt; git hash-object -w test.txt
echo 'version 2' > test.txt; git hash-object -w test.txt
rm test.txt
git cat-file -p 83baae61804e65cc73a7201a7252750c76066a30 > test.txt; cat test.txt

Bonus: verifică singur formula hash-ului (antet blob <dimensiune>\0 + conținut, SHA-1): printf 'blob 13\0test content\n' | shasum (sau sha1sum pe Linux).

Răspunde: de ce hash-ul pentru „test content” e același pe calculatorul tău și al colegului?

Cum îți verifici singur rezultatul
  • Înainte: nicio linie; hash-object --stdin → d670460b4b4aece5915caf5c68d12f560a9fe3e4 (fără -w nu scrie nimic).
  • După -w apare .git/objects/d6/70460b4b4aece5915caf5c68d12f560a9fe3e4 (primele 2 caractere = director).
  • cat-file -t → blob, -s → 13, -p → test content.
  • version 1 → 83baae61804e65cc73a7201a7252750c76066a30, version 2 → 1f7a7a472abf3dd9643fd615f6da379c4acb3e3a; după rm, fișierul se reface din blob și conține version 1.
  • shasum dă tot d670460b…: hash-ul depinde doar de conținut, nu de nume, dată sau calculator.

Întreabă AI-ul ca să înveți

Copiază o întrebare într-un asistent AI. Sunt scrise ca AI-ul să te pună să gândești și să-ți dea indicii, nu răspunsul gata făcut.

De ce același hashînțelegi adresarea după conținut

Lucrez la exercițiul „Git ca bază de date cheie-valoare - blob-uri” din capitolul „10. Git Internals”, la Pro Git. Enunțul: ```bash git init interne && cd interne find .git/objects -type f echo 'test content' | git hash-object --stdin echo 'test content' | git hash-object -w --stdin find .git/objects -type f git cat-file -t d670460b git cat-file -s d670460b git cat-file -p d670460b4b4aece5915caf5c68d12f560a9fe3e4 echo 'version 1' > test.txt; git hash-object -w test.txt echo 'version 2' > test.txt; git hash-object -w test.txt rm test.txt git cat-file -p 83baae61804e65cc73a7201a7252750c76066a30 > test.txt; cat test.txt ``` Bonus: verifică singur formula hash-ului (antet `blob \0` + conținut, SHA-1): `printf 'blob 13\0test content\n' | shasum` (sau `sha1sum` pe Linux). Răspunde: de ce hash-ul pentru „test content”… Întreabă-mă ce intră în calculul hash-ului unui blob și ce nu (numele fișierului, data, autorul). Lasă-mă să deduc singur de ce doi oameni obțin același hash și ce înseamnă „content-addressable”.

Deschide în Claude ↗
Unde e numele fișieruluidescoperi că blob-ul nu ține numele

Lucrez la exercițiul „Git ca bază de date cheie-valoare - blob-uri” din capitolul „10. Git Internals”, la Pro Git. Enunțul: ```bash git init interne && cd interne find .git/objects -type f echo 'test content' | git hash-object --stdin echo 'test content' | git hash-object -w --stdin find .git/objects -type f git cat-file -t d670460b git cat-file -s d670460b git cat-file -p d670460b4b4aece5915caf5c68d12f560a9fe3e4 echo 'version 1' > test.txt; git hash-object -w test.txt echo 'version 2' > test.txt; git hash-object -w test.txt rm test.txt git cat-file -p 83baae61804e65cc73a7201a7252750c76066a30 > test.txt; cat test.txt ``` Bonus: verifică singur formula hash-ului (antet `blob \0` + conținut, SHA-1): `printf 'blob 13\0test content\n' | shasum` (sau `sha1sum` pe Linux). Răspunde: de ce hash-ul pentru „test content”… Am observat că blob-ul nu conține numele `test.txt`. Pune-mi întrebări care să mă ducă la obiectul care ține numele fișierelor, fără să mi-l numești direct.

Deschide în Claude ↗
de făcut

Construiește un commit doar cu comenzi plumbing

nivel 2

Continuă în depozitul interne (are blob-urile version 1 și version 2).

git update-index --add --cacheinfo 100644 83baae61804e65cc73a7201a7252750c76066a30 test.txt
git write-tree
git cat-file -p d8329fc1cc938780ffdd9f94e0d364e0ea74f579
c1=$(echo 'Primul commit' | git commit-tree d8329f)
git cat-file -p $c1
echo 'version 2' > test.txt
git update-index --add test.txt
t2=$(git write-tree)
c2=$(echo 'Al doilea commit' | git commit-tree $t2 -p $c1)
git update-ref refs/heads/main $c2
git log --oneline --stat
cat .git/HEAD; cat .git/refs/heads/main

Desenează graful obiectelor: commituri → tree-uri → blob-uri. Răspunde: de ce hash-ul tree-ului e la fel ca la colegi, dar hash-urile commiturilor diferă?

Cum îți verifici singur rezultatul
  • git write-tree → d8329fc1cc938780ffdd9f94e0d364e0ea74f579; tree-ul conține 100644 blob 83baae61804e65cc73a7201a7252750c76066a30 test.txt.
  • cat-file -p $c1 arată liniile tree d8329f…, author …, committer …, un rând gol și mesajul; nu are parent.
  • git log arată două commituri (Al doilea commit modifică test.txt cu 1 +-; Primul commit îl creează).
  • .git/HEAD → ref: refs/heads/main; refs/heads/main conține hash-ul lui $c2.
  • Tree-ul depinde doar de nume, mod și blob-uri; commitul include autorul și data, care diferă de la om la om.

Întreabă AI-ul ca să înveți

Copiază o întrebare într-un asistent AI. Sunt scrise ca AI-ul să te pună să gândești și să-ți dea indicii, nu răspunsul gata făcut.

Desenez obiecteleîți verifici graful de obiecte

Lucrez la exercițiul „Construiește un commit doar cu comenzi plumbing” din capitolul „10. Git Internals”, la Pro Git. Enunțul: Continuă în depozitul `interne` (are blob-urile `version 1` și `version 2`). ```bash git update-index --add --cacheinfo 100644 83baae61804e65cc73a7201a7252750c76066a30 test.txt git write-tree git cat-file -p d8329fc1cc938780ffdd9f94e0d364e0ea74f579 c1=$(echo 'Primul commit' | git commit-tree d8329f) git cat-file -p $c1 echo 'version 2' > test.txt git update-index --add test.txt t2=$(git write-tree) c2=$(echo 'Al doilea commit' | git commit-tree $t2 -p $c1) git update-ref refs/heads/main $c2 git log --oneline --stat cat .git/HEAD; cat .git/refs/heads/main ``` Desenează graful obiectelor: commituri → tree-uri → blob-uri. Răspunde: de ce hash-ul tree-ului e la fel ca la colegi, dar hash-urile… Îți descriu desenul meu cu obiectele create (câte commituri, tree-uri, blob-uri și săgețile dintre ele). Verifică-l și întreabă-mă despre orice săgeată greșită sau lipsă, fără să-mi dai desenul corect.

Deschide în Claude ↗
Porcelain din plumbinglegi git commit de comenzile plumbing

Lucrez la exercițiul „Construiește un commit doar cu comenzi plumbing” din capitolul „10. Git Internals”, la Pro Git. Enunțul: Continuă în depozitul `interne` (are blob-urile `version 1` și `version 2`). ```bash git update-index --add --cacheinfo 100644 83baae61804e65cc73a7201a7252750c76066a30 test.txt git write-tree git cat-file -p d8329fc1cc938780ffdd9f94e0d364e0ea74f579 c1=$(echo 'Primul commit' | git commit-tree d8329f) git cat-file -p $c1 echo 'version 2' > test.txt git update-index --add test.txt t2=$(git write-tree) c2=$(echo 'Al doilea commit' | git commit-tree $t2 -p $c1) git update-ref refs/heads/main $c2 git log --oneline --stat cat .git/HEAD; cat .git/refs/heads/main ``` Desenează graful obiectelor: commituri → tree-uri → blob-uri. Răspunde: de ce hash-ul tree-ului e la fel ca la colegi, dar hash-urile… Pune-mi întrebări ca să descriu singur ce comenzi plumbing face „în spate” un simplu `git add` + `git commit`. Corectează-mă cu indicii.

Deschide în Claude ↗
de făcut

Referințe, HEAD simbolic și obiecte tag

nivel 2

În depozitul interne (sau orice depozit cu cel puțin două commituri):

ls .git/refs .git/refs/heads
git update-ref refs/heads/test HEAD~1
git branch
git symbolic-ref HEAD
git symbolic-ref HEAD refs/heads/test
git status | head -1
git symbolic-ref HEAD refs/heads/main
git tag usor HEAD~1
git tag -a v1 -m "Prima versiune" HEAD~1
cat .git/refs/tags/usor
cat .git/refs/tags/v1
git cat-file -t v1
git cat-file -p v1

Apoi, într-o clonă a unui depozit (de ex. echipa/ana din capitolul 3), rulează git config --get remote.origin.fetch și ls .git/refs/remotes/origin.

Răspunde: ce diferență vezi între refs/tags/usor și refs/tags/v1? Ce face o ramură, la nivel de fișiere?

Cum îți verifici singur rezultatul
  • git branch arată main și test, deși ai scris doar un fișier în refs/heads/: o ramură e un fișier cu un hash.
  • git symbolic-ref HEAD → refs/heads/main; după schimbare, git status → On branch test.
  • refs/tags/usor conține hash-ul commitului; refs/tags/v1 conține hash-ul unui obiect tag: cat-file -t v1 → tag, iar -p arată object <hash-commit>, type commit, tag v1, tagger … și mesajul.
  • Refspec-ul implicit al clonei: +refs/heads/*:refs/remotes/origin/*.

Întreabă AI-ul ca să înveți

Copiază o întrebare într-un asistent AI. Sunt scrise ca AI-ul să te pună să gândești și să-ți dea indicii, nu răspunsul gata făcut.

Ce e o ramură, de faptexplici ramurile ca referințe

Lucrez la exercițiul „Referințe, HEAD simbolic și obiecte tag” din capitolul „10. Git Internals”, la Pro Git. Enunțul: În depozitul `interne` (sau orice depozit cu cel puțin două commituri): ```bash ls .git/refs .git/refs/heads git update-ref refs/heads/test HEAD~1 git branch git symbolic-ref HEAD git symbolic-ref HEAD refs/heads/test git status | head -1 git symbolic-ref HEAD refs/heads/main git tag usor HEAD~1 git tag -a v1 -m "Prima versiune" HEAD~1 cat .git/refs/tags/usor cat .git/refs/tags/v1 git cat-file -t v1 git cat-file -p v1 ``` Apoi, într-o clonă a unui depozit (de ex. `echipa/ana` din capitolul 3), rulează `git config --get remote.origin.fetch` și `ls .git/refs/remotes/origin`. Răspunde: ce diferență vezi între `refs/tags/usor` și `refs/tags/v1`? Ce face o ramură, la nivel de fișiere? Întreabă-mă ce am găsit în `.git/refs/heads` și ce cred că face Git când creez o ramură sau fac un commit pe ea. Lasă-mă să explic și corectează-mă cu indicii.

Deschide în Claude ↗
HEAD simbolic sau detașatdeosebești HEAD simbolic de HEAD detașat

Lucrez la exercițiul „Referințe, HEAD simbolic și obiecte tag” din capitolul „10. Git Internals”, la Pro Git. Enunțul: În depozitul `interne` (sau orice depozit cu cel puțin două commituri): ```bash ls .git/refs .git/refs/heads git update-ref refs/heads/test HEAD~1 git branch git symbolic-ref HEAD git symbolic-ref HEAD refs/heads/test git status | head -1 git symbolic-ref HEAD refs/heads/main git tag usor HEAD~1 git tag -a v1 -m "Prima versiune" HEAD~1 cat .git/refs/tags/usor cat .git/refs/tags/v1 git cat-file -t v1 git cat-file -p v1 ``` Apoi, într-o clonă a unui depozit (de ex. `echipa/ana` din capitolul 3), rulează `git config --get remote.origin.fetch` și `ls .git/refs/remotes/origin`. Răspunde: ce diferență vezi între `refs/tags/usor` și `refs/tags/v1`? Ce face o ramură, la nivel de fișiere? Pune-mi întrebări despre conținutul lui `.git/HEAD` în mod normal și după `git switch --detach HEAD~1`, ca să ajung singur la diferență. Verifică-mi explicația.

Deschide în Claude ↗
de făcut

Obiecte libere, packfile și delte

nivel 2
git init pachete && cd pachete
seq 1 20000 > mare.txt
git add .; git commit -m "Fișier mare"
echo "linie nouă" >> mare.txt; git commit -am "O linie în plus"
git count-objects -v
du -h .git/objects/?? | sort -h | tail -3
git gc
git count-objects -v
ls .git/objects/pack
git verify-pack -v .git/objects/pack/*.idx | grep blob

Răspunde: câte obiecte sunt libere înainte și după gc? Care dintre cele două versiuni ale lui mare.txt e păstrată întreagă și care ca deltă? De ce așa?

Cum îți verifici singur rezultatul
  • Înainte: count: 6 obiecte libere (2 blob-uri, 2 tree-uri, 2 commituri), packs: 0; două directoare de ~40K.
  • După gc: count: 0, in-pack: 6, packs: 1, size-pack în jur de 44 (KiB), mult sub suma inițială.
  • verify-pack arată blob-ul de 108906 octeți (versiunea nouă) stocat întreg și blob-ul vechi ca deltă de câțiva octeți, cu adâncimea 1 și hash-ul bazei la final: Git păstrează întreagă versiunea recentă, accesată cel mai des.

Întreabă AI-ul ca să înveți

Copiază o întrebare într-un asistent AI. Sunt scrise ca AI-ul să te pună să gândești și să-ți dea indicii, nu răspunsul gata făcut.

Citesc verify-packinterpretezi coloanele lui verify-pack

Lucrez la exercițiul „Obiecte libere, packfile și delte” din capitolul „10. Git Internals”, la Pro Git. Enunțul: ```bash git init pachete && cd pachete seq 1 20000 > mare.txt git add .; git commit -m "Fișier mare" echo "linie nouă" >> mare.txt; git commit -am "O linie în plus" git count-objects -v du -h .git/objects/?? | sort -h | tail -3 git gc git count-objects -v ls .git/objects/pack git verify-pack -v .git/objects/pack/*.idx | grep blob ``` Răspunde: câte obiecte sunt libere înainte și după `gc`? Care dintre cele două versiuni ale lui `mare.txt` e păstrată întreagă și care ca deltă? De ce așa? Îți lipesc liniile `blob` din `git verify-pack -v`. Întreabă-mă ce cred că înseamnă fiecare coloană (dimensiune, dimensiune în pachet, offset, adâncime, bază) și corectează-mă cu indicii.

Deschide în Claude ↗
Instantanee și delteîmpaci modelul cu instantanee cu deltele din pachete

Lucrez la exercițiul „Obiecte libere, packfile și delte” din capitolul „10. Git Internals”, la Pro Git. Enunțul: ```bash git init pachete && cd pachete seq 1 20000 > mare.txt git add .; git commit -m "Fișier mare" echo "linie nouă" >> mare.txt; git commit -am "O linie în plus" git count-objects -v du -h .git/objects/?? | sort -h | tail -3 git gc git count-objects -v ls .git/objects/pack git verify-pack -v .git/objects/pack/*.idx | grep blob ``` Răspunde: câte obiecte sunt libere înainte și după `gc`? Care dintre cele două versiuni ale lui `mare.txt` e păstrată întreagă și care ca deltă? De ce așa? În capitolul 1 scria că Git salvează instantanee, nu diferențe, dar aici văd delte. Pune-mi întrebări care să mă ajute să împac cele două idei singur; nu-mi da explicația direct.

Deschide în Claude ↗
de făcut

Recuperează commituri pierdute cu reflog și fsck

nivel 3

În depozitul pachete (sau orice depozit de test):

for i in 1 2 3; do echo $i > r$i; git add .; git commit -m "R$i"; done
git log --oneline | head -3
git reset --hard HEAD~3          # „pierzi” cele trei commituri
git log --oneline
git reflog | head -2
  1. Recuperează-le într-o ramură nouă, recuperat, folosind reflogul. Verifică cu git log --oneline recuperat.
  2. Caz mai greu — fără reflog: șterge ramura (git branch -D recuperat) și reflogul (rm -rf .git/logs). Găsește din nou commitul cu git fsck --full și creează din el ramura recuperat2.
  3. Verifică că r1, r2, r3 există în recuperat2 (git ls-tree --name-only recuperat2).
Cum îți verifici singur rezultatul
  • Reflogul arată HEAD@{0}: reset: moving to HEAD~3 și HEAD@{1}: commit: R3; pasul 1 se rezolvă cu git branch recuperat HEAD@{1} (sau cu hash-ul lui R3).
  • git fsck --full afișează dangling commit <hash> — commitul R3, la care nu mai arată nicio referință; git branch recuperat2 <hash> îl recuperează, iar R1 și R2 vin odată cu el, ca părinți.
  • git ls-tree --name-only recuperat2 listează și r1, r2, r3.

Întreabă AI-ul ca să înveți

Copiază o întrebare într-un asistent AI. Sunt scrise ca AI-ul să te pună să gândești și să-ți dea indicii, nu răspunsul gata făcut.

Unde caut întâiîți faci un plan de recuperare

Lucrez la exercițiul „Recuperează commituri pierdute cu reflog și fsck” din capitolul „10. Git Internals”, la Pro Git. Enunțul: În depozitul `pachete` (sau orice depozit de test): ```bash for i in 1 2 3; do echo $i > r$i; git add .; git commit -m "R$i"; done git log --oneline | head -3 git reset --hard HEAD~3 # „pierzi” cele trei commituri git log --oneline git reflog | head -2 ``` 1. Recuperează-le într-o ramură nouă, `recuperat`, folosind reflogul. Verifică cu `git log --oneline recuperat`. 2. Caz mai greu — fără reflog: șterge ramura (`git branch -D recuperat`) și reflogul (`rm -rf .git/logs`). Găsește din nou commitul cu `git fsck --full` și creează din el ramura `recuperat2`. 3. Verifică că `r1`, `r2`, `r3` există în `recuperat2` (`git ls-tree --name-only recuperat2`). Am pierdut commituri după un reset. Întreabă-mă ce am făcut și ghidează-mă cu întrebări să aleg între reflog și fsck; nu-mi scrie comenzile direct.

Deschide în Claude ↗
De ce un singur danglingînțelegi de ce fsck arată doar ultimul commit

Lucrez la exercițiul „Recuperează commituri pierdute cu reflog și fsck” din capitolul „10. Git Internals”, la Pro Git. Enunțul: În depozitul `pachete` (sau orice depozit de test): ```bash for i in 1 2 3; do echo $i > r$i; git add .; git commit -m "R$i"; done git log --oneline | head -3 git reset --hard HEAD~3 # „pierzi” cele trei commituri git log --oneline git reflog | head -2 ``` 1. Recuperează-le într-o ramură nouă, `recuperat`, folosind reflogul. Verifică cu `git log --oneline recuperat`. 2. Caz mai greu — fără reflog: șterge ramura (`git branch -D recuperat`) și reflogul (`rm -rf .git/logs`). Găsește din nou commitul cu `git fsck --full` și creează din el ramura `recuperat2`. 3. Verifică că `r1`, `r2`, `r3` există în `recuperat2` (`git ls-tree --name-only recuperat2`). `git fsck` mi-a arătat un singur „dangling commit”, deși am pierdut trei. Pune-mi întrebări despre legăturile dintre commituri până îmi dau seama singur de ce. Verifică-mi apoi explicația.

Deschide în Claude ↗

🪟 A. Appendix A: Git in Other Environments

de făcut

Afișează ramura curentă în promptul terminalului

nivel 1

Alege varianta potrivită shell-ului tău (echo $SHELL).

Zsh (implicit pe macOS) — adaugă în ~/.zshrc, ca în carte:

autoload -Uz vcs_info
precmd_vcs_info() { vcs_info }
precmd_functions+=( precmd_vcs_info )
setopt prompt_subst
RPROMPT='${vcs_info_msg_0_}'
zstyle ':vcs_info:git:*' formats '%b'

Bash — găsește scriptul git-prompt.sh care vine cu Git (de ex. find / -name git-prompt.sh 2>/dev/null; pe Windows e inclus în Git Bash) și adaugă în ~/.bashrc:

. /calea/catre/git-prompt.sh
export GIT_PS1_SHOWDIRTYSTATE=1
export PS1='\w$(__git_ps1 " (%s)")\$ '

Deschide un terminal nou și intră într-un depozit de test: modifică un fișier, schimbă ramura, apoi fă git switch --detach HEAD~1 și urmărește promptul. Activează și completarea automată (git-completion.bash / în zsh e inclusă) și încearcă git sw<Tab> și git switch <Tab>.

Cum îți verifici singur rezultatul
  • În zsh, în partea dreaptă apare numele ramurii (main); în afara depozitelor nu apare nimic.
  • În bash promptul devine de forma ~/depozit (main)$; cu o modificare necomisă (main *); cu HEAD detașat ((a1b2c3d...)).
  • git switch <Tab> propune numele ramurilor.

Întreabă AI-ul ca să înveți

Copiază o întrebare într-un asistent AI. Sunt scrise ca AI-ul să te pună să gândești și să-ți dea indicii, nu răspunsul gata făcut.

Depanez promptulprimești indicii când promptul nu se schimbă

Lucrez la exercițiul „Afișează ramura curentă în promptul terminalului” din capitolul „A. Appendix A: Git in Other Environments”, la Pro Git. Enunțul: Alege varianta potrivită shell-ului tău (`echo $SHELL`). **Zsh** (implicit pe macOS) — adaugă în `~/.zshrc`, ca în carte: ```bash autoload -Uz vcs_info precmd_vcs_info() { vcs_info } precmd_functions+=( precmd_vcs_info ) setopt prompt_subst RPROMPT='${vcs_info_msg_0_}' zstyle ':vcs_info:git:*' formats '%b' ``` **Bash** — găsește scriptul `git-prompt.sh` care vine cu Git (de ex. `find / -name git-prompt.sh 2>/dev/null`; pe Windows e inclus în Git Bash) și adaugă în `~/.bashrc`: ```bash . /calea/catre/git-prompt.sh export GIT_PS1_SHOWDIRTYSTATE=1 export PS1='\w$(__git_ps1 " (%s)")\$ ' ``` Deschide un terminal nou și intră într-un depozit de test: modifică un fișier, schimbă ramura, apoi fă… Promptul meu nu arată ramura. Îți lipesc ce am adăugat în fișierul de configurare și ce shell folosesc. Pune-mi întrebări de verificare (fișierul corect? terminal nou? calea scriptului?) și dă-mi indicii, nu soluția.

Deschide în Claude ↗
Personalizez promptulîți personalizezi promptul singur

Lucrez la exercițiul „Afișează ramura curentă în promptul terminalului” din capitolul „A. Appendix A: Git in Other Environments”, la Pro Git. Enunțul: Alege varianta potrivită shell-ului tău (`echo $SHELL`). **Zsh** (implicit pe macOS) — adaugă în `~/.zshrc`, ca în carte: ```bash autoload -Uz vcs_info precmd_vcs_info() { vcs_info } precmd_functions+=( precmd_vcs_info ) setopt prompt_subst RPROMPT='${vcs_info_msg_0_}' zstyle ':vcs_info:git:*' formats '%b' ``` **Bash** — găsește scriptul `git-prompt.sh` care vine cu Git (de ex. `find / -name git-prompt.sh 2>/dev/null`; pe Windows e inclus în Git Bash) și adaugă în `~/.bashrc`: ```bash . /calea/catre/git-prompt.sh export GIT_PS1_SHOWDIRTYSTATE=1 export PS1='\w$(__git_ps1 " (%s)")\$ ' ``` Deschide un terminal nou și intră într-un depozit de test: modifică un fișier, schimbă ramura, apoi fă… Vreau ca promptul să arate și dacă am fișiere în staging sau neurmărite. Lasă-mă să caut singur opțiunile potrivite (în comentariile din git-prompt.sh sau în documentația vcs_info) și verifică-mi alegerea.

Deschide în Claude ↗
de făcut

Același istoric în linia de comandă și într-o interfață grafică

nivel 1

Folosește un depozit cu ramuri și merge-uri (de ex. ramuri sau onto din capitolul 3). 1. În terminal: git log --oneline --graph --all --decorate. 2. Deschide același depozit într-o interfață grafică pe care o ai: gitk --all și git gui (dacă sunt instalate; vin cu Git pe Windows și cu multe distribuții Linux), GitHub Desktop, VS Code (panoul Source Control) sau alt client. 3. Găsește în interfață: commitul de merge și cei doi părinți ai lui, diferențele unui commit, ramura curentă. 4. Fă din interfață o operație simplă (un commit sau crearea unei ramuri), apoi verifică în terminal cu git log --oneline -3 și git status.

Răspunde: ce ți-a fost mai ușor în interfața grafică și ce în linia de comandă? Ce comandă Git crezi că a rulat interfața pentru operația de la pasul 4?

Cum îți verifici singur rezultatul
  • Graful din interfață are aceeași structură ca git log --graph (aceleași commituri, aceleași ramuri, același romb).
  • Operația făcută din interfață apare imediat în git log / git status: interfața folosește același depozit .git.
  • Cartea notează că interfețele expun de obicei doar o parte din funcționalitate; linia de comandă le are pe toate.

Întreabă AI-ul ca să înveți

Copiază o întrebare într-un asistent AI. Sunt scrise ca AI-ul să te pună să gândești și să-ți dea indicii, nu răspunsul gata făcut.

Compar cele două moduriîți formezi o părere argumentată

Lucrez la exercițiul „Același istoric în linia de comandă și într-o interfață grafică” din capitolul „A. Appendix A: Git in Other Environments”, la Pro Git. Enunțul: Folosește un depozit cu ramuri și merge-uri (de ex. `ramuri` sau `onto` din capitolul 3). 1. În terminal: `git log --oneline --graph --all --decorate`. 2. Deschide același depozit într-o interfață grafică pe care o ai: `gitk --all` și `git gui` (dacă sunt instalate; vin cu Git pe Windows și cu multe distribuții Linux), GitHub Desktop, VS Code (panoul Source Control) sau alt client. 3. Găsește în interfață: commitul de merge și cei doi părinți ai lui, diferențele unui commit, ramura curentă. 4. Fă din interfață o operație simplă (un commit sau crearea unei ramuri), apoi verifică în terminal cu `git log --oneline -3` și `git status`. Răspunde: ce ți-a fost mai ușor în interfața grafică și ce… Întreabă-mă ce am făcut ușor și ce greu în fiecare mod și ajută-mă cu întrebări să ajung la o regulă personală despre când folosesc interfața și când terminalul. Nu-mi spune tu regula.

Deschide în Claude ↗
Ce a rulat interfațalegi o acțiune grafică de comenzile Git

Lucrez la exercițiul „Același istoric în linia de comandă și într-o interfață grafică” din capitolul „A. Appendix A: Git in Other Environments”, la Pro Git. Enunțul: Folosește un depozit cu ramuri și merge-uri (de ex. `ramuri` sau `onto` din capitolul 3). 1. În terminal: `git log --oneline --graph --all --decorate`. 2. Deschide același depozit într-o interfață grafică pe care o ai: `gitk --all` și `git gui` (dacă sunt instalate; vin cu Git pe Windows și cu multe distribuții Linux), GitHub Desktop, VS Code (panoul Source Control) sau alt client. 3. Găsește în interfață: commitul de merge și cei doi părinți ai lui, diferențele unui commit, ramura curentă. 4. Fă din interfață o operație simplă (un commit sau crearea unei ramuri), apoi verifică în terminal cu `git log --oneline -3` și `git status`. Răspunde: ce ți-a fost mai ușor în interfața grafică și ce… Îți descriu operația făcută în interfață și ce văd după aceea în terminal. Pune-mi întrebări ca să ghicesc singur comenzile Git echivalente și verifică-mi răspunsul.

Deschide în Claude ↗
de făcut

Staging pe bucăți și conflicte în VS Code (și cu git add -p)

nivel 2

Ai nevoie de VS Code (sau alt editor cu integrare Git) și un depozit de test. 1. Creează un fișier cu 10 linii, fă commit, apoi modifică linia 1 și linia 10 (două modificări separate). 2. În terminal: git add -p — pune în staging doar prima modificare (y pentru prima bucată, n pentru a doua). Verifică: git diff --staged și git diff. Anulează cu git restore --staged .. 3. În VS Code, panoul Source Control: deschide fișierul modificat, selectează doar linia 10 și alege „Stage Selected Ranges”. Verifică din nou în terminal cu git diff --staged. 4. Provoacă un conflict (ca în exercițiul de merge din capitolul 3) și deschide fișierul în VS Code: folosește butoanele Accept Current / Incoming / Both, apoi încheie merge-ul din terminal.

Cum îți verifici singur rezultatul
  • După pasul 2, git status -s arată MM fișier: git diff --staged conține doar modificarea liniei 1, git diff doar linia 10.
  • După pasul 3, situația e inversă (în staging doar linia 10).
  • La conflict, VS Code evidențiază blocurile dintre <<<<<<< și >>>>>>>; după alegere marcajele dispar, iar git add + git commit încheie merge-ul.

Întreabă AI-ul ca să înveți

Copiază o întrebare într-un asistent AI. Sunt scrise ca AI-ul să te pună să gândești și să-ți dea indicii, nu răspunsul gata făcut.

Când folosesc add -pînțelegi la ce folosește staging-ul parțial

Lucrez la exercițiul „Staging pe bucăți și conflicte în VS Code (și cu git add -p)” din capitolul „A. Appendix A: Git in Other Environments”, la Pro Git. Enunțul: Ai nevoie de VS Code (sau alt editor cu integrare Git) și un depozit de test. 1. Creează un fișier cu 10 linii, fă commit, apoi modifică linia 1 și linia 10 (două modificări separate). 2. În terminal: `git add -p` — pune în staging doar prima modificare (`y` pentru prima bucată, `n` pentru a doua). Verifică: `git diff --staged` și `git diff`. Anulează cu `git restore --staged .`. 3. În VS Code, panoul Source Control: deschide fișierul modificat, selectează doar linia 10 și alege „Stage Selected Ranges”. Verifică din nou în terminal cu `git diff --staged`. 4. Provoacă un conflict (ca în exercițiul de merge din capitolul 3) și deschide fișierul în VS Code: folosește butoanele *Accept Current… Întreabă-mă ce s-ar fi întâmplat dacă puneam ambele modificări în același commit și când ar conta asta pentru un coleg care citește istoria. Lasă-mă să găsesc singur avantajele staging-ului parțial.

Deschide în Claude ↗
Comenzile din spatele butoanelorlegi butoanele editorului de comenzile Git

Lucrez la exercițiul „Staging pe bucăți și conflicte în VS Code (și cu git add -p)” din capitolul „A. Appendix A: Git in Other Environments”, la Pro Git. Enunțul: Ai nevoie de VS Code (sau alt editor cu integrare Git) și un depozit de test. 1. Creează un fișier cu 10 linii, fă commit, apoi modifică linia 1 și linia 10 (două modificări separate). 2. În terminal: `git add -p` — pune în staging doar prima modificare (`y` pentru prima bucată, `n` pentru a doua). Verifică: `git diff --staged` și `git diff`. Anulează cu `git restore --staged .`. 3. În VS Code, panoul Source Control: deschide fișierul modificat, selectează doar linia 10 și alege „Stage Selected Ranges”. Verifică din nou în terminal cu `git diff --staged`. 4. Provoacă un conflict (ca în exercițiul de merge din capitolul 3) și deschide fișierul în VS Code: folosește butoanele *Accept Current… Pune-mi întrebări ca să ghicesc ce comenzi Git (sau ce modificări în fișier) corespund butoanelor din VS Code pentru staging și conflicte. Verifică-mi presupunerile cu `git status` și `git diff`.

Deschide în Claude ↗
întrebare de gândit

Ce unealtă Git pentru ce situație?

nivel 2

Pe baza anexei A, răspunde: 1. De ce cartea predă Git în linia de comandă, deși există multe interfețe grafice? 2. Un coleg nou se teme de terminal. Ce i-ai recomanda pentru primele săptămâni și ce ar trebui totuși să învețe în linia de comandă (gândește-te la rebase interactiv, reflog, bisect)? 3. Ce avantaje are integrarea Git în editor (VS Code, IntelliJ) față de un client separat? 4. Ce îți aduc în terminal completarea automată și un prompt cu starea depozitului? Ce greșeli concrete previn? 5. Alege un instrument concret pe care îl folosești sau l-ai putea folosi și descrie 3 operații pe care le faci mai repede în el decât în terminal.

Cum îți verifici singur rezultatul

Idei de verificare: linia de comandă e singurul loc unde ai toate comenzile Git, iar interfețele implementează doar o parte; GUI-urile sunt bune pentru vizualizarea istoriei, staging pe linii și conflicte; reflogul, bisect, rebase-ul interactiv și hook-urile se învață în terminal. Promptul previne commituri pe ramura greșită sau lucrul în HEAD detașat fără să-ți dai seama.

Întreabă AI-ul ca să înveți

Copiază o întrebare într-un asistent AI. Sunt scrise ca AI-ul să te pună să gândești și să-ți dea indicii, nu răspunsul gata făcut.

Verifică-mi argumenteleprimești feedback pe răspunsuri

Lucrez la exercițiul „Ce unealtă Git pentru ce situație?” din capitolul „A. Appendix A: Git in Other Environments”, la Pro Git. Enunțul: Pe baza anexei A, răspunde: 1. De ce cartea predă Git în linia de comandă, deși există multe interfețe grafice? 2. Un coleg nou se teme de terminal. Ce i-ai recomanda pentru primele săptămâni și ce ar trebui totuși să învețe în linia de comandă (gândește-te la rebase interactiv, reflog, bisect)? 3. Ce avantaje are integrarea Git în editor (VS Code, IntelliJ) față de un client separat? 4. Ce îți aduc în terminal completarea automată și un prompt cu starea depozitului? Ce greșeli concrete previn? 5. Alege un instrument concret pe care îl folosești sau l-ai putea folosi și descrie 3 operații pe care le faci mai repede în el decât în terminal. Îți scriu răspunsurile mele. Verifică-le cu anexa A și, unde sunt superficiale, pune-mi o întrebare suplimentară care să mă facă să le aprofundez singur. Nu-mi da răspunsuri model.

Deschide în Claude ↗
Sfat pentru un colegexersezi explicarea alegerii uneltelor

Lucrez la exercițiul „Ce unealtă Git pentru ce situație?” din capitolul „A. Appendix A: Git in Other Environments”, la Pro Git. Enunțul: Pe baza anexei A, răspunde: 1. De ce cartea predă Git în linia de comandă, deși există multe interfețe grafice? 2. Un coleg nou se teme de terminal. Ce i-ai recomanda pentru primele săptămâni și ce ar trebui totuși să învețe în linia de comandă (gândește-te la rebase interactiv, reflog, bisect)? 3. Ce avantaje are integrarea Git în editor (VS Code, IntelliJ) față de un client separat? 4. Ce îți aduc în terminal completarea automată și un prompt cu starea depozitului? Ce greșeli concrete previn? 5. Alege un instrument concret pe care îl folosești sau l-ai putea folosi și descrie 3 operații pe care le faci mai repede în el decât în terminal. Joacă rolul unui coleg începător care vrea să folosească doar o interfață grafică. Pune-mi obiecții realiste și lasă-mă să-l conving cu argumente; verifică-mi apoi argumentele.

Deschide în Claude ↗

🧩 B. Appendix B: Embedding Git in your Applications

program de scris

Un script Python care citește starea depozitului

nivel 2

Cea mai simplă integrare (B.1) e să apelezi comanda git și să-i citești ieșirea. Scrie stare.py care afișează, pentru depozitul din directorul curent: 1. ramura curentă (git rev-parse --abbrev-ref HEAD); 2. fiecare fișier modificat sau neurmărit, cu codul lui din două litere (git status --porcelain=v1); 3. ultimele 3 commituri ca hash | autor | subiect, folosind un format ușor de despărțit (git log -3 --format=%h%x09%an%x09%s, unde %x09 e un TAB). Schelet:

import subprocess

def git(*args):
    return subprocess.run(["git", *args], capture_output=True, text=True, check=True).stdout

# TODO: ramura, starea, ultimele commituri

Rulează-l într-un depozit de test cu un fișier modificat și unul nou: python3 stare.py.

Răspunde: de ce git status --porcelain și nu git status simplu? Ce probleme are, în general, parsarea textului afișat de Git (cartea le enumeră la B.1)?

Cum îți verifici singur rezultatul
  • Ieșire de forma:
Ramura: main
  ' M' -> index.html
  '??' -> nou.txt
  8b4e691 | Ana Pop | Merge branch 'tema'
  • --porcelain are un format stabil, gândit pentru scripturi, care nu se schimbă între versiuni sau după limbă; ieșirea obișnuită e pentru oameni (poate fi tradusă, colorată, reformatată).
  • Probleme la apelarea comenzii: parsezi text, erorile se citesc greu, pornești un proces nou la fiecare apel.

Întreabă AI-ul ca să înveți

Copiază o întrebare într-un asistent AI. Sunt scrise ca AI-ul să te pună să gândești și să-ți dea indicii, nu răspunsul gata făcut.

Verifică-mi scriptulprimești feedback pe cod

Lucrez la exercițiul „Un script Python care citește starea depozitului” din capitolul „B. Appendix B: Embedding Git in your Applications”, la Pro Git. Enunțul: Cea mai simplă integrare (B.1) e să apelezi comanda `git` și să-i citești ieșirea. Scrie `stare.py` care afișează, pentru depozitul din directorul curent: 1. ramura curentă (`git rev-parse --abbrev-ref HEAD`); 2. fiecare fișier modificat sau neurmărit, cu codul lui din două litere (`git status --porcelain=v1`); 3. ultimele 3 commituri ca `hash | autor | subiect`, folosind un format ușor de despărțit (`git log -3 --format=%h%x09%an%x09%s`, unde `%x09` e un TAB). Schelet: ```python import subprocess def git(*args): return subprocess.run(["git", *args], capture_output=True, text=True, check=True).stdout # TODO: ramura, starea, ultimele commituri ``` Rulează-l într-un depozit de test cu un… Îți lipesc scriptul meu `stare.py` și ce afișează. Verifică dacă tratez corect fișierele cu spații în nume și depozitele fără commituri; dacă găsești probleme, dă-mi indicii, nu codul corectat.

Deschide în Claude ↗
Erori de la gittratezi erorile comenzii git

Lucrez la exercițiul „Un script Python care citește starea depozitului” din capitolul „B. Appendix B: Embedding Git in your Applications”, la Pro Git. Enunțul: Cea mai simplă integrare (B.1) e să apelezi comanda `git` și să-i citești ieșirea. Scrie `stare.py` care afișează, pentru depozitul din directorul curent: 1. ramura curentă (`git rev-parse --abbrev-ref HEAD`); 2. fiecare fișier modificat sau neurmărit, cu codul lui din două litere (`git status --porcelain=v1`); 3. ultimele 3 commituri ca `hash | autor | subiect`, folosind un format ușor de despărțit (`git log -3 --format=%h%x09%an%x09%s`, unde `%x09` e un TAB). Schelet: ```python import subprocess def git(*args): return subprocess.run(["git", *args], capture_output=True, text=True, check=True).stdout # TODO: ramura, starea, ultimele commituri ``` Rulează-l într-un depozit de test cu un… Ce se întâmplă cu scriptul meu dacă îl rulez în afara unui depozit? Întreabă-mă ce cred că face `check=True` și ajută-mă cu indicii să tratez eroarea frumos, fără să-mi scrii tu tratarea.

Deschide în Claude ↗
program de scris

Citește un depozit din Python cu Dulwich

nivel 2

Dulwich (B.5) e o implementare Git în Python pur. Într-un mediu virtual:

python3 -m venv venv && . venv/bin/activate
pip install dulwich

Scrie un script care, pentru un depozit de test cu câteva commituri și ramuri: 1. deschide depozitul (from dulwich.repo import Repo; r = Repo('.')); 2. afișează hash-ul lui HEAD (r.head()), mesajul, autorul și numărul de părinți ai commitului (c = r[r.head()]; atributele message, author, parents sunt de tip bytes / listă); 3. listează referințele (r.refs.keys()); 4. afișează ultimele 2 commituri cu nivelul „porcelain” (from dulwich import porcelain; porcelain.log('.', max_entries=2)). Compară rezultatele cu git log -2 și git show-ref.

Cum îți verifici singur rezultatul
  • r.head() întoarce hash-ul complet al commitului curent (în bytes), același ca git rev-parse HEAD.
  • Pentru un commit de merge, len(c.parents) e 2; mesajul trebuie decodat (c.message.decode()).
  • r.refs.keys() conține b'HEAD', b'refs/heads/main' și celelalte ramuri / taguri, ca git show-ref.
  • porcelain.log afișează commiturile într-un format asemănător cu git log.

Întreabă AI-ul ca să înveți

Copiază o întrebare într-un asistent AI. Sunt scrise ca AI-ul să te pună să gândești și să-ți dea indicii, nu răspunsul gata făcut.

Plumbing și porcelain în Dulwichlegi API-ul Dulwich de conceptele din capitolul 10

Lucrez la exercițiul „Citește un depozit din Python cu Dulwich” din capitolul „B. Appendix B: Embedding Git in your Applications”, la Pro Git. Enunțul: Dulwich (B.5) e o implementare Git în Python pur. Într-un mediu virtual: ```bash python3 -m venv venv && . venv/bin/activate pip install dulwich ``` Scrie un script care, pentru un depozit de test cu câteva commituri și ramuri: 1. deschide depozitul (`from dulwich.repo import Repo; r = Repo('.')`); 2. afișează hash-ul lui HEAD (`r.head()`), mesajul, autorul și numărul de părinți ai commitului (`c = r[r.head()]`; atributele `message`, `author`, `parents` sunt de tip `bytes` / listă); 3. listează referințele (`r.refs.keys()`); 4. afișează ultimele 2 commituri cu nivelul „porcelain” (`from dulwich import porcelain; porcelain.log('.', max_entries=2)`). Compară rezultatele cu `git log -2` și… Întreabă-mă ce obiecte Git (commit, tree, blob) cred că pot accesa prin `r[...]` și cum aș ajunge de la un commit la conținutul unui fișier. Lasă-mă să încerc în cod și dă-mi indicii când mă blochez.

Deschide în Claude ↗
Verifică-mi codulprimești feedback fără rescriere

Lucrez la exercițiul „Citește un depozit din Python cu Dulwich” din capitolul „B. Appendix B: Embedding Git in your Applications”, la Pro Git. Enunțul: Dulwich (B.5) e o implementare Git în Python pur. Într-un mediu virtual: ```bash python3 -m venv venv && . venv/bin/activate pip install dulwich ``` Scrie un script care, pentru un depozit de test cu câteva commituri și ramuri: 1. deschide depozitul (`from dulwich.repo import Repo; r = Repo('.')`); 2. afișează hash-ul lui HEAD (`r.head()`), mesajul, autorul și numărul de părinți ai commitului (`c = r[r.head()]`; atributele `message`, `author`, `parents` sunt de tip `bytes` / listă); 3. listează referințele (`r.refs.keys()`); 4. afișează ultimele 2 commituri cu nivelul „porcelain” (`from dulwich import porcelain; porcelain.log('.', max_entries=2)`). Compară rezultatele cu `git log -2` și… Îți lipesc scriptul meu cu Dulwich și ce afișează. Verifică dacă tratez corect `bytes` față de `str` și ce se întâmplă într-un depozit gol; spune-mi unde greșesc, fără să-mi rescrii codul.

Deschide în Claude ↗
de făcut

Comenzi plumbing bune pentru scripturi

nivel 1

Într-un depozit de test cu câteva ramuri și taguri, rulează și explică fiecare comandă:

git rev-parse HEAD
git rev-parse --short HEAD~1
git rev-parse --abbrev-ref HEAD
git rev-parse --show-toplevel
git rev-list --count HEAD
git for-each-ref --format='%(refname:short) %(objectname:short) %(committerdate:short)' refs/heads
git ls-files -s
git ls-tree -r --name-only HEAD
git cat-file -t HEAD^{tree}

Apoi scrie un one-liner (bash) care afișează ramurile ordonate după data ultimului commit, cele mai recente primele (indiciu: --sort la for-each-ref).

Răspunde: de ce în scripturi sunt preferate aceste comenzi în locul lui git branch sau git log cu formatul implicit?

Cum îți verifici singur rezultatul
  • rev-parse HEAD → hash complet de 40 de caractere; --abbrev-ref HEAD → numele ramurii; --show-toplevel → calea rădăcinii.
  • rev-list --count HEAD → numărul de commituri accesibile din HEAD.
  • for-each-ref afișează câte o linie per ramură (de ex. main 8b4e691 2026-10-09).
  • ls-files -s arată indexul: mod, hash blob, stadiu (0) și cale; cat-file -t HEAD^{tree} → tree.
  • One-liner posibil: git for-each-ref --sort=-committerdate --format='%(refname:short)' refs/heads.

Întreabă AI-ul ca să înveți

Copiază o întrebare într-un asistent AI. Sunt scrise ca AI-ul să te pună să gândești și să-ți dea indicii, nu răspunsul gata făcut.

Explic fiecare comandăîți verifici înțelegerea comenzilor plumbing

Lucrez la exercițiul „Comenzi plumbing bune pentru scripturi” din capitolul „B. Appendix B: Embedding Git in your Applications”, la Pro Git. Enunțul: Într-un depozit de test cu câteva ramuri și taguri, rulează și explică fiecare comandă: ```bash git rev-parse HEAD git rev-parse --short HEAD~1 git rev-parse --abbrev-ref HEAD git rev-parse --show-toplevel git rev-list --count HEAD git for-each-ref --format='%(refname:short) %(objectname:short) %(committerdate:short)' refs/heads git ls-files -s git ls-tree -r --name-only HEAD git cat-file -t HEAD^{tree} ``` Apoi scrie un one-liner (bash) care afișează ramurile ordonate după data ultimului commit, cele mai recente primele (indiciu: `--sort` la `for-each-ref`). Răspunde: de ce în scripturi sunt preferate aceste comenzi în locul lui `git branch` sau `git log` cu formatul implicit? Îți scriu ce cred că face fiecare dintre cele nouă comenzi. Verifică-mi explicațiile și, unde greșesc, pune-mi o întrebare care să mă îndrume spre răspuns.

Deschide în Claude ↗
Scriu un script micaplici comenzile într-un script real

Lucrez la exercițiul „Comenzi plumbing bune pentru scripturi” din capitolul „B. Appendix B: Embedding Git in your Applications”, la Pro Git. Enunțul: Într-un depozit de test cu câteva ramuri și taguri, rulează și explică fiecare comandă: ```bash git rev-parse HEAD git rev-parse --short HEAD~1 git rev-parse --abbrev-ref HEAD git rev-parse --show-toplevel git rev-list --count HEAD git for-each-ref --format='%(refname:short) %(objectname:short) %(committerdate:short)' refs/heads git ls-files -s git ls-tree -r --name-only HEAD git cat-file -t HEAD^{tree} ``` Apoi scrie un one-liner (bash) care afișează ramurile ordonate după data ultimului commit, cele mai recente primele (indiciu: `--sort` la `for-each-ref`). Răspunde: de ce în scripturi sunt preferate aceste comenzi în locul lui `git branch` sau `git log` cu formatul implicit? Vreau un script care listează ramurile locale deja integrate în main și cât de vechi sunt. Lasă-mă să-l scriu cu comenzi plumbing, apoi verifică-l și dă-mi indicii unde nu e robust.

Deschide în Claude ↗
întrebare de gândit

Libgit2, JGit, go-git sau comanda git?

nivel 2

Pe baza anexei B, alege soluția potrivită și argumentează: 1. Un mic script de administrare care rulează pe un server unde Git e deja instalat. 2. O aplicație Android care trebuie să cloneze depozite (fără să depindă de un git instalat). 3. Un serviciu în Go care analizează mii de depozite în paralel, în memorie. 4. O aplicație desktop în C# sau Python care vrea performanță bună și acces la obiecte (bindings pentru libgit2, de ex. LibGit2Sharp sau pygit2). 5. Un instrument Python care trebuie să ruleze oriunde, fără biblioteci native de compilat. Pentru fiecare, notează un dezavantaj al alegerii tale.

Cum îți verifici singur rezultatul

Răspunsuri orientative: 1 — comanda git (simplu, dar parsezi text și pornești procese); 2 — JGit (Java pur); 3 — go-git (Go pur, suportă stocare în memorie); 4 — libgit2 prin bindings (rapid, dar dependență nativă); 5 — Dulwich (Python pur, mai lent decât libgit2). Cartea subliniază că libgit2 nu depinde de git, e reentrant și are API stabil, potrivit pentru integrare în alte aplicații.

Întreabă AI-ul ca să înveți

Copiază o întrebare într-un asistent AI. Sunt scrise ca AI-ul să te pună să gândești și să-ți dea indicii, nu răspunsul gata făcut.

Apără-mi alegerileîți testezi argumentele

Lucrez la exercițiul „Libgit2, JGit, go-git sau comanda git?” din capitolul „B. Appendix B: Embedding Git in your Applications”, la Pro Git. Enunțul: Pe baza anexei B, alege soluția potrivită și argumentează: 1. Un mic script de administrare care rulează pe un server unde Git e deja instalat. 2. O aplicație Android care trebuie să cloneze depozite (fără să depindă de un `git` instalat). 3. Un serviciu în Go care analizează mii de depozite în paralel, în memorie. 4. O aplicație desktop în C# sau Python care vrea performanță bună și acces la obiecte (bindings pentru libgit2, de ex. LibGit2Sharp sau pygit2). 5. Un instrument Python care trebuie să ruleze oriunde, fără biblioteci native de compilat. Pentru fiecare, notează un dezavantaj al alegerii tale. Îți scriu alegerile mele pentru cele 5 situații. Pentru fiecare, pune-mi o obiecție (performanță, portabilitate, licență, dependențe) și lasă-mă să-mi apăr alegerea înainte să-mi spui părerea ta.

Deschide în Claude ↗
Ce înseamnă reentrantînțelegi termenii tehnici din anexa B

Lucrez la exercițiul „Libgit2, JGit, go-git sau comanda git?” din capitolul „B. Appendix B: Embedding Git in your Applications”, la Pro Git. Enunțul: Pe baza anexei B, alege soluția potrivită și argumentează: 1. Un mic script de administrare care rulează pe un server unde Git e deja instalat. 2. O aplicație Android care trebuie să cloneze depozite (fără să depindă de un `git` instalat). 3. Un serviciu în Go care analizează mii de depozite în paralel, în memorie. 4. O aplicație desktop în C# sau Python care vrea performanță bună și acces la obiecte (bindings pentru libgit2, de ex. LibGit2Sharp sau pygit2). 5. Un instrument Python care trebuie să ruleze oriunde, fără biblioteci native de compilat. Pentru fiecare, notează un dezavantaj al alegerii tale. Nu sunt sigur ce înseamnă că libgit2 e „reentrant” și de ce contează pentru o aplicație. Pune-mi întrebări și dă-mi indicii până pot explica singur, cu un exemplu.

Deschide în Claude ↗

📇 C. Appendix C: Git Commands

întrebare de gândit

Ce comandă folosești? 12 situații

nivel 1

Pentru fiecare situație scrie comanda (sau comenzile) din anexa C, fără să te uiți în carte; apoi verifică-te cu git help <comanda> sau git <comanda> -h. 1. Vrei să vezi ce opțiuni are git log, rapid, în terminal. 2. Vrei să aduci modificările de pe server fără să-ți atingi ramurile locale. 3. Ai pus în staging un fișier din greșeală. 4. Vrei să anulezi efectul unui commit deja publicat, fără să rescrii istoria. 5. Vrei să știi cine a modificat ultima dată linia 42 dintr-un fișier. 6. Cauți un text în toate fișierele urmărite. 7. Vrei să trimiți cuiva commiturile pe e-mail, ca fișiere. 8. Vrei să aplici un fișier .patch produs cu git diff. 9. Vrei să muți proiectul pe un stick, cu toată istoria, într-un singur fișier. 10. Vrei să verifici integritatea bazei de date de obiecte. 11. Vrei să vezi tipul și conținutul unui obiect după hash. 12. Vrei să pui deoparte temporar modificările necomise.

Cum îți verifici singur rezultatul

1 git log -h (sau git help log); 2 git fetch; 3 git restore --staged <f> (sau git reset <f>); 4 git revert <commit>; 5 git blame -L 42,42 <f>; 6 git grep <text>; 7 git format-patch (și git send-email); 8 git apply; 9 git bundle create; 10 git fsck; 11 git cat-file -t / -p; 12 git stash.

Întreabă AI-ul ca să înveți

Copiază o întrebare într-un asistent AI. Sunt scrise ca AI-ul să te pună să gândești și să-ți dea indicii, nu răspunsul gata făcut.

Verifică-mi listaîți verifici răspunsurile

Lucrez la exercițiul „Ce comandă folosești? 12 situații” din capitolul „C. Appendix C: Git Commands”, la Pro Git. Enunțul: Pentru fiecare situație scrie comanda (sau comenzile) din anexa C, fără să te uiți în carte; apoi verifică-te cu `git help ` sau `git -h`. 1. Vrei să vezi ce opțiuni are `git log`, rapid, în terminal. 2. Vrei să aduci modificările de pe server fără să-ți atingi ramurile locale. 3. Ai pus în staging un fișier din greșeală. 4. Vrei să anulezi efectul unui commit deja publicat, fără să rescrii istoria. 5. Vrei să știi cine a modificat ultima dată linia 42 dintr-un fișier. 6. Cauți un text în toate fișierele urmărite. 7. Vrei să trimiți cuiva commiturile pe e-mail, ca fișiere. 8. Vrei să aplici un fișier `.patch` produs cu `git diff`. 9. Vrei să muți proiectul pe un stick, cu toată istoria,… Îți lipesc comenzile alese pentru cele 12 situații. Verifică-le și, pentru cele greșite, dă-mi un indiciu despre categoria din anexa C în care să caut, nu comanda corectă.

Deschide în Claude ↗
Quiz rapidexersezi cu situații noi

Lucrez la exercițiul „Ce comandă folosești? 12 situații” din capitolul „C. Appendix C: Git Commands”, la Pro Git. Enunțul: Pentru fiecare situație scrie comanda (sau comenzile) din anexa C, fără să te uiți în carte; apoi verifică-te cu `git help ` sau `git -h`. 1. Vrei să vezi ce opțiuni are `git log`, rapid, în terminal. 2. Vrei să aduci modificările de pe server fără să-ți atingi ramurile locale. 3. Ai pus în staging un fișier din greșeală. 4. Vrei să anulezi efectul unui commit deja publicat, fără să rescrii istoria. 5. Vrei să știi cine a modificat ultima dată linia 42 dintr-un fișier. 6. Cauți un text în toate fișierele urmărite. 7. Vrei să trimiți cuiva commiturile pe e-mail, ca fișiere. 8. Vrei să aplici un fișier `.patch` produs cu `git diff`. 9. Vrei să muți proiectul pe un stick, cu toată istoria,… Pune-mi încă 8 situații noi, una câte una, și lasă-mă să răspund cu comanda. După fiecare răspuns verifică-l și spune-mi pe scurt de ce e corect sau ce opțiune îmi lipsește.

Deschide în Claude ↗
de făcut

Mută un depozit fără rețea cu git bundle

nivel 2
git init sursa && cd sursa
echo 1 > f; git add .; git commit -m c1
echo 2 >> f; git commit -am c2
git bundle create ../repo.bundle HEAD main
git bundle verify ../repo.bundle
cd ..
git clone repo.bundle -b main destinatie
cd destinatie && git log --oneline && cd ..

Acum trimite doar ce e nou:

cd sursa
echo 3 >> f; git commit -am c3
git bundle create ../nou.bundle main~1..main
cd ../destinatie
git bundle list-heads ../nou.bundle
git pull ../nou.bundle main
git log --oneline

Răspunde: când ar fi util un bundle (gândește-te la rețele izolate, e-mail, stick USB)? De ce bundle-ul incremental nu poate fi clonat singur?

Cum îți verifici singur rezultatul
  • verify → ../repo.bundle is okay, conține 2 referințe (HEAD, refs/heads/main) și „records a complete history”.
  • Clona din bundle are c2, c1.
  • list-heads arată o singură linie <hash> refs/heads/main; după pull, log-ul are c3, c2, c1 (fast-forward).
  • Bundle-ul incremental conține doar commitul c3 și cere ca c2 să existe deja în depozitul care îl primește.

Întreabă AI-ul ca să înveți

Copiază o întrebare într-un asistent AI. Sunt scrise ca AI-ul să te pună să gândești și să-ți dea indicii, nu răspunsul gata făcut.

Ce conține bundle-ulînțelegi ce împachetează un bundle

Lucrez la exercițiul „Mută un depozit fără rețea cu git bundle” din capitolul „C. Appendix C: Git Commands”, la Pro Git. Enunțul: ```bash git init sursa && cd sursa echo 1 > f; git add .; git commit -m c1 echo 2 >> f; git commit -am c2 git bundle create ../repo.bundle HEAD main git bundle verify ../repo.bundle cd .. git clone repo.bundle -b main destinatie cd destinatie && git log --oneline && cd .. ``` Acum trimite doar ce e nou: ```bash cd sursa echo 3 >> f; git commit -am c3 git bundle create ../nou.bundle main~1..main cd ../destinatie git bundle list-heads ../nou.bundle git pull ../nou.bundle main git log --oneline ``` Răspunde: când ar fi util un bundle (gândește-te la rețele izolate, e-mail, stick USB)? De ce bundle-ul incremental nu poate fi clonat singur? Întreabă-mă ce cred că se află într-un fișier bundle (referințe, obiecte, un packfile?) și de ce `verify` spune că bundle-ul complet „records a complete history”. Lasă-mă să deduc și verifică-mi explicația.

Deschide în Claude ↗
Planific un transferîți planifici un transfer offline repetat

Lucrez la exercițiul „Mută un depozit fără rețea cu git bundle” din capitolul „C. Appendix C: Git Commands”, la Pro Git. Enunțul: ```bash git init sursa && cd sursa echo 1 > f; git add .; git commit -m c1 echo 2 >> f; git commit -am c2 git bundle create ../repo.bundle HEAD main git bundle verify ../repo.bundle cd .. git clone repo.bundle -b main destinatie cd destinatie && git log --oneline && cd .. ``` Acum trimite doar ce e nou: ```bash cd sursa echo 3 >> f; git commit -am c3 git bundle create ../nou.bundle main~1..main cd ../destinatie git bundle list-heads ../nou.bundle git pull ../nou.bundle main git log --oneline ``` Răspunde: când ar fi util un bundle (gândește-te la rețele izolate, e-mail, stick USB)? De ce bundle-ul incremental nu poate fi clonat singur? Vreau să sincronizez săptămânal un proiect între un calculator fără internet și laptopul meu. Lasă-mă să propun pașii cu bundle-uri incrementale și verifică-i; dă-mi indicii dacă intervalul ales nu e bun.

Deschide în Claude ↗
de făcut

git apply față de git am

nivel 2

Într-un depozit de test cu un fișier urmărit f:

echo "linie nouă" >> f
git diff > ../p.patch
git restore f
git apply --stat ../p.patch
git apply --check ../p.patch && echo "se aplică curat"
git apply ../p.patch
git status -s
git restore f

Apoi fă un commit cu aceeași modificare, exportă-l cu git format-patch -1 -o ../mail, revino cu git reset --hard HEAD~1 și aplică-l cu git am ../mail/*.patch. Compară git log -1 după fiecare metodă.

Răspunde: ce lipsește dintr-un patch făcut cu git diff ca să poată deveni direct un commit? Ce face git apply dacă patch-ul nu se aplică (față de comanda clasică patch)?

Cum îți verifici singur rezultatul
  • --stat arată f | 1 +; --check nu afișează nimic și se tipărește „se aplică curat”; după apply, git status -s arată M f (modificare necomisă, nu commit).
  • git am creează direct commitul, cu autorul, data și mesajul originale.
  • Un git diff nu are autor, dată și mesaj; git apply aplică totul sau nimic (nu lasă fișiere aplicate pe jumătate).

Întreabă AI-ul ca să înveți

Copiază o întrebare într-un asistent AI. Sunt scrise ca AI-ul să te pună să gândești și să-ți dea indicii, nu răspunsul gata făcut.

Când folosesc fiecarealegi între apply și am

Lucrez la exercițiul „git apply față de git am” din capitolul „C. Appendix C: Git Commands”, la Pro Git. Enunțul: Într-un depozit de test cu un fișier urmărit `f`: ```bash echo "linie nouă" >> f git diff > ../p.patch git restore f git apply --stat ../p.patch git apply --check ../p.patch && echo "se aplică curat" git apply ../p.patch git status -s git restore f ``` Apoi fă un commit cu aceeași modificare, exportă-l cu `git format-patch -1 -o ../mail`, revino cu `git reset --hard HEAD~1` și aplică-l cu `git am ../mail/*.patch`. Compară `git log -1` după fiecare metodă. Răspunde: ce lipsește dintr-un patch făcut cu `git diff` ca să poată deveni direct un commit? Ce face `git apply` dacă patch-ul nu se aplică (față de comanda clasică `patch`)? Pune-mi câteva situații (patch primit pe e-mail cu format-patch, diff lipit într-un chat, un patch vechi care poate nu se mai aplică) și lasă-mă să aleg comanda și opțiunile. Verifică-mi alegerea.

Deschide în Claude ↗
Patch care nu se aplicăprimești indicii pentru un patch eșuat

Lucrez la exercițiul „git apply față de git am” din capitolul „C. Appendix C: Git Commands”, la Pro Git. Enunțul: Într-un depozit de test cu un fișier urmărit `f`: ```bash echo "linie nouă" >> f git diff > ../p.patch git restore f git apply --stat ../p.patch git apply --check ../p.patch && echo "se aplică curat" git apply ../p.patch git status -s git restore f ``` Apoi fă un commit cu aceeași modificare, exportă-l cu `git format-patch -1 -o ../mail`, revino cu `git reset --hard HEAD~1` și aplică-l cu `git am ../mail/*.patch`. Compară `git log -1` după fiecare metodă. Răspunde: ce lipsește dintr-un patch făcut cu `git diff` ca să poată deveni direct un commit? Ce face `git apply` dacă patch-ul nu se aplică (față de comanda clasică `patch`)? `git apply --check` mi-a raportat o eroare. Îți lipesc mesajul. Pune-mi întrebări despre ce s-a schimbat în fișier între timp și dă-mi indicii despre opțiuni utile (de ex. pentru three-way), fără să-mi dai comanda directă.

Deschide în Claude ↗
de făcut

Anulează un commit publicat - revert, nu reset

nivel 2

Folosește setup-ul cu doi colegi din capitolul 3 (echipa/server.git, clonele ana și bogdan) sau refă-l. 1. Ana publică un commit greșit:

cd ana
echo "configurare greșită" > config.txt; git add .; git commit -m "Configurare nouă"
git push
cd ../bogdan && git pull && cd ../ana
  1. Varianta corectă: git revert HEAD (acceptă mesajul), git push. La Bogdan: git pull și git log --oneline -3.
  2. Varianta greșită (doar ca să vezi efectul): Ana face un commit greșit nou și îl publică; Bogdan face pull. Ana face git reset --hard HEAD~1 și încearcă git push, apoi git push --force. Bogdan face un commit nou, git pull, git status -sb și git push. Ce a ajuns pe server (git --git-dir=../server.git log --oneline -3)?
Cum îți verifici singur rezultatul
  • După revert apare un commit nou Revert "Configurare nouă"; istoria veche rămâne, config.txt dispare, iar Bogdan primește revertul cu un simplu fast-forward.
  • În varianta greșită, git push simplu e respins (non-fast-forward); --force rescrie ramura de pe server. La Bogdan, git pull spune Already up to date (el are deja tot ce e pe server, plus commitul „șters”), status -sb arată [ahead 2], iar push-ul lui readuce pe server commitul greșit — exact problema rescrierii istoriei publice.

Întreabă AI-ul ca să înveți

Copiază o întrebare într-un asistent AI. Sunt scrise ca AI-ul să te pună să gândești și să-ți dea indicii, nu răspunsul gata făcut.

Prezic ce vede Bogdanprezici efectele asupra colegului

Lucrez la exercițiul „Anulează un commit publicat - revert, nu reset” din capitolul „C. Appendix C: Git Commands”, la Pro Git. Enunțul: Folosește setup-ul cu doi colegi din capitolul 3 (`echipa/server.git`, clonele `ana` și `bogdan`) sau refă-l. 1. Ana publică un commit greșit: ```bash cd ana echo "configurare greșită" > config.txt; git add .; git commit -m "Configurare nouă" git push cd ../bogdan && git pull && cd ../ana ``` 2. **Varianta corectă:** `git revert HEAD` (acceptă mesajul), `git push`. La Bogdan: `git pull` și `git log --oneline -3`. 3. **Varianta greșită (doar ca să vezi efectul):** Ana face un commit greșit nou și îl publică; Bogdan face pull. Ana face `git reset --hard HEAD~1` și încearcă `git push`, apoi `git push --force`. Bogdan face un commit nou, `git pull`, `git status -sb` și `git push`. Ce a ajuns… Înainte de varianta greșită, întreabă-mă ce cred că va vedea Bogdan după `git push --force` al Anei și pull-ul lui. Nu-mi spune; după ce rulez, ajută-mă să explic diferența dintre revert și reset pe istorie publicată.

Deschide în Claude ↗
Regula meaformulezi singur o regulă de anulare

Lucrez la exercițiul „Anulează un commit publicat - revert, nu reset” din capitolul „C. Appendix C: Git Commands”, la Pro Git. Enunțul: Folosește setup-ul cu doi colegi din capitolul 3 (`echipa/server.git`, clonele `ana` și `bogdan`) sau refă-l. 1. Ana publică un commit greșit: ```bash cd ana echo "configurare greșită" > config.txt; git add .; git commit -m "Configurare nouă" git push cd ../bogdan && git pull && cd ../ana ``` 2. **Varianta corectă:** `git revert HEAD` (acceptă mesajul), `git push`. La Bogdan: `git pull` și `git log --oneline -3`. 3. **Varianta greșită (doar ca să vezi efectul):** Ana face un commit greșit nou și îl publică; Bogdan face pull. Ana face `git reset --hard HEAD~1` și încearcă `git push`, apoi `git push --force`. Bogdan face un commit nou, `git pull`, `git status -sb` și `git push`. Ce a ajuns… Ajută-mă să-mi formulez o regulă clară: când folosesc reset, când revert și când amend. Pune-mi întrebări despre dacă un commit e publicat sau nu, și verifică-mi regula finală.

Deschide în Claude ↗