user5957283
user5957283

Reputation:

How to automatically update git hooks?

So, the only hook I use is the post-receive. When I edit this file on my client, I want it to automatically update when I push to the server.

I tried 3 things all of which did not work. In the post-receive hooks I

  1. symbolically linked to the file in the repo
  2. hard linked to the file in the repo
  3. finally, copied the file from the repo into the hooks directory.

So, I keep a copy of this file in my repository, but I want it to automatically deploy.

I think the main issue with the methods I try is that the file is being used when I try to update it, that is, it is acting upon itself.

Is there a defacto way to do this?

Upvotes: 2

Views: 5321

Answers (1)

VonC
VonC

Reputation: 1330012

One possibility would be for your post-receive hook to:

  • detect that the post-receive script is part of what is pushed.
    (See "git post-receive hook to check files": git diff --name-only $1..$2|grep post-receive)
  • make a copy in .git/hook/post-receive.new

Then you install a pre-receive hook which simply check for .git/hook/post-receive.new and rename it as .git/hook/post-receive.
(Meaning post-receive.new disappear, and the next pre-receive hook execution will do nothing)

That way, the hook does not update right away, but it will be updated at the next git push to that same repo.


Note: I thought about detecting and updating the post-receive file modification directly during the pre-receive hook execution, but, as explained by torek in "Git pre-receive hook to check config", this is not trivial:

A pre-receive or update hook is called after the new objects (commits, annotated tag objects, trees, and blobs) have been loaded into the repository, but before the references (branch names, tag names, etc) have been changed.

You would need, for each ref pushed, to diff and check for the presence and content of that file.
It is not impossible, as seen in this php script:

function get_changed_files($base, $commit) {
  list($code, $stdout, $stderr) = git('diff', '--numstat', '--name-only', '--diff-filter=ACMRTUXB', '--ignore-submodules', "{$base}..{$commit}");
  ...
  return explode("\n", $stdout);
}
function get_new_file($filename, $commit) {
  list($code, $stdout, $stderr) = git('show', "{$commit}:{$filename}");
  ...
  return $stdout;
}
...
$line = file_get_contents('php://stdin');
list($base, $commit, $ref) = explode(" ", trim($line));
if ($base == "0000000000000000000000000000000000000000") {
  verbose("Initial push received. Expecting everything to be fine");
  exit;
}
$modified = get_changed_files($base, $commit);
$result = true;
foreach ($modified as $fname) {
  // if fname equals post-receive
  $contents = get_new_file($fname, $commit);
  // copy it to .git/hooks/post-receive
}

Having a two-step process is easier.

Upvotes: 3

Related Questions