3

I'm using the script .git/hooks/pre-commit to take snapshots of a MySQL database along with other project files. Here are the contents:

#!/bin/bash
mysqldump -u user -ppassword --skip-extended-insert dbname > /path/to/repo/dbname.sql
cd /mnt/hoste/Storage/Code/test-repo/
git add /path/to/repo/dbname.sql

If I run:

git commit -am "Message"

A new dump file is created, but then git tells me:

nothing to commit (working directory clean)

Then, if I run the identical commit command again, it works:

1 file changed, 1 insertion(+), 1 deletion(-)

Then, if I run the identical command again, back to "nothing to commit". This pattern continues ad infinitum - works, doesn't work, works, doesn't work. It's not based on time (I've tried commit immediately, and waiting 10 minutes). Mysqldump is certainly updating the .sql file (it date stamps them with hh:mm:ss format near the end of the file).

If I take the script, and run it line by line at the command line (including first cd'ing to the hooks directory to fully simulate running the script), there is a new commit every time. If I put it in an executable file in hooks, or in repo root, and execute it from command line, and then run the commit command, it works every time. It only doesn't work every other time, and then only when it's run from within pre-commit.

What could be causing this weird behaviour?

Duncan Marshall
  • 530
  • 1
  • 6
  • 15
  • I'm fairly sure it's generated afterwards - I have echoes, and other git statuses in the script for test purposes and the all happen before the built in status message. Also the number of commits isn't being incremented on the non-working attempts. – Duncan Marshall Aug 24 '14 at 07:53

2 Answers2

2

In a hook, make sure to always specify the git_dir and work_tree:

git --git-dir=/path/to/your/repo/.git --work-tree=/path/to/your/repo add -- yourFile

By changing folder in a hook, you are not changing what was the current git repo. If that repo is supposed to change, it is best to reference it explicitly with the --git-dir option.

VonC
  • 1,262,500
  • 529
  • 4,410
  • 5,250
  • I added that line to the top of my pre-commit script, and the behaviour is unchanged. To be clear, everything is in the same repo; I'm not attempting to save the mysqldumps in their own repo. – Duncan Marshall Aug 24 '14 at 06:49
  • 1
    @DuncanMarshall not on the top, in the git add line. – VonC Aug 24 '14 at 06:49
  • Oh yeah, I see. But still though, no change. – Duncan Marshall Aug 24 '14 at 07:00
  • 1
    @DuncanMarshall did you specified the path of the `.git` folder within the repo you want for `git-dir`? It is easy to miss the final `.git`. Make sure that path does exist (no typo). What version of git are you using? – VonC Aug 24 '14 at 07:01
  • yes, here is the actual line I'm using: git --git-dir=/mnt/hoste/Storage/Code/test-repo/.git --work-tree=/mnt/hoste/Storage/Code/test-repo/ add -- wptestsite.sql – Duncan Marshall Aug 24 '14 at 07:03
  • 1
    @DuncanMarshall and if you ware to manually go to that repo, would that file be added (meaning, was it perhaps already added in that repo with your previous tests?) – VonC Aug 24 '14 at 07:05
  • I'm not sure I understand your question - the file is modified and added by pre-commit every time it's run, it's just that it is only recognized as having been changed every second time I run the commit command. – Duncan Marshall Aug 24 '14 at 07:08
  • 1
    @DuncanMarshall is it possible this is some kind of synchronization issue (git doesn't yet recognize the modified file). Could you add a sleep for half a second just before the git add? (`sleep 0.5`, http://serverfault.com/a/469259/783) – VonC Aug 24 '14 at 07:12
  • Yeah, thought it was that at first. Added large amounts of sleep, to no avail. It's consistently a works/doesn't work pattern. Also it works 100% of the time that I do this from a non-hook bash script that contains identical commands. I wonder if it has something to do with git not wanting to add files that hooks make, but then I don't know why it would ever work, rather than just 50% of the time. – Duncan Marshall Aug 24 '14 at 07:18
  • 1
    @DuncanMarshall what a `git status` would output in that hook? (especially in the 50% of the time where the `git add` doesn't work) – VonC Aug 24 '14 at 07:20
  • I put `git status` both at the top and bottom of the file. On the time it *didn't* work, the top status command produces `nothing to commit (working directory clean)`, and the bottom produces `modified: wptestsite.sql` but then the normal status message after that still claims the working directory is clean. On the time it *does* work, the _top and bottom_ status messages both say "modified: wptestsite.sql". – Duncan Marshall Aug 24 '14 at 07:28
  • 1
    @DuncanMarshall wait... the bottom message should always state that the file isn't just modified, but added to the index. It should differ from the first status (when the first one works, I mean) – VonC Aug 24 '14 at 07:30
  • In both instances - working and non-working - it says: `# Changes to be committed: # (use "git reset HEAD ..." to unstage) # # modified: wptestsite.sql ` It's just that on the non-working times it then claims there is nothing to commit. – Duncan Marshall Aug 24 '14 at 07:37
  • 1
    @DuncanMarshall so the `git add` *never works* (in the right order), since the `git status` *before* the `git add` already states "`change to be committed`". Can you try a `sleep 0.5` *after* the `git add` and before the second `git status`? – VonC Aug 24 '14 at 07:39
  • That last test already had `sleep 3.0` between `git add` and the last `git status`. Still off-on working pattern. – Duncan Marshall Aug 24 '14 at 07:43
  • 1
    @DuncanMarshall What Os version and git version are you using? – VonC Aug 24 '14 at 07:44
  • git version 1.7.10.4 on Debian 7 – Duncan Marshall Aug 24 '14 at 07:46
  • @DuncanMarshall any chance of trying the same, with a git a bit more recent? (git 2.1.0: http://superuser.com/a/683123/141) – VonC Aug 24 '14 at 07:48
  • Your link for updating to 2.1.0 yilded multiple errors. Thanks anyway, but I think I'm just going to quit trying, and use some other method of doing this. – Duncan Marshall Aug 24 '14 at 07:59
  • 1
    @DuncanMarshall I understand, but using a more recent version of git would be in general a good idea ;) – VonC Aug 24 '14 at 08:00
  • The version I'm running is the one installed by aptitude as of last night. – Duncan Marshall Aug 24 '14 at 08:02
  • 1
    @DuncanMarshall then a quick sompilation from the sources could help: https://www.digitalocean.com/community/tutorials/how-to-install-git-on-debian-7 – VonC Aug 24 '14 at 08:03
  • 1
    @DuncanMarshall I suppose it works better with a recent Git version, then? – VonC Aug 24 '14 at 13:53
  • I tried the DO method, it also failed. Rather than troubleshoot it in order to use pre-commit, I just wrote a bash script to do the same thing. It's not the best way, but can't throw any more hours at it. Thanks for trying though. – Duncan Marshall Aug 25 '14 at 07:17
1

What I observe is that the "pre-commit" hook occurs after git has "frozen" the list of files to be affected (i.e., chosen a content addressable name of the repository state), and it cannot be influenced to alter that; instead, the "git add" in the pre-commit hook is making changes to the index that will be in effect once the commit is finished, and thus the next "git commit" shows the result of the "git add" within the pre-commit git hook.

A more comprehensive discussion is here: Can one re-stage files in a pre-commit git hook?

In my attempts to do "git add" within my own pre-commit hook (I similarly wanted to automatically generate and "git add" some file(s) to my commit), I've tried various tricks with recursive calls to git-commit, but it all ends up being really ugly, and git making un-helpful complaints. I'm going to abandon my hooks/pre-commit attempts, and instead use a shell alias that does "stuff && git add things && git commit".