Architecture Decision Records - ADR260201d

2026/02/01

Force push/pull senza merge resolution

Autore: Marco Orlandin, Architect
Data: 01 Febbraio 2026
Status: Implementato
Progetto: git-side (open-source, sviluppato per Solexma LLC)
Constraint principali: Semplicità d'uso, nessuno stato di conflitto possibile, mental model chiaro per l'utente

Contesto e problema

git-side supporta remote: puoi fare push e pull dei file "a lato" per condividerli tra macchine o con colleghi. La domanda è: cosa succede quando il locale e il remoto divergono?

Nel Git tradizionale, la divergenza si risolve con merge o rebase, operazioni che possono generare conflitti e richiedere intervento manuale. Per un tool che versiona appunti, scratch, config locali, questa complessità è sproporzionata.

Il rischio concreto: un utente fa git side pull, si ritrova in uno stato di conflitto su BACKLOG.md, e non sa come uscirne. Il tool che doveva semplificargli la vita gli ha appena complicato la giornata.

Requisiti non funzionali

  • Nessuno stato di conflitto possibile, mai
  • Operazione deterministica: il risultato è sempre prevedibile
  • Mental model immediato: l'utente deve capire cosa succede senza leggere documentazione
  • Nessuna perdita di dati silenziosa

Opzioni valutate

Opzione 1: Merge standard (come git pull)

  • Pro: Comportamento familiare per chi usa Git.
  • Contro: Genera conflitti. Richiede risoluzione manuale. Stato "conflitto in corso" su file come TODO.md è assurdo. Complessità sproporzionata per il tipo di contenuto.

Opzione 2: Rebase automatico

  • Pro: Storia lineare, meno conflitti rispetto al merge.
  • Contro: Può comunque generare conflitti. Comportamento meno prevedibile. Richiede comprensione di rebase da parte dell'utente.

Opzione 3: Strategia "ours/theirs" automatica

  • Pro: Nessun conflitto, risoluzione automatica.
  • Contro: Semantica ambigua: chi "vince" dipende dalla direzione. Rischio di perdita dati silenziosa se la strategia non è chiara.

Opzione 4: Force push (locale vince) e force pull (remoto vince)

  • Pro: Deterministico. Zero conflitti. Mental model cristallino: push = il mio locale sovrascrive il remoto, pull = il remoto sovrascrive il mio locale. Nessuno stato intermedio possibile.
  • Contro: Una delle due versioni viene sovrascritta. Non c'è "merge intelligente" dei contenuti.

Decisione

Scelta la strategia force: push con --force (locale vince sempre), pull con fetch + reset --hard (remoto vince sempre).

Motivazioni principali:

  1. Zero conflitti: nessuno stato di merge in corso, mai.
  2. Determinismo totale: l'utente sa esattamente cosa succede.
  3. Adeguato al contesto: file "a lato" (appunti, config, scratch) non hanno bisogno di merge a tre vie.
  4. La storia è preservata: le versioni precedenti restano nella storia git, non vengono perse.

Implementazione passo-passo

  1. Push: git push --force origin main, il contenuto locale sovrascrive il remoto.
  2. Pull: git fetch origin main seguito da git reset --hard origin/main, il contenuto remoto sovrascrive il locale.
  3. Nessun merge, fetch-only: Pull non usa git pull ma la sequenza fetch + reset, evitando qualsiasi tentativo di merge.
  4. Branch unico: Operazioni su main per semplicità. Nessun supporto multi-branch nel side repo.

Conseguenze osservate

  • Nessun utente si è mai trovato in stato di conflitto.
  • Il mental model "push = locale vince, pull = remoto vince" è stato compreso immediatamente da tutti i tester.
  • La storia git preserva le versioni precedenti, quindi nessun dato è realmente "perso", solo sovrascritto nella working copy.
  • Lezioni apprese:
    • La complessità del merge è giustificata per codice sorgente, non per ogni tipo di contenuto.
    • "Niente conflitti, mai" è un requisito di UX, non solo tecnico.
    • La semplicità radicale richiede coraggio nelle scelte di design: rinunciare al merge è stata la decisione più opinionata e più apprezzata.

Stack utilizzato

  • Linguaggio: Rust (Edition 2024, MSRV 1.85)
  • Git: git push --force, git fetch + git reset --hard

Quando considerare questo approccio

Se il tuo tool sincronizza contenuti dove:

  • Il merge semantico non ha senso (appunti, config, file binari)
  • La semplicità d'uso è prioritaria rispetto alla granularità
  • L'utente deve avere un mental model immediato

...force operations è quasi sempre la scelta giusta. Aggiungi merge solo quando il contenuto lo richiede davvero.

Hai un caso simile? Contattami. Valutiamo insieme se la semplicità radicale è la strada giusta.