42

I have a clone of a repo on Github in which I created a new feature for upstream. The problem is, I did that in my master branch which also contains other stuff I pulled in from other clones. That totally broke my ability to create a reasonable pull request.

So I want to do the following:

  1. Restore my master branch to be exactly the same as upstream master.
  2. Create a new branch.
  3. Move some of my old commits to the new branch.
  4. Create a pull request off the branch.

And, in the future, I will do all my work in branches and create pull requests off them while leaving my master branch alone and just merging down whatever comes in from upstream.

My questions are:

  1. Is this a reasonable approach?
  2. How would I actually do steps 1 and 3?
the Tin Man
  • 158,662
  • 42
  • 215
  • 303
Manfred Moser
  • 29,539
  • 13
  • 92
  • 123
  • I have a new branch with my old stuff now and really I just want to get rid of my origin/master and create it fresh by getting everything from upstream/master as is and pushing it into my master... how do I do that.. having no luck with this all. – Manfred Moser May 07 '11 at 00:18

9 Answers9

70

Make a new branch to hold stuff

$ git branch old_master

Send to remote for backup (just incase)

$ git checkout old_master
$ git push origin old_master

Reset local master to the commit before you started modifying stuff

$ git checkout master
$ git reset --hard 037hadh527bn

Merge in changes from upstream master

$ git pull upstream master

Now DELETE master on remote repo

On github this won't work without first going into the admin section for the fork and setting the default branch to something other than master temporarily as they try and protect you from blowing stuff away.

$ git push origin :master

And recreate it

$ git push origin master

On github you should now set the default branch back to master

imbr
  • 6,226
  • 4
  • 53
  • 65
wewals
  • 1,447
  • 9
  • 9
  • +1 for that github tip. One day I might be thankful for them trying to save my behind, but this time working around their protecetion was what I needed ;) – c089 Nov 14 '11 at 15:30
  • I got a little confused at the `git pull upstream master` section. I did the following in the end which seemed to work for me. `git pull https://github.com/project/project.git master` – mrswadge Apr 15 '14 at 13:23
  • How do you find the admin section on github? – Todd Freed Jul 15 '17 at 22:39
9

This is almost a reasonable approach, but you're possibly taking things a bit out of order. First thing to do is it create a new branch where your current master points, so that you don't lose the convenient reference to the work you've already done:

git branch mywork-orig master

After that, you can reset master to upstream's view (assuming you have master checked out):

git reset --hard origin/master

Then you can make you own branch with the intended changes:

git checkout -b mywork

Make the changes that you want (cherry-pick them from mywork-orig, etc.), and send a pull request for that.

Phil Miller
  • 36,389
  • 13
  • 67
  • 90
  • Reset did not work. I then tried to do a reset to upstream/master since that is what I want. I want to pull in upstream/master in my local master branch and then push that on o origin/master (which is my clone github itself). – Manfred Moser May 07 '11 at 00:16
  • Don't forget about `git reflog` to get you out of a pickle! – Dominic Mitchell May 09 '11 at 16:53
6

This is late, but didn't see anyone suggest this much simpler method:

# make sure we're in master
git checkout master
# create new branch from current master
git branch tmp_master
# grab most recent changes from upstream w/o applying them
git fetch upstream
# force reset local master to match upstream/master
git reset --hard upstream/master

You saved your local changes to tmp_master and have forced updated master to match the most recent upstream/master. Now to get origin/master looking like upstream/master:

git push -f origin master

Now go ahead and cherry-pick out the commits, or rebase the changes on top of the current master. After which you would already have your new devel branch.

What you wanted to do is totally possible, just not in the order you asked. And it seemed others forgot you can fetch remote changes without actually applying them. Makes life a lot more simple.

Trevor Norris
  • 20,499
  • 4
  • 26
  • 28
3
  1. git reset origin/master
  2. git checkout -b new-branch
  3. git cherry-pick <hash> for each commit
  4. create your pull request.

Alternatively you can do:

  • git checkout -b new-branch
  • git rebase -i origin/master
  • (pick and choose your commits)
  • git checkout master
  • git reset origin/master
Talljoe
  • 14,593
  • 4
  • 43
  • 39
  • `git rebase -i` is an amazing thing. It can be a little overwhelming at first, but well worth learning. – Tekkub May 06 '11 at 22:10
  • Rebase lead me down a rathole of merges and conflicts and in the end I had a non working master branch locally that still had some old wstuff from my commits that I dont want. – Manfred Moser May 07 '11 at 00:17
  • Rule one: never work directly in master. That way if (when) you bugger things up, it's a simple matter to just make a new branch at master and try again. If you notice, Talljoe's instructions explicitly told you to checkout a new branch to do this, and to reset your local master back to where your remote's master is at. – Tekkub May 07 '11 at 01:35
  • yeah.. but the problem is that my remote master on github is all screwed up and I need to reset it to be the same as the upstream master... then I can work as suggested, but how do I get my master on github to be clean?? – Manfred Moser May 08 '11 at 05:43
2

According to git push you can use git push origin +dev:master to:

Update the origin repository’s master branch with the dev branch, allowing non-fast-forward updates. This can leave unreferenced commits dangling in the origin repository.

I'm not certain if this works with github. I don't have anything I need to wipe out right now. :)

It should allow you to make your local master look as you want using git rebase -i, then push the result up to github.


Alternatively, you can delete the master branch on github (git push origin :master) then repopulate it from your local, corrected, master. I have a feeling that github may prevent you from doing this if it's the default branch (as master probably is). If that's the case, go into the Admin section for your repository and change the default to another branch temporarily.

Dominic Mitchell
  • 11,861
  • 4
  • 29
  • 30
2

@Novelocrat suggested almost exactly the same approach I would do. Definitively create a backup branch from the current location of your master branch:

git branch mywork-orig master

In your case, I think origin is your github fork, and upstream is where you forked from. For that reason, when you have your local master checked out you should do:

git reset --hard upstream/master

That will reset it to where upstream's master is. Then you must also push it to your fork on github:

git push origin +master

Then create new branches off of your newly reset master branch, which should now be the same as upstream/master:

git checkout -b mywork

Because you have done so many merges on your old master branch, you can probably not cherry-pick much onto the new feature branches you create. Cherry-pick the commits you can, and then simply (or not so simply ;) re-create the ones you can't easily cherry-pick.

the Tin Man
  • 158,662
  • 42
  • 215
  • 303
Hugo Josefson
  • 193
  • 1
  • 8
  • git reset --hard upstream/master does not seem to work properly. I have done that and the project does not even build now, even though I can build a local clone of upstream just fine. Something is still. different. – Manfred Moser May 10 '11 at 05:37
  • TIP: Keep a `gitk --all &` open at all times, refreshing it between each CLI command you run. That gives a great view into where every head is located, and what each command does. – Hugo Josefson May 11 '11 at 18:22
  • thanks.. btw. the answer from wewals was the solution. A pull request to you is on the way soon. Next release? – Manfred Moser May 11 '11 at 19:16
1

You can push an arbitrary change set to an arbitrary ref within a git repository by using the git push command. In this case, you'll need to identify the hash of the changeset that you want to revert to and set it as the head of the master branch in the remote repository. Assuming that that remote repository is called origin you can use the following, where XXXX is the hash of the change you want to revert to:

git push -f origin XXXX:refs/heads/master

The -f switch will force the change as by default git will not allow you to push non-fastforward changes to a remote repository as it can lead to serious problems if other repositories have been cloned from yours.

Bryan Kyle
  • 13,361
  • 4
  • 40
  • 45
  • So XXXX would be the latest ref of the upstream master I want to be mirrored in my remote master right? Would that kill a branch I made off master or wouldt it preserve the old state in that branch? – Manfred Moser May 09 '11 at 17:34
  • Yes, XXXX would be the latest ref upstream master that you want to be your new remote master head. I'm not sure what it would do to the branch you created. It's likely that it would remain as the git repository would contain all of the old information even if it isn't referenced anywhere. For safety, you could always just clone everything you care about and store it offline while you make these changes, that way if it doesn't work out you have a backup. – Bryan Kyle May 09 '11 at 18:03
1

If you want to force "master" to look like "remotes/origin/master" you can do a forced pull.

$ git pull +master:master
   From git://github.com/matthewmccullough/hellogitworld
   + 1d22ca0...2a52e96 master     -> master  (forced update)
Matthew McCullough
  • 17,160
  • 7
  • 39
  • 38
0

I have an approach that is logical and as safe as possible. Assumptions:

  • You must have the authority to force updates to master on origin.
  • It assumes that no one else has pulled any of the nodes about to be deleted.
  • You can prevent updates to the master branch on origin while you are fixing the master branch locally.

Move/rename the local bad master branch to my-bad-master.

git branch -m master my-bad-master

Update your local master branch to match the origin's master branch.

git pull origin master:master

Save the origin's master branch to a branch called old-master

git branch old-master master

For safety's sake, push the old-master branch to origin

git push origin old-master:old-master
checkout master

Make any changes to the master branch. !!!! Be sure no changes are made on origin to the master branch till you are done !!!!

When done, force the new master branch up to origin.

git push -f origin master:master
Taylored Web Sites
  • 1,017
  • 1
  • 9
  • 15