Restore : défaire le travail en cours

Par Maxime Bréhin • Publié le 25 février 2025 • 4 min

Ajoutée en 2019 à Git, cette commande effectue une partie des actions auparavant réalisée avec la commande reset. L’emploi à l’époque de reset créait beaucoup de confusion sur son rôle et nuisait à la compréhension de son large spectre d’application.

Le but de restore est de fournir une commande dont l’usage est plus précis et limité tout en apportant un vocabulaire plus compréhensible, à savoir “restaurer” l’état de certains fichiers. Dans le même temps, il permet de cantonner la commande reset à un rôle plus clair de déplacement de HEAD.

On trouve deux cas principaux d’application à cette commande :

  1. l’annulation de modificiations en cours dans la copie de travail ;
  2. le retrait de modifications ajoutées au stage / à l’index.

Voyons tout cela dans le détail.

Annuler les modifications en cours dans la copie de travail

Le premier usage qu’offre restore est la capacité à annuler le travail en cours. En gros, on vient de faire des modifications dans un ou plusieurs fichiers et on souhaite revenir à la dernière version connue par Git d’un ou plusieurs fichiers (on peut choisir juste certains fichiers).

flowchart LR
  A["fichier (v0)"] -->|modifs| B["fichier (v1)"]
    B -->|restore| A

Il s’agit de l’appel à la commande sans option (ou avec l’option par défaut --worktree) à laquelle on passe des chemins :

git restore <chemin-1> <chemin-2>

On pourrait croire que la dernière version connue correspond au dernier commit (celle du dépôt local) mais, même si c’est souvent ce résultat qu’on obtiendra, la réalité est qu’il s’agit de la dernière version ajoutée au stage.

sequenceDiagram
  participant A as Working directory
  participant B as Stage
  participant C as Local repository
  B->>A: applique l’état dans la copie de travail

Ça signifie que si on a ajouté des choses au stage avant notre modification, la commande restore va récupérer la version stagée pour l’appliquer dans notre espace de travail. On voit avec l’exemple ci-après :

  • un fichier est modifié donnant lieu à une version v0
  • cette version est ajoutée au stage (le stage stocke v0) ;
  • ce même fichier est à nouveau modifié, donnant une version v1 ;
  • l’exécution de la commande restore écrase v1 avec v0 prise depuis le stage.
stateDiagram
  direction TB

  A: fichier (v0)
  Astaged: fichier (v0)
  B: fichier (v1)
  C: fichier (v0)

  state WorkingDirectory {
    A
    B
    C

    [*] --> A : 1 - modifs
    A --> B : 3 - modifs
    B --> C
  }
  state Stage {
    Astaged
  }
  A --> Stage : 2 - ajout au stage
  Stage --> C : 4 - restore

Ceci revient donc à un appel unique à restore :

git restore fichier

Attention, le travail annulé n’est pas récupérable

Contrairement au second cas d’utilisation de restore, on la demande d’annulation écrase nos modifications courantes sans possibilité de les retrouver (sauf éventuel Ctrl + z dans votre éditeur s’il par chance il est resté ouvert).

Retirer les ajouts au stage

Ce second usage de restore vise à annuler ce qu’on aurait ajouté via un git add … au stage en prévision du prochain commit. On souhaite donc éviter d’embarquer certaines modifications dans le prochain commit sans toutefois annuler complètement notre travail. On veut donc le garder dans notre copie de travail.

On va alors appeler la commande avec l’option --staged :

git restore --staged <chemin-1> <chemin-2>

On peut voir ça comme une commande unstage (qui n’existe pas, mais libre à toi de créer un alias 😉).

Git va alors récupérer la dernière version commitée des fichiers désignés et appliquer celles-ci au stage (une sorte de git add depuis le dépôt local) :

sequenceDiagram
  participant A as Working directory
  participant B as Stage
  participant C as Local repository
  C->>B: applique l’état dans le stage

En aucun cas Git ne touchera à la copie de travail (working directory dans le schéma). Pas d’inquiétude de perdre du travail.

Emploi mixte

On peut souhaiter annuler certaines modifications dans les deux zones, le stage et la copie de travail. Il suffit alors de combiner les options, en exploitant explicitement l’option par défaut --worktree :

git restore --worktree --staged <chemin-1> <chemin-2>
sequenceDiagram
  participant A as Working directory
  participant B as Stage
  participant C as Local repository
  C->>B: applique l’état dans le stage…
  B->>A: …et la copie de travail

Dans le cas d’une annulation de toutes les modifications en cours, certain·e·s préféreront la méthode “à l’ancienne” du git reset --hard. Attention toutefois à comprendre ce qui se passe avec la commande reset car là aussi on perd l’intégralité du travail en cours.

Vérifier avant et après

Ça semble probablement logique, mais je préfère le préciser : idéalement, on vérifie avant l’opération de restore et après. D’ailleurs, la commande git status à laquelle je pense ici, a le bénéfice de fournir des indications dans le terminal sur l’emploi de la commande restore selon le contexte :

> git status

On branch article/restore

Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
  …

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
Vous voulez aller plus loin et maîtriser pleinement les fondamentaux de Git ou être accompagné pour garantir la qualité de vos projets grâce à une bonne mise en place de Git ? On peut vous aider ou vous former, il suffit de nous décrire votre besoin !
Vous pouvez aussi regarder le programme de notre formation "Comprendre Git" ou nous poser vos questions sur notre forum discord.