521

I have forked a repository, then I made some changes and it looks like I've messed up everything.

I wish to start it again from scratch, using the current upstream/master as the base for my work.
Should I rebase my repository or delete it at all?

Splendor
  • 1,386
  • 6
  • 28
  • 62
tampe125
  • 8,231
  • 7
  • 30
  • 45

5 Answers5

1032

The simplest solution would be (using 'upstream' as the remote name referencing the original repo forked):

git remote add upstream /url/to/original/repo
git fetch upstream
git checkout master
git reset --hard upstream/master  
git push origin master --force 

(Similar to this GitHub page, section "What should I do if I’m in a bad situation?")

Be aware that you can lose changes done on the master branch (both locally, because of the reset --hard, and on the remote side, because of the push --force).

An alternative would be, if you want to preserve your commits on master, to replay those commits on top of the current upstream/master.
Replace the reset part by a git rebase upstream/master. You will then still need to force push.
See also "What should I do if I’m in a bad situation?"


A more complete solution, backing up your current work (just in case) is detailed in "Cleanup git master branch and move some commit to new branch".

See also "Pull new updates from original GitHub repository into forked GitHub repository" for illustrating what "upstream" is.

upstream


Note: recent GitHub repos do protect the master branch against push --force.
So you will have to un-protect master first (see picture below), and then re-protect it after force-pushing).

enter image description here


Note: on GitHub specifically, there is now (February 2019) a shortcut to delete forked repos for pull requests that have been merged upstream.

VonC
  • 1,262,500
  • 529
  • 4,410
  • 5,250
  • 5
    hi, it worked great! btw the correct reset syntax is `git reset --hard upstream/master` – tampe125 Mar 11 '12 at 12:11
  • 1
    @tampe125 Excellent. I have fixed the syntax of `git reset` in the answer. – VonC Mar 11 '12 at 13:57
  • Typical Git crap... Take a simple task, and make it difficult. Make half a million people suffer because they can't get a simple workflow correct. – jww May 27 '17 at 01:54
  • You don't need to checkout or reset anything, just invoke `git push --force origin upstream/master:master` – max630 Jun 20 '17 at 04:05
  • I saw your edit but for me GitHub doesn't allow to unprotect master branch that's why I replied. – Hugodby Aug 08 '17 at 08:02
  • @Hugodby Strange: if you are the owner of the repo, you should be able to protect/nuprotect any branch you want. – VonC Aug 08 '17 at 08:04
  • 2
    I got `fatal: ambiguous argument 'upstream/master': unknown revision or path not in the working tree` on `git reset --hard upstream/master ` – Bogdan Mar 25 '20 at 08:40
  • @Bogdan Do you have a remote named upstream (`git remote -v`) and did you `git fetch upstream` first? Then check the output of `git branch -avv`. – VonC Mar 25 '20 at 13:27
  • @VonC - yes to both questions – Bogdan Mar 25 '20 at 17:35
  • @Bogdan Do you see `upstream/master` after the `git branch -avv`? – VonC Mar 25 '20 at 17:36
  • What if I want to do the same thing but with develop branch of original and forked? – Ashok Rayal Mar 25 '20 at 18:04
  • @AshokRayal That would be the same idea, but with deveop instead of master – VonC Mar 25 '20 at 18:05
  • @VonC: I see it like `remotes/origin/HEAD -> origin/integraion` – Bogdan Mar 26 '20 at 15:06
  • @Bogdan It will be easier to continue in a separate question, rather than in those comments. Can you ask a new question? – VonC Mar 26 '20 at 20:03
  • This won't reset all other branches. Is there a way to clean the fork on origin and all its branches so that it equally matches upstream? – Shimmy Weitzhandler Jul 21 '20 at 02:18
  • 1
    @ShimmyWeitzhandler Yes, through script: https://stackoverflow.com/a/58372324/6309 – VonC Jul 21 '20 at 05:08
  • 1
    For those that are having upstream problems, first make sure that upstream is configured bit typing `git remote -v` – Haddock-san May 17 '21 at 12:39
  • may the --force be with you! – rubmz Nov 05 '21 at 19:28
  • you forgot git pull. if you have some changes, you will not be able to commit before pull – Stepan Yakovenko Apr 13 '22 at 21:25
  • @StepanYakovenko The goal of this question is to clean up and restart: no need for a pull. `fetch` + `reset` + `push --force` is enough. – VonC Apr 13 '22 at 22:25
42

Love VonC's answer. Here's an easy version of it for beginners.

There is a git remote called origin which I am sure you are all aware of. Basically, you can add as many remotes to a git repo as you want. So, what we can do is introduce a new remote which is the original repo not the fork. I like to call it original

Let's add original repo's to our fork as a remote.

git remote add original https://git-repo/original/original.git

Now let's fetch the original repo to make sure we have the latest coded

git fetch original

As, VonC suggested, make sure we are on the master.

git checkout master

Now to bring our fork up to speed with the latest code on original repo, all we have to do is hard reset our master branch in accordance with the original remote.

git reset --hard original/master

And you are done :)

Ahmad Awais
  • 33,440
  • 5
  • 74
  • 56
  • 5
    I'm getting `fatal: ambiguous argument 'original/master': unknown revision or path not in the working tree.` on the final step. Any advice? – TomNorway Feb 13 '17 at 12:24
  • 1
    It appears that this just leaves you stock on the original remote branch. I assume this is missing a step to reset YOUR fork back to the correct remote? – Ray Suelzer Apr 29 '17 at 20:42
  • 2
    `original` is better than `upstream` (which Github docs use), as `origin/master` is "upstream" of local `master`. Reduces ambiguity. I wonder if this is why you use it? – vaughan Jul 06 '17 at 09:58
  • 1
    That's exactly why I use it! – Ahmad Awais Jul 06 '17 at 17:36
  • 2
    I followed these instructions and now git status says: On branch master Your branch and 'origin/master' have diverged, and have 52 and 5 different commits each, respectively. (use "git pull" to merge the remote branch into yours) -- but I want to discard my 5 commits. What's the next step? – Stevey Jul 19 '17 at 23:45
  • Getting: fatal: ambiguous argument 'original/master': unknown revision or path not in the working tree. As well. – marsh Jan 31 '21 at 21:26
  • @marsh the branch you want might be called something else, eg. 'main' in my case. Take a look at the repo you're trying to reset from. – iforce2d Oct 06 '21 at 15:59
  • I actually found this harder to understand than the original VonC answer. But thanks for trying. – metaforge Mar 24 '22 at 00:09
11

Following @VonC great answer. Your GitHub company policy might not allow 'force push' on master.

remote: error: GH003: Sorry, force-pushing to master is not allowed.

If you get an error message like this one please try the following steps.

To effectively reset your fork you need to follow these steps :

git checkout master
git reset --hard upstream/master
git checkout -b tmp_master
git push origin

Open your fork on GitHub, in "Settings -> Branches -> Default branch" choose 'new_master' as the new default branch. Now you can force push on the 'master' branch :

git checkout master
git push --force origin

Then you must set back 'master' as the default branch in the GitHub settings. To delete 'tmp_master' :

git push origin --delete tmp_master
git branch -D tmp_master

Other answers warning about lossing your change still apply, be carreful.

Hugodby
  • 1,124
  • 9
  • 24
  • Thanks for this, this was exactly my situation. I can understand why a company wants to protect upstream/master, but why they restrict us from force push on our own personal forked copy is hard to understand... anyway, thanks again! – metaforge Mar 24 '22 at 00:05
6

How to do it 100% through the Sourcetree GUI

(Not everyone likes doing things through the git command line interface)

Once this has been set up, you only need to do steps 7-13 from then on.

Fetch > checkout master branch > reset to their master > Push changes to server

Steps

  1. In the menu toolbar at the top of the screen: "Repository" > "Repository settings"

"Repository" highlighted in the top menu bar

  1. "Add"

"Add" button at the bottom of the dialog

  1. Go back to GitHub and copy the clone URL.

"Clone or Download" button on the Github website followed by the git url

  1. Paste the url into the "URL / Path" field then give it a name that makes sense. I called it "master". Do not check the "Default remote" checkbox. You will not be able to push directly to this repository.

"Remote name" and "URL / Path" fields highlighted in the"Remote details" dialog

  1. Press "OK" and you should see it appear in your list of repositories now.

"master" repository added to the list of repositories in the "Repository settings" dialog

  1. Press "OK" again and you should see it appear in your list of "Remotes".

"master" repository highlighted in remotes list in side bar

  1. Click the "Fetch" button (top left of the Source tree header area)

"Fetch" button in the header area

  1. Make sure the "Fetch from all remotes" checkbox is checked and press "ok"

"Fetch from all remotes" checkbox highlighted in the "Fetch" dialog

  1. Double click on your "master" branch to check it out if it is not checked out already.

  2. Find the commit that you want to reset to, if you called the repo "master" you will most likely want to find the commit with the "master/master" tag on it.

Example of a commit with a "master/master" tag on it

  1. Right click on the commit > "Reset current branch to this commit".

  2. In the dialog, set the "Using mode:" field to "Hard - discard all working copy changes" then press "OK" (make sure to put any changes that you don't want to lose onto a separate branch first).

"Using mode" field highlighted in the "Reset to commit" dialog. It is set to "discard all working copy changes"

  1. Click the "Push" button (top left of the Source tree header area) to upload the changes to your copy of the repo.

"Push" button in the header area

Your Done!

Daniel Tonon
  • 9,261
  • 5
  • 61
  • 64
1

VonC's answer states

Be aware that you can lose changes done on the master branch (both locally, because of the reset --hard, and on the remote side, because of the push --force).

So I'll just cover how to create a new branch in the existing fork which is tracking the main branch of the repo originally forked from.

Why this can be important: Supposing you already have another pull request submitted for a different feature from the same fork. Or anybody else has forked from your fork. Then a hard reset is bad.

Supposing the forked-from remote is called upstream.

git fetch upstream main
git switch -c upstreamb/main/track upstream/main

You will be in a new branch upstreamb/main/track

% git branch 
...
* upstreamb/main/track
% git pull upstream main
From github.com:XXXX/YYYY
 * branch                  main       -> FETCH_HEAD
Already up to date.

Notice that / in the branch name is allowed. To avoid confusion and ambiguity I have added b to upstream to indicate that it is a local branch.

Now you can create a new feature branch from track, and you can use git difftool or whatever to selectively compare and copy from the abandoned work, if necessary.

Craig Hicks
  • 2,199
  • 20
  • 35