Leçon 31 · Récupération
Gardez le travail détaché et commencez une histoire orpheline
Nommez un commit effectué sur un HEAD détaché avant de le quitter, puis démarrez une branche orpheline dans une copie séparée et voyez ce qu'elle supprime et ce qu'elle conserve.
- Niveau: Intermédiaire
- 11 minutes de lecture
- 5 minutes de vidéo
- Mis à jour
- Avant cette leçon: Créez une branche de fonctionnalités et retirez uniquement la référence jetable, Trouver un commit perdu avec reflog
Progression enregistrée dans ce navigateur.
La lecture charge la vidéo depuis YouTube (mode de confidentialité amélioré).
Ce que vous apprendrez
- Dites les TÊTES attachées, détachées et à naître.
- Mettez une branche sur un commit détaché pour qu'il reste accessible.
- Prédisez ce qu'une branche orpheline fait aux fichiers suivis, aux fichiers non suivis et à l'ancienne branche.
- Lire un refus de paiement causé par des changements locaux.
Avant de commencer
Deux copies jetables du résultat M de la leçon 18. Dans la première, vous extrayez le commit M lui-même au lieu de la branche, vous y apportez une petite modification de la feuille de style et souhaitez la conserver. Dans la seconde, vous souhaitez un tout nouvel historique sans rapport pour une branche de documentation uniquement sans toucher à main.
Tout est local et sur le forfait gratuit (GitTree vous demande de vous connecter) : pas de compte d'hébergement, pas de fournisseur, pas d'Internet. Chaque identité est fictive (exemple.com). N'exécutez jamais cette leçon dans un projet réel.
Apportez les modifications dans GitTree ou avec les commandes Git natives, pas les deux dans la même copie. La lecture du résultat est toujours sûre. Les étiquettes de menu proviennent des propres chaînes de GitTree 2.0 et les commandes natives ont été exécutées avec Git 2.43 dans des copies jetables. Les étapes GitTree n'ont pas été exécutées le macOS, Windows ou Linux.
Effets de concept et d'état
HEAD nomme normalement une branche et la validation déplace cette branche. Lorsque HEAD nomme directement un commit, il s'agit de detached : un nouveau commit est réel, mais rien ne le nomme, donc le fait de s'en éloigner le laisse accessible uniquement via le reflog. Mettre une branche dessus résout ce problème. La création d'une branche ne permet pas d'y accéder, sauf si vous le souhaitez.
Une branche orphan est différente. HEAD nomme une branche qui n'a pas encore été validée (une branche à naître). Son premier commit n'a pas de parent, il ne partage donc aucun historique avec main. Git supprime les fichiers suivis du dossier de travail ; les fichiers non suivis et ignorés restent. Si l'ancien .gitignore était suivi, ses règles l'accompagnent et les fichiers qu'il ignorait peuvent désormais s'afficher comme non suivis. Votre ancienne branche conserve chaque commit.
Les deux états sont normaux, pas de dommages. Une extraction est refusée lorsqu'elle écraserait les modifications locales ; rien n'est perdu.
Préparer l’état exact du projet
Commencez par deux copies ordinaires distinctes du résultat de la leçon 18 et laissez votre original intact. Les corps ci-dessous sont la feuille de style de base (BASE_CSS), la feuille élargie (LAYOUT), une modification modifiée (DIRTY_LAYOUT), le fichier readme orphelin (ORPHAN_README), une note locale (LOCAL_NOTE) et une note ignorée (IGNORED_NOTE).
Entrées de fichiers complètes
Enregistrez chaque corps UTF-8/LF complet uniquement dans sa phase indiquée, avec une nouvelle ligne finale et sans clôtures Markdown. BASE_CSS est la référence 48rem héritée ; LAYOUT est le commit 52rem ; DIRTY_LAYOUT est une rediffusion distincte de 56rem non mise en scène. Les deux fichiers de notes appartiennent uniquement à la variante survivant. Les fichiers principaux inchangés héritent de l'entrée complète L018/M.
styles.css — BASE_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;
}styles.css — MISE EN PAGE
: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;
}styles.css — DIRTY_LAYOUT
: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
# 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
Local rehearsal note; preserve this file.rapports/preview.txt — IGNORED_NOTE
Ignored rehearsal preview; preserve these bytes.Dans GitTree
Ouvrez la palette avec Commande+Maj+P (Ctrl+Maj+P sur Ubuntu).
- Dans la première copie, cliquez avec le bouton droit sur le commit M dans le graphique et choisissez Check Out This Commit. Le sélecteur de branche indique « Détaché à… » et le graphique affiche HEAD, detached.
- Enregistrez LAYOUT sous
styles.css, préparez ce fichier et validez-le avec le résuméstyle: widen the hero reading measure. Le panneau compte le changement "sur une TÊTE détachée" pendant que vous travaillez. - Cliquez avec le bouton droit sur le nouveau commit et choisissez Create Branch Here…. Nommez-le
experiment/layout, laissez l'option d'extraction désactivée et choisissez Create Branch. L'avis indique "Expérience/mise en page créée". et HEAD est toujours détaché. - Cliquez avec le bouton droit sur l'étiquette
experiment/layoutet choisissez Check Out Branch. HEAD est à nouveau attaché,styles.cssest LAYOUT etmainpointe toujours vers M. - Dirty checkout. Dans une autre copie, détachez-la à
experiment/layout, modifiezstyles.cssen DIRTY_LAYOUT sans vous engager et essayez de consultermain. La boîte de dialogue "Les modifications locales gênent le principal" répertorie le fichier et propose Commit First, Stash and Switch et Discard and Switch. Choisissez Annuler ; la suppression conserve une copie sousrefs/ogt/trashmais n'est pas nécessaire ici. - Orphan. Dans la deuxième copie, avec un arbre de travail propre, exécutez Create Orphan Branch… depuis la palette. Dans « Créer une branche orpheline dans… ? » tapez
orphan-docs. La boîte de dialogue indique combien de fichiers suivis quittent le dossier de travail, quels fichiers non suivis et ignorés restent et que l'ancien commit est conservé sousrefs/ogt/trash. Annuler a le focus. Choisissez Create Orphan Branch. - L'avis indique "Basculé vers la nouvelle branche orpheline orphelin-docs. Annuler revient en arrière." Le dossier ne contient aucun fichier suivi et le graphique ne montre aucune validation sur la nouvelle branche. Créez
README.mdà partir de ORPHAN_README, mettez-le en scène et validez-le avec le résumédocs: start the separate project guide. Le nouveau commit n'a pas de parent. - Comparez :
maina toujours chaque commit ; la branche orpheline est une racine distincte. Ne poussez aucune des deux copies.
Pour chaque commit ordinaire du cours : Summary est le sujet indiqué, Description est vide et les options Amend Previous Commit, Skip Hooks, Add Signed-off-by, Different Author, Push After Commit et Allow Empty Commit restent désactivées.
Dans la borne
Dans le premier exemplaire :
BASE_SHA="$(git rev-parse main)"
git switch --detach "$BASE_SHA"
git symbolic-ref --quiet --short HEAD; echo $?La dernière commande affiche 1 : HEAD n'est pas une branche. Enregistrez LAYOUT sous styles.css, puis :
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 --short1
experiment/layoutLa commande de création n'attache pas HEAD (la deuxième requête imprime toujours 1), les deux identifiants de rev-parse sont égaux (M) et le statut est vide. Dans une autre copie détachée chez experiment/layout, modifiez styles.css et exécutez git switch main : Git refuse avec "Vos modifications locales apportées aux fichiers suivants seraient écrasées par l'extraction" et le fichier n'est pas modifié.
Dans le deuxième exemplaire, avec un arbre propre :
git switch --orphan orphan-docs
git symbolic-ref --short HEAD
git rev-parse --verify --quiet HEAD; echo $?
git ls-filesorphan-docs
1La branche existe mais n'a pas de validation (rev-parse quitte 1) et ls-files n'imprime rien. Les fichiers suivis ont disparu du dossier, tandis que local-review.txt et reports/ restent et s'affichent désormais comme non suivis. Créez README.md, puis :
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 $?README.md
1
1La nouvelle branche a un commit racine et aucun ancêtre commun avec main (merge-base n'imprime rien et quitte 1).
Résultat
Where you end: le commit détaché est nommé experiment/layout et extrait, main pointe toujours sur M et l'arborescence est propre. La copie orpheline a orphan-docs avec une validation racine qui n'a pas de parent, les anciens fichiers suivis ont disparu du dossier mais conservés par main, et rien n'a été poussé.
Erreurs courantes
- S'engager sur un HEAD détaché et s'éloigner sans branche, ce qui laisse le commit accessible uniquement via le reflog.
- Je m'attends à ce que
Create Branch Here…passe à la nouvelle branche. - Démarrer une branche orpheline avec des modifications suivies non validées ou penser qu'elle supprime
main. - En supposant qu'un fichier ignoré reste ignoré après que son
.gitignorequitte le dossier.
Si quelque chose ne va pas
Si vous avez laissé un commit détaché sans nom, ouvrez le reflog (leçon 29) et mettez-y une branche. Si une branche orpheline était une erreur, Undo revient en arrière alors que la nouvelle branche n'a pas de validation ; sinon, consultez à nouveau main. Un paiement refusé n'a rien changé.
Vérifiez votre compréhension
Répondez à chaque question, puis lisez pourquoi. Les questions marquées « Obligatoire » comptent pour terminer la leçon.
0 sur 6 corrects
Répondez correctement aux questions requises pour terminer la leçon.
Vérifié dans ce navigateur.
Pratique
Indiquez où pointe HEAD dans chaque état (branche, détaché, à naître), l'ID du commit détaché et de la branche dessus, et ce que git ls-files a imprimé sur la branche orpheline. Prédisez ensuite ce qui arrive à un fichier ignoré lorsque le .gitignore disparaît.
Votre propre confirmation : le site ne peut pas voir votre ordinateur.
Pour terminer la leçon, répondez correctement aux questions demandées et confirmez l'exercice pratique.
Récapitulatif
- Un commit détaché a besoin d’une branche pour rester accessible.
- Une branche orpheline démarre une racine distincte et supprime les fichiers suivis du dossier.
- Un paiement refusé protège votre modification.
En rapport
Termes du glossaire introduits
TÊTE détachée — TÊTE منفصل; branche orpheline — فرع يتيم; branche à naître — فرع غير مولود ; root commit — c'est vrai.
Transcription vidéo
La narration de la vidéo, repère par repère.
Afficher la transcription
- Où est la TÊTE ? Trois états.
- HEAD peut nommer une branche, un commit ou un branche sans commit pour le moment.
- Un engagement effectué en étant détaché est réel, mais rien ne le nomme.
- Une branche sur ce commit le conserve accessible.
- Cliquez avec le bouton droit sur le commit M et choisissez Vérifier Hors de cet engagement.
- Modifiez la feuille de style, mettez-la en scène et commettre une fois.
- Cliquez avec le bouton droit sur le nouveau commit et créez un succursale ici, sans la vérifier.
- Maintenant, vérifiez la succursale. La TÊTE est attachée encore une fois.
- Avec une modification non enregistrée, une extraction est refusé. Annuler conserve tout.
- Engagez-vous d'abord, cachez et changez, ou jeter. Le rejet est celui à éviter.
- Pour un nouvel historique, exécutez Create Orphan Branche de la palette.
- Il compte les fichiers suivis qui partent. Ceux qui ne sont pas suivis et ignorés restent.
- Confirmer. Le dossier ne contient aucun fichier suivi.
- Ajoutez un fichier Lisez-moi et validez. Ce commit a pas de parent.
- Dans le terminal, la référence symbolique quitte 1 lorsque La TÊTE est détachée.
- Sur une branche à naître, réanalysez HEAD échoue.
- Après la validation, merge-base ne trouve aucun ancêtre commun.
- Si tu es parti sans branche, le reflog l'a toujours.
- Pratique : nommez HEAD dans chaque état, puis prédire un fichier ignoré.
- Ensuite, récupérez des erreurs après avoir poussé.