2

I'm having a problem with the master branch on a repo. I pulled the master branch in on a server, but that had an unforeseen error in it. In a slightly panicked fashion, I checked out a specific commit which I know still worked.

Now, the application works as it should, but my repo is "Not currently on any branch.". In the meanwhile, there have been changes made on the server itself (very bad practice, I'm aware) that I would like to keep. So my question is - is there any way I can use the current state of my repo and turn that into "master"? I have looked into similar questions and those were solved by doing a merge with the "ours" strategy - but that won't work since I'm not on any branch, I think.

Jens Eeckhout
  • 155
  • 3
  • 10
  • 1
    `git reset` can't cause `Not currently on any branch`. Please give the *exact* steps you used. – Adam Spiers Mar 03 '15 at 10:01
  • @AdamSpiers I'm not actually 100% sure, unfortunately, I was kind of panicking. It might have been `git checkout [hash]` too, where that hash was the last "working" point of master branch. – Jens Eeckhout Mar 03 '15 at 10:03
  • possible duplicate of [Fix a Git detached head?](http://stackoverflow.com/questions/10228760/fix-a-git-detached-head) – Joe Mar 03 '15 at 10:06
  • Do you have a `~/.bash_history` (or similar) to find the exact commands? – Holloway Mar 03 '15 at 10:30
  • @Trengot - good call. Just checked, apparently I did check out a specific commit. – Jens Eeckhout Mar 03 '15 at 10:41
  • 1
    do you have some other commits that you want to keep after the commit where everything works? If not, just revert to the working commit. If you do have other work, then you have a few options. Depending on the fact if you work alone or not, you could rewrite the history of the branch, or just checkout a new branch from the working commit and then cherry pick the other commits you want and then merge it back to master (not very clean). You could also use git reflog to go back to the state before you did the unwanted changes/steps – peshkira Mar 03 '15 at 10:52

1 Answers1

1

Yes, you can, and there's a few ways to go about it. You didn't say much about how your project is set up and whether or not your automatically publishing your master branch.

I highly recommend you try these techniques on a throw-away repo first, just to make sure you know what you're doing before trying it on your live site.

Option 1: Forcefully roll back master

First, save off your current version of master as old-master:

git branch old-master master

Now old-master and master point to the same commit. Next, we'll update master to point at your current commit:

git branch -f master HEAD

At this point, you'll still have a detached HEAD, but the local master will point at the commit you are on.

git checkout master

This will put you back on your local master branch.

There are lots of details here beyond this though. First is the question of whether you should push up this change or not. If you automatically publish the master branch, then you you might consider doing a --force push, but that's extremely unfriendly for your other developers on the team. If you don't automatically publish the site, then there's really not any harm in leaving things as they are, fixing the whatever went wrong, and then updating the site once all the kinks have been worked out. The idea here is: if things don't move automatically, then you don't have to worry about the rug being pulled out from underneath your feet. I don't recommend this option.

Option 2: Revert the bad commits

This is more friendly since you don't have to rollback history. It's best to do this in a separate clone of your repository so you don't have to change your working tree that is being served until after master has been fixed.

Let's say commit WORKS is where everything is working fine, and BROKEN is the current tip of master. It's not clear whether there is more than one broken revision, but assuming it is, then you can simply revert the broken commit. From another working tree, you would do:

# In another working tree, *not* the one for your website
git checkout master
git revert BROKEN
git push origin master

If there's more than one commit breaking things, you can revert them all. Just watch out if any of those commits are merge commits. You can revert an entire range of commits too:

git revert FIRST_BROKEN_COMMIT..LATEST_BROKEN_COMMIT

This will revert all good commits in between too. But this might be exactly what you want, considering the situation.

Finally, you can update your website. In the website's working tree, you can use:

git fetch origin master
git push . FETCH_HEAD:master
git checkout master

While the commit number will change, the contents should not, unless you chose not to revert some commits between WORKS and BROKEN.

Note: git will still see the reverted commits as part of the history, so re-merging a branch will not re-introduce those changes. Unfortunately, it means that you either need to rebase the stuff that works and merge it in again, or simply redo the work and re-introduce it. There's a fair amount of help out there for this topic, including on StackOverflow.

Option 3: Merge master into master

This uses a merge strategy to roll back master to the previous state. It's not any better than Option 2 in my opinion, but it's an option.

Again, you'll have to do this in a separate working tree. Start by creating a new-master branch based on the commit WORKS, though you won't keep it in the end:

# In another working tree, *not* the one for your website
git checkout -b new-master WORKS

At this point, new-master should be pointing to the commit that you really want to be the tip of master (the one that works). Then merge in the tip of master using the ours strategy:

git merge -s ours master

Make sure to put in a meaningful message for the merge, such as "Reverting the site back to commit WORKS".

Now, we need to make the master branch the same as new master:

git push . new-master:master

If you get any error message about diverging, then it's likely you did something wrong. This new history will be a descendant of the broken master branch, so there should be no diverging history.

You can finish this by pushing it up to your remote repo and dropping the new-master branch:

git checkout master
git push origin master
git branch -d new-master

Finally, you can bring your website up-to-date as you would in Option 2:

git fetch origin master
git push . FETCH_HEAD:master
git checkout master

The commit number will change, but the contents should not as we made the tip of master identical to the commit you are on.

Summary

Which one is better largely depends on you. To me, I like Option 2 if there's only a handful of commits involved, and Option 3 is there's more involved. I'd also chose Option 3 if you don't feel confident with Git--there's less to go wrong.

John Szakmeister
  • 44,691
  • 9
  • 89
  • 79