167

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

也许我问错了问题......但是:

我尝试了 uisng config.crlf input,但事情变得有点混乱和失控,特别是当我在事后应用它时。

一方面,事后应用此配置似乎不会影响在应用此选项之前提交到存储库的文件。另一件事是突然间所有的提交都会导致大量关于 CRLF 被转换为 LF 的恼人警告消息。

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

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

更新:

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

4

10 回答 10

127

2013 年更新:

最新的 git 版本授权使用合并策略recursive和策略选项-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(2020 年第四季度)之前,所有内部使用合并递归机制的“合并”操作都应该遵守merge.renormalize配置,但其中许多没有。

请参阅Elijah Newren ( ) 的commit 00906d6commit 8d55225commit 6f6e7cfcommit fe48efb(2020 年 8 月 3 日(由Junio C Hamano 合并 -- --提交 4339259中,2020 年 8 月 10 日)newren
gitster

merge:merge.renormalize为合并机器的所有用途工作

签字人:以利亚·纽伦

' merge' 命令不是唯一的合并命令;其他命令如checkout -mor rebase 也可以。

不幸的是,检查“ merge.renormalize”配置设置的代码的唯一区域是 in builtin/merge.c,这意味着它只能影响由“ merge”命令执行的合并。

将此配置设置的处理移动到,merge_recursive_config()以便其他命令也可以从中受益。


原始答案(2009 年 5 月)

忽略 eol 样式的补丁已于 2007 年6 月提出,但它只关注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 上使用 MSysGit1.6.3 进行设置,用于 DOS 或 Git bash 会话,使用 DiffMerge 或 KDiff3:

  • 在您的 PATH 中设置一个目录(此处为:)c:\HOMEWARE\cmd
  • 在该目录中添加脚本 merge.sh(您最喜欢的合并工具的包装器)

合并.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 配置:

git config ---system core.autoCRLF=false
  • 测试一下,当两行相同(但它们的 eol 字符)时,DiffMerge 或 KDiff3 将在合并期间忽略这些行。

DOS脚本(注意:dos2unix命令来自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):

此时(点击“return”),DiffMerge 或 KDiff3 将打开,您将亲自查看哪些行实际合并,哪些行被忽略。

警告:结果文件将始终处于带有 DiffMerge 的 Windows eol 模式 (CRLF)...
KDiff3 提供以一种或另一种方式保存。

于 2009-05-14T11:57:44.853 回答
107

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

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

如果您向文件添加了导致该文件的规范存储库格式发生更改的属性,例如添加 clean/smudge 过滤器或 text/eol/ident 属性,则合并任何不存在该属性的内容通常会导致合并冲突.

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

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

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

git config merge.renormalize true
于 2012-08-30T10:25:38.720 回答
25

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

对我来说,这个命令完美地做到了:

git merge master -s recursive -X renormalize
于 2013-04-17T08:12:50.800 回答
7

正如这个答案:https ://stackoverflow.com/a/5262473/943928

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

于 2013-01-07T11:44:22.940 回答
4

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

你会失去责备信息,但最好早点而不是晚点:)

于 2009-05-14T08:10:40.983 回答
4

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

于 2013-09-04T21:25:09.437 回答
0

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

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

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

>sfk remcr . .py

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

于 2009-05-16T03:12:15.397 回答
0

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

不幸的是,如果补丁没有完全应用,整个操作就会中止。您无法修复合并冲突。有一个--reject选项可以在文件中保留不可修补的块.rej,这有帮助,但与在一个文件中显示合并冲突不同。

于 2010-08-23T09:49:27.900 回答
-1

阅读解决合并冲突后:强制覆盖所有文件

我终于解决了这个问题的版本。我试图从上游 repo 中提取更新,但我当前的 repo 遇到了与 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
于 2014-12-11T19:08:17.567 回答
-1

但是我建议使用像 sed 这样的工具来实现正确的行尾,然后是 diff 文件。我花了几个小时来区分具有不同行尾的项目。

最好的方法是:

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