2

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?

1 Answers1

3

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.

Community
  • 1
  • 1
VonC
  • 1,262,500
  • 529
  • 4,410
  • 5,250
  • @cadegalt no need for internals: you have the description of those hooks at https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks#Server-Side-Hooks – VonC Mar 01 '16 at 21:59
  • @cadegalt sure, that could work too, and bypass entirely git. If you are the only one pushing to the git repo hosting server, this won't present any risk. – VonC Mar 01 '16 at 22:01
  • @cadegalt no it does not. ssh or https. Not scp (https://git-scm.com/book/ch4-1.html#The-SSH-Protocol) – VonC Mar 02 '16 at 22:18
  • It seems many people want to do this, adding this as a feature in git itself would probably be the most efficient way to do this. –  Mar 07 '16 at 20:31