接收前和接收后挂钩中的Git存放未按预期方式工作

问题描述 投票:0回答:1

有点背景

我正在开发一种流程,它将允许人们访问一个公共环境。我的想法是要有一个只能放入的存储库,而不是一个裸露的存储库,因为我希望人们能够阅读它。我们称之为COMMON这是因为我不希望人们必须克隆存储库才能访问数据。

为此,我具有以下结构:

  1. 本地资源库:想要开发流程的人员可以在其中执行修改,提交并推送到远程资源库的地方
  2. 远程存储库:也用作网关的裸存储库。每当推送到该裸存储库时,它都会被重新执行到COMMON存储库
  3. COMMON信息库:公共的“读取”目录。只有推送才能修改其历史记录,甚至禁止提交(通过预提交钩子)

问题

COMMON存储库不应进行任何直接修改。但是,由于有多个用户在使用sudoers,因此我不能100%确保有人不会直接对其进行修改。或者,相应地,对于Murphy,我100%确信有人有一天会在COMMON资源库中本地修改某些内容...

[为了确保当有人正确地将其推入远程目录时,因此在COMMON存储库中没有冲突,我考虑了以下用于COMMON的钩子:

  • 预接收
#!/bin/bash
#Stash local modifications if there are ones to avoid conflicts
echo "## Local modifications on the Product-Line are stashed with the tag: 'local modifications @ $(date)' "
git stash push -m "local modifications @ $(date)"
exit 0
  • 接收后
#!/bin/bash
#Checks out the the branch that contains the last commit
git checkout $( git log --branches -1 --pretty=format:'%D' | sed  -e 's/.*-> //g' -e 's/.*, //g' )
#Forces synchronization with the last commit
git stash
git stash drop stash@{0}

exit 0

但是,隐藏命令似乎无法正常工作。在本地存储库中进行推送时返回的日志如下:

$> echo toto >> stash_test ; git commit -am "test" ; git push
[tbranch f6e8fbb] test
 1 file changed, 1 insertion(+)
Enumerating objects: 5, done.
Counting objects: 100% (5/5), done.
Delta compression using up to 48 threads
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 351 bytes | 351.00 KiB/s, done.
Total 3 (delta 1), reused 0 (delta 0)
remote: remote: ## Local modifications on the Product-Line are stashed with the tag: 'local modifications @ Mon Dec 23 17:44:59 CET 2019'         
remote: remote: No local changes to save        
remote: remote: Already on 'tbranch'        
remote: remote: M   stash_test        
remote: remote: Saved working directory and index state WIP on tbranch: f6e8fbb test        
remote: remote: stash@{0}: WIP on tbranch: f6e8fbb test        
remote: remote: Dropped stash@{0} (b29b76ceb2b2dfd2fcf6d0577c7200e517641328)        
remote: To ../pl
remote:    f75b5d1..f6e8fbb  tbranch -> tbranch
To /home/usr/TEMP/remote
   f75b5d1..f6e8fbb  tbranch -> tbranch

这里有两个问题:

  • 为了测试COMMON信息库中的自动隐藏,我修改了一个文件。但是,当预接收挂钩到达git stash push -m "msg"时,它将返回No local changes to save
  • 在接收后挂钩中,git stashgit stash drop stash@{0}应该模拟对当前分支的最后一次提交的更新。在日志中,似乎该操作有效,但是,如果我在COMMON信息库中获得了状态,则可以获得:
On branch tbranch
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

    modified:   stash_test
    modified:   test

  • [stash_test是上次提交修改的文件
  • test是本地修改以测试所有过程的文件

双龙效果:1. git stash list为空,其中应包含对test的修改。但是,该日志与之保持一致,因为它没有将test隐藏在预接收钩子中2. stash_test没有更新为最后一次提交...这里很奇怪,因为日志表明一切正常...

我不知所措的是,我尝试手动执行这些步骤,并且...按预期工作。但是我在git管理方面还很陌生,所以我可能会错过一些东西...

问题

  • git stash命令在钩子中是否表现出令人讨厌的行为,使我无法做我想做的事?
  • 还有另一种(也许更好)的方法来实现我想做的事吗?

编辑:找出问题的根本原因

执行钩子后,它位于我的COMMON目录的.git目录中。因此,git stash无法检测到修改。如果在预接收挂钩中执行git status --porcelain,则会得到:

?? HEAD
?? ORIG_HEAD
?? config
?? description
?? gitk.cache
?? hooks/applypatch-msg.sample
?? hooks/commit-msg.sample
?? hooks/fsmonitor-watchman.sample
?? hooks/post-receive
?? hooks/post-update.sample
?? hooks/pre-applypatch.sample
?? hooks/pre-commit
?? hooks/pre-commit.sample
?? hooks/pre-push.sample
?? hooks/pre-rebase.sample
?? hooks/pre-receive
?? hooks/pre-receive.sample
...

这是预期的,因为.git dir的内容不受版本控制。

实际上,即使在@knittl建议使用git reset --hard的情况下也不起作用,因为它在common的'work'目录中没有完成。

我想到的简单解决方法是使用以下命令将操作封装在我的钩子中:

pwd # returns COMMON/.git
pushd .. > /dev/null
pwd # returns COMMON
#hook operations
popd > /dev/null

使用钩子检查pwd命令,我终于在正确的目录中执行隐藏/重置。但是,执行此操作时,远程消息将返回我:

remote: remote: fatal: not a git repository: '.'        

所以现在我有点困惑,因为我实际上是我的COMMON的根,因此应该将其视为git存储库...

即使按照@knittl和@torek的建议,这也不是部署某些东西的黄金方式,我想了解为什么会有这些限制,并且如果有一种覆盖它们的方式

EDIT2:存储在预提交中

在pre-commit钩子中,我执行了一个存储操作,以保存本地修改并中止提交,因此“鲁ck的sudoer”无法提交其更改,但可以稍后选择其修改。在此挂钩中,git stash的执行效果与预期相同。

我想这个问题与接收前/接收后挂钩是服务器端挂钩这一事实有关,通常只应用于裸仓库。

git githooks git-stash
1个回答
0
投票

我终于找到了困扰我的piece of documentation

在Git调用一个钩子之前,它将其工作目录更改为裸存储库中的$ GIT_DIR或非裸存储库中工作树的根。例外是总是在$ GIT_DIR中执行的推送(预接收,更新,后接收,更新后,推送至签出)期间触发的挂钩。

因此GIT_DIR环境变量使我的钩子在COMMON / .git中运行。因此,为了覆盖,我终于将当前工作目录更改为COMMON并设置为GIT_DIR=$(pwd -P)/.git如果未以这种方式设置GIT_DIR,则git不会将COMMON视为git目录(因为默认情况下GIT_DIR='.'且git会在较高级别中查找.git目录)

供参考,我的接收后钩子最终看起来像:

#!/bin/bash

# Make sure that we are on the branch containing the last commit
git checkout -f $( git log --branches -1 --pretty=format:'%D' | sed  -e 's/.*-> //g' -e 's/.*, //g' )

# Forces synchronization with the last commit by discarding the local modifications. A bit trickerish but it works...
cd ..
export GIT_DIR=$(\pwd -P)/.git
git reset --hard

exit 0
© www.soinside.com 2019 - 2024. All rights reserved.