Vai al contenuto
GitTree

Lezione 31 · Recupero

Mantenere il lavoro distaccato e iniziare una storia orfana

Assegna un nome a un commit effettuato su un HEAD distaccato prima di lasciarlo, quindi avvia un ramo orfano in una copia separata e guarda cosa rimuove e cosa mantiene.

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

  • Dite a parte la TESTA attaccata, distaccata e non nata.
  • Metti un ramo su un commit distaccato in modo che rimanga raggiungibile.
  • Prevedi cosa fa un ramo orfano ai file tracciati, ai file non tracciati e al vecchio ramo.
  • Leggi un rifiuto di pagamento causato da modifiche locali.

Prima di iniziare

Due copie usa e getta del risultato M della lezione 18. Nella prima, controlli il commit M stesso invece del ramo, apporti una piccola modifica al foglio di stile lì e vuoi mantenerlo. Nel secondo, desideri una cronologia nuova di zecca e non correlata per un ramo di sola documentazione senza toccare main.

Tutto è locale e nel piano gratuito (GitTree ti chiede di accedere): nessun account di hosting, nessun provider, niente Internet. Ogni identità è fittizia (esempio.com). Non eseguire mai questa lezione in un progetto reale.

Apporta le modifiche in GitTree o con i comandi Git nativi, non entrambi nella stessa copia. Leggere il risultato è sempre sicuro. Le etichette dei menu provengono dalle stringhe proprie di GitTree 2.0 e 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.

Effetti del concetto e dello stato

HEAD normalmente nomina un ramo e il commit sposta quel ramo. Quando HEAD nomina direttamente un commit è detached: un nuovo commit è reale, ma nulla gli dà un nome, quindi spostandosi lo lascia raggiungibile solo attraverso il reflog. Mettendoci sopra un ramo si risolve il problema. La creazione di un ramo non comporta il passaggio ad esso a meno che tu non lo decida.

Un ramo orphan è diverso. HEAD nomina un ramo che non ha ancora alcun commit (un ramo non ancora nato). Il suo primo commit non ha elemento principale, quindi non condivide la cronologia con main. Git rimuove i file tracciati dalla cartella di lavoro; i file non tracciati e ignorati rimangono. Se il vecchio .gitignore veniva tracciato, le sue regole lo accompagnano e i file ignorati ora possono essere visualizzati come non tracciati. Il tuo vecchio ramo mantiene ogni commit.

Entrambi gli stati sono normali, non danni. Un checkout viene rifiutato quando sovrascriverebbe le modifiche locali; nulla è perduto.

Preparare lo stato esatto del progetto

Inizia da due copie ordinarie separate del risultato della lezione 18 e lascia intatto l'originale. I corpi sottostanti sono il foglio di stile della linea di base (BASE_CSS), quello ampliato (LAYOUT), una modifica sporca (DIRTY_LAYOUT), il file readme dell'orfano (ORPHAN_README), una nota locale (LOCAL_NOTE) e una nota ignorata (IGNORED_NOTE).

Completare gli input del file

Salva ogni corpo UTF-8/LF completo solo nella fase indicata, con un ritorno a capo finale e senza recinzioni Markdown. BASE_CSS è il riferimento 48rem ereditato; LAYOUT è il commit 52rem; DIRTY_LAYOUT è un replay 56rem separato e non messo in scena. I due file di note appartengono solo alla variante sopravvissuta. I file principali invariati ereditano l'intero ingresso L018/M.

stili.css — BASE_CSS

Estratto del file · css
:root {
  color-scheme: light;
  --page: #f7f8fa;
  --surface: #ffffff;
  --text: #17212e;
  --link: #154ab5;
  --line: #bac4d0;
}

* {
  box-sizing: border-box;
}

body {
  margin: 0;
  background: var(--page);
  color: var(--text);
  font: 1rem/1.6 system-ui, sans-serif;
}

a {
  color: var(--link);
}

.site-header,
main,
footer {
  width: min(68rem, 100% - 2rem);
  margin-inline: auto;
}

.site-header {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: 1rem;
  padding-block: 1rem;
}

.hero {
  max-width: 48rem;
  padding-block: 3rem;
}

h1 {
  font-size: clamp(2rem, 5vw, 3.5rem);
  line-height: 1.2;
}

.cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(16rem, 100%), 1fr));
  gap: 1rem;
}

.feature-card {
  padding: 1rem;
  border: 1px solid var(--line);
  border-radius: 0.75rem;
  background: var(--surface);
}

section {
  margin-block-end: 2rem;
}

button,
input {
  font: inherit;
}

button,
input {
  padding: 0.5rem 0.75rem;
}

:focus-visible {
  outline: 3px solid var(--link);
  outline-offset: 3px;
}

form {
  display: grid;
  max-width: 28rem;
  gap: 0.5rem;
}

stili.css — DISPOSIZIONE

Estratto del file · css
:root {
  color-scheme: light;
  --page: #f7f8fa;
  --surface: #ffffff;
  --text: #17212e;
  --link: #154ab5;
  --line: #bac4d0;
}

* {
  box-sizing: border-box;
}

body {
  margin: 0;
  background: var(--page);
  color: var(--text);
  font: 1rem/1.6 system-ui, sans-serif;
}

a {
  color: var(--link);
}

.site-header,
main,
footer {
  width: min(68rem, 100% - 2rem);
  margin-inline: auto;
}

.site-header {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: 1rem;
  padding-block: 1rem;
}

.hero {
  max-width: 52rem;
  padding-block: 3rem;
}

h1 {
  font-size: clamp(2rem, 5vw, 3.5rem);
  line-height: 1.2;
}

.cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(16rem, 100%), 1fr));
  gap: 1rem;
}

.feature-card {
  padding: 1rem;
  border: 1px solid var(--line);
  border-radius: 0.75rem;
  background: var(--surface);
}

section {
  margin-block-end: 2rem;
}

button,
input {
  font: inherit;
}

button,
input {
  padding: 0.5rem 0.75rem;
}

:focus-visible {
  outline: 3px solid var(--link);
  outline-offset: 3px;
}

form {
  display: grid;
  max-width: 28rem;
  gap: 0.5rem;
}

stili.css — DIRTY_LAYOUT

Estratto del file · css
:root {
  color-scheme: light;
  --page: #f7f8fa;
  --surface: #ffffff;
  --text: #17212e;
  --link: #154ab5;
  --line: #bac4d0;
}

* {
  box-sizing: border-box;
}

body {
  margin: 0;
  background: var(--page);
  color: var(--text);
  font: 1rem/1.6 system-ui, sans-serif;
}

a {
  color: var(--link);
}

.site-header,
main,
footer {
  width: min(68rem, 100% - 2rem);
  margin-inline: auto;
}

.site-header {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: 1rem;
  padding-block: 1rem;
}

.hero {
  max-width: 56rem;
  padding-block: 3rem;
}

h1 {
  font-size: clamp(2rem, 5vw, 3.5rem);
  line-height: 1.2;
}

.cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(16rem, 100%), 1fr));
  gap: 1rem;
}

.feature-card {
  padding: 1rem;
  border: 1px solid var(--line);
  border-radius: 0.75rem;
  background: var(--surface);
}

section {
  margin-block-end: 2rem;
}

button,
input {
  font: inherit;
}

button,
input {
  padding: 0.5rem 0.75rem;
}

:focus-visible {
  outline: 3px solid var(--link);
  outline-offset: 3px;
}

form {
  display: grid;
  max-width: 28rem;
  gap: 0.5rem;
}

README.md — ORPHAN_README

Uscita
# GitTree Features documentation

This branch contains a documentation-only history for the fictional course project.
The landing page remains on main; no form submits information to a server.
Keep useful detached experiments under a branch name before switching away.

local-review.txt — LOCAL_NOTE

Uscita
Local rehearsal note; preserve this file.

report/preview.txt — IGNORED_NOTE

Uscita
Ignored rehearsal preview; preserve these bytes.

Tra GitTree

Apri la tavolozza con Comando+Maiusc+P (Ctrl+Maiusc+P su Ubuntu).

  1. Nella prima copia, fai clic con il pulsante destro del mouse sul commit M nel grafico e scegli Check Out This Commit. Il selettore del ramo riporta "Distaccato a..." e il grafico mostra HEAD, detached.
  2. Salva LAYOUT come styles.css, metti in stage quel file e confermalo con il Riepilogo style: widen the hero reading measure. Il pannello conta il resto “a TESTA staccata” mentre si lavora.
  3. Fai clic con il pulsante destro del mouse sul nuovo commit e scegli Create Branch Here…. Chiamalo experiment/layout, lascia disattivata l'opzione di verificarlo e scegli Create Branch. L'avviso dice "Esperimento/layout creato". e HEAD è ancora staccato.
  4. Fai clic con il pulsante destro del mouse sull'etichetta experiment/layout e scegli Check Out Branch. HEAD è nuovamente collegato, styles.css è LAYOUT e main punta ancora a M.
  5. Dirty checkout. In un'altra copia, scollegati a experiment/layout, modifica styles.css in DIRTY_LAYOUT senza impegnarti e prova a controllare main. La finestra di dialogo "Le modifiche locali sono in mezzo al main" elenca il file e offre Commit First, Stash and Switch e Discard and Switch. Scegli Annulla; Lo scarto mantiene una copia sotto refs/ogt/trash ma non è necessario qui.
  6. Orphan. Nella seconda copia, con un albero di lavoro pulito, esegui Create Orphan Branch… dalla tavolozza. In "Creare un ramo orfano in...?" digitare orphan-docs. La finestra di dialogo indica quanti file tracciati lasciano la cartella di lavoro, quali file non tracciati e ignorati rimangono e che il vecchio commit viene mantenuto in refs/ogt/trash. Annulla ha il focus. Scegli Create Orphan Branch.
  7. L'avviso dice "Passato al nuovo ramo orfano orphan-docs. Annulla i passaggi indietro." La cartella non ha file tracciati e il grafico non mostra alcun commit sul nuovo ramo. Crea README.md da ORPHAN_README, mettilo in stage e confermalo con il Riepilogo docs: start the separate project guide. Il nuovo commit non ha genitore.
  8. Confronta: main ha ancora tutti i commit; il ramo orfano è una radice separata. Non spingere nessuna delle due copie.

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.

Nel terminale

Nella prima copia:

Command · bash
BASE_SHA="$(git rev-parse main)"
git switch --detach "$BASE_SHA"
git symbolic-ref --quiet --short HEAD; echo $?

L'ultimo comando stampa 1: HEAD non è un ramo. Salva LAYOUT come styles.css, quindi:

Command · bash
git commit --quiet -am "style: widen the hero reading measure"
git branch experiment/layout
git symbolic-ref --quiet --short HEAD; echo $?
git rev-parse HEAD^ main
git switch --quiet experiment/layout
git symbolic-ref --short HEAD
git status --short
Uscita
1
experiment/layout

Il comando di creazione non allega HEAD (la seconda query stampa ancora 1), i due ID di rev-parse sono uguali (M) e lo stato è vuoto. In un'altra copia staccata in experiment/layout, modifica styles.css ed esegui git switch main: Git rifiuta con "Le tue modifiche locali ai seguenti file verrebbero sovrascritte dal checkout" e il file non viene toccato.

Nella seconda copia, con un albero pulito:

Command · bash
git switch --orphan orphan-docs
git symbolic-ref --short HEAD
git rev-parse --verify --quiet HEAD; echo $?
git ls-files
Uscita
orphan-docs
1

Il ramo esiste ma non ha commit (rev-parse esce 1) e ls-files non stampa nulla. I file tracciati sono stati rimossi dalla cartella, mentre local-review.txt e reports/ rimangono e ora vengono visualizzati come non tracciati. Crea README.md, quindi:

Command · bash
git add -- README.md
git commit --quiet -m "docs: start the separate project guide"
git ls-tree -r --name-only HEAD
git rev-list --max-parents=0 --count HEAD
git merge-base --all main orphan-docs; echo $?
Uscita
README.md
1
1

Il nuovo ramo ha un commit root e nessun antenato comune con main (merge-base non stampa nulla ed esce 1).

Risultato

Where you end: il commit distaccato si chiama experiment/layout ed è stato estratto, main punta ancora a M e l'albero è pulito. La copia orfana ha orphan-docs con un commit root che non ha elemento principale, i vecchi file tracciati sono stati rimossi dalla cartella ma conservati da main e non è stato inviato nulla.

Errori comuni

  • Effettuare il commit su un HEAD distaccato e passare senza un ramo, il che lascia il commit raggiungibile solo tramite il reflog.
  • Previsto che Create Branch Here… passi al nuovo ramo.
  • Avviare un ramo orfano con modifiche rilevate non salvate o pensare che elimini main.
  • Supponendo che un file che è stato ignorato rimanga ignorato dopo che il suo .gitignore ha lasciato la cartella.

Se qualcosa va storto

Se hai lasciato un commit distaccato senza nome, apri il reflog (lezione 29) e inseriscici un ramo. Se un ramo orfano è stato un errore, Undo torna indietro mentre il nuovo ramo non ha commit; altrimenti controlla di nuovo main. Un checkout rifiutato non ha cambiato nulla.

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

    Cos'è una TESTA staccata?

    Scegli una risposta.

  2. Domanda 2 di 6

    Quali di queste sono vere riguardo ad un ramo orfano? (scelta multipla)

    Scegli ogni risposta applicabile.

  3. Domanda 3 di 6
    Obbligatorio

    Ti impegni su un HEAD distaccato, crei experiment/layout lì senza verificarlo e guardi HEAD. Che cos'è?

    Scegli una risposta.

  4. Domanda 4 di 6

    Modifica l'input: l'albero di lavoro ha una modifica non confermata su styles.css quando provi a estrarre main. Che succede?

    Scegli una risposta.

  5. Domanda 5 di 6
    Obbligatorio

    git ls-files non stampa nulla subito dopo git switch --orphan orphan-docs. C'è qualcosa che non va?

    Scegli una risposta.

  6. Domanda 6 di 6
    Obbligatorio

    Dopo il primo commit su orphan-docs, quali riletture mostrano che si tratta di una radice separata? (scelta multipla)

    Scegli ogni risposta applicabile.

0 di 6 corretto

Rispondi correttamente alle domande richieste per completare la lezione.

Controllato in questo browser.

Pratica

Riporta dove punta HEAD in ogni stato (ramo, distaccato, non nato), l'ID del commit distaccato e del ramo su di esso e cosa git ls-files è stampato sul ramo orfano. Quindi prevedere cosa succede a un file ignorato quando il .gitignore scompare.

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

  • Un commit distaccato necessita di un ramo per rimanere raggiungibile.
  • Un ramo orfano avvia una radice separata e rimuove i file tracciati dalla cartella.
  • Un check-out rifiutato protegge la tua modifica.

Termini del glossario introdotti

HEAD distaccato — HEAD منفصل; ramo orfano: فرع يتيم; ramo non ancora nato: فرع غير مولود; commit root — إيداع جذري.

Trascrizione video

La narrazione del video, spunto per spunto.

Mostra la trascrizione
  1. Dov'è la TESTA? Tre stati.
  2. HEAD può nominare un ramo, un commit o un file branch senza ancora alcun commit.
  3. Un impegno effettuato mentre si è distaccati è reale, ma niente lo nomina.
  4. Un ramo su quel commit lo mantiene raggiungibile.
  5. Fare clic con il pulsante destro del mouse sul commit M e scegliere Controlla Fuori questo impegno.
  6. Cambia il foglio di stile, mettilo in scena e impegnarsi una volta.
  7. Fare clic con il pulsante destro del mouse sul nuovo commit e creare un file ramo qui, senza verificarlo.
  8. Ora controlla la filiale. La TESTA è allegata di nuovo.
  9. Con una modifica non salvata, un checkout è rifiutato. Annulla mantiene tutto.
  10. Impegnati prima, metti da parte e cambia, o scartare. Lo scarto è quello da evitare.
  11. Per una nuova cronologia, esegui Crea orfano Ramo dalla tavolozza.
  12. Conta i file tracciati che lasciano. Quelli non tracciati e ignorati rimangono.
  13. Conferma. La cartella non contiene file tracciati.
  14. Aggiungi un file leggimi e conferma. Questo impegno ha nessun genitore.
  15. Nel terminale, simbolico-rif esce 1 quando La TESTA è staccata.
  16. Su un ramo non ancora nato, rev-parse di HEAD fallisce.
  17. Dopo il commit, merge-base non trova antenato comune.
  18. Se sei rimasto senza ramo, effettua il reflog ce l'ha ancora.
  19. Esercizio: nominare HEAD in ogni stato, quindi prevedere un file ignorato.
  20. Successivamente, recupera dagli errori dopo aver spinto.