Ignore specific changes to a file in git, but not the entire file

Kevin picture Kevin · May 17, 2013 · Viewed 14k times · Source

I have a file in a git repository that has a local change on it. I want to have git ignore the local change forever, but not the file. In particular,

  • If the file isn't touched besides this change, git add . should never stage it.
  • Likewise, git commit -a shouldn't commit it.
  • If I ever make an additional change to the file, I should be able to stage and commit that change - but the change I'm ignoring should not be staged and committed.

Is there a way to do this? Doing some research, I read about "smudge/clean cycles," where, if I read correctly,

  1. the file would be marked as unchanged,
  2. the change I made would be overwritten when I checkout,
  3. and then a script would automatically reapply the change and then mark the file as unchanged again.

I am very new to git and scripting, though (I'm an intern with C# and Java experience), so if that's what I need to do, can you please post detailed directions or a link to a tutorial on how to set a smudge/clean cycle up?

Background: I want my working branch to be out of sync with the trunk. There is a low priority bug that only affects development machines, so rather than fix it, we're just commenting out the offending code. Obviously, we don't want this code to be removed from production, where it works just fine.

Answer

Mark Lodato picture Mark Lodato · May 17, 2013

You can use the skip-worktree bit. Turn it on with:

git update-index --skip-worktree <file>

After that, git will never stage local changes for <file> and will fail (loudly) if git itself has to write to <file> (say, in a merge or a checkout).

If you ever want to stage a future change, you can turn it off, stage the new change, and then turn it back on:

git update-index --no-skip-worktree <file>
git add -p <file>
git update-index --skip-worktree <file>

While not perfect, this might be good enough. It will be up to you to notice that <file> has unstaged changes, since git will no longer tell you that

Note: My original suggestion was to use assume-unchanged. As explained in Git - Difference Between 'assume-unchanged' and 'skip-worktree', it is really skip-worktree that you want. In particular, assume-unchanged is a promise to Git that you won't change the file, and if you violate that promise Git is allowed to erase your changes or commit them! In contrast, Git will not erase or commit your skip-worktree changes.