Git 挂钩可以自动将文件添加到提交吗?

发布于 2024-09-10 16:01:51 字数 426 浏览 20 评论 0原文

我想使用 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

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

I'd like to add an automatically generated file to the same commit using a pre- or post-commit hook in Git, dependent on the files that were modified in that commit. How would I go about this?

I've tried this as a pre-commit hook, but no luck:

#!/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

This successfully adds them to the repository, but does not add them to the commit. I've also tried using the last two exec lines in a post-commit hook along with the pre-commit inspection, but no good either.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(11

鯉魚旗 2024-09-17 16:01:52

可以使用预提交挂钩来做你想做的事情。我们对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

It's possible to do what you want using pre-commit hooks. We do something similar for a heroku deployment (compiling coffeescript to javascript). The reason your script isn't working is because you used the exec command improperly.

From the man page:

The exec builtin is used to replace the currently running shells process image with a new command. On successful completion, exec never returns. exec can not be used inside a pipeline.

Only your first exec command is running. After that your script is basically terminated.

Give something like this a try (as a pre-commit hook):

#!/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
不疑不惑不回忆 2024-09-17 16:01:52
#!/bin/sh
#
#  .git/hooks/pre-commit
#

git add file.xyz

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

git 版本 1.7.12.4 (Apple Git-37)

#!/bin/sh
#
#  .git/hooks/pre-commit
#

git add file.xyz

This worked just fine for me.
It will be part of the current commit.

git version 1.7.12.4 (Apple Git-37)

不知在何时 2024-09-17 16:01:52

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

在预提交中:

  • 触摸文件 .commit 或其他内容。 (请务必将其添加到 .gitignore

在提交后:

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

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

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

如果有人知道更好的方法,我会洗耳恭听,但现在似乎有效。

You could use a combination of a pre and post commit script.

In the pre-commit:

  • Touch a file .commit or something. (be sure to add this to .gitignore)

In the post-commit:

if .commit exists you know a commit has just taken place but a post-commit hasn't run yet. So, you can do your code generation here. Additionally, test for .commit and if it exists:

  • add the files
  • commit --amend -C HEAD --no-verify (avoid looping)
  • delete .commit file

This is roughly the process I use to store a .metadata file in the repository generated from metastore.

If anyone knows a better way I'm all ears but it seems to work for now.

凑诗 2024-09-17 16:01:52

您可以使用update-index

git update-index --add my_files

You can use update-index:

git update-index --add my_files

快乐很简单 2024-09-17 16:01:52

编写一个post-commit脚本来生成您的文件,然后让那个做(类似的事情)git add my_files;怎么样? git commit --amend

How about writing a post-commit script instead which generates your files, and then have that do (something along the lines of) git add my_files; git commit --amend.

凉月流沐 2024-09-17 16:01:52

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

#!/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)

I had the same need and this approach worked pretty well for me:

#!/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

where "create_my_files" should be executable, for example if it is a python file you could execute it as "python create_my_files && git add my_files"

and is true you don't need a pre-commit to commit again (that would create a infinite nasty loop :p)

感情旳空白 2024-09-17 16:01:52

如果文件是自动生成的,并且它们可以在任何地方生成(隐含在您希望在 Git 预提交挂钩中构建它们的愿望),那么您就不应该首先将它们置于源代码控制之下。您应该只控制源文件——生成的文件应该作为构建脚本的一部分生成。

将生成的文件置于源代码控制之下的唯一原因是当它需要唯一/特权资源来生成(例如许可程序)或需要大量时间来生成时。

添加

来自http://git-scm.com/docs/githooks:

预提交 该钩子由 git 调用
提交,并且可以绕过
--无验证选项。它不带任何参数,并且在之前调用
获取建议的提交日志
消息并进行提交。退出
该脚本的状态为非零
导致 git 提交中止。

默认的预提交钩子,当
启用,捕捉线路介绍
带有尾随空格和中止
找到这样一行时的提交。

调用所有 git commit 挂钩
与环境变量
GIT_EDITOR=:如果该命令不会
调出编辑器来修改
提交消息。

预提交挂钩的目的是在提交之前对工作区的状态和提交的内容进行通过/失败检查。尝试更改提交的内容是行不通的。

我的建议是在构建脚本中添加两个步骤:(1)一个步骤将构建所有需要生成的过时文件(并将它们添加到工作区),以及(2)一个步骤将检查以确保所有生成的文件都是最新的,并返回非零状态代码。您的 Git 预提交挂钩应该运行第二步。您的开发人员应该接受培训以根据需要运行第一步。

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.

末蓝 2024-09-17 16:01:52

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

在这里你可以发现问题已解决。在那里,它会在每次提交时更新文件版本,添加新的修改文件并根据需要修改提交。它正在全面工作:
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 再次修改提交,从而允许提交永久完成。

Yes, you can add generated files automatically on the commit using git hooks! But it requires a tricky script.

Here you can find the problem solved. There, it is updating the file version on every commit, adding a new modified file and amending the commit as you need it to. It is fully working:
https://github.com/evandrocoan/.versioning

Then you just replace the 'Version File Replacement' algorithm on the file 'updateVersion.sh', by your algorithm. Maybe you need to change a few things like, remove the branch limitation, because there, the script only runs if you are on the 'develop' branch.

Also, it will only change the specified file, if is staged. If the file is not staged, then it will do nothing than the normal/usual commit. More precisely, it print out what it is doing on every step.

I am going to explain, that trick. It is quite tricky. On the prepare-commit-msg-hook, it detects whether the desired file is being staged and committed. After that, it creates a flag file, and stops the prepare-commit-msg-hook.
Later on the post-commit-hook, it checks whether the flag file exists. If yes, it amends the files on the commit.

Attention, it would create a infinity loop because it would call again the prepare-commit-msg-hook (as we are amending). But it does not happen because of the flag file. When the prepare-commit-msg-hook runs and find the flag file, it "knows" what is happening. Then is just deletes the flag file and do not create it again. Doing it, it will block the post-commit-hook from amending again the commits, allowing the commit to finish for good.

想象一下,您有一个预提交钩子可以执行此操作:

#!/bin/bash

echo "--- Dataset Pre-Commit Hook ---"

DATASET_REPO_PATH="$(pwd)"

python3 -m my_script_that_generates_or_modifies_a_file
git -C $DATASET_REPO_PATH add file

echo "--- Done ---"
exit

当且仅当已经有需要提交的内容时,它才会起作用。它不一定是同一个文件。如果没有需要提交的内容, git add git add file 将起作用,但不会提交。

有效的示例:

  1. 您更改了一个文件,并添加了它(例如,gitignore
gt; git status
On branch master

No commits yet

Changes to be committed:
  (use "git rm --cached <file>..." to unstage)
        new file:   .gitignore
  1. 运行提交。首先,pre-commit 挂钩将运行并创建file。然后它就会提交。
--- Dataset Pre-Commit Hook ---
--- Done ---
[master (root-commit) 2ba2f7c] First commit
 3 files changed, 34 insertions(+)
 create mode 100644 .gitignore
 create mode 100644 file
  1. 您可以看到消息显示 file 已提交。 git status 现在输出:
On branch master
nothing to commit, working tree clean

不起作用的示例

  1. 您没有任何可添加的内容。您当然可以运行 git add ,但它不会执行任何操作。 git status 给出:
On branch master
Your branch is up to date with 'origin/master'.

nothing to commit, working tree clean
  1. 运行提交。该钩子将创建文件。但提交消息显示他什么也没做。
--- Dataset Pre-Commit Hook ---
--- Done ---
On branch master
Your branch is up to date with 'origin/master'.

nothing to commit, working tree clean
  1. 验证状态 git status
On branch master
Your branch is up to date with 'origin/master'.

Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        modified:   file
  1. 您可以看到该文件确实已修改,并且已添加,但尚未提交。您需要再次运行 git commit 才能正常工作。

我尝试将其添加为 post-commit 挂钩,但没有成功。如果有人知道解决此问题的方法,我很想知道。

Imagine you have a pre-commit hook that does this:

#!/bin/bash

echo "--- Dataset Pre-Commit Hook ---"

DATASET_REPO_PATH="$(pwd)"

python3 -m my_script_that_generates_or_modifies_a_file
git -C $DATASET_REPO_PATH add file

echo "--- Done ---"
exit

It will work IF AND ONLY IF, there was already something to be commited. It does not have to be the same file tho. If there was nothing to be commited, the git add git add file will work, but will not be commited.

Example that works:

  1. You changed a file, and added it (for example, the gitignore)
gt; git status
On branch master

No commits yet

Changes to be committed:
  (use "git rm --cached <file>..." to unstage)
        new file:   .gitignore
  1. Run commit. First, the pre-commit hook will run and create file. Then it will commit.
--- Dataset Pre-Commit Hook ---
--- Done ---
[master (root-commit) 2ba2f7c] First commit
 3 files changed, 34 insertions(+)
 create mode 100644 .gitignore
 create mode 100644 file
  1. You can see the message says file was commited. And git status now outputs:
On branch master
nothing to commit, working tree clean

Example that DOES NOT work

  1. You have nothing to add. You can of course run git add but it will do nothing. git status gives:
On branch master
Your branch is up to date with 'origin/master'.

nothing to commit, working tree clean
  1. Run commit. The hook will create file. But the commit message says he did nothing.
--- Dataset Pre-Commit Hook ---
--- Done ---
On branch master
Your branch is up to date with 'origin/master'.

nothing to commit, working tree clean
  1. Verify the status git status
On branch master
Your branch is up to date with 'origin/master'.

Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        modified:   file
  1. You can see that file was indeed modified, and that it was added, but yet not commited. You need to run git commit again for it to work.

I tried adding that as a post-commit hook but got no luck. If someone knows a fix for this case, I would love to know.

我也只是我 2024-09-17 16:01:52

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

git add $file

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

I was facing same problem in pre-commit hook also. I was modifying one file and committing but it was taking previous file not updated file so by adding git command(as below) in pre-commit hook, it solved.

git add $file

note: $file is your file to be added.

别忘他 2024-09-17 16:01:51

由于 git add 在预提交中也不适用于我,因此我遵循了 mark 的想法,即使用 .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 知识很少的人更容易遵循 mark 的想法。

Since git add was also not working for me in a pre commit, I followed mark's idea of using a .commit file and splitting the process into pre- and post-commit.

Here is some code that should be easy to understand

In the pre-commit:

  • Touch a file .commit or something. (be sure to add this to .gitignore)
#!/bin/sh 
echo 
touch .commit 
exit

In the post-commit:

if .commit exists you know a commit has just taken place but a
post-commit hasn't run yet. So, you can do your code generation here.
Additionally, test for .commit and if it exists:

  • add the files
  • commit --amend -C HEAD --no-verify (avoid looping)
  • delete .commit file
#!/bin/sh
echo
if [ -e .commit ]
    then
    rm .commit
    git add yourfile
    git commit --amend -C HEAD --no-verify
fi
exit

Hope this makes it easier for people with few bash knowledge to follow mark's idea.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文