A Quick Git Rebase Tutorial

If there’s one thing you should know about me (technically), it’s that I love a good rebase. I loathe merge commits and a nice, linear commit history brings me joy. Since I am somehow leading my current team (who decided that was a good idea???), we are using rebase pretty heavily! I’ve found that people often get flustered with merge conflicts and wanted to do a quick tutorial covering merge conflicts and a basic rebase. Let me know what you think!

My Git Workflow

One thing I’ve learned as a developer is that everyone has a slightly different git workflow. Mine is pretty simple, rarely uses anything beyond the basics (other than rebase), so, if you are an early career developer, consider trying it on for size. Let’s get started!

I’ve just grabbed a ticket, so I’m ready to get started. First things first: I need to create a new branch off main.

git checkout -b my-awesome-branch

Now that I’m on my branch, I can start making changes. I will make one small change and create a new file. Now I’m ready to commit! But first, I must validate that the changes I’m committing are precisely what I want. You might think, “Jennifer, I just made these changes; why do I need to recheck it?” While it might seem silly, you will be surprised by the changes creeping into your commits if you aren’t careful. One really common one is dependency updates. So first: we will do a git status and a git diff.

command prompt showing the results of git status -s

You’ll notice that I didn’t just do git status but git status -s. The -s is for “short” and I prefer that because it gives me all the information I need in a nice compact manner. The M says that a file is modified and the ? means that it’s a new, untracked file. Next, I want to do git diff which will pop up a window (by default using vim) that looks something like this:

output of git diff

It shows that I added one new line in README.md. You’ll notice that nothing will show up for the untracked file! Now that I’m confident that my changes are what I want them to be, I’m going to do git add -A and then run git status -s again (which I have mapped to git s).

output of git add -A and git s

Time for a commit! If I have a longer commit message that I want to write, I will do a full git commit. More often, I will just use git commit -m to do it all in one line.

output from `git commit -m "extremely necessary hello_world script"`

Now, time to push it up.

output from git push

That might be all. However, like many developers, I often realize I have made a mistake. I like to pretend my mistakes never happened! Some people will just make a brand new commit with a message like “fixing typo”. Me? I pretend my typos never happened by making my changes, adding the file, then doing git commit —-amend.

git status -s, git diff, git add, git status -s, and git commit --amend

There are a couple of spots in this where I couldn’t get it all in one. So here’s the git diff that happened at the 9:34 timestamp:

git diff

Clearly I realized that I didn’t actually want “World” but for some reason wanted my name instead. After I added the file, this is what pops up when I do git commit -—amend:

output from git commit --amend

As you might be able to tell, I could also edit my commit message here! I also use amend if I have made a typo in a commit message or if I just want to expand on my initial, too short message. After amending (or rebasing), you will have to do a git push -f or a “force push”. Why? Because you are effectively rewriting git history!

git push -f

IMPORTANT NOTE if you are working on the same branch as someone else, be careful about force pushing. Consider using git push —-force-with-lease instead. And always make sure to let your buddy know that you are doing this.

That’s pretty much it! It might seem like a lot, but it actually gets pretty quick pretty fast as muscle memory kicks in. If you are interested in some shortcuts, here’s an example of what my .gitconfig sometimes looks like.

What’s your git workflow? Is there something you think I should change? Let me know!

Squashing Commits & Keeping Your History Clean

I'm a big fan of committing early and often. However, if you are anything like me, that means your commit history looks something like this:

added feature
fixed typo
oops another typo
added tests
fix failing test
fix another failing test
UGH TYPO

Fine for me alone, but not a great reference for the rest of the team when they try to figure out WTF I was doing a month or a year later. I've already written about how to rebase and squash commits before, so I won't cover that again. I do want to go a little more into why it's important to do so. Each commit message should reflect a distinct piece of work done. What I need to do now is rebase and change my commits to be more like this:

Added endpoint to return list of components
Added unit tests for component index endpoint

Now, if someone does a git blame, they can get the full context of what I was doing, not just a one character typo change. It's also worth expanding out your messaging and putting more context in the description. Every team has their own style and rules, but, personally, this is my normal git workflow and I'm a huge fan.

Git Rebase

For a while I was staying away from git rebase because I kept getting crazy errors and commits that weren’t mine whenever I tried to rebase. No more!

# rebase!
git checkout branch-i-want-to-merge
git log
git rebase -i HEAD~6
git log
git rebase old-branch
git checkout old-branch
git merge branch-i-want-to-merge

Command by command:

I have a branch called branch-i-want-to-merge that has 6 commits. I have a master branch called old-branch that I want to merge my branch into, but not before cleaning up the commit history (does everyone need to know that I forgot an s?).

I have branch-i-want-to-merge checked out. I double check my number of commits by doing a git log and counting them. I see 6, so I do a git rebase -i HEAD~6. After this, I do a git log again to verify that I only have 1 commit.

Now I want to make sure my new branch has all the commits from the old branch, so I do git rebase old-branch. Success!

Final steps: I check out old-branch, then do merge in my new branch with a git merge branch-i-want-to-merge. All done! That wasn’t so hard, right?