问题
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).
- My repository and all subrepo are in a clean state (ie:
hg st -S
returns nothing). - 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 :
- 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 byhg st
anymore - 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) - Doing a clean update (
hg up -C
) "solves" the issue - If I change the permission only in the
.git
directory the subrepo is still considered clean - 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.
回答1:
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:
- Navigating to your Git sburepo
- 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".
来源:https://stackoverflow.com/questions/8170240/mercurial-internals-git-subrepository-status-after-aggressive-permission-chang