Vai al contenuto
GitTree

Lezione 21 · Storia e integrazione

Merge versus rebase: scegli con un grafico

Esegui l'unione e il rebase da due copie identiche della stessa divergenza, confronta i due grafici, i genitori e gli alberi dei file e impara l'unica regola che decide tra loro: chi altro ha già i tuoi commit.

Avanzamenti salvati in questo browser.

La riproduzione carica il video da YouTube (modalità ottimizzata per la privacy).

Narrazione in inglese · English and Arabic didascalie

Apri la pagina del videoGuarda su YouTube

Cosa imparerai

  • Inizia l'unione e il rebase da copie identiche, quindi il confronto è giusto.
  • Legge i due genitori di un commit di unione e il nuovo genitore singolo di un commit ribasato.
  • Spiega perché due copie possono terminare con gli stessi file e avere comunque storie diverse.
  • Scegli con una regola: riscrivi solo i commit che nessun altro ha.

Prima di iniziare

Hai bisogno di due copie separate della divergenza della lezione 20, denominate gittree-merge e gittree-rebase. In ogni copia il ramo feature/signup-form contiene uno dei tuoi commit (chiamiamolo S), il ramo updated-main contiene un commit diverso (chiamiamolo N), entrambi iniziati dallo stesso commit M e rescue/signup-before-rebase punta a S. Il ramo dell'argomento è stato estratto e l'albero di lavoro è pulito. Non creare la seconda copia dal risultato della prima.

Qui tutto è locale e con il piano gratuito (GitTree ti chiede di accedere): nessun account di hosting, nessun provider, niente Internet. Ogni identità è fittizia (esempio.com) e non dovresti mai eseguire questa lezione all'interno di un progetto reale.

Apporta le modifiche in GitTree o con i comandi Git nativi, non entrambi nella stessa copia. Leggere il risultato successivamente è sempre sicuro. Le etichette dei menu provengono dalle stringhe proprie di GitTree 2.0; i comandi nativi sono stati eseguiti con Git 2.43 in copie usa e getta. I passaggi GitTree non sono stati eseguiti su macOS, Windows o Linux; le scorciatoie dell'app utilizzano Comando su macOS dove questa pagina scrive Ctrl.

Effetti del concetto e dello stato

Un confronto è giusto solo quando entrambe le copie iniziano dagli stessi riferimenti e dagli stessi file. Se prima unisci e poi ribasi il risultato, stai ponendo una domanda diversa: il replay ora ha un commit di unione nel suo intervallo.

Merge mantiene entrambe le linee di lavoro. Aggiunge un nuovo commit, K, con due genitori: prima S, poi N. S e N mantengono i loro ID.

Rebase riproduce il tuo commit sopra N. Il risultato, S′, ha la stessa modifica di S ma un nuovo genitore e l'ID di un commit include il suo genitore, quindi S′ ha un nuovo ID. La vecchia S sopravvive solo perché la filiale di soccorso la indica ancora.

Quando nulla è in conflitto, entrambe le copie terminano con lo stesso albero di file. Alberi uguali non significano storia uguale: un grafico mantiene un diamante, l'altro una linea retta e gli ID di commit differiscono.

Quale sia quello giusto non è una questione di gusti. Se altre persone hanno già i tuoi commit, riprodurli interrompe le loro copie, quindi unisci. Se i commit sono privati, un rebase è sicuro e fornisce una cronologia lineare se il tuo team ne preferisce una. Né migliora il codice.

In ogni copia si sposta solo il ramo dell'argomento. Il server, updated-main e quello principale originale non vengono toccati.

Preparare lo stato esatto del progetto

Fai una divergenza, poi copiala due volte. Inizia da una copia ordinaria separata del progetto così come lo ha lasciato la lezione 18 (il principale è il merge commit M). Lascia intatto il tuo gittree-features originale e non eseguirlo mai in un checkout di origine. L'identità demo è GitTree Demo, demo@example.com, con la firma disattivata solo in questo repository.

Completare gli input del file

Risparmia solo nella fase denominata di seguito. Questi sono corpi UTF-8/LF completi con un ritorno a capo finale; non incollare mai le recinzioni Markdown. I file eseguibili non modificati ereditano l'input denominato. Le versioni in varianti separate non devono sovrascrivere l'originale.

index.html — ISCRIVITI

Estratto del file · html
<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>GitTree Features — course demo</title>
  <link rel="stylesheet" href="styles.css">
</head>
<body>
  <header class="site-header">
    <a href="#main">GitTree Features</a>
  </header>
  <main id="main" tabindex="-1">
    <section class="hero" aria-labelledby="hero-title">
      <p class="eyebrow">GitTree Learn demo project</p>
      <h1 id="hero-title">See your work clearly.</h1>
      <p id="hero-copy">Choose one change, then check what Git saved.</p>
    </section>
    <section class="features" aria-labelledby="features-title">
      <h2 id="features-title">Follow your work</h2>
      <div class="cards">
        <article class="feature-card">
          <h3>History</h3>
          <p>Read commits and branches together.</p>
        </article>
        <article class="feature-card">
          <h3>Changes</h3>
          <p>Review the exact content selected for a commit.</p>
        </article>
        <article class="feature-card">
          <h3>Recovery</h3>
          <p>Inspect the scope of a recovery point before using it.</p>
        </article>
      </div>
    </section>
    <section aria-labelledby="plans-title">
      <h2 id="plans-title">Choose the workflow you need</h2>
      <div class="cards">
        <article class="feature-card">
          <h3>Local Git</h3>
          <p>Local Git workflows work without signing in.</p>
        </article>
        <article class="feature-card">
          <h3>Connected workflows</h3>
          <p>Provider integrations and Nour require Pro or an applicable trial.</p>
        </article>
      </div>
    </section>
    <section aria-labelledby="signup-title">
      <h2 id="signup-title">Try the demo form</h2>
      <form id="signup-form" novalidate>
        <label for="demo-email">Demo email</label>
        <input id="demo-email" name="email" type="email" autocomplete="off" aria-describedby="signup-hint">
        <p id="signup-hint">Use a fictional example.com address. Nothing is sent.</p>
        <button type="submit">Check the address locally</button>
        <p id="signup-result" role="status"></p>
      </form>
    </section>
  </main>
  <footer><p>Built by a fictional team for GitTree Learn. Review one change at a time.</p></footer>
  <script type="module" src="site.js"></script>
</body>
</html>

docs/integration-note.md — DOC_MERGE

Uscita
# Integration review

This note was written on main while signup work was private.

Tra GitTree

Apri la tavolozza con Comando+Maiusc+P (Ctrl+Maiusc+P su Ubuntu), digita il nome esatto del comando e selezionalo. Le azioni su un ramo con nome utilizzano il menu di scelta rapida di quel ramo.

  1. Apri gittree-merge. Quindi scegli New Tab e apri gittree-rebase dal suo elenco Recent. Ogni scheda è intitolata con il nome della cartella, quindi puoi distinguerle.
  2. Nella scheda gittree-merge mantieni feature/signup-form controllato. Fai clic con il pulsante destro del mouse su updated-main e scegli Merge updated-main into feature/signup-form.
  3. Sotto Record it as scegli Always a merge commit, quindi scegli Merge una volta. Il nuovo commit ha due genitori: prima S, poi N.
  4. Passa alla scheda gittree-rebase. È ancora a S e N, esattamente come l'hai salvato. Non utilizzare la copia unita.
  5. Fai clic con il pulsante destro del mouse su updated-main e scegli Rebase feature/signup-form onto updated-main. Leggi Options for this rebase e lascia entrambe le opzioni disattivate, quindi scegli Rebase feature/signup-form una volta.
  6. Seleziona il commit riprodotto. Il suo genitore è N e il suo ID è nuovo. La vecchia S porta ancora il nome rescue/signup-before-rebase.
  7. In ogni scheda apri Show Files → index.html e docs/integration-note.md. Sono la stessa pagina e la stessa nota in entrambe le copie. Quindi ritorna con Back to Graph.
  8. Confronta i due grafici, quindi indica quale regola decide la scelta per questo ramo prima di scegliere un risultato. Conserva entrambe le copie così come sono.

Per ogni commit ordinario nel corso: Summary è l'oggetto dichiarato, Description è vuoto e le opzioni Amend Previous Commit, Skip Hooks, Add Signed-off-by, Different Author, Push After Commit e Allow Empty Commit rimangono disattivate. Questa lezione non prevede un commit ordinario.

Nel terminale

Costruisci la divergenza in una copia separata e pulita del risultato della lezione 18 (il lavoro che hai svolto nell'app, scritto come comandi nativi):

Command · bash
git switch --create feature/signup-form

Salva l'intera pagina di ISCRIZIONE come index.html, quindi:

Command · bash
git add -- index.html
git commit --quiet -m "feat: add the local signup demonstration"
git branch rescue/signup-before-rebase
BASE_SHA="$(git rev-parse HEAD~1)"
git switch --quiet --create updated-main "$BASE_SHA"

Il giorno updated-main salva l'intera nota DOC_MERGE come docs/integration-note.md, quindi:

Command · bash
git add -- docs/integration-note.md
git commit --quiet -m "docs: add the integration review"
git switch --quiet feature/signup-form

BASE_SHA è il commit M da cui crescono entrambe le linee. Ora crea le due copie indipendenti da questo stato esatto (cd .. && cp -R gittree-features gittree-merge && cp -R gittree-features gittree-rebase). Nella copia unita:

Command · bash
git merge --quiet --no-ff --no-edit updated-main
git rev-list --parents -n 1 HEAD
git rev-parse 'HEAD^{tree}'
git status --short

Nella copia rebase intatta:

Command · bash
git rebase --quiet --no-autostash --no-update-refs --no-autosquash updated-main
git rev-list --parents -n 1 HEAD
git rev-parse 'HEAD^{tree}'
git status --short

git rev-list --parents -n 1 HEAD stampa l'ID del commit seguito dai suoi genitori: tre ID nella copia di unione, due nella copia di rebase. Le due righe HEAD^{tree} hanno lo stesso ID e git status --short non stampa nulla in entrambe. I due ID commit HEAD sono diversi. I tuoi ID saranno diversi da quelli di chiunque altro; confronta i tuoi tra loro, non con questa pagina.

Se l'argomento non avesse un commit proprio e updated-main fosse semplicemente in vantaggio rispetto a esso, git merge avanzerebbe velocemente per impostazione predefinita e non creerebbe alcun commit di unione. Questo è un input diverso e un risultato diverso; sceglilo apposta, non fingere mai una fusione tra due genitori.

Risultato

Where you end: la copia unificata ha un nuovo commit K con genitori S e N; la copia rebase ha S′ con genitore N, e la vecchia S è conservata dal ramo di salvataggio. Gli alberi dei file sono uguali, entrambi gli stati sono puliti e quello principale originale, M e il server non sono stati modificati.

Errori comuni

  • Supponendo che un grafico lineare significhi che il vecchio ID di commit è sopravvissuto. Un rebase crea sempre nuovi commit.
  • Avvio del rebase dal risultato dell'unione. Questo è un esperimento diverso e la riproduzione può includere il commit dell'unione.
  • Confrontando i due ID HEAD e aspettandosi che siano d'accordo. Confronta invece gli alberi.
  • Ripetendo l'unione o il rebase dopo che è già terminato.

Se qualcosa va storto

Non scartare nessuno dei risultati per forzarli a corrispondere. Se gli alberi differiscono, confronta i riferimenti iniziali, qualsiasi risoluzione dei conflitti e qualsiasi commit aggiuntivo, quindi ricomincia dalla divergenza salvata. Un ramo di salvataggio conserva solo la cronologia impegnata; non mantiene i file non salvati.

Controlla la tua comprensione

Rispondi a ciascuna domanda, quindi leggi il motivo. Le domande contrassegnate come "Obbligatorio" contano ai fini del completamento della lezione.

  1. Domanda 1 di 6

    Dallo stesso inizio, unisci updated-main in feature/signup-form in una copia e ribase feature/signup-form in updated-main in un'altra. Quanti genitori ha il nuovo tip commit dell'argomento in ogni copia?

    Scegli una risposta.

  2. Domanda 2 di 6

    Quali di questi sono gli stessi in entrambe le copie una volta che l'unione e il rebase sono terminati senza conflitti?

    Scegli ogni risposta applicabile.

  3. Domanda 3 di 6
    Obbligatorio

    Dopo il rebase, cosa è successo al tuo topic originale commit S?

    Scegli una risposta.

  4. Domanda 4 di 6

    Cambia l'input: il tuo argomento non ha un proprio commit e updated-main è semplicemente davanti a esso. Ti unisci con la modalità predefinita, "Avanti veloce se possibile, altrimenti un commit di unione". Che succede?

    Scegli una risposta.

  5. Domanda 5 di 6
    Obbligatorio

    Un collega ha già ritirato feature/signup-form e sta sviluppando su di esso. Vuoi che la cronologia di main rimanga in ordine. Qual è la scelta sicura?

    Scegli una risposta.

  6. Domanda 6 di 6
    Obbligatorio

    Quali riletture mostrano che il confronto era giusto e mostrano come è finito?

    Scegli ogni risposta applicabile.

0 di 6 corretto

Rispondi correttamente alle domande richieste per completare la lezione.

Controllato in questo browser.

Pratica

Riporta i due elenchi principali, i due ID HEAD e i due ID dell'albero. Spiegare perché il risultato atteso è ID di albero uguali accanto a ID HEAD diversi. Quindi prevedere, senza farlo, cosa fa un'unione predefinita quando l'argomento non ha un proprio commit.

La tua conferma: il sito non può vedere il tuo computer.

Per completare la lezione rispondere correttamente alle domande richieste e confermare l'esercizio pratico.

Riepilogo

  • Stesso inizio, storia diversa.
  • Alberi uguali non significano storia uguale.
  • Unisci quando gli altri hanno i tuoi commit. Rebase solo quelli privati.

Termini del glossario introdotti

Rebase — إعادة تأسيس; ripetere: إعادة تطبيق; ramo di salvataggio — فرع حفظ.

Trascrizione video

La narrazione del video, spunto per spunto.

Mostra la trascrizione
  1. Unire o riorganizzare? Lo stesso lavoro può andarsene due storie diverse.
  2. Correremo entrambi dallo stesso inizio puntare e confrontare.
  3. Il tuo ramo ha un commit. L'aggiornato il ramo ne ha un altro.
  4. Entrambi sono cresciuti dallo stesso impegno, quindi nessuno dei due contiene l'altro.
  5. Per prima cosa prepara la divergenza e creane due copie identiche.
  6. Un test corretto richiede gli stessi riferimenti e file in entrambe le copie.
  7. Ecco la prima copia. Ci uniremo questo.
  8. E questa è la seconda copia. Lo teniamo intatto per il rebase.
  9. Fare clic con il pulsante destro del mouse su aggiornato-principale e sceglierlo Unisci comando.
  10. In Registra come scegli Sempre un'unione impegnarsi.
  11. Scegli Unisci una volta e attendi il vero risultato.
  12. Il nuovo commit ha due genitori: your commit, quindi aggiornato-main.
  13. Ora la seconda copia. Ha ancora i due impegni originali.
  14. Fare di nuovo clic con il pulsante destro del mouse su aggiornato-principale e scegliere Ribase questa volta.
  15. La finestra di dialogo nomina il ramo e il file bersaglio. Lascia entrambe le opzioni disattivate.
  16. Ribasare una volta. Git riproduce il tuo commit top di aggiornato-main.
  17. Il commit riprodotto ha un nuovo genitore, quindi ottiene un nuovo ID.
  18. Il vecchio impegno non è andato perduto: il salvataggio il ramo lo indica ancora.
  19. Ora confronta i file. La pagina è la stesso in entrambe le copie.
  20. Così è la nota di integrazione. Stessi file, storia diversa.
  21. Guarda i due grafici: un diamante con a unisci commit e una linea retta.
  22. Quindi quale dovresti usare? Chiedi a chi altro ha i tuoi impegni.
  23. Se altri li hanno, uniscili. Un rebase lo farebbe riscrivere la loro storia.
  24. Se i commit sono privati, rebase lo è sicuro e dà una linea retta.
  25. Né migliora il tuo codice. La regola riguarda la proprietà.
  26. Ora dimostralo nel terminale. Innanzitutto, il genitori di ogni punta.
  27. Tre ID per la copia unificata: il commit, e i suoi due genitori.
  28. Due ID per la copia rebase: il commit, ed è un genitore.
  29. Poi gli alberi dei file: un ID, stampato due volte. Stessi file.
  30. Ma i due ID di commit differiscono. Uguale alberi, storie diverse.
  31. Cambia l'input: supponi che il tuo ramo avesse nessun impegno proprio.
  32. Un'unione predefinita avanzerebbe quindi rapidamente, senza commit di unione.
  33. Non riprogrammare mai un ramo di qualcun altro ha già.
  34. Se gli alberi differiscono, confronta l'inizio prima gli arbitri.
  35. Non eliminare un risultato per forzarne i due partita.
  36. Pratica: segnalare i genitori, i documenti d'identità e gli alberi dalle tue copie.
  37. Successivamente, riordina, schiaccia e riformula il tuo impegni locali.