Est-il possible pour git-merge d'ignorer les différences de fin de ligne?

150

Est-il possible git merged'ignorer les différences de fin de ligne?

Peut-être que je pose la mauvaise question ... mais:

J'ai essayé uisng config.crlf inputmais les choses sont devenues un peu désordonnées et incontrôlables , surtout quand je l'ai appliqué après coup .

D'une part, appliquer cette configuration après coup ne semble pas affecter les fichiers qui ont été validés dans le référentiel avant d'appliquer cette option. Une autre chose est que soudainement, tous les commits entraînent maintenant de nombreux messages d'avertissement ennuyeux concernant la conversion de CRLF en LF.

Pour être honnête, je ne me soucie pas vraiment de la fin de ligne utilisée, je préfère personnellement le style Unix \n, mais peu importe. Tout ce qui m'importe, c'est git merged'être un peu plus intelligent et d'ignorer les différences de fin de ligne.

Parfois, j'ai deux fichiers identiques, mais git les marquerait comme étant en conflit (et le conflit est le fichier entier ) simplement parce qu'ils utilisent un caractère de fin de ligne différent.

Mettre à jour:

J'ai découvert que cela git diffaccepte une --ignore-space-at-eoloption, serait-il possible de laisser git mergeutiliser cette option également?

hasen
la source
28
Oh je souhaite. Cette fin de ligne dans git est totalement cassée
1800 INFORMATION
Je viens d'ajouter un cas de test illustrant que l'outil de fusion tiers ignorera le style eol lors d'une fusion
VonC
Donc, pour clarifier (d'après ce que je peux déterminer): il n'y a aucun moyen d'obtenir git d'ignorer les CR mais de se plaindre de tous les autres espaces de fin?
Stephen
Assurez-vous de jeter un oeil à la réponse ci-dessous à propos degit config merge.renormalize true
qneill

Réponses:

115

Mise à jour 2013:

Les versions plus récentes de git autorisent l'utilisation de la fusion avec l' option de stratégie recursiveet de stratégie ( ):-X

git merge -s récursif -Xignore-space-at-eol

Mais utiliser " -Xignore-space-change" est aussi une possibilité

  • Fab-V mentionne ci - dessous :
    git merge master -s récursif -X renormaliser
    
    

jakub.g commente également que les stratégies fonctionnent également avec le tri sélectif :

git cherry-pick abcd123456 --strategy=recursive --strategy-option=renormalize 

Cela fonctionne bien mieux que ignore-all-space.


Réponse originale (mai 2009)

Le patch pour ignorer le style eol a été proposé en juin 2007 , mais cela ne concerne que git diff --ignore-space-at-eol, non git merge.

À l'époque, la question a été posée:

Devrait --ignore-space-at-eolêtre une option pour git-merge?
Les fusions sont là où cette fonctionnalité compte.
Quelle est la sémantique d'une fusion auto-résolue avec ces options en vigueur - sont-elles uniquement utilisées pour la détection de changement de nom, ou ne signalons-nous pas, par exemple, les conflits avec uniquement des changements d'espaces? Et si nous ne le faisons pas, quelle version acceptons-nous automatiquement?

Julio C Hamano n'était pas vraiment enthousiaste:

C'est certes tentant, mais je pense que cela devrait être laissé à des séries ultérieures.
Je soupçonne que cela introduirait un concept de deux types différents de diffs, l'un à traiter mécaniquement (c'est-à-dire à utiliser en fusion avec "git-merge-recursive" et à appliquer avec "git-am"), et un autre à inspecter par les humains à comprendre.
Il peut souvent être utile de casser l'entrée pour ce dernier cas, même si la sortie de la comparaison de fichiers d'entrée munged peut ne pas être facilement utilisable pour une application mécanique.

L'idée générale, quand il s'agit git merge, est de s'appuyer sur l'outil de fusion tiers.

Par exemple, j'ai configuré DiffMerge pour être l'outil de fusion Git, en définissant un ensemble de règles qui permet à cet outil de fusion d'ignorer eol pour certains types de fichiers.


Installation sous Windows, avec MSysGit1.6.3, pour une session DOS ou Git bash, avec DiffMerge ou KDiff3:

  • définissez un répertoire dans votre PATH (ici:) c:\HOMEWARE\cmd.
  • ajoutez dans ce répertoire le script merge.sh (wrapper pour votre outil de fusion préféré)

merge.sh:

#!/bin/sh

# Passing the following parameters to mergetool:
#  local base remote merge_result

alocal=$1
base=$2
remote=$3
result=$4

if [ -f $base ]
then
    #"C:/Program Files/SourceGear/DiffMerge/DiffMerge.exe" "$alocal" "$base" "$remote" -m --result="$result" --title1="Mine" --title2="Merging to: $result" --title3="Theirs"

    # for merge respecting eol, KDiff3 is better than DiffMerge (which will always convert LF into CRLF)
    # KDiff3 will display eol choices (if Windows: CRLF, if Unix LF)
    "C:/Program Files/KDiff3/kdiff3.exe" -m "$base" "$alocal" "$remote" -o "$result"
else
    #there is not always a common ancestor: DiffMerge needing 3 files, BASE will be the result
    #"C:/Program Files/SourceGear/DiffMerge/DiffMerge.exe" "$alocal" "$result" "$remote" -m --result="$result" --title1="Mine" --title2="Merging to: $result" --title3="Theirs"

    # KDiff3 however does know how to merge based on 2 files (not just 3)
    "C:/Program Files/KDiff3/kdiff3.exe" -m "$base" "$remote" -o "$result"
fi
  • Déclarez votre wrapper de fusion pour Git

Commandes Git config:

git config --global merge.tool diffmerge
git config --global mergetool.diffmerge.cmd "merge.sh \"$PWD/$LOCAL\" \"$PWD/$BASE\" \"$PWD/$REMOTE\" \"$PWD/$MERGED\"
git config --global mergetool.diffmerge.trustExitCode false
git config --global mergetool.diffmerge.keepBackup false
  • Vérifiez que autoCRLF est faux

git config au niveau du système:

git config ---system core.autoCRLF=false
  • Testez que, lorsque deux lignes sont identiques (mais leurs caractères eol), DiffMerge ou KDiff3 ignoreront ces lignes lors d'une fusion.

Script DOS (note: la commande dos2unix vient d'ici , et est utilisée pour simuler un style Unix eol. Cette commande a été copiée dans le répertoire mentionné au début de cette réponse.):

C:\HOMEWARE\git\test>mkdir test_merge C:\HOMEWARE\git\test>cd test_merge C:\HOMEWARE\git\test\test_merge>git init C:\HOMEWARE\git\test\test_merge>echo a1 > a.txt & echo a2 >> a.txt C:\HOMEWARE\git\test\test_merge>git add a.txt C:\HOMEWARE\git\test\test_merge>git commit -m "a.txt, windows eol style" C:\HOMEWARE\git\test\test_merge>git checkout -b windows Switched to a new branch 'windows' C:\HOMEWARE\git\test\test_merge>echo a3 >> a.txt & echo a4 >> a.txt C:\HOMEWARE\git\test\test_merge>git add a.txt C:\HOMEWARE\git\test\test_merge>git commit -m "add two lines, windows eol style" C:\HOMEWARE\git\test\test_merge>git checkout master C:\HOMEWARE\git\test\test_merge>git checkout -b unix Switched to a new branch 'unix' C:\HOMEWARE\git\test\test_merge>echo au3 >> a.txt & echo au4 >> a.txt && echo au5 >> a.txt C:\HOMEWARE\git\test\test_merge>dos2unix a.txt Dos2Unix: Processing file a.txt ... C:\HOMEWARE\git\test\test_merge>git add a.txt C:\HOMEWARE\git\test\test_merge>git commit -m "add 3 lines, all file unix eol style" [unix c433a63] add 3 lines, all file unix eol style C:\HOMEWARE\git\test\test_merge>git merge windows Auto-merging a.txt CONFLICT (content): Merge conflict in a.txt Automatic merge failed; fix conflicts and then commit the result. C:\HOMEWARE\git\test\test_merge>git ls-files -u 100644 39b4c894078a02afb9b1dfeda6f1127c138e38df 1 a.txt 100644 28b3d018872c08b0696764118b76dd3d0b448fca 2 a.txt 100644 3994da66530b4df80189bb198dcfac9b8f2a7b33 3 a.txt C:\HOMEWARE\git\test\test_merge>git mergetool Merging the files: a.txt Normal merge conflict for 'a.txt': {local}: modified {remote}: modified Hit return to start merge resolution tool (diffmerge):

À ce stade (en cliquant sur «retour»), DiffMerge ou KDiff3 s'ouvrira, et vous verrez par vous-même quelles lignes sont réellement fusionnées et quelles lignes sont ignorées.

Attention : le fichier résultat sera toujours en mode Windows eol (CRLF) avec DiffMerge ...
KDiff3 propose de sauvegarder d'une manière ou d'une autre.

VonC
la source
Merci pour le tuyau! Meld et FileMerge sur Mac semblent également être d'excellentes applications.
Léo Léopold Hertz 준영
1
Pour info, les stratégies fonctionnent aussi avec le cherry-picking : git cherry-pick abcd123456 --strategy=recursive --strategy-option=renormalize (cela fonctionne beaucoup mieux que ignore-all-space)
jakub.g
1
@ jakub.g bon point! Je l'ai inclus dans la réponse pour plus de visibilité.
VonC
98

Je cherchais la même réponse et j'ai découvert cette

Fusionner des branches avec des attributs d'archivage / d'extraction différents

Si vous avez ajouté des attributs à un fichier qui entraînent la modification du format de référentiel canonique de ce fichier, comme l'ajout d'un filtre de nettoyage / bavure ou d'attributs text / eol / ident, la fusion de tout élément où l'attribut n'est pas en place entraînerait normalement des conflits de fusion. .

Pour éviter ces conflits de fusion inutiles, git peut être invité à exécuter une extraction et une archivage virtuelles des trois étapes d'un fichier lors de la résolution d'une fusion à trois en définissant la variable de configuration merge.renormalize. Cela empêche les modifications provoquées par la conversion d'archivage de provoquer des conflits de fusion parasites lorsqu'un fichier converti est fusionné avec un fichier non converti.

Tant qu'un "smudge → clean" donne le même résultat qu'un "clean" même sur des fichiers déjà maculés, cette stratégie résoudra automatiquement tous les conflits liés aux filtres. Les filtres qui n'agissent pas de cette manière peuvent provoquer des conflits de fusion supplémentaires qui doivent être résolus manuellement.

Donc, exécuter cette commande dans n'importe quel référentiel fera l'affaire:

git config merge.renormalize true
Fabio
la source
20
Cela mérite maintenant d'être la réponse par défaut. Beaucoup de choses ont changé depuis que la question a été posée pour la première fois, la gestion de cela par git est maintenant intégrée avec merge.renormalize comme vous le dites.
Anton I. Sipos
C'est juste génial .. sauve ma journée
matthaeus
4

Ce que j'ai fait a été de tout laisser par défaut (c'est-à-dire autocrlf = true), de toucher tous les fichiers (find. -Exec touch {} \;), de laisser git les voir comme "modifiés" et de les valider, et en finir. Sinon, vous serez toujours soit en proie à des messages ennuyeux ou des différences surprenantes, soit vous devrez désactiver toutes les fonctionnalités d'espace blanc de git.

Vous perdrez les informations de blâme, mais il vaut mieux le faire le plus tôt possible :)

Ben Hymers
la source
4

"git merge -Xrenormalize" fonctionne comme un charme.

Jake
la source
1

http://stahlforce.com/dev/index.php?tool=remcrlf

Je l'ai essayé, mais si après la dernière ligne de votre code vous n'aviez pas déjà CRLF, il ajoute par lui-même un LF et le fichier semble changé dans git. A part ça, ça marche.

l'homme fourmi
la source
0

Il me semble maintenant que le meilleur moyen est de normaliser les fins de ligne sur les deux branches (et de commettre) avant de les fusionner.

J'ai recherché sur Google "convertir crlf en lf" et j'ai trouvé ceci dans les premiers résultats:
http://stahlforce.com/dev/index.php?tool=remcrlf

Je l'ai téléchargé et utilisé, cela semble être un bon outil.

>sfk remcr . .py

Assurez-vous cependant de spécifier un répertoire et un type de fichier (par exemple .py) sinon il pourrait essayer de jouer avec le contenu du .gitrépertoire!

hasen
la source
0

AFAICT, (je ne l'ai pas essayé), vous pouvez utiliser git diffpour comparer la branche que vous souhaitez fusionner avec l'ancêtre commun, puis appliquer les résultats avec git apply. Les deux commandes ont des --ignore-whitespaceoptions pour ignorer les erreurs de fin de ligne et d'espace blanc.

Malheureusement, si le patch ne s'applique pas correctement, toute l'opération est abandonnée. Vous ne pouvez pas résoudre les conflits de fusion. Il existe une --rejectoption pour laisser des morceaux non patchables dans les .rejfichiers, ce qui aide, mais ce n'est pas la même chose que d'afficher les conflits de fusion dans un fichier.

rjmunro
la source
-1

Après avoir lu Résoudre les conflits de fusion: Forcer l'écrasement de tous les fichiers

J'ai finalement résolu ma version de ce problème. J'essayais d'extraire les mises à jour du dépôt en amont, mais mon actuel avait des problèmes liés à CRLF et je n'ai pas pu fusionner en conséquence. Il convient de noter que je n'avais AUCUN CHANGEMENT LOCAL dont je devais m'inquiéter. Les étapes suivantes ont résolu mon problème:

Selon les instructions de github sur la synchronisation des fourches ( https://help.github.com/articles/syncing-a-fork/ ):

  1. git fetch upstream

  2. git reset --hard upstream/master
    Ma compréhension limitée de git me dit que cela fait ce que je veux - rebaser mon fork (sans modifications réelles non validées) pour obtenir toutes les modifications apportées à la source en amont. Selon la page source, cette étape ne devrait normalement pas être requise, mais le problème CRLF l'a rendue obligatoire.

  3. git merge upstream/master

  4. git push
propagé
la source
1
Vous vous rendez compte que cela git reset --hard upstream/masterjette votre succursale locale et la pointe vers upstream/master, faisant git merge upstream/masterun no-op?
Christoffer Hammarström
-1

Cependant, je suggère d'utiliser un outil comme sed pour obtenir des fins de ligne correctes, puis des fichiers diff. J'ai passé quelques heures sur différents projets avec différentes fins de ligne.

Le meilleur moyen était de:

  1. copier uniquement les fichiers de projet (omettre le .gitrépertoire) dans un autre répertoire, créer un référentiel dedans, puis ajouter des fichiers et les valider (devrait être sur la branche maître dans le nouveau référentiel).
  2. copier les fichiers du deuxième projet vers le même dossier, mais une autre branche par exemple dev( git checkout -b dev), valider les fichiers sur cette branche et exécuter (si le premier projet est en master): git diff master..dev --names-only pour voir uniquement les noms des fichiers modifiés
user4686964
la source