【问题标题】:GitHub for Windows Pre-Commit HookGitHub for Windows 预提交挂钩
【发布时间】:2012-09-13 15:50:35
【问题描述】:

我们有一个开发团队,他们使用 50/50 的 GitHub for windows 和 Bash shell 进行 Git 管理。

我们已经实现了预提交挂钩(旨在运行单元测试并在测试失败时使提交失败)。作为一个简化版本,我附上了一个简化版本,它在下面演示了我们的问题。

#!/bin/sh
exit 1

如果我们尝试从 bash shell 提交,预期的提交会失败。但是,如果我们从 GitHub for windows 应用程序执行相同的提交,它会成功提交到本地 repo。

那么有谁知道我们如何从 GitHub 应用程序中获得相同的功能?不幸的是,我们无法将用户从应用程序中移出,它现在是一个明显的漏洞。

感谢您的帮助。

【问题讨论】:

  • 虽然我喜欢 GitHub for Windows 的想法,但我个人发现它很慢,在某些情况下甚至会出现错误。到目前为止,我不会向生产团队推荐它。
  • 您是否尝试过联系 github for windows 团队寻求支持?您可以将它们邮寄到 support@github.com
  • @nightcracker - 较新的版本似乎更稳定,但由于它易于下载和安装,我们需要填补这个漏洞。
  • @ksol - 谢谢,我们确实给了他们一个机会,但还没有收到任何回复,所以向社区开放。

标签: git github


【解决方案1】:

很抱歉带来坏消息,但 GitHub for Windows 不支持预提交挂钩,因为它使用 libgit2 进行提交。

【讨论】:

  • 你说的很对,我们从 github 得到了这样的回应:不幸的是 GitHub for Windows 不支持 pre-commit hooks,因为我们实际上并没有使用 git.exe 来提交(我们使用一个项目称为 libgit2,它比 git.exe 快得多,但不支持某些功能)。如果你依赖这些,你可能不得不使用 Git Shell 来进行提交。
  • 很确定我写了那个回复:)
  • 是不是只有Github for Windows不能执行的pre-commit hooks?
  • 虽然某些其他钩子当前可能会执行,但它们将来可能不会执行
【解决方案2】:

使用 Git shell 你可以有提交钩子。我得到了一些使用 PowerShell 的提交钩子。我发现了一个 powerShell 脚本,它执行 lint,我扩展它以运行 phpunit 和 phpcs(路径是硬编码的,所以你需要调整):

预提交文件:

#!/bin/sh
echo 
exec powershell.exe -ExecutionPolicy RemoteSigned -File '.\.git\hooks\pre-commit-hook.ps1'
exit

pre-commit.ps1 文件:

###############################################################################
#
# PHP Syntax Check for Git pre-commit hook for Windows PowerShell
#
# Author: Vojtech Kusy <wojtha@gmail.com>
# Author: Chuck "MANCHUCK" Reeves <chuck@manchuck.com>
#
###############################################################################

### INSTRUCTIONS ###

# Place the code to file "pre-commit" (no extension) and add it to the one of 
# the following locations:
# 1) Repository hooks folder - C:\Path\To\Repository\.git\hooks
# 2) User profile template   - C:\Users\<USER>\.git\templates\hooks 
# 3) Global shared templates - C:\Program Files (x86)\Git\share\git-core\templates\hooks
# 
# The hooks from user profile or from shared templates are copied from there
# each time you create or clone new repository.

### SETTINGS ###

# Path to the php.exe
$php_exe = "C:\php\php.exe";

# Path to the phpcs
$php_cs = "C:\Includes\PEAR\phpcs.bat";

# Path to the phpunit
$php_unit = "C:\Includes\PEAR\phpunit.bat";

# Path to the phpunit bootstrap file
$bootstrap = "tests\bootstrap.php";

# Flag, if set to 1 require test file to exist, set to 0 to disable
$requireTest = 1;

# Extensions of the PHP files 
$php_ext = "php|phtml"

# Flag, if set to 1 git will unstage all files with errors, set to 0 to disable
$unstage_on_error = 0;

### FUNCTIONS ###

function php_syntax_check {
    param([string]$php_bin, [string]$extensions, [int]$reset) 

    $err_counter = 0;

    write-host "Pre-commit PHP syntax check:" -foregroundcolor "white" -backgroundcolor "black"

    git diff-index --name-only --cached HEAD -- | foreach {             
        if ($_ -match ".*\.($extensions)$") {
            $file = $matches[0];
            $errors = & $php_bin -l $file   
            $testFileExists = (Test-Path $file -PathType Leaf)
            write-host $file ": "  -foregroundcolor "gray"  -backgroundcolor "black" -NoNewline
            if ($testFileExists) {
                if ($errors -match "No syntax errors detected in $file") {
                    write-host "OK!" -foregroundcolor "green" -backgroundcolor "black"
                }
                else {              
                    write-host "ERROR! " $errors -foregroundcolor "red" -backgroundcolor "black"
                    if ($reset) {
                        git reset -q HEAD $file
                        write-host "Unstaging ..." -foregroundcolor "magenta" -backgroundcolor "black"
                    }
                    $err_counter++
                }
            } else {
                write-host "OK! (file deleted)" -foregroundcolor "green" -backgroundcolor "black"
            }
        }
    }

    if ($err_counter -gt 0) {
        write-host "Some File(s) have syntax errors. Please fix then commit" -foregroundcolor "red" -backgroundcolor "black"
        exit 1
    }    
}

function php_cs_check {
    param([string]$php_cs, [string]$extensions, [int]$reset) 

    $err_counter = 0;

    write-host "Pre-commit PHP codesniffer check:" -foregroundcolor "white" -backgroundcolor "black"

    git diff-index --name-only --cached HEAD -- | foreach {     
        if ($_ -match ".*\.($extensions)$") {
            $file = $matches[0];

            write-host $file ": "  -foregroundcolor "gray"  -backgroundcolor "black" -NoNewline
            if ($file -match "tests\/") {
                write-host "PASSED! (test file)" -foregroundcolor "green" -backgroundcolor "black"
            } else {
                $errors = & $php_cs --standard=Zend $file           

                if ($LastExitCode) {
                    write-host "FAILED! (contains errors)"  -foregroundcolor "red" -backgroundcolor "black"
                    if ($reset) {
                        git reset -q HEAD $file
                        write-host "Unstaging ..." -foregroundcolor "magenta" -backgroundcolor "black"
                    }
                    $err_counter++
                } else {                
                    write-host "PASSED!" -foregroundcolor "green" -backgroundcolor "black"
                }
            }
        }
    }

    if ($err_counter -gt 0) {
        write-host "Some File(s) are not following proper codeing standards. Please fix then commit" -foregroundcolor "red" -backgroundcolor "black"
        exit 1
    }    
}

function php_unit_check {
    param([string]$php_unit, [string]$bootstrap, [string]$extensions, [int]$reset, [int]$requireTest) 

    $err_counter = 0;

    write-host "Pre-commit PHP unit check:" -foregroundcolor "white" -backgroundcolor "black"

    git diff-index --name-only --cached HEAD -- | foreach {     
        if ($_ -match ".*\.($extensions)$") {
            $file = $matches[0];

            write-host $file ": "  -foregroundcolor "gray"  -backgroundcolor "black" -NoNewline
            if ($file -match "tests\/") {
                write-host "SKIPPED! (test file)" -foregroundcolor "green" -backgroundcolor "black"
            } elseif ($file -match ".*Bootstrap.php") {
                write-host "SKIPPED! (bootstrap file)" -foregroundcolor "green" -backgroundcolor "black"
            } elseif ($file -match "([application|library\\NDX].*)(.($extensions))$") {

                $testFile = 'tests/' + $matches[1] + "Test.php";
                $testFileExists = (Test-Path $testFile -PathType Leaf)

                if ($testFileExists) {
                    $errors = & $php_unit --bootstrap $bootstrap $testFile
                    if ($LastExitCode) {
                        write-host "FAILED! (" $testFile ")"  -foregroundcolor "red" -backgroundcolor "black"
                        if ($reset) {
                            git reset -q HEAD $file
                            write-host "Unstaging ..." -foregroundcolor "magenta" -backgroundcolor "black"
                        }
                        $err_counter++
                    } else {
                        write-host "PASSED!" -foregroundcolor "green" -backgroundcolor "black"

                    }
                } elseif($requireTest) {
                    write-host "FAILED! Test file Not found: (" $testFile ")"  -foregroundcolor "red" -backgroundcolor "black"
                    if ($reset) {
                        git reset -q HEAD $file
                        write-host "Unstaging ..." -foregroundcolor "magenta" -backgroundcolor "black"
                    }
                    $err_counter++
                } else {
                    write-host "PASSED! (Test file not found and not required)" -foregroundcolor "darkGreen" -backgroundcolor "black"
                }
            } else {
                write-host "IGNORED!" -foregroundcolor "darkGreen" -backgroundcolor "black"
            }
        }
    }

    if ($err_counter -gt 0) {
        write-host "Some File(s) failed unit testing. Please fix then commit" -foregroundcolor "red" -backgroundcolor "black"
        exit 1
    }    
}
### MAIN ###

php_syntax_check $php_exe "php|phtml" $unstage_on_error
write-host
php_cs_check $php_cs "php" $unstage_on_error
write-host
php_unit_check $php_unit $bootstrap "php" $unstage_on_error $requireTest

【讨论】:

    【解决方案3】:

    您可以考虑使用 Visual Studio(或您的构建器)预构建事件,但如果需要完全自动化,也有一个问题。 Here is an example use. 现在,该解决方案还需要路径上的git.exe,但用户不需要与其交互。如果比我聪明的人能解决文章中提到的反斜杠问题,那就太好了。

    【讨论】:

      【解决方案4】:

      添加一个答案作为当前选择的答案不再是这种情况。我能够编写一个预提交挂钩,它适用于 Windows 的 GitHub Desktop、Windows 的 SourceTree 和 Windows 的 Git Bash。

      我不确定这是否是 Windows 提交挂钩的硬性要求,但我包含了对 sh.exe 的准确引用,如下所示:

      #!C:/Program\ Files/Git/usr/bin/sh.exe
      

      它运行良好!

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-06-02
        • 2013-02-07
        • 2014-01-03
        • 2018-02-28
        • 2015-03-09
        • 1970-01-01
        • 2014-07-26
        • 2013-03-20
        相关资源
        最近更新 更多