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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/914939/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-10 06:30:37  来源:igfitidea点击:

Simple tool to 'accept theirs' or 'accept mine' on a whole file using git

gitmerge

提问by nosatalian

I don't want a visual merge tool, and I also don't want to have to vi the conflicted file and manually choose the between HEAD (mine) and the imported change (theirs). Most of the time I either want all of their changes or all of mine. Commonly this is because my change made it upsteam and is coming back to me through a pull, but may be slightly modified in various places.

我不想要一个可视化合并工具,而且我也不想在冲突文件中手动选择 HEAD(我的)和导入的更改(他们的)。大多数时候,我要么想要他们的所有更改,要么想要我的所有更改。通常,这是因为我的更改使其上游并通过拉动返回给我,但可能在各个地方略有修改。

Is there a command line tool which will get rid of the conflict markers and choose all one way or another based on my choice? Or a set of git commands which I can alias myself to do each one.

是否有命令行工具可以摆脱冲突标记并根据我的选择选择所有方式?或者一组 git 命令,我可以用别名来做每一个。

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

Doing this is rather annoying. For 'accept mine' I have tried:

这样做相当烦人。对于“接受我的”,我尝试过:

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.

How am I supposed to get rid of these change markers?

我应该如何摆脱这些更改标记?

I can do:

我可以:

git reset HEAD Makefile; rm Makefile; git checkout Makefile

But this seems rather round about, there must be a better way. And at this point, I'm not sure if git even thinks the merge happened, so I don't think this necessarily even works.

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

Going the other way, doing 'accept theirs' is equally messy. The only way I can figure it out is do:

反过来说,“接受他们的”同样是一团糟。我能弄清楚的唯一方法是:

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

This also gives me a messed up commit message, which has Conflicts: Makefile in it twice.

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

Can someone please point out how to do the above two actions in a simpler way? Thanks

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

回答by Jakub Nar?bski

The solution is very simple. git checkout <filename>tries to check out file from the index, and therefore fails on merge.

解决方法很简单。git checkout <filename>尝试从index检出文件,因此合并失败。

What you need to do is (i.e. checkout a commit):

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

To checkout your own versionyou can use oneof:

要检查您自己的版本,您可以使用以下之一

git checkout HEAD -- <filename>

or

或者

git checkout --ours -- <filename>

or

或者

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

To checkout the other versionyou can use oneof:

要签出其他版本,您可以使用以下之一

git checkout test-branch -- <filename>

or

或者

git checkout --theirs -- <filename>

or

或者

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

You would also need to run 'add' to mark it as resolved:

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

git add <filename>

回答by Siva Mandadi

Try this:

尝试这个:

To accept theirs changes: git merge --strategy-option theirs

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

To accept yours: git merge --strategy-option ours

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

回答by kynan

Based on Jakub's answer you can configure the following git aliases for convenience:

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

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

They optionally take one or several paths of files to resolve and default to resolving everything under the current directory if none are given.

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

Add them to the [alias]section of your ~/.gitconfigor run

将它们添加到[alias]您的~/.gitconfig或运行的部分

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'

回答by Dar

Based on kynan's answer, here are the same aliases, modified so they can handle spaces and initial dashes in filenames:

根据 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"

回答by Parakleta

The ideal situation for resolving conflicts is when you know ahead of time which way you want to resolve them and can pass the -Xoursor -Xtheirsrecursive merge strategy options. Outside of this I can see three scenarious:

解决冲突的理想情况是当您提前知道要解决它们的方式并且可以传递-Xours-Xtheirs递归合并策略选项时。除此之外,我可以看到三个场景:

  1. You want to just keep a single version of the file (this should probably only be used on unmergeable binary files, since otherwise conflicted and non-conflicted files may get out of sync with each other).
  2. You want to simply decide all of the conflicts in a particular direction.
  3. You need to resolve some conflicts manually and then resolve all of the rest in a particular direction.
  1. 您只想保留文件的单个版本(这可能只应用于不可合并的二进制文件,否则冲突和非冲突文件可能会彼此不同步)。
  2. 您只想简单地决定特定方向上的所有冲突。
  3. 您需要手动解决一些冲突,然后在特定方向解决所有其余冲突。

To address these three scenarios you can add the following lines to your .gitconfigfile (or equivalent):

要解决这三种情况,您可以将以下几行添加到您的.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

The get(ours|theirs)tool just keeps the respective version of the file and throws away all of the changes from the other version (so no merging occurs).

get(ours|theirs)工具仅保留文件的相应版本并丢弃其他版本的所有更改(因此不会发生合并)。

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.

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

The keep(ours|theirs)tool simply edits out the diff markers and enclosed sections, detecting them by regular expression. This has the advantage that it preserves the diff options from the merge command and allows you to resolve some conflicts by hand and then automatically resolve the rest. It has the disadvantage that if there are other conflict markers in the file it could get confused.

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

These are all used by running git mergetool -t (get|merge|keep)(ours|theirs) [<filename>]where if <filename>is not supplied it processes all conflicted files.

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

Generally speaking, assuming you know there are no diff markers to confuse the regular expression, the keep*variants of the command are the most powerful. If you leave the mergetool.keepBackupoption unset or true then after the merge you can diff the *.origfile against the result of the merge to check that it makes sense. As an example, I run the following after the mergetooljust to inspect the changes before committing:

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

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

Note: If the merge.conflictstyleis not diff3then the /^|||||||/pattern in the sedrule needs to be /^=======/instead.

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