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

发布于 2024-07-19 17:22:25 字数 547 浏览 17 评论 0原文

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

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

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

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

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

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

更新:

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

Is it possible for git merge to ignore line-ending differences?

Maybe I'm asking the wrong question ... but:

I tried uisng config.crlf input but things got a bit messy and out of control, specially when I applied it after the fact.

For one thing, applying this config after the fact doesn't seem to affect files that were committed to the repository before applying this option. Another thing is that suddenly all commits now result in lots of annoying warning messages about CRLF being converted to LF.

To be honest, I don't really care what line-ending is used, I personally prefer the Unix style \n, but whatever. All I care about, is for git merge to be a bit smarter and ignore the differences in line-endings.

Sometimes I have two identical files, but git would mark them as being in conflict (and the conflict is the whole file) simply because they use a different line ending character.

Update:

I found out that git diff accepts a --ignore-space-at-eol option, would it be possible to let git merge use this option as well?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(10

梦萦几度 2024-07-26 17:22:25

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

对我来说,这个命令完美地完成了任务:

git merge master -s recursive -X renormalize

After reading https://stackoverflow.com/a/12194759/1441706 and https://stackoverflow.com/a/14195253/1441706

for me, this command did the trick perfectly:

git merge master -s recursive -X renormalize
吐个泡泡 2024-07-26 17:22:25

不过我建议使用 sed 等工具来实现正确的行结尾,然后比较文件。 我花了几个小时来比较具有不同行结尾的项目。

最好的方法是:

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

however i suggest to use tool like sed to achieve correct line endings, and then diff files. I spent couple hours on diffing projects with various line endings.

The best way was to:

  1. copy only project files (omit .git directory) to another directory create repository in it, then add files and commit them (should be on master branch in new repository).
  2. copy files from second project to same folder, but another branch for example dev (git checkout -b dev), commit files on this branch and run (if first project is in master):
    git diff master..dev --names-only
    to see names of changed files only
花桑 2024-07-26 17:22:25

2013 年更新:

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

请参阅 提交 00906d6提交 8d55225, 提交 6f6e7cf,提交 fe48efb(2020 年 8 月 3 日),作者:伊利亚·纽伦 (newren)
(由 Junio C Hamano -- gitster -- 合并于 提交 4339259,2020 年 8 月 10 日)

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

签字人:伊利亚·纽伦

merge”命令并不是唯一进行合并的命令; 其他命令如 checkout -m 或 rebase 也可以。

不幸的是,检查“merge.renormalize”配置设置的代码的唯一区域位于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 (您最喜欢的合并工具的包装器)

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 config ---system core.autoCRLF=false
  • git config: 测试一下,当两个行是相同的(但它们的 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):

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

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

Update 2013:

More recent git versions authorize using merge with strategy recursive and strategy option (-X):

But using "-Xignore-space-change" is also a possibility

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

jakub.g also comments that the strategies work also with cherry-picking:

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

This works much better than ignore-all-space.


Before Git 2.29 (Q4 2020), All "mergy" operations that internally use the merge-recursive machinery should honor the merge.renormalize configuration, but many of them didn't.

See commit 00906d6, commit 8d55225, commit 6f6e7cf, commit fe48efb (03 Aug 2020) by Elijah Newren (newren).
(Merged by Junio C Hamano -- gitster -- in commit 4339259, 10 Aug 2020)

merge: make merge.renormalize work for all uses of merge machinery

Signed-off-by: Elijah Newren

The 'merge' command is not the only one that does merges; other commands like checkout -m or rebase do as well.

Unfortunately, the only area of the code that checked for the "merge.renormalize" config setting was in builtin/merge.c, meaning it could only affect merges performed by the "merge" command.

Move the handling of this config setting to merge_recursive_config() so that other commands can benefit from it as well.


Original answer (May 2009)

The patch for ignoring eol style has been proposed in June 2007, but it only concerns git diff --ignore-space-at-eol, not git merge.

At the time, the question has been askeed:

Should --ignore-space-at-eol be an option to git-merge ?
Merges are where this functionality matters.
What are the semantics of an auto-resolved merge with those options in effect -- are they only used for rename detection, or do we, e.g., not flag conflicts with only whitespace changes ? And if we don't, which version do we accept automatically ?

Julio C Hamano was not exactly enthusiastic:

This certainly is tempting, but I suspect that should be left to later rounds.
I suspect that it would introduce a concept of two different kinds of diffs, one to be mechanically processed (i.e. use in merge with "git-merge-recursive", and apply with
"git-am"), and another to be inspected by humans to understand.
It often may be useful to munge the input for the latter case, even though the output from comparing munged input files may not be readily usable for mechanical application.

The general idea, when it comes to git merge, is to rely on the third-party merge tool.

For instance, I have setup DiffMerge to be the tool for Git merge, setting a ruleset which allow that merge tool to ignore eol for certain type of files.


Setup on Windows, with MSysGit1.6.3, either for DOS or Git bash session, with DiffMerge or KDiff3:

  • set a directory into your PATH (here: c:\HOMEWARE\cmd).
  • add in that directory the script merge.sh (wrapper for your favorite merge tool)

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
  • Declare your merge wrapper for Git

Git config commands:

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
  • Check that autoCRLF is false

git config at system level:

git config ---system core.autoCRLF=false
  • Test that, when two lines are identical (but their eol chars), both DiffMerge or KDiff3 will ignore those line during a merge.

DOS script (note: the dos2unix command comes from here, and is used to simulate a Unix eol-style. That command has been copied in the directory mentioned at the beginning of this answer.):

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

At this point (Hitting "return"), DiffMerge or KDiff3 will open, and you will see for yourself what lines are actually merged, and what lines are ignored.

Warning: the result file will always be in Windows eol mode (CRLF) with DiffMerge...
KDiff3 offers to save in one way or another.

天暗了我发光 2024-07-26 17:22:25

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

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

如果您向文件添加了导致规范的属性
要更改该文件的存储库格式,例如添加
清洁/涂抹过滤器或文本/eol/ident 属性,合并任何内容
属性不存在的地方通常会导致合并
冲突。

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

只要“smudge→clean”会产生与“clean”相同的输出
即使对于已经被弄脏的文件,此策略也将
自动解决所有与过滤器相关的冲突。 过滤器可以做到
不以这种方式行事可能会导致额外的合并冲突,必须
手动解决。

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

git config merge.renormalize true

I was looking for the same answer and I found out this

Merging branches with differing checkin/checkout attributes

If you have added attributes to a file that cause the canonical
repository format for that file to change, such as adding a
clean/smudge filter or text/eol/ident attributes, merging anything
where the attribute is not in place would normally cause merge
conflicts.

To prevent these unnecessary merge conflicts, git can be told to run a
virtual check-out and check-in of all three stages of a file when
resolving a three-way merge by setting the merge.renormalize
configuration variable. This prevents changes caused by check-in
conversion from causing spurious merge conflicts when a converted file
is merged with an unconverted file.

As long as a "smudge→clean" results in the same output as a "clean"
even on files that are already smudged, this strategy will
automatically resolve all filter-related conflicts. Filters that do
not act in this way may cause additional merge conflicts that must be
resolved manually.

So running this command in any repository will do the trick:

git config merge.renormalize true
笑忘罢 2024-07-26 17:22:25

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

你可以尝试: git合并-s递归-Xignore-space-at-eol

As in this answer: https://stackoverflow.com/a/5262473/943928

You could try: git merge -s recursive -Xignore-space-at-eol

墨小沫ゞ 2024-07-26 17:22:25

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

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

What I did was leave everything as default (i.e. autocrlf=true), touch all files (find . -exec touch {} \;), let git see them as 'modified' and commit them back, and be done with it. Otherwise you'll always either be plagued by annoying messages or surprising differences, or have to turn off all of git's whitespace features.

You'll lose blame information, but it's better to do it sooner rather than later :)

最好是你 2024-07-26 17:22:25

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

"git merge -Xrenormalize" works like a charm.

手心的温暖 2024-07-26 17:22:25

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

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

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

>sfk remcr . .py

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

It seems to me now that the best way is to normalized the line endings on both branches (and commit) before merging them.

I googled "convert crlf to lf" and found this as the first results:
http://stahlforce.com/dev/index.php?tool=remcrlf

I downloaded it and used, seems like a nice tool.

>sfk remcr . .py

Be sure though to specify a directory and a file type (e.g. .py) otherwise it might try to mess with the contents of the .git directory!

川水往事 2024-07-26 17:22:25

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

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

AFAICT, (I haven't tried it) you could use git diff to compare the branch you want to merge to the common ancestor, then apply the results with git apply. Both commands have --ignore-whitespace options to ignore line ending and white space errors.

Unfortunately, if the patch doesn't apply cleanly, the whole operation is aborted. You can't fix merge conflicts. There is a --reject option to leave unpatchable hunks in .rej files, which helps, but isn't the same as having the merge conflicts shown in one file.

银河中√捞星星 2024-07-26 17:22:25

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

我终于解决了这个问题的版本。 我试图从上游存储库中提取更新,但我当前的存储库存在 CRLF 相关问题,因此无法合并。 应该指出的是,我没有需要担心的局部变化。 以下步骤解决了我的问题:

按照 github 关于同步分叉的说明 (https:// help.github.com/articles/syncing-a-fork/):

  1. git fetchupstream

  2. git重置--hard上游/master
    我对 git 的有限理解告诉我,这正在做我想做的事——重新调整我的分支(没有实际未提交的更改)以获得对上游源代码所做的所有更改。 根据源页面,通常不需要此步骤,但 CRLF 问题使其成为必需。

  3. git 合并上游/master

  4. git Push

After reading Resolve merge conflicts: Force overwrite all files

I finally resolved my version of this issue. I was trying to pull updates from the upstream repo but my current one was having CRLF related issues and was unable to merge as result. It should be noted I had NO LOCAL CHANGES i needed to worry about. The following steps resolved my issue:

As per github's instructions on syncing forks (https://help.github.com/articles/syncing-a-fork/):

  1. git fetch upstream

  2. git reset --hard upstream/master
    My limited understanding of git tells me this is doing what i want-- rebasing my fork (with no actual uncommitted changes) to gain all the changes made to the upstream source. According to the source page, this step should normally not be required, but the CRLF issue made it required.

  3. git merge upstream/master

  4. git push
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文