1

I created a branch, say 'new_branch' from the develop branch on bitbucket and from my local I switch to it

git checkout -b new_branch 

After I git pull the code, I tried

git status 

to see the modified files.

However from the output, I didn't see one file that I knew was modified, other modified files seemed OK.

For that particular file, say 'test.cs', I did

git diff origin/new_branch -- local-path/test.cs

and confirm the change, but how come wasn't it shown on the 'git status' output?

As a result I can't do add/commit/push the file in.

Can anyone help? Hope I made myself clear.

J.E.Y
  • 1,173
  • 2
  • 15
  • 37
  • That isn't how Git works. `git status` shows you changes between your working directory and the commit you're on. – user229044 Jun 09 '16 at 20:06

1 Answers1

1

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).

Community
  • 1
  • 1
torek
  • 448,244
  • 59
  • 642
  • 775