How should git behave when two links to same file are different?

299 views Asked by At

I observed the following behavior while working with the perl code base (on branch maint-5.004):

bash-3.2$ git status | grep modified
#       modified:   configure
bash-3.2$ git reset --hard
HEAD is now at 9a4fb7e copy over bleads .gitignore
bash-3.2$ git status | grep modified
#       modified:   Configure
bash-3.2$ git reset --hard
HEAD is now at 9a4fb7e copy over bleads .gitignore
bash-3.2$ git status | grep modified
#       modified:   configure

This is happening because the two files share an inode (they are the same file), but they are different in the git index. My question is: how did that happen? If git is tracking 2 links to the same file, should git be expected to flag it as an error when only one of them is modified? Is this a git bug or user error?

Update:

It appears that the issue is not with git, but is related to case sensitivity of the filesystem (hfs+).

$ mkdir tmp
$ cd tmp
$ touch foo
$ ls -i foo Foo
10301082 Foo    10301082 foo

I think perhaps that OS X needs to reconsidered as a useful platform for development, as this behavior is absurd.

3

There are 3 answers

0
Jiri Klouda On BEST ANSWER

Source control systems generally have problem tracking hardlinks. You should have made one of them a symlink and add the symlink to git and it would work fine. Git can handle symlinks fine.

Unless you would somehow point to a source control system that a file you add to repository is a hardlink, it has no way to know and it certainly won't go comparing inodes of all files on every add just to find out if that is the case.

Even systems that do allow hardlinks try to avoid creating them at all costs, since the number of problems created by hardlinks is quite high and all the resulting bugs and inconsistencies are very hard to track. After a while and few renames and moves of one of the links, two different teams could each own one piece of the hardlink in their part of source tree and a fight over the content of the version tree of the object ensues with nobody being too wise about why with no modifications done to your part of source tree a file content is changing. It's better to use symbolic links.

0
Chuck Vose On

Seems like a git bug to me. As I understand it you made a hardlink from Configure to configure and git is properly seeing them as separate entities but when one changes they should both change in the git index.

Am I correct in the assessment that these are hardlinked?

0
Thiago Arrais On

I'm not sure git actually tracks inodes, it probably only concerns itself with file names. Take a look at this sample execution, for instance:

$ mkdir so.question
$ cd so.question/
$ git init
Initialized empty Git repository in /tmp/so.question/.git/
$ echo "test" > a
$ ln a b
$ ls -i
539367 a  539367 b
$ git add a b
$ git commit -m"One"
[master (root-commit) 897cdea] One
 2 files changed, 2 insertions(+), 0 deletions(-)
 create mode 100644 a
 create mode 100644 b
$ echo "test" >> a
$ git add a
$ git commit -m"Two"
[master bbcba39] Two
 1 files changed, 1 insertions(+), 0 deletions(-)
$ ls -i
539367 a  539367 b
$ git reset --hard
HEAD is now at bbcba39 Two
$ ls -i
539367 a  539389 b

Notice that if I record a commit with changes to only one of the files, git records a change to the file a and assumes b wasn't changed (as I would expect). As far as git is concerned, the other file wasn't modified. If you later do a git reset, the file inodes will no longer be the same as they differ.

I wasn't able to reproduce the behaviour you reported (git status reporting modifications right after a hard reset) and I wonder if this is even possible (if not for a bug). Can you come up with a small example that shows the behaviour you observed?