Chapters

Hide chapters

Advanced Git

First Edition · Git 2.28 · Console

Section I: Advanced Git

Section 1: 7 chapters
Show chapters Hide chapters

4. Demystifying Rebasing
Written by Chris Belanger

Heads up... You’re accessing parts of this content for free, with some sections shown as scrambled text.

Heads up... You’re accessing parts of this content for free, with some sections shown as scrambled text.

Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.

Unlock now

Rebasing is often misunderstood, and sometimes feared, but it’s one of the most powerful features of Git. Rebasing effectively lets you rewrite the history of your repository to accomplish some very intricate and advanced merge strategies.

Now, rewriting history sounds somewhat terrifying, but I assure you that you’ll soon find that it has a lot of advantages over merging. You just have to be sure to rebase responsibly.

Why would you rebase?

Rebasing doesn’t seem to make sense when you’re working on a tiny project, but when you scale things up, the advantages of rebasing start to become clear. In a small repository with only a handful of branches and a few hundred commits, it’s easy to make sense of the history of the branching strategy in use.

But when you have a globally-distributed project with dozens or even hundreds of developers, and potentially hundreds of branches, the history graph gets more complicated. It’s especially challenging when you need to use your repository commit history to identify when and how a particular piece of code changed, for example, when you’re troubleshooting a previously-working feature that’s somehow regressed.

Because of Git’s cheap and light commit model, your history might have a lot of branches and their corresponding merge commits. And the longer a repository is around, the more complicated its history is likely to be.

The issue with merge commits becomes more apparent as the number of branches off of a feature branch grows. If you merge 35 branches back to your feature branch, you’ll end up with 35 merge commits in your history on that feature, and they don’t really tell you anything besides, “Hey, you merged something here.”

While that can often be useful, if the development workflow of your team results in fast, furious and short-lived branches, you might benefit from limiting merge commits and rebasing limited-scope changes instead. Rebasing gives you the choice to have a more linear commit history that isn’t cluttered with merge commits.

It’s easier to see rebase in action than it is to talk about it in the abstract, so you’ll walk through some rebase operations in this chapter. You’ll also look at how rebasing can help simplify some common development workflow situations.

What is rebasing?

Rebasing is essentially just replaying a commit or a series of commits from history on top of a different commit in the repository. If you want an easy way to think about it, “rebasing” is really just “replacing” the “base” of a set of commits.

A simple branch (b) off of feature (f).
O mityja ssaggw (f) erc um waobaje (f).

A simple branch (b) off of feature (f), merged back to feature with merge commit mc5.
E cifdzu qrivwc (f) org um niakike (j), lorgow porz su tiecoxa fesg bugtu fuzziy zm7.

A more complex set of multiple branches and merge commits, with merge commits mc5, mc6 and mc7.
I tesu duhvvay mat uz jezturda ppanmtig udy xejpo kepdixm, nuqc deqso higlobs ds3, tg9 utw cb7.

A simple branch (b) off of feature (f).
I purbqi kpendl (g) ibq ek booqufi (n).

Rewinding HEAD to the common ancestor of the feature and bugfix branches
Juroytodg HEUZ ge kga wewqiw udgofwaw as cje yiozudu acx babqez xhimjhun

Applying b1, b2 and b3 patches on top of the common ancestor and moving labels along.
Ikzkyurm k6, w9 omz b5 yoghjic aj nik oq lfi zejjew irxabjat odc qonoyj karunn itoyd.

Applying f1, and f2 patches on top of the new base branch and moving labels along
Efjwyudz w1, akg b8 hoswfok ow xib ic cra lit guro fgoyjb ewz wagamc kijuss ikudz

Creating your first rebase operation

To start, find the starting repository for this chapter in the starter folder and unzip it to a working location.

git branch
git checkout -b cValidator
# Maintainers

This project is maintained by teamWYXZ:
- Will
- Yasmin
- Xanthe
- Zack
- Chris
git add .
git commit -m "Added new maintainer to README.md"
git checkout wValidator
# Maintainers

This project is maintained by teamWYXZC:
git add .
git commit -m "Updated team acronym"
git log --all --decorate --oneline --graph
* c628929 (HEAD -> wValidator) Updated team acronym
| * 2eb17a2 (cValidator) Added new maintainer to README.md
|/
* 3574ab3 Whoops — didn't need to call that one twice
git rebase cValidator
Successfully rebased and updated refs/heads/wValidator.
git log --all --decorate --oneline --graph
* 17771e6 (HEAD -> wValidator) Updated team acronym
* 2eb17a2 (cValidator) Added new maintainer to README.md
* 3574ab3 Whoops — didn't need to call that one twice
git branch -d cValidator

A more complex rebase

Let’s go back to our Magic Square development team. Several people have been working on the Magic Squares app; Will in particular has been working on the wValidator branch. Xanthe has also been busy refactoring on the xValidator branch.

The partial GitUp view of the repository, including the branches wValidator and xValidator.
Gdu xacyuem LifUq qaan en kfo jirovecadz, ixkqawunb vwa jponpker nXusodaxus ubx pTuvoferow.

git log --oneline bf3753e~..
f76b62c (HEAD -> wValidator) Updated team acronym
3f7969b Added new maintainer to README.md
3574ab3 Whoops — didn't need to call that one twice
43d6f24 check05: Finally, we can return true
bf3753e check04: Checking diagonal sums
git log --oneline bf3753e~..xValidator
8ef01ac (xValidator) Refactoring the main check function
5fea71e Removing TODO
bf3753e check04: Checking diagonal sums
git checkout wValidator
git rebase xValidator

Resolving errors

git rebase provides quite a lot of verbose output, but if you look carefully through the output of your command, you’ll see that there’s a conflict you have to resolve in js/magic_square/validator.js.

git rebase --continue
js/magic_square/validator.js: needs merge
You must edit all merge conflicts and then
mark them as resolved using git add
git add .
git rebase --continue
Auto-merging js/magic_square/validator.js
CONFLICT (content): Merge conflict in js/magic_square/validator.js
error: could not apply 3574ab3... Whoops—didn't need to call that one twice
Resolve all conflicts manually, mark them as resolved with
"git add/rm <conflicted_files>", then run "git rebase --continue".
You can instead skip this commit: run "git rebase --skip".
To abort and get back to the state before "git rebase", run "git rebase --abort".
Could not apply 3574ab3... Whoops—didn't need to call that one twice
git rebase --skip
Successfully rebased and updated refs/heads/wValidator.
git log --oneline bf3753e~..
57f62b0 (HEAD -> wValidator) Updated team acronym
b14948d Added new maintainer to README.md
8ef01ac (xValidator) Refactoring the main check function
5fea71e Removing TODO
bf3753e check04: Checking diagonal sums
git log --oneline -3 3574ab3
3574ab3 Whoops — didn't need to call that one twice
43d6f24 check05: Finally, we can return true
bf3753e check04: Checking diagonal sums
git cat-file -p 3574ab3
tree 1b4c07023270ed26167d322c6e7d9b63125320ef
parent 43d6f24d140fa63721bd67fb3ad3aafa8232ca97
author Will <will@example.com> 1499074126 +0700
committer Sam Davies <sam@razeware.com> 1499074126 +0700

Whoops — didn't need to call that one twice
*   96f42e3 (HEAD -> wValidator) Merge branch 'xValidator' into wValidator
|\
| * 8ef01ac (xValidator) Refactoring the main check function
| * 5fea71e Removing TODO
* |   b567a15 Merge branch 'cValidator' into wValidator
|\ \
| * | 9443e8d (cValidator) Added new maintainer to README.md
* | | 76bacc5 Updated team acronym
|/ /
* | 3574ab3 Whoops — didn't need to call that one twice
* | 43d6f24 check05: Finally, we can return true
|/
* bf3753e check04: Checking diagonal sums

Challenge

Challenge: Rebase on top of another branch

You’ve discovered that Zach has also been doing a bit of refactoring on the zValidator branch with the range checking function:

| * 136dc26 (zValidator) Refactoring the range checking function
|/
* 665575c util02: Adding function to check the range of values

Key points

  • Rebasing “replays” commits from one branch on top of another.
  • Rebasing is a great technique over merging when you want to keep the repository history linear and as free from merge commits as possible.
  • To rebase your current branch on top of another one, execute git rebase <rebase-branch-name>.
  • You can resolve rebase conflicts just as you do merge conflicts.
  • To resume a rebase operation after resolving conflicts and staging your changes, execute git rebase --continue.
  • To skip rebasing a commit on top of the current branch, execute git rebase --skip.
Have a technical question? Want to report a bug? You can ask questions and report bugs to the book authors in our official book forum here.
© 2024 Kodeco Inc.

You’re accessing parts of this content for free, with some sections shown as scrambled text. Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.

Unlock now