Monday, November 23, 2015

Using Git hooks together with JGit / Egit

Git hooks currently supported by JGit / EGit

Git currently supports 13 client-side hooks. Not all of them are supported by JGit / EGit. The following list outlines which client-side hooks have already been implemented in JGit: 
  • pre-commit
  • prepare-commit-msg
  • commit-msg
  • post-commit
  • post-rewrite
  • applypatch-msg
  • pre-applypatch
  • post-applypatch
  • pre-rebase
  • pre-push
  • post-checkout
  • post-merge
  • pre-auto-gc
As of JGit v4.2.0 support for hooks is only enabled when the JGit file system layer detects a POSIX or a Win32 + Cygwin file system.

Necessary prerequisites to use Git hooks when running under Windows

In order for the Git hooks to be called by JGit when running under Windows you have to do two things:
  1. Install Cygwin (do not forget to install the Git package)
  2. Add the Cygwin bin folder (e.g. cygwin64\system\bin) to the Windows PATH environment variable.
The next section outlines how the JGit file system layer actually checks on which file system it is running on. So in case if you have any problems when using with JGit and Git hooks I recommend reading on. 

Details about the JGit Filesystem layer

The JGit file system class hierachy is as follows:


            +----------------------+
            |abstract class        |
            |FS                    |
            +----------------------+
            |                      |
            |runHookIfPresent()    |
            |does not support hooks|
            +-----+------------+---+
                  ^            ^
                  |            |
                  |            |
                  |            |
+-----------------+----+    +--+---------------+
|class                 |    |class             |
|FS_Win32              |    |FS_POSIX          |
+----------------------+    +------------------+
|                      |    |                  |
|runHookIfPresent()    |    |runHookIfPresent()|
|does not support hooks|    |does support hooks|
+-----------------+----+    +------------------+
                  ^
                  |
                  +------+
                         |
               +---------+--------+
               |class             |
               |FS_Win32_Cygwin   |
               +------------------+
               |                  |
               |runHookIfPresent()|
               |does support hooks|
               +------------------+


The default implementation of runHookIfPresent(...) in FS does not support running hooks:

public ProcessResult runHookIfPresent(Repository repository,
        final String hookName,
        String[] args) throws JGitInternalException {
    return runHookIfPresent(repository, hookName, args, System.out, System.err,
            null);
}

And how does the FS layer decide if it's running on a Win32 or FS_Win32 + Cygwin file system? The presece of a Cygwin installation is determined by the isCygwin() function in the FS_Win32_Cygwin class:

/**
 * @return true if cygwin is found
 */
public static boolean isCygwin() {
    final String path = AccessController
            .doPrivileged(new PrivilegedAction() {
                public String run() {
                    return System.getProperty("java.library.path"); //$NON-NLS-1$
                }
            });
    if (path == null)
        return false;
    File found = FS.searchPath(path, "cygpath.exe"); //$NON-NLS-1$
    if (found != null)
        cygpath = found.getPath();
    return cygpath != null;
}

It simply checks if the Windows PATH variable contains the file cygpath.exe. (Reminder: The java.library.path is pre-populated with the PATH entries when running under Windows.)

1 comment:

  1. If you already have Git installed on your PC simply add the following to your PATH:

    C:\Program Files\Git\usr\bin\

    It already has "cygpath.exe" file int it.

    ReplyDelete