我有两个存储库副本,每个存储库都有几十个存储状态(stash@{0}
,stash@{1}
,...)。
我需要删除其中一个副本,并且我想将所有隐藏的更改从我要删除的副本传输到我将保留的副本。我想保留关于所有藏匿状态的父母和日期的所有信息,以及索引的状态。
我一直在阅读文档,我找不到任何简单/直接的方法来做到这一点。有可能吗?
更新1:我希望将更改保持为存储状态而不是提交的原因之一是,通过使用--index
标志,我可以检索提交和更改工作目录中的两个更改。如果我创建一个提交,我也将破坏隐藏状态的信息,其中父,索引和工作副本彼此不同。我隐藏的状态通常对应于初步测试工作,这些工作远非可编译,没有准备好承诺,而且目前我没有时间经历数十个整理它们。
更新2:我想我知道如何查看我要备份的信息,例如,
$ git show stash{5}
commit eb5731e828f467dbe9214d0e6a350f33898c1363
Merge: c9608582 1d6cb78d
Author: Author <[email protected]>
Date: Wed Sep 20 18:54:51 2017 +0100
清楚地产生工作目录状态(commit
行)和日期的id,而Merge:
行中的id是父提交id和索引的id。
我不知道的是如何将所有这些信息转移到存储库的第二个副本,作为它的新存储状态。
更新3:澄清:存储库的两个副本已经存储了状态。
更新 - 我确实希望继续并与其他人一致认为导致这种情况的工作流程可能不是最好的工作流程。[1]但是每个人都如此忙碌,并没有很多人提供关于你如何从你想去的地方到达你想去的地方的实际答案。所以:
存储信息存储在提交集合中,加上带有大量操作的reflog的ref。处理reflog将是您要求的最难的部分。
reflog不仅被认为是一个本地数据结构(因此不存在共享它的内置行为),但是每个repo可能都有一个冲突的reflog表示本地堆栈状态,并且如何组合它们的问题并不简单。
一种方法可能看起来像这样。我会称回购你正在放弃source
,而你正在保留target
。
首先,在source
中的每个藏匿状态创建易于共享的引用。
$ cd /path/to/source
$ git tag stash-s0 stash
$ git tag stash-s1 stash@{1}
$ git tag stash-s2 stash@{2}
// etc.
您还需要记下所有隐藏消息。他们在藏匿的reflog中。
$ git reflog stash
1111111 stash@{0}: Custom Stash Message Here
2222222 stash@{1}: WIP on master: 1234567 2
(你可以将它们作为注释存储在标签上,但IMO真的不比其他任何东西更方便......)
现在你需要将这些标签(及其历史)复制到target
;这将确保存在所有存储的数据
$ cd /path/to/target
$ git fetch --tags file://localhost/path/to/source
(file://localhost/path/to/source
是source
的一个可能的URL,假设它可以从target
本地访问;你可以使用任何git URL,或者如果source
已经是target
的已配置远程,你可以使用远程名称而不是url。)
现在是棘手的部分;你需要重建stash
上的target
reflog。
首先,您需要跟踪target
s stash
reflog中已有的任何条目。您可以使用标签执行此操作,与source
中的藏匿处相同。
$ git tag stash-t0 stash
$ git tag stash-t1 stash@{1}
// etc.
并且,再次记下现有的存储条目消息
$ git reflog stash
3333333 stash@{0}: WIP on master: 7654321 2
然后你可以删除隐藏ref。通常情况下,我不会绕过git接口,但在这种情况下,它并不像是一种“安全”的方式。
$ rm .git/refs/stash
$ rm .git/logs/refs/stash
最后,您可以构建新的存储堆栈。你的第一个命令是
$ git update-ref --create-reflog -m "<stash-message-1>" refs/stash <tag-name-1>
或者,在新的足够版本的git上
$ git stash store -m "<stash-message-1>" <tag-name-1>
其中<stash-message-1>
和<tag-name-1>
是你记录的藏匿消息,它们现在是堆栈中的最后一个(最旧的/“底部”)存储,以及你用来保存该存储状态的标记。每个后续命令都是
$ git update-ref -m "<stash-message-n>" refs/stash <tag-name-n>
要么
$ git stash store -m "<stash-message-n>" <tag-name-n>
在存储列表中“向前穿越”。
然后你可以取消你使用的标签。
$ git tag -d stash-s1
// ...
[1]在git中创建临时分支然后根据需要使用交互式rebase来清理历史记录是可行的,因为您最终准备将其迁移到“真正的”分支。而且无论如何,存储与真正的提交一样“重量级”,因为存储是真正的提交。藏匿是很好的,可以将一些变化推迟一段时间,这样你就可以快速地使用你的工作树来获得其他东西,但是长寿命藏匿并不是最好的。
存储不是以这种方式移动的,你应该真正做私有分支,你可以做几个提交而不发布它们。但是,由于stashes实际上是作为隐藏提交实现的,所以如果你愿意做一些黑客攻击,你可以复制它们。
这些说明对我有用,但它们可能取决于当前的git版本或其他细节,YMMV:
.git/stash
和.git/logs/refs/stash
从源存储库复制到目标。警告!这将覆盖整个藏匿列表!您可以尝试连接两个.git/logs/refs/stash
文件以合并两个stashes(较旧的第一个),但显然你不能合并存储的提示。git config uploadpack.allowAnySHA1InWant true
。$REFS
):git stash list --format=%H
。git fetch SOURCE $REFS
($REFS
是步骤3的输出)。git stash list
检查目标存储库中的所有内容是否正常。git gc
并检查可能显示缺失数据的任何warning: reflog of 'refs/stash' references pruned commits
消息。诀窍在于git中的stas实际上是作为名为stash
的隐藏引用的reflog实现的。因此,如果您复制ref,reflog并获取所有引用的提交,它将正常工作。并且因为你不能通过哈希获取提交,除非它是公共引用的一部分(并且stash
不是)你需要放松这个条件,这就是为什么你需要uploadpack.allowAnySHA1InWant = true
注意:如果源仓库中没有.git/stash
文件,则表示已打包。您可以使用git rev-parse stash
获取该文件中应包含的内容。
注意2:如果您在目标目录中有藏匿,并且您不认为手动编辑reflog是一个好主意(它不是!),您可以使用不同的名称复制原始的存储文件,例如stash2
。然后你可以用git reflog stash2
看到这个替代藏匿处并用git apply stash2@{N}
应用它们。
将A的存放转移到B和B可能有自己的存储。
git push <path_to_B> stash@{N}:refs/tags/stashN
。运行一个循环来推送它们。git rev-parse refs/stash
并获得哈希值。在B中,运行echo $hash > .git/refs/stash
。用你在A中得到的真实哈希替换$hash
。.git/logs/refs/stash
的内容附加到B的.git/logs/refs/stash
。 B的原始.git/logs/refs/stash
的最后一行是hash1 hash2 name email timestamp message
。 A的第一行是hash3 hash4 name email timestamp message
。在B的附加hash3
中将hash2
更改为.git/logs/refs/stash
。stash0
到stashN
的所有标签。以git tag -d stash0
为例。