You were working in a git repo and you committed your change to master. Happens all the time. Panic not.
Here are the steps to recover
Create a new branch from your current master branch. This will include your new commit. (to be clear, you should replace ‘description-of-work’ with a short name for your new branch)
git branch description-of-work
now reset your current master branch to upstream
git reset --hard origin/master
All fixed.
Why did this work?
A branch in git points to a specific commit. All commits are named by hashes. For example, right now, I have a keystone repo with my master branch pointing to
$ git show master commit bbfd58a6c190607f7063d15a3e2836e40806ef57 Merge: e523119 f18911e Author: Jenkins <jenkins@review.openstack.org> Date: Fri Jul 11 23:36:17 2014 +0000 Merge "Do not use keystone's config for nova's port"
This is defined by a file in .git/refs:
$ cat .git/refs/heads/master bbfd58a6c190607f7063d15a3e2836e40806ef57
I could edit this file by hand and have the same effect as a git checkout. Lets do exactly that.
$ cp .git/refs/heads/master .git/refs/heads/edit-by-hand $ git branch edit-by-hand * master $ git show edit-by-hand commit bbfd58a6c190607f7063d15a3e2836e40806ef57 Merge: e523119 f18911e Author: JenkinsDate: Fri Jul 11 23:36:17 2014 +0000 Merge "Do not use keystone's config for nova's port"
OK, lets modify this the right way:
$ git checkout edit-by-hand Switched to branch 'edit-by-hand' $ git reset --hard HEAD~1 HEAD is now at e523119 Merge "Adds hacking check for debug logging translations" $ git show edit-by-hand commit e52311945a4ab3b47a39084b51a2cc596a2a1161 Merge: b0d690a 76baf5b Author: JenkinsDate: Fri Jul 11 22:19:03 2014 +0000 Merge "Adds hacking check for debug logging translations" ...
that made it in to:
$ cat .git/refs/heads/edit-by-hand e52311945a4ab3b47a39084b51a2cc596a2a1161
Here is the history for the edit-by-hand branch
$ git log edit-by-hand --oneline
Returns
e523119 Merge "Adds hacking check for debug logging translations" b0d690a Merge "multi-backend support for identity" 6aa0ad5 Merge "Imported Translations from Transifex" ...
I want the full hash for 6aa0ad5 so:
git show --stat 6aa0ad5 commit 6aa0ad5beb39107ffece6e5d4a068d77f7d51059
Lets set the branch to point to this:
$ echo 6aa0ad5beb39107ffece6e5d4a068d77f7d51059 > .git/refs/heads/edit-by-hand $ git show commit 6aa0ad5beb39107ffece6e5d4a068d77f7d51059 Merge: 2bca93f bf8a2e2 Author: JenkinsDate: Fri Jul 11 21:48:09 2014 +0000 Merge "Imported Translations from Transifex"
What would you expect now? I haven’t looked yet, but I would expect git to tell me that I have a bunch of unstaged changes; basically, everything that was in the commits on master that I chopped off of edit-by-hand. Lets look:
$ git status On branch edit-by-hand Changes to be committed: (use "git reset HEAD..." to unstage) modified: doc/source/configuration.rst modified: doc/source/developing.rst modified: etc/keystone.conf.sample ... Untracked files: (use "git add <file>..." to include in what will be committed)
It was pretty long, so I cut out some files.
I can undo all those “changes” by setting the hash back to the original value:
$ echo e52311945a4ab3b47a39084b51a2cc596a2a1161 > .git/refs/heads/edit-by-hand $ git status On branch edit-by-hand Untracked files: (use "git add <file>..." to include in what will be committed)
Why did that work? Without the explicit “checkout” command, the current workspace was left unchanged.