使用git在整个文件上“接受他们”或“接受我的”的简单工具

时间:2009-05-27 10:06:53

标签: git merge

我不想要一个可视化合并工具,而且我也不希望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;

这也给了我一个混乱的提交消息,它有两次冲突:Makefile。

有人可以指出如何以更简单的方式执行上述两项操作吗?感谢

5 个答案:

答案 0 :(得分:547)

解决方案非常简单。 git checkout <filename>尝试从索引检出文件,因此在合并时失败。

您需要做的是(即结帐提交):

要结帐自己的版本,您可以使用一个

git checkout HEAD -- <filename>

git checkout --ours -- <filename>

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

要结帐其他版本,您可以使用一个

git checkout test-branch -- <filename>

git checkout --theirs -- <filename>

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

您还需要运行“添加”以将其标记为已解决:

git add <filename>

答案 1 :(得分:63)

试试这个:

接受他们的更改:git merge --strategy-option theirs

接受你的:git merge --strategy-option ours

答案 2 :(得分:48)

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

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

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

将它们添加到[alias]的{​​{1}}部分或运行

~/.gitconfig

答案 3 :(得分:16)

基于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"

答案 4 :(得分:0)

解决冲突的理想情况是,您提前知道要解决冲突的方式,并且可以通过-Xours-Xtheirs递归合并策略选项。在此之外,我可以看到三个方案:

  1. 您只想保留文件的单个版本(此文件可能仅应用于不可合并的二进制文件,因为否则冲突和非冲突的文件可能会彼此不同步)。
  2. 您只想简单地确定特定方向上的所有冲突。
  3. 您需要手动解决一些冲突,然后再按特定方向解决所有其他冲突。

要解决这三种情况,您可以将以下行添加到.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(ours|theirs)工具仅保留文件的相应版本,并丢弃其他版本的所有更改(因此不会发生合并)。

merge(ours|theirs)工具从文件的本地,基本和远程版本重新进行三种方式的合并,选择解决给定方向上的冲突。具体来说,有一些警告:它忽略了传递给merge命令的diff选项(例如算法和空白处理);从原始文件中干净地进行合并(因此,对文件的任何手动更改都将被丢弃,可能是好是坏);并具有不能与文件中的差异标记混淆的优点。

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

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

通常来说,假设您知道没有差异标记会混淆正则表达式,则该命令的keep*变体是最强大的。如果您未设置mergetool.keepBackup选项或设置为true,则在合并之后,您可以将*.orig文件与合并结果进行比较以检查其是否有意义。例如,我在mergetool之后运行以下命令,只是在提交之前检查更改:

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

注意:如果merge.conflictstyle不是diff3,则/^|||||||/规则中的sed模式需要为/^=======/代替。