git pull vs git pull --rebase - Brief Overview
The git pull and git rebase are almost similar with some differences. You may have already heard of git fetch
command which will fetch down all the changes from the remote repository server to your local workstation that you don’t have yet, it will not modify your working directory at all. It will simply get the data for you and let you merge it yourself. Next you can use git merge to merge the changes. Now instead of performing this git fetch followed by git merge, you can directly use git pull
.
The git rebase is sort of an alternative to merge functionality. Instead of creating a new commit that combines the two branches, the git rebase moves the commits of one of the branches on top of the other.
Let us explore each one of them individually.
git pull command (without rebase)
In truth, git pull is a super command; in fact, it is basically the sum of two other git commands, git fetch
and git merge
. The git pull command is used to pull the remote modifications to the local repository.
To understand this let us explore both commands individually:
Use git fetch + git merge separately
- The
git fetch
command communicates with a remote repository and fetches down all the information that is in that repository that is not in your current one and stores it in your local database. - When you clone a repository, local versions of its branches are also maintained. The fetch command updates these local versions with the latest commits from the remote.
- It could happen that someone pushed a commit or more on top of a branch, but you realized those commits are not good for you, or simply they are just wrong. So, using git fetch, you can get and inspect them before applying them on your local branch with a git merge.
- Here I have cloned a project into my local workstation from gitlab. I am using new-feature branch of this project. Now there is another user
alisha
who is also using the same branch of the same project.
Now as deepak
user I have made some commits and pushed the same to remote branch:
deepak@ubuntu:~/gc_dev$ git commit -m "commit-3" -a [feature dcdbcb1] commit-3 1 file changed, 1 insertion(+), 1 deletion(-) deepak@ubuntu:~/gc_dev$ git push origin feature ... To gitlab.com:golinuxcloud/gc_dev.git a12c5d0..dcdbcb1 feature -> feature
Check the list of commit ids, here dcdbcb1
is my latest commit ID
deepak@ubuntu:~/gc_dev$ git log --oneline dcdbcb1 (HEAD -> feature, origin/feature) commit-3 a12c5d0 commit-2 80be119 commit-1 a8afb3c (origin/main, main) commit-C e3ab8c3 commit-B 54a79f1 commit-A
Now use alisha
tries to fetch the latest refs and commits from remote branch and stores it locally:
alisha@ubuntu:~/gc_dev$ git fetch remote: Enumerating objects: 5, done. remote: Counting objects: 100% (5/5), done. remote: Compressing objects: 100% (2/2), done. remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 0 Unpacking objects: 100% (3/3), 251 bytes | 125.00 KiB/s, done. From gitlab.com:golinuxcloud/gc_dev a12c5d0..dcdbcb1 feature -> origin/feature
As you see the commit information from dcdbcb1
ID is fetched but the actual commit is not merged which is why our latest commit still shows commit-2
:
alisha@ubuntu:~/gc_dev$ git log --oneline a12c5d0 (HEAD -> feature) commit-2 80be119 commit-1 a8afb3c (origin/main, origin/HEAD, main) commit-C e3ab8c3 commit-B 54a79f1 commit-A
As you can see the latest changes were fetched but were not merged in your local workstation. Now at this stage you can manually perform a git merge to merge the changes:
alisha@ubuntu:~/gc_dev$ git merge
Updating a12c5d0..dcdbcb1
Fast-forward
file2 | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
Now alisha
can see that the latest commit from user deepak
is also applied to your local workstation:
alisha@ubuntu:~/gc_dev$ git log --oneline dcdbcb1 (HEAD -> feature, origin/feature) commit-3 a12c5d0 commit-2 80be119 commit-1 a8afb3c (origin/main, origin/HEAD, main) commit-C e3ab8c3 commit-B 54a79f1 commit-A
Use git pull (git fetch + git merge)
Now we will just use git pull instead of using the fetch and merge command separately. So I have made one more commit with ID db1a9f2
using deepak
user as you can check below from deepak's
workstation:
deepak@ubuntu:~/gc_dev$ git log --oneline db1a9f2 (HEAD -> feature, origin/feature) commit-4 dcdbcb1 commit-3 a12c5d0 commit-2 80be119 commit-1
Now let's directly perform a git pull from alisha's
workstation:. But first make sure alisha
is connected to the feature branch:
alisha@ubuntu:~/gc_dev$ git branch
* feature
main
Next we will initiate the git pull from feature branch on remote repository:
alisha@ubuntu:~/gc_dev$ git pull origin feature remote: Enumerating objects: 5, done. remote: Counting objects: 100% (5/5), done. remote: Compressing objects: 100% (2/2), done. remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 0 Unpacking objects: 100% (3/3), 251 bytes | 62.00 KiB/s, done. From gitlab.com:golinuxcloud/gc_dev * branch feature -> FETCH_HEAD dcdbcb1..db1a9f2 feature -> origin/feature Updating dcdbcb1..db1a9f2 Fast-forward file2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
As you can see above, the pull command has fetched the refs and commits and has also merged the recent changes from deepak
to alisha's
local repository:
alisha@ubuntu:~/gc_dev$ git log --oneline db1a9f2 (HEAD -> feature, origin/feature) commit-4 dcdbcb1 commit-3 a12c5d0 commit-2 80be119 commit-1 a8afb3c (origin/main, origin/HEAD, main) commit-C e3ab8c3 commit-B 54a79f1 commit-A
How git merge works
- I have already covered git merge in detail with multiple examples
- Suppose you have a main branch which contains the code changes for your application.
- Now there are multiple bugs reported on this main branch, so each bug is assigned to a different developer. Now we assign a different branch to each developer so they can continue with the bug fix changes while the main branch continues to have stable code.
- Once the developer has fixed and tested the changes then they will switch to the main branch and then merge their branch with main branch. This would merge all the commits which were done in the developer branch
In this example diagram as you can see, the developer has created a new branch by using git checkout -b feature. in the feature branch he does 2 commits and then now since he knows the bug has been fixed so he switches to main branch and merge his changes.
The basic git workflow of git merge would be:
## Create and switch to a bugfix branch
## If a branch already exists then -b can be removed from this command
## -b will create a new branch on your local workstation
git checkout -b bugfix
## work on your changes
git add
git commit
## you may also push the changes to remote branch to save the work
## this will create a branch bugfix on remote repository
git push origin bugfix
##To merge, switch to the branch into which you plan to merge your changes
git checkout main
## Perform the merge
git merge bugfix
How git pull works
We have already covered this part in detail with examples in the above section so I will just brief out the workflow:
## user1 pulls feature branch
user1$ git pull feature
user1$ git checkout feature
## user2 pulls feature branch
user2$ git pull feature
user2$ git checkout feature
## user1 makes some changes and pushes to remote feature branch
user1$ git commit -m "some message" -a
user1$ git push origin feature
## user2 pulls the latest changes
## This command will fetch + merge the changes from user1 into user2 local workstation
user2$ git pull origin
git pull --rebase command
- Now you must be wondering when git pull is already getting all the files, commits, refs from the remote repository then why should I use rebase with git pull ?
- The main reason we do a
git pull --rebase
over git pull is because it avoids loops in the project history. - For instance, the master branch has had many changes since you began working on your feature branch. You want to acquire the newest updates from the master branch to your local branch while maintaining a clean history of your branch to appear as you have been working off the latest master branch.
- Git rebase guarantees a clean merge between your feature branch back into the master branch without keeping commit history.
- Why then do we need a clean history? The importance of a clean history becomes evident when carrying out Git operations to explore the foundation of a regression.
- Quite literally, the process of rebasing is a way of rewriting the history of a branch by moving it to a new “base” commit.
If you perform a git pull of a branch with some merge commits, then the commit history would be like this:
But when we perform a git pull --rebase
then the commit history would be like this:
How git rebase works
Let me explain this part with an example. I have made some commits in the main
branch as you can see here:
deepak@ubuntu:~/gc_dev$ git log --oneline 0320b58 (HEAD -> main, origin/main) commit-E 6d2bc8b commit-D a8afb3c commit-C e3ab8c3 commit-B 54a79f1 commit-A
Now some other developer was also working on the feature
branch and they also did some commits on the feature branch:
deepak@ubuntu:~/gc_dev$ git log --oneline fdff32d (HEAD -> feature, origin/feature) commit-5 db1a9f2 commit-4 dcdbcb1 commit-3 a12c5d0 commit-2 80be119 commit-1 a8afb3c commit-C e3ab8c3 commit-B 54a79f1 commit-A
The feature branch also contains reference of main branch as we had checked out feature branch after commit-C
. Now let us merge feature
branch into main
branch.
First we should switch to main
branch:
deepak@ubuntu:~/gc_dev$ git switch main
Switched to branch 'main'
Your branch is up to date with 'origin/main'.
Next merge the feature branch into main branch:
deepak@ubuntu:~/gc_dev$ git merge feature
Merge made by the 'recursive' strategy.
file2 | 1 +
1 file changed, 1 insertion(+)
create mode 100644 file2
Check the commit history, a new commit b9a3bcb
has been created for the merge:
deepak@ubuntu:~/gc_dev$ git log --oneline b9a3bcb (HEAD -> main) Merge branch 'feature' fdff32d (origin/feature, feature) commit-5 0320b58 (origin/main) commit-E 6d2bc8b commit-D db1a9f2 commit-4 dcdbcb1 commit-3 a12c5d0 commit-2 80be119 commit-1 a8afb3c commit-C e3ab8c3 commit-B 54a79f1 commit-A
As you can see now the commit history contains the changes from both main and feature branch but it is not in properly aligned.
So we use rebase the main branch:
deepak@ubuntu:~/gc_dev$ git pull --rebase
Successfully rebased and updated refs/heads/main.
Now verify the commit history, as you can see the commits are now aligned properly in a single line as we had shown in the image and the extra commit which was created for the merge request is also not there any more:
deepak@ubuntu:~/gc_dev$ git log --oneline 24084d3 (HEAD -> main) commit-5 8748146 commit-4 08ffd72 commit-3 cb4fcac commit-2 cba988c commit-1 0320b58 (origin/main) commit-E 6d2bc8b commit-D a8afb3c commit-C e3ab8c3 commit-B 54a79f1 commit-A
So I hope this should help you clear your doubts of difference between git pull and git pull with rebase.
When to use git pull --rebase
- When multiple individuals are working on the same branch
- When you want to crush multiple commits
- When you want to overwrite the history.
- When you want to repeat each commit and add the changes.
Pros
- Git rebase can streamline complex history
- Controlling a single change is easy
- It avoids merging commits in busy repositories
Cons
- Crushing features to a handful of changes can hide the data.
- Rebasing on public repositories is not advisable. Rewriting history on public/shared branches can make teamwork suffer from breakage.
- It has more work since one requires to keep updating the feature branches every time.
- Rebasing with a remote repository requires one to force push. This has been seen as a bigger problem to people who have not set git push as default.
Summary
This two git commands are not interchangeable.
Git pull
downloads the newest changes from the remote repository and applies the changes to your local repository. Generally, git pull
is git fetch
and git merge.
Rebasing on the other hand can be a replacement for git merge
. Instead of making a new commit that joins the two branches and leaves a commit history, it adds your changes above other new remote changes at the same time rewrite the commit history, making the commit history much cleaner that git merge.
You can also pull using rebase instead of git merge
, by the use of git pull --rebase
. The changes made on your local repository will be added on top of the changes from remote repository and your local repository will be up to date.