Puis-je 'git commit' un fichier et ignorer ses modifications de contenu?

355

Chaque développeur de mon équipe a sa propre configuration locale. Ces informations de configuration sont stockées dans un fichier appelé devtargets.rbqui est utilisé dans nos tâches de construction de râteau. Je ne veux pas que les développeurs s'encombrent mutuellement du fichier devtargets.

Ma première pensée a été de mettre ce fichier dans la .gitignoreliste pour qu'il ne s'engage pas à git.

Puis j'ai commencé à me demander: est-il possible de valider le fichier, mais d'ignorer les modifications apportées au fichier? Donc, je validerais une version par défaut du fichier, puis lorsqu'un développeur la changerait sur sa machine locale, git ignorerait les modifications et ne s'afficherait pas dans la liste des fichiers modifiés lorsque vous effectuez un statut git ou une validation git .

Est-ce possible? Ce serait certainement une fonctionnalité intéressante ...

Derick Bailey
la source

Réponses:

459

Bien sûr, je fais exactement cela de temps en temps en utilisant

git update-index --assume-unchanged [<file> ...]

Pour annuler et recommencer le suivi (si vous avez oublié quels fichiers n'ont pas été suivis, consultez cette question ):

git update-index --no-assume-unchanged [<file> ...]

Documentation pertinente :

- [no-] assume-unchanged
Lorsque cet indicateur est spécifié, les noms d'objet enregistrés pour les chemins ne sont pas mis à jour. Au lieu de cela, cette option active / désactive le bit "supposé inchangé" pour les chemins. Lorsque le bit "supposer inchangé" est activé, l'utilisateur promet de ne pas modifier le fichier et permet à Git de supposer que le fichier d'arbre de travail correspond à ce qui est enregistré dans l'index. Si vous souhaitez modifier le fichier d'arbre de travail, vous devez désactiver le bit pour le dire à Git. Cela est parfois utile lorsque vous travaillez avec un gros projet sur un système de fichiers qui a un lstat(2)appel système très lent (par exemple, cifs).

Git échouera (gracieusement) au cas où il aurait besoin de modifier ce fichier dans l'index, par exemple lors de la fusion dans un commit; ainsi, si le fichier supposé non suivi est modifié en amont, vous devrez gérer la situation manuellement.

Échouer gracieusement dans ce cas signifie que s'il y a des modifications en amont de ce fichier (modifications légitimes, etc.) lorsque vous effectuez un pull, il dira:

$ git pull
…
From https://github.com/x/y
   72a914a..106a261  master     -> origin/master
Updating 72a914a..106a261
error: Your local changes to the following files would be overwritten by merge:
                filename.ext

et refusera de fusionner.

À ce stade, vous pouvez surmonter cela en annulant vos modifications locales, voici une façon:

 $ git checkout filename.ext

puis tirez à nouveau et modifiez à nouveau votre fichier local, ou pourrait définir –no-assume-unchangedet vous pouvez faire stash et fusion normale, etc. à ce moment-là.

Rob Wilkerson
la source
10
cette commande fait-elle son travail localement dans le dossier .git? Je veux dire, si j'exécute cette commande pour un fichier config.php, cela se propagera-t-il aux autres utilisateurs qui utilisent le dépôt?
Magus
16
@Magus: Non. Cela ne fonctionnera que pour vous.
Rob Wilkerson
3
Et peu de temps après, vous voudrez savoir comment déterminer si un fichier est supposé inchangé: stackoverflow.com/questions/2363197/…
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
10
Les modifications apportées aux fichiers ignorés de cette manière sont perdues lorsque "git stash" est utilisé. Y a-t-il un moyen de contourner cela?
Alexis
5
Ce n'est pas pour ça git update-index --assume-unchanged. public-inbox.org/git/…
jsageryd
97

La façon préférée de le faire est d'utiliser git update-index --skip-worktree <file>, comme expliqué dans cette réponse :

assume-unchangedest conçu pour les cas où il est coûteux de vérifier si un groupe de fichiers a été modifié; lorsque vous définissez le bit, git (bien sûr) suppose que les fichiers correspondant à cette partie de l'index n'ont pas été modifiés dans la copie de travail. Cela évite donc un désordre d'appels de statistiques. Ce bit est perdu chaque fois que l'entrée du fichier dans l'index change (donc, lorsque le fichier est modifié en amont).

skip-worktreeest plus que cela: même lorsque git sait que le fichier a été modifié (ou doit être modifié par une réinitialisation --hard ou similaire), il prétendra qu'il ne l'a pas été, en utilisant plutôt la version de l'index. Cela persiste jusqu'à ce que l'index soit supprimé.

Pour annuler cela, utilisez git update-index --no-skip-worktree <file>

Depuis la version 2.25.1 de git, ce n'est plus la voie recommandée non plus, en citant:

Les utilisateurs essaient souvent d'utiliser les bits supposés inchangés et skip-worktree pour dire à Git d'ignorer les modifications apportées aux fichiers suivis. Cela ne fonctionne pas comme prévu, car Git peut toujours vérifier les fichiers d'arborescence de travail par rapport à l'index lors de l'exécution de certaines opérations. En général, Git ne fournit pas un moyen d'ignorer les modifications apportées aux fichiers suivis, donc des solutions alternatives sont recommandées.

Par exemple, si le fichier que vous souhaitez modifier est une sorte de fichier de configuration, le référentiel peut inclure un exemple de fichier de configuration qui peut ensuite être copié dans le nom ignoré et modifié. Le référentiel peut même inclure un script pour traiter l'exemple de fichier comme un modèle, le modifiant et le copiant automatiquement.

1615903
la source
Est-ce que cela fonctionne pour tous les utilisateurs qui extraient le référentiel? Vont-ils obtenir certains fichiers mais ne pourront plus ajouter de modifications, par erreur, à moins de le dire explicitement?
mmm
2
@momomo le drapeau est stocké dans l'index donc non, c'est seulement pour un seul utilisateur. Voir la réponse d' erjiang pour quelque chose qui fonctionne sur tous les utilisateurs.
1615903
J'essaie de comprendre quel devrait être le contenu du fichier. J'ai commenté la réponse à laquelle vous avez fait référence, mais je n'ai obtenu aucune réponse. Où est-il censé se trouver et quel est son contenu? Savez-vous?
mmm
Je ne suis pas en train de suivre. La commande est utilisée pour ignorer un fichier spécifique que vous spécifiez dans la commande. Le contenu de ce fichier n'est pas pertinent.
1615903
1
La documentation de Git indique spécifiquement de ne pas utiliser git update-index --skip-worktreeà cette fin.
bk2204
43

La pratique courante semble être de créer un devtargets.default.rbfichier et de le valider, puis de demander à chaque utilisateur de copier ce fichier devtargets.rb(qui figure dans la liste .gitignore). Par exemple, CakePHP fait de même pour son fichier de configuration de base de données qui change naturellement d'une machine à l'autre.

erjiang
la source
6
Vous ne pouvez pas .gitignore un fichier qui est suivi. .gitignore n'a d'effet que pour les fichiers qui ne sont pas dans l'index.
CB Bailey
1
j'essayais d'éviter de faire ça, même si je n'ai vraiment pas de bonne raison. nous le faisons maintenant et je pense que c'est une douleur de se rappeler que j'ai besoin de créer ma propre version sans ".default" dans le nom.
Derick Bailey
11
@DerickBailey Mais pour être honnête, il est plus facile de se rappeler de copier le fichier que de se souvenir d'utiliser l' --assume-unchangedoption pour tous ceux qui clonent le référentiel.
Dan
1
@DerickBailey, vous pouvez également configurer votre build de râteau par défaut devtargets.default.rbsi devtargets.rbn'existe pas.
Luke
@erjang, que contient ce fichier devtargets.default.rb? Un exemple?
mmm
2

Pour les utilisateurs d'IntelliJ IDEA: Si vous souhaitez ignorer les modifications apportées à un ou plusieurs fichiers, vous pouvez le déplacer vers un autre Change Set.

  • Rendez-vous sur Local Changes( Cmd + 9)
  • Sélectionnez le ou les fichiers que vous souhaitez ignorer
  • F6 pour les déplacer vers un autre Change Set
Eugène
la source