How do I hook a git pull on the remote?

2020-05-27 04:02发布

问题:

Is there a way to hook when a git pull happens on the remote (similar to a pre-receive or post-receive). Basically I'd like to be able to cause the remote to commit whatever it has when there is a pull.

In my situation, whatever is live on the remote is an authoritative source which may get modified without a git commit. I want to make sure when I pull I'm always able to get the latest of whatever is live.

回答1:

First, to answer your actual question: there are no hooks invoked on the remote side when someone fetches. (When someone pulls, all the remote knows is that they fetched from it - it doesn't know whether they ran git pull, git fetch, git remote update...)

As for your actual situation: I agree with Magnus that it'd be best to simply have commits take place after edits, or failing that, have some sort of periodic task (cronjob?) that checks for modifications and commits if it finds any. If you don't like either of those choices, you're left with streamlining things so that it's quick and easy for you to trigger a commit in the remote repository just before pulling.

Also, I'd suggest not regarding a repository with a work tree as your canonical repository. It's asking for trouble if you ever need to push to it. Instead, you could have a bare canonical repository which your live repository pushes to after committing, and install a post-receive hook in that bare repository to update the live repository when necessary.



回答2:

Unfortunately git does not natively supply hooks for this, as it is a perfect use-case to want to check something before allowing a pull/fetch.

I don't know if your 'remote' is on a local machine, but if it isn't, have a look at gitolite which has hooks that are meant exactly for this:

From the v2 gitolite docs:

"gl-pre-git" hook

Although git has lots of nice hooks you can tap into, they all run only on a push. There's nothing that runs on a fetch or a clone, and there's no way to run something before git-receive-pack or git-upload-pack, (as the case may be) are invoked.

That's what the gl-pre-git hook is for. If an executable hook called gl-pre-git is present, it will be invoked with the current directory set to repo.git, and with a single argument which will be either R or W depending on what the client is trying to do.

For v3 gitolite, here are the docs about triggers. The documentation is a bit cryptic, but here is how it works:

  1. in ~/.gitolite.rc add (on the global scope):

    PRE_GIT => [ '<pre_git_trigger_script_name>' ]

  2. in the same file look at the line allowing to set LOCAL_CODE and set it to where ever you like

  3. In the directory that you set for LOCAL_CODE, create a subdirectory called 'triggers' and create a script called <pre_git_trigger_script_name> with whatever you want to do at that point... (make sure do to: chmod +x <pre_git_trigger_script_name>

  4. run gitolite setup

  5. test && have a good day

update: Actually using gitolite, I think you could have the pre-git trigger do something like pushing to an unexisting branch and then hook to pre-receive in your non-bare repository to reject the push, but to do git add --all . && git commit -m"autocommit" && push gitolite in the process. This is handy when you don't want to allow the gitolite hosting user privileges to run commands directly in your non-bare repository.



回答3:

I have no direct experience with git hooks, and this page may help, but it doesn't look like you're going to be able to do it.

The easier (and better IMO) solution would be to use a repo other than the production environment as the authoritative source. Can you do this? A production environment is very rarely used as the authoritative source because latest and most stable are two very different things...

FYI, I only ever perform a git pull or git status when in a production environment. Any changes are made on my local repo, tested, committed, pushed to github, then pulled down to the production environment.

UPDATE
I should point out that one of the great strengths and features of git is that it is a distributed source control system. As such, there isn't really any such thing as an authoritative source.



回答4:

I think you can't do this with hooks, for what I understand reading the hooks' doc there's no hook that fits into your requirement.

If I need something like what you want I'd create a script on 'remote' that runs every hour and checks if any file was changes (git status) and commit all (git commit -a -m "Auto commit").



回答5:

It's not something I've ever done before, but you can run bash scripts from inside php:

http://www.devx.com/opensource/Article/40785
http://us2.php.net/function.exec

Which should allow you to commit and push a set of changes via a PHP script. Chuck an interface over it or integrate it into your current editing process and you should be good to go.



回答6:

Who/what is editing this file? If it's something being changed when someone changes something on a site, that must be triggered by something, which means you can automate this. When this something happens and the file is saved, there you should trigger the commit. The commit has to be done sometime and it might as well be at that time.