Course Tonight

Course Tonight

Did You Know?

We design Docy for the readers, optimizing not for page views or engagement

Chapter 12: Rebasing

Estimated reading: 10 minutes 6 views

Parameter: –continue Restart the rebasing process after having resolved a merge conflict.

Parameter: –abort Abort the rebase operation and reset HEAD to the original branch. If a branch was provided when the rebase operation was started, then HEAD will be reset to that branch. Otherwise, HEAD will be reset to where it was when the rebase operation was started.

Parameter: –keep-empty Keep the commits that do not change anything from their parents in the result.

Parameter: –skip Restart the rebasing process by skipping the current patch.

Parameter: -m, –merge Use merging strategies to rebase. When the recursive (default) merge strategy is used, this allows rebase to be aware of renames on the upstream side. Note that a rebase merge works by replaying each commit from the working branch on top of the upstream branch. In case of a merge conflict, the side reported as “ours” is the rebased series starting with upstream, and “theirs” is the working branch. In other words, the sides are swapped.

Parameter: –stat Show a diffstat of what changed upstream since the last rebase. The diffstat is also controlled by the configuration option rebase.stat.

Parameter: -x, –exec command Perform an interactive rebase, stopping between each commit and executing the given command.

Section 12.1: Local Branch Rebasing Rebasing reapplies a series of commits on top of another commit.

To rebase a branch, first checkout the branch and then rebase it on top of another branch.

git checkout topic
git rebase master # rebase current branch onto master branch

Before rebase:

 A---B---C topic
/
D---E---F---G master

After rebase:

             A'--B'--C' topic
            /
D---E---F---G master

These operations can be combined into a single command:

git rebase master topic # rebase topic branch onto master branch

Important: After the rebase, the applied commits will have different hashes. You should not rebase commits you have already pushed to a remote host. This may result in the inability to git push your local rebased branch to a remote host, leaving your only option as git push --force.

Section 12.2: Rebase: ours and theirs, local and remote During a rebase, the meaning of “ours” and “theirs” is switched.

When using merge tools, the following terminology is used:

  • “ours” refers to the local branch (master)
  • “theirs” refers to the remote branch (topic)

On a merge:

c--c--x--x--x(*) <- current branch topic ('*' = HEAD)
\
\
\--y--y--y <- other branch to merge

On a rebase:

c--c--x--x--x(*) <- current branch topic ('*' = HEAD)
\
\
\--y--y--y <- upstream branch

A rebase switches the sides because the first thing a rebase does is to checkout the upstream branch to replay the current commits on top of it.

The rebase will then replay ‘their’ commits on the new ‘our’ topic branch.

Section 12.3: Interactive Rebase This example describes how to use git rebase in interactive mode. Interactive rebase allows you to change commit messages, reorder commits, split commits, and squash commits.

To initiate an interactive rebase, use the following command:

git rebase -i

The -i option enables interactive mode. You can then perform various actions on your commits.

To rearrange the last three commits, run:

git rebase -i HEAD~3

A file will open in your text editor, where you can select how your commits will be rebased. Change the order of your commits, save the file, and close the editor to initiate the rebase with the new order.

To reword a commit message, run the same command:

git rebase -i HEAD~3

Change pick (default) to reword on the commit where you want to change the message. The rebase will stop at that commit, allowing you to modify the commit message. Close the editor to proceed.

You can also change the content of a commit. Change pick to edit for the desired commit. Git will stop at that commit and provide the original changes in the staging area. Adapt the changes by unstaging or adding new changes. Commit the changes once the staging area contains the desired changes.

To split a commit into multiple commits, replace pick with edit for the commit. Git will stop at that commit and place its content into the staging area. Run git reset HEAD^ to move the commit to the working directory. Add and commit the files in a different sequence to split the commit into multiple ones.

To squash multiple commits into one, use the command:

git rebase -i HEAD~3

Replace pick with squash for the commits you want to squash. During the rebase, the instructed commit will be squashed on top of the previous commit, resulting in a single commit.

Section 12.4: Rebase down to the initial commit Starting from Git 1.7.12, it is possible to rebase down to the root commit, which is the first commit made in a repository. Use the command:

git rebase -i

--root

Section 12.5: Configuring autostash Autostash is a useful configuration option when using rebase for local changes. It allows you to bring in commits from the upstream branch without committing immediately.

To enable autostash, run the following one-time configuration command:

git config --global rebase.autostash

Then, when performing a rebase on the upstream branch, use:

git rebase @{u}

The autostash will be applied after the rebase is finished, regardless of whether it was successful or aborted. If there are conflicts between the autostash and the new commits, resolve the conflicts before committing. Autostash simplifies the process of stashing and applying changes during a rebase.

Section 12.6: Testing all commits during rebase Before submitting a pull request, it’s beneficial to ensure that each commit in the branch compiles successfully and passes tests. You can automate this process using the -x parameter.

For example:

git rebase -i -x make

This command performs an interactive rebase and stops after each commit to execute the make command. If make fails, Git will pause the rebase, allowing you to fix the issues and amend the commit before proceeding to the next one.

Section 12.7: Rebasing before a code review To facilitate easier code reviews, it’s recommended to organize scattered commits into more meaningful ones. By reorganizing chronologically created commits into topical commits, the code review process becomes smoother and reduces the chances of bugs slipping through.

The following strategy assumes the following:

  • You’re working on a feature branch based on the master branch.
  • Your feature consists of three main layers: front-end, back-end, and DB.
  • Your commits touch multiple layers simultaneously.
  • Ultimately, you want three commits in your branch: one for front-end changes, one for back-end changes, and one for DB changes.

The strategy involves transforming chronological commits into topical commits. Follow these steps:

  1. Split all commits into multiple smaller commits, each containing only one topic at a time (e.g., front-end, back-end, DB changes).
  2. Reorder the topical commits and squash them into single commits for each topic.

Example:

$ git log –oneline master..
975430b db adding works: db.sql logic.rb
3702650 trying to allow adding todo items: page.html logic.rb
43b075a first draft: page.html and db.sql

$ git rebase -i master

This will be shown in the text editor:

pick 43b075a first draft: page.html and db.sql
pick 3702650 trying to allow adding todo items: page.html logic.rb
pick 975430b db adding works: db.sql logic.rb

Change it to:

e 43b075a first draft: page.html and db.sql
e 3702650 trying to allow adding todo items: page.html logic.rb
e 975430b db adding works: db.sql logic.rb

Git will apply one commit at a time and prompt you. You can then perform the following steps:

  • When stopped at a commit, you can amend the commit using git commit --amend.
  • Once you’re satisfied with the changes, run git rebase --continue.

Repeat these steps for every commit.

Afterward, you’ll have the following commits:

$ git log --oneline
0309336 db adding works: logic.rb
06f81c9 db adding works: db.sql
3264de2 adding todo items: page.html
675a02b adding todo items: logic.rb
272c674 first draft: page.html
08c275d first draft: db.sql

Run the rebase one more time to reorder and squash:

$ git rebase -i master

This will be shown in the text editor:

pick 08c275d first draft: db.sql
pick 272c674 first draft: page.html
pick 675a02b adding todo items: logic.rb
pick 3264de2 adding todo items: page.html
pick 06f81c9 db adding works: db.sql
pick 0309336 db adding works: logic.rb

Change it to:

pick 08c275d first draft: db.sql
s 06f81c9 db adding works: db.sql
pick 675a02b adding todo items: logic.rb
s 0309336 db adding works: logic.rb
pick 272c674 first draft: page.html
s 3264de2 adding todo items: page.html

NOTICE: Ensure that you tell Git rebase to apply/squash the smaller topical commits in the order they were chronologically committed. Otherwise, you might encounter unnecessary merge conflicts.

When the interactive rebase is completed, you will have the following commits:

$ git log --oneline master..
74bdd5f adding todos: GUI layer
e8d8f7e adding todos: business logic layer
121c578 adding todos: DB layer

Recap:

You have successfully rebased your chronological commits into topical commits. It’s important to note that you may not need to perform this process every time, but when necessary, you now have the knowledge and capability to do so. Additionally, you have gained a deeper understanding of Git rebase.

Section 12.8: Aborting an Interactive Rebase You have started an interactive rebase. If you encounter any issues or decide to abort the rebase, follow these steps:

>

  • In the editor where you pick your commits, delete all commits and actions (lines not starting with the # sign).
  • By removing everything, the rebase will be aborted.
  • The help text in the editor provides the following hint:

    # Rebase 36d15de..612f2f7 onto 36d15de (3 command(s))
    #
    # 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 = like "squash", but discard this commit's log message
    # x, exec = run command (the rest of the line) using shell
    #
    # These lines can be re-ordered; they are executed from top to bottom.
    #
    # If you remove a line here THAT COMMIT WILL BE LOST.
    #
    # However, if you remove everything, the rebase will be aborted.
    # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    # Note that empty commits are commented out

    Section 12.9: Setup git-pull for automatically performing a rebase If your team follows a rebase-based workflow and you want each newly created branch to perform a rebase operation instead of a merge operation during a git pull, you can set it up by adding the following to your .gitconfig or .git/config file:

    [branch

    ] autosetuprebase = always

    You can also achieve this using the command line:

    git config [--global] branch.autosetuprebase always

    Alternatively, you can configure the git pull command to always behave as if the --rebase option was passed:

    [pull]
    rebase = true

    This can be set up using the command line as well:

    git config [--global] pull.rebase true

    Section 12.10: Pushing after a rebase After performing a rebase and rewriting history, you may encounter issues when executing git push. By default, it will complain about rewriting history. To overcome this, you can use git push --force, but it is recommended to consider git push --force-with-lease. This command ensures that the push fails if the local remote-tracking branch differs from the branch on the remote. It helps avoid overwriting someone else’s recent push.

    Note: Be cautious when using git push --force or git push --force-with-lease as they rewrite the branch’s history. If other contributors have pulled the branch before the forced push, they may encounter errors during their git pull or git fetch operations due to the diverged local and remote histories. It is best to coordinate with other contributors to minimize such errors.

    Leave a Comment

    Share this Doc

    Chapter 12: Rebasing

    Or copy link

    CONTENTS