Est-ce que git peut ignorer une ligne spécifique?

115

J'utilise git pour synchroniser avec phonegap lors des tests sur le navigateur natif du téléphone. En tant que tel, j'ai la ligne suivante:

var isPhoneGap = false;

Évidemment, je change cela lors de la construction, mais y a-t-il un moyen de configurer git pour ignorer cette ligne ou dois-je aller le mettre dans son propre fichier et l'ignorer de cette façon?

J'utilise Gitx et le terminal sous OSX 10.6.

Iolo
la source
@ user494461: Les filtres Git sont le moyen de le faire: stackoverflow.com/a/16244970/520162
eckes
1
Vous ne pouvez pas détecter l'environnement et utiliser un fichier de configuration eniroment?
exussum
En bref: Non. Mais j'ai écrit un script de préprocesseur qui recherche certains codes commentés et les supprime avant leur publication sur git. Découvrez-le ici: github.com/franklinchou/ahk_config/blob/master/preprocess.sh
franklin

Réponses:

104

Si votre fichier est d'un type spécifique, vous pouvez déclarer un pilote de filtre de contenu , que vous pouvez déclarer dans un .gitattributesfichier (comme présenté dans le "Développement de mots clés" de " Attributs Git "):

http://git-scm.com/figures/18333fig0702-tn.png

*.yourType filter=yourFilterName

(vous pouvez même définir ce filtre pour un fichier spécifique , si vous le souhaitez)

Mettre en place:

  • yourFilterName.smudge(déclenché sur git checkout) et

    git config --global filter.yourFilterName.smudge 'sed "s/isPhoneGap = .*/isPhoneGap = true/"'
    
  • yourFilterName.clean(déclenché le git add)

    git config --global filter.yourFilterName.clean 'sed "s/isPhoneGap = .*/isPhoneGap = false/"'
    

Votre fichier apparaîtrait inchangé le git status, mais sa version extraite aurait la bonne valeur pour isPhoneGap.

VonC
la source
1
Merci pour cela. ça marche. Savez-vous comment créer un git diff or statut git, mais ignorez les filtres? Donc je peux encore voir ce qui est différent? Mon cas d'utilisation concerne les journaux de débogage ... que je veux finalement supprimer ... @jthill @VonC
timh
1
@timh si le filtre fonctionne, git status ou git diff ne devrait rien afficher.
VonC
1
c'est dommage qu'il n'y ait pas de moyen plus simple dans GIT. git ignore <filename> <linenumber> serait si pratique!
kiedysktos le
22
@kiedysktos numéro de lin? Et si le numéro de ligne change?
VonC le
Cela a très bien fonctionné, mais les utilisateurs de Windows font attention, le gitconfig est très pointilleux avec les caractères qu'il veut contenir, donc lorsque vous essayez des expressions régulières semi-exotiques, vous pouvez avoir des problèmes. J'ai fini par mettre mes appels sed dans un fichier helper.sh séparé que j'ai appelé depuis mon gitconfig sh ".git/helper.sh"en m'assurant de passer tous les paramètres à sed avec "$@"(je suppose que seul le chemin du fichier est passé).
ohaal le
43

Vous pouvez utiliser

git update-index --assume-unchanged [file]

pour ignorer les modifications d'un fichier que vous ne voulez pas suivre. J'utilise cette solution lorsque j'ai besoin d'avoir un fichier dans le référentiel, mais ce fichier a des parties qui changent que je n'ai pas toujours besoin de suivre.

Lorsque le fichier comporte des modifications importantes, vous devez procéder comme suit:

git update-index --no-assume-unchanged [file]

Consultez également l' index de mise à jour de la documentation Git pour le --[no-]assume-unchangedparamètre.

Lorsque ces indicateurs sont spécifiés, les noms d'objets enregistrés pour les chemins ne sont pas mis à jour. Au lieu de cela, ces options définissent et annulent le bit "supposer inchangé" pour les chemins. Lorsque le bit "assume inchangé" est activé, git arrête de vérifier les fichiers de l'arbre de travail pour d'éventuelles modifications, vous devez donc désactiver manuellement le bit pour indiquer à git quand vous changez le fichier de l'arbre de travail.

Carlos
la source
2
Est-ce que cela va toujours récupérer la nouvelle version quand je fais git pull?
Saad Rehman Shah
1
@Caffeine quand vous faites git pull, vous obtenez la dernière version qui a été validée, ce sera la dernière avant que vous ne changiez en '--assume-inchangé' le fichier.
Carlos
1
Je pense que --skip-worktreec'est une meilleure option dans la plupart des cas. stackoverflow.com/a/39583010/4233593
Jeff Puckett
3
cela ignore les mises à jour du fichier entier pas une ligne spécifique
nikoss
6

Gitx devrait vous permettre de valider ou d'ignorer des lignes individuelles (vous le savez peut-être déjà), mais vous devrez le faire à chaque fois que vous vous engagez. Je pense qu'il serait préférable d'avoir un fichier de configuration par cible de déploiement (vous pouvez les version), et un paramètre d'exécution pour la façon dont vous démarrez le serveur (comme ./myserver --config=whatever.js).

Andy Ray
la source
5

Poursuivant https://stackoverflow.com/a/20574486/4935114 , @Mike a proposé de créer un pre-commithook qui se trouvera grepdans les fichiers intermédiaires pour les lignes que l'on pourrait vouloir ignorer. Le hook vérifie si ces lignes ont été mises en scène. Si c'est le cas, c'est echoun avertissement et c'est exitavec du code 1donc le processus de validation ne se poursuit pas.

Inspiré par la réponse de @ Mike , je me suis retrouvé à utiliser peut-être une version améliorée de son hook qui s automatiquement reset (avec le -pdrapeau) la ligne spécifique que nous voulons ignorer.

Je ne suis pas sûr que ce hook fonctionnera dans une situation où vous avez de nombreux fichiers avec cette ligne à ignorer, mais ce pre-commithook recherche un changement dans cette ligne dans un fichier spécifique buildVars.java. Le script de hook ressemblait à ceci lorsque je l'ai testé sur ma machine.

#!/bin/sh

# this hook looks for lines with the text `var isPhoneGap = false;` in the file `buildVars.java` and it resets these lines to the previous state before staged with `reset -p`

if [[ $(git diff --no-ext-diff --cached buildVars.java | grep --count -e "var\ isPhoneGap[\ ]*=[\ ]*") -ne 0 ]]; then
    cat <<EOW
WARNING: You are attempting to commit changes which are not supposed to be commited according to this \`pre-commit\` hook
This \`pre-commit\` hook will reset all the files containing this line to it's previous state in the last commit.
EOW
    echo /$'\n'isPhoneGap$'\n'y$'\n'q | git reset -p
    # BONUS: Check if after reseting, there is no actual changes to be commited and if so, exit 1 so the commit process will abort.
    if [[ $(git diff --no-ext-diff --cached | wc -l) -eq 0 ]]; then
        echo there are no actual changes to be commited and besides the change to the variable \'isPhoneGap\' so I won\'t commit.
        exit 1
    fi
fi

Explication

Ce que j'ai fait, c'est faire écho à des séquences de contrôle qui recherchent l'expression régulière isPhoneGappendant un resetprocessus interactif . Émulant ainsi un utilisateur qui appuie sur /pour rechercher isPhoneGap, appuie ylorsqu'on lui demande s'il veut supprimer ce patch et enfin appuie sur qpour quitter l'interactif reset.

Le processus de patch inversé interactif est documenté ici: https://git-scm.com/docs/git-add#git-add-patch


REMARQUE: le script ci-dessus en supposant que la variable interactive.singleKeyest false. Si vous avez configuré le vôtre sur true, supprimez-en un $'\n'de la echocommande juste après l'avertissement.

Doron Behar
la source
3

Voici comment vous pouvez le faire avec les filtres git :

  1. Créer / ouvrir le fichier gitattributes:
    • <racine du projet> /. gitattributes (sera validé dans le dépôt)
      OU
    • <racine du projet> /. git / info / attributes (ne sera pas validé dans le dépôt)
  2. Ajoutez une ligne définissant les fichiers à filtrer:
    • *.rb filter=gitignore, c'est-à-dire exécuter le filtre nommé gitignoresur tous les *.rbfichiers
  3. Définissez le gitignorefiltre dans votre gitconfig:
    • $ git config --global filter.gitignore.clean "sed '/#gitignore$/'d", ie supprimer ces lignes
    • $ git config --global filter.gitignore.smudge cat, c'est-à-dire ne rien faire lors de l'extraction du fichier du référentiel

Remarques:
Bien sûr, cela concerne les fichiers ruby, appliqués lorsqu'une ligne se termine par #gitignore, appliqués globalement dans ~/.gitconfig. Modifiez ceci selon vos besoins.

Avertissement!!
Cela laisse votre fichier de travail différent du dépôt (bien sûr). Tout retrait ou rebasage signifiera que ces lignes seront perdues! Cette astuce peut sembler inutile car ces lignes sont perdues à plusieurs reprises lors de l'extraction, du rebase ou de l'extraction, mais j'ai un cas d'utilisation spécifique pour l'utiliser.

Juste git stash save "proj1-debug" pendant que le filtre est inactif (désactivez-le temporairement gitconfigou quelque chose). De cette façon, mon code de débogage peut toujours être git stash applyajouté à mon code à tout moment sans craindre que ces lignes ne soient jamais commises accidentellement.

J'ai une idée possible pour résoudre ces problèmes, mais je vais essayer de la mettre en œuvre une autre fois.

Merci à Rudi et jw013 pour avoir mentionné les filtres git et gitattributes.

Kache
la source
2

Un pilote de filtre de contenu n'est pas une bonne solution. Vous pourrez peut-être masquer cette ligne de git status/ etc mais elle n'est pas vraiment ignorée. Dès que vous modifiez la valeur, votre répertoire de travail sera marqué comme sale même si la modification peut ne pas être visible.

Si vous voulez vraiment que cette ligne ne fasse pas partie du contrôle de version, la remplacer par un argument de ligne de commande ou la placer dans un fichier d'inclusion ou de construction ignoré peut être le seul moyen pratique.

patricktokeeffe
la source
"Dès que vous modifiez la valeur, votre répertoire de travail sera marqué comme sale même si le changement peut ne pas être visible": il ne devrait pas, si le script de nettoyage restaure toujours le fichier dans son contenu d'origine.
VonC
C'est ce que j'avais pensé. J'utilise GitExtensions et il affichera le fichier comme modifié même si le volet diff est vide. Peut-être parce que le filtre propre n'est pas exécuté avant l'enregistrement du fichier. Peut-être parce que c'est msysgit, pas git-git. IDK, YMMV
patricktokeeffe
1

J'imagine que cela pourrait être quelque chose qui apparaît dans plus d'une ligne de votre source.

Je pense qu'il serait plus propre d'avoir un fichier .userbuildconfig d'une certaine sorte que vous incluez simplement et que les valeurs par défaut soient enregistrées. Ensuite, vous pouvez utiliser la suggestion de Carlos pour marquer ce fichier seul comme supposé inchangé. De cette façon, les autres modifications apportées au fichier pour lesquelles vous devez vérifier le paramètre ne sont pas manquées.

Cela peut vous permettre de régler les macros de préprocesseur localement (ou pour java quelque chose comme ceci https://stackoverflow.com/a/1813873/1270965 ).

johnb003
la source
-1

Nan. Vous ne pouvez ignorer que des fichiers individuels (et plus) car les lignes dans .gitignore correspondent aux noms de fichiers et non au contenu des fichiers. Vous avez déjà mentionné la solution à ce problème, c'est-à-dire ignorer un seul fichier contenant ce contenu que vous souhaitez ignorer.

ralphtheninja
la source
Je suis d'accord, dans mon cas, il était suffisant et possible d'inclure simplement ce contenu à partir d'un fichier ignoré. Donc en déplaçant tous les paramètres ignorables. Là. De plus, j'ai créé une copie de ce fichier ignoré et l'ai ajouté à l'index comme référence, afin que les informations sur ce qui doit être dans ce fichier ne soient pas perdues.
Urs