306 votes

Comment git reset --hard un sous-répertoire?

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.

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 fichier a/c/ac qui est censé être exclus par les rares de la caisse. Notez que je ne veux explicitement restaurer a/a et a/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 que a.

#!/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

344voto

VonC Points 414372

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?".

151voto

krlmlr Points 5572

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

35voto

Dan Cruz Points 7016

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

4voto

Jonathan Wren Points 2106

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.

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