Comment git reset --hard un sous-répertoire?
Mise à JOUR: Ce travail de manière plus intuitive que de Git 1.8.3, voir ma propre réponse.
Imaginer 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 faire
git checkout .
, mais git checkout . ajoute répertoires exclus par le peu de caisse -
Il 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.
De nouveau: 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 la 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 pas veulent explicitement restaurer a/a
et a/b
, je ne le "connais" a
et que vous voulez restaurer tout en dessous. MODIFIER: 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
- que penser d'un
git stash && git stash drop
? - qu'en est
git checkout -- /path/to/subdir/
? git stash
ne pas accepter un argument de chemin...- Nope. Sera également ajouter des fichiers exclus par le peu de caisse.
- Re: bounty. Ce n'est pas le lieu pour obtenir des réponses à partir crédible / sources officielles ou pour des réponses à partir de git développeurs. Pour journal d'un bug sur éparses caisse, vous devez utiliser la commande git liste de diffusion [email protected] .
- Il ne ressemble pas à la éparses fonction commande est quelque chose de prévu pour être vraiment utilisé... il suffit de ne pas l'utiliser et de définir un repo git pour chaque projet.
- Alors pourquoi il y a un bouton radio à la lecture de "la Recherche d'une réponse dessin de crédible et/ou de sources officielles." dans le monde des chasseurs de dialogue? Je n'ai pas le type que moi-même! Aussi essayer de googler "git reset sous-répertoire" (sans les guillemets) et voir ce qui est sur les 3 premières positions. Pour assurer un message à un kernel.org liste de diffusion seront plus difficiles à trouver. -- Aussi, pour moi, il n'est pas encore clair si ce comportement est du à un bug ou une fonctionnalité.
- Cela ne me permet pas à l'aide de
bisect
et amis sur plusieurs projets en même temps. -- Je pense que sparse checkout est un doux fonctionnalité, bugs ou autres problèmes peuvent être résolus. - Je viens de dire que si vous voulez une réponse de la part du Git développeurs, alors vous devriez demander à l'endroit approprié; il semble un peu inutile d'espérer que l'on viendra ici ou que quelqu'un va relayer le message sur quand la liste de diffusion existe un moyen pour vous de communiquer avec Git développeurs.
- La droite. Je vais poster un lien vers la liste de diffusion (merci pour l'adresse btw), nous allons voir si il y aura plus de commentaires.
Vous devez vous connecter pour publier un commentaire.
Avec Git 2.23 (août 2019), vous avez la nouvelle commande
git restauration
À remplacer à la fois l'indice et l'arbre de travail avec
HEAD
de contenu, comme unreset --hard
serait, mais pour un chemin d'accès spécifique.Réponse originale à cette question (2013)
Note (comme commenté par Dan Fabulich) que:
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 duHEAD
commettre.Comme répondu par Ajedi32, à la fois la caisse des formes de ne pas supprimer les fichiers qui ont été supprimés dans la cible de révision.
Si vous avez des fichiers supplémentaires dans l'arbre de travail qui n'existent pas dans la TÊTE, un
git checkout HEAD -- <path>
de ne pas les supprimer.Remarque: Avec
git checkout --superposition de TÊTE -- <path>
Git (2.22, T1 2019), les fichiers qui apparaissent dans l'index et de l'arbre de travail, mais pas dans<tree-ish>
sont supprimés, pour les faire correspondre<tree-ish>
exactement.Mais que 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?".git checkout HEAD -- .
, fichiers exclus par le peu de caisse réapparaître. Qu'est-ce quegit update-index --skip-worktree
censé faire?git checkout HEAD -- <path>
, puis supprimez les répertoires qui ont été restaurés (mais qui sont toujours déclarés dans la sparse checkout).git checkout HEAD -- <path>
ne semble pas se comporter de la même comme un hard reset. Une réinitialisation matérielle supprime les fichiers dans le chemin d'accès qui ne sont plus dans la révision. Dans mon expérience (git 1.8.3.3),git checkout HEAD -- <path>
ne le fait pas.reset --hard
avec un chemin d'accès:reset-path = "!f() { : git checkout ; rm -rf \"$2\" && git checkout \"$1\" -- \"$2\" ; }; f"
. Cependant, cela va également supprimer sans traces de fichiers quand il ne devrait pas, mais c'est un compromis raisonnable pour la commodité qu'il offre à l'heure actuelle.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:
(où
a
est le répertoire que vous voulez hard-reset). Le comportement d'origine peut être consulté viagit checkout -- .
où.
désigne le répertoire courant.git reset -- a
(où a est le répertoire que vous souhaitez réinitialiser)git reset --hard
tout le repo?Essayez de changer
à
Depuis la version 1.7.0, Git est
ls-fichiers
les honneurs le skip-worktree drapeau.L'exécution de votre script de test (avec quelques modifications mineures de changer
git commit
... àgit commit -q
etgit status
àgit status --short
) sorties:L'exécution de votre script de test avec le projet de
checkout
changement sorties:git checkout
respecter le "skip-worktree" bits en premier lieu?checkout.c
ettree.c
ne révèle pas que le skip-worktree drapeau est utilisé.Pour le cas d'un simple rejet des changements, la
git checkout -- path/
ougit checkout HEAD -- path/
commandes suggérées par d'autres réponses de l'excellent travail. Toutefois, lorsque vous souhaitez réinitialiser un répertoire à une révision autre que la TÊTE, cette solution a un problème important: il ne supprime pas les fichiers qui ont été supprimés dans la cible de révision.Donc, au lieu de cela, j'ai commencé à l'aide de la commande suivante:
Cela fonctionne par trouver la diff entre la cible s'engager et l'index, puis l'application de cette diff dans le sens inverse pour le répertoire de travail et l'index. Fondamentalement, cela signifie qu'il rend le contenu de l'index en fonction du contenu de la révision que vous avez spécifié. Le fait que
git diff
prend un argument de chemin permet de limiter cet effet à un fichier ou d'un répertoire.Car cette commande est assez long et j'ai l'intention de l'utiliser fréquemment, j'ai mis en place un alias pour cela que j'ai nommé
reset-checkout
:Vous pouvez l'utiliser comme ceci:
Ou tout simplement:
git checkout --overlay HEAD -- <path>
commande @VonC mentionne dans sa réponse?git checkout --overlay HEAD -- <path>
n'est pas encore sorti (Git 2.22 sera publié au T2 2019)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 le--keep-index
drapeau. Dans votre exemple, vous pouvez ranger le b répertoire, puis réinitialiser tout le reste.Cela vous arrive à un point où la dernière partie de votre script sera de sortie ce:
Je crois que cela a été la cible de résultat (b est modifié, un/* 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.
git add
tout saufa
, droit? Il semble difficile dans la pratique.git add .
puisgit reset a
à ajouter à tout sauf à laa
.git add
ne pas ajouter de fichiers supprimés. Donc, si vous êtes seulement la récupération de fichiers supprimés,git add .
ajoute tous les fichiers modifiés, mais pas des supprimées.Je vais offrir un terrible possibilité ici, car je n'ai aucune idée de la façon de faire n'importe quoi avec git, sauf
add
commit
etpush
, voici comment j'ai "retourné" un sous-répertoire:J'ai commencé un nouveau référentiel sur mon pc local, est revenue le tout pour le commettre, je voulais copier le code, puis copié les fichiers dans mon répertoire de travail,
add
commit
push
et le tour est joué. Ne les déteste pas le joueur, la haine de M. Torvalds pour être plus intelligent que nous tous.Si la taille de la sous-répertoire n'est pas particulièrement énorme, ET si vous souhaitez rester à l'écart de la CLI, voici une solution rapide à manuellement réinitialiser le sous-répertoire:
Acclamations. Vous venez de remettre à zéro manuellement un sous-répertoire dans votre branche à être le même que celui de la branche master !!
Ajedi32's réponse est ce que je cherchais, mais pour certains commet je suis tombé sur cette erreur:
error: cannot apply binary patch to 'path/to/directory' without full index line
Peut-être parce que certains fichiers du répertoire sont des fichiers binaires. L'ajout de '--binary option à la commande git diff fixé: