Tracked, Untracked, and Ignored: An Exploration with git ls-files

The git ls-files command is used in Git to display detailed information about files that are tracked by Git in a repository. It's very helpful when you want to understand which files are in the index (staged for the next commit) or to debug certain issues with your repository.

Most Useful Options:

  1. -s: Show the details of indexed files.

  2. -o: Show other (untracked) files.

  3. -i: Show ignored files with the -o option.

  4. --stage: Show staged contents' object name, mode bits, and stage number in the output.

  5. --deleted: Show only deleted files in the output.

  6. --modified: Show only modified files in the output.

  7. -c, --cached: Show cached files in the output (default).

  8. --exclude=<pattern>: Show files in the output that do not match the given pattern.

  9. --exclude-from=<file>: Read exclude patterns from <file>.

  10. --exclude-standard: Add the standard Git exclusions: .git/info/exclude, .gitignore in each directory, and the user's global exclusion file.

Workshop Exercises:

  1. Understanding Tracked Files:

    • Create a new Git repository using git init.

    • Create 3 files: a.txt, b.txt, and c.txt.

    • Add a.txt to Git using git add a.txt.

    • Use git ls-files to see which files are tracked by Git.

Solution:

    mkdir ls-files-test
    cd ls-files-test
    git init
    touch a.txt b.txt c.txt
    git add a.txt
    git ls-files    # This should show a.txt
  1. Exploring Untracked and Ignored Files:

    • Continuing from the previous exercise, create a .gitignore file and add b.txt to it.

    • Use git ls-files -o to show untracked files.

    • Use git ls-files -o -i --exclude-standard to show ignored files.

Solution:

    echo "b.txt" > .gitignore
    git ls-files -o   # This should show b.txt, c.txt and .gitignore
    git ls-files -o -i --exclude-standard # This should show b.txt

--exclude-standard: This is an important option here. It tells Git to use the standard ignore patterns when determining which files are ignored. The standard ignore sources are:

  • Patterns from .gitignore files in the repository (both in the root and in subdirectories).

  • Patterns from the .git/info/exclude file in the specific repository.

  • Patterns from the global ignore file, usually located at $HOME/.config/git/ignore or $HOME/.gitignore (depending on your setup).

  1. Seeing Details of Indexed Files:

    • Use git ls-files -s to see the details of indexed files.

Solution:

    git ls-files -s   # This should show details of a.txt, including mode bits, object name, and stage number.

The git ls-files -s (or --stage) command displays the staging area (or index) entries. Each entry has various pieces of information, including the stage number.

In the context of the Git index, the stage number indicates the state of a file in a merge conflict scenario. When a merge conflict occurs, multiple versions of the conflicted file are added to the index, each with a different stage number:

  • Stage 0: The file is not in conflict and is typically what you'd see in the index outside of merge conflicts.

  • Stage 1: Represents the "base" version of the file, which is the common ancestor of the branches being merged.

  • Stage 2: Represents the version from the "current" branch (the branch you're on, and you're trying to merge another branch into).

  • Stage 3: Represents the version from the "other" branch (the branch you're trying to merge).

So, if you're in the middle of resolving a merge conflict and run git ls-files -s, you might see multiple entries for the conflicted file, each with stage numbers 1, 2, and 3. These entries give you access to the different versions of the file, helping you understand the differences and resolve the conflict.

For example, the output might look like this for a conflicted file named conflict.txt:

    100644 2b3f1e0f015efe16c478c57f651f8bb5a8d8f5e3 1   conflict.txt
    100644 f67e6e9c5b4f6f193c8c37b385b7c8c2c6c456ff 2   conflict.txt
    100644 9f3f1e0f014afe16c578c77f252f7bb4a8a9d4b2 3   conflict.txt

Here, the columns represent:

  1. Mode bits.

  2. Object name (SHA-1).

  3. Stage number.

  4. File name.

You'd typically resolve the conflict, add the resolved file to the index, and then commit. After resolving and adding, the git ls-files -s command would then only show a stage 0 entry for that file.

  1. Identifying Modified Files:

    • Modify a.txt and use git ls-files --modified to identify the changed files.

Solution:

    echo "Hello, World!" > a.txt
    git ls-files --modified  # This should show a.txt

References

  1. git ls-files command

  2. What does "git ls-files" do exactly and how do we remove a file from it?