---
title: Confirm your changes at the end of a git rebase
teaser: 'It''s not always obvious what changed in your code after a git rebase. This
  tool makes changes more visible and helps you undo them if needed.

  '
tags: git,development,workflow,productivity
author: Jonas Meinerz
published_on: 2020-04-28
---

## Problem

Long-lived feature branches are not ideal, but they are sometimes unavoidable.
When working with big teams and large codebases, it is reasonable for feature
development, dependency upgrades, and refactorings to happen simultaneously.

I recently found myself trying to rebase a feature on top of a large piece
of refactoring. I did not feel confident after the rebase was applied, and
decided to compare the current version of my branch against how it was before
the rebasing began. The diff I got was not what I wanted, so I reverted the
rebase and tried again.

Saving the SHA of my not-yet-rebased branch to a variable so I could run
`git diff $before_rebase_sha` after rebasing quickly became a pattern for me
while developing that feature. The issue was I didn't always remember to
`export before_rebase_sha=$(git rev-parse HEAD)` before I started rebasing,
which made so I had to spend quite a lot of time looking staring at the output
of `git reflog`.

What I was missing was something that showed me the changes caused by my rebasing
and reverted them when I wasn't happy. So I built that.

## Solution

`git log --oneline` on my current repository returns the following:

```bash
ec7bfbb (HEAD -> master) Third
9d2b628 Second
2fc8388 First
```

But I'm not quite happy with my second commit, which looks like this:

```diff
commit 9d2b6284957c0506cc975c4a473b2704db0a8581
Author: Jonas Meinerz <jonas@thoughtbot.com>
Date:   Fri Apr 24 11:11:41 2020 +0100

    Second

diff --git a/test.txt b/test.txt
index 9daeafb..e4e595b 100644
--- a/test.txt
+++ b/test.txt
@@ -1 +1 @@
-test
+testy
diff --git a/test2.txt b/test2.txt
new file mode 100644
index 0000000..6f2a9ef
--- /dev/null
+++ b/test2.txt
@@ -0,0 +1 @@
+secondy
```

I want to get rid of those 'y' at the end of the first lines of both my
files. In order to do that, I will run

```
git rebase -i HEAD~2
```

And I will choose to edit that specific commit:

![Editing commit during interactive rebase](https://images.thoughtbot.com/blog-vellum-image-uploads/jItJHj6lSzuBlGgkleh3_Screenshot%202020-04-24%20at%2012.15.53.png)

But my change resulted in conflicts:

![Conflicts during interactive rebase](https://images.thoughtbot.com/blog-vellum-image-uploads/ZMae5oE5QsmIxV3yfKl2_Screenshot%202020-04-24%20at%2012.18.41.png)

After solving those conflicts and running `git rebase --continue` comes the part
that used to bother me. Now, thanks to a small amount of automation, I get a diff
displayed to me in a friendly way. I can also reset my branch to how it was before
I started rebasing if I so wish:

![Confirmation dialogue after rebase](https://images.thoughtbot.com/blog-vellum-image-uploads/Z7y7SFJTR0OXp9pwlQEr_Screenshot%202020-04-24%20at%2012.19.40.png)

## How I built it

Using [git hooks](https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks),
I created a pre-rebase hook to write the SHA into a file I could read
later on:

```bash
#!/bin/sh

rebasing_file="$PWD"/.git/rebase_in_progress
echo $(git rev-parse HEAD) > $rebasing_file
```

And a post-rewrite hook to show me the diff and ask whether I want to
keep them:

```bash
#!/usr/bin/env bash

# post-rewrite is called after amend and rebase but we only want to run
# this particular hook after a rebase
if [[ $1 == 'amend' ]]; then
  exit 0
fi

rebasing_file="$PWD"/.git/rebase_in_progress

if [[ -f $rebasing_file ]]; then
  sha_pre_rebase=$(cat $rebasing_file)

  if [[ $(git diff $sha_pre_rebase) ]]; then
    echo "Your rebase resulted in code changes"
    git diff $sha_pre_rebase

    read -p "Do you want to keep the changes? [Y/n] " -n 1 -r < /dev/tty
    echo ""

    if [[ $REPLY =~ ^[Yy]$ ]]; then
      echo "Cool! All changes kept"
    else
      echo "Discarding changes..."
      echo ""
      git reset --hard $sha_pre_rebase
    fi
  else
    echo "Your rebase caused no code changes, good for you"
  fi

  rm $rebasing_file
fi
```

## Try it yourself

Would you like to try it out? I have created a
[GitHub repository](https://github.com/jmeinerz/rebasing-hook) with the
code and instructions on how to add it to your projects.

## Useful links:

* [rebasing-hook on GitHub](https://github.com/jmeinerz/rebasing-hook)
* [git hooks](https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks)
* [git reflog](https://git-scm.com/docs/git-reflog) - this can save your life
