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

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

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

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

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

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

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

Обновлять:

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


person hasen    schedule 14.05.2009    source источник
comment
О, я бы хотел. Эта строка, заканчивающаяся в git, полностью сломана   -  person 1800 INFORMATION    schedule 14.05.2009
comment
Не похоже, что это можно сделать напрямую, но этот пост предлагает обходной путь. osdir.com/ml/git/2009-02/msg02532.html   -  person Dean Smith    schedule 14.05.2009
comment
Просто добавлен тестовый пример, показывающий, что сторонний инструмент слияния игнорирует стиль eol во время слияния.   -  person VonC    schedule 14.05.2009
comment
stahlforce.com/dev/index.php?tool=remcrlf Я попробовал , но если после последней строки в вашем коде у вас еще не было CRLF, он сам добавляет LF, и файл выглядит измененным в git. В остальном это работает.   -  person antman    schedule 24.01.2011
comment
Итак, чтобы уточнить (из того, что я могу определить): нет способа заставить git игнорировать CR, но жаловаться на все остальные конечные пробелы?   -  person Stephen    schedule 01.08.2014
comment
Обязательно ознакомьтесь с приведенным ниже ответом о git config merge.renormalize true   -  person qneill    schedule 10.02.2020


Ответы (10)


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

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

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

  • Fab-V упоминает ниже:
    git merge master -s recursive -X renormalize
    

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

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

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


До Git 2.29 (4 квартал 2020 г.) все операции слияния, которые внутренне используют рекурсивный механизм слияния, должны учитывать конфигурацию merge.renormalize, но многие из них этого не делали.

См. commit 00906d6, совершить 8d55225, Элайджа Ньюрен (newren).
(Объединено пользователем Junio ​​C Hamano - gitster - в фиксации 4339259 , 10 авг.2020 г.)

merge: заставьте merge.renormalize работать для всех видов использования механизмов слияния

Подписал: Элайджа Ньюрен

Команда «merge» - не единственная, которая выполняет слияние; другие команды, такие как checkout -m или rebase, тоже.

К сожалению, единственная область кода, которая проверяла параметр конфигурации merge.renormalize, находилась в builtin/merge.c, что означает, что это может повлиять только на слияние, выполняемое командой merge.

Переместите обработку этого параметра конфигурации на merge_recursive_config(), чтобы другие команды также могли получить от него пользу.


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

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

Тогда был задан вопрос:

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

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

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

Общая идея, когда дело доходит до git merge, - полагаться на сторонний инструмент слияния.

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


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

  • установите каталог в свой PATH (здесь: 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:

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 ложь

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

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

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

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 предлагает сохранить тем или иным способом.

person VonC    schedule 14.05.2009
comment
Спасибо за совет! Meld и FileMerge на Mac тоже кажутся отличными приложениями. - person Léo Léopold Hertz 준영; 26.05.2009
comment
Для информации, стратегии также работают с сбором вишен: git cherry-pick abcd123456 --strategy=recursive --strategy-option=renormalize (это работает намного лучше, чем ignore-all-space) - person jakub.g; 10.10.2014
comment
@ jakub.g хороший момент! Я включил его в ответ для большей наглядности. - person VonC; 10.10.2014

Я искал тот же ответ и обнаружил это

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

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

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

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

Так что запуск этой команды в любом репозитории поможет:

git config merge.renormalize true
person Fabio    schedule 30.08.2012
comment
Теперь это заслуживает того, чтобы быть ответом по умолчанию. Многое изменилось с тех пор, как вопрос был задан впервые, обработка этого git теперь встроена в merge.renormalize, как вы говорите. - person Anton I. Sipos; 24.10.2012
comment
Это просто здорово .. спасает мне день - person matthaeus; 15.02.2019

После прочтения https://stackoverflow.com/a/12194759/1441706 и https://stackoverflow.com/a/14195253/1441706

для меня эта команда отлично справилась:

git merge master -s recursive -X renormalize
person Fab V.    schedule 17.04.2013

Как в этом ответе: https://stackoverflow.com/a/5262473/943928

Вы можете попробовать: git merge -s recursive -Xignore-space-at-eol

person Rune Schjellerup Philosof    schedule 07.01.2013

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

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

person Ben Hymers    schedule 14.05.2009

"git merge -Xrenormalize" работает как шарм.

person Jake    schedule 04.09.2013

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

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

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

>sfk remcr . .py

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

person hasen    schedule 16.05.2009

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

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

person rjmunro    schedule 23.08.2010

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

Я наконец решил свою версию этой проблемы. Я пытался получить обновления из вышестоящего репозитория, но у моего текущего были проблемы, связанные с 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
person propagated    schedule 11.12.2014
comment
Вы понимаете, что git reset --hard upstream/master отбрасывает вашу локальную ветку и указывает на upstream/master, что делает git merge upstream/master закрытым? - person Christoffer Hammarström; 05.11.2015

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

Лучше всего было:

  1. скопируйте только файлы проекта (опустите каталог .git) в другой каталог, создайте в нем репозиторий, затем добавьте файлы и зафиксируйте их (они должны быть в главной ветке в новом репозитории).
  2. скопируйте файлы из второго проекта в ту же папку, но в другую ветку, например dev (git checkout -b dev), зафиксируйте файлы в этой ветке и запустите (если первый проект находится в главном): git diff master..dev --names-only, чтобы увидеть только имена измененных файлов
person user4686964    schedule 18.03.2015