Pourquoi git ne peut pas effectuer de réinitialisations matérielles / logicielles par chemin?

138

$ git reset -- <file_path> peut réinitialiser par chemin.

Cependant, $ git reset (--hard|--soft) <file_path>signalera une erreur comme ci-dessous:

Cannot do hard|soft reset with paths.
yao
la source

Réponses:

143

Parce que cela ne sert à rien (d'autres commandes fournissent déjà cette fonctionnalité), et cela réduit le risque de faire la mauvaise chose par accident.

Un "hard reset" pour un chemin est juste fait avec git checkout HEAD -- <path>(vérification de la version existante du fichier).

Une réinitialisation logicielle pour un chemin n'a pas de sens.

Une réinitialisation mixte pour un chemin est ce que git reset -- <path>fait.

ambre
la source
72
Personnellement, je pense qu'il git checkout -- <path>devrait être remplacé par git reset --hard <path>. Ça a tellement plus de sens ...
vergenzt
24
git checkout -- <path>ne fait pas de réinitialisation matérielle; il remplace le contenu de l'arborescence de travail par le contenu mis en scène. git checkout HEAD -- <path>effectue une réinitialisation matérielle pour un chemin, en remplaçant à la fois l'index et l'arborescence de travail par la version du commit HEAD.
Dan Fabulich
1
@EdPlunkett Er, la deuxième phrase de la réponse vous indique quelle autre commande fournit la fonctionnalité.
Ambre
16
-1: l'extraction de ladite révision ne supprimera pas les fichiers de la copie de travail si ladite révision contient des fichiers supprimés. reset --hardavec un chemin fournirait cette pièce manquante. Git est déjà si puissant que l'excuse "Nous ne vous laissons pas faire cela pour votre propre protection" ne contient aucune eau: il existe de nombreuses façons de faire la mauvaise chose "par accident". Rien de tout cela n'a d'importance de toute façon quand vous en avez git reflog.
void.pointer
1
comme mentionné par @ void.pointer checkout ne supprimera pas les fichiers. Si vous voulez ce comportement, regardez cette réponse. Pourtant, j'espère qu'un jour nous y arriverons git reset --hard -- <path>. Il existe des cas d'utilisation légitimes pour cela.
Mariusz Pawelski
18

Vous pouvez accomplir ce que vous essayez de faire en utilisant git checkout HEAD <path>.

Cela dit, le message d'erreur fourni n'a aucun sens pour moi (car git resetfonctionne très bien sur les sous-répertoires), et je ne vois aucune raison pour laquelle git reset --hardne devrait pas faire exactement ce que vous lui demandez.

Aaron Kent
la source
l'utilisation de la vérification met en scène les modifications, ce qui n'est pas la même chose qu'une réinitialisation --soft
worc
11

La question comment est déjà répondu , je vais expliquer la partie pourquoi .

Alors, que fait git reset ? Selon les paramètres spécifiés, il peut faire deux choses différentes:

  • Si vous spécifiez un chemin, il remplace les fichiers correspondants dans l'index par les fichiers d'un commit (HEAD par défaut). Cette action n'affecte pas du tout l'arbre de travail et est généralement utilisée comme l'opposé de git add.

  • Si vous ne spécifiez pas de chemin, il déplace la tête de branche actuelle vers un commit spécifié et, avec cela , réinitialise éventuellement l'index et l'arborescence de travail à l'état de ce commit. Ce comportement supplémentaire est contrôlé par le paramètre mode:
    --soft : ne touchez pas l'index et l'arbre de travail.
    --mixed (par défaut): réinitialise l'index mais pas l'arborescence de travail.
    --hard : réinitialise l'index et l'arbre de travail.
    Il existe également d'autres options, voir la documentation pour la liste complète et quelques cas d'utilisation.

    Lorsque vous ne spécifiez pas de validation, la valeur par défaut est HEAD, donc git reset --softne fera rien, car il s'agit d'une commande pour déplacer la tête vers HEAD (à son état actuel). git reset --hard, d'autre part, a du sens en raison de ses effets secondaires , il dit de déplacer la tête vers HEAD et de réinitialiser l'index et l'arbre de travail sur HEAD.

    Je pense qu'il devrait être clair maintenant pourquoi cette opération n'est pas destinée à des fichiers spécifiques de par sa nature - elle est destinée à déplacer une tête de branche en premier lieu, en réinitialisant l'arbre de travail et l'index est une fonctionnalité secondaire.

utilisateur
la source
il est clair que la réinitialisation est destinée à déplacer une tête de branche en premier lieu, mais comme elle a la fonctionnalité supplémentaire de réinitialiser l'arbre de travail et l'index pour des validations entières et la fonctionnalité de réinitialiser l'index pour des fichiers spécifiques, pourquoi ne le fait-il pas avez la fonctionnalité de réinitialisation de l'arborescence de travail pour des fichiers spécifiques? Je pense que c'est ce que demande le PO.
Danilo Souza Morães
Peut-être parce que cette fonctionnalité (réinitialisation de l'arborescence de travail pour des fichiers spécifiques) est déjà disponible en tant que git checkoutcommande? Et faire une réinitialisation pour faire la même chose dérouterait davantage les utilisateurs. Ma réponse a été que l' --hardoption n'est pas applicable à des fichiers spécifiques car il s'agit d'un mode de réinitialisation de branche, pas de réinitialisation d'index. Et la réinitialisation de l'arbre de travail s'appelle checkout, comme vous pouvez le lire dans d'autres réponses. Tout cela n'est qu'une mauvaise conception de l'interface utilisateur de Git, à mon humble avis.
utilisateur
Comparer la première option à git checkout: git reset --définit uniquement l'index, tandis que git checkout --définit uniquement l'arborescence de travail?
seeker_of_bacon
4

Assurez-vous de mettre une barre oblique entre l'origine ou l'amont (source) et la branche réelle:

git reset --hard origin/branch

ou

git reset --hard upstream/branch`
Pascal Nitcheu
la source
Veuillez relire la question.
Xerus
3

Il y a une raison très importante derrière cela: les principes de checkoutetreset .

En termes Git, checkout signifie "intégrer l'arborescence de travail actuelle". Et avec, git checkoutnous pouvons remplir l'arborescence de travail avec des données de n'importe quelle zone, qu'il s'agisse d'un commit dans le référentiel ou de fichiers individuels d'un commit ou de la zone de préparation (qui est même la valeur par défaut).

À son tour, git reset n'a pas ce rôle. Comme son nom l'indique, il réinitialisera la référence actuelle mais en ayant toujours le référentiel comme source, indépendamment du "reach" (--soft, --mixed ou --hard).

Résumer:

  • checkout : De n'importe où (index / repo commit) -> arbre de travail
  • reset : commit Repo -> Overwrite HEAD (et éventuellement index et arbre de travail)

Par conséquent, ce qui peut être un peu déroutant, c'est l'existence de git reset COMMIT -- filescar "écraser HEAD" avec seulement quelques fichiers n'a pas de sens!

En l'absence d'explication officielle, je ne peux que spéculer que les développeurs git ont trouvé que resetc'était toujours le meilleur nom d'une commande pour annuler les modifications apportées à la zone de préparation et, étant donné que la seule source de données était le référentiel, alors " étendons le fonctionnalité »au lieu de créer une nouvelle commande.

C'est donc git reset -- <files>déjà un peu exceptionnel: il n'écrasera pas la HEAD. IMHO toutes ces variations seraient des exceptions. Même si nous pouvons concevoir une --hardversion, d'autres (par exemple --soft) n'auraient pas de sens.

F Pereira
la source
J'aime cette réponse. Vraiment, git reset -- <files>tombé comme si elle avait été ajoutée car c'est une fonctionnalité utile, mais personne ne savait dans quelle commande elle devait être placée. Heureusement, nous avons maintenant beaucoup plus sains d'esprit git restorequi ont des fonctionnalités git checkout -- <path> git checkout <commit> -- <path>et des git reset [<commit>] -- <path>valeurs par défaut beaucoup plus saines et encore plus de fonctionnalités que vous ne pouviez pas faire auparavant (contrairement à ce que dit la réponse acceptée. Maintenant, vous pouvez enfin restaurer facilement l'arbre de travail, sans toucher à l'index).
Mariusz Pawelski
0

Explication

Le git resetmanuel répertorie 3 modes d'appel:

  • 2 sont au niveau des fichiers: ils n'affectent pas l'arborescence de travail , mais fonctionnent uniquement sur les fichiers de l'index spécifié par <paths>:

    • git reset [-q] [<tree-ish>] [--] <paths>..
    • git reset (--patch | -p) [<tree-ish>] [--] [<paths>...]
  • 1 est commise: fonctionne sur tous les fichiers référencés <commit>et peut affecter l'arborescence de travail:

    • git reset [<mode>] [<commit>]

Il n'y a pas de mode d'appel qui n'opère que sur les fichiers spécifiés et affecte l'arborescence de travail.

solution de contournement

Si vous voulez les deux:

  • Réinitialiser la version d'index / cache d'un ou plusieurs fichiers
  • Extraire le (s) fichier (s) (c'est-à-dire faire correspondre l'arborescence de travail à l'index et à la version de validation)

Vous pouvez utiliser cet alias dans votre fichier de configuration git:

[alias]
  reco   = !"cd \"${GIT_PREFIX:-.}\" && git reset \"$@\" && git checkout \"$@\" && git status --short #"  # Avoid: "fatal: Cannot do hard reset with paths."

Vous pouvez ensuite effectuer l'une des opérations suivantes:

$ git reco <paths>

$ git reco <branch/commit> <paths>

$ git reco -- <paths>

(Mnenonic pour reco: reset && check out)

Tom Hale
la source
-2

git reset --soft HEAD ~ 1 nom de fichier annule la validation mais les modifications restent en local. le nom de fichier peut être - pour tous les fichiers validés

Peiti Li
la source
6
fatalCannot do soft reset with paths.
alt