Slashes in Git commands

Published in Technology

When answering a question in the always invaluable Write the Docs Slack community, I came to a realization about something that’s been bothering me for a while in Git: the presence or absence of slashes with remote and branch names.

For example, if you want to get all changes to the remote branch main, you might run this command:

bash
git fetch origin main

But if you wanted to rebase your current branch onto that branch, you’d run this command:

bash
git rebase origin/main

Why the difference?

I didn’t see a reason for it, which may have contributed to my almost never remembering which version to use when. Autocompletion was helpful for this, but it still bothered me not to know.

How I saw the light

The question I was answering was about something else in Git I’ve often found confusing.

Say you have different branches based on features, like feature1, feature2, and so on. And other people are working on other features.

If you’ve been working on feature1 for a while and then want to switch over to feature2 to see what your colleagues have been up to, you might see something like this:

bash
$ git checkout feature2
Switched to branch 'feature2'
Your branch is up to date with 'origin/feature2'.

But if you message your colleague to ask why they’ve been so lazy and not added any commits, they might tell you they’ve added lots of commits and pushed them already. And if you fetch the branch before you switch, you can see them:

bash
$ git fetch origin feature2
$ git checkout feature2
Switched to branch 'feature2'
Your branch is behind 'origin/feature2' by 24 commits, and can be fast-forwarded.
  (use "git pull" to update your local branch)

Now your colleague seems far more productive.

Anyway, the confusion comes from that first response from Git:

bash
Your branch is up to date with 'origin/feature2'.

As you can see after fetching, that simply isn’t true if you think of the origin/feature2 branch as representing the remote code (in GitHub, GitLab, or wherever). And most people (or at least I) would think of it that way.

That’s when I realized I had to change how I thought of the branch.

What the slash represents

In explaining this, I came to realize that origin/feature2 represented my local record of what is in the remote branch.

Git is only responsive. It is not sitting in the background, automatically checking for updates to all your remote repositories. When you run a command like git fetch or git pull, you tell Git to check remote repositories for updates. Git then creates a record of that repository, which it stores as references beginning with origin/ (or whatever you’ve named your remote).

So when Git tells you your branch is up to date with 'origin/feature2', it’s not referring what’s currently at the origin. It’s referring to what was at the origin the last time you checked, whether that was 1 hour or 1 year ago. It’s the list of changes that you have in the origin/ directory within your .git directory. The slash represents the local directory.

Which commands need which version

Some Git commands are focused on communicating with the remote repository. With git pull or git push, you’re working with the actual remote repository and getting or updating a list of changes. In these cases, you separate the remote name (origin) from the branch name (feature2).

Other Git commands are focused on making other changes. With git rebase and git reset, you’re applying a list of changes to a specific branch. You need to have the list of changes at hand to apply them, so you use a local list. In these cases, you use a local reference: origin/feature2.

Hopefully, seeing this process can help someone else understand why Git is the way it is and so have to look things up just a little less. I still think the message of Your branch is up to date is misleading, but now that I understand it and how slashes work, I understand why it is like that and how to use the information it presents.