Help! I just force-pushed to master! What do I do now?

Help! I just force-pushed to master! What do I do now?

Sandro Padin
Sandro Padin

June 08, 2015

Calm down... Let your teammates know. Ask them not to push anything up to master.

You can fix this. Jump to the option that best describes what you did, and start there.

The instructions in the scenarios above will get master pointing back to the right commit. The only difference being that if you fetched before the force-push, you'll already have the commit that you need to push back to master. If you didn't fetch before the force-push, you'll have to attack the problem another way.

I force-pushed to master on GitHub and there were changes I hadn't pulled.

You'll need to find the sha1 of the commit that was on master before your force-push. Create a branch from that commit, pull the branch from GitHub, then push that commit back onto master.

Find the sha1 of the last commit on master

You have a couple of options.

If you use a CI tool, check the tool to find the most recent build of master before your force-push. Grab the sha1 associated with the most recent commit on that build.

Once you find the sha1, you can skip to the next step.

No CI tool, no problem. Use the GitHub Events API, to find the most recent commit to master before your force-push.

 $ curl https://api.github.com/repos/:owner/:repo/events

If this is a private repo, you will need to append the -u flag with your username and password.

 $ curl https://api.github.com/repos/:owner/:repo/events -u [username]:[password]

If you use 2-factor authentication, you should create an OAuth token and use that instead.

 $ curl https://api.github.com/repos/:owner/:repo/events -u [generated-token]:x-oauth-basic

Below is a sample reponse at the time of this writing.

 $ curl https://api.github.com/repos/spadin/dotbashrc
[
		{
				"id": "2718080214",
				"type": "PushEvent",
				"actor": {
						"id": 21626,
						"login": "spadin",
						"gravatar_id": "",
						"url": "https://api.github.com/users/spadin",
						"avatar_url": "https://avatars.githubusercontent.com/u/21626?"
				},
				"repo": {
						"id": 32646354,
						"name": "spadin/dotbashrc",
						"url": "https://api.github.com/repos/spadin/dotbashrc"
				},
				"payload": {
						"push_id": 629937920,
						"size": 1,
						"distinct_size": 1,
						"ref": "refs/heads/master",
						"head": "faa94777e501d20da30afe677d9103297ec0cd69",
						"before": "e1e5bb6dfb6a7d21bdb94bb64bc27318b2df7851",
						"commits": [
								{
										"sha": "faa94777e501d20da30afe677d9103297ec0cd69",
										"author": {
												"email": "sandropadin@gmail.com",
												"name": "Sandro Padin"
										},
										"message": "Add Golang config",
										"distinct": true,
										"url": "https://api.github.com/repos/spadin/dotbashrc/commits/faa94777e501d20da30afe677d9103297ec0cd69"
								}
						]
				},
				"public": true,
				"created_at": "2015-04-11T22:58:20Z"
		},
		{
				"id": "2683572652",
				"type": "PushEvent",
				"actor": {
						"id": 21626,
						"login": "spadin",
						"gravatar_id": "",
						"url": "https://api.github.com/users/spadin",
						"avatar_url": "https://avatars.githubusercontent.com/u/21626?"
				},
				"repo": {
						"id": 32646354,
						"name": "spadin/dotbashrc",
						"url": "https://api.github.com/repos/spadin/dotbashrc"
				},
				"payload": {
						"push_id": 616014920,
						"size": 1,
						"distinct_size": 1,
						"ref": "refs/heads/master",
						"head": "e1e5bb6dfb6a7d21bdb94bb64bc27318b2df7851",
						"before": "455a26757e0d077a7e039ec24b8cd431cabd1dc5",
						"commits": [
								{
										"sha": "e1e5bb6dfb6a7d21bdb94bb64bc27318b2df7851",
										"author": {
												"email": "sandropadin@gmail.com",
												"name": "Sandro Padin"
										},
										"message": "Add rbenv",
										"distinct": true,
										"url": "https://api.github.com/repos/spadin/dotbashrc/commits/e1e5bb6dfb6a7d21bdb94bb64bc27318b2df7851"
								}
						]
				},
				"public": true,
				"created_at": "2015-03-28T02:50:47Z"
		}
]

Find the commit to refs/heads/master that was pushed just before your force-push. Read the commit message and look at the timestamp to confirm this is the right commit. Take note of the sha1.

Create a new branch from the sha1 you found

Again, use the GitHub API, but this time use it to create a new branch from the sha1 you found in the last step.

$ curl -i \
 -H "Accept: application/json" \
 -H "Content-Type: application/json" -X POST \
 -d '{"ref":"refs/heads/[branch-name-to-create]", "sha":"[add-your-sha1]"}' \
 -u [username]:[password]
 https://api.github.com/repos/spadin/dotbashrc/git/refs

Pull your newly created branch from GitHub

 $ git pull origin/[branch-name-i-created]

Almost there!

You now have everything you need to get master back to normal! Move on to the final steps.

I fetched the most recent commits from GitHub before I force-pushed to master.

or I followed the steps above and I have a branch with the last commit before my force-push.

All you have to do now is push the sha1 back onto the master branch on GitHub.

 $ git push origin [sha1-of-good-commit]:master

If that doesn't work, you may have to force-push. This is the whole reason we're here, eh? :)

 $ git push -f origin [sha1-of-good-commit]:master

You're done.

Let your teammates know everything is fixed... and resume breathing normally again.

Mistakenly force-pushing something happens to a lot of people. Don't beat yourself up. Learn from your mistake and try not to let it happen again.

I got the idea of using the Github API like this from this blog post.