How do I use 'git rebase -i' to rebase all changes in a branch?

Git

Git Problem Overview


Here's an example:

>git status
# On branch master
nothing to commit (working directory clean)
>git checkout -b test-branch
>vi test.c
>git add test.c
>git commit -m "modified test.c"
>vi README
>git add README
>git commit -m "modified README"

Now I want to do a 'git rebase -i' that will let me rebase all commits for this branch. Is there something like 'git rebase -i HEAD~MASTER' or similar. I figure I could do 'git rebase -i HEAD~2', but I really don't want to have to count how many commits have been made. I could also do 'git rebase -i sha1' but I don't want to comb through git log to find the first commit sha1. Any ideas?

Git Solutions


Solution 1 - Git

Ok, I'm asuming the branch is called "feature" and it was branched from "master".

There's this little git command called merge-base. It takes two commits and gives you the first common ancestor of both of those. So...

git merge-base feature master

...will give you the first common ancestor of those two commits. Guess what happens when you pass that commit to git rebase -i, like...

git rebase -i `git merge-base feature master`

Interactive rebase from the first common ancestor of both master and feature branch. Profit! ;)

Solution 2 - Git

The issue with all provided solutions is, they do not allow you to rebase from the very first commit. If the first commit hash is XYZ and you do:

git rebase -i XYZ

You only rebase starting from the 2nd commit.

If you want to rebase from the first commit you do:

git rebase -i --root

Solution 3 - Git

Have you tried: git rebase -i master?

Solution 4 - Git

Use gitk (*nix), or gitx (OS X) or similar on other platforms, and have a look at which commit was the root of your branch. Then run:

git rebase -i <the SHA hash of the root commit>

For example, I have a repository that I inspected using gitx:

gitx screencap

Now that I know the root hash I can run this:

git rebase -i 38965ed29d89a4136e47b688ca10b522b6bc335f

And my editor pops up with this and I can rearrange/squash/whatever as I please.

pick 50b2cff File 1 changes.
pick 345df08 File 2 changes.
pick 9894931 File 3 changes.
pick 9a62b92 File 4 changes.
pick 640b1f8 File 5 changes.
pick 1c437f7 File 6 changes.
pick b014597 File 7 changes.
pick b1f52bc File 8 changes.
pick 40ae0fc File 9 changes.

# Rebase 38965ed..40ae0fc onto 38965ed
#
# Commands:
#  pick = use commit
#  edit = use commit, but stop for amending
#  squash = use commit, but meld into previous commit
#
# If you remove a line here THAT COMMIT WILL BE LOST.
# However, if you remove everything, the rebase will be aborted.
#

I'm sure there's some magic way to convince git to figure out the root of the tree automatically, but I don't know what it is.

EDIT: That magic is this:

git log master..other_feature | cat

Which will show you all the commits on that branch, and piping to cat will disable the pager so you see the first commit immediately.

EDIT: combining the above gives a fully automated solution:

git rebase -i  `git log master..other_feature --pretty=format:"%h" | tail -n 1`~

Solution 5 - Git

The OP's problem as I understand it

This answer applies if you don't actually want to rebase on top of master, but you'd rather just squash all commits into one, since diverging from master.

The problem with rebasing from a different branch

The problem with git rebase -i master is that you may have merge conflicts that you don't necessarily want to deal with at the moment, or you may fix a conflict in one commit, only to fix it again in another commit during the course of the rebase.

The problem with rebasing from a known commit

The whole problem here is that you have to know which commit you have to refer to, either by its SHA, or HEAD~x, etc. This is only a minor annoyance but it is an annoyance.

The better way

If you instead want to rebase all the commits in your current branch, since the most recent commit it shared with its parent branch, you can add the following alias to .gitconfig:

rbi = !sh -c \"git rebase -i `git merge-base $1 HEAD`\" -

Usage

git rbi parentBranch

You can then use an interactive rebase to pick/reword/edit/squash/etc all commits in your branch, since it diverged from the parent branch. My typical flow is to pick the oldest commit (the one at the top), and set all other commits to f (or fixup).

How it works

This alias is just a shell script, that is using an argument which refers to the parent branch. That argument is passed into git merge-base in order to determine the most recent shared commit between that branch, and the current branch.

Solution 6 - Git

Since Git v1.7.10, you can just run git rebase without argument, and it will find the fork point and rebase your local changes on the upstream branch.

You need to have configured the upstream branch for this to work (i.e. git pull without argument should work).

For more details, see the docs for git rebase:

> If is not specified, the upstream configured in > branch..remote and branch..merge options will be used (see > git-config[1] for details) and the --fork-point option is assumed. If > you are currently not on any branch or if the current branch does not > have a configured upstream, the rebase will abort.

Solution 7 - Git

A general solution (if you don't know the name of the upstream branch) is:

git rebase -i @{upstream}

Note that if your upstream (probably a tracking branch) has updated since you last rebased, you will pull in new commits from the upstream. If you don't want to pull in new commits, use

git rebase -i `git merge-base --all HEAD @{upstream}`

but that is a bit of a mouthful.

Solution 8 - Git

git rebase -i --onto @{u}... @{u}

Interactive rebase starting from the single merge point of HEAD and its upstream including all commits in HEAD that are not in its upstream.

In other words exactly what you want.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionsemmons99View Question on Stackoverflow
Solution 1 - GitDanNetwalkerView Answer on Stackoverflow
Solution 2 - GitJoost den BoerView Answer on Stackoverflow
Solution 3 - GitididakView Answer on Stackoverflow
Solution 4 - GitOttoView Answer on Stackoverflow
Solution 5 - GitSeth FlowersView Answer on Stackoverflow
Solution 6 - GitMatthieu MoyView Answer on Stackoverflow
Solution 7 - GitAlex BrownView Answer on Stackoverflow
Solution 8 - GitbbexView Answer on Stackoverflow