[英]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.local
和config.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.