It's not clear to me what you think is wrong.
Let's note here that git status
reports a lot of things. The information on specific files, such as local-path/test.cs
, comes from two git diff
commands, but not from the one you are running.
The index / staging-area
In a normal Git repository, there are three items of interest with regard to each file. There is the file's state in your current (or HEAD
) commit. There is the file's state in your work-tree, where you can edit the file with your favorite editor(s), run any normal commands on it, and so on. And, there is the file's state in Git's index, also called Git's "staging area".
The staging area is, in essence, "what will go into the next commit you make". Remember that in Git, every commit is a complete snapshot of your work: every file that is staged (or "tracked", i.e., is not an "untracked file") is recorded exactly as it appears in the staging area. Once you make the commit, the staging area matches the commit you just made. It's not empty—it's full of files—but a git diff
that compares the commit to the index will be empty, because the index and the commit contain the same stored-up work-tree. If you then modify a file in the work tree and git add
it, Git replaces the index version with the work-tree version, so that now the index and the HEAD
commit differ.
git status
and git diff
With that in mind, let's take a look at your specific git diff
command, and the git diff
documentation. You ran:
git diff origin/new_branch -- local-path/test.cs
The documentation says, in part:
git diff [--options] <commit> [--] [<path>...]
This form is to view the changes you have in your working tree
relative to the named <commit>. You can use HEAD to compare it with
the latest commit, or a branch name to compare with the tip of a
different branch.
This means you were comparing the work-tree version of local-path/test.cs
against the version in the commit at the tip of origin/new_branch
.
The index version of the file has no part in this comparison.
Now let's look at what git status
diffs. These quotes are still from the git diff
documentation:
git diff [--options] --cached [<commit>] [--] [<path>...]
This form is to view the changes you staged for the next commit
relative to the named <commit>. Typically you would want comparison
with the latest commit, so if you do not give <commit>, it defaults
to HEAD. If HEAD does not exist (e.g. unborn branches) and <commit>
is not given, it shows all staged changes. --staged is a synonym of
--cached.
You can safely ignore the slightly odd notion of "unborn branch" here. This compares a specific commit versus the index. By default, it compares HEAD
vs the index. This tells you what would be different in a new commit.
This is the first diff that git status
does, to find out what you would commit if you committed now.
We also find, in the git diff
documentation, this:
git diff [--options] [--] [<path>...]
This form is to view the changes you made relative to the index
(staging area for the next commit). In other words, the differences
are what you could tell Git to further add to the index but you
still haven't. You can stage these changes by using git-add(1).
In other words, this compares the index to the work-tree. Whatever shows up as different here, you could git add
to your index, so that it shows up in the first diff that git status
runs. Instead, it currently shows up in the second diff that git status
runs.
After git status
has run these two diffs, it prints any files that showed up in either one, as "changes staged for commit" or "changes not staged for commit"—or, in some cases, both. (For instance, you can add a line to README
and stage that, then add another line to README
but not stage it yet. Now you have changes from HEAD
to index—the first line you added—and changes from index to work-tree: the second line you added.)
Again, git status
reports all of these. You say it is reporting nothing: this means that your HEAD
commit matches your index, and your index matches you work-tree. There is one special case to consider before we move on.
For untracked files—which are by definition not in the index and not in the HEAD
commit—git status
normally reports them as "untracked files". This is often more annoying than useful, so you can use .gitignore
to tell git status
to shut up about these files. Check your .gitignore
to see if it is ignoring local-path/test.cs
. Presumably it is not, but if it is, that could be the reason you would not see anything.
Putting it all together
You also say that if you git diff origin/new_branch -- local-path/test.cs
, you do see differences. This means that your work-tree does not match the commit to which origin/new_branch
points.
From git status
(and assuming no .gitignore
action), we know that the HEAD
and work-tree versions of local-path/test.cs
are the same. And, we see that the origin/new_branch
version of local-path/test.cs
are different. We can therefore conclude that the HEAD
version is not the origin/new_branch
version: these must be two different commits.
This is a perfectly normal state. Sometimes git status
does report something else for this state, though.
Upstream branches
Specifically, each branch can have an upstream branch. No branch is required to have an upstream branch, and there is no constraint on the form of the upstream branch if there is one, but every branch can have one—and only one—upstream.
Normally, a local branch like master
or new_branch
usually has a remote-tracking branch like origin/master
or origin/new_branch
as its upstream.
The existence of the upstream is, again, optional. But if there is one, git status
uses it to compare the current branch against its upstream.
Specifically, if new_branch
has origin/new_branch
set as its upstream, and if—as we believe we have just proved—new_branch
and origin/new_branch
differ, git status
will tell us that one branch is ahead of the other, or behind the other, or both. (The git status
command does this by comparing the commits—not their contents, just the commits themselves—that are reachable from the two branches. I'm not going into any further detail here; for much more on this, see this answer.)
None of this can happen unless the current branch has an upstream set.
You wrote that you ran:
git checkout -b new_branch
This form of git checkout
creates a new branch, and by default, does not set an upstream for it.
To set an upstream, use git branch --set-upstream-to
(see the documentation for git branch
for details).
Note that git checkout name
, when name
does not currently exist as a local branch, but origin/name
does exist, will create the local branch name
with its upstream set to origin/name
. This is very different from git checkout -b
, which creates a local branch with no upstream set (and often a different starting value for the branch tip).