Git stash堆栈是否被推送到远程仓库?

47

我的stash堆栈是否已推送到远程仓库?还是被完全忽略了?

我只是好奇是否应该偶尔处理一下,将其中的一些内容删除以节省服务器空间。

2个回答

52

不行。存储库是本地的。

$ man git stash:

当您想记录工作目录和索引的当前状态,但希望回到干净的工作目录时,请使用git stash。该命令将保存您的本地修改并还原工作目录以匹配HEAD提交。

不过我不会在本地保留太多这样的内容。随着时间的推移,您会失去对它们的追踪,并且它们变得有些无用。


40
作为一般规则,不行。但如果你想的话,你可以推送它。
关于push(以及fetch),这些都是基于“refspecs”工作的,其中您命名本地引用名称 - 或者对于push和特定情况,原始提交ID - 然后还有远程引用名称。
那么引用名称到底是什么?
大多数情况下,您会命名分支引用,例如master,或像origin/master这样的“远程分支”。令人困惑的是,git所谓的“远程分支”实际上是一个本地实体,而不是远程分支,而是在您的存储库中使用特殊名称的分支。
分支实际上只是一个名称以refs/heads/开头的引用。那几乎就是分支的全部内容。 (关于分支还有另外一件特殊的事情:当您在其中制作新提交时,分支会自动移动。也就是说,如果您在您的主分支上并且您进行了新提交,则git会更新refs/heads/master以指向新提交。)
“远程分支”是一个引用,其名称以refs/remotes/开头,然后包含远程的名称(通常为origin)。因此,refs/remotes/origin/master是一个“远程分支”:它是您存储库中的本地实体,是您的git用于跟踪“上一次与origin检查时master在哪里”的名称。每当您从/推送到origin时,1 git会根据其所看到的内容更新您的origin/branch名称。 标签只是以refs/tags/开头的引用。
通常情况下,你可以省略所有这些前缀,只需写master表示你的主分支在refs/heads/master中,origin/master表示refs/remotes/origin/masterv2.3表示refs/tags/v2.3。Git会自动判断使用哪个前缀,因为这很明显。详细规则请参见gitrevisions。(令人恼火的是,git checkoutgit branch并不总是严格遵循gitrevisions的规则:当它们知道某些东西应该是一个分支名时,它们只是假设refs/heads/部分。然而,其他git命令确实按照描述的方式工作。)

stash脚本使用的引用名称是refs/stash。因此,您可以通过编写stash来命名此引用;Git会发现它既不是分支,也不是远程分支,也不是标签,最终将使用refs/stash来解析名称。2

...这意味着什么?

这意味着如果您编写了以下内容:

$ git push origin stash:ssss

git会查找您的存储(只有一个单独的存储),并尝试将其推送到名为 ssss 的远程引用。这很可能会失败;当我尝试时,发生了以下情况:
error: unable to push to unqualified destination: ssss
The destination refspec neither matches an existing ref on the remote nor
begins with refs/, and we are unable to guess a prefix based on the source ref.
error: failed to push some refs to 'ssh://[redacted]/tmp/t'

只是为了好玩,我尝试了下一个命令,却得到了不同的错误:

$ git push origin stash:refs/ssss
Counting objects: 8, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (4/4), done.
Writing objects: 100% (4/4), 485 bytes | 0 bytes/s, done.
Total 4 (delta 3), reused 0 (delta 0)
remote: error: refusing to create funny ref 'refs/ssss' remotely
To ssh://[redacted]/tmp/t
 ! [remote rejected] stash -> refs/ssss (funny refname)
error: failed to push some refs to 'ssh://[redacted]/tmp/t'

然而,这个有效:

$ git push origin stash:refs/heads/ssss

这次操作在远程创建了一个名为ssss的新分支。你也可以将其推送到远程标签(refs/tags/tagname)。虽然存储区不会将stash视为分支或标签,但你可以像推送分支或标签一样进行推送。一旦你尝试这样做,远程只知道你正在发送某些提交对象及其相关的树、blob等,并且应该将“最高”的提交存储在你提供的(完整)名称下。3 这就是为什么你可以推送原始提交ID来在远程创建标签的原因。
$ git push af7ec93:refs/tags/foo

假设有一个提交ID以af7ec93开头。

关于“stash堆栈”的另一个说明

使用refs/stash引用的reflog创建了“堆栈”。当您写入stash@{1}时,这使用相同的gitrevisions规则来解析为提交ID。由于git push允许您使用任何解析为有效ID的内容,因此您也可以将其推送到远程名称。但是您可能不应该这样做;就像refs/stash下面最顶部的stash项一样,它们作为常规提交没有太多意义。(Stash存储在内部作为合并提交,但其内容被奇怪地打包,尝试将其用作普通提交会产生不太有用的结果。)


1自从git 1.8.2左右以来,在git中这完全是真实的。但在旧版本的git中,特别是在使用git pull时,有时会在获取时跳过更新远程分支。

2如果您查询gitrevisions,您会发现这并不完全准确:它会将stash视为refs/stash,而不是查找分支名称。

3git push通常会自动构建完整名称:如果您正在推送master(即refs/heads/master),则它知道这是一个分支,因此git push master:newbranch将在远程创建refs/heads/newbranch。但是,您也可以拼写完整的名称,以便在远程上创建标签,例如。当您推送空的本地引用以删除远程引用时,此操作也适用于删除操作:git push :refs/tags/delete_me


正如bcmcfc已经说过的那样,保留大量的存储往往是一个不好的想法。相反,我会保留大量的分支(除非我真的想在某些远程上保存它们,否则我会避免推送它们);这些分支有名称,因此更易于管理(但仅仅是一点点)。效率上没有区别,因为stashes和branches都仅用于包含提交-无论是特殊的stash合并提交还是普通提交。但是,如果您使用分支而不是stash,则可能希望确保您的push.default配置为避免推送所有分支。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接