繁体   English   中英

交互式合并使用git和未跟踪的本地文件跟踪的文件

[英]Interactively merge files tracked with git and untracked local files

我使用了一些软件包(比如gitlab),你可以通过他们的git repo克隆来安装。 它们通常带有一些config.example (在版本控制下),您可以将其复制到您自己的config文件中(不受版本控制或甚至在.gitignore.gitignore )并适应您的需要。

更新上游程序包时,例如更改配置文件选项,这些选项显然只会反映在config.example

是否有一系列我缺少的git命令可以帮助我将config.example的更改与upstream/HEAD的新更改进行比较,甚至可能将它们交互式地合并到我的本地config文件中?

如果我可以在git add/commit --interactive获得类似交互式补丁模式的东西,那会很棒。

  • 您可以将vim用作vimdiff的合并工具。
  • Emacs也可以使用ediff-mode完成此ediff-mode

您可以通过多种方式解决这个问题。 我可以想到两个: git-merge-file和旧的patch git-merge-file方法提供了一些交互性,而patch方法则不提供。

使用git-merge-file解决方案

假设您有一个原始文件config.example ,用于创建本地无版本文件config.local 现在,当上游更新config.example ,您可以执行类似以下步骤的操作来合并任何新更改。

$ git fetch
$ git show master:config.example > config.example.base
$ git show origin/master:config.example > config.example.latest
$ git merge-file config.local config.example.base config.example.latest

这将使用通常的冲突标记更新config.local ,然后您必须使用您最喜欢的合并工具解析(Emacs中的ediff非常好,我确信Vim有类似的模式)。 例如,以下三个文件,

config.example.base

Original: 
          some config

config.example.latest

Original: 
          some config

Upstream:
          new upstream config

config.local

Original: 
          some config

My changes:
          some other config

将合并如下:

Original: 
          some config

<<<<<<< config.local
My changes:
          some other config
=======
Upstream:
          new upstream config
>>>>>>> config.example.latest

您可以不费力地编写脚本。 顺便说一下, git-merge-file可以对任何3 git-merge-file进行操作,它们不需要在git下进行版本控制。 这意味着可以使用它来合并任何三个文件!

patch解决方案:

假设相同的文件名, config.localconfig.example ,以下应该可以工作。

$ git fetch
$ git diff master..origin/master -- config.example | sed -e 's%\(^[-+]\{3\}\) .\+%\1 config.local%g' > /tmp/mypatch
$ patch < /tmp/mypatch

git checkout --patch选择diff git checkout --patch ,这里最简单的可能是将你的内容放在上游路径上,做到这一点,然后清理:

cp config  config.example
git checkout -p upstream   config.example
mv config.example  config
git checkout @  config.example

这将从git add --patch获得两个差异块选择。

如果你想要完整的git合并,你可以通过像git read-tree那样设置一个索引条目然后在那个条目上调用git的普通合并驱动程序来获取git来使用任意内容。 Git将不同的内容版本称为“阶段”; 他们是1:原来的,2:你的,3:他们的。 合并比较从1到2和从1到3的变化,并做它的事情。 要进行设置,请使用git update-index

orig_example=        # fill in the commit with the config.example you based yours on
new_upstream=        # fill in the name of the upstream branch

( while read; do printf "%s %s %s\t%s\n" $REPLY; done \
| git update-index --index-info ) <<EOD
100644 $(git rev-parse $orig_example:config.example)  1 config
100644 $(git hash-object -w config)                   2 config
100644 $(git rev-parse $new_upstream:config.example)  3 config
EOD

并且您已为该路径上演了自定义内容的合并。 现在去做:

git merge-index git-merge-one-file -- config

并且它要么自动充电,要么保留通常的冲突粪便,根据需要进行修复,如果需要,可以使用git rm --cached --ignore-unmatch (或保留)索引条目。

顺便提一下,您放入索引的路径名(此处所有三个条目中的“config”)不一定存在或与任何事情有关。 你可以将它命名为“wip”或“deleteme”或任何你想要的东西。 合并是索引条目中id'd的内容。

我认为这可能会在这里做你想做的事。 如果你真的想从上游的变化中选择你可以把你自己的内容放在config.example上并执行git checkout -p upstream -- config.example ,它执行git add -p的反转,然后把东西放回去他们的方式。

要在本地仓库中使用upstream/HEAD的相应文件来config.example ,您可以运行:

git diff upstream/HEAD config.example

不幸的是我不知道如何让git直接将更改应用于git不跟踪的文件。

一个名为sdiff的工具可能会做你想要的。

使用sdiff -o config config.example config调用它(在您的情况下)

以下应该有效:

git diff <some-args> | perl -pe 's/path\/to\/changes\/file/path\/other/g' > t
patch -p1 < t 
rm t

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM