"the README file is modified in the working directory but not yet staged": We're not tracking this file. Still, Git understands that it has been modified. From the last snapshot.

No, this is wrong: specifically, the file is staged (and the staged copy matches the HEAD copy, and this makes the file tracked). The tricky part with the staging-area is that it is normally mostly invisible. This leads people down the wrong path in trying to understand how it works.

First, let's tackle some Git terminology. There are three entities of interest at this point: the current commit, the staging-area—which actually has three names—and the work-tree. The three names for the staging-area are index, staging-area, and cache, and these three names reflect the low quality of Linus Torvald's original choice ("index") or the enormous importance of the invisible staging-area, or both. (I think both.) Let's look deeper at each one:

  • The current commit, which we can also name via the name HEAD (in all capitals1), is of course a commit—it's a snapshot of all the files that were in the staging area when you (or whoever) ran git commit. This snapshot is permanent (mostly) and read-only (entirely). Its true name is not HEAD—that's just a symbolic name by which we can find it right now—but rather some big ugly hash ID. The hash ID appears random, but is in fact a cryptographic checksum of the complete contents of the commit. That's why the commit can't be changed—changing anything would change the checksum, resulting in a different commit.

    The files stored within2 the commit are also read-only. They are stored in a special, Git-only, compressed form. This particular compression has the nice property that if the contents of a file are the same from one commit to another, these commits all share the underlying compressed file-image. That means you can commit a big file millions of times, if you like, and not use any more space than committing that file once.

  • The index / staging-area / cache is this crazy almost-invisible data structure. It contains all the files at all times, in the same way that a commit contains all the files. The files in the index are also in this special compressed Git-only format. The key difference between a file copy in the index / staging-area, and a copy in a commit, is that the index one can be overwritten.

    (The index also caches—hence the name "cache"—information about the work-tree, to make Git go faster. These two facts, that the index holds all the files all ready to go into the next commit, and that it caches stuff about the work-tree, are what make git commit so insanely fast, compared to other similar version control systems.)

  • The work-tree is the simplest of the three, but in a sense, also the one Git cares the least about. It's where you do your work on your files. These files are in the ordinary format that the rest of your computer programs understand. They are the most important to you, but the least important to Git: a --bare repository has no work-tree, but Git can still function (in a more limited way of course).

The work-tree is the only one of these three things that you can see easily and directly. Simply use whatever command it is that lists files or views files: there they are, plain to see. Fortunately, commits are easy to see as well, by checking them out.

When you initially check out some particular commit—via git checkout master or git checkout develop, for instance—Git populates both your index / staging-area and you work-tree from that commit. It sets HEAD to be a symbolic name for the correct hash ID. That way, the index already has in it all the same files that are in the HEAD commit, and the work-tree has all the same files that are in the index.

If you modify a file in the work-tree, and then run git add on it, Git copies the work-tree version of that file into the index / staging-area. Now the HEAD commit version and the index version differ, but the index version and the work-tree version agree with each other.

If you modify a file in the work-tree but don't run git add on it, the HEAD and index versions agree, but the index version disagrees with the work-tree version.

If you modify a file in the work-tree, then (1) use git add to copy it to the index / staging-area and (2) modify it again, now all three versions of that file differ. This is where you will see an MM status.

What git status is doing is, in effect, running two diffs. The first one compares HEAD to the index. Whatever is different here is "staged for commit". The second diff compares the index to the work-tree. Whatever is different here is "not staged for commit". That's almost it—we're nearly done!

Last, let's take a look at the term tracked as applied to files. In Git, a file is tracked if and only if it is in the index / staging-area. It's really that simple! The tricky part is telling whether a file is in fact in the index, since it's normally so invisible there.

The git status command compares the index: first, it compares HEAD vs index. Suppose some file is in both HEAD and index and has the same contents in both. Then you won't see it here. Likewise, you won't see it here if it's the same in the index and the work-tree. So if the file is in the index, but matches both HEAD and work-tree versions, it's invisible.

Suppose some file isn't in the index. If it's in HEAD, git status will tell you that between HEAD and the index, the file got deleted—a D in the first column of the short output. So in that case you can tell: the file has gone away from the index, and is no longer tracked. It won't be in the next commit.

Suppose some file isn't in HEAD, but is in the index. In this case git status will tell you that between HEAD and the index, the file got added—an A in the first column of the short output. So in that case you can tell that the file is now tracked, and will be in the next commit.

The tricky case occurs when a file is both untracked and ignored, because now, if the file is not in the HEAD commit (and by definition it's not in the index—we just said it was untracked), the first column can't tell you anything: it's not in either of those two entities, so Git says nothing here. The second column could tell you that the index and work-tree don't match, if the file exists in the work-tree, but since you told Git that the untracked work-tree file should be ignored, git status won't mention it here either.

Finally, there are a few things worth mentioning:

  • You can actually view the index. Run git ls-files --stage to see a quick view of most of what is actually in the staging-area. This is impractical in a big project, precisely because the staging-area holds a copy of every file—well, every file that will be committed. That can be tens of thousands of files. It's much more useful to view the difference between the HEAD commit and the index / staging-area, so that's what git status does (in the first column of --short output).

  • You can also view the contents of a commit directly. Run git ls-tree -r HEAD to see all of the committed files. The output is similar to git ls-files --stage. (It adds the Git object type name and takes away the staging number, and uses a tree structure rather than the index's flattened-tree.) As with git ls-files --stage this is mainly useful for debugging Git or writing fancy new commands, not for regular work.

The key here is that git status summarizes the state of the three entities of interest, by comparing HEAD to the index, and then comparing the index to the work-tree. The two columns show you the differences between them, stripped down to just a letter code and a file name. Even though the next commit will be a snapshot of every file that is in the index / staging-area at that time, it's more useful to tell you what's different about that snapshot, as compared to the current snapshot, or the potential snapshot you could make by copying work-tree files into the index.


1On Windows and MacOS where opening a file named readme.txt opens an existing file named README.TXT (and vice versa), you can use lowercase, but Git has various places where it hard-codes the all-capitals HEAD string, so it's best to stick with that. If you don't like typing that much, the character @ is a synonym for HEAD.

2Technically, a commit stores the hash ID of a tree object. The tree object stores each file's name, mode (100644 or 100755), and content-hash-ID, along with names and hash IDs for subtrees as needed. Hence the file contents are not actually inside the commit, but rather laid out as blob objects, right alongside commit and tree objects. This is the mechanism by which commits—and the index!—share blob objects so that however many snapshots you have of a big file, you really only have one copy in the repository database.

Answer from torek on Stack Overflow
🌐
Git
git-scm.com › docs › git-status
Git - git-status Documentation
Displays paths that have differences between the index file and the current HEAD commit, paths that have differences between the working tree and the index file, and paths in the working tree that are not tracked by Git (and are not ignored by gitignore[5]). The first are what you would commit by running git commit; the second and third are what you could commit by running git add before running git commit. ... Give the output in the short-format.
🌐
GitHub
github.com › git-guides › git-status
Git Guides - git status · GitHub
When in doubt, run git status. This is always a good idea. The git status command only outputs information, it won't modify commits or changes in your local repository.
🌐
Atlassian
atlassian.com › git › tutorials › inspecting a repository
Git Status: Inspecting a repository | Atlassian Git Tutorial
December 15, 2025 - The git status command displays the state of the working directory and the staging area. It lets you see which changes have been staged, which haven’t, and which files aren’t being tracked by Git.
Top answer
1 of 2
12

"the README file is modified in the working directory but not yet staged": We're not tracking this file. Still, Git understands that it has been modified. From the last snapshot.

No, this is wrong: specifically, the file is staged (and the staged copy matches the HEAD copy, and this makes the file tracked). The tricky part with the staging-area is that it is normally mostly invisible. This leads people down the wrong path in trying to understand how it works.

First, let's tackle some Git terminology. There are three entities of interest at this point: the current commit, the staging-area—which actually has three names—and the work-tree. The three names for the staging-area are index, staging-area, and cache, and these three names reflect the low quality of Linus Torvald's original choice ("index") or the enormous importance of the invisible staging-area, or both. (I think both.) Let's look deeper at each one:

  • The current commit, which we can also name via the name HEAD (in all capitals1), is of course a commit—it's a snapshot of all the files that were in the staging area when you (or whoever) ran git commit. This snapshot is permanent (mostly) and read-only (entirely). Its true name is not HEAD—that's just a symbolic name by which we can find it right now—but rather some big ugly hash ID. The hash ID appears random, but is in fact a cryptographic checksum of the complete contents of the commit. That's why the commit can't be changed—changing anything would change the checksum, resulting in a different commit.

    The files stored within2 the commit are also read-only. They are stored in a special, Git-only, compressed form. This particular compression has the nice property that if the contents of a file are the same from one commit to another, these commits all share the underlying compressed file-image. That means you can commit a big file millions of times, if you like, and not use any more space than committing that file once.

  • The index / staging-area / cache is this crazy almost-invisible data structure. It contains all the files at all times, in the same way that a commit contains all the files. The files in the index are also in this special compressed Git-only format. The key difference between a file copy in the index / staging-area, and a copy in a commit, is that the index one can be overwritten.

    (The index also caches—hence the name "cache"—information about the work-tree, to make Git go faster. These two facts, that the index holds all the files all ready to go into the next commit, and that it caches stuff about the work-tree, are what make git commit so insanely fast, compared to other similar version control systems.)

  • The work-tree is the simplest of the three, but in a sense, also the one Git cares the least about. It's where you do your work on your files. These files are in the ordinary format that the rest of your computer programs understand. They are the most important to you, but the least important to Git: a --bare repository has no work-tree, but Git can still function (in a more limited way of course).

The work-tree is the only one of these three things that you can see easily and directly. Simply use whatever command it is that lists files or views files: there they are, plain to see. Fortunately, commits are easy to see as well, by checking them out.

When you initially check out some particular commit—via git checkout master or git checkout develop, for instance—Git populates both your index / staging-area and you work-tree from that commit. It sets HEAD to be a symbolic name for the correct hash ID. That way, the index already has in it all the same files that are in the HEAD commit, and the work-tree has all the same files that are in the index.

If you modify a file in the work-tree, and then run git add on it, Git copies the work-tree version of that file into the index / staging-area. Now the HEAD commit version and the index version differ, but the index version and the work-tree version agree with each other.

If you modify a file in the work-tree but don't run git add on it, the HEAD and index versions agree, but the index version disagrees with the work-tree version.

If you modify a file in the work-tree, then (1) use git add to copy it to the index / staging-area and (2) modify it again, now all three versions of that file differ. This is where you will see an MM status.

What git status is doing is, in effect, running two diffs. The first one compares HEAD to the index. Whatever is different here is "staged for commit". The second diff compares the index to the work-tree. Whatever is different here is "not staged for commit". That's almost it—we're nearly done!

Last, let's take a look at the term tracked as applied to files. In Git, a file is tracked if and only if it is in the index / staging-area. It's really that simple! The tricky part is telling whether a file is in fact in the index, since it's normally so invisible there.

The git status command compares the index: first, it compares HEAD vs index. Suppose some file is in both HEAD and index and has the same contents in both. Then you won't see it here. Likewise, you won't see it here if it's the same in the index and the work-tree. So if the file is in the index, but matches both HEAD and work-tree versions, it's invisible.

Suppose some file isn't in the index. If it's in HEAD, git status will tell you that between HEAD and the index, the file got deleted—a D in the first column of the short output. So in that case you can tell: the file has gone away from the index, and is no longer tracked. It won't be in the next commit.

Suppose some file isn't in HEAD, but is in the index. In this case git status will tell you that between HEAD and the index, the file got added—an A in the first column of the short output. So in that case you can tell that the file is now tracked, and will be in the next commit.

The tricky case occurs when a file is both untracked and ignored, because now, if the file is not in the HEAD commit (and by definition it's not in the index—we just said it was untracked), the first column can't tell you anything: it's not in either of those two entities, so Git says nothing here. The second column could tell you that the index and work-tree don't match, if the file exists in the work-tree, but since you told Git that the untracked work-tree file should be ignored, git status won't mention it here either.

Finally, there are a few things worth mentioning:

  • You can actually view the index. Run git ls-files --stage to see a quick view of most of what is actually in the staging-area. This is impractical in a big project, precisely because the staging-area holds a copy of every file—well, every file that will be committed. That can be tens of thousands of files. It's much more useful to view the difference between the HEAD commit and the index / staging-area, so that's what git status does (in the first column of --short output).

  • You can also view the contents of a commit directly. Run git ls-tree -r HEAD to see all of the committed files. The output is similar to git ls-files --stage. (It adds the Git object type name and takes away the staging number, and uses a tree structure rather than the index's flattened-tree.) As with git ls-files --stage this is mainly useful for debugging Git or writing fancy new commands, not for regular work.

The key here is that git status summarizes the state of the three entities of interest, by comparing HEAD to the index, and then comparing the index to the work-tree. The two columns show you the differences between them, stripped down to just a letter code and a file name. Even though the next commit will be a snapshot of every file that is in the index / staging-area at that time, it's more useful to tell you what's different about that snapshot, as compared to the current snapshot, or the potential snapshot you could make by copying work-tree files into the index.


1On Windows and MacOS where opening a file named readme.txt opens an existing file named README.TXT (and vice versa), you can use lowercase, but Git has various places where it hard-codes the all-capitals HEAD string, so it's best to stick with that. If you don't like typing that much, the character @ is a synonym for HEAD.

2Technically, a commit stores the hash ID of a tree object. The tree object stores each file's name, mode (100644 or 100755), and content-hash-ID, along with names and hash IDs for subtrees as needed. Hence the file contents are not actually inside the commit, but rather laid out as blob objects, right alongside commit and tree objects. This is the mechanism by which commits—and the index!—share blob objects so that however many snapshots you have of a big file, you really only have one copy in the repository database.

2 of 2
2

You can read about what the letters means here :

https://www.git-scm.com/docs/git-status#_short_format

If "staging area", "added" or "unmerged" are unfarmiliar to you, maybe you need to deepen your git understanding. Or maybe just stop using the -s flag, which is really simpler to understand.

The git pro git is really git, but you can't pick what you want to read. Read everything, in the correct order. https://git-scm.com/book/en/v2

🌐
GeeksforGeeks
geeksforgeeks.org › git › git-status
Git Status - GeeksforGeeks
March 14, 2026 - To use the git status command, navigate to your Git repository in your terminal and type: ... This command does not require any arguments, and its output provides a snapshot of your repository’s status.
🌐
Git Tower
git-tower.com › learn › git faq › how to use git status in git (with examples)
How to Use git status in Git (with Examples) | Learn Version Control with Git
5 days ago - git status shows the current state of your working copy — which files have changed, which are staged for the next commit, and whether your branch is in sync with its remote counterpart.
🌐
CloudBees
cloudbees.com › blog › git-status-in-depth
Git Status in Depth: Understanding Your File States
November 1, 2021 - Remember we added file3 in the no-history state? We can see it under the "Ignored files" heading in the output of the git status command as shown above.
🌐
Initial Commit
initialcommit.com › blog › git-status
Git Status Command | Uses, Applications & Related Commands
April 5, 2022 - The git status command provides useful information about the current state of your Git repository. It outputs the active branch, remote sync status, and a list of modified files in the working directory and staging area.
Find elsewhere
🌐
Linux Man Pages
linux.die.net › man › 1 › git-status
git-status(1): working tree status - Linux man page
Displays paths that have differences between the index file and the current HEAD commit, paths that have differences between the working tree and the index file, and paths in the working tree that are not tracked by git (and are not ignored by gitignore(5)). The first are what you would commit by running git commit; the second and third are what you could commit by running git add before running git commit. ... Give the output in the short-format.
🌐
MIT
web.mit.edu › git › www › git-status.html
git-status(1) Manual Page
Displays paths that have differences between the index file and the current HEAD commit, paths that have differences between the working tree and the index file, and paths in the working tree that are not tracked by Git (and are not ignored by gitignore(5)). The first are what you would commit by running git commit; the second and third are what you could commit by running git add before running git commit. ... Give the output in the short-format.
🌐
DataCamp
datacamp.com › tutorial › git-status
Git Status: How To Track Changes in Your Project with Confidence | DataCamp
April 1, 2025 - Git status shows your repo's current state. Learn how to use it effectively, interpret output, and streamline your Git workflow with practical examples.
🌐
Stefan Judis
stefanjudis.com › today-i-learned › the-short-version-of-git-status-and-the-close-but-different-porcelain-mode
The short version of 'git status' and the close but different '--porcelain' mode | Stefan Judis Web Development
September 15, 2025 - git status -s highlights the characters that give information on the files' status. This highlighting makes it easier to read. This formatting and color highlighting are missing when using --porcelain.
🌐
Medium
medium.com › @Ariobarxan › git-status-d105b3dd2ae7
Git status. This article is one of the articles in… | by Ario Liyan | Medium
September 17, 2023 - This makes it ideal for quickly assessing the state of your repository without overwhelming you with excessive details. The short status command output consists of a two-column format.
🌐
TheServerSide
theserverside.com › blog › Coffee-Talk-Java-News-Stories-and-Opinions › How-to-master-the-Git-status-command
How to master the Git status command
If a file is edited the status reported will be modified: $ echo "Hello World" >> index.html $ git status On branch feature Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git checkout -- <file>..." to discard changes in working directory) modified: index.html no changes added to commit (use "git add" and/or "git commit -a")
🌐
gitlearn
gitlearn.io › blog › git status flags explained: -s, -b, --verbose and more
git status Flags Explained: -s, -b, --verbose and More | gitlearn
April 3, 2026 - --short (or -s): Displays each file on a single line using a two-character status code. The left character represents the staging area, the right represents the working directory. Both can be set if a file has changes in both areas. --branch (or -b): Adds branch information to the output, including how many commits ahead or behind you are compared to the upstream branch. Usually combined with -s. Tip: git status -sb is a popular daily driver — compact output with branch context at a glance.
🌐
LabEx
labex.io › questions › what-is-git-status-command-92739
What is Git status command? | LabEx
April 20, 2026 - ## What is the Git status command? The `git status` command is a fundamental Git command that allows you to view the current state of your Git repository.
🌐
TutorialsPoint
tutorialspoint.com › git › git-status.htm
Git Status
The git status command displays the status of our working directory. The output of git status shows where HEAD is at any given time (on a branch or commit). It provides following information: Following is the syntax of git status command: The git
🌐
Z0zerox
z0zerox.github.io › Git-Commands-CheatSheet › 01_basics › status.html
git status | Git Commands Cheat Sheet
# Full status output git status # Short format (condensed output) git status -s # Show branch and tracking info git status -sb
🌐
init, Inc.
terminal.guide › home › git › commands › status guide
git status Command Guide - Terminal Guide
January 19, 2026 - # Basic status check git status # Short format output git status -s # Show branch and tracking info git status -sb