我需要在服务器上做什么才能确保当我推送它时,最初裸Git存储库会更新工作目录?

时间:2017-05-25 17:17:34

标签: git remote-server

在远程计算机上:

  1. mkdir mlcode.git && cd mlcode.git && git init --bare
  2. post-receive中创建包含

    ~/mlcode.git/hooks文件
    #!/bin/sh
    GIT_WORK_TREE=/home/ubuntu/mlcode
    export GIT_WORK_TREE
    git checkout -f
    
  3. chmod +x ~/mlcode.git/hooks/post-receive
  4. mkdir mlcode
  5. 然后在本地机器上我将远程机器设置为repo并推送。这似乎有效(远程存储库按预期更新,提取确认,等等)。但没有检查出来。

    经过一些实验后,似乎在我明确创建分支的服务器之后(在第一次推送之后?)之后需要一个额外的步骤并用

    之类的方式检查它
    GIT_WORK_TREE=/home/ubuntu/mlcode git checkout -f -B thebranch
    

    完成后,按预期更新mlcode的内容。但我不确定手动结账和分支创建是充分的还是必要的(我发现的许多在线指令都没有):它似乎已经奏效了。

    我需要在服务器上运行什么才能确保最初裸存储库在我推送时更新工作目录?上面的明确步骤是否必要?不同的post-receive会避免它吗?

1 个答案:

答案 0 :(得分:1)

简短的回答是肯定的:不同(更好)的接收后可以避免这个问题。特别是,如果您只有一个工作树应该更新,当且仅当一个特定分支xyz被更新时,您可以在更新一个分支时明确检出一个分支:

#! /bin/sh
while read ohash nhash ref; do
    case "$ref" in
    refs/heads/xyz) git --work-tree=/path/to/deploy checkout -f xyz;;
    esac
done

这仍然不是伟大的收件后挂钩,但它略有改进。请阅读以下讨论了解更多信息。

讨论

首先尝试此练习:当您运行没有参数的git checkout或没有分支名称的git checkout -f时,在任何普通,非裸,Git存储库中会发生什么?检查哪个分支?请随意在the git checkout documentation中查找答案。如果你git checkout分支名称,那么将其与检出的分支进行比较。

同样,在非裸存储库中运行git branch。哪个分支是最新的? Git甚至知道怎么做?

既然你已经完成了这个练习,你认为哪个分支在存储库中检出? (说真的,做练习,它会帮助你记住答案并解释所有这些。)

Push提交提交和更新参考

当存储库是git push的目标时,实际发生的是接收主机系统获取一系列对象(提交和/或标记,和/或与它们一起使用的树和/或blob)来自其他一些Git。然后,它从另一个Git获得一个或多个请求(常规推送)或命令(强制推送):"请将refs/tags/v1.2设置为1234567..."或者"将refs/heads/branchname设置为feedbee...,我的意思是!"它根据git push作为git push的参数提供的内容,根据 refspec 获得一个这样的请求或命令。

如果引用命名分支(refs/head/whatever),并且接受分支更新(是正确的快进或强制),则更新存储库的分支映射中的相应分支-names to commit-IDs。

裸存储库仍然具有当前分支和索引

正如您现在所知,git checkout没有参数(或只有-f)会检出当前分支

收件后挂钩:

#!/bin/sh
git --work-tree=/path/to/work/tree checkout -f

不是错误,正是如此。但它快速而肮脏,而且有些邋..接收收到了一些东西 - 可能是一些提交,也许是一个标签或者代替 - 并将它们放在裸存储库中。 更改存储在当前分支下的哈希ID了吗?谁知道? 当前的分支是什么?

这部分至少很容易回答。当前分支是存储在HEAD中的分支。使用git symbolic-ref HEAD进行查看。如果这表示refs/heads/master,则当前分支为master

我们刚刚获得该分支的更新吗?谁知道?好吧,收件后挂钩本身可以知道。 假设读取所有标准输入,告诉它,一次一行,哪些引用 - 分支,标签或其他 - 更新,以及它们是什么旧的和新的哈希ID是。 收件后挂钩并不烦人。它只是重新检出当前分支,更新与否。

如果当前分支 更新,Git将根据索引知道要替换(或添加或删除)的文件,这是跟踪Git的内容写进了工作树。如果当前的分支没有得到更新,Git会做一些繁忙的工作而且没有什么真正的改变(这是文档中的"荣耀的无操作")。

即使在裸存储库中也是如此。通常情况下,根本就没有工作树,但是您提供的--work-tree$GIT_WORK_TREE会覆盖core.bare的{​​{1}}设置。

但签出的分支是当前分支。它之后仍然是当前分支,因为此git checkout命令中没有分支名称

  

...我明确地......用[/ p>]之类的东西检查[分支]

git checkout

当您使用分支名称签出时,您将获得该特定分支, Git将当前分支更改为您指定的分支。具有 no 分支名称的未来GIT_WORK_TREE=/home/ubuntu/mlcode git checkout -f -B thebranch 将检出当前分支,即您刚刚在此处指定的分支(假设没有干预变更)。

任何存储库的当前分支也会影响克隆

当您从某个存储库中git checkout时,无论是否裸露,新克隆都会以当前分支开始。大多数情况下,这是git clone - 但这只是因为您通常会克隆其当前分支为master的现有存储库。默认情况下,新克隆以相同的当前分支开始。 (您可以使用master更改-b branch-or-tag-name方面的此行为。)

这意味着每当您更改用于克隆和推送的裸存储库的当前分支时,您就会更改某个克隆该存储库时将获得的分支。这可能没什么大不了的,但你应该知道它。

只有一个索引

裸存储库通常具有工作树。因此,它也不需要索引,因为索引会记住工作树中的内容,并用于构建 next 提交,但两者都没有在这个没有工作树的裸存储库中有任何意义。

一旦你开始给它一个clone的临时工作树,突然 (单个)索引很重要。该索引可以跟踪工作树中的内容。如果你总是每次都给这个裸存储库提供相同的工作树,那么只有一个索引的事实不是问题:一个工作树,一个索引,一切都匹配。

但是如果你给它一个秒,不同的临时工作树......好吧,现在你有一个索引试图跟踪两个不同的工作树。这不是那么好用。 Git有点聪明,有时候注意到索引对于工作树来说都是错误的并且使它全部解决了。但它并没有总是解决问题。您现在至少需要两个索引文件用于两个工作树(或者您可以每次都清除索引文件工作树,以便&# 39; s没有什么不同步,但这会破坏跟踪工作树的索引的缓存/速度方面。