Introduction to git fetch vs git pull
In this tutorial git fetch vs git pull, we will learn and compare how the two work in a remote and local repository.
Git fetch
A git fetch function downloads the most recent changes in a shared remote repository after the last fetch. Understand that the git fetch operator does not engage in any file transfer but serves to check any recent changes in the remote.
Git pull
A git pull function transfers and merge the upstream metadata into the local active repository.
git pull = git fetch + git merge
To update the latest remote changes to your active local repository git fetch function is the most recommended. That’s because the fetch function will not automatically merge those updates into your local codes like what git pull does. Fetched contents are kept separate from your current local commit until you decide to merge them.
Only consider git pull when you are sure you have a clean copy to update remote changes to your local active copy.
git fetch vs git pull visual comparison
The diagram below illustrates the comparison between git fetch vs git pull functions.
git fetch vs git pull workflow
Here is a basic command workflow which will you give you a high level idea of git fetch vs git pull in real time scenario:
git fetch workflow
## checkout to your branch git checkout mybranch ## fetch the changes git fetch ## check the difference compared to origin git diff origin/mybranch ## perform rebase git rebase
git pull workflow
## checkout to your branch git checkout mybranch ## pull the changes ## This perform fetch + merge git pull
A comparison table for git fetch vs git pull function
Below is a table that displays the comparison between the git fetch function vs git pull function:
git fetch | git pull |
---|---|
Syntax: git fetch <remote> | Syntax: git pull <remote-branch> |
It updates all the changes from the remote repo to the local one without merging them | It fetches and integrates the remote changes |
Keeps checks for any updates from the remote | Update the remote changes by directly merging them into the local repo |
Uses the checkout command to merge the remote changes into local repository | does not need the checkout command to merge the changes into local as its an automatic process of fetch and merge |
It is a safe approach for getting remote data as there is no room for conflicts | It has high possibilities of creating conflicts especially when two developers are working on the same branch and perform pull |
It gives you the autonomy to merge the remote changes to your local repo as per your preferences | The process is automatic and you have no room for making further adjustment once you perform git pull |
Updates you about the work done by other developers on a collaborated project | Updates and merges the work from other developers into your local repository |
Example-1: Using git fetch vs git pull to get new branch from remote repository
How git fetch works
Assuming we have a repository git_pull
which is used by multiple developers. Now these developers create different branch, every time they are working on some development or testing activity.
For example user deepak and alisha have cloned this project and user alisha has created a new branch in her local workstation.
alisha@ubuntu:~/git_pull$ git branch * main alisha@ubuntu:~/git_pull$ git checkout -b dev Switched to a new branch 'dev' alisha@ubuntu:~/git_pull$ git branch * dev main
Next alisha performs some work with commit id e27f9a2
and then pushes her changes to remote repository:
alisha@ubuntu:~/git_pull$ git push origin dev alisha@ubuntu:~/git_pull$ git log --oneline
Sample Output:
Now user deepak performs git fetch to get all the refs, tags and branched from remote repository to his local repo:
deepak@ubuntu:~/git_pull$ git fetch
remote: Enumerating objects: 4, done.
remote: Counting objects: 100% (4/4), 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), 293 bytes | 293.00 KiB/s, done.
From gitlab.com:golinuxcloud/git_pull
* [new branch] dev -> origin/dev
From the output you can see, a new branch dev
has also been fetched.
Verify the available branches:
deepak@ubuntu:~/git_pull$ git branch -a
Sample Output:
Check if all the commits from alisha are also fetched:
deepak@ubuntu:~/git_pull$ git checkout dev deepak@ubuntu:~/git_pull$ git branch deepak@ubuntu:~/git_pull$ git log --oneline
Sample Output:
So, looks like with git fetch, all the commits from alisha were also fetched and merged into the dev
branch. This is because git fetch has actually fetched all the available branch from remote repository along with the changes in those branch
How git pull works
Next we use git pull to verify the same activity. User alisha creates another branch i.e. prod and pushes some of her changes to remote repository into this new branch:
alisha@ubuntu:~/git_pull$ git checkout -b prod
Switched to a new branch 'prod'
alisha@ubuntu:~/git_pull$ git branch
dev
main
* prod
alisha@ubuntu:~/git_pull$ git log --oneline
Sample Output:
So based on this output, alisha has added a new commit 83eccc0
into the prod
branch.
Next deepak performs git pull this time to get all the latest changes from remote repository. The output looks pretty much the same as git fetch as this also indicates a new branch being pulled.
deepak@ubuntu:~/git_pull$ git pull
remote: Enumerating objects: 4, done.
remote: Counting objects: 100% (4/4), done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 3 (delta 1), reused 0 (delta 0), pack-reused 0
Unpacking objects: 100% (3/3), 255 bytes | 18.00 KiB/s, done.
From gitlab.com:golinuxcloud/git_pull
* [new branch] prod -> origin/prod
Already up to date.
List the available branch, here you can see now we have a new prod
remote branch:
deepak@ubuntu:~/git_pull$ git branch -a
Sample Output:
Verify the changes from alisha user inside the prod branch:
deepak@ubuntu:~/git_pull$ git checkout prod deepak@ubuntu:~/git_pull$ git log --oneline
Sample Output:
As you can see, the commit id 83eccc0 from alisha has also been pulled.
Conclusion
In this example we don't see any difference between git fetch and git pull as both the commands were able to get all the changes from remote repositories which were committed inside a different branch compared to the local branch where the pull or fetch operation was performed.
So we can conclude that when you are performing git fetch or git pull for a different branch (not your current branch) then all the changes are fetched/pulled and merged into that respective branch.
Example-2: Using git fetch + git rebase vs git pull (on same branch)
In this section we will demonstrate the usage of git fetch vs git pull while working on the same branch. We have a project with 2 developers, deepak and alisha. Both of them have cloned the repo's (git_pull) main branch.
How git fetch works?
Now alisha already starts working on this project and she commits a new file and pushes the same to remote repo. As you can see, currently she is working on the main branch and has committed alisha_file
into the remote repo with commit id 8e954f8
alisha@ubuntu:~/git_pull$ git branch * main alisha@ubuntu:~/git_pull$ git log --oneline 8e954f8 (HEAD -> main, origin/main, origin/HEAD) alisha's first file cf2e9eb Initial commit
Next deepak decides to fetch the changes before starting with his assigned tasks.
deepak@ubuntu:~/git_pull$ git log --oneline cf2e9eb (HEAD -> main, origin/main, origin/HEAD) Initial commit deepak@ubuntu:~/git_pull$ git branch * main
Next deepak performs a git fetch operation. From the fetch output you can see that reference of commit id 8e954f8
has been fetched successfully from the remote repository:
deepak@ubuntu:~/git_pull$ git fetch
remote: Enumerating objects: 4, done.
remote: Counting objects: 100% (4/4), 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), 257 bytes | 257.00 KiB/s, done.
From gitlab.com:golinuxcloud/git_pull
cf2e9eb..8e954f8 main -> origin/main
Next we check the commit history, but the commit id 8e954f8
entry is missing here. This is how git fetch works. It fetches all references of all the commits from the remote repository, but it does not merge them automatically. So this gives you a window to check the differences and make any changes to avoid any merge conflict.
deepak@ubuntu:~/git_pull$ git log --oneline
cf2e9eb (HEAD -> main) Initial commit
Compare the differences between local and remote repository. As highlighted, we have a new commit on remote repository for alisha_file
which is not available locally.
deepak@ubuntu:~/git_pull$ git diff origin/main
diff --git a/alisha_file b/alisha_file
deleted file mode 100644
index e69de29..0000000
Once we know there are no impacts of the merge, we will perform a rebase to merge all the changes into our local branch:
deepak@ubuntu:~/git_pull$ git rebase origin/main
Successfully rebased and updated refs/heads/main.
Check if there are any more missing changes (we get a blank output):
deepak@ubuntu:~/git_pull$ git diff origin/main
Re-verify the commit history and now you can see the commit id from alisha which she did while working on this project.
deepak@ubuntu:~/git_pull$ git log --oneline 8e954f8 (HEAD -> main, origin/main, origin/HEAD) alisha's first file cf2e9eb Initial commit
How git pull works?
Now next let's see how git pull would have handled this scenario. Alisha has again done some commit as you can see:
alisha@ubuntu:~/git_pull$ git log --oneline 3c81f88 (HEAD -> main, origin/main, origin/HEAD) First commit 8e954f8 aliasha's first file cf2e9eb Initial commit
But the same is not available on deepak's local repo as he has not pulled the latest changes. So let's perform a git pull:
deepak@ubuntu:~/git_pull$ git pull origin main
Now if you compare the difference in the output compared to git fetch in the previous section, we have some new entry which I have highlighted in the sample output below.
With git pull, both git fetch + git merge has been performed. This should explain the basic difference between both the commands.
You can also verify the commit history:
deepak@ubuntu:~/git_pull$ git log --oneline 3c81f88 (HEAD -> main, origin/main, origin/HEAD) First commit 8e954f8 aliasha's first file cf2e9eb Initial commit
Conclusion
With this exercise now we learned that git fetch will only fetch the refs and tags from the remote repository but it will not merge them into your current branch. You must explicitly use git rebase to rebase your local repo with the remote repository and merge the changes.
While git pull performs fetch and subsequently merge operation so the end user does not need to perform a rebase operation separately
Example-3: Using git fetch + git merge vs git pull (on different branch)
In this section we will use git fetch + git merge and compare it with git pull operation. Technically in all the discussion we have mentioned that git pull = git fetch + git merge
, but in the previous section we used git rebase
instead of merge
.
So, let's also take one example with git fetch + git merge operation. In the following example, both the users are working on main
branch.
How git fetch works
User alisha has done some new commits into the main
branch and has pushed the same to remote repository. She is currently working on dev branch:
alisha@ubuntu:~/git_pull$ git branch
* dev
main
prod
Here she performs some commits and sends to remote repository:
alisha@ubuntu:~/git_pull$ echo "new text" >> new_file alisha@ubuntu:~/git_pull$ git commit -m "added new text" -a alisha@ubuntu:~/git_pull$ git push origin dev
Verify the commit history:
alisha@ubuntu:~/git_pull$ git log --oneline
Sample Output:
Next user deepak wants to fetch and merge the changes from dev branch into prod branch. So he switches to prod
branch and lists the available commits from the prod
branch:
deepak@ubuntu:~/git_pull$ git checkout prod Branch 'prod' set up to track remote branch 'prod' from 'origin'. Switched to a new branch 'prod' deepak@ubuntu:~/git_pull$ git branch dev main * prod deepak@ubuntu:~/git_pull$ git log --oneline 83eccc0 (HEAD -> prod, origin/prod) Added prod_file e27f9a2 (origin/dev, dev) Added new_file 5094f93 (origin/main, origin/HEAD, main) Second commit 3c81f88 First commit 8e954f8 aliasha's first file cf2e9eb Initial commit
Next deepak performs a fetch operation which will fetch all the changes from dev
branch into the prod
branch:
deepak@ubuntu:~/git_pull$ git fetch origin dev
remote: Enumerating objects: 5, done.
remote: Counting objects: 100% (5/5), done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 3 (delta 1), reused 0 (delta 0), pack-reused 0
Unpacking objects: 100% (3/3), 246 bytes | 246.00 KiB/s, done.
From gitlab.com:golinuxcloud/git_pull
* branch dev -> FETCH_HEAD
e27f9a2..126cd7c dev -> origin/dev
But our commit history has not changed. that's because the changes are not merged yet, so we have a window to take care of any conflicts which can be common when merging two branches.
Here you can check the list of changes between local repo on prod
branch vs dev
branch on remote repo.
deepak@ubuntu:~/git_pull$ git log --oneline
Sample Output:
Next you can continue with the merge operation to merge dev
branch into prod
branch:
deepak@ubuntu:~/git_pull$ git merge origin/dev
Merge made by the 'recursive' strategy.
new_file | 1 +
1 file changed, 1 insertion(+)
Verify the available commits. Now we have a new commit ID which was used to merge the changes between dev
and prod
branch.
deepak@ubuntu:~/git_pull$ git log --oneline
Sample Output:
How git pull works
We perform the same exercise with git pull this time. Alisha has again done some changes as part of e2fe8c0
ID and pushed to dev branch of the remote repository:
alisha@ubuntu:~/git_pull$ git log --oneline
Sample Output:
Next deepak will perform git pull to directly merge the changes from dev
branch into prod
branch.
deepak@ubuntu:~/git_pull$ git branch
Sample Output:
deepak@ubuntu:~/git_pull$ git pull origin dev
Sample Output:
As you can see, the pull action has done fetch + merge operation combined. You can also verify the same by checking the commit history:
deepak@ubuntu:~/git_pull$ git log --oneline
Sample Output:
Conclusion
Here we learned that if we are using git fetch to fetch the changes from a different branch then git merge can be used to merge both the branch. Although with git merge you will have one additional commit ID.
But the same thing happens with git pull, the only difference is that as expected git pull will not give you an opportunity to check for any merge conflicts. But again in such cases the pull operation will fail and will work only once you have fixed any conflicts
What's Next
git pull vs git pull --rebase explained with examples
Summary
From the example above you will notice that by using git fetch compared to git pull we first fetched the remote changes, checkout and then merge. On the other hand, updating the changes using git pull is an express procedure combining fetch and merge.
Further reading