In a previous post, I had discussed how to create a clean branch within your Git repo with no commit history. You might want to do that if you were releasing part of your closed project to GitHub, for example. But the time comes to issue fixes or new features. How do you bring those in? The typical Git workflow expects that everything, your new features and hotfixes, comes back into the develop and master branches, but you need to also push them to your ‘clean’ branch. Enter interactive rebasing, commit squashing, and patch making. It’s important to note that I really only advocate this method when preparing a block that really should be viewed as porting a group of changes from one build channel to another, where the history would either be confusing or inappropriate to include.
#1 – Break out your updates
It starts with a bit of planning. Generally, you probably have a good idea of when you are starting on a new feature or debugging something of significant enough that you would not want to duplicate the fixes manually. In those cases, I recommend creating a feature/ or hotfix/ branch, and then doing your work there.
#2 – Prepare to Share
Once you have made and tested your changes, and are confident enough to bring it back into your build, turn to interactive rebasing. The nuts and bolts of interactive mode is explained in the docs, but I can’t directly link to it, so you’ll have to scroll down to ‘Interactive Mode’ yourself to get to it.
You will be doing a few steps that you do not want to push and will ultimately be mixed-resetting locally, so don’t get too careless. I am assuming that you have been submitting your feature/ or hotfix/ branch to a central repo, so your local changes can be reset.
So let’s assume you have done some work in a temporary branch, and made a few commits along the way.
You will want to launch rebase into interactive mode.
This brings you into the interactive interface.
Rebase gives you several options, but in this scenario (we want a clean commit history pushed to a separate build), the ‘squash‘ option proves a perfect solution. It allows you to collect a number of commits and convert them into a single commit, which you can then convert into a patch. So you need to edit your rebase commands, picking one of your commits, and then opting to ‘squash’ the rest.
Save your commands, and that will bring you to the COMMIT_EDITMSG screen, where I tend to clean up my message history to make it appear as a single, cohesive patch.
Save you edits and you should be done with the rebasing.
#3 – Create the Patch
So now that you have your work nicely condensed down to a single commit with notes and messages to document the changes, it is easily converted into a patch for your separate build.
Simply call format-patch from the command line, referencing your most recent commit.
This will create a .patch file in the top of your repo directory. Depending on your needs and wants you may or may not want to remove the patch from your directory at this point.
#4 – Reset the Branch
At this point, you need to undo your rebase and your squashing for the good of your primary build. Rather that should be a mixed or a hard reset depends on if you want to keep the patch available in your primary repo. If you do a hard reset, remember to remove the .patch file, because you will need it – that is what all this work has been leading up to. Reset back to a previous commit and resync with your central server.
#5 – Apply the Patch
Change to your cleaner, public branch and run
git am < do-something.patch
This will apply the specific commit, with all the changes, but without the additional, connected history.
In conclusion
So, sure, it’s not an every day need, but handy to have when it becomes required.
Feel free to leave any questions or comments below if I can help or make anything more clear.
Leave a Reply