【问题标题】:Is it possible for git-merge to ignore line-ending differences?git-merge 是否可以忽略行尾差异?
【发布时间】:2010-10-26 02:36:22
【问题描述】:

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

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

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

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

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

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

更新:

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

【问题讨论】:

  • 哦,我希望。 git 中的这一行结束的东西完全坏了
  • 看起来这不能直接完成,但这篇文章建议解决方法。 osdir.com/ml/git/2009-02/msg02532.html
  • 刚刚添加了一个测试用例,说明那些第三方合并工具在合并过程中会忽略 eol 样式
  • stahlforce.com/dev/index.php?tool=remcrlf 我试过了,但是如果在代码的最后一行之后你还没有 CRLF,它会自己添加一个 LF,并且文件在 git 中看起来会发生变化。除此之外它还有效。
  • 所以,澄清一下(据我所知):没有办法让 git 忽略 CR,但抱怨所有其他尾随空格?

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


【解决方案1】:

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

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

【讨论】:

    【解决方案2】:

    2013 年更新:

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

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

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

    jakub.g 还有comments策略也适用于樱桃采摘

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

    这比ignore-all-space好得多。


    在 Git 2.29(2020 年第四季度)之前,所有内部使用合并递归机制的“合并”操作都应遵循 merge.renormalize 配置,但其中许多没有。

    参见Elijah Newren (newren)commit 00906d6commit 8d55225commit 6f6e7cfcommit fe48efb(2020 年 8 月 3 日)。
    (由 Junio C Hamano -- gitster -- 合并到 commit 4339259,2020 年 8 月 10 日)

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

    签字人:Elijah Newren

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

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

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


    原始答案(2009 年 5 月)

    忽略eol样式的补丁已经在June 2007提出,但它只涉及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(您最喜欢的合并工具的包装器)

    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 配置:

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

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

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

    【讨论】:

    • 感谢您的提示! Mac 中的 Meld 和 FileMerge 似乎也是很棒的应用程序。
    • 对于信息,该策略也适用于 cherry-pickinggit cherry-pick abcd123456 --strategy=recursive --strategy-option=renormalize(这比 ignore-all-space 效果更好)
    • @jakub.g 好点!我已将其包含在答案中以提高知名度。
    【解决方案3】:

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

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

    我下载并使用了,感觉是个不错的工具。

    >sfk remcr . .py
    

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

    【讨论】:

      【解决方案4】:

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

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

      【讨论】:

        【解决方案5】:

        我一直在寻找相同的答案,我发现this

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

        如果您在文件中添加了导致规范的属性 要更改该文件的存储库格式,例如添加 clean/smudge filter 或 text/eol/ident 属性,合并任何东西 属性不存在的地方通常会导致合并 冲突。

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

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

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

        git config merge.renormalize true
        

        【讨论】:

        • 这现在应该成为默认答案。自从第一次提出这个问题以来已经发生了很大变化,git 对此的处理现在内置于 merge.renormalize 正如你所说的那样。
        • 这太棒了..节省了我的一天
        【解决方案6】:

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

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

        【讨论】:

          【解决方案7】:

          看完https://stackoverflow.com/a/12194759/1441706https://stackoverflow.com/a/14195253/1441706

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

          git merge master -s recursive -X renormalize
          

          【讨论】:

            【解决方案8】:

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

            【讨论】:

              【解决方案9】:

              看完Resolve merge conflicts: Force overwrite all files

              我终于解决了这个问题的版本。我试图从上游 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

              【讨论】:

              • 您意识到git reset --hard upstream/master 会丢弃您的本地分支并将其指向upstream/master,从而使git merge upstream/master 成为空操作?
              【解决方案10】:

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

              最好的办法是:

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

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 2012-01-02
                • 1970-01-01
                • 2011-02-05
                • 2016-05-26
                • 2023-01-30
                相关资源
                最近更新 更多