【问题标题】:git stash in pre-commit hook fails on first commit预提交挂钩中的 git stash 在第一次提交时失败
【发布时间】:2012-07-11 13:24:39
【问题描述】:

我正在开发一个 pre-commit 挂钩,它使用 YUI Compressor 来缩小任何已准备提交的 CSS 和 JavaScript 文件。文件缩小后,缩小的版本会自动暂存以进行提交。我读过自动将机器生成的文件添加到提交中通常不是一个好主意,但我认为在这种情况下它是可以的。这是它的样子:

git status 的输出:

# On branch master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#   modified:   _site-wide.css
#
# Changes not staged for commit:
#   (use "git add <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
#   modified:   _subpage.css
#

git commit -m "Updated site-wide styling" 的输出:

1 CSS file was minified and added to the Git repository
0 JavaScript files were minified and added to the Git repository
[master 41f1815] Updated site-wide styling
 2 files changed, 2 insertions(+), 2 deletions(-)

这里发生的是 pre-commit 钩子使用 YUI Compressor 压缩_site-wide.css,将结果输出到site-wide.css(没有前导下划线)。然后它上演site-wide.css 提交。预提交钩子跳过了_subpage.css,因为尽管它已被修改,但它并未暂存以进行提交。

由于磁盘上的 CSS 和 JavaScript 文件可能与暂存以提交的 CSS 和 JavaScript 文件不同,我在压缩文件之前运行 git stash -q --keep-index,然后在之后运行 git stash pop -q。这个 pre-commit 钩子在已经有提交的存储库上工作正常,但是如果我在第一次提交之前将 pre-commit 钩子放在适当的位置,我会得到:

git status的输出:

# On branch master
#
# Initial commit
#
# Changes to be committed:
#   (use "git rm --cached <file>..." to unstage)
#
#   new file:   _site-wide.css
#   new file:   _subpage.css
#

git commit -m "Initial commit" 的输出:

fatal: bad revision 'HEAD'
fatal: bad revision 'HEAD'
fatal: Needed a single revision
You do not have the initial commit yet
2 CSS files were minified and added to the Git repository
0 JavaScript files were minified and added to the Git repository
No stash found.

git status的输出:

# On branch master
#
# Initial commit
#
# Changes to be committed:
#   (use "git rm --cached <file>..." to unstage)
#
#   new file:   _site-wide.css
#   new file:   _subpage.css
#   new file:   site-wide.css
#   new file:   subpage.css
#

我现在将粘贴预提交挂钩的代码。请记住,为了灵活,我编写了这个脚本,以便它可以在任何 CakePHP 项目中运行,而不仅仅是具有 Git 存储库的项目。我还编写了它,以便您可以强制它缩小所有 CSS 和 JavaScript 文件,而不仅仅是暂存提交的文件。这是通过运行.git/hooks/pre-commit force 来完成的。代码如下:

#!/bin/bash

css_files_to_ignore=(
    #"_do_not_minify.css"
)

js_files_to_ignore=(
    #"_do_not_minify.js"
)

if git rev-parse --git-dir > /dev/null 2>&1; then
    git_repository=true
    base_folder="$(git rev-parse --show-toplevel)/app/webroot"

    if [ "$1" == "force" ]; then
        process_unstaged_files=true
    else
        process_unstaged_files=false
    fi
else
    git_repository=false
    base_folder="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/webroot"
fi

if [ -f /Applications/yuicompressor.jar ]; then
    # Mac

    yuicompressor_path=/Applications/yuicompressor.jar
else
    # Linux

    yuicompressor_path=$(command -v yui-compressor)
fi

function process_assets()
{
    extension=$1
    files_minified=0

    for infile in $(echo "$base_folder/$extension/*.$extension")
    do
        # Only process files.

        [[ -f $infile ]] || continue

        filename=${infile##*/}

        # If the filename starts with an underscore, that means that the file is
        # eligible for minification.

        [[ ${filename:0:1} == "_" ]] || continue

        ignore_this_file=false

        files_to_ignore=$extension"_files_to_ignore"

        for i in $(eval echo \${$files_to_ignore[@]})
        do
            if [[ $i == $filename ]]; then
                ignore_this_file=true
                break
            fi
        done

        if [ $git_repository == true ] && [ $process_unstaged_files == false ] && git diff --quiet --cached $infile; then
            # This file is NOT staged for commit.

            ignore_this_file=true
        fi

        if [ $ignore_this_file == false ]; then
            minified_file="$base_folder/$extension/${filename:1}"

            if [ ! -f "$minified_file" ] || test $infile -nt $minified_file; then
                $yuicompressor_command "$infile" -o "$minified_file"

                if [ $git_repository == true ] && [ $process_unstaged_files == false ]; then
                    git add "$minified_file"
                fi

                ((files_minified++))
            fi
        fi
    done

    # Output a summary of what was done.

    if [ $extension == "css" ]; then
        file_type="CSS"
    else
        file_type="JavaScript"
    fi

    echo -n "$files_minified $file_type file"

    if [ $files_minified -eq 1 ]; then
        echo -n " was"
    else
        echo -n "s were"
    fi

    echo -n " minified"

    if [ $git_repository == true ] && [ $process_unstaged_files == false ]; then
        echo " and added to the Git repository"
    else
        echo
    fi
}

if [ -f "$yuicompressor_path" ]; then
    if [ ${yuicompressor_path: -4} == ".jar" ]; then
        yuicompressor_command="java -jar $yuicompressor_path"
    else
        yuicompressor_command=$yuicompressor_path
    fi

    if [ $git_repository == true ] && [ $process_unstaged_files == false ] && ! git diff --quiet --cached; then
        # The staging area is what should be processed rather than what is currently
        # on disk.

        git stash -q --keep-index

        stashed=true
    else
        stashed=false
    fi

    process_assets css
    process_assets js

    if [ $stashed == true ]; then
        git stash pop -q
    fi
else
    echo "YUI Compressor was not found. Aborting."
    exit 1
fi

我怎样才能做到这一点?任何帮助将不胜感激。

【问题讨论】:

  • 可以贴一下钩子代码吗?似乎它试图检查尚不存在的HEAD 修订版,这就是您收到错误的原因。您可以尝试添加 try/catch。

标签: git githooks pre-commit-hook git-stash


【解决方案1】:

我得出的结论是没有解决方案,因为某些 Git 命令在没有 HEAD 时根本无法工作。另外,在考虑了更多之后,我决定无论如何这都是一种边缘情况,至少对我来说是这样,因为我的第一次提交通常是一些基本的东西,比如我使用的框架的文件。所以我可以在第一次提交后实现钩子。

我感谢 Hassek 的时间以及阅读本文的其他人的时间。谢谢!

【讨论】:

  • 如果您仍然对此感兴趣,您正在寻找“干净的过滤器”,以便在工作树内容进入 repo 的过程中对其进行清理。
【解决方案2】:

使用 Git 2.22(2019 年第二季度,7 年后),有一个,git stash as rewritten in C

commit 1ac528c(2019 年 2 月 25 日)Paul-Sebastian Ungureanu (weekly-digest[bot])

stash:使push -q安静

此提交的行为发生了变化。
当没有初始提交时,stash 的 shell 版本仍然会显示 一条消息。
如果指定了--quiet-q,则此提交使push 不显示任何消息。

所以你不应该看到带有git stash -q &lt;command&gt;的“You do not have the initial commit yet”,从Git 2.22的新的用C重写的stash命令开始。

【讨论】:

    猜你喜欢
    • 2019-06-02
    • 2015-07-08
    • 1970-01-01
    • 2019-07-07
    • 2020-02-06
    • 1970-01-01
    • 2013-08-26
    • 2021-09-10
    相关资源
    最近更新 更多