Reputation: 14693
How do I force git
to run a post-receive
hook on a server even if I don't have a new commit to push?
I use git to automatically deploy a website to a server. I have a bare repo in a protected area of the server and a post-receive
hook that checks out the contents and systematically copies over certain files into a public_html
folder. (Inspired by this tutorial)
I got tired of modifying the post-receive
hook manually on the server, so my post-receive
hook now actually copies over a new version of itself from the repo:
#!/bin/sh
rm -rf ~/../protected/*
GIT_WORK_TREE=~/../protected git checkout -f
# Rewrite over this file with any updates from the post-receive file
cp ~/../protected/post-receive hooks/post-receive
# Delete public_html
# Copy stuff public_html
The problem, of course, is that the new post-receive
hook never gets run. A seemingly simple solution would be merely to push again, but now everything is already up to date. This is annoying, because it requires me to fake a new commit every time I update the post-receive
hook. Is there a way to invoke the post-receive
hook without faking a commit or ssh
ing in?
git push
git push -f
Upvotes: 83
Views: 27572
Reputation: 60565
Post-receive is the wrong place for artificial command responses.
You want your server-side goodies in the pre-receive exit, dependent on the updated ref -- do e.g. git update-ref refs/commands/update-hooks @
on the server, then you can e.g. git push server +@:commands/update-hooks
, and in the server's pre-receive you can
while read old new ref; do case $ref in
commands/update-hooks)
maybe check the incoming commit for authorization
update hooks here
echo the results from the update
denypush=1
;;
refs/heads/master)
extreme vetting on master-branch updates here
;;
esac; done
((denypush)) && exit $denypush
Upvotes: 4
Reputation: 6460
If you want to avoid making a fake new commit, you can simply use
git commit --amend --no-edit
This will modify the last commit record and you will be able to use git push -f
(assuming from your answer that you're fine with the overwrite).
I use this command relatively often to fix something in the last commit before pushing, so I made an alias for it:
git config --global alias.amend 'commit --amend --no-edit'
Now I can use it directly for the use case as yours (git amend
), or
git amend -a
git amend -m 'better message'
Upvotes: 18
Reputation: 3752
I made a bash function to do this. It assumes that you have ssh access can ~/.ssh/config
set accordingly. The default remote is origin
kick-git() {
remote="${1:-origin}"
ssh $(echo $(git remote get-url "$remote")/hooks/post-receive | tr ':' ' ')
}
Source and run kick-git [remote]
Upvotes: 3
Reputation: 51
In my case i login into remote and run:
$ sh project.git/hooks/post-receive
works fine!
Upvotes: 5
Reputation: 21815
I tried empty commits and delete upload branch.
But what about a direct ssh command:
ssh your_host /path/to/your_repo/hooks/post-receive
Upvotes: 3
Reputation: 4760
I like Jamie Carl's suggestion but it doesn't work, and I got the error:
remote: error: By default, deleting the current branch is denied, because the next error: 'git clone' won't result in any file checked out, causing confusion.
In my case I'm testing post-receive hooks on my localhost against a bare repository. Warning/super important, run this command only on the remote
server location!
git update-ref -d refs/heads/develop
It'll delete the reference for the develop branch (you may also need to delete any of the files you deployed for that branch too), then you can go ahead and do the git push deploy_localtest develop
or whatever push command you want for that branch.
Upvotes: 1
Reputation: 5228
After the initial push replacing the script, you can do this :
git commit --allow-empty -m 'push to execute post-receive'
The --allow-empty
flag overrides git's default behavior of preventing you from making a commit when there are no changes.
Use an alias and make your life even easier
Add the following to ~/.gitconfig
[alias]
pushpr = "!f() { git push origin master;git commit --allow-empty -m 'push to execute post-receive';git push origin master; }; f"
Now Just do git pushpr
git pushpr
This will push any changes to master, which in your case will trigger your post receive replacement script, then it will push again (using the --allow-empty
flag) which will then execute your updated post-receive
script.
Upvotes: 72
Reputation: 1204
I know this probably going to be considered "dangerous" but I like to live on the edge.
I just delete the remote branch and then push it again. Make sure your local branch is up-to-date first to limit the chance of losing stuff.
So if I want to trigger post-receive, in my case to get the testing branch to provision, all I do is:
$ git push origin :testing
$ git push origin testing
Don't accept this as the answer though. It's more of a just FYI thing.
Upvotes: 25
Reputation: 87411
I'm afraid you have to ssh to the server and run the hook script manually. git push
doesn't make the server run the pre-push, pre-receive and post-receive hooks if there was nothing added (i.e. when git prints Everything up-to-date).
The rest of the answer is about version-tracking the post-receive hook, so you can modify it without sshing to the server.
Add a shell script named do-post-receive
to the local repository:
$ ls -ld .git
$ echo 'echo "Hello, World!"' >do-post-receive
$ git add do-post-receive
$ git commit do-post-receive -m 'added do-post-receive'
Replace your hooks/post-receive
hook on the server with:
#! /bin/sh
while read OLDID NEWID BRANCH; do
test "$BRANCH" = refs/heads/master && eval "$(git show master:do-post-receive)"
done
(Make sure to chmod 755 hooks/post-receive
on the server.)
Push your changes from the local repository to the server, and watch your do-post-receive
code run:
$ git push origin master
...
remote: Hello, World!
...
Upvotes: 13