So I've just learned that git rebase -i allows users to merge individual commits in the middle of a branch's history. For that,

$ git rebase -i

This should bring a list of all commits in reverse order, similar to the one listed below:

pick 2361d4d implements something
pick a700451 fixes a bug
pick 79f9d04 fixes a bug again
pick 3172f07 implements some other thing

# Rebase 484d6d2..3172f07 onto 484d6d2 (4 commands)
#
# Commands:
# p, pick  = use commit
# r, reword  = use commit, but edit the commit message
# e, edit  = use commit, but stop for amending
# s, squash  = use commit, but meld into previous commit
# f, fixup [-C | -c]  = like "squash" but keep only the previous
#                    commit's log message, unless -C is used, in which case
#                    keep only this commit's message; -c is same as -C but
#                    opens the editor
# x, exec  = run command (the rest of the line) using shell
# b, break = stop here (continue rebase later with 'git rebase --continue')
# d, drop  = remove commit
# l, label  = label current HEAD with a name
# t, reset  = reset HEAD to a label
# m, merge [-C  | -c ]  [# ]

It's possible to merge commit 79f9d04 with a700451 by updating the list of commands to set squash instead of pick in the commit you want to flatten onto the previous one, such as:

pick 2361d4d implements something
pick a700451 fixes a bug
squash 79f9d04 fixes a bug again
pick 3172f07 implements some other thing

(...)

Once we save the commit, Git opens an editor to rework the new commit message for the squashed commits, and you're set.

  • lysdexic@programming.dev
    hexagon
    ·
    1 year ago

    As a followup to this post, I've started including git rebase -i in my workflow when working on local branches. Basically things went like this:

    • I start working on an issue in a dedicated feature branch.
    • I commit small changes such as "Updates this feature in this component", "fixes this glitch on this function", "removes this dead code".
    • I keep going until I'm done.
    • If I stumble upon small nits, I just commit them right at the head.
    • when I'm done I run an interactive rebase and move these small commits around to sort commits that belong together.
      • nits and followup fixes are squashed together,
      • cleanup commits are moved to the start of the branch to line them up to be pushed as a separate pull request,
      • push a PR for the issue

    To me this really paves a way to a far better workflow and faster turnaround times.