How to rebase your git branch

You worked on a branch and are ready to merge it into main. But main has changed since you started working on your branch. You need to rebase your branch on top of main.

You created a branch named b1 from main and made 3 commits.

Your Git history looks like this:

alina

alina git:( b1 ) git log --graph --oneline --all

* 022a4c4 (HEAD -> b1, origin/b1) add B3.txt

* eeb98bb add B2.txt

* f9bcc02 add B1.txt

* 8dcf726 (origin/main, origin/HEAD, main) add A2.txt

* 22bdc8d add A1.txt

* 950c5f3 Initial commit

alina git:( b1 )

and corresponds to this graph:

alina

022a4c4eeb98bbf9bcc028dcf72622bdc8d950c5f3b1mainorigin/b1origin/mainHEAD

Let’s imagine that you switch back to your main branch and make a commit there.

alina

alina git:( b1 ) git switch main

Switched to branch 'main'

Your branch is up to date with 'origin/main'.

alina git:( main )

Instead of making a random commit, let’s assume you want to cherry-pick a commit from b1 into main. You select the commit f9bcc02 and apply it on top of main.

This commit added a file called B2.txt:

alina

alina git:( main ) git cherry-pick eeb98bb

[main cd008e5] add B2.txt

 Date: Fri Jul 7 08:04:20 2023 -0700

 1 file changed, 1 insertion(+)

 create mode 100644 B2.txt

alina git:( main ) ls

A1.txt    A2.txt    B2.txt    README.md

alina git:( main ) git log --graph --oneline --all

* cd008e5 (HEAD -> main) add B2.txt

| * 022a4c4 (origin/b1, b1) add B3.txt

| * eeb98bb add B2.txt

| * f9bcc02 add B1.txt

|/  

* 8dcf726 (origin/main, origin/HEAD) add A2.txt

* 22bdc8d add A1.txt

* 950c5f3 Initial commit

(END)

:11

(END)

alina git:( main )

Now, let’s return to your b1 branch. You want to rebase it on top of main.

alina

alina git:( main ) git switch b1

Switched to branch 'b1'

Your branch is up to date with 'origin/b1'.

alina git:( b1 )

Your commit graph now looks like this:

alina

cd008e5022a4c4eeb98bbf9bcc028dcf72622bdc8d950c5f3b1mainorigin/b1origin/mainHEAD

The situation is as follows:

  • The main branch has a commit cd008e5 that you don’t have on b1, but it is a cherry-pick of eeb98bb, which you have on b1.
  • The b1 branch has 2 extra commits 022a4c4 and f9bcc02 that you don’t have on main.

The git rebase command will take the commits that are on b1 but not on main, and apply them on top of main by re-applying the changes they introduce on top of the commits on main.

alina

alina git:( b1 ) git rebase main

warning: skipped previously applied commit eeb98bb

hint: use --reapply-cherry-picks to include skipped commits

hint: Disable this message with "git config advice.skippedCherryPicks false"

Rebasing (1/2)

Rebasing (2/2)

Successfully rebased and updated refs/heads/b1.

alina git:( b1 )

The git rebase command is smart enough to realize that the commit eeb98bb wouldn’t change anything on main (because that commit was cherry-picked), so it skips it.

The commit graph is then as follows:

alina

c2b644e72700fecd008e5022a4c4eeb98bbf9bcc028dcf72622bdc8d950c5f3b1mainorigin/b1origin/mainHEAD

As usual, when in this state, a git push will be rejected because the remote branch b1 is behind the local branch b1.

alina

alina git:( b1 ) git push

To ssh://remote.mygit.com/gitpowerup/arenas.git

 ! [rejected]        b1 -> b1 (non-fast-forward)

error: failed to push some refs to 'ssh://remote.mygit.com/gitpowerup/arenas.git'

hint: Updates were rejected because the tip of your current branch is behind

hint: its remote counterpart. Integrate the remote changes (e.g.

hint: 'git pull ...') before pushing again.

hint: See the 'Note about fast-forwards' in 'git push --help' for details.

alina git:( b1 )

To push the changes, a git push --force-with-lease is required. It is always risky to use the --force option when pushing, so the --force-with-lease option provides a safer alternative. It will fail if someone else has already pushed commits on b1 in the meantime.

alina

alina git:( b1 ) git push --force-with-lease

Enumerating objects: 10, done.

Counting objects: 100% (10/10), done.

Delta compression using up to 8 threads

Compressing objects: 100% (6/6), done.

Writing objects: 100% (9/9), 738 bytes | 738.00 KiB/s, done.

Total 9 (delta 2), reused 0 (delta 0), pack-reused 0

remote: 

remote: Create a new pull request for 'b1':

remote:   http://localhost:3030/gitpowerup/arenas/compare/main...b1

remote: 

remote: . Processing 1 references

remote: Processed 1 references in total

To ssh://remote.mygit.com/gitpowerup/arenas.git

 + 022a4c4...c2b644e b1 -> b1 (forced update)

alina git:( b1 )

And your commit graph becomes:

alina

c2b644e72700fecd008e5022a4c4eeb98bbf9bcc028dcf72622bdc8d950c5f3b1mainorigin/b1origin/mainHEAD

On the server side, the commit graph is now in sync with your local repository.

arenas.git

c2b644e72700fecd008e5022a4c4eeb98bbf9bcc028dcf72622bdc8d950c5f3b1mainHEAD

There are a few dangling commits that will be cleaned up later by Git.