4

我有一个分支和主干的服务器存储库。分支是所有团队成员的存储库。我试图svn hooks只在分支下的仓库中使用,但它似乎不能正常工作。以下是我尝试采取的步骤:

  1. my_repo从远程服务器的签出branch/my_repo

  2. 由于本地 repomy_repo没有任何内容,我在本地创建了一个新的 svn repo 并将包括/hooks文件夹在内的所有内容复制到my_repo.

  3. 我在其中创建了一个空文件my_repo并添加了一行文本。然后svn add这个文件。

  4. 修改了my_repo/hooks/pre-commit.tmpl文件并使其始终不通过错误代码 1。现在它看起来像:

#!/bin/sh
1号出口
  1. 复制pre-commit.tmpl到 pre-commit 并将 pre-commit 的执行许可添加到我自己

  2. 服务器包含其他人的现在服务器的结构是这样的:

- 服务器
    - 分支
        - my_repo
            - 我的文件
            - 挂钩
                - 预提交
        - 汤姆的回购
        - 其他团队成员的回购
    - 树干
  1. 在签出的仓库中,我使用以下方式提交了更改:svn commit -m "dumb change"

现在从这里我应该无法提交,它应该给我一个代码 1 的错误,对吗?但我在任何地方都看不到它。

  1. 然后我尝试将 hooks 文件夹放在顶层,并与分支和树干处于同一水平。即结构看起来像:
-服务器
    - 分支机构
        - my_repo
            - 我的文件
        - 汤姆的回购
        - 其他团队成员的回购
    - 树干
    - 挂钩
        - 预提交

但是,仍然无法正常工作。叹...

但是,在 David 的帮助下,我弄清楚了该怎么做以及出了什么问题: 1. 强调:hooks 文件夹的所有权应该与创建存储库的人相同。因此,我不得不要求所有者将挂钩文件添加到服务器。我没有在服务器上创建存储库,因此这些文件在我的工作目录中是不可见的。2.现在这是我尝试过的:

  1)在我自己的Linux系统上,我`svnadmin create`一个新的存储库,可能称为test_server:其中有文件夹:confs,db,hooks,locks;文件:格式,readme.txt
  2)在同一级别上,mkdir 一个新文件夹(称为working_dir)作为您的本地工作目录并从test_server 签出。现在 working_dir 包含一个名为 test_server 的文件夹,它是空的。您在步骤 1 中看不到任何文件夹或文件
  3) 如上所述修改 test_server 的 hooks 文件。
  4)尝试添加一个文件并在working_dir/test_server文件夹中的文件中添加一个新行并提交。
  5)现在您应该看到提交失败并显示消息:svn:提交被预提交挂钩(退出代码 1)阻止,没有输出。

非常感谢大卫和任何人早些时候发表评论!

4

5 回答 5

6

当您运行挂钩时,STDOUT(通常由echo语句产生)被禁用。这意味着您的脚本不能使用 STDOUT 打印出任何内容,即使它已被重定向到文件。

相反,您需要打开另一个文件描述符而不是使用1(STDOUT)。您可以使用该exec命令打开另一个文件描述符,然后将其通过管道传输到文件中:

exec 4> $my_file  #Opening my_file for writing
echo "This is going to $my_file" >&4

STDERR 也被重定向。收集 STDERR 的输出并将其发送回调用客户端,但仅当挂钩返回非零退出代码时。这为您提供了一种与客户端沟通挂钩失败原因的方法。

您还必须小心,因为挂钩运行的环境已被清除。偶数$PATH为空。

这些是钩子脚本可以在命令行中正常运行的一些原因,但当它作为钩子执行时则不行。

如果您不相信钩子正在工作,只需将其设置为以非零退出代码退出。如果您从 Subversion 收到交易失败的消息,您就知道钩子脚本已执行。

我还建议您至少使用svnserve作为 Subversion 服务器——即使您是唯一使用存储库的人。file://即使我是唯一一个使用存储库的人,我也从不使用。该svnserve过程使用起来非常简单,而且相当轻巧。

另外,永远不要svn在钩子脚本中使用。改为使用svnlook


附录

我想非常非常清楚地说明这一点。我们需要同意一些定义:

  • SERVER 是运行 Subversion 存储库的机器。您使用该命令svnadmin create foo创建了一个foo将充当存储库本身的目录。
  • REPOSITORY DIRECTORY 是该svnadmin create命令在服务器上创建的目录。这是存储库的服务器端。您不会在此处看到您已签入 Subversion 的任何文件。相反,您将看到一个hooks目录和一个db目录。这是服务器用来跟踪其更改的内容。
  • svn checkoutWORKING DIRECTORY 是您为签出项目的特定版本所做的目录。
  • svnREPOSITORY 是您使用各种命令(如svn lsorsvn log或)时获得的 REPOSITORY DIRECTORY 的虚拟视图svn co。这不是存储库目录,而是存储库的视图。

好的,现在我们解决了这个问题:

Hook 脚本存放在 REPOSITORY DIRECTORY 目录下hooks。当您创建存储库目录时,已经有一个子目录调用hooks了一些用于挂钩脚本的模板。这些将有一个*.tmpl后缀。要制作钩子,您需要用钩子脚本替换其中一个脚本,并删除该*.tmpl后缀。钩子脚本必须具有可执行权限并且归运行 Subversion SERVER 进程的用户所有。(用户运行httpdsvnserve服务器上的命令)。

挂钩适用于整个存储库。您不能仅在特定分支受到影响时才告诉钩子不要触发。但是,您的钩子脚本可以查看文件所在的位置并据此采取行动。我有一个预提交钩子可以做到这一点。它使用控制文件根据文件的位置确定需要采取的操作。然而,每次提交发生时,即使它不需要做任何事情,这个钩子也会触发。

我希望这回答了你的问题。

于 2013-02-20T03:10:27.607 回答
1

您是否尝试过在其他地方使用输出文件,例如/tmp?听起来您正试图写回您的工作副本目录,所以钩子脚本可能无法访问那里?

请注意,该钩子将以任何运行 SVN服务器进程的用户身份运行,而不是 SVN客户端。因此,如果您使用的是 Apache WebDAV 类型的访问,它将是 Apache 的用户(我认为);如果使用 SSH 访问,则为svn+ssh://user@path语法中列出的用户;

于 2013-02-19T20:58:41.007 回答
0

修改了 hooks/pre-commit.tmpl 文件,现在看起来像

预提交钩子需要命名为预提交。pre-commit.tmpl 只是一个示例文件,永远不会运行。

于 2013-02-20T01:46:33.157 回答
0

看了你的问题,感觉有点迷茫。我来这里只是为了确保您的理解是正确的:

Subversion 中没有“签出回购”之类的东西。我们有 repo(通常在远程服务器中),从该 repo 签出后,我们有一个本地工作副本。Hooks 是在存储库中发生的事情,而不是本地工作副本。

根据您对步骤的描述,这就是我得到的:

  1. 从远程存储库签出:远程服务器

  2. 由于签出的工作副本没有任何内容,我在本地创建了一个新的 svn 存储库,并将包括 /hooks 文件夹在内的所有内容复制到我签出的工作副本中。

  3. 我在签出的工作副本中创建了一个空文件并添加了一行文本。然后svn添加这个文件。

  4. 修改了工作副本中的 hooks/pre-commit.tmpl 文件,现在它看起来像:(已删除)

  5. 为所有用户添加执行许可并将 pre-commit.tmpl 复制到 pre-commit (这些都发生在工作副本中)

  6. 在签出的工作副本中,我使用以下命令提交了更改: svn commit -m "dumb change"

如果我的理解是正确的,那么您只是误解了钩子的使用。钩子是放在存储库中的东西,而不是工作副本。当您提交(或执行其他操作)时,Hook 在存储库计算机上运行,​​而不是在本地计算机上运行。

于 2013-02-20T02:41:10.003 回答
0

从 tmpl 复制并将 exec 添加到 hooks 脚本,如下所示

cp post-commit.tmpl post-commit
chmod +x post-commit
于 2018-06-21T11:22:04.297 回答