I'm trying to take a branch with changes and bring it back to be identical to the upstream it diverged from. The changes are both local and have been pushed to github, so neither git reset
or git rebase
are really viable, since they change history, which is a bad thing with a branch that's already been pushed.
I've also tried git merge
with various strategies but none of them undo the local changes, i.e. if I'd added a file, a merge might bring other files back in line, but I'll still have that file that the upstream doesn't have.
I could just create a new branch off the upstream, but i'd really like a merge that in terms of revision history applies all the changes to take my branch and make it identical to the upstream again, so that I can safely push that change without clobbering history. Is there such a command or series of commands?
change to the remote upstream branch and do a
git merge
with the merge strategy set toours
.All the history will still be present, but you'll have an extra merge commit. The important thing here is to start from the version you want to be at and merge
ours
with the branch github is actually at.There's also a way with little help of plumbing command - IMHO the most straightforward. Say you want to emulate "theirs" for 2 branches case:
This merges arbitrary number of heads (2 in the example above) using tree of one of them (bar in the example above, providing 'theirs' tree), disregarding any diff/file issues (commit-tree is low level command, so it doesn't care about those). Note that head can be just 1 (so equivalent of cherry-pick with "theirs").
Note, that which parent head is specified first, can influence some stuff (see e.g. --first-parent of git-log command) - so keep that in mind.
Instead of git-show, anything else capable of outputting tree and commit hashes can be used - whatever one's is used to parsing (cat-file, rev-list, ...). You can follow everything with git commit --amend to interactively beautify commit message.
You could merge your upstream branch to your
dev
branch, with a custom merge driver "keepTheirs":See "“
git merge -s theirs
” needed — but I know it doesn't exist".In your case, only one
.gitattributes
would be required, and akeepTheirs
script like:git merge --strategy=theirs
Simulation #1Shows as a merge, with upstream as the first parent.
Jefromi mentions (in the comments) the
merge -s ours
, by merging your work on the upstream (or on a temp branch starting from upstream), and then fast-forwarding your branch to the result of that merge:(Edit 2011):
This workflow has been reported in this blog post by the OP:
git merge --strategy=theirs
Simulation #2Shows as a merge, with ours as the first parent.
(proposed by jcwenger)
git merge --strategy=theirs
Simulation #3This blog post mentions:
git merge --strategy=theirs
Simulation #4(same blog post)
git merge --strategy=theirs
Simulation #5(proposed by Barak A. Pearlmutter):
git merge --strategy=theirs
Simulation #6(proposed by the same Michael Gebetsroither):
Heavy handed, but hell, what can possibly go wrong?
You can do this rather easily now:
This gets your local repo in-sync with the origin, and preserves the history.
Another simulation for
git merge -s theirs ref-to-be-merged
:An alternative to the double reset would be applying the reverse patch: