threads / discuss / 44425

git -C has unexpected behaviour

Subject: git -C has unexpected behaviour

## tl;dr

5 messages between Nov 4, 2016 and Nov 7, 2016.

replies: 4people: 3as markdown or json

Felix Nairz· Nov 4, 2016, 14:28 UTC · lore
Hi guys,
I ran into some really weird git behaviour today.
My git --version is: git version 2.8.1.windows.1

We have a git repository with a submodule called TestData. The data in there is modified and reset as part of our unit tests.

The submodule is a sub-folder of the git repository called TestData. So the relative path from the git repository to the submodule is .\TestData

If I delete the entire TestData folder and run git -C .\TestData reset --hard

I will get the following error: git : fatal: Cannot change to '.\TestData': No such file or directory This is as expected.

Now, to the unexpected part, which I think is a bug:

If the TestData folder is there, but empty (I deleted all the files), then running

git -C .\TestData reset --hard
will NOT throw me an error but run
git reset --hard

on the git repository (not the submodule in the sub-directory!), without warning, or error. This is easy to reproduce by having an empty .\TestData folder, and just changing any file in your git repository before running

git -C .\TestData reset --hard
and seeing the local file changes gone.

Because of this we have had losses of uncommitted changes a few times now (loosing a few days of work, and getting a bit paranoid), but could never find the root cause for this until today, where I found out that it happens when the TestData directory is empty.

Thank for looking into this, and I am looking forward to hear your opinions about this.

Best Regards, Felix Nairz
Stefan Beller· Nov 4, 2016, 16:10 UTC · re: Felix Nairz · lore

Re: git -C has unexpected behaviour

On Fri, Nov 4, 2016 at 7:28 AM, Felix Nairz <felix.nairz@gmail.com> wrote:
Show 24 quoted lines
> Hi guys,
>
> I ran into some really weird git behaviour today.
>
> My git --version is: git version 2.8.1.windows.1
>
> We have a git repository with a submodule called TestData. The data in
> there is modified and reset as part of our unit tests.
>
> The submodule is a sub-folder of the git repository called TestData.
> So the relative path from the git repository to the submodule is
> .\TestData
>
> If I delete the entire TestData folder and run
> git -C .\TestData reset --hard
>
> I will get the following error:
> git : fatal: Cannot change to '.\TestData': No such file or directory
> This is as expected.
>
>
> Now, to the unexpected part, which I think is a bug:
>
> If the TestData folder is there, but empty (I deleted all the files),

And "all the files" includes the ".git" file, which git uses to find out if it is in a git repository. So it keeps walking up until it finds a .git file/directory, which is the parent project.

Once a git directory is found, the main function of git initializes some data structures, e.g. the "path prefix" inside the repository which would be " .\TestData" in your case. then the actual command is found and run.

So what it is doing is: "Suppose you are in the TestData directory of the parent project and then run the command ..."

My gut reaction was to propose to check if any GITLINK (submodule) is a prefix of said "path prefix" and then rather initialize and operate on the submodule.

However I do not think this is a good idea:
* Git wants to be fast and checking if we are in any submodule
slows down the common case.
* Historically commands in un-initialized or deinitialized submodules
behave as if in the parent project. I think if we'd fix this issue, other
people would complain as their workflow is harmed.
>
> Because of this we have had losses of uncommitted changes a few times
> now (loosing a few days of work, and getting a bit paranoid),
* commit early, commit often such that the losses are less than a few days.
* do not remove the submodule directory as a whole thing
  (make sure the .git file is there and not wiped)
* instead use "git -C TestData clean -dffx && git -C TestData reset --hard"
   https://git-scm.com/docs/git-clean
> could never find the root cause for this until today, where I found
> out that it happens when the TestData directory is empty.

I am undecided if it is a bug or a feature. Fixing this as a bug would be a performance penalty. Not fixing it may incur data losses. I dunno.

Show 5 quoted lines
>
> Thank for looking into this, and I am looking forward to hear your
> opinions about this.
>
> Best Regards, Felix Nairz
Johannes Schindelin· Nov 4, 2016, 16:36 UTC · re: Felix Nairz · lore

Re: git -C has unexpected behaviour

Hi Felix,
On Fri, 4 Nov 2016, Felix Nairz wrote:
Show 13 quoted lines
> Now, to the unexpected part, which I think is a bug:
> 
> If the TestData folder is there, but empty (I deleted all the files),
> then running
> 
> git -C .\TestData reset --hard
> 
> will NOT throw me an error but run
> 
> git reset --hard
> 
> on the git repository (not the submodule in the sub-directory!),
> without warning, or error.

I *think* that this is actually intended. Please note that -C is *not* a synonym of --git-dir. It is more of a synonym of

	cd .\TestData
	git reset --hard

In other words, you probably expected -C to specify the top-level directory of a worktree, and you expected Git to error out when it is not. Instead, Git will treat -C as a directory *from where to start*; It *can* be a subdirectory of the top-level directory of the worktree.

Please note that
	git --git-dir=.\TestData\.git reset --hard

will not work, though, as it mistakes the current directory for the top-level directory of the worktree. What you want to do is probably

	git -C .\TestData --git-dir=.git reset --hard

This will tell Git to change the current working directory to the top-level of your intended worktree, *and* state that the repository needs to be in .git (which can be a file containing "gitdir: <real-git-dir>", which is the default in submodules).

If the repository is *not* found, this command will exit with a failure.

Ciao, Johannes

Felix Nairz· Nov 7, 2016, 07:26 UTC · re: Johannes Schindelin · lore

Re: git -C has unexpected behaviour

Hi guys,
thanks for the answer and the clarification.

From what you are saying I can see that this expects as designed. It's confusing in the submodule case, but I get you don't want to add extra rules which slow down performance and mess with other people at the same time.

I will look into the git-dir solution, this seems to be exactly what I need.
Thanks, Felix

On Fri, Nov 4, 2016 at 5:36 PM, Johannes Schindelin <Johannes.Schindelin@gmx.de> wrote:

Show 47 quoted lines
> Hi Felix,
>
> On Fri, 4 Nov 2016, Felix Nairz wrote:
>
>> Now, to the unexpected part, which I think is a bug:
>>
>> If the TestData folder is there, but empty (I deleted all the files),
>> then running
>>
>> git -C .\TestData reset --hard
>>
>> will NOT throw me an error but run
>>
>> git reset --hard
>>
>> on the git repository (not the submodule in the sub-directory!),
>> without warning, or error.
>
> I *think* that this is actually intended. Please note that -C is *not* a
> synonym of --git-dir. It is more of a synonym of
>
>         cd .\TestData
>         git reset --hard
>
> In other words, you probably expected -C to specify the top-level
> directory of a worktree, and you expected Git to error out when it is not.
> Instead, Git will treat -C as a directory *from where to start*; It *can*
> be a subdirectory of the top-level directory of the worktree.
>
> Please note that
>
>         git --git-dir=.\TestData\.git reset --hard
>
> will not work, though, as it mistakes the current directory for the
> top-level directory of the worktree. What you want to do is probably
>
>         git -C .\TestData --git-dir=.git reset --hard
>
> This will tell Git to change the current working directory to the
> top-level of your intended worktree, *and* state that the repository needs
> to be in .git (which can be a file containing "gitdir: <real-git-dir>",
> which is the default in submodules).
>
> If the repository is *not* found, this command will exit with a failure.
>
> Ciao,
> Johannes
Johannes Schindelin· Nov 7, 2016, 16:54 UTC · re: Felix Nairz · lore

Re: git -C has unexpected behaviour

Hi Felix,
On Mon, 7 Nov 2016, Felix Nairz wrote:
> From what you are saying I can see that this expects as designed. It's
> confusing in the submodule case, but I get you don't want to add extra
> rules which slow down performance and mess with other people at the
> same time.

The "messing with other people" is the key point. There are most likely other users than just me who use the fact that `git -C sub/directory/ ...` works in a subdirectory of a checkout.

Ciao, Johannes

← back to recent threads