Question

Disclaimer : I'm not asking for a solution, a workaround or any kind of advice on how to do things, I'm just curious about the internals of Mercurial.

I have a mercurial repository with some subrepository in it (Git and Mercurial).

  1. My repository and all subrepo are in a clean state (ie: hg st -S returns nothing).
  2. I do some aggressive permission changes at the root : chown www-data:www-data -R *

Now, hg st -S returns each and every file of the Git subrepos (the Mercurial ones are still considered "clean") as modified. The output of hg diff -S -g is empty. I was wondering why this happened ?

What I've discovered so far :

  1. If I do a git status in one of the subrepo, the command show no pending modification and this particular repo isn't marked as modified by hg st anymore
  2. If I limit the permission changes to a subrepo, only this subrepo is marked as modified (ie the "problem" isn't linked to the state of a file in the .hg directory)
  3. Doing a clean update (hg up -C) "solves" the issue
  4. If I change the permission only in the .git directory the subrepo is still considered clean
  5. The output of hg --debug up -C differs for a Git subrepo marked as modified :

"clean" git subrepo :

subrepo/git1: git config --bool core.bare 
subrepo/git1: git rev-parse HEAD
subrepo/git1: git diff-index --quiet HEAD

"modified" git subrepo :

subrepo/git2: git config --bool core.bare
subrepo/git2: git rev-parse HEAD
subrepo/git2: git diff-index --quiet HEAD
  subrepo subrepo/git2: other changed, get git://github.com/XXXX/YYYY.git:6f2442d36bb44724af116b97c85d2e344fc9a0a2:git
subrepo/git2: git cat-file -e 6f2442d36bb44724af116b97c85d2e344fc9a0a2
subrepo/git2: git config --bool core.bare
subrepo/git2: git rev-parse HEAD
subrepo/git2: git reset HEAD
subrepo/git2: git reset --hard HEAD

So, as far as I can tell, the permission changes in the metadata isn't the cause here, so what is ? I'm probably just missing something really simple.

FYI, I use the 1.9.3 version and I don't remember if I remarked the same comportment on a previous one.

And before someone propose that I stop doing the permission change like this, I already did and I'm not confronted to this problem anymore, it's just that I like to understand why something is happening ;)

Update

running git diff-index HEAD gives the following output :

[...]
:100644 100644 fef0f187a5eabc82dc1a90661bd86d317114e40e 0000000000000000000000000000000000000000 M      my/file/insubrepo.php
[...]

If I run git diff-index -p HEAD, the diff is empty. I still have no clue why git consider these files modified.

Was it helpful?

Solution

The likely problem (with a potential solution):

Changing the file mode will change the file stat with respect to the Git index (as noted here).

To correct the problem try:

  1. Navigating to your Git sburepo
  2. Run git update-index --refresh

That should fix the file stat being dirty.


Background info on Mercurial internals:

To determine if a Git subrepo is dirty (i.e. has local modifications), Mercurial runs git diff-index --quiet HEAD.

See the dirty method of subrepos.py::gitsubrepo.

I expect that after you change permissions, git diff-index shows the changes that your manual execution of git status does not.

The output of git diff-index is formatted as follows (see man page for details):

:<mode before> <mode after> <status> <file>

Given the output you listed above, this says that: "File my/file/insubrepo.php has been modified in the working copy, but the file mode is the same".

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top