`git update-index`: changing what is added to the staging area

This is a short post about git index, i.e. the staging area, and about the git command to ignore changes in specific file locally.

Background

Most git beginners know about gitignore, the file specifies intentionally untracked files that Git should ignore. But as we start to work on large codebases, we become more aware that .gitignore is part of a shared workflow for all contributors of the same repo.

What if my workflow deviates from the shared workflow? Specifically, how do I ignore certain file from being added to my staging area that is not listed in .gitignore? The files I have been wanting to ignore locally are db file <name>.sql or some cache files like <name>.cache.

The problem

My git workflow usually involves git add . and git diff. Both give me information about all changes I made locally. The former adds them to the staging area, the latter helps me to visualise them easily on my terminal. And before I use any of these two commands, I usually start by running git status to glance at the list of changed files.

But these become awkward to use when I have changes I don’t intend to add to my staging area.

For example, let’s say I have a changed file hosting.cache that I don’t want to add to my staging area:

git status

# =>  modified:   hosting.cache
      modified:   changes_I_want_to_commit_1.rb
      modified:   changes_I_want_to_commit_2.rb
      ...

If I run git add . now, git will add all changes for these three files to my staging area. And when I use git diff, the changes in hosting.cache clutter my view because git will also show me the changes from hosting.cache.

I had used a clumsy workaround by first adding all changed files to staging with git add ., then using git restore --staged <file> to unstage the specific file. And I’d repeat this when I work on the next commit on the same branch. This is clearly not the right way!

The Solution

Turns out there is a command to ignore changes in a specific file locally: git update-index --skip-worktree <filename>.

Interesting. But how does it work? What is an index in git?

💡 To update the index simply means to update the staging area. index actually is what I have understood as “the staging area”. By modifying the index, I am telling git to register / de-register certain file contents in the working tree to the staging area.

git update-index --skip-worktree hosting.cache
git status

# =>  modified:   changes_I_want_to_commit_1.rb
      modified:   changes_I_want_to_commit_2.rb
      ...

This doesn’t mean that the change I made in hosting.cache is now gone, the change is still in my working directory. But now git has ignored that change for my index.

Reverting the change

Worry about ignoring changes that you meant to commit? If you update index on the wrong file, you can reverse the change with git update-index --no-skip-worktree <filename>.

Caution

This is a one-off solution to avoid changes in certain files from being added to the staging area. To consistently ignore certain files across all git operations, it’s best to set up the git configuration differently.

See you next time 👋
Julia