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

Answers:


115

2013年更新:

较新的git版本授权使用带有策略合并recursive和策略选项-X):

git merge -s递归-Xignore-at-eol

但是也可以使用“ -Xignore-space-change


jakub.g评论说该策略也适用于摘樱桃

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

效果比更好ignore-all-space


原始答案(2009年5月)

已经在20076月提出了忽略eol风格的补丁,但是它只是涉及git diff --ignore-space-at-eol,而不是git merge

当时,这个问题已经提出:

应该--ignore-space-at-eol是一个选择git-merge吗?
合并是此功能很重要的地方。
具有这些选项的自动解析合并的语义是什么-它们仅用于重命名检测,还是我们(例如,仅标记空格更改而不标记冲突)?如果我们不接受,我们会自动接受哪个版本?

Julio C Hamano并非完全热情:

这当然很诱人,但我怀疑应该留待以后的回合。
我怀疑它会引入两种不同的差异的概念,一种进行机械处理(即与“ git-merge-recursive”合并使用,并与“ git-am”结合使用),另一种将由人类了解。
即使比较比较杂乱的输入文件的输出对于机械应用而言可能不容易使用,但为后一种情况调整输入通常可能很有用。

谈到时,通常的想法git merge是依靠第三方合并工具。

例如,我将DiffMerge设置为Git合并的工具,并设置了一个规则集,该规则集允许该合并工具忽略某些类型文件的eol。


在Windows上使用DiffMerge或KDiff3使用MSysGit1.6.3在DOS或Git bash会话上进行安装:

  • 在您的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命令来自此处,用于模拟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将打开,您将自己看到实际上合并了哪些行,而忽略了哪些行。

警告:使用DiffMerge,结果文件将始终处于Windows eol模式(CRLF)...
KDiff3提供了一种或多种保存方式。


谢谢你的小费!Mac中的Meld和FileMerge似乎也是很棒的应用程序。
莱奥波德·赫兹(LéoLéopoldHertz),2009年

1
信息方面,该策略还适用于“ 采摘樱桃”:( git cherry-pick abcd123456 --strategy=recursive --strategy-option=renormalize 这比效果更好ignore-all-space
jakub.g 2014年

1
@ jakub.g好点!我将其包含在答案中以提高可见性。
VonC 2014年

98

我一直在寻找相同的答案,我发现了这个

合并具有不同签入/签出属性的分支

如果您已向文件中添加了导致该文件的标准存储库格式更改的属性,例如添加了干净/污迹过滤器或文本/ eol / ident属性,则将属性不存在的任何内容合并通常会导致合并冲突。

为了防止这些不必要的合并冲突,在通过设置merge.renormalize配置变量来解决三向合并时,可以告诉git对文件的所有三个阶段运行虚拟检出和检入。当转换后的文件与未转换的文件合并时,这可以防止由签入转换引起的更改引起虚假合并冲突。

只要“涂抹→清除”结果与“清除”结果相同,即使在已经被涂抹的文件上,此策略也会自动解决所有与过滤器相关的冲突。不以此方式起作用的过滤器可能会导致其他合并冲突,必须手动解决。

因此,在任何存储库中运行此命令将达到目的:

git config merge.renormalize true

20
现在应该将其作为默认答案。自从首次提出问题以来,情况已经发生了很大的变化,正如您所说的那样,git的处理现在内置在merge.renormalize中。
安东·西波斯

这真是太棒了..拯救我的一天
matthaeus



4

我所做的就是将所有内容保留为默认值(即autocrlf = true),触摸所有文件(查找。-exec touch {} \ ;;),让git将它们视为“已修改”并提交回去,然后完成。否则,您总是会被烦人的消息或令人惊讶的差异所困扰,或者不得不关闭git的所有空白功能。

您会丢失责备信息,但最好尽早进行:)


4

“ git merge -Xrenormalize”的工作原理很吸引人。




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关于同步fork的说明(https://help.github.com/articles/syncing-a-fork/):

  1. git fetch upstream

  2. git reset --hard upstream/master
    我对git的有限了解告诉我,这是我想要的工作-重新整理fork(没有实际的未提交的更改)以获取对上游源所做的所有更改。根据源页面,通常不需要执行此步骤,但是由于CRLF问题而要求执行此步骤。

  3. git merge upstream/master

  4. git push

1
您意识到git reset --hard upstream/master丢弃了本地分支并将其指向upstream/master,因此git merge upstream/master没有操作吗?
ChristofferHammarström,2015年

-1

但是我建议使用sed之类的工具来实现正确的行尾,然后比较文件。我花了几个小时的版本比较各种行结尾的项目。

最好的方法是:

  1. 仅将项目文件(省略.git目录)复制到另一个目录中,在其中创建存储库,然后添加文件并提交(应位于新存储库的master分支上)。
  2. 将文件从第二个项目复制到相同的文件夹,但是另一个分支(例如devgit checkout -b dev),在该分支上提交文件并运行(如果第一个项目在master中): git diff master..dev --names-only 仅查看已更改文件的名称
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.