Git status doesn’t know if your local repository is out of date

To setup the scenario that will be demonstrated in this blog article, a new commit has been pushed to the dev branch of my PowerShell repository on GitHub from a computer named PC01. Then I switched over to using to an alternate computer named PC02 that was up to date prior to that latest commit being pushed to GitHub from PC01. This means that the dev branch of the PowerShell repository on PC02 is one commit behind the remote origin on GitHub.

You would think that checking the status of the dev branch for the PowerShell repository on PC02 would show it as being out of date by one commit, but it doesn’t. It says “Your branch is up-to-date with ‘origin/dev’“:


Everything looks correct when double checking the settings for the remote origin:


The simplest way to know if the branch is out of date is to run the following command:


You could also use the fetch command with the dry run option, but I prefer the previous command.


I’m going to disable the network card on PC02 to show you a secret about checking the status of your Git repository:


Most Git commands run against your local repository which is one of the reasons that Git is so fast and it’s also one of the strengths of Git due to its ability to allow you to work while being disconnected from the network. The problem this creates though, is that checking the status of your Git repository doesn’t actually communicate with the remote origin to tell you what the current status is. The status is based off of the last time a fetch or pull was performed which is why checking the status doesn’t necessarily provide accurate information.

Notice that no errors are generated when checking the status of my PowerShell repository while being disconnected from the network:


An error is generated when I run the command that I previously recommended that actually reports the correct status of whether or not my local repository is out of date with the remote origin one:


If you’re like me, you want to know a little more about what’s going on under the hood. I fired up process monitor and used the file monitor portion of it to determine that Git status uses the SHA1 hash that’s stored in the following file to know what the latest commit is for the dev branch of my PowerShell repository on the remote origin:


That file is only updated during a fetch or pull which explains why Git status has no idea that a more recent commit has been added to the remote origin.

My point about most git commands running locally has been made so I’ll re-enable the network card on PC02:


Now to leverage my existing PowerShell skills along with some Git commands to work a little magic. First, I’ll return the SHA1 hash of the most recent dev branch commit for my local PowerShell repository and store it in a variable named localCommit. Then I’ll return the same thing for the remote origin and store it in a variable named remoteCommit. I’ll compare the two to see if they’re equal. Next I’ll run a command so if they’re not equal, run git fetch. Lastly, I’ll run Git status which now shows that my local repository is indeed out of date by one commit:


The previous example could easily be turned into a function that would not only check the status, but fetch the changes if your local repository is indeed out of date:

The current version of the Update-MrGitRepository function can be found in my PowerShell repository on GitHub.

Now you can see that the SHA1 hash stored in the file that I referenced earlier is the same as the latest commit for both the local and remote repositories:


You might be wondering why my local repository is still one commit behind? That’s because although I fetched the changes, I didn’t merge them. Now that I have the changes downloaded, you can see the commit that the local dev branch is pointing to along with the one that the remote one points to:


I can simply merge those changes in and now my local dev branch points to the same commit as the remote one:


Let’s take one last look at the log to make sure that both the local and remote repositories point to the same commit:


As you can see, they do. I could have also used git pull to run both git fetch and git merge with one command.


Leave a Reply

%d bloggers like this: