Cover Image: Puppy Bath Time! by pixel artist Andrea Zevallos - @SazdxHikari
Finally! My feature is ready for review. Now I'm opening the PR… but hold on!🚨📰
Ponder the question: How does your branch look like?
$> git log --pretty=format:'%h - %s' main..feature/drag-n-drop-grid
f6dec33 - chore: revert tsconfig
ee409e7 - revert DragDropWrapper (recover prev. code)
7dfcee2 - fix ci 6a84dd7 - testing
d14ffee - new component <DragDropGridWrapper />
914cca3 - wip
8796b3e - feat: replace internal library for <DragDropWrapper />
f6ad24c - chore: review .eslint + tsconfig
7da219e - new dependency 'react-draggable-tags'
That 'WIP' commit? sure I wasn't into writing a message; the 'fix-CI' one? I didn't expect it to occur; the 'revert' over there? yep that was causing too much trouble 🤷♀ .
Development process has these steps back. You start coding with some idea in mind; maybe you change the approach while coding; maybe you add some extra - not 100% related - boy-scouting; maybe you reinforce the coverage of a piece you're to use, etc.
Thing is, final history might look better when merging it to master. git
allows us to change the past, and pretend you did nailed it from the beginning.
All we need is the Gem of Time
$> git rebase --interactive main
Our example branch
Before messing up with time traveling, let's schematize our feature branch.
- Add new dependency to the project
- Unrelated change to
eslint
andtsconfig
config files - Start the feature itself: change the internal implementation of a React component 4, WIP (continues commit #3)
- Here we change the approach: instead of changing the existing component (prob. we'll mark it as deprecated at some point), we decided to create a brand new component.
- Tests for the new component
- Fix CI (continues commit #6)
- We recover the original component (using
get reset
) keeping both components in the project. - Revert
tsconfig
change from commit #2 (prob. it was causing more noise than expected
Baby Steps
1. Don't panic.
Remember that once you've committed, you can't lose your work(*).
You may save the reference (the hash) of the top commit. This can be used as a panic-button any time to get back to the initial situation.
$> git reset --hard <ref>
(*) there could be extreme situations like loosing the hard drive or zombie apocalypse 🧟 but you get what I mean.
2. Start squashing (s) any 'WIP' and 'Fix prev. commit' to their parent.
Change the word pick
by s
for those commits. In this example:
$» git rebase --interactive main
pick 7da219e new dependency 'react-draggable-tags'
pick f6ad24c chore: review .eslint + tsconfig
pick 8796b3e feat: replace internal library for <DragDropWrapper />
s 914cca3 wip
pick d14ffee new component <DragDropGridWrapper />
pick 6a84dd7 testing
s 7dfcee2 fix ci
pick ee409e7 revert DragDropWrapper (recover prev. code)
pick f6dec33 chore: revert tsconfig
When squashing (s), you'll be prompted for the resulting message. In this case we'll discard commit message #2 both times
3. Place together (move) every related commit.
In this example, we're moving the top-most commit to be right after it's counterpart. Besides, we're squashing the testing commit to its parent.
4. Keep squashing
Now that we have these 3 - let's call them - 'sections'. Seems fair that we can squash one last time.
Note: with
rebase
you may get merge conflicts (exactly the same way you face conflicts with git merge).
My recommendation is to keep focused on "How will this code look like in the final picture?"; pretend you did nailed it from the beginning.
5. Finishing touches 💅. Take the chance to reword (r) commit messages.
Personally I use Semantic Commit Messages. But we can cover that at another time.
This is our branch after taking a bath 🧽. Much better right?
$> git log --pretty=format:'%h - %s' main..feature/drag-n-drop-grid
a3f5f33 - feat: new component <DragDropGridWrapper />
f6ad24c - chore: review .eslint
7da219e - chore: new dependency 'react-draggable-tags'
TL;DR
- Don't panic. Once you've committed, you can't lose your work. You may prepare a panic-button copying the hash.
- Squash (s) any "WIP" and "Fix prev. commit" to their parents.
- Place together (move) every related commit.
- (If applicable) keep squashing.
- Reword (r) commit messages.
- Thanks for reading 💚.
Top comments (2)
This is a great summary of a rather advanced approach to git.
I had only used
rebase
in the past for fixing nasty problems, but never to tidy up my code before sharing / pushing. I think it's an excellent idea and use of the feature and I will try to incorporate it into my workflow. Thanks for sharing!Also, great write up, straight to the point, and with useful illustrations! :-o
PS: I'd love to hear more about these Semantic Commit Messages
Thanks for the nice words! really appreciated.
Yep! planning to write a post about Semantic Co Messages... there are already posts about them but I think I can share one idea or two :)