git-merge是否可以忽略行尾差异?

时间:2009-05-14 07:25:05

标签: git merge git-svn line-endings eol

git merge是否可以忽略行尾差异?

也许我问的是错误的问题......但是:

我试过了config.crlf input,但事情变得有些混乱和失控,特别是当我在事实之后应用时。

首先,在应用此选项之后,在事实之后应用此配置似乎不会影响已提交到存储库的文件。另一件事是突然所有提交现在导致许多关于CRLF被转换为LF的恼人警告消息。

老实说,我并不关心使用什么行结尾,我个人更喜欢Unix风格\n,但无论如何。我所关心的只是让git merge变得更聪明,而忽略了行尾的差异。

有时我有两个相同的文件,但是git会将它们标记为冲突(并且冲突是整个文件),因为它们使用不同的行结束符。

更新

我发现git diff接受--ignore-space-at-eol选项,是否可以让git merge使用此选项?

12 个答案:

答案 0 :(得分:105)

2013年更新:

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

git merge -s recursive -Xignore-space-at-eol

但使用“-Xignore-space-changeis also a possibility

  • Fab-V提及below
    git merge master -s recursive -X renormalize
    
    

jakub.gcomments 策略也适用于挑选

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

这比ignore-all-space好得多。


原始答案(2009年5月)

June 2007中提出了忽略eol风格的补丁,但它仅涉及git diff --ignore-space-at-eol,而不关注git merge

当时,问题已被搁置:

  

--ignore-space-at-eolgit-merge的选项吗?   合并是这个功能很重要的地方   自动解析合并的语义与那些有效的选项有什么关系 - 它们仅用于重命名检测,还是我们,例如,不标记只有空格更改的冲突?如果我们不这样做,我们会自动接受哪个版本?

Julio C Hamano并不是很热心:

  

这当然很诱人,但我怀疑应该留待以后的轮次   我怀疑它会引入两种不同类型的差异的概念,一种是机械处理的(即与“git-merge-recursive”合并使用),并适用于   “git-am”),另一个被人类检查以便理解   尽管比较munged输入文件的输出可能不容易用于机械应用,但通常对后一种情况的输入很有用。

关于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 command comes from here,用于模拟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提供以某种方式保存。

答案 1 :(得分:89)

我正在寻找相同的答案,我发现了this

  

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

     

如果您已将属性添加到导致规范的文件中   要更改的文件的存储库格式,例如添加   清理/涂抹过滤器或text / eol / ident属性,合并任何东西   属性不存在的地方通常会导致合并   冲突。

     

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

     

只要“涂抹→清洁”产生与“干净”相同的输出   即使是已经弄脏的文件,这个策略也会   自动解决所有与过滤器相关的冲突。做的过滤器   不以这种方式行事可能会导致必须的额外合并冲突   手动解决。

因此,在任何存储库中运行此命令都可以解决问题:

git config merge.renormalize true

答案 2 :(得分:21)

阅读https://stackoverflow.com/a/12194759/1441706https://stackoverflow.com/a/14195253/1441706

对我来说,这个命令完美地完成了这个技巧:

git merge master -s recursive -X renormalize

答案 3 :(得分:6)

在答案中:https://stackoverflow.com/a/5262473/943928

您可以尝试:git merge -s recursive -Xignore-space-at-eol

答案 4 :(得分:4)

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

你会失去责备信息,但最好早点而不是以后做这件事:)

答案 5 :(得分:4)

“git merge -Xrenormalize”就像魅力一样。

答案 6 :(得分:1)

看起来这不能直接完成,但这篇文章建议解决。

http://osdir.com/ml/git/2009-02/msg02532.html

答案 7 :(得分:1)

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

我试了一下,但是如果你的代码中的最后一行之后你还没有CRLF它会自己添加一个LF并且文件看起来在git中发生了变化。 除此之外它还有效。

答案 8 :(得分:0)

现在在我看来,最好的方法是在合并它们之前规范化两个分支(和提交)上的行结尾。

我用谷歌搜索“将crlf转换为lf”并发现这是第一个结果:
http://stahlforce.com/dev/index.php?tool=remcrlf

我下载并使用,似乎是一个不错的工具。

>sfk remcr . .py

请确保指定目录和文件类型(例如.py),否则可能会尝试弄乱.git目录的内容!

答案 9 :(得分:0)

AFAICT,(我还没试过)您可以使用git diff来比较要合并到共同祖先的分支,然后使用git apply应用结果。这两个命令都有--ignore-whitespace个选项来忽略行结尾和空格错误。

不幸的是,如果补丁不能干净地应用,整个操作就会中止。您无法修复合并冲突。有一个--reject选项可以在.rej文件中保留不可修补的数据库,这有助于,但与在一个文件中显示合并冲突不同。

答案 10 :(得分:-1)

阅读Resolve merge conflicts: Force overwrite all files

我终于解决了这个问题的版本。我试图从上游回购中提取更新,但我当前的更新有CRLF相关问题,因此无法合并。应该注意的是,我无需担心本地更改。以下步骤解决了我的问题:

根据github关于同步分叉的说明(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

答案 11 :(得分:-1)

但是我建议使用像sed这样的工具来实现正确的行结尾,然后使用diff文件。我花了几个小时在各种行结尾的 diffing 项目上。

最好的方法是:

  1. 仅将项目文件(省略.git目录)复制到另一个目录中创建存储库,然后添加文件并提交它们(应该在新存储库的主分支上)。
  2. 将文件从第二个项目复制到同一个文件夹,但是另一个分支,例如devgit checkout -b dev),在此分支上提交文件并运行(如果第一个项目在master中):        git diff master..dev --names-only 仅查看已更改文件的名称