Чи можливо для git-merge ігнорувати різниці між рядками?


150

Чи можна git mergeігнорувати відмінності між рядками?

Можливо, я задаю неправильне запитання ... але:

Я спробував uisng, config.crlf inputале все стало трохи брудно і поза контролем, особливо коли я застосував це після факту .

З одного боку, застосування цього конфігурації після факту, схоже, не впливає на файли, які були скоєні в сховищі перед застосуванням цієї опції. Інша справа, що раптом усі зобов’язання зараз призводять до того, що багато дратуючих попереджувальних повідомлень про CRLF перетворюються на LF.

Якщо чесно, мені зовсім не байдуже, що використовується лайн-енд, я особисто віддаю перевагу стилю Unix \n, але що б там не було. Мене просто хвилює, git mergeщоб бути трохи розумнішим і ігнорувати відмінності в закінченнях рядків.

Іноді у мене є два однакових файли, але git позначає їх як конфліктні (а конфлікт - це весь файл) просто тому, що вони використовують інший символ, що закінчується рядком.

Оновлення:

Я дізнався, що git diffприймає --ignore-space-at-eolваріант, чи можна було б дозволити також git mergeвикористовувати цей варіант?


28
О, я хочу. Ця річ, що закінчується річчю в git, повністю розбита
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 renormalize
    
    

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-rekursive" і застосовувати з "git-am"), а інший підлягати інспекції люди зрозуміти.
Часто може бути корисним з’єднати вхід для останнього випадку, хоча вихід із порівняння відтворених вхідних файлів може бути непридатним для механічного застосування.

Загальна ідея, якщо мова йде про те git merge, полягає в тому, щоб покластися на сторонній інструмент злиття.

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


Установка в Windows, з MSysGit1.6.3, або для DOS або Git bash сеансу, з 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 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 неправдивий

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

Я шукав ту саму відповідь , і я дізнався це

Об’єднання гілок з різними атрибутами реєстрації / оформлення замовлення

Якщо ви додали атрибути до файлу, які спричиняють зміну формату канонічного сховища для цього файлу, наприклад, додавання чистого / розмазаного фільтра або атрибутів text / eol / ident, об'єднання будь-якого місця, де атрибут не знаходиться на місці, як правило, спричинить конфлікти злиття .

Щоб запобігти цим непотрібним конфліктам злиття, git може бути запропоновано запустити віртуальну перевірку та реєстрацію всіх трьох етапів файлу при вирішенні тристороннього злиття, встановивши змінну конфігурації merge.renormalize. Це запобігає появі змін, викликаних конверсією реєстрації, викликати помилкові конфлікти злиття, коли перетворений файл об'єднується з неперетвореним файлом.

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

Таким чином, запустивши цю команду в будь-якому сховищі, виконайте свою справу:

git config merge.renormalize true

20
Тепер це заслуговує на відповідь за замовчуванням. Багато що змінилося з того часу, як було вперше задано запитання, тепер це питання вбудовано в git merge.renormalize.
Антон І. Сіпос

Це просто приголомшливо ... рятує мій день
Матфей



4

Що я зробив, це залишити все як за замовчуванням (тобто autocrlf = true), торкніться всіх файлів (find. -Exec touch {} \;), нехай git бачить їх як "модифіковані" та виконує їх назад, і роби це з цим. Інакше вам завжди або будуть мучити набридливі повідомлення чи дивовижні розбіжності, або доведеться вимкнути всі функції білого простору git.

Ви втратите інформацію про вину, але краще зробити це швидше, ніж пізніше :)





0

Мені зараз здається, що найкращим способом є нормалізація закінчень рядків на обох гілках (і фіксація) перед їх об'єднанням.

Я в Google "перетворив 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, для досягнення правильних закінчень рядків, а потім файлів diff. Я витратив пару годин на розмін проекти з різними закінченнями рядків.

Найкращим способом було:

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