Files
pages/2025/10/12/recover.html
2026-01-17 09:36:00 +00:00

322 lines
20 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<!-- Begin Jekyll SEO tag v2.8.0 -->
<title>一次找回GitHub上被删除仓库的经历 | Mayx的博客</title>
<meta name="generator" content="Jekyll v3.9.5" />
<meta property="og:title" content="一次找回GitHub上被删除仓库的经历" />
<meta name="author" content="mayx" />
<meta property="og:locale" content="zh_CN" />
<meta name="description" content="在GitHub中寻找踪迹也许是非常简单的事情……" />
<meta property="og:description" content="在GitHub中寻找踪迹也许是非常简单的事情……" />
<meta property="og:site_name" content="Mayx的博客" />
<meta property="og:type" content="article" />
<meta property="article:published_time" content="2025-10-12T00:00:00+08:00" />
<meta name="twitter:card" content="summary" />
<meta property="twitter:title" content="一次找回GitHub上被删除仓库的经历" />
<meta name="google-site-verification" content="huTYdEesm8NaFymixMNqflyCp6Jfvd615j5Wq1i2PHc" />
<meta name="msvalidate.01" content="0ADFCE64B3557DC4DC5F2DC224C5FDDD" />
<meta name="yandex-verification" content="fc0e535abed800be" />
<script type="application/ld+json">
{"@context":"https://schema.org","@type":"BlogPosting","author":{"@type":"Person","name":"mayx"},"dateModified":"2025-10-12T00:00:00+08:00","datePublished":"2025-10-12T00:00:00+08:00","description":"在GitHub中寻找踪迹也许是非常简单的事情……","headline":"一次找回GitHub上被删除仓库的经历","mainEntityOfPage":{"@type":"WebPage","@id":"/2025/10/12/recover.html"},"publisher":{"@type":"Organization","logo":{"@type":"ImageObject","url":"https://avatars0.githubusercontent.com/u/17966333"},"name":"mayx"},"url":"/2025/10/12/recover.html"}</script>
<!-- End Jekyll SEO tag -->
<link rel="canonical" href="https://mabbs.github.io/2025/10/12/recover.html" />
<link type="application/atom+xml" rel="alternate" href="/atom.xml" title="Mayx的博客" />
<link rel="alternate" type="application/rss+xml" title="Mayx的博客(RSS)" href="/rss.xml" />
<link rel="alternate" type="application/json" title="Mayx的博客(JSON Feed)" href="/feed.json" />
<link rel="stylesheet" href="/assets/css/style.css?v=1768642553" />
<!--[if !IE]> -->
<link rel="stylesheet" href="/Live2dHistoire/live2d/css/live2d.css" />
<!-- <![endif]-->
<link rel="search" type="application/opensearchdescription+xml" href="/opensearch.xml" title="Mayx的博客" />
<link rel="webmention" href="https://webmention.io/mabbs.github.io/webmention" />
<link rel="pingback" href="https://webmention.io/mabbs.github.io/xmlrpc" />
<link rel="preconnect" href="https://summary.mayx.eu.org" crossorigin="anonymous" />
<link rel="prefetch" href="https://www.blogsclub.org/badge/mabbs.github.io" as="image" />
<link rel="blogroll" type="text/xml" href="/blogroll.opml" />
<link rel="me" href="https://github.com/Mabbs" />
<script src="/assets/js/jquery.min.js"></script>
<!--[if lt IE 9]>
<script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery-ajaxtransport-xdomainrequest/1.0.3/jquery.xdomainrequest.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/respond.js/1.4.2/respond.min.js"></script>
<![endif]-->
<script>
var lastUpdated = new Date("Sat, 17 Jan 2026 17:35:53 +0800");
var BlogAPI = "https://summary.mayx.eu.org";
</script>
<script src="/assets/js/main.js"></script>
<!--[if !IE]> -->
<!-- Global site tag (gtag.js) - Google Analytics -->
<script async="async" src="https://www.googletagmanager.com/gtag/js?id=UA-137710294-1"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'UA-137710294-1');
</script>
<script src="/assets/js/instant.page.js" type="module"></script>
<!-- <![endif]-->
</head>
<body>
<!--[if !IE]> --><noscript><marquee style="top: -15px; position: relative;"><small>发现当前浏览器没有启用JavaScript这不影响你的浏览但可能会有一些功能无法使用……</small></marquee></noscript><!-- <![endif]-->
<!--[if IE]><marquee style="top: -15px; position: relative;"><small>发现当前浏览器为Internet Explorer这不影响你的浏览但可能会有一些功能无法使用……</small></marquee><![endif]-->
<div class="wrapper">
<header class="h-card">
<h1><a class="u-url u-uid p-name" rel="me" href="/">Mayx的博客</a></h1>
<img src="https://avatars0.githubusercontent.com/u/17966333" fetchpriority="high" class="u-photo" alt="Logo" style="width: 90%; max-width: 300px; max-height: 300px;" />
<p class="p-note">Mayx's Home Page</p>
<form action="/search.html">
<input type="text" name="keyword" id="search-input-all" placeholder="Search blog posts.." />&#160;<input type="submit" value="搜索" />
</form>
<br />
<p class="view"><a class="u-url" href="/Mabbs/">About me</a></p>
<ul class="downloads">
<li style="width: 270px; border-right: none;"><a href="/MayxBlog.tgz">Download <strong>TGZ File</strong></a></li>
</ul>
</header>
<section class="h-entry">
<small><time class="date dt-published" datetime="2025-10-12T00:00:00+08:00">12 October 2025</time> - 字数统计1736 - 阅读大约需要6分钟 - Hits: <span id="/2025/10/12/recover.html" class="visitors">Loading...</span></small>
<h1 class="p-name">一次找回GitHub上被删除仓库的经历</h1>
<p class="view">by <a class="p-author h-card" href="//github.com/Mabbs">mayx</a></p>
<div id="outdate" style="display:none;">
<hr /><p>
这是一篇创建于 <span id="outime"></span> 天前的文章,其中的信息可能已经有所发展或是发生改变。
</p>
</div>
<script>
daysold = Math.floor((new Date().getTime() - new Date("Sun, 12 Oct 2025 00:00:00 +0800").getTime()) / (24 * 60 * 60 * 1000));
if (daysold > 90) {
document.getElementById("outdate").style.display = "block";
document.getElementById("outime").innerHTML = daysold;
}
</script>
<hr />
<b>AI摘要</b>
<p id="ai-output">这篇文章讲述了作者通过GitHub的Fork特性找回一个被删除的Brainfuck可视化演示仓库的经历。由于原仓库和作者主页都已消失作者推测GitHub在Fork时会共享对象库只要有任意一个Fork仓库存在GitHub就会保留所有对象从而可以通过找到一个Fork仓库的最新提交Hash值来还原目标仓库。作者通过Linux内核仓库的Fork进行验证随后在互联网档案馆上找到目标仓库的Fork以及其Hash值最终通过Git命令将本地仓库的HEAD指针指向目标提交成功恢复了该仓库的代码并将其部署到自己的GitHub Pages上。最后作者发现Software Heritage组织会保存所有代码因此在遇到类似情况时可以直接通过该平台进行查找。</p>
<hr />
<ul><li><a href="#起因">起因</a></li><li><a href="#github的特性">GitHub的特性</a></li><li><a href="#找回仓库">找回仓库</a></li><li><a href="#结局">结局</a></li></ul>
<hr />
<main class="post-content e-content" role="main"><p>在GitHub中寻找踪迹也许是非常简单的事情……<!--more--></p>
<h1 id="起因">
<a href="#起因"><svg class='octicon' viewBox='0 0 16 16' version='1.1' width='16' height='32' aria-hidden='true'><path fill-rule='evenodd' d='M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z'></path></svg></a> 起因
</h1>
<p>前段时间,有人和我聊天的时候提到了<a href="https://esolangs.org/wiki/Brainfuck">Brainfuck</a>语言,让我回想起了高中时写的<a href="/%E6%BC%94%E8%AE%B2%E7%A8%BF/2018/06/20/Coding.html">演讲稿</a>。那时候我在演讲时也介绍了Brainfuck语言。对于Brainfuck的解释器<a href="https://rosettacode.org/wiki/RCBF">各种语言都可以实现</a>不过我当时为了方便理解用了一个在GitHub Pages上的网站用可视化的方式演示了它的运行过程效果很不错。现在既然聊到了自然就想分享一下这个<a href="https://fatiherikli.github.io/brainfuck-visualizer/">演示的网站</a>但我正想打开时发现网站已经404了😰。 </p><p>
在GitHub Pages上的网站都有对应的仓库现在不仅原仓库消失了连作者的<a href="https://github.com/fatiherikli">首页</a>都打不开看样子是完全退出GitHub了……那么我想找到这个网站的想法就无法实现了吗不过GitHub有些有意思的特性也许能帮助我找回这个网站。</p>
<h1 id="github的特性">
<a href="#github的特性"><svg class='octicon' viewBox='0 0 16 16' version='1.1' width='16' height='32' aria-hidden='true'><path fill-rule='evenodd' d='M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z'></path></svg></a> GitHub的特性
</h1>
<p>在GitHub中一个普通的仓库可能没有什么特别的也许就是服务器上的一个文件夹。但是当仓库被其他人Fork的时候就不一样了在执行Fork时显然GitHub不会完整复制整个仓库。否则同一个仓库在服务器上会占用双倍空间这显然不合理。另外想想Git的结构它由提交对象和分支指针构成每次提交都有唯一的Hash值且不会冲突。因此可以推测GitHub在实现Fork时所有被Fork的仓库可能共享同一个对象库而每个用户仓库只保存指针这样所有仓库只会占用增量空间而不会存储重复内容。 </p><p>
但这样也会带来一个问题首先因为很多人可能要共用一部分对象所以也很难确认对象的所有权而且也因为这个原因所有的对象要能被所有人访问。因此在整个Fork网络中只要有一个仓库存在GitHub就必须保留所有的对象而且每个仓库都能访问这个网络中所有的对象。为了验证这一点我们可以用最知名的<a href="https://github.com/torvalds/linux">Linux内核仓库</a>做个示例。 </p><p>
首先对Linux仓库进行Fork然后我们可以随便做一些改动比如在README中写“Linux已经被我占领了😆”之类的内容提交到自己的仓库并且记下提交的Hash值接下来就可以把自己的仓库删掉了。如果上面的猜想是正确的那么在这个Fork网络中的任何一个仓库查看我刚刚的提交应该都可以于是我直接在主仓库拼上了<a href="https://github.com/torvalds/linux/tree/78e1d0446b94012da8639aa2b157d4f2dee481ce">提交的Hash值</a>(顺便一说只要值唯一,和其他的提交不冲突,<a href="https://github.com/torvalds/linux/tree/78e1d044">短的Hash值</a>也可以果不其然能找到刚刚修改的内容这样一来只要GitHub和任意一个Linux仓库的Fork还存在这个提交就永远存在了😝。</p>
<h1 id="找回仓库">
<a href="#找回仓库"><svg class='octicon' viewBox='0 0 16 16' version='1.1' width='16' height='32' aria-hidden='true'><path fill-rule='evenodd' d='M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z'></path></svg></a> 找回仓库
</h1>
<p>那么接下来找回之前网站的方案就很简单了我只要找到网站仓库的任意一个Fork然后只要知道最新的提交Hash我就可以还原最新的仓库了。Fork倒是好找随便搜一下<a href="https://github.com/ashupk/brainfuck-visualizer">就能找到一个</a>。这个Fork的最新提交是2016年但要想找到我当年演讲的版本至少到2018年之后。不过这个Hash值也不太好找虽然理论上爆破短Hash值也可以但是感觉太麻烦了没有那个必要所以我干脆直接去互联网档案馆看看能找到的<a href="https://web.archive.org/web/20201229125043/https://github.com/fatiherikli/brainfuck-visualizer/">最新的仓库页面</a>这样我就能找到它的Hash值了然后我再把Fork仓库的地址和Hash拼到一起就看得到最新代码了。 </p><p>
当然仅仅看到代码还不够。我想Fork这个项目并在自己的GitHub Pages上部署一份。有没有什么好办法可以将我仓库的HEAD指针指向最新的提交呢其实很简单首先我要Fork这个Fork仓库然后Clone我的仓库到本地。不过此时Clone下来的仓库并不包含GitHub上完整的对象库因此直接checkout或reset是不行的。这时Hash值就派上用场了通过fetch拉取对应提交后就可以进行上述操作。具体命令如下</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git fetch origin &lt;commit-hash&gt;
git reset <span class="nt">--hard</span> &lt;commit-hash&gt;
git push origin master
</code></pre></div></div>
<p>最终我就获得了包含<a href="https://github.com/Mabbs/brainfuck-visualizer">最新代码</a><a href="https://mabbs.github.io/brainfuck-visualizer/">Brainfuck可视化演示</a>了🎉。</p>
<h1 id="结局">
<a href="#结局"><svg class='octicon' viewBox='0 0 16 16' version='1.1' width='16' height='32' aria-hidden='true'><path fill-rule='evenodd' d='M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z'></path></svg></a> 结局
</h1>
<p>后来我才知道,原来有一个专门的组织<a href="https://archive.softwareheritage.org">Software Heritage</a>会保存所有代码,根本没必要搞这些花里胡哨的操作😂,像这个仓库也是能很轻易在<a href="https://archive.softwareheritage.org/browse/origin/directory/?origin_url=https://github.com/fatiherikli/brainfuck-visualizer">上面</a>找到这下以后知道了再遇到类似情况就可以直接去Software Heritage查找而不必在互联网档案馆上找线索瞎折腾了🤣。</p></main>
<small style="display: block">tags: <a rel="category tag" class="p-category" href="/search.html?keyword=GitHub"><em>GitHub</em></a> - <a rel="category tag" class="p-category" href="/search.html?keyword=Git"><em>Git</em></a> - <a rel="category tag" class="p-category" href="/search.html?keyword=%E4%BB%A3%E7%A0%81%E6%81%A2%E5%A4%8D"><em>代码恢复</em></a> - <a rel="category tag" class="p-category" href="/search.html?keyword=%E8%BD%AF%E4%BB%B6%E5%AD%98%E6%A1%A3"><em>软件存档</em></a> <span style="float: right;"><a href="https://gitlab.com/mayx/mayx.gitlab.io/tree/master/_posts/2025-10-12-recover.md">查看原始文件</a></span></small>
<h4 style="border-bottom: 1px solid #e5e5e5;margin: 2em 0 5px;">推荐文章</h4>
<p id="suggest-container">Loading...</p>
<script>
var suggest = $("#suggest-container");
$.get(BlogAPI + "/suggest?id=/2025/10/12/recover.html&update=" + lastUpdated.valueOf(), function (data) {
if (data.length) {
getSearchJSON(function (search) {
suggest.empty();
var searchMap = {};
for (var i = 0; i < search.length; i++) {
searchMap[search[i].url] = search[i];
}
var tooltip = $('<div class="content-tooltip"></div>').appendTo('body').hide();
for (var j = 0; j < data.length; j++) {
var item = searchMap[data[j].id];
if (item) {
var link = $('<a href="' + item.url + '">' + item.title + '</a>');
var contentPreview = item.content.substring(0, 100);
if (item.content.length > 100) {
contentPreview += "……";
}
link.hover(
function(e) {
tooltip.text($(this).data('content'))
.css({
top: e.pageY + 10,
left: e.pageX + 10
})
.show();
},
function() {
tooltip.hide();
}
).mousemove(function(e) {
tooltip.css({
top: e.pageY + 10,
left: e.pageX + 10
});
}).data('content', contentPreview);
suggest.append(link);
suggest.append(' - ' + item.date + '<br />');
}
}
});
} else {
suggest.html("暂无推荐文章……");
}
});
</script>
<br />
<div class="pagination">
<span class="prev">
<a href="/2025/09/01/quine.html">
上一篇关于ZIP Quine与自产生程序的探索
</a>
</span>
<br />
<span class="next">
<a href="/2025/11/01/mirrors.html">
下一篇:让博客永恒的探索
</a>
</span>
</div>
<!--[if !IE]> -->
<link rel="stylesheet" href="/assets/css/gitalk.css">
<script src="/assets/js/gitalk.min.js"></script>
<div id="gitalk-container"></div>
<script>
var gitalk = new Gitalk({
clientID: '36557aec4c3cb04f7ac6',
clientSecret: 'ac32993299751cb5a9ba81cf2b171cca65879cdb',
repo: 'mabbs.github.io',
owner: 'Mabbs',
admin: ['Mabbs'],
id: '/2025/10/12/recover', // Ensure uniqueness and length less than 50
distractionFreeMode: false, // Facebook-like distraction free mode
proxy: "https://cors-anywhere.mayx.eu.org/?https://github.com/login/oauth/access_token"
})
gitalk.render('gitalk-container')
</script>
<!-- <![endif]-->
</section>
<!--[if !IE]> -->
<div id="landlord" style="left:5px;bottom:0px;">
<div class="message" style="opacity:0"></div>
<canvas id="live2d" width="500" height="560" class="live2d"></canvas>
<div class="live_talk_input_body">
<form id="live_talk_input_form">
<div class="live_talk_input_name_body" >
<input type="checkbox" id="load_this" />
<input type="hidden" id="post_id" value="/2025/10/12/recover.html" />
<label for="load_this">
<span style="font-size: 11px; color: #fff;">&#160;想问这篇文章</span>
</label>
</div>
<div class="live_talk_input_text_body">
<input name="talk" type="text" class="live_talk_talk white_input" id="AIuserText" autocomplete="off" placeholder="要和我聊什么呀?" />
<button type="submit" class="live_talk_send_btn" id="talk_send">发送</button>
</div>
</form>
</div>
<input name="live_talk" id="live_talk" value="1" type="hidden" />
<div class="live_ico_box" style="display:none;">
<div class="live_ico_item type_info" id="showInfoBtn"></div>
<div class="live_ico_item type_talk" id="showTalkBtn"></div>
<div class="live_ico_item type_music" id="musicButton"></div>
<div class="live_ico_item type_youdu" id="youduButton"></div>
<div class="live_ico_item type_quit" id="hideButton"></div>
<input name="live_statu_val" id="live_statu_val" value="0" type="hidden" />
<audio src="" style="display:none;" id="live2d_bgm" data-bgm="0" preload="none"></audio>
<input id="duType" value="douqilai" type="hidden" />
</div>
</div>
<div id="open_live2d">召唤伊斯特瓦尔</div>
<!-- <![endif]-->
<footer>
<p>
<small>Made with ❤ by Mayx<br />Last updated at 2026-01-17 17:35:53<br /> 总字数614622 - 文章数178 - <a href="/atom.xml" >Atom</a> - <a href="/README.html" >About</a></small>
</p>
</footer>
</div>
<script src="/assets/js/scale.fix.js"></script>
<!--[if !IE]> -->
<script src="/assets/js/main_new.js"></script>
<script src="/Live2dHistoire/live2d/js/live2d.js"></script>
<script src="/Live2dHistoire/live2d/js/message.js"></script>
<!-- <![endif]-->
</body>
</html>