LinuxCommandLibrary

git-rebase

Integrate changes from one branch onto another

TLDR

Rebase the current branch on top of another specified branch

$ git rebase [new_base_branch]
copy

Start an interactive rebase, which allows the commits to be reordered, omitted, combined or modified
$ git rebase [[-i|--interactive]] [target_base_branch_or_commit_hash]
copy

Continue a rebase that was interrupted by a merge failure, after editing conflicting files
$ git rebase --continue
copy

Continue a rebase that was paused due to merge conflicts, by skipping the conflicted commit
$ git rebase --skip
copy

Abort a rebase in progress (e.g. if it is interrupted by a merge conflict)
$ git rebase --abort
copy

Move part of the current branch onto a new base, providing the old base to start from
$ git rebase --onto [new_base] [old_base]
copy

Reapply the last 5 commits in-place, stopping to allow them to be reordered, omitted, combined or modified
$ git rebase [[-i|--interactive]] [HEAD~5]
copy

Auto-resolve any conflicts by favoring the working branch version (theirs keyword has reversed meaning in this case)
$ git rebase [[-X|--strategy-option]] theirs [branch_name]
copy

SYNOPSIS


git rebase [options] [upstream] [branch]
git rebase [options] --onto newbase [upstream] [branch]
git rebase [options] (--continue | --abort | --quit | --skip | --edit-todo)

PARAMETERS

-i or --interactive
    Engage interactive rebase, allowing modification of individual commits (e.g., pick, reword, edit, squash, fixup, drop, exec).

--onto newbase
    Reapply commits from the current branch, which are not in upstream, onto a new base commit specified by newbase.

--continue
    Resume the rebase operation after resolving conflicts or performing an edit action.

--abort
    Terminate the rebase process and reset the branch to its state before the rebase began.

--quit
    Stop the rebase process, but keep the current state of the working directory and index as they are. Does not revert changes.

--skip
    Skip the current commit that caused a conflict and proceed to the next commit in the rebase sequence.

--autosquash
    Automatically mark commits for 'squash' or 'fixup' if their message starts with 'squash! ' or 'fixup! ' during interactive rebase.

--rebase-merges
    Attempt to re-create merge commits during the rebase, preserving their structure. This is an advanced option for complex histories.

--root
    Rebase all commits reachable from the specified branch, up to the initial commit of the repository, rather than just up to an upstream.

--exec command
    Execute an arbitrary shell command after each commit during an interactive rebase. Useful for running tests or checks.

DESCRIPTION


The git-rebase command is a powerful tool for rewriting commit history. It allows you to move, combine, or edit a sequence of commits, making your project's history cleaner and more linear. Unlike git merge, which integrates changes by creating a new merge commit, git rebase reapplies commits from one branch onto another, effectively changing their base. This results in a linear history, which can be easier to read and understand, especially in a collaborative environment.

Common uses include:
• Cleaning up local commits: Before pushing to a shared remote, you can use interactive rebase to squash small, incremental commits into logical units, reword commit messages, or drop unnecessary commits.
• Integrating upstream changes: Instead of merging upstream changes into your feature branch, you can rebase your feature branch onto the latest upstream branch. This makes it look like you started your feature branch from the very latest code, avoiding unnecessary merge commits.
• Moving commits: Rebase can move a series of commits from one base to another, effectively detaching them from their original history and reattaching them elsewhere.

While highly beneficial for maintaining a clean project history, git-rebase rewrites commit SHAs. This makes it a potentially dangerous operation on branches that have already been pushed to a shared remote, as it can cause divergence for other collaborators. Therefore, the general rule of thumb is: "Do not rebase published history."

CAVEATS


1. Rewrites History: git rebase fundamentally changes the SHA-1 hashes of rewritten commits. This is the primary reason why it's generally advised not to rebase branches that have already been pushed to a shared remote repository. Doing so can cause significant history divergence for other collaborators, requiring complex resolution (e.g., force pushing and then other users having to re-clone or reset).
2. Force Pushing: If you rebase a branch that was previously pushed, you will need to use git push --force or, preferably, git push --force-with-lease to update the remote. --force-with-lease is safer as it prevents overwriting remote work if someone else has pushed to the same branch since your last pull.
3. Conflict Resolution: Rebasing can lead to conflicts if the changes being rebased conflict with the target branch. Resolving these conflicts can be repetitive and challenging, especially across many commits.
4. Complexity: While powerful, interactive rebase can be complex. Missteps can lead to lost commits or a convoluted history if not handled carefully. Always ensure you have a backup or know how to use git reflog to recover.

CONFLICT RESOLUTION DURING REBASE


When git rebase encounters conflicts, it pauses and allows you to resolve them. The process is similar to resolving merge conflicts:
1. Identify conflicts: Git will tell you which files have conflicts. Use git status to see them.
2. Edit files: Open the conflicted files and manually resolve the differences. Remove Git's conflict markers (<<<<<<<, =======, >>>>>>>).
3. Stage changes: After resolving, use git add <file> for each modified file.
4. Continue rebase: Run git rebase --continue. Git will then apply the next commit or finish the rebase.

If you wish to skip a problematic commit, use git rebase --skip. To abandon the entire rebase operation, use git rebase --abort.

INTERACTIVE REBASE COMMANDS


When using git rebase -i, Git opens an editor with a list of commits and instructions. Each line represents a commit, prefixed by a command. You can modify these commands to alter the history:
• pick (p): Use the commit as is.
• reword (r): Use the commit, but edit the commit message.
• edit (e): Use the commit, but pause for amending the commit (e.g., fix a bug, split into multiple commits).
• squash (s): Use the commit, but merge it into the previous commit. A new commit message will be created combining both.
• fixup (f): Like squash, but discards this commit's log message.
• drop (d): Remove the commit.
• exec (x): Run a shell command on the commit.
• break (b): Pause the rebase at the current point, allowing manual intervention before continuing.

HISTORY


git-rebase has been a fundamental command in Git since its early days, reflecting Linus Torvalds' preference for a linear, clean project history. It was designed to provide an alternative to merge commits, allowing developers to integrate upstream changes by re-applying their local work on top of the latest upstream commits. The core functionality of reapplying commits was present from very early Git versions.

The addition of the --interactive (-i) option significantly enhanced git-rebase's power and flexibility. This feature, which enables users to reorder, squash, edit, or drop individual commits, transformed rebase from a simple re-application tool into a comprehensive history rewriting utility. It became crucial for preparing clean, logical commit sets before sharing them.

More recent developments include options like --rebase-merges, which attempts to preserve merge commits during a rebase, addressing a long-standing limitation where rebase would flatten all history. This makes rebase viable for repositories with complex merge-based workflows. The command continues to evolve with improvements aimed at making it safer and more robust, especially concerning conflict resolution and integration with different workflows.

SEE ALSO

git-merge(1): Integrates changes from one branch into another by creating a new merge commit., git-cherry-pick(1): Applies a single commit from one branch onto another. Rebase can be seen as automated cherry-picking of a series of commits., git-reflog(1): Records updates to the tip of branches and other references. Essential for recovering from mistakes during rebase., git-reset(1): Resets the current HEAD to a specified state, often used to undo local commits or resolve rebase issues.

Copied to clipboard