Git Time Travel Magic — Amend / Rebase

How and Why You Should Modify Your Git Timeline

We all know you can modify your git history, but most of us won’t. It’s not until we need history that we care. We’re keeping history for a reason, and making a good git history means you’re a good wizard.

S omeone says, “I’m going to change my git history” and everyone cringes.

If you were like me, something feels blasphemous at first glance of the idea of modifying history. Historical negationism is usually associated with the worst kinds of people. You might think of Holocaust deniers, book burners, or redacted governmental cover-ups, but what’s the other side of that coin? What about cleaning up the noise? What about cleaning false history!?

How many of you were told “Columbus set out to prove the world was round”? I know I was told this, and it’s such a fun story for kids! It’s also a complete fabrication. The Ancient Greeks, and in turn the scientific world, knew the world was round 2000 years before Columbus even set sail.

Just as accurate

Our git history is no better. Often times we defy the spirit of history by flooding our commit messages with a hubris that our job is done. As humans those mistakes will happen, and the result isn’t always pretty. How many of you have abandoned the readability of your git history?

History never looks like history in the present, but we can fix that. You don’t have to wallow in regret. We’re all coding wizards! Let’s dig into what we can do to change history!

Warning, warning, warning

Modifying history should be done within your own local domain. Editing master, pushing with --force , and other collective edits outside of your branch are dangerous. This post is introducing the basics of time manipulation, and in no means should you consider this a guide to meddle with a distributed history. Due to the nature of this article, each section is beset with warnings specific to the time manipulation you’re doing.

To quote Hermione Granger:

Wow Gant, can you be more dramatic!?

Of course! Alternate timelines are powerful, but they’re not really that complicated either. The best description of editing git history has to be the classic scene from Back to the Future II.

WARNING — this is for fun, you can skip it if you don’t have the…. TIME!

There are a few well known, and relatively friendly charms we can learn to really grok being an A+ 💯 git historian. In this blog we’ll cover the basics:

Amend

Rebase

Now that we’re same-paging it, let’s open our book of spells to Chapter 1 and get started, shall we?

Can I get an Amend!

We’re going to start simple by modifying the nearest history possible. Your last commit. It’s easy! Surely, at some point you found yourself wishing you could.

Fix a typo in your code

Fix a typo in your commit message

Add forgotten files essential to the commit intention

Fix tests that didn’t pass, and thus have more code to add

To modify the last commit, we have a friendly charm called --amend . Simply add this tag to your next commit for a historical rewrite.

Run git log to see how history looks, and we see our last commit is properly modified, with our typo removed from history.

Success! We re-wrote history.

We could have restructured our last commit in any way. Modified the message further, modified the code, or adjusted staged files. Our amend gives us freedom to pretend our previous commit never even happened.

And yes, you can amend an amend!

This is a good moment for a warning. Don’t amend a pushed commit. The answer is simple. Once you have pushed, you’ll have to modify history for yourself and the remote repo you pushed to, which is generally more advanced magic than you should toy with on a whim. Commits that are local only, reside as easy targets.

Though git log shows no sign of our tampering, our local git still has traces (priori incantatem). Using git reflog we can summon all the changes you might have thought were gone.

There it all is! The dirty truth! From our amend to even revealing a git reset it’s all recorded in our reflog. This history is harmless since it’s not pushed with our commits. For 99.9% of us, we can leave these logs in place. However, it should be noted that reflog entries can be removed as well. We can remove our typo from our reference logs with the command git reflog delete HEAD@{1} for… purely academic purposes, of course.

“All your rebase are belong to us”

OK time travelers, let’s level up!

You may have heard about rebase, and you should! It’s getting more popular, especially in the lands of GitHub. By little explanation, GitHub recently released a way to rebase pull requests.

With great drop-downs come great power!!!

“So what is rebase?” The Easy answer…

A normal git merge creates a graph. This graph doesn’t miss a thing! We don’t rewrite any history, in fact we track all timelines. We can understand the graph that Doc draws in blackboard in Back to the Future II, and we can understand any of these commits with a similar graph!

Above are alternate timelines for git, in some crazed higher-order dimensional perspective. But the movie Back to the Future II was told in a linear perspective. As humans, graphs appeal to us analytically, but not naturally.

Naturally, we want to see through the graph and into the story it tells.

Regardless of alternate timelines that affect one another, we end with one timeline; we land in one branch; we tell one story.

First my project started with A, then we added C, and then B

Who cares if B started before C, but was added later? Complexity isn’t our friend. You have to choose, do you want something analytically correct, or do you want something clearly readable? If your git history is for machines, you’re happy with charts. If it’s for people, you want a story, which follows linear progression, you want to rebase!

WARNING: This is a pretty big divergence from GitFlow. The disciples of GitFlow will maintain graphs for accuracy. GitFlowists will even use --no-ff (no fast-forward) to keep alternate timelines of features intact.

GitFlow Philosophy Excerpt

It’s safe to say GitFlow and Rebase hold antithetical value systems in their git history. Remember, one is a historical graph, the other is a clean story.

So, what does this story look like when we rebase? Well, let’s take a look at a hypothetical Git example. Let’s say our current git graph looks like so:

Graph thanks to https://www.draw.io/

We want to merge our hero commits (orange) into the main timeline. Does it matter that someone finished enemies before we finished hero? If the answer is no, then it’s easy to clean up the story we’re telling. Let’s simply take our timeline and flatten it in a reasonable way. We’ll put this branch at the end.