I use a couple of software packages (like gitlab) that you install by cloning from their git repo. They typically come with some config.example
(under version control), which you copy to your own config
file (not under version control or even ignored in .gitignore
) and adapt to your needs.
When the upstream package is updated and for example changes the config file options that will obviously only be reflected in config.example
.
Is there a chain of git commands that i'm missing that can help me compare the changes of config.example
to the new one in upstream/HEAD
and maybe even merge them interactively into my local config
file?
Would be awesome if i could get something like the interactive patch mode in git add/commit --interactive
.
To diff just
config.example
in your local repo with the corresponding file inupstream/HEAD
you can run:Unfortunately I don't know of a way to make git directly apply the changes to a file that git doesn't track.
There is a tool called sdiff that might do what you want.
Invoke it (in your case) with
sdiff -o config config.example config
git checkout --patch
selects diff hunks, simplest here might be to put your content at the upstream path, do that, and clean up after:that will get you the two-diff hunk selection from
git add --patch
.vim
as a merge tool withvimdiff
.Emacs
can do this as well withediff-mode
.You could probably approach this in many ways. I could think of two:
git-merge-file
and good oldpatch
. Thegit-merge-file
method offers some interactivity, whereas thepatch
method offers none.Solution with
git-merge-file
Lets say you have an original file
config.example
which you use to create a local unversioned file,config.local
. Now when upstream updatesconfig.example
, you can follow something like the following steps to merge any new changes.This will update
config.local
with the usual conflict markers, which you will then have to resolve with your favourite merge tool (ediff
in Emacs is nice, I'm sure there are similar modes for Vim). For example, the following three files,config.example.base:
config.example.latest:
config.local:
will be merged like this:
You could probably script this without much effort. Btw,
git-merge-file
can operate on any 3 files, they need not be version controlled undergit
. That means one could use it to merge any three files!Solution with
patch
:Assuming the same file names,
config.local
andconfig.example
, the following should work.If you want the full git merge, you can get git to do it with arbitrary content by setting up an index entry as
git read-tree
does and then invoking git's normal merge driver on just that entry. Git refers to the different content versions as "stages"; they are 1: the original, 2: yours, 3: theirs. The merge compares the changes from 1 to 2 and from 1 to 3 and does its thing. To set it up, usegit update-index
:and you've staged a merge of custom content for that path. Now do it:
and it'll either automerge or leave the usual conflict droppings, fix it up as you like and
git rm --cached --ignore-unmatch
(or keep) the index entry if you want.The pathname you put in the index (the "config" in all three entries here), by the way, doesn't have to already exist or have anything to do with anything. You could name it "wip" or "deleteme" or anything you want. The merge is of the content id'd in the index entry.
I think that's likely to do what you want here. If you really do want to pick and choose from the upstream changes you can put your own content at config.example and do
git checkout -p upstream -- config.example
, that does the inverse ofgit add -p
, then put things back the way they were.