VCS setup: mergiraf + jj + textconv

Tutorijal: sintaksni merge, jj sa zakljucanim push-ovanim commit-ima, diff nad PDF/DOCX, docdiff CLI

Podešeno 19–26. septembra 2026. na Kimi mašini (Windows 11, git 2.55). Kontekst i "zašto": xit-haxy-patch-based-merge i binarni-fajlovi-verzionisanje-i-diff.

Šta je instalirano i šta radi

AlatVerzijaČemu služi
mergiraf0.16.3rešava git konflikte po sintaksi koda
jj (Jujutsu)0.45.1alternativni klijent nad git repoom
textconv (pdftotext, pandoc)—git diff nad PDF i DOCX fajlovima

Binarni fajlovi su u %LOCALAPPDATA%\Microsoft\WinGet\Packages\... i na PATH-u (važi u novootvorenom terminalu).

Config fajlovi:


1. mergiraf (uz običan git)

Radi sam, ništa se ne poziva ručno. Uključen je za merge, rebase, cherry-pick nad 75 tipova fajlova iz ~/.gitattributes.

git merge grana        # mergiraf prvo probava sintaksni merge

Šta dobijaš: konflikti tipa "dve grane dodale različite funkcije/importe na isto mesto" prolaze bez intervencije. Isti konflikt bez mergiraf-a staje.

KomandaŠta radi
mergiraf solve <fajl>reši fajl koji već ima oznake konflikta
mergiraf review <id>pokaže šta je mergiraf odlučio (id ispiše on)
mergiraf=0 git merge xpreskoči mergiraf za tu jednu komandu

Ograničenja: samo tekstualni kod (ne binarni fajlovi), i nikad ne pogađa — pravi konflikt ostavlja sa oznakama.

2. Provera merge-a (važno)

Git ne proverava rešenje konflikta: čovek može upisati bilo šta, i to prođe (evil merge). Jedina komanda koja to pokaže:

git show --remerge-diff <merge-commit>   # razlika: mehanički merge vs. commit-ovano
git log  --remerge-diff                  # kroz istoriju

Zato posle svakog automatskog merge-a važe testovi, a ne vera u alat.

3. jj — svakodnevni tok

Uključivanje na postojećem repou (git ostaje, jj ide pored):

cd <repo>
jj git init --colocate
jj bookmark track master@origin    # da lokalni master prati server

git status posle ovoga piše HEAD (no branch) — normalno.

Rad:

jj git fetch
jj new main@origin           # počni novi commit na vrhu main-a
# ... menjaj fajlove; nema `git add`, jj snima sam ...
jj st                        # šta je izmenjeno
jj describe -m "Poruka"      # poruka za trenutni commit
jj new                       # zatvori ga i počni sledeći

jj bookmark create moja-grana -r @-
jj git push --bookmark moja-grana

Usklađivanje i dorada:

jj git fetch
jj rebase -d main@origin     # konflikt ne prekida rad, zapiše se u commit
jj resolve --list            # koji fajlovi su u konfliktu
jj resolve                   # pokreće mergiraf (podešen kao merge-editor)

Vraćanje bilo čega:

jj op log                    # dnevnik svih operacija
jj undo                      # vrati poslednju
jj abandon <change-id>       # baci commit

Zaključavanje push-ovanog (tvoje pravilo)

Podešeno je da je sve što postoji na serveru nepromenljivo:

"immutable_heads()" = "builtin_immutable_heads() | remote_bookmarks()"

Provereno: jj describe nad push-ovanim commit-om vraća Error: Commit ... is immutable. Lokalni commit-i se menjaju normalno.

Posledica: dorada posle review-a ide novim commit-om, ne prepravkom:

jj new moja-grana
# ... ispravke ...
jj describe -m "Ispravke posle review-a"
jj bookmark move moja-grana --to @
jj git push --bookmark moja-grana

Zamke jj-a (naučeno na svojoj koži)

  1. CRLF. Git for Windows ima core.autocrlf=true u sistemskom configu; jj po defaultu ne konvertuje krajeve linija → prvi commit menja svaku liniju u svim fajlovima. Rešeno globalno: working-copy.eol-conversion = "input-output".
  2. Dugačke putanje. jj.exe nema longPathAware u manifestu, pa Windows limit od 260 znakova važi i kad je LongPathsEnabled=1. Repo putanja mora biti kratka (~<100). Simptom: Failed to write index file ... (os error 3).
  3. Nema Git LFS podrške → medija repoe ne stavljati pod jj.
  4. Ne pokreće git hook-ove (pre-commit i sl.) — pokreni ručno pre push-a.
  5. Commit bez poruke se ne može push-ovati (jj describe prvo).
  6. Svi novi fajlovi se automatski prate. Ako .gitignore nije uredan, u commit uleti i .env. Stroža varijanta: snapshot.auto-track = "none()" + jj file track.

Isključivanje jj-a iz repoa: obriši .jj, pa git checkout master.

4. textconv — diff nad PDF i DOCX

Podešeno globalno; radi u svakom repou, bez ičega u projektu:

git diff  ugovor.pdf        # vidi se tekst, ne "Bin 1433 -> 1433 bytes"
git log -p ponuda.docx      # istorija sadržaja dokumenta
git show HEAD:ponuda.docx | pandoc --to=plain   # jedna verzija kao tekst

Provereno na dve verzije istog ugovora — diff je pokazao samo izmenjene stavke (rok 30→45 dana, cena 1000→1200 EUR).

Kako je podešeno:

diff.pdf.textconv  = sh -c "pdftotext -layout -q \"$0\" -"
diff.docx.textconv = pandoc --to=plain --wrap=none
+ cachetextconv=true  (keš konverzije, drugi diff je instant)
~/.gitattributes: *.pdf binary diff=pdf ; *.docx binary diff=docx ; *.exe/*.dll binary

Detalji koje treba znati:

Dodavanje novih formata

# XLSX preko CSV-a (traži xlsx2csv)
git config --global diff.xlsx.textconv "xlsx2csv"
echo '*.xlsx binary diff=xlsx' >> ~/.gitattributes

# EXE/DLL: spisak izvezenih funkcija umesto bajtova (traži VS build tools)
git config --global diff.exe.textconv 'sh -c "dumpbin /exports \"$0\""'

5. Ad-hoc poređenje dokumenata (van git-a)

Princip: oba fajla pretvori u tekst, pa uporedi tekst. Radi i kad fajlovi nisu u repou.

Pretvaranje u tekst po formatu:

FormatKomanda
DOCXpandoc --to=plain --wrap=none a.docx
PDFpdftotext -layout -q a.pdf -
XLSXxlsx2csv a.xlsx (nije instalirano)

Najkraće: docdiff

CLI koji sve gornje radi sam (~/.claude/docdiff.js, na PATH-u kao docdiff):

docdiff v1.docx v2.docx        # dva DOCX-a
docdiff ugovor.pdf ugovor.docx # razliciti formati
docdiff t1.xlsx t2.xlsx        # tabele

Izlaz (podrazumevano po rečima):

--- v1.docx  (pandoc)
+++ v2.docx  (pandoc)
Rok: [-30-]{+45+} dana
Garancija: [-12 meseci-]{+24 meseca+}
{+Napomena: dodata stavka+}
OpcijaEfekat
--linesklasičan diff po redovima
--blankne čisti prazne redove (tačniji prelom, više šuma)
--rawispiše samo pretvoren tekst fajla A
--keepostavi .txt fajlove i javi gde su
--no-colorbez boja

Izlazni kod: 0 isti sadržaj, 1 ima razlika, 2 greška — može u skript i u hook.

Formati i čime se pretvaraju: PDF preko pdftotext; DOCX, ODT, RTF, PPTX, EPUB, HTML, MD preko pandoc; XLSX, XLS, DOC, PPT preko LibreOffice-a (soffice --headless); TXT, CSV, JSON, XML direktno. Ako pandoc padne, sam pređe na LibreOffice.

Ručni recepti ispod su korisni kad treba nešto posebno (drugi format prikaza, filtriranje).

Dva DOCX-a (ručno)

pandoc --to=plain --wrap=none v1.docx > a.txt
pandoc --to=plain --wrap=none v2.docx > b.txt
git diff --no-index --word-diff a.txt b.txt

Izlaz označava izmene unutar reda: Rok: [-30-]{+45+} dana. --word-diff je bolji od običnog diff-a za tekst pisan u rečima.

Napomena o <(...): konstrukcija radi u Git Bash-u sa MSYS alatima (diff, grep, pandoc), ali NE sa native Windows programima kao git.exe. Bash prosledi putanju /dev/fd/63, koju git vidi kao /proc/<pid>/fd/63 i ne ume da je otvori (error: Could not access '/proc/1532/fd/63'). Zato za git diff prvo upiši u prave fajlove, a diff -u <(...) <(...) može direktno. U PowerShell-u <(...) ne postoji uopšte — to je druga stvar.

Za ugovore i dopise je Word: Review → Compare ipak najbolji, jer poredi strukturu dokumenta i rezultat daje kao praćene izmene. Gornji recept je za skript i za brz pregled.

Različiti formati, ručno (PDF protiv DOCX)

Može, jer se poredi tekst, a ne format:

pdftotext -layout -q ugovor.pdf - > p.txt
pandoc --to=plain --wrap=none ugovor.docx > d.txt
diff -u -B p.txt d.txt

-B ignoriše razliku u praznim linijama — bez njega svaki pasus ispada kao izmena, jer pandoc ostavlja prazan red između pasusa, a pdftotext ne.

Šta se poredi, a šta ne:

Znači: dobro za "da li je promenjen rok ili cena", nije za "da li dokument izgleda isto".

6. Vraćanje na staro

cp ~/.gitconfig.bak-2026-09-19 ~/.gitconfig    # git podešavanja
winget uninstall jj-vcs.jj
winget uninstall Mergiraf.Mergiraf

~/.gitattributes obriši ručno ako ga ne želiš (pre setup-a nije postojao).

7. Šta NIJE instalirano (a bilo je u razmatranju)

Git LFS, WinMerge, Beyond Compare, radare2, ImageMagick, restic — vidi binarni-fajlovi-verzionisanje-i-diff za kada šta uzeti.

Izvor: vcs-jj-mergiraf-textconv.md