title: "Git workflow and retroactively moving commits to a new branch" date: 2019-01-23
The following is a git workflow micro-tip, for moving changes committed to master to a new branch, where they belong.
I recently started rewriting a website layout, and expected to only make some very minor changes. I didn't bother creating a new branch, as I am the only one who works on the website, and figured I wouldn't be changing enough to warrant it. I was then interrupted mid-implementation (something which I try my best to avoid, and which will be the topic of an upcoming blog post), and committed the unfinished rewrite to the master branch. When I came back a few days later to finish the feature, I was left with a messy master branch, and I was annoyed at myself for not having followed better workflow practices. Luckily, this problem is very easy to fix; I describe the solution below.
Before I describe the fix, however, note that the practice of committing to the master branch is almost always a mistake; when using git (or another source/version control system), you want to make use of branches when developing new features, no matter how minor. You ought to strive to keep master clean and always deployable, while using other branches for works-in-progress. Master then functions as a protected safe-haven, to which you can always return, and which will always serve you well in your quest for stable and shiny new features. See this guide for a great overview of the git workflow (focused on using GitHub as a remote repository, but applicable to any other host, e.g., notabug.org or gitlab)
Cautionary tale concluded. If you have committed changes to master (or another branch that you have decided is not the right home for the new feature), and decide you now want to move them to another branch, the fix is fairly straightforward. You need only create a new branch, git reset master to an earlier commit (using either a count or a commit hash), and then commit any future changes to the new branch.
Note that you can find the hash of the commit you'd like to return to with:
$ git log
or for prettier output:
$ git log --oneline --decorate --color --graph
The hash of the commit I wanted to return to was a477073, which you can see below.
Assuming the currently checked-out branch is master, the whole process looks like this:
$ git log # Find target commit hash
$ git branch new_feature_branch # Create new branch, retains commits
$ git reset --hard a477073 # Revert master
$ git checkout new_feature_branch # Select new branch
And that's it! At this point, your new_feature_branch should house the most recent code, and master branch should be returned to its pristine state, pre-feature implementation.
There are some nuances/gotchas to be aware of with this, e.g., you probably don't want to do this with code that has been pulled by others (you may cause some merge conflicts and hair-loss), but for simple, single-maintainer repos, it should work fine.
More detail about this process can be found on this stackoverflow post.
Happy feature-writing!