I've been trying to figure out a workflow in git for resetting my clone of an upstream branch to the current upstream state, but without discarding my history. The reason for not dropping the history is that a) it's antithetical to me to ever discard anything from revision control, and b) i push my local changes to a public repo, which means others might have cloned it and are following my changes, so a git reset or git rebase is a bad thing.
Sure, merge usually does just fine, but in the case of me working on something that is not accepted upstream or was made irrelevant by an upstream change the merge would not get rid of my dead end changes.
One option is to leave my clones of upstream branches alone and always create working branches that i discard once the task is completed and each new working branch is a new branch off the upstream master.
After digging around a while, I found almost what i wanted:
git merge --strategy=ours <branch>
which brings in history from
<branch> but adds one more commit recording the changes required to keep the current branch at its pre-merge state. Except i want to do the opposite
git merge --strategy=theirs <upstream/branch> // does not exist!
which would bring in the history from
<upstream/branch> and record a commit with the changes required to make the current branch a replica of
<upststream/branch>. While there is something that looks like it would do that, i.e.
git merge --strategy=recursive -X theirs <upstream/branch>
but that will not discard local changes that do not conflict with upstream changes.
A workflow to fake git merge –strategy=theirs
Assuming i must just be overlooking a command or switch, I asked on stackoverflow and with the help of users kelloti and jefromi (update: VonC updated his answer to more precisely reflect this workflow) was able to put together a workflow that fakes
get a temp copy of the upstream branch
git co -b temp <upstream/branch>
merge our version of the branch into the upstream with ours strategy
git merge --strategy=ours <branch>
commit if necessary (i.e. auto-commit or fast forward didn't happen)
git commit ...
checkout our version of the branch
git co <branch>
merge temp (which will be a fast forward)
git merge temp
push the changes to our origin repo
get rid of the temp branch
git branch -D temp
It's a bit convoluted but does leave us with our history and a re-freshed local copy of the upstream master.
Update: Why do i want this again?
I'm setting up the worflow for MindTouch DReAM right now. Up until now, we'd been collobrating via SVN without development branches. I had kept my own private git repo, because I am rather particular about committing frequently and wanting those commits backed up remotely.
As long as my repo had nothing to do with the public version, this was all fine, but since now I'd want the ability to collorate on WIP with other team members and outside contributors, I want to make sure that my public branches are reliable for others to branch off and pull from, i.e. no more rebase and reset on things I've pushed to the remote backup, since it's now on github and public.
So that leaves me with how i should proceed. 99% of the time my copy will go into the upstream master, so i want to work my master and push into upstream most of the time. But every once in a while what i have in wip will get invalidated by what goes into upstream and i will abandon some part of my wip. At that point I want to bring my master back in sync with upstream, but not destroy any commit points on my publicly pushed master. I.e. i want a merge with upstream that ends up with the changeset that make my copy identical to upstream. And that's what
git merge --strategy=theirs should do.