我不需要一个可视化的合并工具,我也不希望必须vi冲突的文件,并手动在HEAD(我的)和导入的更改(他们的)之间进行选择。大多数时候,我要么想要他们所有的更改,要么想要我所有的更改。通常情况下,这是因为我的更改是向上的,并通过拉回来给我,但可能在不同的地方略有修改。

有没有一种命令行工具可以消除冲突标记,并根据我的选择选择所有的一种方式或另一种方式?或者一组git命令,我可以别名自己做每一个。

# accept mine
alias am="some_sequence;of;commands"
alias at="some_other_sequence;of;commands"

这样做很烦人。 为了“接受我的”,我试过:

randy@sabotage ~/linus $ git merge test-branch
Auto-merging Makefile
CONFLICT (content): Merge conflict in Makefile
Automatic merge failed; fix conflicts and then commit the result.

randy@sabotage ~/linus $ git checkout Makefile 
error: path 'Makefile' is unmerged

andy@sabotage ~/linus $ git reset --hard HEAD Makefile 
fatal: Cannot do hard reset with paths.

我该怎么去掉这些变化标记呢?

我可以:

git reset HEAD Makefile; rm Makefile; git checkout Makefile

但这似乎有点绕,肯定有更好的办法。在这一点上,我不确定git是否认为合并发生了,所以我认为这不一定有效。

反过来说,“接受他们的”同样很麻烦。 我唯一能搞清楚的办法就是:

git show test-branch:Makefile > Makefile; git add Makefile;

这也给了我一个混乱的提交消息,其中两次包含Conflicts: Makefile。

谁能告诉我如何用更简单的方法来做以上两个动作?谢谢


当前回答

试试这个:

要接受他们的更改:git合并-策略-选项他们的 要接受您的更改:git合并-策略选项我们的

其他回答

解决办法很简单。Git checkout <filename>试图从索引中检出文件,因此合并失败。

你需要做的是(即签出一个提交):

要签出您自己的版本,您可以使用以下方法之一:

git checkout HEAD -- <filename>

or

git checkout --ours -- <filename>

(警告!:如果你要换基地,我们的和他们的就交换了。)

or

git show :2:<filename> > <filename> # (stage 2 is ours)

要签出另一个版本,您可以使用其中之一:

git checkout test-branch -- <filename>

or

git checkout --theirs -- <filename>

or

git show :3:<filename> > <filename> # (stage 3 is theirs)

你还需要运行'add'将其标记为已解决:

git add <filename>

根据kynan的回答,这里是相同的别名,修改后可以处理文件名中的空格和首字符:

accept-ours = "!f() { [ -z \"$@\" ] && set - '.'; git checkout --ours -- \"$@\"; git add -u -- \"$@\"; }; f"
accept-theirs = "!f() { [ -z \"$@\" ] && set - '.'; git checkout --theirs -- \"$@\"; git add -u -- \"$@\"; }; f"

根据Jakub的回答,你可以为方便配置以下git别名:

accept-ours = "!f() { git checkout --ours -- \"${@:-.}\"; git add -u \"${@:-.}\"; }; f"
accept-theirs = "!f() { git checkout --theirs -- \"${@:-.}\"; git add -u \"${@:-.}\"; }; f"

它们可以选择一个或多个文件路径来解析,如果没有给出,则默认解析当前目录下的所有文件。

将它们添加到~/的[alias]部分。Gitconfig或run

git config --global alias.accept-ours '!f() { git checkout --ours -- "${@:-.}"; git add -u "${@:-.}"; }; f'
git config --global alias.accept-theirs '!f() { git checkout --theirs -- "${@:-.}"; git add -u "${@:-.}"; }; f'

解决冲突的理想情况是,您提前知道希望以哪种方式解决冲突,并且可以传递-Xours或- xtheir递归合并策略选项。除此之外,我可以看到三个场景:

您希望只保留文件的单个版本(这应该只用于不可合并的二进制文件,否则冲突文件和非冲突文件可能会彼此不同步)。 你只想把所有的冲突都确定在一个特定的方向上。 您需要手动解决一些冲突,然后按照特定的方向解决其余所有冲突。

为了解决这三种情况,你可以在你的.gitconfig文件(或等效文件)中添加以下行:

[merge]
  conflictstyle = diff3
[mergetool.getours]
  cmd = git-checkout --ours ${MERGED}
  trustExitCode = true
[mergetool.mergeours]
  cmd = git-merge-file --ours ${LOCAL} ${BASE} ${REMOTE} -p > ${MERGED}
  trustExitCode = true
[mergetool.keepours]
  cmd = sed -i '' -e '/^<<<<<<</d' -e '/^|||||||/,/^>>>>>>>/d' ${MERGED}
  trustExitCode = true
[mergetool.gettheirs]
  cmd = git-checkout --theirs ${MERGED}
  trustExitCode = true
[mergetool.mergetheirs]
  cmd = git-merge-file --theirs ${LOCAL} ${BASE} ${REMOTE} -p > ${MERGED}
  trustExitCode = true
[mergetool.keeptheirs]
  cmd = sed -i '' -e '/^<<<<<<</,/^=======/d' -e '/^>>>>>>>/d' ${MERGED}
  trustExitCode = true

get(我们的|他们的)工具只保留文件的各自版本,并丢弃来自其他版本的所有更改(因此不会发生合并)。

The merge(ours|theirs) tool re-does the three way merge from the local, base, and remote versions of the file, choosing to resolve conflicts in the given direction. This has some caveats, specifically: it ignores the diff options that were passed to the merge command (such as algorithm and whitespace handling); does the merge cleanly from the original files (so any manual changes to the file are discarded, which could be good or bad); and has the advantage that it cannot be confused by diff markers that are supposed to be in the file.

keep(我们的|他们的)工具只是编辑出差异标记和封闭的部分,通过正则表达式检测它们。这样做的好处是保留了merge命令中的diff选项,并允许您手动解决一些冲突,然后自动解决其余冲突。它的缺点是,如果文件中有其他冲突标记,它可能会混淆。

这些都是通过运行git mergetool -t (get|merge|keep)(我们的|他们的)[<filename>]来使用的,如果没有提供<filename>,它会处理所有冲突的文件。

一般来说,假设您知道没有diff标记来混淆正则表达式,命令的keep*变体是最强大的。如果你离开合并工具。keepBackup选项未设置或为true,则合并后,您可以区分*。根据合并的结果来检查它是否有意义。作为一个例子,我在合并工具之后运行以下命令,只是为了在提交之前检查更改:

for f in `find . -name '*.orig'`; do vimdiff $f ${f%.orig}; done

注:如果合并。Conflictstyle不是diff3,那么sed规则中的/^|||||||/模式需要改为/^=======/。

试试这个:

要接受他们的更改:git合并-策略-选项他们的 要接受您的更改:git合并-策略选项我们的