Mise à JOUR: Ce sera un travail plus intuitif que de Git 1.8.3, voir ma propre réponse.
Imaginez la suite de cas d'utilisation: je veux me débarrasser de tous les changements dans un sous-répertoire de mon Git arbre de travail, en laissant toutes les autres sous-répertoires intacte.
Je peux le faire
git checkout .
, mais git checkout . ajoute répertoires exclus par le peu de caisseIl est
git reset --hard
, mais il ne me laisse pas le faire pour un répertoire:> git reset --hard . fatal: Cannot do hard reset with paths.
Encore une fois: Pourquoi git ne peut pas faire de hard/soft resets par chemin?
Je peux inverser le patch, en l'état actuel à l'aide de
git diff subdir | patch -p1 -R
, mais c'est plutôt drôle de façon de le faire.Quelle est la bonne commande Git pour cette opération?
Le script ci-dessous illustre le problème. Insérez le bon de commande ci-dessous l'
How to make files
commentaire -- la commande en cours sera de restaurer le fichiera/c/ac
qui est censé être exclus par les rares de la caisse. Notez que je ne veux explicitement restaurera/a
eta/b
, je ne le "connais"a
et que vous voulez restaurer tout en dessous. EDIT: Et j'ai aussi ne pas "savoir"b
, ou d'autres répertoires se trouvent sur le même niveau quea
.#!/bin/sh rm -rf repo; git init repo; cd repo for f in a b; do for g in a b c; do mkdir -p $f/$g touch $f/$g/$f$g git add $f/$g git commit -m "added $f/$g" done done git config core.sparsecheckout true echo a/a > .git/info/sparse-checkout echo a/b >> .git/info/sparse-checkout echo b/a >> .git/info/sparse-checkout git read-tree -m -u HEAD echo "After read-tree:" find * -type f rm a/a/aa rm a/b/ab echo >> b/a/ba echo "After modifying:" find * -type f git status # How to make files a/* reappear without changing b and without recreating a/c? git checkout -- a echo "After checkout:" git status find * -type f
Réponses
Trop de publicités?Note (comme commenté par Dan Fabulich):
-
git checkout -- <path>
ne pas faire un hard reset: il remplace l'arbre de travail contenu avec la mise en scène des contenus. -
git checkout HEAD -- <path>
fait un hard reset pour un chemin d'accès, de remplacer à la fois l'indice et l'arbre de travail avec la version de l'HEAD
commettre.
Voir si la caisse peut respecter un git update-index --skip-worktree
(pour les répertoires que vous voulez ignorer), comme mentionné dans "Pourquoi les fichiers exclus garder sa réapparition dans mon git sparse checkout?".
Selon Git développeur Duy Nguyen qui a gentiment mis en œuvre la fonctionnalité et un commutateur de compatibilité, les ouvrages suivants, comme prévu comme de Git 1.8.3:
git checkout -- a
Essayez de changer
git checkout -- a
pour
git checkout -- `git ls-files -m -- a`
Depuis la version 1.7.0, Git de l' ls-files
honneurs le skip-worktree drapeau.
L'exécution de votre script de test (avec quelques modifications mineures évolution git commit
... git commit -q
et git status
de git status --short
) sorties:
Initialized empty Git repository in /home/user/repo/.git/
After read-tree:
a/a/aa
a/b/ab
b/a/ba
After modifying:
b/a/ba
D a/a/aa
D a/b/ab
M b/a/ba
After checkout:
M b/a/ba
a/a/aa
a/c/ac
a/b/ab
b/a/ba
L'exécution de votre script de test avec le projet de checkout
changement de sorties:
Initialized empty Git repository in /home/user/repo/.git/
After read-tree:
a/a/aa
a/b/ab
b/a/ba
After modifying:
b/a/ba
D a/a/aa
D a/b/ab
M b/a/ba
After checkout:
M b/a/ba
a/a/aa
a/b/ab
b/a/ba
Une réinitialisation normalement tout changer, mais vous pouvez utiliser git stash
à choisir ce que vous voulez garder. Comme vous l'avez mentionné, stash
n'accepte pas un chemin d'accès directement, mais il peut encore être utilisé pour garder un chemin d'accès spécifique avec l' --keep-index
drapeau. Dans votre exemple, vous pouvez ranger le b répertoire, puis réinitialiser tout le reste.
# How to make files a/* reappear without changing b and without recreating a/c?
git add b #add the directory you want to keep
git stash --keep-index #stash anything that isn't added
git reset #unstage the b directory
git stash drop #clean up the stash (optional)
Cela vous arrive à un point où la dernière partie de votre script sera de sortie ce:
After checkout:
# On branch master
# Changes not staged for commit:
#
# modified: b/a/ba
#
no changes added to commit (use "git add" and/or "git commit -a")
a/a/aa
a/b/ab
b/a/ba
Je crois que cela a été la cible de résultat (b reste modifiés,* les fichiers sont de retour, a/c n'est pas recréé).
Cette approche a l'avantage d'être très flexible; vous pouvez obtenir aussi fine que vous souhaitez ajouter des fichiers spécifiques, mais pas d'autres, dans un répertoire.