6

I found a peculiar behavior with git, and I can reproduce it every time on my machine.

If I have two local repositories, one bare inside the folder express.git, and the other non-bare with a working tree inside the folder express, both in the same parent folder, I can do the command git pull ../express.git from inside the express folder. This automatically updates everything inside express.

However, if I run the command git --git-dir /home/cisw470p/stu006/express/.git pull /home/cisw470p/stu006/express.git master from a location no located in either git repository, then the express repo will pull changes, but won't automatically update the working tree. I then have to run git add . to add all changes and then make another commit from inside express and now everything is good.

Why doesn't the long version of the command using the --git-dir option not automatically update the working tree for express? Is there a reason for this, or did I find a bug?

EDIT: I just tried it again but edited a different file and now it worked. I'm completely lost.

trusktr
  • 44,284
  • 53
  • 191
  • 263
  • How are you expecting git to find the work tree with the long form? Have you tried adding the `--work-tree=...` arg? – Lily Ballard Mar 16 '12 at 22:08
  • Inside `express` is the work tree along with the `.git` folder, like a normal repo. – trusktr Mar 16 '12 at 22:19
  • When giving `git` an explicit git-dir, why are you expecting it to just assume the parent of the git dir is a work tree? That could be a rather dangerous assumption in many cases (notably, if the git dir is actually a bare repo) – Lily Ballard Mar 16 '12 at 22:26
  • Good point. I'm still getting familiar with git. So far I've only encountered bare repos or repos where the working tree is in the parent of the .git folder so I thought it was like a default. Let me see if the work-tree option fixes everything. – trusktr Mar 16 '12 at 23:14
  • Most people never even use the `--git-dir` or `--work-tree` flags. They're mostly only useful when writing esoteric scripts that need to reach in and poke at other repositories. When using these sorts of options, you need to specify everything because you're explicitly telling git not to follow its default heuristics to detect them. – Lily Ballard Mar 16 '12 at 23:33
  • @KevinBallard Hey, I tried using the --work-tree option but I get the error `git-pull cannot be used without a working tree`. For example, I have --git-dir /path/to/repo/.git --work-tree /path/to/repo` in my git, but it doesn't work. Am I using it wrong? – trusktr Mar 16 '12 at 23:36
  • @KevinBallard By the way, can you post an answer so I can accept it? – trusktr Mar 16 '12 at 23:47
  • Answer posted. It seems the work tree needs to be an absolute path. – Lily Ballard Mar 17 '12 at 00:00

1 Answers1

12

If you run git --git-dir=some/dir/.git pull, by default git will assume the current directory is the work tree. Not the parent of some/dir/.git, but your current pwd. This means that running that command will try to update the current directory as if it's the work tree and will end up writing files into your pwd that don't belong there.

The appropriate solution is to use the --work-tree flag in conjunction with --git-dir to tell it where the work tree is. In this case you'd want git --git-dir=some/dir/.git --work-tree=some/dir pull. However, after experimentation it seems there's a second problem here. If you try this command as-is, you'll probably be told git-pull cannot be used without a working tree. It seems the issue here is git needs its work tree to be an absolute path instead of a relative one.

What you really want to run is git --git-dir=some/dir/.git --work-tree="$PWD"/some/dir pull. Alternatively, you could just try cd some/dir && git pull. If you don't want to change your cwd, you can wrap this in a subshell, i.e. ( cd some/dir && git pull ).

Lily Ballard
  • 182,031
  • 33
  • 381
  • 347
  • Interesting. Using a subshell works at the command line, but the problem is if i do `(cd some/dir/.git && git pull)` inside a hook script it won't work and I will get an error telling me no git repo exists at that location (`fatal: Not a git repository`); the same error whether I cd to the absolute paths `/some/repo` or `/some/repo/.git`. That's why I resorted to using --git-dir, and now --work-tree. However, I'm using absolute paths, and i'm is still getting the `git-pull cannot be used without a working tree` error. My path starts with `/`, which means it is absolute, right? – trusktr Mar 17 '12 at 00:24
  • Yes, starting with a `/` means it's absolute. Maybe the path is wrong? Also, you should just use `(cd some/dir && git pull)`, not `(cd some/dir/.git && git pull)`. If you can run `git pull` from that dir in an interactive terminal, you should be able to do so from a subshell in a script. – Lily Ballard Mar 17 '12 at 02:55
  • Regardless, with or without the .git in the path I get the same error... I'll post it when I'm back from mobile. And yeah, I triple checked I'm typing the correct path. – trusktr Mar 17 '12 at 03:22
  • @trusktr: Do you have the `GIT_DIR` or `GIT_WORK_TREE` environment variables set? The `--git-dir` and `--work-tree` arguments *should* be overriding those though. – Lily Ballard Mar 17 '12 at 04:26
  • Ahah, turns out it's a bug with the version of git that I have: http://stackoverflow.com/questions/9745941/ – trusktr Mar 17 '12 at 06:35
  • Hmm... so if I try using the `(cd some/dir/.git && git pull)` method it works at the command line perfectly, but not inside my post-receive hook script. I wonder why? – trusktr Mar 17 '12 at 08:14
  • Whenever I execute `(cd some/dir/.git && git pull)` in a shell script I get the error `fatal: Not a git repository: '.'` despite the fact that it works perfectly when I do it manually from the command line. – trusktr Mar 17 '12 at 08:24
  • @trusktr: Ok, so it sounds like you did have a `GIT_DIR` env var. – Lily Ballard Mar 17 '12 at 22:27
  • Yeah, so I'm not using the `--git-dir` or `--work-tree` options anymore, since there's a bug in my version and since I have discovered to that `unset GIT_DIR` works. – trusktr Mar 17 '12 at 23:29