...For the cases where, yes, you actually do want it.
For the impatient
assuming you're in a clean checkout on the tip of your current branch:
git merge -s ours ref-to-be-merged
git diff ref-to-be-merged git apply -R --index
git commit -F .git/COMMIT_EDITMSG --amend
you can then double check that everything is as you expect with
git diff ref-to-be-merged
, which should be empty.
The longer story
It's noted from time to time that git does not have a
-s theirs
option to complement the
-s ours
strategy when merging (or, it did,
but it was removed long ago, see below). For those not savvy the
idea with
git merge -s ours
is to pretend as though a merge from some
other branch has occurred, though the result remains the current branch's
contents, unchanged. This is a neat trick that can be used to show that
all changes in some branch have been superceded by the current branch,
which can help ease merges further down the line as parallel devlopment
continues.
However, there is no corresponding
-s theirs
option, which would
conversely say that "everything developed up to here is superceded by
this other branch". This feature was
discussed and discarded
by one of the git authors, who instead advised a developer to throw away
the previous work and start on a fresh branch:
One big problem "-s theirs" has, compared to the above "reset to origin,
discarding or setting aside the failed history" is that your 'master'
history that your further development is based on will keep your failed
crap in it forever if you did "-s theirs". Hopefully you will become a
better programmer over time, and you may eventually have something worth
sharing with the world near the tip of your master branch. When that
happens, however, you cannot offer your master branch to be pulled by
the upstream, as the wider world will not be interested in your earlier
mistakes at all.
In what would probably qualify as "most cases", he's right, but sometimes
you
do want to do this, and not because you have "crap" in your history,
but perhaps because you want to change the baseline for development in
a public repository where rebasing should be avoided.
In debian, for example, it's pretty common for maintainers who use
git-buildpackage
to build debian packages from git to have two branches: an "upstream"
branch and a "debianized" branch. The upstream branch will follow the
changes from the upstream project (either by importing tarballs, or
by pulling directly from the project's git repo if they also use git),
while the debianized branch contains all the packaging related changes
as well as any debian-specific changes to the code.
In this context, if the upstream project uses git and rebases their
history (out of your control), or if they shift development to a different
branch, you might want to have a way to merge with their latest changes
without rebasing/abandoning your current debian branch. Hence, a "
theirs
"
merge.
The author is totally right that the upstream project may be less interested
in pulling from such a repository (since they would drag in the entire
previous history), and if that's a problem you might need to
splinter off the old branch and start a fresh branch instead. But at
least for the projects with which I work, I find that it's more likely
that pulling is pretty much one way upstream to debian, and that the
patches flow back to the upstream project by way of bug trackers,
git format-patch sendmail
, or quilt patches sitting in the
patch-tracker. And if it becomes
a problem later you're no worse off, you can still split off a new
branch or take some other action.
So anyway, I
asked Teh Internetz
and found a few hits in the right direction, such as this guy at
stack overflow, or this guy
here. But from an aesthetic point of view I thought
their solutions still left some room for improvement--they were both
more complicated, involved setting up temporary branches, and I don't know,
just weren't
pretty on the eyes. So, ending where I started, this is
the relatively clean and easy to follow 3 lines I conjured up,
which I will give to teh internetz for posterity.
git merge -s ours ref-to-be-merged
git diff ref-to-be-merged git apply -R --index
git commit -F .git/COMMIT_EDITMSG --amend
Alternatively, if you want to keep the local upstream branches
fast-forwardable, a potential compromise is to work with the
understanding that for sid/unstable, the upstream branch can
from time to time be reset/rebased (based on events that are
ultimately out of your control on the upstream project's side).
This isn't a big deal and working with that assumption means that
it's easy to keep the local upstream branch in a state where it
only takes fast-forward updates. However, on the debian branch
your less interested in the clean upstream development, and instead
want to keep a sane history of the debianization work, so on this
branch you still do something like a
merge -s theirs
(though in
this case, you probably want to amend the previous version's ./debian
dir back in post-merge). So applying the same approach as above
with the slight modification, in practice (assuming you're on the clean
tip of the debian unstable branch, that'd be):
git branch -m upstream-unstable upstream-unstable-save
git branch upstream-unstable upstream-remote/master
git merge -s ours upstream-unstable
git diff ref-to-be-merged git apply -R --index --exclude="debian/*"
git commit -F .git/COMMIT_EDITMSG --amend
PS
In spirit, this is a similar approach to what's done by the
XSF team,
though I would argue that with what I'm describing both the approach
and the resulting history are a bit cleaner and easier to follow.
Also, thanks to
ron
,
mrvn
,
jcristau
, and
nthykier
on
#debian-devel
for some quick reviewing of this.