
Git rebase in depth - ddevault
https://git-rebase.io
======
gwright
About 99.9% of the time when people talk about rebase they talk about
‘editing’ history or ‘rewriting’ history as in the first sentence of the
article.

I find that terminology terribly misleading and when I was learning git and
rebase it confused the heck out of me.

No commits are harmed in the operation of `git rebase`. All the commits you
had in the repo before the rebase are _still_ in the repo. Git rebase creates
a new sequence of commits and after doing its work relocates the branch name
to the tip of the new sequence but you can easily access the previous commits
if need be:

    
    
        $ git co feature-branch
        $ git rebase develop
        $ git co -b before-rebase-feature-branch feature-branch@{1}

~~~
Nullabillity
It's not 'editing' the raw history files, but you're still presenting a false
history to your coworkers. To me there are essentially two kinds of rebases:

\- Summarizing history: squashing "implemented subfeature A.A" and
"implemented subfeature A.B" into "implemented feature A"

\- Rewriting history: moving commits around, changing the base commit, and so
on

In my opinion summarizing history is acceptable, you're making a creative
decision that certain information will not be useful in the review/when trying
to understand the code in the future.

Rewriting, on the other hand, is essentially lying. You're creating repository
states that never existed, and which you have never tested. In the worst case,
consider the following history:

    
    
        *     F: (master) Merge branch 'component2'
        |\  
        | *   E: (component2) Fixed component 2's integration with 1
        | *   D: (component2) Merge branch 'master' into component2
        | |\  
        | |/  
        |/|   
        * |   C: (master) Refactored component 1's API
        | *   B: (component2) Implemented component 2 that depends on 1
        |/  
        *     A: (master) Base
    

Yes, it could probably be completely linearized, but that would be a horrible
idea. Commit B will leave the repository in a completely nonsensical state.
Sure, you could squash in E to mitigate it (since, luckily, nothing else
happened in component 2 in the meantime), but then you're still stuck
explaining what will likely look like a bunch of really weird design decisions
compared to if you had designed against component 1's new API immediately.

Historical context matters. If in doubt, don't rebase. _Never_ `git pull
--rebase` blindly.

~~~
gwright
It isn't lying. Advocates of rebase are always talking about a work flow where
you are curating a set of proposed changes before merging into your "public"
branches (.e.g, development or master).

No one is advocating that you use rebase on your public branches or basically
any branch that has been "published". We are talking about feature branches or
spikes or branches that exist just on one developer's machine.

~~~
Nullabillity
You're lying about the path that you took to get to that point, and you're
creating a lot of (public) nonsense commits on the way there (unless you're
very careful, and/or overly squash-happy).

Whether you've published the true history earlier is irrelevant to that
discussion.

~~~
gwright
Let me try again. I'm advocating that you use rebase to improve the quality of
your changes that will be reviewed before merging or even before being
reviewed at all.

If I make three commits and then realize that I should have included something
in the first commit, I use rebase to create a new sequence of three commits
that has the corrected version of the first commit. I haven't shared those
commits with anyone, this is just work that I've done locally.

Are you seriously advocating that creating a pull request with: (A, B, C,
A-fixup) is better than using rebase and then creating a pull request with:
(better-A, B, C)?

You think that second case is "lying" because I didn't show the intermediate
step that included the mistake?

~~~
Nullabillity
Yes, it is lying.

You can mitigate most of the damage if it is convincing enough (for example,
go through B' and C' and make sure everything still makes sense at each
point), but realistically nobody is going to do that, because it's pretty
inefficient way to spend your time. And even then, you're still removing
context (unless you're just fixing a typo).

> I'm advocating that you use rebase to improve the quality of your changes
> that will be reviewed before merging or even before being reviewed at all.

That was clear from the start. But the fact that X breaks Y doesn't imply that
Y is a good idea when X doesn't apply.

~~~
gwright
I really don't understand why you are choosing to use the word "lying".

Us mere humans make mistakes all the time. Typos, omissions, false starts, and
so on. What is the value of throwing that raw set of events at a reviewer or
complicating the understanding of the changes when viewed in retrospect from
the future? What is the reason you call curating the work into a more polished
form "lying"? Why do you think the time spent being intentional about changes
isn't valuable when compared to the time spent by a reviewer (or your future
self) to sort through the flotsam and jetsam of your intermediate work?

~~~
fulafel
But reviewers in most Git workflows mainly look at PRs. Then if as a reviewer
you want to see how the sausage was made, you can zoom in on the commits,
including all the messy reality of how the work was done. In some
circumstances you might of course want to hide this, but in an open and safe
collegial environment this lets the reviewer understand your thought and work
process.

~~~
raimue
The reviewer also won't see all the things the author tried without ever
committing these states. They don't need to see all the messy steps, or they
would have needed to look over the authors shoulder all the time.

I rather review the final patch series with changes in logical order and not
necessarily in the order the code was written or with intermediate work that
was later reverted or changed again. I do look at commits, because also every
commit message counts and is supposed to explain the individual change.

~~~
fulafel
Sure, it's not a perfect record. But as in most things, perfect is the enemy
of good.

The messy reality is valuable, when talking with your teammates about how the
work was done and what kind of bumps were along the way. It's not about
looking over their shoulders, it's about using data to develop together as a
team, eliminating hinderances, etc - if you have the mutual trust to do that.
And of course you yourself can go back and look for patterns of mistakes or
problematic areas in code based on your history.

Like I said, to judge the change its, the whole PR diff is usually the most
useful unit of inspection when you just want to see what happens. And if it's
a big pr, you can of course always merge child PR's or branches against the
big PR/branch, and look at the merge diffs.

~~~
fulafel
Another formulation of the "learning as a team" idea-

The science principle of publishing your experiments, including failed ones,
has the same benefits in sw engineering: others can build on your failed
attempts, or save time by not replicating them.

------
malingo
My eyes were opened on git-rebase when I read [https://matthew-
brett.github.io/pydagogue/rebase_without_tea...](https://matthew-
brett.github.io/pydagogue/rebase_without_tears.html)

The full version of the command as

    
    
        $ git rebase --onto new-base start end
    

takes the commit range (start,end] and re-commits them on top of the new-base
commit. The commit range doesn't have to be a full branch and you don't even
need to be on the branch to run the command this way. It's very intuitive and
I nearly always use the full version now.

I've also gotten into the habit of "pinning" my branch before I rebase so that
I have it in its original form. If the branch name is my-branch, then the
command

    
    
        $ git branch my-branch{-hold,}
    

which is a handy (bash-specific?) shortcut of

    
    
        $ git branch my-branch-hold my-branch
    

leaves you on my-branch and creates a new branch label called my-branch-hold
that points to the same place.

EDIT: clarification of pre-rebase branching

~~~
gbacon
I’ll sometimes do the same for a rebase that looks like it will be hairy, and
I like to call the bookmarks, for example,

    
    
        git branch my-branch-mulligan

------
zemo
Git rebase is great. Honestly I think the argument that "if you have to push
-f that means rebase is wrong" is making a huge assumption about how people
use branches and why people are force pushing branches.

Force pushing branches is what you do when you have pushed a branch that you
expect to modify. Why would you do that? Because that's how Github and
Bitbucket have taught people to conduct PR's.

If your immediate reaction is that "rebase is bad UX", ask yourself whether or
not pull requests are good UX. I honestly think rebase is great, but that pull
requests are extremely bad UX, and the UX blame is misplaced on rebase when
where it really belongs is on pull requests.

~~~
u801e
> Force pushing branches is what you do when you have pushed a branch that you
> expect to modify. Why would you do that? Because that's how Github and
> Bitbucket have taught people to conduct PR's.

I thought that Github and Bitbucket encouraged people to push up additional
commits to fix issues in their PR. So, a typical PR will end up with a commit
history like:

    
    
      Implement a feature method
      Add calls to new feature method
      Update to version 1.2.3
      fixing missing semi-colon
      addressed comments
      one more thing
      now its working
    

People who force-push are the ones who are trying to keep a clean commit
history (meaning you don't have those extra 4 commits). So, your point about a
PR being bad UX versus a rebase is correct, but not for the reason you state.

~~~
cyphar
Almost no projects I've worked on that use GitHub ask people to push fixup
commits. In fact, maintainers (like me) often have to ask people to squash
their commits into reasonable chunks.

~~~
Liskni_si
It's not the project that asks people to push fixups, it's that GitHub, as
opposed to e.g. Gerrit, makes it hard to see what changed (how your comments
were addressed) after a force push, so it's best that people only add commits.

Ideally they'd use git commit --fixup=<sha> -p, and then git rebase
--autosquash when the maintainer approves the merge, but few people care.

(And what I'm saying isn't really accurate any more since GitHub does show
force-pushes in the pull request UI these days and one can run git range-diff
on that. But this wasn't possible last year.)

------
Sahhaese
When you have a command so confusing that you need an entire website dedicated
to a single command, and still need to warn against using it, then _perhaps_
you've got the UX wrong.

~~~
Sir_Cmpwn
git is a version control framework more so than a version control system. It
starts from simple primitives, exposes them to the user, then builds complex
and powerful tools on top of them. Because git rebase gives you primitives to
accomplish high-level tasks (e.g. "reorder these commits"), the learning
experience is different because you have to learn the low-level details to
accomplish your high-level task. However, because those low-level details are
accessible to you, you are afforded a greater flexibility in inventing new
high-level tasks.

~~~
Sahhaese
But those high level tasks could also be exposed directly. There's nothing to
stop there being more commands which more directly accomplish the desired
tasks.

The idea that git is good _because_ it is difficult to use is just "git
snobbery", as is the idea that it _must_ be difficult because it's a DVCS.

There's nothing to stop git having two levels of the API, one exposed for
tools to build off of with the full complexity and another for every day use.

~~~
Espressosaurus
Mercurial's interface is just fine, and these days it's just as powerful as
Git.

Things could be better. There's an existence proof. It just lost the mindshare
war and so now we're stuck with Git, which I still have to look up basic
syntax for because its command set is contradictory and makes no sense. (Is it
git <x>? git <y> \--x? git <z> <a-b>? Something else entirely? Who knows!)

~~~
guitarbill
I used to agree with this, now I've stopped worrying. Because if git is the
worst part of your workflow, that's a great problem to have. But at many
places, git is the _best_ part.

(I've also had to work with various IBM CVS, and they are universally garbage.
When I get frustrated at git, all I have to do is think back to those.)

So yes, Mercurial is better, but is it worth the effort? Not in my experience.

~~~
hnthrowaway919
I know it's popular to shit on anything that isn't git these days, but you
mentioned IBM CVS. I've used a couple of them, but primarily RTC (Rational
Team Concert). I know that was an IBM acquisition and not a home-grown
solution (what wasn't?). I personally prefer some features of RTC over how to
do the equivalent in git. Namely, being able to move change sets (think
commits) around freely, not having to deal with rebasing/merging into whatever
branch you want to put it in/on. I also think there's something to be said for
a CVS system that is built for teams that work together daily, compared to a
system that's built for a "remote contributor" model.

That being said, I use git daily and find that I'm able to do everything I
want and more, so I'm not looking to make a switch. Unfortunately, most people
don't care to learn how to use git beyond "checkout, commit, push, call for
help".

~~~
guitarbill
There was one before RTC, called CMVC, which was truly awful, especially using
after 2010 felt like an insult to developer productivity.

I forget all the reasons why RTC isn't great, but the main one: if the server
goes down, you're screwed. This happened several times, and we basically went
to the pub instead of working. Slow to check out. Streams sucked compared to
branches (especially when the server admin restricted creation of streams,
meaning you simply could not branch at all if I'm remembering), and the
capability to stash changes/switch branches to work on different work items if
one was blocked was also more cumbersome. Code review was terrible.

A centralised paradigm does simplify things a lot mentally, but the workflow
suffers IMO.

~~~
hnthrowaway919
You certainly make some good points about the downsides of RTC. RTC's streams
are often compared to git's branches because they're the closest construct,
but they are definitely very different and have pretty minimal overlap,
considering they're basically the parallel construct. IMO stashing changes was
not bad (suspending change sets, I believe it was called), but perhaps I was
mostly doing that within 1 stream and not between streams. I agree that code
review was not great, though I'm not a _huge_ fan of GitHub's comment/PR
review mechanism either. I'm not aware of code reviewing built in to git
itself, though I could be totally missing it.

~~~
guitarbill
> I'm not aware of code reviewing built in to git itself

I guess you can pull a branch or email a patch and diff it with the diff tool
of your choice.

There's a few options for gir review UIs, e.g. Gerrit or GitLab. Kind of
unix-y, just have the VCS be a good VCS.

------
Amorymeltzer
The warning regarding "public, shared, or stable branches" is always
warranted, but I think those warnings end up reverberating where they needn't.
Before interacting with anything public or shared — when working solo or
locally — `rebase` can be hugely helpful. When starting out with something
complicated, I often make separate commits for different files or steps; using
rebase to reorder commits or amend can make turning your first steps into a
viable change much easier, and can help with merge conflicts down the line. I
also find it helpful for large commit messages; rather than needing to write
everything at once, making liberal use of `fixup` or `squash` can keep
disparate thoughts or bug fixes manageable.

I'd never use it on a public or shared branch, but `rebase --interactive` and
`--exec` are some of my most-mused git aliases.

~~~
V-2
I'd use rebase --interactive quite aggressively on a public branch when it's a
_feature branch_ that's not yet been merged. As I'm the only owner of it, the
way I see it I owe no guarantees to anyone. You're welcome to watch it, but
it's work in progress in every aspect.

~~~
Amorymeltzer
Github and refined-github[1] make it easier, by keeping track of changes from
a `push -f` and having merge/squash/rebase options on merging, but I know of
large projects with an explicit "no rebasing" rule as it can get confusing for
reviewers. I'd say it depends on the project, maintainers, and general
workflow. Which is good!

1: [https://github.com/sindresorhus/refined-
github](https://github.com/sindresorhus/refined-github)

------
dbaupp
The 'push -f' suggestion could instead recommend 'push --force-with-lease' to
be less error prone in case one is accidentally pushing to a concurrently
modified branch.

Also, unless the diagram is confusing with the alignment, the "rebase to
rebase" example seems to be implicitly assuming --onto, because the last
common ancestor of 'master' and 'feature-2' includes 2 commits on that branch:
the first of 'feature-1' and then the one that is only on 'feature-2'.

~~~
Sir_Cmpwn
I've heard this before, but I felt that `--force-with-lease` requires a
lengthier explanation in an an already intimidating article, is harder to
type, and generally isn't useful for users of the Sourcehut workflow. It's
definitely a useful tool, though. Maybe I should add a footnote.

~~~
chris_mc
I don't get the "extra letters" argument as a Computer Scientist. Most of my
time is spent figuring out what I'm going to do before I type anything,
whether that's research, staring at code for hours to see how it works, or
something else. I could type 3x as many characters each day and would probably
only work an extra 10 minutes per day. Maybe I'm the exception, but I don't
like brevity for brevity sake.

~~~
recursive
You could also consider it "harder to remember".

~~~
chris_mc
I normally use "git push --fo<TAB>" or "git push --fo<UP ARROW>" in zsh, but
after seeing the switch option "\--force-with-lease" pop up each time I've
memorized it now. I let my CLI do the work for me most of the time, but when I
can't there's always "man COMMAND". After doing anything a bunch of times, you
remember it.

------
pizzapill
I've you use rebase to rewrite history a lot I have found/developed a couple
helpful commands (tested & working on Linux bash).

Put those in your ~/.gitconfig:

    
    
      [alias]
       fu = "!f() { local msg=\"fixup! $(git log --oneline -n1 | cut -d ' ' -f2-)\"; git commit -am \"${msg}\" && git rebase -i --autosquash HEAD~2; }; f"
       fuc = "!f() { local msg=\"$(git log --oneline -n1 | cut -d ' ' -f2-)\"; if [[ \"${msg}\" != "fixup!"* ]]; then msg=\"fixup! ${msg}\"; fi; git commit -am \"${msg}\"; }; f"
       xx = "!f() { git reset --hard && git clean -f -d; }; f"
    

From now on:

git fu = (git fix up) combines last commit and all staged changes into one
commit with the last commit message

git fuc = (git fix up comment) commits all staged changes as a new commit with
the last commit message, but prefixed with "fixup!". Except if the last commit
message is already prefixed with "fixup!". Now you can work on the same thing
but commit incremental steps. In the end you just do: git rebase -i master (or
similar) and they will be all in one commit.

git xx = get rid off all unstaged/uncommited changes in current directory.
Very destructive, very useful.

Last but not least. If you have a lot of "fixup!" or "squash!" commits and
need to interactively rebase without autosquashing them do:

git rebase --no-autosquash -i master

------
sktrdie
Weird they don't talk of the `git commit --fixup=` command. And then
`--autosquash` when rebasing.

~~~
umvi
Is --fixup the same as --amend?

~~~
Liskni_si
Conceptually, it's similar, and after git rebase --autosquash, the result is
the same. But you can amend/fixup (call it whatever you want) any commit in
your branch, not just the last one.

------
jaequery
FWIW i've never really needed rebase. i am pretty happy with seeing all the
commits that ever happened.

~~~
rich-tea
What do you use your git history for? History is either worth keeping, in
which case you should maintain it like any other artifact, or it's not, in
which case you should squash down master to a single commit every time you
merge.

But maybe you use your history for something else that I haven't considered.

~~~
rgoulter
While I like the idea of rearranging commits to convey a nice (but "not how it
originally happened") development sequence, I think in practice this matters
less than (say) good commit messages, or the difference between merging and
rebasing.

(--fixup type commits aside).

Practical benefits from not squashing history:

\- Can bisect to find bug introduction.

\- Can annotate/praise/blame to find who/when some change was made.

\- Adam Tornhill's "Code as a Crime Scene" argues that it'd be beneficial to
consume VCS history to provide health metrics on the codebase. (e.g. use VCS
to check which sources have many contributors (thus potentially high defects),
or check for "lost knowledge" from developers who have left).

\- Can build/run an older version of the software.

But is there really a big advantage from putting time into maintaining a
sequence of commits? EDIT: Ah, I see another comment point out that
"maintaining a nice history" tends to mean fixing very borked commits. That
makes sense. :-)

~~~
rich-tea
All of these advantages don't make sense if half your commits are broken
versions of the software. Rebasing helps ensure that each commit is valid.
That's important for the reasons you mention. Having a log of what you
actually did is not important.

------
andreareina
The reflog has saved my bacon more times than I care to admit.

------
module0000
I just recently(last month) broke my habit of `git checkout feature && git
merge master`, replacing it with `git checkout feature && git rebase master`.
Don't know why I spent so long doing it with merge, and just mentally trying
to ignore the useless commit messages that resulted.

EDIT: I meant to include this link, which is a pretty brief yet thorough
explanation of when/how/why to rebase:
[https://www.atlassian.com/git/tutorials/merging-vs-
rebasing](https://www.atlassian.com/git/tutorials/merging-vs-rebasing)

------
cryptonector
I've a script I need to publish that does a bisect-like thing to rebase across
thousands of commits quickly and ensuring that when there are conflicts you
are asked to resolve them at the commit that caused them. It was original
written by @vdukhovni (GitHub).

Also, I've this gist on how to think about git:
[https://gist.github.com/nicowilliams/a6e5c9131767364ce2f4b39...](https://gist.github.com/nicowilliams/a6e5c9131767364ce2f4b3996549748d)

------
chrismorgan
A few markup errors:

• In a number of code blocks, angle brackets are not escaped, and so text
doesn’t appear in the end result.

• `<span style="color: maroon">#include</span> &ltstdio.h&gt;` lacks the
semicolon

• The paragraph immediately after the #conflicts heading lacks its <p>.

I also think it would be worthwhile mentioning in the first footnote a hazard
of empty commits: that they will be dropped by default when rebasing.

------
pricechild
I'm missing something obvious but all of the history you show is in the
reverse order to default behaviour?

Am I missing a config setting you explain somewhere?

~~~
raimue
This looks normal. The order of the 'git rebase' plan shows the sequence in
which commits will be applied from top to bottom.

You are probably thinking of 'git log', which uses the reverse order with the
newest commit at the top.

~~~
pricechild
Huh... how long have I been using git...?!

Not sure why I was convinced otherwise, must be log's behaviour as you say.
Had to test to believe it!

------
amelius
Regarding the rewriting of history: can't the git history itself be stored in
git somehow, so its change over time (and e.g. by tools such as git-rebase) is
properly tracked? Of course you'd need a meta tool to change the history of
the history, but perhaps it's not needed?

~~~
Sir_Cmpwn
It is: man git-reflog.

------
human20190310
I fear that any process that allows for a _git push -f_ at any time is
eventually going to result in someone hammering a shared/public repo when they
meant to hammer their personal repo.

~~~
oauea
Just block force pushes to shared branches.

~~~
blueline
one of us owes the other a coke :-)

~~~
human20190310
The author should add "block force push to master" to the comprehensive guide
:)

------
madlynormal
Is there a benefit to rebasing vs merging, specifically if your flow is to
squash commits before merging back into base?

~~~
zemo
Most people's aversion to rebase is an aversion to altering history. Since
squashing alters history anyway, I'd argue that you might as well just use
rebase when you do it.

In a rebase-oriented workflow, every commit has exactly one parent, and the
commit history is entirely linearized. Merge commits have more than one
parent, which means going backwards through the history means that you have to
essentially navigate the branching structure to navigate the history. That
makes it pretty hard to do!

A linear history is comparatively easier to reason about than a history with
all of its branches. It's also, in a sense, less "true"! So it depends what
you care about. Do you care about telling the exact story of everything that
happened to everyone on the project, or do you care about the history of
changes to the one shared copy?

Linear histories also make it easy to step backwards through the history one
commit at a time. I personally just do `get checkout HEAD^` over and over,
walking through the history in reverse, since most breakages are noticed
within a few commits of their occurrence. I really like being able to do that.
A lot of people think that's useless!

If you have one copy of the project that is considered authoritative, and all
developers are synchronizing via that single authoritative copy, creating a
clean and linear history is possible.

------
falsedan
> _One of Git 's core value-adds is the ability to edit history_

I didn't make it past this line. git is extremely good at keeping history
immutable; it's also good at creating new, alternative histories and moving
between them.

~~~
kadoban
Editing history in git is also well supported and _very_ commonly used, and
git does it well. It's just not for absolute beginners, and the UI is
occasionally not great. If git did not want you to ever change history,
filter-branch, rebase, rebase -i, fixups, squashes and a bunch of other
inclusions are odd, to say the least.

~~~
falsedan
My point is, git doesn't let you edit history; it lets you make branches
easily & the original history remains unaltered. It's trivially easy to detect
altered history, and talking about 'editing history' gives the impression that
repos are vulnerable to attack.

~~~
kadoban
What wording would you suggest to refer to these kinds of operations?
Replacing history?

You mentioned "altered" history, which to me isn't much different from
"edited" or "modified", though maybe that was just a slip and not your
preference?

There does need to be some term for it. If I push a reordered branch, I
clearly did more than nothing, even if we don't want to call that modifying
history.

I do question if any term will work perfectly, or if there is any full
solution other than one learning git to an intermediate level before
discussing it. The problem, as I see it, is that there are (at least) two
concepts of history, there is the DAG of commits, where ancestors are older,
and there are branch-heads where you can change what they point to in
unrestricted ways (pretty much the reflog). I'm not sure English has a really
good metaphor that's going to capture everything.

------
limxto0
All the git-rebase-fu I have ever needed while working with pull requests, I
have found in this well written guide:
[https://github.com/susam/gitpr](https://github.com/susam/gitpr)

Quoting from this document below.

    
    
      # Rebase topic branch on the main development branch (optional).
      git checkout TOPIC-BRANCH
      git rebase master
    
      # Edit commits, e.g., last 3 commits in topic branch (optional).
      git checkout TOPIC-BRANCH
      git rebase -i HEAD~3
    
      # Force push rebased/edited commits to the pull request (optional).
      git push -f origin TOPIC-BRANCH

~~~
gitzen
Thank you for sharing this link. Until now, I never understood properly how
rebase and fast-forward merges work. This simple note in this document made it
all clear.

"Beginners to this workflow should always remember that a Git branch is not a
container of commits, but rather a lightweight moving pointer that points to a
commit in the commit history.

    
    
        A---B---C
                ↑
             (master)
    

When a new commit is made in a branch, its branch pointer simply moves to
point to the last commit in the branch.

    
    
        A---B---C---D
                    ↑
                 (master)
    

A branch is merely a pointer to the tip of a series of commits. With this
little thing in mind, seemingly complex operations like rebase and fast-
forward merges become easy to understand and use."

Suddenly everything makes sense now!

------
rich-tea
What I really like to do is make actual fixup (or squash) commits during a
code review and just push these to the branch normally. That way reviewers can
easily keep up with the changes. Right at the end, the maintainer requests
that the original developer does a rebase --autosquash before the branch is
actually merged.

This works really well but I rarely see people talk about it. It means you
don't have to use something complicated like github or gitlab to keep up with
rebases. It works for everyone.

~~~
sktrdie
Indeed this is the whole reason I like fixups. Reviewers can actually keep up
with the requested changes and know exactly which fixup-commit is related to
which change.

