81

我想根据在该提交中修改的文件,使用 Git 中的提交前或提交后挂钩将自动生成的文件添加到同一个提交中。我该怎么办?

我已经尝试将此作为预提交挂钩,但没有运气:

#!/bin/sh
files=`git diff --cached --name-status`
re="<files of importance>"
if [[ $files =~ $re ]]
then
  echo "Creating files"
  exec bundle exec create_my_files
  exec git add my_files
  exec git commit --amend -C HEAD
fi

这成功地将它们添加到存储库中,但不会将它们添加到提交中。我还尝试在提交后挂钩中使用最后两个 exec 行以及提交前检查,但也没有好处。

4

10 回答 10

70

由于 git add 在预提交中也不适用于我,因此我遵循了马克的想法,即使用 .commit 文件并将过程分为提交前和提交后。

这是一些应该易于理解的代码

在预提交中:

  • 触摸一个文件 .commit 什么的。(请务必将此添加到 .gitignore)
#!/bin/sh 
echo 
touch .commit 
exit

在提交后:

如果 .commit 存在,您知道提交刚刚发生,但后提交尚未运行。因此,您可以在这里进行代码生成。此外,测试 .commit 是否存在:

  • 添加文件
  • commit --amend -C HEAD --no-verify (避免循环)
  • 删除 .commit 文件
#!/bin/sh
echo
if [ -e .commit ]
    then
    rm .commit
    git add yourfile
    git commit --amend -C HEAD --no-verify
fi
exit

希望这能让对 bash 知识很少的人更容易遵循马克的想法。

于 2012-10-09T14:44:03.713 回答
36

使用预提交钩子可以做你想做的事。我们为heroku 部署做了类似的事情(将coffeescript 编译成javascript)。您的脚本无法正常工作的原因是您exec不正确地使用了该命令。

手册页

exec 内置命令用于用新命令替换当前运行的 shell 进程映像。成功完成后, exec 永远不会返回。exec 不能在管道内使用。

只有您的第一个 exec 命令正在运行。之后,您的脚本基本上被终止。

试试这样的东西(作为预提交钩子):

#!/bin/sh
files=`git diff --cached --name-status`
re="<files of importance>"
if [[ $files =~ $re ]]
then
  echo "Creating files"
  bundle exec create_my_files
  git add my_files
fi
于 2010-10-19T19:14:16.467 回答
14
#!/bin/sh
#
#  .git/hooks/pre-commit
#

git add file.xyz

这对我来说很好。它将成为当前提交的一部分。

git version 1.7.12.4 (Apple Git-37)

于 2013-02-14T12:03:05.590 回答
10

您可以使用前提交和后提交脚本的组合。

在预提交中:

  • 触摸一个文件 .commit 什么的。(请务必将此添加到 .gitignore)

在提交后:

如果 .commit 存在,您知道提交刚刚发生,但后提交尚未运行。因此,您可以在这里进行代码生成。此外,测试 .commit 是否存在:

  • 添加文件
  • commit --amend -C HEAD --no-verify (避免循环)
  • 删除 .commit 文件

这大致是我用来在 Metastore 生成的存储库中存储 .metadata 文件的过程。

如果有人知道更好的方法,我会全神贯注,但现在似乎可行。

于 2012-04-16T20:14:44.340 回答
10

您可以使用update-index

git update-index --add my_files

于 2010-07-19T19:26:46.903 回答
2

If the files are automatically generated, and they can be generated anywhere (implicit in your desire to build them in the Git pre-commit hook) then you shouldn't be putting them under source control in the first place. You should only control source files -- generated files should be generated as part of the build scripts.

The only reason to put a generated file under source control is when it requires unique/privileged resources to generate (such as a licensed program) or it requires a significant amount of time to generate.

Added

From http://git-scm.com/docs/githooks :

pre-commit This hook is invoked by git commit, and can be bypassed with --no-verify option. It takes no parameter, and is invoked before obtaining the proposed commit log message and making a commit. Exiting with non-zero status from this script causes the git commit to abort.

The default pre-commit hook, when enabled, catches introduction of lines with trailing whitespaces and aborts the commit when such a line is found.

All the git commit hooks are invoked with the environment variable GIT_EDITOR=: if the command will not bring up an editor to modify the commit message.

The intent of the pre-commit hook is to be a pass-fail check on the state of the workspace and the contents of the commit, prior to making the commit. Attempting to change the contents of the commit won't work.

My recommendation would be add two steps to your build scripts: (1) a step that will build all of the out-of-date files that needs to be generated (and adds them to the workspace), and (2) a step that will check to ensure that all of the generated files are up-to-date, and return a non-zero status code. Your Git pre-commit hook should run the second step. Your developers should be trained to run the first step as necessary.

于 2010-07-19T19:32:39.300 回答
2

不如编写一个post-commit脚本来生成你的文件,然后让它去做(类似的事情)git add my_files; git commit --amend

于 2010-07-19T20:31:41.343 回答
1

我有同样的需求,这种方法对我来说效果很好:

#!/bin/sh
files='git diff --cached --name-only'
re="<files of importance>"
if [[ $files =~ $re ]]
then
   echo "Creating files"
   create_my_files && git add my_files
fi

其中“create_my_files”应该是可执行的,例如,如果它是一个 python 文件,您可以将其执行为“python create_my_files && git add my_files”

确实,您不需要预先提交即可再次提交(这将创建一个无限的讨厌循环:p)

于 2012-01-10T00:57:22.300 回答
1

是的,您可以使用 git 钩子在提交时自动添加生成的文件!但它需要一个棘手的脚本。

在这里您可以找到已解决的问题。在那里,它会在每次提交时更新文件版本,添加新的修改文件并根据需要修改提交。它完全正常工作: https ://github.com/evandrocoan/.versioning

然后,您只需用您的算法替换文件“updateVersion.sh”上的“版本文件替换”算法。也许您需要更改一些内容,例如删除分支限制,因为在那里,脚本仅在您位于“开发”分支时运行。

此外,它只会更改指定的文件(如果已暂存)。如果文件没有暂存,那么它只会执行正常/通常的提交。更准确地说,它打印出每一步都在做什么。

我要解释一下,那个把戏。这很棘手。在 prepare-commit-msg-hook 上,它检测是否正在暂存和提交所需的文件。之后,它会创建一个标志文件,并停止 prepare-commit-msg-hook。稍后在 post-commit-hook 上,它检查标志文件是否存在。如果是,它会修改提交上的文件。

注意,它会创建一个无限循环,因为它会再次调用 prepare-commit-msg-hook(正如我们正在修改的那样)。但它不会因为标志文件而发生。当 prepare-commit-msg-hook 运行并找到标志文件时,它“知道”发生了什么。然后只是删除标志文件并且不再创建它。这样做,它将阻止 post-commit-hook 再次修改提交,从而使提交永久完成。

于 2016-07-21T04:03:47.480 回答
-2

我在预提交钩子中也面临同样的问题。我正在修改一个文件并提交,但它正在使用以前的文件而不是更新的文件,因此通过在 pre-commit 挂钩中添加 git 命令(如下所示),它解决了。

git add $file

注意:$file是您要添加的文件。

谢谢,

于 2016-11-08T14:10:46.577 回答