Make git status show unmodified/unchanged tracked files?

Here is a brief snippet example (which you can paste in your Linux terminal), creating a new git repository and adding some files to it (using git version 1.7.9.5):

cd /tmp/
mkdir myrepo_git
cd myrepo_git/
git init
git config user.name "Your Name"
git config user.email you@example.com
echo "test" > file_tracked_unchanged.txt
echo "test" > file_tracked_changed.txt
echo "test" > file_untracked.txt
git add file_tracked_unchanged.txt 
git add file_tracked_changed.txt
git commit -m "initial commit"

Now, after the initial commit, I want to change the file_tracked_changed.txt files, and keep the others (here, only file_tracked_unchanged.txt) unchanged for the next commit. Below is a snippet which demonstrates that, and the diverse outputs of git status vs git ls-files (git shell output is prefixed with #):

  • git “reset” workdir to HEAD without touching staging area
  • How can I treat a file not a binary (git)
  • Append the commit message automatically to the file being committed in Git
  • How do I get a “git log” patch for a specific commit
  • Reasons why git is not visible to Rstudio (OSX)
  • Split text file using Unix utilities, like grep and sed
  • echo "test more" >> file_tracked_changed.txt
    
    git status -uno
    # # On branch master
    # # 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:   file_tracked_changed.txt
    # #
    # no changes added to commit (use "git add" and/or "git commit -a")
    git status
    # # On branch master
    # # 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:   file_tracked_changed.txt
    # #
    # # Untracked files:
    # #   (use "git add <file>..." to include in what will be committed)
    # #
    # # file_untracked.txt
    # no changes added to commit (use "git add" and/or "git commit -a")
    git status -uno --short
    #  M file_tracked_changed.txt
    git status --short
    #  M file_tracked_changed.txt
    # ?? file_untracked.txt
    git ls-files -v
    # H file_tracked_changed.txt
    # H file_tracked_unchanged.txt
    
    git add file_tracked_changed.txt
    
    git status -uno
    # # On branch master
    # # Changes to be committed:
    # #   (use "git reset HEAD <file>..." to unstage)
    # #
    # # modified:   file_tracked_changed.txt
    # #
    # # Untracked files not listed (use -u option to show untracked files)
    git status
    # # On branch master
    # # Changes to be committed:
    # #   (use "git reset HEAD <file>..." to unstage)
    # #
    # # modified:   file_tracked_changed.txt
    # #
    # # Untracked files:
    # #   (use "git add <file>..." to include in what will be committed)
    # #
    # # file_untracked.txt
    git status -uno --short
    # M  file_tracked_changed.txt
    git status --short
    # M  file_tracked_changed.txt
    # ?? file_untracked.txt
    git ls-files -v
    # H file_tracked_changed.txt
    # H file_tracked_unchanged.txt
    

    What I’m looking for, is a command which will show all tracked files in a directory (which git ls-files -v does), with their accurate repository status (which git ls-files doesn’t show, as it shows H as status for all tracked files). For instance, I’d like to obtain something like the pseudocode:

    git status-tracked
    # M file_tracked_changed.txt
    # . file_tracked_unchanged.txt
    

    … where the dot . would a symbol indicating a tracked, but unchanged file (if I recall correctly, SVN may use a U character for these).

    Ultimately, I’d like to also show the status of all files in a directory, as in the pseudocode:

    git status-tracked-and-untracked
    # M file_tracked_changed.txt
    # . file_tracked_unchanged.txt
    # ?? file_untracked.txt
    

    … but it’s more important to me to get to the status of all tracked files, as in the pseudo git status-tracked above.

    Any command in git, that already does something like this?

  • How would you measure inserted / changed / removed code lines (LoC)?
  • Git: Should I ignore the Index or is there a killer application for it?
  • How to run git rebase interactive mode to remove duplicate commits
  • Github working on fork while waiting for pull request
  • .gitignore and remove cached makes it so I can't see the file on the server al all?
  • git staging patches: with hunk smaller than a line
  • 4 Solutions collect form web for “Make git status show unmodified/unchanged tracked files?”

    Thanks @sdaau. I’ve made a few changes so that it runs much faster, and delivers results in the same format as git status:

    git ls-files | while read -r line;
    do
        st=$(git status -s "$line");
        if [ -n "$st" ]; then
            echo "$st";
        else
            echo "   $line";
        fi;
    done
    

    Thanks to @Andomar, for the git ls-tree tip; this is what it shows:

    git ls-tree --name-status HEAD
    # file_tracked_changed.txt
    # file_tracked_unchanged.txt
    

    … but I want statuses :)

     

    OK, here is a solution, calling both ls-files and status, and interleaving them with a bit of bash parsing:

    git ls-files -cdmoskt --abbrev=8 | while read -r line; do \
      fn=$(echo "$line" | sed 's/.*\s\(\w\+\)/\1/'); \
      st=$(git status -s "$fn" | printf "%-02s " $(sed 's/\([[:print:]]\+\)\s.*/\1/')); \
      echo "$st- $line"; \
    done
    

    If you run this as in the OP example, you get:

    git ls-files -cdmoskt --abbrev=8 | while read -r line; do fn=$(echo "$line" | sed 's/.*\s\(\w\+\)/\1/'); st=$(git status -s "$fn" | printf "%-02s " $(sed 's/\([[:print:]]\+\)\s.*/\1/')); echo "$st- $line"; done
    # ?? - ? file_untracked.txt
    # M  - H 100644 52e7a08e 0  file_tracked_changed.txt
    #    - H 100644 9daeafb9 0  file_tracked_unchanged.txt
    

    … which is basically what I wanted. (I’ll post back here if I have luck in converting this into a git alias).


    EDIT: here as git alias (for ~/.gitconfig):

      ls-fstatus = "! cd $PWD/$GIT_PREFIX; git ls-files -cdmoskt --abbrev=8 | while read -r line; do \
        fn=$(echo \"$line\" | sed \"s/.*\\s\\([[:print:]]\\+\\)/\\1/\"); \
        st=$(git status -s "$fn" | printf \"%-02s \" $(sed \"s/\\([[:print:]]\\+\\)\\s.*/\\1/\")); \
        echo \"$st- $line\"; \
      done "
    

    … so one can just call git ls-fstatus in a given git repo subdirectory.

    Inspired by @RogerDueck’s answer, I made a script that executes git ls-files and git status only once each. It runs about 15 times faster on my repo with ~ 1700 files, just under 2 sec.

    EDIT: Added a number of fixes and some unittests, moved to GitHub: https://github.com/frnhr/git-fullstatus

    Sample output:

     M some/file
    D  another/file
     D more/files/blahblah
    A  this/is/an/added/file/i/think
       an/unchanged_file
       another/unchanged_file
    
    git status -s | egrep -v '^\?\?'
    

    This filters out lines that start with ??, that is, the untracked files.

    Git Baby is a git and github fan, let's start git clone.