web-dev-qa-db-fra.com

Ignorer les modifications spécifiques d'un fichier dans git, mais pas le fichier entier

J'ai un fichier dans un référentiel git qui a un changement local dessus. Je veux que git ignore pour toujours le changement local, mais pas le fichier. En particulier,

  • Si le fichier n'est pas touché en plus de cette modification, git add . ne doit jamais le mettre en scène.
  • Également, git commit -a ne devrait pas le valider.
  • Si jamais j'apporte une modification supplémentaire au fichier, je devrais pouvoir mettre en scène et valider cette modification - mais la modification que j'ignore ne devrait pas pas être mise en scène et engagée.

Y a-t-il un moyen de faire cela? En faisant des recherches, j'ai lu sur "cycles de maculage/nettoyage", où, si je lis correctement,

  1. le fichier serait marqué comme inchangé,
  2. le changement que j'ai fait serait écrasé lors de mon paiement,
  3. puis un script réappliquerait automatiquement la modification, puis marquerait à nouveau le fichier comme inchangé.

Je suis très nouveau dans le git et les scripts, cependant (je suis stagiaire avec C # et Java), donc si c'est ce que je dois faire, pouvez-vous s'il vous plaît publier des instructions détaillées ou un lien à un tutoriel sur la façon de configurer un cycle de maculage/nettoyage?

Contexte: Je veux que ma branche de travail ne soit pas synchronisée avec le tronc. Il y a un bogue de faible priorité qui n'affecte que les machines de développement, donc plutôt que de le corriger, nous commentons simplement le code incriminé. Évidemment, nous ne voulons pas que ce code soit retiré de la production, où cela fonctionne très bien.

45
Kevin

À mon avis, la situation que vous décrivez est la suivante: vous souhaitez conserver un répertoire de travail différent du référentiel local.

Ce n'est pas conseillé; parce que ces modifications ne sont pas validées, vous aurez peu de recours si un fichier est accidentellement supprimé ou modifié d'une manière que vous ne souhaitez pas.

Par conséquent, il est recommandé de valider toutes vos modifications. Si vous souhaitez séparer ces modifications, vous pouvez facilement le faire en utilisant une branche. Exemple

git checkout -b new-branch
# now you can change the file without affecting master
echo bar >> foo
git add
git commit
# and back to master
git checkout master
3
Steven Penny

Vous pouvez utiliser le skip-worktree bit. Allumez-le avec:

git update-index --skip-worktree <file>

Après cela, git ne mettra jamais en scène les modifications locales pour <file> et échouera (bruyamment) si git lui-même doit écrire dans <file> (par exemple, lors d'une fusion ou d'un paiement).

Si jamais vous souhaitez mettre en scène un changement futur, vous pouvez le désactiver, mettre en scène le nouveau changement, puis le réactiver:

git update-index --no-skip-worktree <file>
git add -p <file>
git update-index --skip-worktree <file>

Bien qu'il ne soit pas parfait, cela pourrait être suffisant. Ce sera à vous de remarquer que <file> a des changements non programmés, car git ne vous dira plus que

Remarque: Ma suggestion initiale était d'utiliser assume-unchanged. Comme expliqué dans Git - Différence entre 'assume-unchanged' et 'skip-worktree' , c'est vraiment skip-worktree que tu veux. En particulier, assume-unchanged est une promesse à Git que vous ne modifierez pas le fichier, et si vous ne respectez pas cette promesse, Git est autorisé à effacer vos modifications ou à les valider! En revanche, Git ne supprimera pas ou engagez votre skip-worktree changements.

41
Mark Lodato

Le "mode patch" de Git est parfait pour ajouter seulement certaines modifications d'un fichier à votre commit.

Pour le démarrer, tapez git add -p, git commit -p (directement pour valider le message une fois terminé), ou git add --interactive (plus d'invites).

Il vous guide essentiellement à travers chaque section de code affichée dans git diff et vous demande si vous souhaitez la mettre en scène ou non.

Lorsque vous atteignez le changement, répondez n o, ou e pour ouvrir le correctif dans votre $ EDITOR.

6
Riking

Ces réponses sont bonnes, mais ne résoudront peut-être pas mieux le problème de @ Kevin. J'avais une préoccupation similaire, souvent en modifiant un fichier de configuration afin que l'application sur laquelle je travaillais accède à ma propre base de données de développement privée au lieu de celle de production. Ce n'est qu'une question de temps avant de m'enregistrer accidentellement et de pousser ces changements de configuration! J'avais juste besoin d'un moyen léger pour ignorer un fichier. Voici ce que j'ai appris:

  • Tout d'abord, apportez les modifications nécessaires à votre fichier. Je l'appellerai my_config.

  • Effectuez un fichier de correctif de cette modification avec git diff >../somewhere-else/my_config.patch

  • Dites maintenant à git d'ignorer ce fichier (sans avoir à modifier le .gitignore enregistré): git update-index --assume-unchanged my_config

Maintenant, tant que vous n'apportez pas de modifications à my_config que vous faites souhaitez vous enregistrer, vous pouvez travailler librement. Pour arrêter d'ignorer my_config, faire git update-index --no-assume-unchanged my_config. Après avoir récupéré les modifications de quelqu'un d'autre sur my_config, vous pouvez facilement restaurer votre modification privée avec git apply ../somewhere-else/my_config.patch, puis ... assumer-inchangé à nouveau, comme ci-dessus, et reprendre le travail!

Voici quelques alias utiles que vous pouvez mettre dans votre ~/.gitconfig:

[alias]
    unchanged = update-index --assume-unchanged
    changed = update-index --no-assume-unchanged
    show-unchanged = !"git ls-files -v | sed -e 's/^[a-z] //p; d'"
6
Tyler Perkins

Remarque: d'autres personnes ont dit que rester à l'écart des changements locaux persistants est une mauvaise idée, et je n'ai aucune raison d'être en désaccord. Envisagez d'autres options.

Voici la méthode que j'aime:

  1. Apportez quelques modifications que vous souhaitez conserver sur votre ordinateur local.
  2. Utilisation git branch local et git checkout local pour créer une nouvelle branche pour vos modifications locales. (Si je ne me trompe pas, ces commandes ne configureront pas automatiquement une branche distante, donc la nouvelle branche ne sera pas poussée.)
  3. Utilisation git commit pour valider vos modifications.
  4. Apportez les modifications que vous souhaitez pousser en amont.
  5. Utilisation git checkout parent pour revenir à la branche que vous souhaitez pousser.
  6. Utilisation git commit pour valider cette branche.
  7. Utilisation git Push pour pousser vos modifications.
  8. Utilisation git checkout local pour revenir à votre succursale locale.
  9. Utilisation git rebase parent pour apporter les modifications de parent à local. L'utilisation de rebase fera en sorte que vos modifications locales restent au-dessus des modifications dans parent.
  10. Revenez à l'étape 4 et répétez ad nauseam.

Avec cela, vous n'avez pas à dire manuellement à git quelles modifications sont locales et lesquelles ne le sont pas à chaque fois que vous souhaitez effectuer une modification non locale.

2
Tanner Swett

Oui, cela pourrait probablement être fait en utilisant des filtres de maculage/nettoyage. Cependant, je déconseille fortement de faire cela, car cela serait plutôt complexe et sujet aux erreurs (par exemple, cela perturberait de nombreux outils s'appuyant sur git, cela rendrait les problèmes difficiles à déboguer, etc.).

De plus, ce n'est généralement pas une bonne idée d'avoir des changements locaux permanents. Un point important de l'utilisation d'un SCM est que vous pouvez extraire une version et la faire fonctionner immédiatement. Cela signifie que tout ce dont vous avez besoin doit être enregistré.

Je ne pense pas qu'il y ait de "Nice" façon de le faire, ni avec git ni probablement avec la plupart des autres SCM. Je vous recommande de reconsidérer vos besoins.

Le problème semble être que vous avez un fichier avec un "contenu mixte": du contenu qui est toujours le même et d'autres qui doivent être modifiés localement (options spécifiques à la machine?). La façon recommandée de gérer cela n'est pas de consigner le fichier problématique, mais plutôt de consigner un fichier "modèle", puis de générer le vrai fichier au moment de la construction. Essayez d'enquêter. Ce sera plus de travail maintenant (peut-être), mais cela facilitera les choses, surtout si vous devez prendre en charge plus de variations ou si d'autres personnes veulent travailler sur le même projet.

Modifier (basé sur les informations dans le commentaire)

Vous écrivez que vous souhaitez ignorer un changement de code local qui n'est nécessaire que pour les machines de développement, mais pas en production.

Dans ce cas, au lieu de commenter, enveloppez le code dans une condition quelconque, afin qu'il ne s'exécute que sur les machines de développement (par exemple, en utilisant la compilation conditionnelle, ou en lisant un fichier de configuration ou une propriété d'environnement, ou ... (1 )). Ensuite, vous pouvez archiver le code normalement.

Encore mieux, corrigez simplement le bug. Si un bogue rend le développement difficile, alors à mon humble avis, il est hautement prioritaire.

Le simple fait de commenter le code n'est pas une bonne idée. Il est sujet aux erreurs et doit être effectué à chaque fois que vous passez à la caisse. Surtout, l'exécution de code différent en développement et en production demande des problèmes et doit être évitée autant que possible.

(1) À titre d'exemple: dans notre entreprise, nous avons une variable d'environnement spécifiquement pour des cas comme celui-ci. Il indique si le code est en cours de développement, en test bêta ou en production, et est défini par nos scripts de construction et de déploiement. Cependant, il n'est généralement utilisé que pour des choses simples comme le choix de chemins de fichiers différents. Il est déconseillé de modifier la logique du programme en fonction de l'environnement, comme expliqué ci-dessus.

1
sleske

Si vous ne pouvez pas utiliser .gitignore car vous devez apporter des modifications parallèles dans le même fichier (comme dans vos commentaires), alors une option est git add -p En utilisant cela, vous pouvez ajouter ou ignorer en conséquence.

Le problème avec la commande git ci-dessus est que ce sera plus un processus manuel. Je suppose que vous ne trouverez peut-être aucune autre approche automatisée pour votre problème.

0
Bijendra

S'il vous arrive d'utiliser Intellij comme IDE, alors il a une fonctionnalité intéressante (listes de modifications) qui, je crois, fait exactement ce que OP demande.

Vous pouvez marquer et nommer une partie spécifique de votre diff local. Si la mémoire est bonne, cela gardera ces changements séparés de toutes les autres modifications locales et ne sera organisé pour la validation que si vous choisissez activement de le faire - tant que vous effectuez votre validation à partir d'intellij.

0
LOAS

Depuis Git 2.5 (juillet 2015), vous pouvez utiliser git worktree :

git worktree add -b patch-1 ../patch-1

Il s'agit essentiellement de créer une branche, mais cela place la nouvelle branche dans un nouveau dossier à côté du dépôt parent. C'est bien parce que vous pouvez travailler sur cette branche, même sans vous engager, puis revenir à master avec un répertoire de travail propre.

0
user4427511