git 合并文件因使用 git 显示的 bash 进程替换运算符而失败
git merge-file fails with bash process substitution operator that uses git show
我正在尝试使用三向合并将 git 中文件的更改合并到不受版本控制 () 的文件中。
因为有一个 git merge-file <local> <base> <other>
需要 3 个文件,而且我不喜欢创建中间文件并忘记清理它们,所以我使用了 bash <(...)
进程替换我经常做的操作员。
事实证明,这似乎并没有像预期的那样工作,如以下示例所示 git 2.4.2 和 2.4.3 在两个不同的系统上。
示例:
让我们为此创建一个小测试,以便我们知道我们在说什么。我们将创建一个文件 foo.txt
(git 中的文件至少有 2 个版本)和一个不受版本控制的文件 bar.txt
:
git init
echo -e 'foo\nbar' > foo.txt
git add foo.txt
git commit -m'init'
echo -e 'foo\nbar\nend' > foo.txt
git commit -a -m'end'
echo -e 'start\nfoo\nbar' > bar.txt
git show HEAD^:foo.txt > foo.txt.base
git show master:foo.txt > foo.txt.end
这给我们留下了几个如下所示的文件:
foo.txt @ HEAD^ & foo.txt.base:
foo
bar
foo.txt @master & foo.txt.end:
foo
bar
end
bar.txt:
start
foo
bar
有中间文件:
现在让我们 运行 git merge-file -p bar.txt foo.txt.base foo.txt.end
:
start
foo
bar
end
这也是我希望通过以下方法获得的输出。
使用进程替换:
但是如果我 运行: git merge-file -p bar.txt <(git show HEAD^:foo.txt) <(git show master:foo.txt)
, 我得到这个输出:
start
foo
bar
这不是预期的并且(有时!)echo $?
打印 1
指示错误。
更奇怪的是,由于我无法理解这种行为,我决定重新运行 上面的命令(向上箭头),当出现这个输出时更加困惑:
<<<<<<< bar.txt
start
foo
bar
=======
foo
bar
end
>>>>>>> /dev/fd/62
因为我真的没想到会失败,更不用说不确定了,我又 运行 几次也找到了这个输出:
<<<<<<< bar.txt
start
foo
bar
=======
>>>>>>> /dev/fd/62
为了缩小问题范围,我尝试 git merge-file -p bar.txt <(echo -e 'foo\nbar') <(echo -e 'foo\nbar\nend')
可靠地打印预期的合并:
start
foo
bar
end
问题
谁能解释一下这种奇怪的行为?
我显然可以通过不使用进程替换来修复它,但我想了解为什么会发生这种情况,因为我在很多 bash 脚本中使用了进程替换。我也对允许我仍然使用进程替换的解决方法感兴趣。
此外,如果您认为这是一个错误,我想知道它源自哪个组件:git show
、git merge-file
或 bash?
正如评论和 here 中所指出的,这可能是 <(...)
提供不支持 seek
的类似 FIFO 的文件的问题。 ZSH 中显示相同的行为,除非像这样调用:
git merge-file -p bar.txt =(git show HEAD^:foo.txt) =(git show master:foo.txt)
这意味着问题源于 git merge-file
需要它可以 seek
的文件,而 <(...)
没有提供这些文件。
我正在尝试使用三向合并将 git 中文件的更改合并到不受版本控制 (
因为有一个 git merge-file <local> <base> <other>
需要 3 个文件,而且我不喜欢创建中间文件并忘记清理它们,所以我使用了 bash <(...)
进程替换我经常做的操作员。
事实证明,这似乎并没有像预期的那样工作,如以下示例所示 git 2.4.2 和 2.4.3 在两个不同的系统上。
示例:
让我们为此创建一个小测试,以便我们知道我们在说什么。我们将创建一个文件 foo.txt
(git 中的文件至少有 2 个版本)和一个不受版本控制的文件 bar.txt
:
git init
echo -e 'foo\nbar' > foo.txt
git add foo.txt
git commit -m'init'
echo -e 'foo\nbar\nend' > foo.txt
git commit -a -m'end'
echo -e 'start\nfoo\nbar' > bar.txt
git show HEAD^:foo.txt > foo.txt.base
git show master:foo.txt > foo.txt.end
这给我们留下了几个如下所示的文件:
foo.txt @ HEAD^ & foo.txt.base:
foo
bar
foo.txt @master & foo.txt.end:
foo
bar
end
bar.txt:
start
foo
bar
有中间文件:
现在让我们 运行 git merge-file -p bar.txt foo.txt.base foo.txt.end
:
start
foo
bar
end
这也是我希望通过以下方法获得的输出。
使用进程替换:
但是如果我 运行: git merge-file -p bar.txt <(git show HEAD^:foo.txt) <(git show master:foo.txt)
, 我得到这个输出:
start
foo
bar
这不是预期的并且(有时!)echo $?
打印 1
指示错误。
更奇怪的是,由于我无法理解这种行为,我决定重新运行 上面的命令(向上箭头),当出现这个输出时更加困惑:
<<<<<<< bar.txt
start
foo
bar
=======
foo
bar
end
>>>>>>> /dev/fd/62
因为我真的没想到会失败,更不用说不确定了,我又 运行 几次也找到了这个输出:
<<<<<<< bar.txt
start
foo
bar
=======
>>>>>>> /dev/fd/62
为了缩小问题范围,我尝试 git merge-file -p bar.txt <(echo -e 'foo\nbar') <(echo -e 'foo\nbar\nend')
可靠地打印预期的合并:
start
foo
bar
end
问题
谁能解释一下这种奇怪的行为?
我显然可以通过不使用进程替换来修复它,但我想了解为什么会发生这种情况,因为我在很多 bash 脚本中使用了进程替换。我也对允许我仍然使用进程替换的解决方法感兴趣。
此外,如果您认为这是一个错误,我想知道它源自哪个组件:git show
、git merge-file
或 bash?
正如评论和 here 中所指出的,这可能是 <(...)
提供不支持 seek
的类似 FIFO 的文件的问题。 ZSH 中显示相同的行为,除非像这样调用:
git merge-file -p bar.txt =(git show HEAD^:foo.txt) =(git show master:foo.txt)
这意味着问题源于 git merge-file
需要它可以 seek
的文件,而 <(...)
没有提供这些文件。