2

I know how to use git update-index --assume-unchanged on a file in a working directory.

My question is this: Is there any easy way to still check the difference of the file from, say, the version of that pointed to by the HEAD?

Right now I have to temporarily undo -assume-unchanged before I can run git diff. The sequence goes like this:

git update-index --no-assume-unchanged foo.java
git diff foo.java
git update-index --assume-unchanged foo.java

This works but it is kind of clumsy.

The file is tracked by git but I need a locally modified version for my development environment. And I never want to commit the locally mofified version into git.

Updated

The question still applies even when I switch to use skip-worktree instead of assume-unchanged. I have just learned that the former option is a better one if the file is intended to be changed. See this link for more information about the two options.

leeyuiwah
  • 6,562
  • 8
  • 41
  • 71
  • You can run `git diff --no-index` to use `git diff` as a fancier version of plain `diff` ... or just run plain `diff`. But either way you'll have to have a copy of the specific version of the file you want to diff against, such as an extract from the `HEAD` commit, saved somewhere as an ordinary file. – torek Sep 18 '17 at 17:22
  • @torek -- But then it seems the steps are even more clumsy that the sequence that I am using (having to check out a version of the file as an ordinary file somewhere). Thanks anyway! – leeyuiwah Sep 18 '17 at 17:24
  • 2
    I *think* the correct answer is "use `--skip-worktree`, not `--assume-unchanged`", but I'm not sure. Edit: [it looks like you should be doing that](https://stackoverflow.com/questions/13630849/git-difference-between-assume-unchanged-and-skip-worktree) whether or not it actually helps with `git diff` in particular. – Daniel H Sep 18 '17 at 17:24
  • @Daniel H -- Thanks for the note. I agree with your comment after reading this: https://stackoverflow.com/a/13631525 – leeyuiwah Sep 18 '17 at 18:01
  • @leeyuiwah Does that also help with `git diff`, or do you still need a solution to that? – Daniel H Sep 18 '17 at 18:04
  • @Daniel H -- The question still applies even if switch to use `--skip-worktree`. I updated my question above. Thanks! – leeyuiwah Sep 18 '17 at 18:10
  • With ordinary diff you can script it somewhat: `git cat-file -p HEAD:path | diff -U - path`. Git's diff seems to require two paths arguments (based on documentation), though if you have `/dev/stdin` you could use that. – torek Sep 18 '17 at 18:25

2 Answers2

1

This will accomplish what you're trying to do. For a file named Foo.java:

git show HEAD:Foo.java | git diff --no-index Foo.java -

How does it work? git show <rev>:<path> spits out the contents of the file, as they exist in the object database (see gitrevisions(7)). Using this, calling regular diff with process substitution is a viable solution, as in diff Foo.java <(git show HEAD:Foo.java), assuming you're using a shell environment that supports process substitution. (I've used this when comparing patches.)

You cannot, however, replace this usage of diff with git diff --no-index to get all the color and word features of git diff, as the Git maintainers are very firm about not allowing process substitution with --no-index. (The diff algorithm tries to hash the file contents first, and this is not possible if the file contents are being streamed.) However, --no-index does allow the second file to be standard input (as a special concession to Unix tradition, I suppose), using the special name -.

Thus, you show the file's contents with git show @:Foo.java and pipe it into git diff --no-index, naming the file in the work tree and a dash indicating stdin.

The same trick will work for (npx) prettier (see prettier), which sends the prettified code to standard output if not editing in place. I was able to use npx prettier file.js | git diff --no-index file.js - to highlight the exact line the linter was complaining about. (See this comment and those it references for the source of this idea.)

Menachem
  • 911
  • 7
  • 22
0

(Thanks for all the discussion. I am answering my own question here.)

It seems that there are no easier solution. However, by using alias I can cut down a bit on the typing.

Here are my git aliases:

[alias]
        # show only files that have been skip-worktree
        lsfswt = !git ls-files -v | grep "^S"
        uiswt = update-index --skip-worktree
        uinswt = update-index --no-skip-worktree

With those aliases, here are what I need to type:

git uinswt foo.java
git diff foo.java
git unswt foo.java
leeyuiwah
  • 6,562
  • 8
  • 41
  • 71