Update for future readers: Are you looking for a way to undo something with Git? The git undo command won’t help with your current issue (it needs to be installed ahead of time), but it can make dealing with future issues a lot easier. Try installing git-branchless, and then see the documentation for git undo.


Motivation

Git is a version control system with robust underlying principles, and yet, novice users are terrified of it. When they make a mistake, many would rather delete and re-clone the repository than try to fix it. Even proficient users can find wading through the reflog tedious.

Why? How is it so easy to “lose” your data in a system that’s supposed to never lose your data?

Well, it’s not that it’s too easy to lose your data — but rather, that it’s too difficult to recover it. For each operation you want to recover from, there’s a different “magic” incantation to undo it. All the data is still there in principle, but it’s not accessible to many in practice.

Here’s my theory: novice and intermediate users would significantly improve their understanding and efficacy with Git if they weren’t afraid of making mistakes.

Solution

To address this problem, I offer git undo, part of the git-branchless suite of tools. To my knowledge, this is the most capable undo tool currently available for Git. For example, it can undo bad merges and rebases with ease, and there are even some rare operations that git undo can undo which can’t be undone with git reflog.

Update 2021-06-21: user gldnspud on Hacker News points out that the GitUp client also supports undo/redo via snapshots, also by adding additional plumbing on top of Git.

I’ve presented demos below, and briefly discussed the implementation at the end of the article. My hope is that by making it easier to fix mistakes, novice Git users will be able to experiment more freely and learn more effectively.

Demos

Undoing an amended commit:

Undoing a merge conflict that was resolved wrongly:

Implementation

git undo is made possible by a recent addition to Git: the reference-transaction hook. This hook triggers whenever a change is made to a reference, such as a branch. By recording all reference moves, we can rebuild the state of the commit graph at any previous point in time. Then we accomplish the undo operation by restoring all references to their previous positions in time (possibly creating or deleting references in the process).

I originally built git-branchless in order to replicate a certain Mercurial workflow, but the data structures turn out to be flexible enough to give us a git undo feature nearly for free. You can find more detail at the Architecture page for the project.

The following are hand-curated posts which you might find interesting.

Want to see more of my posts? Follow me on Twitter or subscribe via RSS.

Comments