Возможно ли для git-merge игнорировать различия в конце строки?


150

Можно ли git mergeигнорировать различия в конце строки?

Может я задаю не тот вопрос ... но:

Я попытался использовать, config.crlf inputно все стало немного грязно и вышло из-под контроля, особенно когда я применил его после свершившегося факта .

Во-первых, применение этой конфигурации после факта, похоже, не влияет на файлы, которые были зафиксированы в хранилище до применения этой опции. Другое дело, что внезапно все коммиты теперь приводят к большому количеству раздражающих предупреждающих сообщений о преобразовании CRLF в LF.

Если честно, мне все равно, какой конец строки используется, я лично предпочитаю стиль Unix \n, но неважно. Все, что меня волнует, это git mergeчтобы быть немного умнее и игнорировать различия в окончаниях строк.

Иногда у меня есть два идентичных файла, но git помечает их как конфликтующие (и конфликт - это весь файл) просто потому, что они используют другой символ окончания строки.

Обновить:

Я узнал, что git diffпринимает --ignore-space-at-eolопцию, можно ли будет разрешить git mergeиспользовать эту опцию, а?


28
О, я желаю.
1800 ИНФОРМАЦИЯ

Только что добавил тестовый пример, иллюстрирующий, что сторонний инструмент слияния будет игнорировать стиль eol во время слияния
VonC

Итак, чтобы уточнить (из того, что я могу определить): нет никакого способа заставить git игнорировать CR, но жаловаться на все остальные пробелы?
Стивен

Обязательно посмотрите ответ ниже оgit config merge.renormalize true
qneill

Ответы:


115

Обновление 2013:

Более поздние версии git разрешают использовать слияние со стратегией recursiveи опция стратегии ( -X):

git merge -s рекурсивный -Xignore-space-at-eol

Но использование " -Xignore-space-change" также возможно

  • Fab-V упоминает ниже :
    git merge master -s рекурсивный -X перенормировать
    
    

jakub.g также отмечает, что стратегии работают также с сбором вишни :

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

Это работает намного лучше, чем ignore-all-space.


Оригинальный ответ (май 2009 г.)

Патч для игнорирования стиля eol был предложен в июне 2007 года , но это касается git diff --ignore-space-at-eolне только git merge.

В то время был задан вопрос:

Должен ли --ignore-space-at-eolбыть вариант git-merge?
Слияния, где эта функциональность имеет значение.
Какова семантика автоматического разрешения слияния с этими действующими параметрами - используются ли они только для обнаружения переименования, или мы, например, не помечаем конфликты только изменениями пробелов? И если мы не делаем, какую версию мы принимаем автоматически?

Хулио С Хамано не был в восторге:

Это, конечно, заманчиво, но я подозреваю, что это следует оставить на более поздние раунды.
Я подозреваю, что это представило бы концепцию двух различных типов различий: один для механической обработки (т. Е. Использовать в слиянии с "git-merge-recursive" и применять с "git-am"), а другой - для проверки люди, чтобы понять.
Часто может оказаться полезным выполнить входные данные в последнем случае, даже если выходные данные, полученные в результате сравнения файлов с входными данными, могут быть нелегко использовать для механического применения.

Основная идея git mergeзаключается в том, чтобы полагаться на сторонний инструмент слияния.

Например, я настроил DiffMerge как инструмент для слияния Git, установив набор правил, которые позволяют этому инструменту слияния игнорировать eol для файлов определенного типа.


Установка в Windows, с MSysGit1.6.3, для сеансов DOS или Git bash, с DiffMerge или KDiff3:

  • установить каталог в ваш путь (здесь:) c:\HOMEWARE\cmd.
  • добавьте в этот каталог скрипт merge.sh (обертка для вашего любимого инструмента слияния)

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
  • Объявите свою оболочку слияния для Git

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
  • Убедитесь, что autoCRLF имеет значение false

git config на системном уровне:

git config ---system core.autoCRLF=false
  • Проверьте, что, когда две строки идентичны (но имеют свои символы eol), DiffMerge или KDiff3 будут игнорировать эти строки во время слияния.

Сценарий DOS (примечание: команда dos2unix происходит отсюда и используется для имитации стиля Unix eol. Эта команда была скопирована в каталог, упомянутый в начале этого ответа.):

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):

В этот момент (нажав «Возврат») откроется DiffMerge или KDiff3, и вы сами увидите, какие строки фактически объединены, а какие игнорируются.

Предупреждение : файл результатов всегда будет в режиме Windows eol (CRLF) с DiffMerge ...
KDiff3 предлагает сохранить так или иначе.


Спасибо за совет! Meld и FileMerge в Mac, кажется, тоже отличные приложения.
Лео Леопольд Герц 준영

1
Для информации, стратегии работают также с сбором вишни : git cherry-pick abcd123456 --strategy=recursive --strategy-option=renormalize (это работает намного лучше, чем ignore-all-space)
jakub.g

1
@ jakub.g хороший момент! Я включил его в ответ для большей наглядности.
VonC

98

Я искал тот же ответ, и я узнал это

Объединение веток с различными атрибутами checkin / checkout

Если вы добавили в файл атрибуты, которые приводят к изменению канонического формата хранилища для этого файла, например, добавление фильтра clean / smudge или атрибутов text / eol / идент, объединение чего-либо, если атрибут отсутствует, обычно вызывает конфликты слияния ,

Чтобы предотвратить эти ненужные конфликты слияния, git может сказать, что нужно выполнить виртуальную проверку и регистрацию всех трех этапов файла при разрешении трехстороннего слияния, задав переменную конфигурации merge.renormalize. Это предотвращает изменения, вызванные преобразованием при регистрации, из-за ложных конфликтов слияния, когда преобразованный файл объединяется с непревращенным файлом.

До тех пор, пока «smudge → clean» приводит к тому же результату, что и «clean» даже к файлам, которые уже были загрязнены, эта стратегия автоматически разрешает все конфликты, связанные с фильтрами. Фильтры, которые не действуют таким образом, могут вызвать дополнительные конфликты слияния, которые должны быть разрешены вручную.

Таким образом, выполнение этой команды в любом хранилище сделает свое дело:

git config merge.renormalize true

20
Это заслуживает того, чтобы быть ответом по умолчанию. Многое изменилось с тех пор, как вопрос был задан впервые, обработка git теперь встроена в merge.renormalize, как вы говорите.
Антон Иванович Сипос

Это просто потрясающе .. спасает мой день
Матфей



4

Что я сделал, так это оставил все по умолчанию (то есть autocrlf = true), коснулся всех файлов (найдите. -Exec touch {} \;), позволил git увидеть их как «измененные» и зафиксировать их обратно, и с этим покончено. В противном случае вы всегда будете страдать от раздражающих сообщений или неожиданных различий, или вам придется отключить все пробелы в git.

Вы потеряете информацию о вине, но лучше сделать это раньше, чем позже :)





0

Теперь мне кажется, что лучший способ - нормализовать окончания строк в обеих ветвях (и зафиксировать) перед их объединением.

Я гуглил "преобразовать crlf в lf" и нашел это как первые результаты:
http://stahlforce.com/dev/index.php?tool=remcrlf

Я скачал его и использовал, похоже, хороший инструмент.

>sfk remcr . .py

Обязательно укажите каталог и тип файла (например, .py), иначе он может попытаться возиться с содержимым .gitкаталога!


0

AFAICT, (я не пробовал), вы можете использовать, git diffчтобы сравнить ветку, которую вы хотите объединить с общим предком, а затем применить результаты git apply. Обе команды имеют --ignore-whitespaceопции, чтобы игнорировать конец строки и ошибки пробела.

К сожалению, если патч не применяется корректно, вся операция прерывается. Вы не можете исправить конфликты слияния. Существует --rejectвозможность оставить в .rejфайлах непатчимые фрагменты , что помогает, но не то же самое, что конфликты слияния, отображаемые в одном файле.


-1

После прочтения Решить конфликты слияния: принудительно перезаписать все файлы

Я наконец решил свою версию этой проблемы. Я пытался получить обновления из вышестоящего репозитория, но у моего текущего были проблемы, связанные с CRLF, и я не смог объединиться в результате. Следует отметить, что у меня не было никаких локальных изменений, о которых мне нужно было беспокоиться. Следующие шаги решили мою проблему:

В соответствии с инструкциями github по синхронизации вилок ( https://help.github.com/articles/syncing-a-fork/ ):

  1. git fetch upstream

  2. git reset --hard upstream/master
    Мое ограниченное понимание git говорит мне, что я делаю то, что хочу - перебираю свой форк (без фактических незафиксированных изменений), чтобы получить все изменения, сделанные в исходном коде. Согласно исходной странице, этот шаг обычно не требуется, но проблема CRLF сделала его обязательным.

  3. git merge upstream/master

  4. git push

1
Вы понимаете, что git reset --hard upstream/masterвыбрасываете свой местный филиал и указывает на это upstream/master, делая git merge upstream/masterнеоперативный?
Кристоффер Хаммарстрем

-1

Тем не менее, я предлагаю использовать такой инструмент, как sed, чтобы получить правильные окончания строк, а затем файлы сравнения. Я потратил пару часов на сравнивают проекты с различными окончаниями линии.

Лучший способ был:

  1. скопируйте только файлы проекта (пропустите .gitкаталог) в другой каталог, создайте в нем репозиторий, затем добавьте файлы и зафиксируйте их (должен быть в основной ветке в новом репозитории).
  2. скопируйте файлы из второго проекта в ту же папку, но в другую ветку, например dev( git checkout -b dev), зафиксируйте файлы в этой ветке и запустите (если первый проект находится в master): git diff master..dev --names-only увидеть только имена измененных файлов
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.