Demystifying Git: What Actually Happens When You Pull?

Demystifying Git: What Actually Happens When You Pull?

May 26, 2026

If you use Git daily, you have likely run into one of these errors when attempting to synchronize your code:

  • fatal: Need to specify how to reconcile divergent branches.
  • fatal: The current branch has no upstream branch.

To a beginner, these warnings feel like Git is complaining about broken code. To an experienced developer, they are simple reminders of how Git’s internals work.

Let’s unpack what is actually happening behind the scenes when you run these commands, and look at the single file where Git stores all this information.


The git pull Misconception

The most common misunderstanding in Git revolves around this command:

git pull origin feature-branch

If you are currently working on your local main branch, you might run this command thinking: “I want to update my local feature-branch with whatever is on GitHub.”

Instead, Git throws a warning about divergent branches. Why?

Under the hood, git pull is actually a combination of two separate commands:

  1. git fetch: Go to GitHub, find feature-branch, and download its latest commits.
  2. git merge: Take those downloaded commits and merge them into the branch you are currently on.

Because you were on main, Git tried to merge the downloaded feature-branch commits directly into main. Since main and feature-branch have different commit histories (they have “diverged”), and because you haven’t configured a default merge strategy, Git aborts the action to prevent a messy conflict.

The rule of thumb: Git can only update the files and pointer of the branch you currently have active. If you want to update a branch, check it out first:

git checkout feature-branch
git pull

How Git Remembers: Under the Hood of .git/config

Where does Git keep track of which local branch goes to which remote branch?

If you open the hidden directory at the root of any Git project and look at the .git/config file, you will find a plain text configuration file. Here is a typical example:

[remote "origin"]
	url = [email protected]:username/repository.git
	fetch = +refs/heads/*:refs/remotes/origin/*

[branch "main"]
	remote = origin
	merge = refs/heads/main

When you create a brand new branch locally (e.g., git checkout -b new-feature), it exists only on your machine. The .git/config file has no entry for it.

If you try to run git push or git pull, Git reads this config, sees no [branch "new-feature"] block, and says: “I don’t know where to send/fetch this.”

Once you run:

git push -u origin new-feature

The -u (upstream) flag tells Git to write a new entry to your .git/config file:

[branch "new-feature"]
	remote = origin
	merge = refs/heads/new-feature

From that point forward, a simple git push or git pull works seamlessly because Git has a lookup address.


Why Does git remote -v List the Same URL Twice?

If you run git remote -v to check your remote configuration, you will see output like this:

origin  [email protected]:username/repository.git (fetch)
origin  [email protected]:username/repository.git (push)

This output is generated directly from the [remote "origin"] block in your .git/config file. By default, Git assumes you want to pull (fetch) changes from and push changes to the exact same repository.

However, you can configure them separately. For instance, if you want to pull updates from an upstream open-source project but push your changes to your own personal fork, you can configure a separate pushurl in your config:

[remote "origin"]
	url = [email protected]:OriginalProject/repo.git
	pushurl = [email protected]:YourUsername/repo.git

Now, git remote -v will show different URLs for fetching and pushing.


Wrap Up

Git isn’t magic; it is a collection of pointers, configurations, and commit histories stored locally in your .git folder.

The next time Git complains about divergent branches or missing upstream configuration, remember that it is just asking you two simple questions: “Which branch do you want to merge this into?” and “Where in my config file should I write this link?”