web-dev-qa-db-fra.com

Git: comment supprimer un fichier de l'index sans supprimer des fichiers d'un référentiel

Quand vous utilisez

git rm --cached myfile

il ne supprime pas du système de fichiers local, ce qui est l'objectif. Mais si vous avez déjà versionné et validé le fichier, l'avez placé dans un référentiel central et l'avez extrait dans un autre référentiel avant d'utiliser la commande, le fichier sera supprimé du système.

Existe-t-il un moyen de supprimer le fichier du contrôle de version sans le supprimer de tout système de fichiers?

Edit: Clarifié, j'espère.

148
Fletcher Moore

Je ne pense pas qu'un commit Git puisse enregistrer une intention du type «arrête de suivre ce fichier, mais ne le supprime pas».

Une telle intention nécessitera une intervention en dehors de Git dans tous les référentiels fusionnant (ou rebase sur) un commit qui supprime le fichier.


Enregistrer une copie, appliquer la suppression, restaurer

Le plus simple est probablement de dire aux utilisateurs en aval de sauvegarder une copie du fichier, d'extraire votre suppression, puis de restaurer le fichier . Si ils extraient via rebase et apportent des modifications au fichier, ils avoir des conflits. Pour résoudre de tels conflits, utilisez git rm foo.conf && git rebase --continue (si la validation en conflit comporte des modifications autres que celles du fichier supprimé) ou git rebase --skip (si la validation en conflit a uniquement été remplacée par le fichier supprimé).

Restaurer le fichier sans suivi après avoir extrait une validation qui le supprime

S'ils ont déjà extrait votre validation de suppression, ils peuvent toujours récupérer la version précédente du fichier avec git show :

git show @{1}:foo.conf >foo.conf

Ou avec git checkout (selon les commentaires de William Pursell; mais souvenez-vous de le retirer à nouveau de l'index!):

git checkout @{1} -- foo.conf && git rm --cached foo.conf

S'ils ont pris d'autres mesures depuis la suppression de votre suppression (ou s'ils tirent avec réassignation dans une HEAD isolée), ils peuvent avoir besoin de quelque chose d'autre que @{1}. Ils pourraient utiliser git log -g pour trouver le commit juste avant de retirer votre suppression.


Dans un commentaire, vous indiquez que le fichier que vous souhaitez «annuler le suivi, mais conserver» est une sorte de fichier de configuration nécessaire à l'exécution du logiciel (directement à partir d'un référentiel).

Conserver le fichier comme «par défaut» et l’activer manuellement/automatiquement

S'il n'est pas totalement inacceptable de continuer à gérer le contenu du fichier de configuration dans le référentiel, vous pourrez peut-être renommer le fichier suivi de (par exemple) foo.conf en foo.conf.default, puis demander à vos utilisateurs de cp foo.conf.default foo.conf après avoir appliqué la validation de changement de nom . Ou, si les utilisateurs utilisent déjà une partie existante du référentiel (par exemple, un script ou un autre programme configuré par le contenu du référentiel (par exemple, Makefile ou similaire)) pour lancer/déployer votre logiciel, vous pouvez incorporer un mécanisme par défaut au lancement./processus de déploiement:

test -f foo.conf || test -f foo.conf.default &&
    cp foo.conf.default foo.conf

Avec un tel mécanisme par défaut en place, les utilisateurs devraient pouvoir extraire un commit qui renomme foo.conf en foo.conf.default sans avoir à effectuer de travail supplémentaire . De plus, vous évitez de copier manuellement un fichier de configuration si vous effectuez des installations/référentiels supplémentaires. A l'avenir.

La réécriture de l'historique nécessite une intervention manuelle de toute façon…

S'il est inacceptable de maintenir le contenu dans le référentiel, vous voudrez probablement le supprimer complètement de l'historique avec quelque chose comme git filter-branch --index-filter … . Cela revient à réécrire l'historique, ce qui nécessitera une intervention manuelle de chaque branche/référentiel. (Voir la section «Récupération à partir de la base de données amont» dans la page de manuel git rebase ) . Le traitement spécial requis pour votre fichier de configuration ne serait qu'une étape supplémentaire à effectuer lors de la récupération de la réécriture:

  1. Enregistrez une copie du fichier de configuration.
  2. Récupérer de la réécriture.
  3. Restaurez le fichier de configuration.

Ignorer pour prévenir la récurrence

Quelle que soit la méthode que vous utilisiez, vous voudrez probablement inclure le nom de fichier de configuration dans un fichier .gitignore du référentiel, afin que personne ne puisse réapparaître par inadvertance git add foo.conf (cela est possible, mais requiert -f--force) . fichier de configuration, vous pouvez envisager de les "déplacer" dans un seul répertoire et d'ignorer le tout (par "déplacement", je veux dire changer l'endroit où le programme s'attend à trouver ses fichiers de configuration, et obtenir les utilisateurs (ou le mécanisme de lancement/déploiement) copier/déplacer les fichiers vers leur nouvel emplacement, vous ne voudriez évidemment pas _/git mv un fichier dans un répertoire que vous allez ignorer).

108
Chris Johnsen

Avait le même problème cette semaine quand j'ai commis par accident, puis essayé de supprimer un fichier de construction d'un référentiel partagé, et cela:

http://gitready.com/intermediate/2009/02/18/temporarily-ignoring-files.html

a bien fonctionné pour moi et n’a pas encore été mentionné.

git update-index --assume-unchanged <file>

Pour supprimer le fichier qui vous intéresse du contrôle de version, utilisez toutes vos autres commandes normalement.

git update-index --no-assume-unchanged <file>

Si vous avez toujours voulu le remettre en place.

Edit: veuillez consulter les commentaires de Chris Johnsen et KPM, cela ne fonctionne que localement et le fichier reste sous contrôle de version pour les autres utilisateurs s’ils ne le font pas également. La réponse acceptée donne des méthodes plus complètes/correctes pour traiter ce problème. Aussi quelques notes du lien si vous utilisez cette méthode:

De toute évidence, il y a pas mal de mises en garde qui entrent en jeu avec cette . Si vous ajoutez le fichier directement, il sera ajouté à l'index . La fusion d'un commit avec cet indicateur activé entraînera l'échec de la fusion gracieusement afin que vous puissiez le manipuler manuellement.

85
Tom Power

Pour supprimer le fichier de l'index, utilisez:

git reset myfile

Cela ne devrait pas affecter votre copie locale ou celle de quelqu'un d'autre.

30
Armand

Après avoir exécuté la commande git rm --cached, essayez d’ajouter myfile au fichier .gitignore (créez-en un s’il n’existe pas). Cela devrait dire à git d'ignorer myfile.

Le fichier .gitignore est versionné, vous devez donc le valider et le transférer dans le référentiel distant.

15
awgy
  1. git rm --cached remove_file
  2. ajouter un fichier à gitignore
  3. git add .gitignore
  4. git commit -m "Excluding"
  5. S'amuser ;)

Ma solution est de tirer sur l'autre copie de travail et ensuite:

git log --pretty="format:" --name-only -n1 | xargs git checkout HEAD^1

qui dit obtenir tous les chemins de fichiers dans le dernier commentaire et les extraire du parent de HEAD. Travail accompli.

1
Tom Viner

Les solutions ci-dessus fonctionnent bien dans la plupart des cas . Cependant, si vous devez également supprimer toutes les traces de ce fichier (c’est-à-dire des données sensibles telles que des mots de passe), vous voudrez également le supprimer de l’ensemble de votre historique de validation, comme le fichier. pourrait encore être récupéré à partir de là.

Voici une solution qui supprime toutes les traces du fichier de votre historique de validation complet, comme s'il n'avait jamais existé, tout en maintenant le fichier en place sur votre système.

https://help.github.com/articles/remove-sensitive-data/

Vous pouvez en fait passer à l'étape 3 si vous vous trouvez dans votre référentiel git local et que vous n'avez pas besoin d'effectuer une analyse. Dans mon cas, je n'avais besoin que des étapes 3 et 6, car j'avais déjà créé mon fichier .gitignore et figurais dans le référentiel sur lequel je voulais travailler.

Pour voir vos modifications, vous devrez peut-être accéder à la racine GitHub de votre référentiel et actualiser la page. Parcourez ensuite les liens pour vous rendre à un ancien commit contenant le fichier, afin de voir s'il a été supprimé. Pour moi, l'actualisation de l'ancienne page de validation ne montre pas le changement.

Cela avait l'air intimidant au début, mais en réalité, c'était facile et fonctionnait à merveille! :-)

0
SherylHohman