裸git repo post-receive hook不再能够结账

时间:2017-04-24 13:59:09

标签: git git-post-receive git-bare

我在Web服务器上使用了一个简单的git repo,使用post-receive hook来自动检查对网站的更改。这一直很有效。

然而,一位同事最近克隆了裸仓(git clone <ssh url>),对其本地仓库进行了一些更改,提交了它们,然后将更改推回(git push origin master)。我不确定这个过程是否是导致问题的原因,但是自推送以来,后接收挂钩不再有效。它输出失败:

fatal: You are on a branch yet to be born

这是钩子:

#!/bin/bash
GIT_WORK_TREE=/home/marweldc/app git checkout -f

我可以将我的同事从遥控器所做的更改拉到我的本地实例。在服务器上的裸仓库中运行git branch显示* mastergit log显示所有更改,包括我的同事,因此远程仓库显然可以正常跟踪。< / p>

但是,如果我这样做,例如,GIT_WORK_TREE=/home/marweldc/app git status我得到以下输出:

# Not currently on any branch.
#
# Initial commit
#
# Untracked files:
#   (use "git add <file>..." to include in what will be committed)
#
#       ../CONTRIBUTING.md
#       ../README.inno.txt
#       <all the other files and folders that should be in the repo>
nothing added to commit but untracked files present (use "git add" to track)

我也尝试过运行GIT_WORK_TREE=/home/marweldc/app git checkout -f master,产生:

error: pathspec '.git/master' did not match any file(s) known to git.

我们很难过。什么改变导致我们的钩子在它之前正常工作时以这种方式失败?

修改

我尝试过的一些事情在下面发表评论:

    来自裸仓库内的
  • cat HEAD会产生ref: refs/heads/master
  • 来自裸仓库中的
  • GIT_TRACE=1 git rev-parse master

    trace: built-in: git 'rev-parse' 'master' 
    f6462b06f75d126ab932e3cfccef7385da2805ba 
    

    但是设置了--work-tree选项的相同命令会产生

    trace: built-in: git 'rev-parse' 'master'
    master
    fatal: ambiguous argument 'master': unknown revision or path not in the working tree.
    Use '--' to separate paths from revisions
    
  • 运行GIT_WORK_TREE=/home/marweldc/app-new git checkout -f(一个新的目录来结帐)可以正常使用

1 个答案:

答案 0 :(得分:1)

编辑:这里有一些非常具体的(可能是CentOS特定的)问题,在这里使用的旧Git版本1.7.1中有单独的Git和工作树目录,这样对于这个特定情况, --work-tree=/home/marweldc/app导致Git无法在Git目录和工作树之间来回传递。 (其他工作树路径不会导致问题。)

Git没有注意到自己无法回到裸存储库,然后无法对分支名称做任何事情(因为它无法返回到存储库,它可能会在所有内容中失败此时)。

更现代的Git可能首先没有bug,或者会注意到在工作树和裸存储库之间来回切换失败。

同时,指定--git-dir=<path>似乎解决了这个问题。

原始(一般)答案如下。

此:

  

fatal: You are on a branch yet to be born

意味着它所说的,尽管它说的可能令人困惑。 :-)你真的是&#34; on&#34;一些尚不存在的分支。

(目前还不清楚 - 你可能有一个&#34;分离的HEAD&#34;,就像Git所说的那样 - 但它看起来好像你不再拥有一个master分支,如果你曾经做过的话。)

短版

使用git branch查看您现在所在的分支机构以及您可以使用的分支机构。使用git symbolic-ref HEAD refs/heads/master强制将裸存储库HEAD设置回master分支。对于名为 B 的其他分支,请使用refs/heads/B

长篇答案,即接下来发生的事情。

无论存储库是否存在,它仍然具有当前分支

在任何普通的非裸存储库中,您可以通过运行git status来查看您所在的分支。但git status查看工作树,因此在 bare 存储库中,git status拒绝运行:没有工作树。

查看您所在分支的另一种方法是运行git branch

$ git branch
  diff-merge-base
* master
  stash-exp

这适用于裸存储库和非裸存储库。 *以当前分支的名称命名。

如何在常规存储库中更改您所依赖的分支?

答案 1 是:git checkout。例如,git checkout master会将您(或我)放在master上,git checkout stash-exp会将您(或我)放在stash-exp上。

1 还有另一种方法,使用管道命令,但你通常不想使用它,因为它可能会弄乱当前的差异提交,索引和工作树。但是由于裸存储库没有工作树,所以这变得......好吧,#34;安全&#34;太强大,但我们可以说&#34;更不那么危险&#34;。

如何在裸存储库中更改您所依赖的分支?

答案是仍然 git checkout

当您在裸存储库中签出分支时,它会使用和更改当前分支,其方式与在非裸存储库中签出分支时完全相同。 < / p>

当然,您不能 git checkout裸存储库中的分支,因为它会更新工作树。当您使用git --work-tree=... checkout ...时,可以除外。您提供要签出的分支的名称,并且像往常一样将新分支名称写入HEAD如果您通过哈希ID签出提交,那么分离{ {1}}像往常一样。

未出生(孤儿)分支

但还有一个特殊情况:如果您将HEAD设置为尚不存在的分支的名称(就像使用HEAD一样例如),将名称放入git checkout --orphan而不创建分支。这在普通(非裸)存储库中是正常的,除了你只在两种情况下看到它:

  • 首次创建新的空存储库时。您已HEAD,但master尚不存在。您可以通过在存储库中放置提交来解决此问题,该提交将转到master,从而创建master。 (新提交是 root 提交,即没有父提交。)

  • 当您使用master时:通过将分支的名称写入{{1},这与您在新的空存储库中设置时的方式相同像往常一样,但没有创建分支。您可以通过编写一个新的提交来解决这种情况,该提交将进入未出生的分支,该分支将创建分支,该分支现在已经生成(存在,指向您刚刚创建的新根提交。)

在裸存储库中执行相同的操作

显然,你不能在裸存储库中以通常的方式执行此操作,因为通常的方法是使用工作树,git checkout --orphan事物到索引中,{{1} }。裸存储库没有工作树。 (它仍然有索引和HEAD,您可以在提供工作树git add时执行此操作,仍然可以通过写入因为他们不了解索引,所以这对于许多人的接收后部署挂钩有点棘手和混乱。)

可以所做的一切,并且在裸存储库中一直这样做是接收git commit es。当您收到推送时,您接受来自另一个Git形式的请求(或命令):

  • 请将git checkout分支设置为提交--work-tree
  • 删除分支git push

(由您决定是否以及如何在master1234567挂钩中检查这些请求。如果您没有做任何特别的事情,那么您可以获得Git&#39; s默认的内置检查,允许任何人创建或删除任何分支或标记,但只允许快速推送分支。)

例如,假设您在裸存储库中的分支testing上,而分支pre-receive 尚不存在。然后,Interwebs上的某个人连接到你的服务器并说:&#34;嘿,你,裸Git存储库,在这里有一些提交,现在创建分支update指向提交master&#34!;在这种情况下,假设您接受此请求/命令,一旦您的Git完成为他们提供服务,您现在有一个master。这将带你从:

master

为:

1234567

因为您之前不存在的当前分支master确实现在存在。

使用管道命令

fatal: You are on a branch yet to be born On branch master 管道命令旨在用于脚本。他们假设您确切知道自己在做什么。 (如果你在不知道自己在做什么的情况下使用它们,你就会弄得一团糟:它们没有内置的安全检查。)其中第二个特别是Git如何在内部设置master来选择你的哪个分支&#34; on&#34;。

如果你跑:

git update-ref

这会将git symbolic-ref写入HEAD,您现在是git symbolic-ref HEAD refs/heads/branch。它没有更新索引并且它没有更新工作树 - 但是在裸存储库中,没有工作树,并且接收推送不会更新索引,所以这与收到推送时发生的情况非常相似。

因此,这是一个相当安全的事情。它允许您更改所在的分支,而无需使用ref: refs/heads/branch。这是正常的和正确的,尽管很谨慎 - 确保正确拼写分支名称,并包含HEAD前缀方式以在裸存储库中设置On branch branch