在mercurial中,有没有办法从已删除的00changelog.d中恢复?

时间:2017-12-01 23:05:49

标签: mercurial

00changelog.d被意外删除了。

有没有办法从中恢复?

或者恢复自上次推送以来所做的更改?

1 个答案:

答案 0 :(得分:4)

技术上可行,尽管有一些信息丢失,因为00changelog.d文件包含诸如变更集作者,提交日期,提交消息和变更集的命名分支之类的信息。也就是说,可以根据00manifest.{d,i}中的父信息高度确定地重建数据。

00changelog.d中的数据是变更集散列的一部分,因此与上游存储库共享的数据完全相同非常重要,因此为了重建更改日志你需要克隆你的上游存储库(本地只有我们有一些余地)。

简而言之,在我们开始之前做好准备:

  • 上游存储库的克隆(让我们假设它在./upstream/中)
  • 本地存储库的备份(让我们假设它在./local-backup/中)
  • 您的本地存储库(让我们假设它在./local/中)
  • rm ./local/.hg/store/00changelog.*从新鲜的石板开始

接下来,您需要我为此次活动编写的以下Mercurial扩展程序:

import os
import weakref

from mercurial.commands import command
from mercurial import scmutil, changelog, error, node

@command('reconstruct', [], '<path to 00changelog.i>')
def reconstruct(ui, repo, changelog_index):
    'reconstructs repository from upstream changelog if local changelog has been deleted'
    other_opener = scmutil.vfs(os.path.dirname(changelog_index),
                               expandpath=True,
                               realpath=True)
    upstream_changelog = changelog.changelog(other_opener)
    local_manifest = repo.manifest
    local_changelog = repo.changelog

    if len(local_changelog) != 0:
        raise error.Abort('not running on repository with actual changelog data')

    local_manifest_nodes = {local_manifest.node(rev): rev for rev in local_manifest}
    reconstructed_manifests = set()
    reconstructed_manifests_map = {}

    lock = repo.lock()
    try:
        tr = repo.transaction('reconstruct')
        trp = weakref.proxy(tr)

        for rev in upstream_changelog:
            data = upstream_changelog.read(upstream_changelog.node(rev))
            prevs = upstream_changelog.parentrevs(rev)
            p1 = node.nullid if prevs[0] == -1 else upstream_changelog.node(prevs[0])
            p2 = node.nullid if prevs[1] == -1 else upstream_changelog.node(prevs[1])
            if data[0] in local_manifest_nodes:
                n = local_changelog.add(data[0], data[3], data[4],
                                       trp, p1, p2,
                                       data[1], data[2], data[5])
                reconstructed_manifests.add(data[0])
                reconstructed_manifests_map[data[0]] = n

        missing_manifests = sorted(
                ((n, r) for n, r in local_manifest_nodes.iteritems()
                        if n not in reconstructed_manifests),
                key=lambda (x,y): y)

        for n, rev in missing_manifests:
            p1, p2 = local_manifest.parents(n)
            p1 = node.nullid if p1 == node.nullid else reconstructed_manifests_map[p1]
            p2 = node.nullid if p2 == node.nullid else reconstructed_manifests_map[p2]

            n2 = local_changelog.add(n, '', 'missing', trp, p1, p2, 'user')
            reconstructed_manifests_map[n] = n2
        tr.close()
    finally:
        if tr:
            tr.release()
        lock.release()

将此文件放在./reconstruct.py中。现在我们能够恢复变化:

  • cd local
  • hg --config extensions.reconstruct=../reconstruct.py reconstruct ../upstream/.hg/store/00changelog.i
  • 等一会儿(没有进展)

所有仅属于本地的更改都会包含完全虚假的更改日志信息,但可以使用histeditmq扩展程序手动修复此问题。

请注意,上面的扩展做了一些简化的假设:清单对应于您的更改日志1:1。由于您只删除了00changelog.d而不是00changelog.i,因此可以使用00changelog.i中更准确的父信息,但这需要更多代码。

另请注意,上面的扩展使用了一些最新的Python功能,因此您的Mercurial需要基于Python 2.7。