<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>DNKYr的博客</title>
        <link>https://dnkyr.xyz/zh/</link>
        <description>Recent content on DNKYr的博客</description>
        <generator>Hugo -- gohugo.io</generator>
        <language>zh</language>
        <lastBuildDate>Sun, 24 May 2026 16:02:32 -0700</lastBuildDate><atom:link href="https://dnkyr.xyz/zh/index.xml" rel="self" type="application/rss+xml" /><item>
            <title>从零开始写 Git（0）</title>
            <link>https://dnkyr.xyz/zh/post/dgit-0/</link>
            <pubDate>Sun, 24 May 2026 16:02:32 -0700</pubDate>
            <guid>https://dnkyr.xyz/zh/post/dgit-0/</guid>
            <description>&lt;h1 id=&#34;什么是-git&#34;&gt;什么是 Git？&#xA;&lt;/h1&gt;&lt;p&gt;在 Linus 看来，Git 可以代表很多东西——心情好时是 &amp;ldquo;global information tracker&amp;rdquo;，崩溃时则是 &lt;a class=&#34;link&#34; href=&#34;https://git.kernel.org/pub/scm/git/git.git/tree/README?id=e83c5163316f89bfbde7d9ab23ca2e25604af290&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;&amp;ldquo;goddamn idiotic truckload of sh*t&amp;rdquo;&lt;/a&gt;。它是 Linus Torvalds 在 2005 年 4 月用大概 7 天写出来的分布式版本控制工具。创造出来的目的是让 Linux 内核的开发变得便捷（而不是用邮件来发送源码）。随着近些年的发展，Git 已经是全球开发者和软件工程师不得不日常使用的一个工具。建立在 Git 之上的 &lt;a class=&#34;link&#34; href=&#34;https://www.github.com&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;GitHub&lt;/a&gt; 已经是全球最大的代码托管平台。&lt;/p&gt;&#xA;&lt;h1 id=&#34;到底什么是-git&#34;&gt;到底什么是 Git？&#xA;&lt;/h1&gt;&lt;p&gt;我先来讲一个我认识的人的事。ta 每次写作文的时候都喜欢写很多不同的版本（初稿、第二稿、终稿、终终稿、绝对不改稿、绝对绝对不改-终稿……）。每次写的时候都必须复制一个上一版本的作文来进行修改。&lt;/p&gt;&#xA;&lt;p&gt;如果是编程的话，情况就会更加复杂。修改一个 bug 可能会导致更多 bug 的出现。可能我修到一半不想修了想回去，我都不知道哪个才是我一开始的版本。每次都手动复制粘贴的话，人早就迷失了。&lt;/p&gt;&#xA;&lt;p&gt;而 Git 就是把复制存储这些自动化，并且加了些小功能，比如 &lt;code&gt;diff&lt;/code&gt;（可以看到和上个版本的区别）、&lt;code&gt;log&lt;/code&gt;（可以看到不同版本之间的依赖关系）等等。&lt;/p&gt;&#xA;&lt;h1 id=&#34;为什么我要重新写-git&#34;&gt;为什么我要重新写 Git？&#xA;&lt;/h1&gt;&lt;p&gt;早些时候，我在油管上刷视频的时候，看到了 &lt;a class=&#34;link&#34; href=&#34;https://www.youtube.com/@ThePrimeTimeagen&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;ThePrimeagen&lt;/a&gt; 在说 Linus Torvalds 在没有 AI、没有 LLM 的情况下用 7 天就写出了一个能跑的 Git 版本。而现在的计科学生有 ChatGPT、有 Claude 的帮助，各种文章来解释 Git 的原理，重新写一个 Git 的克隆版十分简单，最多一两个月就可以做到。这个过程也能让人了解 Git 的实际工作原理和基本的文件系统操作（如创建、删除文件/文件夹，计算 SHA-1，文件路径搜索，读写文件等）。&lt;/p&gt;&#xA;&lt;p&gt;当时的我又对 Rust 十分感兴趣，于是就打算用 Rust 来写一个 Git 实现。在开写之前，我找 Claude 验证了一下这个项目的可行性：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img alt=&#34;Claude discussing writing Git in Rust&#34; class=&#34;gallery-image&#34; data-flex-basis=&#34;180px&#34; data-flex-grow=&#34;75&#34; height=&#34;1011&#34; loading=&#34;lazy&#34; sizes=&#34;(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px&#34; src=&#34;https://dnkyr.xyz/zh/post/dgit-0/Claude-discussion-git-rust.png&#34; width=&#34;762&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;理论可行，并且写 Git 并不需要使用复杂的 lifetime、borrow checker、async 等 Rust 生态内比较困难的特性，所以并没有一个十分复杂的学习曲线。&lt;/p&gt;&#xA;&lt;h1 id=&#34;git-的实现方式&#34;&gt;Git 的实现方式&#xA;&lt;/h1&gt;&lt;p&gt;在 Git 里，所有东西都是一个 object 存储在 &lt;code&gt;.git/objects&lt;/code&gt; 文件夹里面。&lt;/p&gt;&#xA;&lt;p&gt;以下是存储在 objects 文件夹里面的 4 种 object：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;&lt;strong&gt;Blob&lt;/strong&gt;：一个 blob 代表一个文件，用 bytes string 存储 &lt;code&gt;blob &amp;lt;size&amp;gt;\0&amp;lt;content&amp;gt;&lt;/code&gt;，再用 SHA-1 来生成独属于每个文件状态的哈希值，相当于一个对文件状态的快照。通过 SHA-1 可以在 objects 目录中找到对应的文件内容。原始的文件名则存储在引用该 blob 的 tree object 中。&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;&lt;strong&gt;Commit&lt;/strong&gt;：这是一般使用 Git 的人接触最多的 object（&lt;code&gt;git commit&lt;/code&gt;）。一个 commit 由这几个部分组成：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;代表目前 repository 状态的 tree&lt;/li&gt;&#xA;&lt;li&gt;代表上一个 commit 的 parent（如果是第一个 commit 的话，此行为空）&lt;/li&gt;&#xA;&lt;li&gt;作者&lt;/li&gt;&#xA;&lt;li&gt;committer（早些时候的 Git 并没有 remote，开发者都是用邮件来传达源码的，所以会导致编写源码的人和提交的人并不是同一个人）&lt;/li&gt;&#xA;&lt;li&gt;commit 名称&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;&lt;strong&gt;Tag&lt;/strong&gt;：一个 tag 是一个指向某个 commit 的引用，通常用于标记发布版本（如 v1.0、v2.0）。它也可以附带一个标签信息（annotated tag），包含作者、日期和签名等内容。&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;&lt;strong&gt;Tree&lt;/strong&gt;：一个 tree 里带有很多个 blob，相当于对当前 Git worktree 的一个整体快照。Tree 也拥有独属于自己的 SHA-1 编号。&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;&lt;img alt=&#34;A flowchart showing .git/objects internal implementation&#34; class=&#34;gallery-image&#34; data-flex-basis=&#34;322px&#34; data-flex-grow=&#34;134&#34; height=&#34;1068&#34; loading=&#34;lazy&#34; sizes=&#34;(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px&#34; src=&#34;https://dnkyr.xyz/zh/post/dgit-0/git-object-implementation.png&#34; srcset=&#34;https://dnkyr.xyz/zh/post/dgit-0/git-object-implementation_hu_442ebdb505a07329.png 800w, https://dnkyr.xyz/zh/post/dgit-0/git-object-implementation.png 1437w&#34; width=&#34;1437&#34;&gt;&lt;/p&gt;&#xA;&lt;h1 id=&#34;plumbing-vs-porcelain&#34;&gt;Plumbing vs. Porcelain&#xA;&lt;/h1&gt;&lt;p&gt;在 Git 的日常使用命令当中：&lt;code&gt;commit&lt;/code&gt;、&lt;code&gt;push&lt;/code&gt;、&lt;code&gt;add&lt;/code&gt;、&lt;code&gt;reset&lt;/code&gt;、&lt;code&gt;switch&lt;/code&gt;、&lt;code&gt;pull&lt;/code&gt; 都属于 porcelain 命令。它们并不会直接操作底层的 object。这些也是 Linus 在写完 Git 转交给 Junio Hamano 之后才增加的便于日常使用的命令。&lt;/p&gt;&#xA;&lt;p&gt;Linus 在那七天主要是写出了 Git 的 plumbing 命令：&lt;code&gt;cat-file&lt;/code&gt;、&lt;code&gt;hash-object&lt;/code&gt;、&lt;code&gt;ls-tree&lt;/code&gt;、&lt;code&gt;log&lt;/code&gt;、&lt;code&gt;init&lt;/code&gt; 等直接操作单个 object 的命令。而这些命令也是此文要实现的目标。&lt;/p&gt;&#xA;&lt;h1 id=&#34;为什么要用-rust-来写&#34;&gt;为什么要用 Rust 来写？&#xA;&lt;/h1&gt;&lt;p&gt;Linus 的 Git 是用 C 来实现的。C 的特点是底层并且要求开发者手动控制内存。这就导致 C 在运行时十分快速，但在开发者疏忽的情况下容易发生内存泄漏等 bug。&lt;/p&gt;&#xA;&lt;p&gt;其他语言（如 Go、JavaScript、Python）则使用垃圾收集器来在程序运行时自动回收内存，但缺点是垃圾收集器会导致程序运行速度的减慢。&lt;/p&gt;&#xA;&lt;p&gt;而 Rust 通过特色的 borrow checker 和 lifetime 机制，达到了在编译时就可以防止内存泄漏的效果。这就让 Rust 有 C 一样快的速度和 Go 一样的安全特性。&lt;/p&gt;&#xA;&lt;p&gt;&lt;del&gt;其实就是入了 Rust 邪教&lt;/del&gt;&lt;/p&gt;&#xA;&lt;p&gt;总之，这个 Git project 就是一个让我上手 Rust 的小练手项目。那让我们开始吧！&lt;/p&gt;&#xA;&lt;h1 id=&#34;rust-开发环境配置&#34;&gt;Rust 开发环境配置&#xA;&lt;/h1&gt;&lt;h2 id=&#34;通用配置macos--linux&#34;&gt;通用配置（macOS / Linux）&#xA;&lt;/h2&gt;&lt;p&gt;如果你使用 macOS 或常见的 Linux 发行版（Debian、RedHat、Arch 等），可以直接用一行命令安装：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;curl --proto &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;=https&amp;#39;&lt;/span&gt; --tlsv1.2 -sSf https://sh.rustup.rs | sh&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;你也可以使用系统的软件包管理器来安装（如 Homebrew、apt、dnf、pacman 等）。具体如何安装可以参考 &lt;a class=&#34;link&#34; href=&#34;https://www.rust-lang.org/tools/install/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;Rust 官网&lt;/a&gt; 和你的发行版对应的 wiki。&lt;/p&gt;&#xA;&lt;h2 id=&#34;我的配置nixos&#34;&gt;我的配置（NixOS）&#xA;&lt;/h2&gt;&#xA;    &lt;blockquote&gt;&#xA;        &lt;p&gt;如果你不用 NixOS，下面的内容不太通用，可以跳过。&lt;/p&gt;&#xA;&#xA;    &lt;/blockquote&gt;&#xA;&lt;p&gt;我个人使用 NixOS 来作为我的日常使用和开发的发行版。它的特性是可复刻性和声明式配置方法。通过类似于 Git 的 SHA-1 的方式在 &lt;code&gt;/nix/store&lt;/code&gt; 里来管理不同软件包的版本和依赖。总的来说，就是一般系统的安装 Rust 方法不适用于我的系统。&lt;/p&gt;&#xA;&lt;p&gt;我安装 Rust 开发环境的方法是用 Nix flake 来创造出一个 dev shell，再通过 direnv 让我进入这个项目的时候就自动进入 dev shell。如果你写过 JavaScript / Go / Rust / Python 等语言的话，你可以把 &lt;code&gt;flake.nix&lt;/code&gt; 看作是 &lt;code&gt;package.json&lt;/code&gt; / &lt;code&gt;go.mod&lt;/code&gt; / &lt;code&gt;Cargo.toml&lt;/code&gt; / &lt;code&gt;pyproject.toml&lt;/code&gt;。&lt;code&gt;flake.nix&lt;/code&gt; 也会生成一个 &lt;code&gt;flake.lock&lt;/code&gt;，就像是 &lt;code&gt;package-lock.json&lt;/code&gt; / &lt;code&gt;go.sum&lt;/code&gt; / &lt;code&gt;Cargo.lock&lt;/code&gt; / &lt;code&gt;poetry.lock&lt;/code&gt; 这些锁定依赖软件包的工具。&lt;/p&gt;&#xA;&lt;p&gt;当然我不需要从零开始写一个开发 Rust 的 Nix flake。Nix 自己自带了一个开发 Rust 的模板。在文件夹里面打开 shell 运行：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;nix flake init -t templates#rust&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;就会生成以下的 &lt;code&gt;flake.nix&lt;/code&gt;：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-nix&#34; data-lang=&#34;nix&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  inputs &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    naersk&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;url &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;github:nix-community/naersk/master&amp;#34;&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    nixpkgs&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;url &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;github:NixOS/nixpkgs/nixpkgs-unstable&amp;#34;&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    utils&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;url &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;github:numtide/flake-utils&amp;#34;&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  };&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  outputs &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      self&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      nixpkgs&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      utils&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      naersk&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    utils&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;lib&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;eachDefaultSystem (&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      system:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        pkgs &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; nixpkgs { &lt;span style=&#34;color:#66d9ef&#34;&gt;inherit&lt;/span&gt; system; };&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        naersk-lib &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; pkgs&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;callPackage naersk { };&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#66d9ef&#34;&gt;in&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        defaultPackage &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; naersk-lib&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;buildPackage &lt;span style=&#34;color:#e6db74&#34;&gt;./.&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        devShell &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#66d9ef&#34;&gt;with&lt;/span&gt; pkgs;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          mkShell {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            buildInputs &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; [&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              cargo&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              rustc&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              rustfmt&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              pre-commit&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              rustPackages&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;clippy&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            ];&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            RUST_SRC_PATH &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; rustPlatform&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;rustLibSrc;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          };&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    );&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;之后只要在这个 &lt;code&gt;flake.nix&lt;/code&gt; 所在的目录运行：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;nix develop&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;就会生成一个 &lt;code&gt;flake.lock&lt;/code&gt; 和一个安装了 cargo（Rust 包管理器）、rustc（Rust 编译器）、rustfmt（Rust formatter）、clippy（Rust linter）的开发环境。&lt;/p&gt;&#xA;&lt;p&gt;如果你嫌每次进入开发环境都需要输入命令太麻烦的话，你可以使用 direnv 来自动化这个命令。创建一个 &lt;code&gt;.envrc&lt;/code&gt; 文件在根目录里，并且输入：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;use flake&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;就可以自动进入开发环境了。&lt;/p&gt;&#xA;&lt;h1 id=&#34;小结&#34;&gt;小结&#xA;&lt;/h1&gt;&lt;p&gt;这篇文章简单概括了：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Git 的作用&lt;/li&gt;&#xA;&lt;li&gt;我重写 Git 的理由&lt;/li&gt;&#xA;&lt;li&gt;Git 的内部对象模型（Blob、Commit、Tag、Tree）&lt;/li&gt;&#xA;&lt;li&gt;Plumbing 与 Porcelain 命令的区别&lt;/li&gt;&#xA;&lt;li&gt;Rust 的特性&lt;/li&gt;&#xA;&lt;li&gt;开发环境的配置&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;&lt;strong&gt;下篇文章将正式开始重写 Git。&lt;/strong&gt;&lt;/p&gt;&#xA;</description>
        </item></channel>
</rss>
