1357 votes

Pourquoi y a-t-il deux façons de déstocker un fichier dans Git ?

Parfois, git suggère git rm --cached pour déstocker un fichier, parfois git reset HEAD file . Quand dois-je utiliser lequel ?

EDITAR:

D:\code\gt2>git init
Initialized empty Git repository in D:/code/gt2/.git/
D:\code\gt2>touch a

D:\code\gt2>git status
# On branch master
#
# Initial commit
#
# Untracked files:
#   (use "git add <file>..." to include in what will be committed)
#
#       a
nothing added to commit but untracked files present (use "git add" to track)

D:\code\gt2>git add a

D:\code\gt2>git status
# On branch master
#
# Initial commit
#
# Changes to be committed:
#   (use "git rm --cached <file>..." to unstage)
#
#       new file:   a
#
D:\code\gt2>git commit -m a
[master (root-commit) c271e05] a
 0 files changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 a

D:\code\gt2>touch b

D:\code\gt2>git status
# On branch master
# Untracked files:
#   (use "git add <file>..." to include in what will be committed)
#
#       b
nothing added to commit but untracked files present (use "git add" to track)

D:\code\gt2>git add b

D:\code\gt2>git status
# On branch master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#       new file:   b
#

22 votes

Pourquoi ? Je dirais que c'est parce que l'interface en ligne de commande de git a évolué de manière organique et n'a jamais été soumise à une restructuration majeure pour rendre les choses cohérentes. (Si vous n'êtes pas d'accord, notez comment git rm peut à la fois scène a suppression et aussi déstabiliser un ajout )

5 votes

@romkyns : Je suis d'accord que l'interface de Git a plusieurs bizarreries parce qu'elle a évolué organiquement, mais une suppression est sûrement une fonction inverse d'une addition, donc n'est-il pas logique que rm pour défaire add ? Comment pensez-vous rm devrait se comporter ?

10 votes

La seule réponse réelle à votre question est que juste après un git init il n'y a pas HEAD à réinitialiser.

2177voto

Ryan Stewart Points 46960

git rm --cached <filePath> ne se déstabilise pas un fichier, il s'agit en fait met en scène la suppression du ou des dossiers du repo (en supposant qu'il était déjà livré auparavant) mais laisse le fichier dans votre arbre de travail (vous laissant avec un fichier non suivi).

git reset -- <filePath> se déstabiliser toutes les modifications échelonnées pour le(s) fichier(s) donné(s).

Cela dit, si vous avez utilisé git rm --cached sur un nouveau fichier qui est mis à disposition, il semblerait que vous venez de le déstocker puisqu'il n'a jamais été livré auparavant.

Mise à jour de git 2.24
Dans cette nouvelle version de git, vous pouvez utiliser git restore --staged au lieu de git reset . Voir docs git .

80 votes

Je dirais git rm --cached déstocke le fichier mais ne le supprime pas du répertoire de travail.

0 votes

C'est un peu comme cvs rm pour annuler localement cvs add encore une fois.

5 votes

La suppression d'un fichier mis à disposition pour l'ajout de manière à ce qu'il ne soit plus mis à disposition peut certainement être appelée "déstockage d'un fichier mis à disposition pour l'ajout", n'est-ce pas ? Le résultat final est pas une suppression par étapes c'est certain, donc je pense que le malentendu est totalement compréhensible.

347voto

manojlds Points 96599

git rm --cached est utilisé pour supprimer un fichier de l'index. Dans le cas où le fichier est déjà dans le repo, git rm --cached supprimera le fichier de l'index, le laissant dans le répertoire de travail et un commit le supprimera également du repo. En fait, après la livraison, vous auriez déprogrammé le fichier et conservé une copie locale.

git reset HEAD file ( qui par défaut utilise le --mixed ) est différent dans la mesure où, dans le cas où le fichier est déjà dans le repo, il remplace la version indexée du fichier par celle du repo (HEAD), ce qui a pour effet de déstocker l'élément modifications à ce sujet.

Dans le cas d'un fichier non versionné, il va déstocker le fichier entier car le fichier n'était pas présent dans le HEAD. Dans cet aspect git reset HEAD file y git rm --cached sont identiques, mais ils ne sont pas identiques ( comme expliqué dans le cas des fichiers déjà dans le repo)

A la question de Why are there 2 ways to unstage a file in git? - il n'y a jamais vraiment qu'une seule façon de faire quelque chose dans git. c'est ce qui fait sa beauté :)

8 votes

La réponse acceptée et celle-ci sont toutes deux excellentes, et expliquent pourquoi vous utilisez l'une plutôt que l'autre. Mais elles ne répondent pas directement à la question implicite suivante pourquoi est-ce que git suggère deux méthodes différentes. Dans le premier cas de l'exemple de l'OP, un git init vient d'être effectué. Dans ce cas, git suggère "git rm --cached" parce qu'à ce moment-là il n'y a pas de commits dans le dépôt et donc HEAD n'est pas valide. "git reset HEAD -- a" produit : "fatal : Failed to resolve 'HEAD' as a valid ref".

5 votes

Avec 'git checkout', ne perdriez-vous pas toutes les modifications que vous avez apportées au fichier ? Ce n'est pas la même chose que de déstocker un fichier, à moins que je ne comprenne mal.

1 votes

there is never really only one way to do anything in git. that is the beauty of it - Hmm... pourquoi ? c'est toujours génial, quand il n'y a qu'un seul moyen évident. cela nous fait gagner beaucoup de temps et de mémoire dans le cerveau ;))

140voto

waldir Points 371

Tout simplement :

  • git rm --cached <file> permet à git d'arrêter complètement le suivi du fichier (en le laissant dans le système de fichiers, contrairement à un simple git rm *)
  • git reset HEAD <file> annule toutes les modifications apportées au fichier depuis la dernière livraison. (mais ne les rétablit pas dans le système de fichiers, contrairement à ce que le nom de la commande pourrait suggérer**). Le fichier reste sous contrôle de révision.

Si le fichier n'était pas dans le contrôle de révision avant (c'est-à-dire que vous déstockez un fichier que vous venez juste d'ajouter à votre liste de contrôle de révision), il est possible que le fichier ne soit pas dans le contrôle de révision. git add pour la première fois), alors les deux commandes ont le même effet, d'où l'apparence de "deux façons de faire quelque chose".

* Gardez à l'esprit la réserve que @DrewT mentionne dans sa réponse, concernant <code>git rm --cached</code> d'un fichier qui a été <em>précédemment engagé </em>au référentiel. Dans le contexte de cette question, d'un fichier qui vient d'être ajouté et qui n'a pas encore été livré, il n'y a pas lieu de s'inquiéter.

** Pendant longtemps, j'ai eu peur d'utiliser la commande git reset à cause de son nom - et encore aujourd'hui, je regarde souvent la syntaxe pour être sûr de ne pas me planter. ( <strong>mise à jour </strong>: J'ai finalement pris le temps de <a href="https://github.com/tldr-pages/tldr/blob/master/pages/common/git-reset.md" rel="noreferrer">résumer l'utilisation de <code>git reset</code> dans une page tldr </a>Ainsi, j'ai maintenant un meilleur modèle mental de son fonctionnement et une référence rapide lorsque j'oublie un détail).

0 votes

C'est git rm <file> --cached

11 votes

Je ne pense vraiment pas que le édition du 4 août 2015 à cette réponse était une amélioration globale. Elle a peut-être corrigé l'exactitude technique (je ne me sens pas qualifié pour évaluer cela), mais j'ai peur qu'elle ait rendu le ton de la réponse beaucoup moins accessible, en introduisant un langage comme "unsets the imperative to begin tracking a currently-untracked file", et en utilisant un jargon comme "index" et "HEAD", précisément le genre de choses qui effraient les débutants. Si quelqu'un le peut, merci de l'éditer pour rétablir un langage plus convivial pour les nouveaux venus.

8 votes

D'accord avec @waldyrious. La réponse originale ne sortait peut-être pas directement du manuel git, mais elle répondait à la question à un niveau technique suffisant. Les détails techniques auraient dû être clarifiés dans les commentaires, pas sous la forme d'une modification qui obscurcit l'intention initiale.

59voto

Daniel Alder Points 425

Ce fil de discussion est un peu vieux, mais je veux quand même ajouter une petite démonstration car ce n'est toujours pas un problème intuitif :

me$ git status
# On branch master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#   new file:   to-be-added
#   modified:   to-be-modified
#   deleted:    to-be-removed
#

me$ git reset -q HEAD to-be-added

    # ok

me$ git reset -q HEAD to-be-modified

    # ok

me$ git reset -q HEAD to-be-removed

    # ok

# or alternatively:

me$ git reset -q HEAD to-be-added to-be-removed to-be-modified

    # ok

me$ git status
# On branch master
# Changes not staged for commit:
#   (use "git add/rm <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
#   modified:   to-be-modified
#   deleted:    to-be-removed
#
# Untracked files:
#   (use "git add <file>..." to include in what will be committed)
#
#   to-be-added
no changes added to commit (use "git add" and/or "git commit -a")

git reset HEAD (sans -q ) donne un avertissement sur le fichier modifié et son code de sortie est 1 qui sera considéré comme une erreur dans un script.

Edit : git checkout HEAD to-be-modified to-be-removed fonctionne également pour le déstockage, mais supprime complètement le changement de l'espace de travail.

Mise à jour de git 2.23.0 : De temps en temps, les commandes changent. Maintenant, git status dit :

  (use "git restore --staged <file>..." to unstage)

... qui fonctionne pour les trois types de changement.

0 votes

Merci, ce n'était pas tout à fait clair dans les deux premières réponses (probablement juste mon ignorance de la terminologie) que git reset laissait les modifications dans le fichier localement (par opposition à git checkout qui les rétablirait).

0 votes

Vous devriez mettre un avertissement au début sur la version, parce que l'ancienne version supprime les fichiers dans les nouvelles versions.

0 votes

@DanielAlder sry, je viens de re-tester, il ne supprime pas, mon erreur.

16voto

DrewT Points 527

Ces 2 commandes ont plusieurs différences subtiles si le fichier en question est déjà dans le repo et sous contrôle de version (précédemment commis etc.) :

  • git reset HEAD <file> déstocke le fichier dans le commit actuel.
  • git rm --cached <file> va déstocker le fichier pour les futurs commits également. Il n'est pas indexé jusqu'à ce qu'il soit ajouté à nouveau avec la commande git add <file> .

Et il y a une autre différence importante :

  • Après avoir exécuté git rm --cached <file> et pousser votre branche vers le distant, toute personne tirant votre branche depuis le distant obtiendra le fichier ACTUELLEMENT supprimé de son dossier, même si, dans votre environnement de travail local, le fichier devient simplement non suivi (c'est-à-dire qu'il n'est pas physiquement supprimé du dossier).

Cette dernière différence est importante pour les projets qui incluent un fichier de configuration où chaque développeur de l'équipe a une configuration différente (c'est-à-dire une url de base, une ip ou un port différents). git rm --cached <file> toute personne qui tire votre branche devra recréer manuellement la configuration, ou vous pouvez leur envoyer la vôtre et ils pourront la rééditer avec leurs paramètres d'ip (etc.), car la suppression n'affecte que les personnes tirant votre branche à distance.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X