Git-merge 是否可以忽略行结尾的差异?

git merge有可能忽略行结尾的差异吗?

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

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

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

老实说,我并不在乎使用什么样的行结尾,我个人更喜欢 Unix 风格的 \n,但无所谓。我所关心的是,让 git merge更聪明一点,忽略行结尾的差异。

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

更新:

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

84566 次浏览

我所做的就是将所有内容保留为默认值(即 autocrlf = true) ,触摸所有文件(find)。- exec touch {} ;) ,让 git 看到它们被“修改”,并将它们提交回来,然后就可以了。否则,您将总是被烦人的消息或令人惊讶的差异所困扰,或者不得不关闭 git 的所有空格特性。

你会失去责备的信息,但是最好尽早这样做。)

2013年更新:

最近的 git 版本授权使用策略 recursive和策略 选择(-X)的 merge:

但是用“ -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配置,但是其中许多没有遵守。

提交00906d6提交8d55225第六季,第7集承认吧(2020年8月3日) by Elijah Newren (newren)
(由 朱尼奥 · C · 哈马诺 gitster于2020年8月10日在 提交4339259合并)

merge : 使 merge.renormalize适用于合并机械的所有用途

由 Elijah Newren 签名

merge”命令不是唯一执行合并的命令; 其他命令(如 checkout -m或 rebase)也执行合并。

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

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


原答案(2009年5月)

二零零七年六月中已经提出了忽略 eol 风格的补丁,但它只涉及到 git diff --ignore-space-at-eol,而不是 git merge

当时,人们提出了一个问题:

--ignore-space-at-eol应该是 git-merge的一个选项吗?
合并是这个功能的关键所在。
带有这些选项的自动解析合并的语义是什么——它们仅用于重命名检测,还是仅用空格更改来标记冲突?如果我们不接受,我们会自动接受哪个版本?

胡里奥• C •哈马诺(Julio C Hamano)对此并不热心:

这当然很诱人,但我认为这应留待以后的回合。
我怀疑它会引入两种不同差异的概念,一种是机械处理的(例如,在 merge 中使用“ git-merge-return”,并使用 “ git-am”) ,另一个需要人类检查来理解。
对于后一种情况,删除输入通常是有用的,即使比较删除的输入文件的输出可能不能很容易地用于机械应用程序。

git merge的总体思路是依靠第三方合并工具。

例如,我设置了 区分合并作为 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 配置命令:

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 是否为 false

Git 在系统级的配置:

git config ---system core.autoCRLF=false
  • 测试,当两行是相同的(但他们的 eol 字符) ,区分合并或 K扬3将忽略这些行在合并过程中。

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):

在这一点上(点击“返回”) ,将打开“区分合并”或“ KDiff3”,您将亲眼看到哪些行实际上被合并了,哪些行被忽略了。

警告 : 结果文件将始终处于 Windows eol 模式(CRLF) ,并且..。
KDiff3以这样或那样的方式提供保存。

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

我在谷歌上搜索了“将 crlf 转换为 lf”,发现第一个结果是这样的:
Http://stahlforce.com/dev/index.php?tool=remcrlf

我下载并使用了它,看起来是个不错的工具。

>sfk remcr . .py

但是,一定要指定一个目录和一个文件类型(例如。Py) ,否则它可能会试图干扰 .git目录的内容!

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

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

我在寻找同样的答案,结果找到了 这个

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

如果向文件添加了属性,导致规范的 存储库格式,以便更改该文件,例如添加一个 清除/污点过滤器或文本/eol/身份属性,合并任何东西 属性不合适的地方通常会导致合并吗 冲突。

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

只要“污迹→清洁”的结果与“清洁”的结果相同 即使在已经被弄脏的文件上,这种策略也会 自动解决所有与过滤器相关的冲突 不以这种方式操作可能会导致额外的合并冲突,这些冲突必须是 手动解决。

因此,在任何存储库中运行这个命令都可以实现以下功能:

git config merge.renormalize true

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

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

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

对我来说,这个命令完美地解决了问题:

git merge master -s recursive -X renormalize

“ git 合并-异常化”很有效。

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

我终于解决了这个问题。我试图从上游回购更新,但我目前的是有 CRLF 相关的问题,无法合并的结果。应该指出,我没有本地的变化,我需要担心。以下步骤解决了我的问题:

根据 github 关于同步叉子(https://help.github.com/articles/syncing-a-fork/)的说明:

  1. git fetch upstream


  2. 我对 git 的有限理解告诉我,这是在做我想做的事情——重新定位我的 fork (没有实际的未提交更改) ,以获得对上游源代码所做的所有更改。根据源页面,这一步骤通常不应该是必需的,但 CRLF 问题使其成为必需的。

  3. git merge upstream/master

  4. git push

然而,我建议使用工具喜欢 sed 实现正确的行结束,然后差异文件。我花了几个小时在 与众不同项目与各种行结束。

最好的办法是:

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