作为Lasse V. Karlsen said in a comment,在第一种情况下没有任何反应,因为您没有向遥控器推送任何更新。
当你运行git push 时,你是在告诉你的 Git 通过网络电话调用另一个 Git 并给它一些项目和/或指令。你有两个例子:git push remote_repo master 和 git push remote_repo branch_from_previous_commit。让我们先拿第一个。
您使用的完整序列是:
git checkout <sha1_of_previous_commit>
git push remote_repo master
第一步让你得到 Git 所谓的 分离的 HEAD,这只是意味着你现在不在分支上,因此你所做的任何新提交都将在不更改任何现有的情况下进行分支机构。你什么都没做,所以这还没有关系,然后你告诉你的 Git 告诉他们的 Git 你的 master 分支,这意味着无论你当前的分支是什么——或者在这种情况下,不是——仍然没关系。
你的 Git 调用他们的 Git——在这种情况下是你服务器的 Git;让我们将它称为 S for server——你的 Git 会告诉 S:“请设置你的,S, master 提交 somehash"(其中 somehash 是存储在您的名字 master 中的任何哈希 ID)。 S 检查 他的 master 并且它已经设置为该哈希,1 所以 S em> 什么都不做,然后说“好的,都完成了!”
你的第二个序列做得更多:
git checkout <sha1_of_previous_commit>
git checkout -b branch_from_previous_commit
git push remote_repo branch_from_previous_commit
在这里,您的第一个命令像以前一样分离 HEAD,但是您的第二个命令在您自己的存储库中创建了一个 new 分支名称,指向当前提交,这是您在第一次签出的提交命令。 (顺便说一句,您可以将这两个组合为git checkout -b <name> <hash>。)
这一次,你的 Git 像以前一样调用 S,但不是说“请将你的 master 设置为 hash”,而是说“请设置你的 @ 987654336@ 到 散列。”想必S还没有这样的分支;因为您使用的是 Git 版本 1.9,或者已将您的更高版本的 Git 配置为像旧的 Git 一样工作,所以您的 Git 最终会告诉 S 来创建该分支。同样地,S 确实 创建了那个分支,也就是说,这个推送成功了。现在我们必须看看另一台机器上发生了什么,即从S的角度来看发生了什么。
(有关与您的当前问题大多无关的更多详细信息,请参阅What does GIT PUSH do exactly?)
1我在这里做另一个假设,即您之前成功推送了您的master,或者没有提交您的master。
如 S 上所见
当 Git 电话响起时,您的服务器 S 正在安静地嗡嗡作响。2响铃!响铃! S 应答,这是自称是你的人打来的电话。另一个 Git 说“你好,请将你的 branch_from_previous_commit 设置为 somehash。”您 (S) 检查这是否正确,因此您创建了一个新引用 refs/heads/branch_from_previous_commit,并将其设置为 somehash。然后你会看到你有一个post-receive 钩子,所以你运行它,在它的标准输入上输入这一行(全部作为一行——为了显示的目的,我把它分成三行):
0000000000000000000000000000000000000000
somehashsomehashsomehashsomehashsomehash
refs/heads/branch_from_previous_commit
全零值是一个指示符:“此引用是新的”。非零值是新的哈希。引用名称refs/heads/branch_from_previous_commit 是分支的全名:post-receive 脚本可以判断它是一个 branch 名称,因为名称以refs/heads/ 开头,并且可以获取分支名称通过剥离 refs/heads/ 部分。
如果您的电话要求您创建标签,则全名是refs/tags/sometag;如果它要求您创建六个分支,再更新三个分支,创建一个标签并删除两个分支,您会将所有 12 个名称连同它们的旧哈希 ID 和新哈希 ID 一起输入到 post-receive 脚本中。如果名称是新的,则旧的哈希 ID 为全零;如果名称被删除,则新的哈希 ID 为全零;否则,两个哈希 ID 都不是零,它们是更新的分支或标签的旧值和新值。3
你还没有向我们展示你的脚本,所以现在我必须猜测编辑:你在脚本中添加了一条评论,内容如下:
git --work-tree=/var/www/html/site.com --git-dir=/path/to/remote/bare checkout -f
(甚至没有从标准输入读取)。此脚本错误。4
git checkout 命令采用选项,包括 -f 或 --force,但也包括分支名称。 这个脚本提供什么分支名称?
If a git checkout command is given no branch name, what branch does Git check out? Click on the documentation link to see the following text:
您可以省略<branch>,在这种情况下,命令会退化为“检查当前分支”,这是一个美化的空操作,具有相当昂贵的副作用,仅显示跟踪信息(如果存在)当前分支。
当前分支是什么?请记住,我们是服务器S,在我们的 Git 存储库中工作。我们不是客户。我们正在接听 Git 电话,我们有我们自己的存储库,有自己的分支和自己的 HEAD。 我们的 HEAD 里有什么?
很可能,我们的HEAD 包含分支名称master。所以我们将再次检查我们的master,做(如文档所述)一种昂贵的无操作。我们刚刚收到创建新分支 branch_from_previous_commit 的请求这一事实完全不相关:我们被告知要检查 当前 分支,所以我们这样做了。
请注意,如果我们收到将 我们的 master 更改为新的、不同的哈希的请求,我们会验证这样做是可以的,然后就完成了(前提是可以) ,然后运行我们的post-receive 脚本,该脚本将检查我们的(更新的)master。那会真的做点什么。但这不是我们得到的,也不是我们所做的。
因此,您需要做的至少是以下其中一项:
修改 post-receive 脚本:了解部署不同分支的含义。这比看起来要困难,因为每个 Git 存储库都有一个主 index,而 Git 假设该索引与工作树匹配。如果您设置了多个部署工作树,则必须为每个此类树设置多个索引文件,否则会使索引无效。
使用修改master 分支的推送。
更改服务器上的当前分支。如果部署命令是git checkout 没有分支名称,它将部署当前分支。如果您以某种方式更改它,它将部署不同的提交。如何做到这一点是一个不同的问题,但请注意git checkout <branch-name> 更改了当前分支(同时还检查了该分支的提示提交)。如果您选择喜欢部署脚本,这可能会影响您。
在任何情况下,最好至少一点点设计部署脚本,以扫描正在更新的分支和/或标签,然后运行仅在待部署的分支发生更改时签出部署。这不是必需的,但如果您的服务器将保留多个分支和/或标签,那么它是一个好主意,并且/或标签,只有一个或一些要部署。
2实际上,可能是 ssh-phone 或 https-phone,然后有其他东西接听,最终在确定 是你之后,将手机交给转到 Git。但我们不必担心这一点。
3标签更新需要--force,因为无论如何都是 Git 1.8.2。当且仅当分支更新是非快进时才需要强制。除了这些内置规则之外,如果您愿意,您的 pre-receive 和 update 挂钩可以拒绝所有(预接收)或选定(更新)参考更改。
4或者至少是次优的,尽管它会在最初完成工作。