git-rebase
Integrate changes from one branch onto another
TLDR
Rebase the current branch on top of another specified branch
Start an interactive rebase, which allows the commits to be reordered, omitted, combined or modified
Continue a rebase that was interrupted by a merge failure, after editing conflicting files
Continue a rebase that was paused due to merge conflicts, by skipping the conflicted commit
Abort a rebase in progress (e.g. if it is interrupted by a merge conflict)
Move part of the current branch onto a new base, providing the old base to start from
Reapply the last 5 commits in-place, stopping to allow them to be reordered, omitted, combined or modified
Auto-resolve any conflicts by favoring the working branch version (theirs keyword has reversed meaning in this case)
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!
--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.