User Tools

Site Tools


git_hooks

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
git_hooks [2019/02/19 09:25]
rpjday [Default hook installation for a new repository]
git_hooks [2019/02/19 11:10]
rpjday [Default hook installation for a new repository]
Line 9: Line 9:
   * client-side   * client-side
   * server-side   * server-side
 +
 +Note that hooks can get their arguments from any combination of:
 +
 +  * the environment
 +  * command-line arguments
 +  * stdin
  
 ===== Default hook installation for a new repository ===== ===== Default hook installation for a new repository =====
Line 26: Line 32:
   * ''​update.sample*''​   * ''​update.sample*''​
  
-These are sample scripts supplied by Git that you can use as is, or customize to taste. In order to activate such scripts:+These are sample scripts supplied by Git that you can use as is, or customize to taste. In order to activate such scripts ​once they'​re copied to the new repository:
  
   * Make sure they are marked as executable.   * Make sure they are marked as executable.
-  * Remove the ''​.sample'' ​prefix.+  * Remove the ''​.sample'' ​suffix (exact spelling is important).
  
-===== Properties of hooks =====+===== Where hooks are effectively run =====
  
-  * They must be marked executable in order to be active. +From ''​man githooks''​:
-  * They normally live in ''​$GIT_DIR/​hooks''​, unless overridden via ''​core.hooksPath''​. +
-  * Running ''​git init''​ on an existing directory will copy in only new hooks; it will never overwrite existing hooks. +
-  * Hooks can get their arguments via the environment,​ command-line arguments, and stdin. +
- +
-===== Supporting code ===== +
- +
-==== run_commit_hook() ====+
  
 <​code>​ <​code>​
-int run_commit_hook(int editor_is_usedconst char *index_file,​ const char *name, ...) +Before Git invokes a hookit changes its working directory to 
-{ +either $GIT_DIR in a bare repository or the root of the working 
-        ​struct argv_array hook_env = ARGV_ARRAY_INIT;​ +tree in a non-bare repositoryAn exception are hooks triggered 
-        va_list args; +during a push (pre-receiveupdatepost-receivepost-update
-        int ret; +push-to-checkoutwhich are always executed in $GIT_DIR.
- +
-        argv_array_pushf(&​hook_env,​ "​GIT_INDEX_FILE=%s",​ index_file);​ +
- +
-        /* +
-         * Let the hook know that no editor will be launched+
-         */ +
-        if (!editor_is_used) +
-                argv_array_push(&​hook_env"​GIT_EDITOR=:"​);​ +
- +
-        va_start(argsname); +
-        ret = run_hook_ve(hook_env.argv,nameargs); +
-        ​va_end(args)+
-        argv_array_clear(&​hook_env);​ +
- +
-        return ret; +
-}+
 </​code>​ </​code>​
- +===== commit-related ​client-side hooks =====
-==== builtin/​commit.c ​==== +
- +
-<​code>​ +
-static int prepare_to_commit(const char *index_file,​ const char *prefix, +
-                             ​struct ​commit ​*current_head,​ +
-                             ​struct wt_status *s, +
-                             ​struct strbuf *author_ident) +
-+
-        struct stat statbuf; +
-        struct strbuf committer_ident = STRBUF_INIT;​ +
-        int commitable;​ +
-        struct strbuf sb = STRBUF_INIT;​ +
-        const char *hook_arg1 = NULL; +
-        const char *hook_arg2 = NULL; +
-        int clean_message_contents = (cleanup_mode != COMMIT_MSG_CLEANUP_NONE);​ +
-        int old_display_comment_prefix;​ +
- +
-        /* This checks and barfs if author is badly specified */ +
-        determine_author_info(author_ident);​ +
- +
-        if (!no_verify && run_commit_hook(use_editor,​ index_file, "pre-commit",​ NULL)) +
-                return 0; +
-                 +
-                ... snip ... +
-                 +
-        if (run_commit_hook(use_editor,​ index_file, "​prepare-commit-msg",​ +
-                            git_path_commit_editmsg(),​ hook_arg1, hook_arg2, NULL)) +
-                return 0; +
- +
-        if (use_editor) { +
-                struct argv_array env = ARGV_ARRAY_INIT;​ +
- +
-                argv_array_pushf(&​env,​ "​GIT_INDEX_FILE=%s",​ index_file);​ +
-                if (launch_editor(git_path_commit_editmsg(),​ NULL, env.argv)) { +
-                        fprintf(stderr,​ +
-                        _("​Please supply the message using either -m or -F option.\n"​));​ +
-                        exit(1); +
-                } +
-                argv_array_clear(&​env);​ +
-        } +
- +
-        if (!no_verify &&​ +
-            run_commit_hook(use_editor,​ index_file, "​commit-msg",​ git_path_commit_editmsg(),​ NULL)) { +
-                return 0; +
-        } +
- +
-        return 1; +
-}                 +
-</​code>​ +
- +
-<​code>​ +
-int cmd_commit(int argc, const char **argv, const char *prefix) +
-+
-        const char *argv_gc_auto[] = {"​gc",​ "​--auto",​ NULL}; +
-        static struct wt_status s; +
-        static struct option builtin_commit_options[] = { +
- +
-... snip ... +
- +
-        run_commit_hook(use_editor,​ get_index_file(),​ "​post-commit",​ NULL); +
-        if (amend && !no_post_rewrite) { +
-                commit_post_rewrite(current_head,​ &​oid);​ +
-        } +
-        if (!quiet) { +
-                unsigned int flags = 0; +
- +
-                if (!current_head) +
-                        flags |= SUMMARY_INITIAL_COMMIT;​ +
-                if (author_date_is_interesting()) +
-                        flags |= SUMMARY_SHOW_AUTHOR_DATE;​ +
-                print_commit_summary(prefix,​ &oid, flags); +
-        } +
- +
-        UNLEAK(err);​ +
-        UNLEAK(sb);​ +
-        return 0; +
-+
-</​code>​ +
- +
-===== The client-side hooks =====+
  
 ==== pre-commit ==== ==== pre-commit ====
  
-In a nutshell (from ''​man githooks''​):+From ''​man githooks'':​
  
 <​code>​ <​code>​
-This hook is invoked by git commit, and can be bypassed with+This hook is invoked by git commit(1), and can be bypassed with
 the --no-verify option. It takes no parameters, and is invoked the --no-verify option. It takes no parameters, and is invoked
 before obtaining the proposed commit log message and making a before obtaining the proposed commit log message and making a
Line 210: Line 113:
  
 # If there are whitespace errors, print the offending file names and fail. # If there are whitespace errors, print the offending file names and fail.
-</​code>​ 
- 
-Here's the money command: 
- 
-<​code>​ 
-exec git diff-index --check --cached $against -- 
 </​code>​ </​code>​
  
Line 346: Line 243:
 This hook is meant primarily for notification,​ and cannot affect This hook is meant primarily for notification,​ and cannot affect
 the outcome of git commit. the outcome of git commit.
 +</​code>​
 +
 +There is no sample script provided by Git; you're on your own here.
 +
 +===== Overriding the default hooks =====
 +
 +==== git init ====
 +
 +When initializing a new repository, the template content used for the new repository comes from one of (in order of precedence):​
 +
 +  * the ''​%%--%%template=<​template directory>''​ option
 +  * the value of the ''​$GIT_TEMPLATE_DIR''​ environment variable
 +  * the ''​init.templateDir''​ configuration option
 +  * the contents of ''/​usr/​share/​git-core/​templates/''​
 +
 +==== git clone ====
 +
 +When cloning a repository, the only way to override the installation of default hooks (and template content) is via the ''​%%--%%template=<​template directory>''​ command-line option.
 +==== During normal operation ====
 +
 +From ''​man git-config'':​
 +
 +<​code>​
 +core.hooksPath
 +    By default Git will look for your hooks in the
 +    $GIT_DIR/​hooks directory. Set this to different path, e.g.
 +    /​etc/​git/​hooks,​ and Git will try to find your hooks in that
 +    directory, e.g.  /​etc/​git/​hooks/​pre-receive instead of in
 +    $GIT_DIR/​hooks/​pre-receive.
 +
 +    The path can be either absolute or relative. A relative
 +    path is taken as relative to the directory where the hooks
 +    are run (see the "​DESCRIPTION"​ section of githooks(5)).
 +
 +    This configuration variable is useful in cases where you’d
 +    like to centrally configure your Git hooks instead of
 +    configuring them on a per-repository basis, or as a more
 +    flexible and centralized alternative to having an
 +    init.templateDir where you’ve changed default hooks.
 </​code>​ </​code>​
git_hooks.txt · Last modified: 2019/02/19 11:10 by rpjday