【问题标题】:How to add a file to the index in a git pre-commit hook如何在 git pre-commit 挂钩中将文件添加到索引
【发布时间】:2012-03-15 06:37:09
【问题描述】:

我四处寻找重复的内容,虽然其中一些有相似的标题,但我没有发现任何人和我有同样的问题,所以就这样吧。

我编写了一个在pre-commit 上运行的脚本,并使用git status --porcelain 的输出来编译我的项目中已更改的任何LESS 文件。这部分工作正常。但我希望 .css 文件包含在当前提交中。所以除了运行编译器之外,我的脚本还运行git add <filename>。这就是事情变得棘手的地方。

文件添加到索引中,但它不是当前提交的索引。因此,如果我修改style.less,并运行git commit -a(或手动git add style.less),编译器应该生成style.cssstyle.min.css 并将它们添加到当前提交中。但是我注意到的行为只是 style.less 被提交,尽管两个 .css 文件被添加到下一次提交的索引中。

所以我的问题是:有没有办法在预提交挂钩中将文件添加到提交中,以便它们对该提交生效?请注意,在运行预提交挂钩之前,这两个 .css 文件没有被修改,所以我不能在此之前添加它们。我也知道我可以以非零状态退出钩子,因此提交被取消但文件被添加,但我希望避免这种情况。有更好的想法吗?

【问题讨论】:

    标签: git githooks


    【解决方案1】:

    我无法重现您的问题。我最初的猜测是 GIT_INDEX_FILE 环境变量被您的 pre-commit 钩子取消设置。但是,当我尝试从 pre-commit 取消设置 GIT_INDEX_FILE 时,我遇到了另一个问题(Git 抱怨 .git/index 被锁定)。

    这是一个示例脚本,它显示 Git 按您的预期运行,并且肯定有其他问题。此脚本初始化一个新的测试存储库,创建一个 pre-commit 钩子来模拟您的钩子所做的事情,并进行一些测试提交:

    #!/bin/sh
    
    # initialize the test repository
    rm -rf testrepo
    git init testrepo
    cd testrepo
    
    # create the pre-commit hook
    cat <<\EOF >.git/hooks/pre-commit
    #!/bin/sh
    git status --porcelain | while IFS= read -r line; do
        # todo: handle renames and deletions of a *.less file
        f=${line#???}
        case ${f} in
            *.less)
                fb=${f%.less}
                echo bar >>"${fb}".css
                echo baz >>"${fb}".min.css
                git add "${fb}".css "${fb}".min.css
                ;;
        esac
    done
    EOF
    chmod +x .git/hooks/pre-commit
    
    # create foo.less, commit it
    echo foo >foo.less
    git add foo.less
    git commit -m "add foo.less"
    
    # modify foo.less, commit it
    echo foo2 >>foo.less
    git commit -a -m "modify foo.less"
    

    如果您在测试存储库中运行 git log -p 并查看生成的提交,您将看到 foo.cssfoo.min.cssfoo.less 被修改时被修改。

    这就是为什么我认为您的问题是由更改/取消设置 GIT_INDEX_FILE 环境变量引起的:

    git commit -a 运行时,Git 会创建一个临时索引文件并使用它而不是默认的.git/index 来创建提交。为了让git add 之类的操作在pre-commit 钩子中工作,Git 将GIT_INDEX_FILE 环境变量设置为它在运行pre-commit 之前创建的临时索引的名称。如果您的钩子取消设置GIT_INDEX_FILE,或将其设置为.git/index,那么您钩子内的所有 Git 操作都将尝试修改原始索引,而不是用于生成提交的临时索引。

    但是,临时索引文件也充当了对原始索引文件的锁定。如果一个钩子试图修改原始索引,而临时索引存在,那么 Git 将中止并报错。

    【讨论】:

    • 我运行了您的脚本,它按预期工作,与我的真实存储库的实际行为相反。稍后我会对此进行更多研究,如果我弄清楚了什么,我会回复你。谢谢!
    • 因为努力而给了你赏金,尽管我仍然无法弄清楚发生了什么。再次感谢!
    【解决方案2】:

    在我看来,您可以将 git 属性 'clean' 作为更新生成文件的脚本。通常,该挂钩可以运行脚本来整理您的源代码,但我认为它可以用于“清理”您生成的输出。 当您执行“git add”时会触发此属性,您可以让脚本在生成的文件上执行另一个“git add”。

    【讨论】:

    • 您能详细说明一下吗?我做了一些谷歌搜索,发现了一些关于 Git 属性的信息,但没有关于如何将脚本附加到它们或如何布置 add 属性的信息。
    【解决方案3】:

    您可以利用修改最后一次提交的机会。只是一个想法。

    【讨论】:

    • 我确实考虑过这个选项,但我希望避免它。它涉及运行提交,运行钩子,然后让原始提交完成,然后运行第二次提交(除非我遗漏了什么),这看起来手动执行很复杂,而使用挂钩自动执行则有点荒谬。跨度>
    • 虽然通过钩子自动运行时,它会完美地完成这项工作。
    【解决方案4】:

    您首先为什么要这样做?您正试图将生成的文件包含到版本控制中,这通常不是一个好主意。如果您需要 style.min.css 在结帐时出现,为什么不能在结帐后在构建步骤中生成它?

    【讨论】:

    • 因为 CSS 文件不是二进制文件,它们只是静态文本文件。生成的文件没有放在版本控制中,因为它们通常会导致合并冲突,而您实际上并没有解决它们的好方法(二进制文件),但对于 CSS 文件,您很少遇到这个问题。我不想在我们的网络服务器上安装 LESS 编译器来完成合并/更新后的工作。然而,尽管如此,它确实证明是一种更简单的方法来完成我想要做的事情,尽管它并不理想。
    • 为什么这是公认的答案?这根本解决不了问题。
    • 我猜他接受了我的“你做错了”的非回答,因为在这种情况下它解决了他的问题(可以说没有回答他的问题)。如果他不首先检查 LESS 文件,“我如何将它们滑入提交”的问题就会消失。
    猜你喜欢
    • 2012-01-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-02-15
    • 2011-06-17
    • 2020-06-24
    • 2023-04-11
    相关资源
    最近更新 更多