Re: Weird behaviour of git diff-index in container

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi!

Timo Funke wrote:

> podman run --rm -it -v `pwd`:/git:z --entrypoint sh docker.io/alpine
> > container# apk add git
> > container# cd /git
> > container# git diff-index --quiet HEAD -- ; echo $?
> 1
> > container# git diff-index --quiet HEAD -- ; echo $?
> 1
> > container# git status
> On branch master
> nothing to commit, working tree clean
> > container# git diff-index --quiet HEAD -- ; echo $?
> 0
>
>
> What did you expect to happen? (Expected behavior)
> `git diff-index --quiet HEAD -- ; echo $?` should return `0`
> even without executing `git status`.
>
> What happened instead? (Actual behavior)
> Without executing `git status` `git diff-index --quiet HEAD -- ; echo $?`
> will repeatedly print `1`.
>
> What's different between what you expected and what actually happened?
> It is odd that `git diff-index --quiet HEAD -- ; echo $?` prints
> different results depending on whether `git status` was executed.

I love this example.  Thanks for writing.

I checked "git help diff-index" to see whether it describes this
pitfall, and I didn't see an explanation.  So at the very least you
have uncovered a documentation bug.

The difference between diff-index and status here is a difference
between "porcelain" (user-facing) commands and "plumbing"
(script-facing) commands.  In Git's index file there is stat(2)
information for each file; if that stat(2) information matches the
corresponding file in the working directory then we know it hasn't
been modified relative to what is in the index.  If the stat(2)
information differs from the working copy, on the other hand, the
behavior depends on whether the command being run is porcelain or
plumbing:

 - plumbing commands assume that the script author has run "git
   update-index --refresh -q" first to update the stat(2) information
   if the file hasn't changed.  This allows efficient scripts to
   refresh the index once and then run multiple commands that rely on
   the result of that:

	git update-index --refresh -q || :
	for rev in "${revs[@]}"
	do
		if git diff-index --quiet "$rev" --
		then
			... do something ...
		fi
	done

 - porcelain commands such as "git status" implicitly refresh the
   index before doing anything else.  This allows them to produce the
   expected result even if the repository is a copy made using "cp -a"
   or has been transferred across machines on a USB stick.

Some places I expected to find an explanation of this:

- documentation for the "git diff-index" command ("git help
  diff-index").  It does not mention this behavior.

- documentation for the "git diff" command ("git help diff").  It also
  doesn't mention this.  That's particularly surprising because it
  would be a great place to document the diff.autoRefreshIndex setting
  that affects this behavior of the "git diff" command (described in
  Documentation/config/diff.txt).

- the Git user manual (Documentation/user-manual.txt).  It describes
  "git update-index --refresh" but very briefly.  It doesn't describe
  the above scripting pattern.

- Git's command-line conventions ("git help cli").  No mention.

- overview of plumbing and porcelain commands ("man git").  No
  mention.

- the Git scripting manual ("git help core-tutorial").  It describes
  "git update-index --refresh" after a "cp -a" but not its use in
  scripts.

- the history of Git's contrib/examples/.  This contains many examples
  of the above scripting pattern but is not very discoverable.

So there are many opportunities for someone to document this better.
If you'd be interested in pursuing that, I'd be happy to provide some
pointers.

Thanks,
Jonathan



[Index of Archives]     [Linux Kernel Development]     [Gcc Help]     [IETF Annouce]     [DCCP]     [Netdev]     [Networking]     [Security]     [V4L]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]     [Fedora Users]

  Powered by Linux