Pushing & Pulling Commits in Git
17 min read·Jan 1, 2025
In Git, pushing, pulling, and fetching refer to three correlated operations used to keep local and remote repositories in sync, where:
- Pushing means uploading the changes made in a local repository to a remote repository, making them available to other developers.
- Pulling means downloading and integrating the changes made by you or other developers to a remote repository into a local repository.
- Fetching means downloading the changes made to a remote repository without integrating them.
Local vs remote branches
A local branch is a branch that only exists on your local copy of the Git repository, and that only you can view, create, modify, and delete.
A remote branch, on the other hand, is a branch that exists on the remote repository, whose commits can be downloaded (i.e. pulled) and updated (i.e. pushed) by you and other developers, and that serves as a reference point for local branches.
In practice, local branches are usually connected to remote branches, then called upstream branches, which allow developers to push and pull commits to and from the remote repository, ensuring that everyone's work is synchronized.
Checking if a branch is "ahead" or "behind"
When working with remote repositories, it is very common for local branches to get out of sync with their corresponding upstream branches.
When the commits of a local branch have not yet been pushed to the remote repository, the local branch is then considered ahead of the remote branch, as it has more commits.
On the other hand, when the commits of a remote branch have not been pulled into the local branch, the local branch is then considered behind the remote branch, as it has less commits.
To check whether a local branch is ahead of, behind, or in sync with its upstream branch, you can use the git status command:
$ git status
On branch main
Your branch is ahead of 'origin/main' by N commit.
(use "git push" to publish your local commits)
nothing to commit, working tree clean
Listing upstream branches
To output a list of all remote branches, you can use the git branch -r command:
$ git branch -r
<origin>/<branch>
On the other hand, to output a list of all local branches and their connected upstream branches (if they have one), you can use the git branch -vv command:
$ git branch -vv
* <local> <hash> [<remote>: <status>] <message>
Where:
*indicates the checked out branch.<local>is the name of the local branch.<hash>is the latest commit hash on that branch.<remote>is the name of the upstream branch.<status>is the number of commits ahead or behind.<message>is the commit message of the latest commit on that branch.
Example
This command will list 2 local branches:
$ git branch -vv
* main 3975fbd [origin/main: ahead 1] refactor: update server port
develop 8821236 refactor: add healthcheck route
Where:
- The local
mainbranch is ahead of the remoteorigin/mainbranch by 1 commit. - The local
developbranch is not connected to any upstream branch.
Pushing commits to a remote repository
To push the local commits of a branch to a remote repository, you can use the git push command:
$ git push <origin> <branch>
Where:
<origin>is the name of the remote repository you cloned (e.g.,origin).<branch>is the name of the remote branch you want to push the local commits to (e.g.,feature).
Note: If the specified upstream branch doesn't exist on the remote repository, it will be automatically created.
Example
This command will:
- Create a new upstream branch named
developon the remote repository namedorigin. - Upload the latest commits to it.
$ git push origin develop
Enumerating objects: 5, done.
Counting objects: 100% (5/5), done.
Delta compression using up to 8 threads
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 361 bytes | 361.00 KiB/s, done.
Total 3 (delta 1), reused 0 (delta 0), pack-reused 0
remote: Resolving deltas: 100% (1/1), completed with 1 local object.
remote:
remote: Create a pull request for 'develop' on GitHub by visiting:
remote: https://github.com/learnbackend/git-lesson-test/pull/new/develop
remote:
To github.com:learnbackend/git-lesson-test.git
* [new branch] develop -> develop
Tracking a remote branch
By default, Git doesn't keep track of the relationships between local and remote branches.
When pushing a local branch to a remote repository for the first time, you can tell Git to track (or associate) the local branch to the remote branch using the --set-upstream flag:
$ git push --set-upstream <origin> <branch>
Once the upstream branch is set, you will no longer need to specify the remote nor the checked out branch name every time you push commits:
$ git push
On the other hand, to set or change the upstream branch of a local branch, you can use the git branch command as follows:
$ git branch --set-upstream-to <origin>/<branch>
Example
This command will:
- Create a new upstream branch named
developon the remote repository namedorigin. - Upload the latest local commits.
- Set a tracking relationship between the local
developbranch and the remoteorigin/developbranch.
$ git push --set-upstream origin develop
Enumerating objects: 8, done.
Counting objects: 100% (8/8), done.
Delta compression using up to 8 threads
Compressing objects: 100% (6/6), done.
Writing objects: 100% (6/6), 689 bytes | 689.00 KiB/s, done.
Total 6 (delta 2), reused 0 (delta 0), pack-reused 0
remote: Resolving deltas: 100% (2/2), completed with 1 local object.
remote:
remote: Create a pull request for 'develop' on GitHub by visiting:
remote: https://github.com/learnbackend/git-lesson-test/pull/new/develop
remote:
To github.com:learnbackend/git-lesson-test.git
* [new branch] develop -> develop
branch 'develop' set up to track 'origin/develop'.
Pulling commits from a remote repository
To pull the latest commits from a remote branch into a local branch, which implies both fetching and merging, you can use the git pull command:
$ git pull [<origin> <branch>]
Where:
<origin>is the name of the remote repository you cloned.<branch>is the name of the remote branch you want to pull the commits from.
Note: If the remote branch is already tracked, you can use the
git pullcommand without arguments.
💡 Tip: It is considered good practice to first pull the latest commits from the remote branch before starting to work on the local branch in order to avoid creating unnecessary merge conflicts.
Fetching upstream branches
To download a copy of all upstream branches on your local machine without actually merging their commits locally, you can use the git fetch command:
$ git fetch
This allows you to first inspect the changes that have been made upstream before deciding how to integrate them, thus avoiding potential losses or conflicts.
Alternatively, to fetch the commits of a specific upstream branch, you can use the following syntax:
$ git fetch <origin> <branch>
Example
This command will fetch the missing origin/develop upstream branch:
$ git fetch
From github.com:learnbackend/git-lesson-test
* [new branch] develop -> origin/develop
This command will only download the latest commits of the upstream origin/develop branch:
$ 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 1), reused 3 (delta 1), pack-reused 0 (from 0)
Unpacking objects: 100% (3/3), 369 bytes | 184.00 KiB/s, done.
From github.com:learnbackend/git-lesson-test
8821236..fb48a56 develop -> origin/develop
Creating a local branch from an upstream branch
When cloning a remote repository or fetching remote branches, Git only creates a local branch for the default branch (usually main or master).
To create a local branch from an upstream branch, you can use the git switch -c command as follows:
$ git switch -c <local> <origin>/<remote>
Example
This command will first fetch locally the upstream branch origin/develop
$ git fetch
From github.com:learnbackend/git-lesson-test
* [new branch] develop -> origin/develop
Then, this command will create a new local branch named develop based off the upstream branch origin/develop:
$ git switch -c develop origin/develop
branch 'develop' set up to track 'origin/develop'.
Switched to a new branch 'develop'
Finally, this command will check the current state of local branches:
$ git branch -vv
* develop 8821236 [origin/develop] refactor: update server port
main 3975fbd [origin/main: ahead 1] refactor: update server port
Untracking upstream branches
To tell Git to stop tracking an upstream branch, you can checkout the desired local branch and use the git branch command as follows:
$ git branch --unset-upstream
Removing local upstream branches
To remove an upstream branch from the local repository, you can use the git branch command as follows:
$ git branch -r -d <origin>/<remote>
Example
This command will delete the local copy of the upstream branch origin/develop:
$ git branch -d -r origin/develop
Deleted remote-tracking branch origin/develop (was fb48a56).
Which is both confirmed by the branch being marked as "gone":
$ git branch -vv
* develop fb48a56 [origin/develop: gone] feat: add new hello endpoint
main 4be366e [origin/main] feat: initial commit
And its removal from the list of remote branches:
$ git branch -r
origin/main
Removing remote upstream branches
To remove a branch from the remote repository, you can use the git push command as follows:
$ git push <origin> -delete <remote>
⚠️ Warning: This operation is irreversible! Before deleting an upstream branch from the repository, first make sure that the branch has been fully merged and that all your collaborators have been warned!
Example
This command will delete the origin/develop branch from the remote repository:
$ git push origin --delete develop
To github.com:learnbackend/test.git
- [deleted] develop
Summary
Here's a summary of what you've learned in this lesson:
- Pushing means uploading the changes made in a local repository to a remote repository.
- Pulling means downloading and integrating the changes made to a remote repository into a local repository.
- Fetching means downloading the changes made to a remote repository without integrating them.
- A local branch is a branch that only exists on your local copy of the Git repository.
- A remote branch is a branch that exists on the remote repository.
- An upstream branch is a remote branch that is tracked by a local branch.
- A local branch is ahead if it has more commits than its upstream branch.
- A local branch is behind if it has less commits than its upstream branch.
- The
git branch -rcommand is used to list the remote branches present in the local repository. - The
git branch -vvcommand is used to list the local branches and their upstream branches. - The
git pushcommand is used to upload local commits to a remote branch. - The
git pullcommand is used to download and merge commits from a remote branch. - The
git fetchcommand is used to download branches and commits from the remote repository without merging them. - The
git switch -ccommand is used to create a local branch from a remote branch. - The
git branch --unset-upstreamcommand is used to track a remote branch. - The
git branch -r -dcommand is used to remove a remote branch from the local repository. - The
git push --deletecommand is used to remove a remote branch from the remote repository.
Enjoying the courses?
I've made these courses completely free so anyone can learn from them. If they've helped you and you'd like to actively support the work behind BackendBrewery, you can leave a tip:
Support BackendBrewery