在 git Push 上硬重置

发布于 2024-10-29 05:33:48 字数 490 浏览 7 评论 0原文

我在远程仓库上有一个接收后挂钩脚本,我正在推送它,它会执行 git reset --hard

类似这样的事情:

$ git push opal
Counting objects: 74, done.
Delta compression using up to 2 threads.
Compressing objects: 100% (45/45), done.
Writing objects: 100% (53/53), 16.68 KiB, done.
Total 53 (delta 20), reused 0 (delta 0)
remote: warning: updating the current branch
remote: HEAD is now at 88f1e35 tweak lavalamp styles

我在这里不明白的是 - 远程说 head 是现在在 XXX,但是当我登录服务器时 - 远程工作副本根本没有更新!

有什么想法吗?

I have a post-receive hook script sitting on the remote repo I am pushing to that does a git reset --hard

Something like this:

$ git push opal
Counting objects: 74, done.
Delta compression using up to 2 threads.
Compressing objects: 100% (45/45), done.
Writing objects: 100% (53/53), 16.68 KiB, done.
Total 53 (delta 20), reused 0 (delta 0)
remote: warning: updating the current branch
remote: HEAD is now at 88f1e35 tweak lavalamp styles

What i don't understand here is - the remote says head is now at XXX but when i log into the server - the remote working copy is not updated at all!

any idea?

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

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

发布评论

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

评论(3

七分※倦醒 2024-11-05 05:33:48

问题在于 Git 命令在为钩子脚本创建的环境中与正常环境中的行为方式有所不同。

首先,挂钩脚本运行时将其当前工作目录设置为 Git 目录本身(即非裸存储库的 .git/ 目录)。其次,挂钩脚本使用 GIT_DIR 环境变量集运行并指向 Git 存储库(同样是非裸存储库的 .git/ 目录)。

通常,如果您尝试从 .git/ 目录运行 git reset --hard ,它会终止并显示以下消息:

fatal: This operation must be run in a work tree

但是当设置 GIT_DIR 时,Git 命令假定当前目录是工作树。由于钩子运行时的当前目录是 .git/ 目录,因此您的 git reset --hard 实际上是将工作树文件直接“签出”到 中.git/ 而不是其父目录(即您现在在 .git/ 目录中拥有版本化内容的副本)。

希望您的存储库中的版本化内容都没有与 一致的路径名Git 在 Git 存储库本身中使用的路径名。如果它们确实一致,那么您的 git reset --hard 将会覆盖存储库的一些内部结构,您可能需要从其他存储库重新克隆它。如果您确信版本化内容不会与 Git 的内部路径名冲突,那么您可以用以下方法清理它:

# make a backup of your repository first!
(cd .git && GIT_DIR=$PWD git ls-files -cz | xargs -0 rm)

这只会删除当前跟踪的文件(它将留下那些已被删除但曾经被删除过的文件)。在损坏的钩子处于活动状态时推送的提示提交中进行跟踪)。


一种解决方案是在调用 Git 命令之前将当前工作目录更改为正常工作树并取消设置 GIT_DIR 和 GIT_WORK_TREE。

⋮
test "${PWD%/.git}" != "$PWD" && cd .. 
unset GIT_DIR GIT_WORK_TREE
# you can now safely use Git commands
⋮

另一个解决方案是显式重置 GIT_DIR,在那里设置 GIT_WORK_TREE 和 chdir。 Git 常见问题解答 “为什么我看不到“git Push”之后的远程仓库?” 建议更新后< /em> 脚本 就是这样做的。链接脚本也更安全,因为如果在进行硬重置之前索引或工作树脏了,它会进行隐藏。

The issue is a difference in how Git commands behave in the environment created for hook scripts versus your normal environment.

First, hook scripts run with their current working directory set to the Git directory itself (i.e. the .git/ directory of a non-bare repository). Second, hook scripts run with the GIT_DIR environment variable set and pointing to the Git repository (again, the .git/ directory of a non-bare repository).

Normally, if you try to run git reset --hard from the .git/ directory, it will die with the following message:

fatal: This operation must be run in a work tree

But when GIT_DIR is set, Git commands assume that the current directory is the working tree. Since the current directory when the hook runs is the .git/ directory, your git reset --hard is actually “checking out” your working tree files directly into .git/ instead of its parent directory (i.e. you now have a copy of your versioned content in your .git/ directory).

Hopefully none of versioned content in your repository has pathnames that coincide with pathnames that Git uses in Git repositories themselves. If they do coincide, then your git reset --hard will have overwritten some bit of the internal structure of your repository and you will probably want to re-clone it from some other repository. If you are confident that none of the versioned content conflicts with Git’s internal pathnames, then you may be able to clean it up with this:

# make a backup of your repository first!
(cd .git && GIT_DIR=$PWD git ls-files -cz | xargs -0 rm)

This will only remove currently tracked files (it will leave behind files that have since been removed, but were once tracked in tip commits pushed while the broken hook was active).


One solution is to change the current working directory to the normal working tree and unset GIT_DIR and GIT_WORK_TREE before calling Git commands.

⋮
test "${PWD%/.git}" != "$PWD" && cd .. 
unset GIT_DIR GIT_WORK_TREE
# you can now safely use Git commands
⋮

Another solution is to explicitly reset GIT_DIR, set GIT_WORK_TREE and chdir there. The Git FAQ “Why won't I see changes in the remote repo after "git push"?” recommends a post-update script that does just this. The linked script is also much safer since it makes a stash if the index or working tree is dirty before doing the hard reset.

掩于岁月 2024-11-05 05:33:48

简而言之,使用钩子一行:

git --git-dir=. --work-tree=$PWD/.. reset --hard

更准确地说,在服务器上编辑文件.git/hooks/post-receive

#!/bin/sh
git --git-dir=. --work-tree=$PWD/.. reset --hard

将其设置为可执行:

chmod +x .git/hooks/post-receive

从客户端推送到此存储库时,它应该这样说:

HEAD is now at abcd123 comment

In short, use the hook one-liner:

git --git-dir=. --work-tree=$PWD/.. reset --hard

To be more precise, edit the file .git/hooks/post-receive on the server:

#!/bin/sh
git --git-dir=. --work-tree=$PWD/.. reset --hard

Set it executable:

chmod +x .git/hooks/post-receive

When pushing to this repo from the client, it should say something like:

HEAD is now at abcd123 comment
溺ぐ爱和你が 2024-11-05 05:33:48

那么脚本可能没有运行。它不会在哑 http 服务器上运行。
它将通过 ssh 运行。我不确定智能 http 服务器。

如果不是这样,您应该检查钩子上的“执行”权限(chmod +x .git/hooks/post-receive)。当您这样做时,通常要检查所有权和权限。

如果这看起来没问题,只需在脚本中包含一个日志语句作为第一行(例如 date "%T $0 Updated" >> /tmp/debug_hook.log)并检查日志文件以查看是否有任何内容已更新。

此外,推送可能实际上不做任何事情(一切都是最新的)。在这种情况下,不调用挂钩是有道理的。

如果所有这些都没有给出提示,请发布 .git/config,因为它驻留在服务器上(或至少是部分服务器)。 git log -1 HEAD 是否在服务器上给出了预期的结果?您的钩子脚本是否包含任何可能覆盖 GIT_DIR、GIT_WORK_TREE 或 GIT_INDEX_FILE 的内容?

Well the script is probably not run. It will not run over dumb http server.
It will run over ssh. I'm not sure with smart http server.

If it's not that, you ought to check the 'execute' permisssion on the hook (chmod +x .git/hooks/post-receive). While you're at it, generally check owenership and permissions.

If that seems ok, simply include a logstatement as first line in the script (e.g. date "%T $0 executed" >> /tmp/debug_hook.log) and check the logfile to see whether anything got updated.

Also, it is possible for a push to not actually do anything (everything up-to-date). In that case, it makes sense that the hook isn't called

If all this doesn't give a hint, please post .git/config as it resides on the server (or at least part of). Does git log -1 HEAD give the expected outcome on the server? Does your hook script contain anything that may override GIT_DIR, GIT_WORK_TREE or GIT_INDEX_FILE?

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