<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/"
    xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ Lai Weiqing - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ freeCodeCamp 是一个免费学习编程的开发者社区，涵盖 Python、HTML、CSS、React、Vue、BootStrap、JSON 教程等，还有活跃的技术论坛和丰富的社区活动，在你学习编程和找工作时为你提供建议和帮助。 ]]>
        </description>
        <link>https://www.freecodecamp.org/chinese/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ Lai Weiqing - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/chinese/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Sat, 23 May 2026 08:28:40 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/chinese/news/author/weiqinglai/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ 如何克服程序员的障碍？5 个建议帮助你保持高效率 ]]>
                </title>
                <description>
                    <![CDATA[ 作为程序员，我们可能有一些类似的经历。 一个是分号（;）、方括号（[]）和括号（{}）带来的困扰——谁没花过几个小时去寻找它们放错位置或者哪里遗漏了呢？ 另一个是当我们不想做任何事情的时候，学会利用代码编译的时间偷懒休息。 但是，最普遍的经历是被称为 coder's block 的情况，也就是程序员的障碍，它可能让你无缘无故地写不出任何有用的代码。 就像作家的障碍一样，它可能会突然困扰程序员，并且几乎是不可能克服的。我知道这个情况，因为它曾经在我身上发生过很多次。所以，我经常有挫败感，做一些职业测验 [https://www.training.com.au/ed/career-quiz/]，因为我想自己肯定在职业路线上走入了误区。 幸运的是，我找到了几种方法来克服程序员的障碍。自那以后，我的工作一直很顺利。我想它们适用于任何容易陷入到编码障碍的人。 你可以每天使用下面五种方法，保持生产力，并摆脱程序员的障碍。 在纸上开始每个项目 几乎每次我在编写项目遇到麻烦的时候，我都能追溯到一个特定的原因。这是因为我一开始就想去关注项目的所有细节。 当你这样做的时候，即使是一个普通的 ]]>
                </description>
                <link>https://www.freecodecamp.org/chinese/news/how-to-beat-coders-block-and-stay-productive/</link>
                <guid isPermaLink="false">60e1bb080f76ab0660b14067</guid>
                
                    <category>
                        <![CDATA[ 效率 ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Lai Weiqing ]]>
                </dc:creator>
                <pubDate>Sat, 03 Jul 2021 12:00:00 +0000</pubDate>
                <media:content url="https://chinese.freecodecamp.org/news/content/images/2021/07/coders-block-tips.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>作为程序员，我们可能有一些类似的经历。</p>
<p>一个是分号（;）、方括号（[]）和括号（{}）带来的困扰——谁没花过几个小时去寻找它们放错位置或者哪里遗漏了呢？</p>
<p>另一个是当我们不想做任何事情的时候，学会利用代码编译的时间偷懒休息。</p>
<p>但是，最普遍的经历是被称为 coder's block 的情况，也就是程序员的障碍，它可能让你无缘无故地写不出任何有用的代码。</p>
<p>就像作家的障碍一样，它可能会突然困扰程序员，并且几乎是不可能克服的。我知道这个情况，因为它曾经在我身上发生过很多次。所以，我经常有挫败感，做一些<a href="https://www.training.com.au/ed/career-quiz/">职业测验</a>，因为我想自己肯定在职业路线上走入了误区。</p>
<p>幸运的是，我找到了几种方法来克服程序员的障碍。自那以后，我的工作一直很顺利。我想它们适用于任何容易陷入到编码障碍的人。</p>
<p>你可以每天使用下面五种方法，保持生产力，并摆脱程序员的障碍。</p>
<h2 id="">在纸上开始每个项目</h2>
<p>几乎每次我在编写项目遇到麻烦的时候，我都能追溯到一个特定的原因。这是因为我一开始就想去关注项目的所有细节。</p>
<p>当你这样做的时候，即使是一个普通的编码项目，你也很容易被它庞大的规模所吓倒。另外，在没有具体想法的情况下就开始编写代码总是会导致灾难。</p>
<p>相反，首先要在纸上勾勒出项目的粗略轮廓，这是有经验的程序员习惯做的事情，但初级程序员往往会选择跳过。</p>
<p>你所要做的就是写出你尝试创建的程序的目的，然后是列一个你认为满足所有需求的子功能列表。</p>
<p>这个简单的动作可以帮助你将项目分解为看起来并不会令人生畏的较小的逻辑块，而且它让你有机会提前发现可能会在以后减慢你的进度的明显问题。</p>
<p>当你这样做完以后，你可以把工作大纲转换成自己喜欢的在线日历，这能帮你可视化构成项目的所有小任务。</p>
<p>对我来说，有一个完整的项目时间表，我就可以更轻松地一次专注于工作的一个逻辑部分。</p>
<p>可能是因为它消除了一个庞大项目给人的压力，或者减轻了完成每个部分的时间压力，这种方法有助于缓解我们的焦虑。</p>
<h2 id="">在沙箱中找到乐趣</h2>
<p>有时候克服程序员的障碍的最佳方法是做出一些东西——任何有效的东西。所以，如果我感觉脑子转不过来，我就会在沙箱中尝试构建一些有趣的东西。</p>
<p>因为我更多是做 Web 前端开发，所以我的首选站点是 <a href="https://codesandbox.io/">CodeSandbox</a> 和 <a href="https://codepen.io/">CodePen</a>。可能还有其他站点更适合你的需求。</p>
<p>比如，<a href="https://repl.it/">Replit</a> 支持超过 50 种编程语言来编写代码。如果你遇到困难，你甚至可以在他们的社区里寻求帮助。</p>
<p>有时候，和其他程序员来回碰撞，提出想法，可以帮助你打破阻碍你继续工作的思维僵局。</p>
<h2 id="">维护一个待办事项列表</h2>
<p>当我想在某个项目取得进展的时候，没有一个简单任务的列表，也会让我产生程序员障碍。</p>
<p>换句话说，当你在做一些特别具有挑战性的事情而陷入困境的时候，你也不希望就这样被困住，什么都不能做。</p>
<p>为了避免这种情况，你应该在每个项目的生命周期内维护一个实时更新的待办任务列表。我使用 <a href="https://www.scrum.org/resources/what-is-a-product-backlog">Scrum 产品待办列表</a>（即使我不需要和团队协作的时候，我也会用它）。</p>
<p>在列表里列出代码重构和外观更改之类的任务——换句话说，即简单且低优先级的任务。当你被一些难的任务困住的时候，你可以先解决这些简单的事情，这也是在推进你的项目。</p>
<p>有时候，完成简单任务有助于你重新找到成就感，打开思维。</p>
<h2 id="">有策略地休息</h2>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/03/tired-coder.jpg" alt="tired-coder" width="600" height="400" loading="lazy"><br>
<em>Image: Monstar Studio / Adobe Stock</em></p>
<p>如果你花点时间搜索“程序员的障碍”，你会看到很多文章都建议你在面对编程挑战时先休息一下。</p>
<p>好吧，休息也是一把双刃剑，因为一不小心你就会拖延，这样休息会导致更大的问题。</p>
<p>当我第一次去探索克服程序员的障碍的技巧的时候，我就意识到了这一点。刚开始，我对我的休息时间非常负责——当我想理清头绪时，只需要散步五分钟或走到咖啡机面前。</p>
<p>但很快，我发现自己在找理由让自己在所坚持的事情上分心，比如我花了半天时间在网上搜索价格合理的显卡。</p>
<p>所以，休息是你尝试突破程序员的障碍的好方法，但是你需要有策略地休息。</p>
<p>我最后发现，使用有时间限制、远离计算机的休息作为我大脑有意重置过程的最后一步非常有效。当我陷入困境的时候，我就会像下面这样做：</p>
<ul>
<li>花 15 分钟解决问题</li>
<li>花 5 分钟从头开始回顾所有事情</li>
<li>再花 15 分钟解决问题</li>
<li>走开至少 10 分钟，做一些与编码无关的事情</li>
<li>重复上述步骤</li>
</ul>
<p>几乎每次我都能在休息 10 分钟后找到我想要的答案。再继续休息下去你可能会分心，以至于会忘记休息前结束的地方和逻辑思路。这就是为什么只能短暂休息，然后立即要重新开始的原因。</p>
<p>如果你够幸运的话，你可能不用经常重复上述过程。这样你就可以保持专注，避免在非生产性任务上浪费太多时间。</p>
<p>但是要小心，不要完全跳过休息时间。你确实需要时不时地暂停工作，以放松大脑。</p>
<p>我习惯在上午的日程安排中少休息会儿，抽出一些时间跟随 YouTube 上的<a href="https://www.top10.com/workout-channels-on-youtube">锻炼频道</a>做运动。</p>
<h2 id="">总是留下面包屑痕迹</h2>
<p>对于程序员的障碍来说，“预防为主，治疗为辅”这句老话再正确不过了。这就是我养成了在编码项目中控制何时以及如何停止工作的习惯的原因。</p>
<p>我这样做是因为我发现当我试图从中断的地方重新开始的时候时，我正在做的那些被打断和没完成的事情只会让我感觉到头疼。</p>
<p>相反，如果我需要停止做某件事，我会留下特定和详细的笔记告诉我接下来要做什么。即使很匆忙，我也会留下面包屑的痕迹，这样我回来时就不必从头回溯做了什么工作了。</p>
<p>它为我省去了重新进入“编程模式”的麻烦，因为我不必费力地想上次中断的地方在哪。而且我不会在寻找重新开始的位置时过度分析已经完成的代码的漏洞。</p>
<p>这两种情况都会让你慢下来，并导致你陷入程序员的障碍。自从我开始给自己留下一些面包屑的痕迹以后，我就再也没有遇到过这两个问题了。</p>
<h2 id="">成为一个势不可挡的程序员</h2>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/03/cheerful-positive-coder.jpg" alt="cheerful-positive-coder" width="600" height="400" loading="lazy"></p>
<p><em>Image: deagreez / Adobe Stock</em></p>
<p>我不能向你保证这五种方法可以让你远离程序员的障碍。但我可以告诉你的是，它们会帮助你远离导致程序员的障碍的一些常见情况。</p>
<p>自从我在编程时运用这些方法之后，我就没有在某个问题上停留超过一两个小时——这是来自一个不止一次想要放弃编程、转行的人的经验。</p>
<p>即使它们对你的效果只有一半，你也会成为一个势不可挡的程序员！</p>
<p><em>Featured image: DragonImages / Adobe Stock</em></p>
<!--kg-card-end: markdown--><p>原文：<a href="https://www.freecodecamp.org/news/how-to-beat-coders-block-and-stay-productive/">How to Beat Coder's Block – Five Tips to Help You Stay Productive</a>，作者：<a href="https://www.freecodecamp.org/news/author/andrej/">Andrej Kovacevic</a></p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ 阅读 Git 代码，提升你的编程技能 ]]>
                </title>
                <description>
                    <![CDATA[ 现今有很多时新的方法可以帮你提升编程知识和技能，比如：  * 参加一个免费或付费的在线编程课程  * 读一本编程书  * 选择一个个人项目，通过编写代码来动手学习  * 跟随一个在线教程项目去学  * 多关注一些编程博客的最新动态并保持同步 每一种方法都会吸引不同的人，并且每种方法里都有些东西肯定会使你成为一个更好的程序员。如果你是一个中级或高级程序员，那几乎可以肯定这里的每种方法你已经尝试了至少一次。 但是，绝大多数开发人员都忽略了另一种方法，我认为这很可惜，因为它可以学到很多东西。这种方法就是通过阅读、分析和理解现有的高质量代码库来学习！ 我们很幸运地生活在这样一个经常可以通过高质量、免费和开源（FOSS）项目免费访问优质代码的时代， 而且从 GitHub 或 BitBucket 之类的网站上将这些代码库的副本克隆到我们的本地计算机上，只需不到一分钟的时间。 此外，像 Git 这样的现代版本控制系统让我们可以查看软件开发历史中任意节点的代码。显然，我们眼前能看到大量丰富的信息！ 在本文中，我们将讨论 Git 代码的原始版本，以分析如何通过阅读现有代码帮助提升你的编程技能 ]]>
                </description>
                <link>https://www.freecodecamp.org/chinese/news/boost-programming-skills-read-git-code/</link>
                <guid isPermaLink="false">606d7a41b3b14e058ee04a12</guid>
                
                    <category>
                        <![CDATA[ Git ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Lai Weiqing ]]>
                </dc:creator>
                <pubDate>Wed, 07 Apr 2021 09:35:00 +0000</pubDate>
                <media:content url="https://chinese.freecodecamp.org/news/content/images/2021/04/christian-wiediger-i2cwRt3WxZk-unsplash.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>现今有很多时新的方法可以帮你提升编程知识和技能，比如：</p>
<ul>
<li>参加一个免费或付费的在线编程课程</li>
<li>读一本编程书</li>
<li>选择一个个人项目，通过编写代码来动手学习</li>
<li>跟随一个在线教程项目去学</li>
<li>多关注一些编程博客的最新动态并保持同步</li>
</ul>
<p>每一种方法都会吸引不同的人，并且每种方法里都有些东西肯定会使你成为一个更好的程序员。如果你是一个中级或高级程序员，那几乎可以肯定这里的每种方法你已经尝试了至少一次。</p>
<p>但是，绝大多数开发人员都忽略了另一种方法，我认为这很可惜，因为它可以学到很多东西。这种方法就是<strong>通过阅读、分析和理解现有的高质量代码库来学习！</strong></p>
<p>我们很幸运地生活在这样一个经常可以通过高质量、免费和开源（FOSS）项目免费访问优质代码的时代， 而且从 GitHub 或 BitBucket 之类的网站上将这些代码库的副本克隆到我们的本地计算机上，只需不到一分钟的时间。</p>
<p>此外，像 Git 这样的现代版本控制系统让我们可以查看软件开发历史中任意节点的代码。显然，我们眼前能看到大量丰富的信息！</p>
<p>在本文中，我们将讨论 Git 代码的原始版本，以分析如何通过阅读现有代码帮助提升你的编程技能。</p>
<p>我们将介绍为什么有关 Git 的代码值得学习，如何访问 Git 的代码以及回顾一些相关的 C 语言编程概念。</p>
<p>我们将概述 Git 的原始代码库结构，并学习如何在代码中实现 Git 的核心功能。</p>
<p>最后，我们将为好奇的开发人员推荐一些后续步骤，以便他们继续从 Git 的代码和其他项目中学习。</p>
<h2 id="git">为什么要学习关于 Git 的代码呢？</h2>
<p>对于中级开发人员来说，Git 的代码库是用来进一步提高他们的编程知识和技能的一个极好资源。以下是 Git 代码值得深入研究的 7 个原因：</p>
<ol>
<li>
<p>Git 可能是当今使用的最受欢迎的软件开发工具。简而言之，如果你是开发人员，则可能会使用 Git。学习 Git 的代码如何工作将使你对每天使用的基本工具有更深入的了解。</p>
</li>
<li>
<p>Git 很有趣！Git 是一种多功能工具，可以解决许多有趣的问题，能帮助开发人员在代码上进行协作。作为一个好奇的人，我非常喜欢学习更多有关它的知识。</p>
</li>
<li>
<p>Git 的代码是用 <strong>C</strong> 语言编写的，这给开发人员提供了一个很好的机会，使他们可以了解一种以前可能很少使用的重要语言。</p>
</li>
<li>
<p>Git 利用了许多重要的编程概念，包括 <em>内容寻址数据库、文件压缩/解压缩、哈希函数、缓存</em> 和 <em>简单数据模型</em> 。Git 的代码说明了如何在实际项目中实现这些概念。</p>
</li>
<li>
<p>Git 的代码和设计非常<em>优雅</em>。这是一个功能强大的极简代码库的一个很好的示例，它可以清晰有效地实现其目标。</p>
</li>
<li>
<p>Git 的初始提交代码很小，它仅由 10 个文件组成，总共包含少于 1,000 行代码。与大多数其他项目相比这是非常小的，并且理解起来不会花费很多时间。</p>
</li>
<li>
<p>Git 的初始提交代码可以成功编译和执行。这意味着你可以使用并测试 Git 代码的原始版本，以了解其工作原理。</p>
</li>
</ol>
<p>现在，让我们看一看要如何访问 Git 代码的原始版本。</p>
<h2 id="git">如何查看 Git 的初始提交代码呢？</h2>
<p>Git 代码库的正式副本托管在 <a href="https://github.com/git/git">GitHub 公开仓库</a>中。但是，我创建了 Git 代码库的一个分支，并在源码中添加了大量的行内注释以帮助开发人员轻松地逐行阅读它。</p>
<p>由于这是我 Git 历史上的第一次提交，所以我把项目命名为 <strong>Baby Git</strong>。Baby Git 的代码库托管在 <a href="https://bitbucket.org/jacobstopak/baby-git">BitBucket 公开仓库</a> 中。</p>
<p>我建议通过在终端中运行以下命令将 Baby Git 代码库克隆到你的本地计算机：</p>
<pre><code class="language-sh">git clone https://bitbucket.org/jacobstopak/baby-git.git
</code></pre>
<p>如果你想坚持使用 Git 的原始代码库（即无需我所添加的大量注释），请改用以下命令：</p>
<pre><code class="language-sh">git clone https://github.com/git/git.git
</code></pre>
<p>通过运行命令 <code>cd git</code> 跳转到新生成的 <code>git</code> 目录，随意浏览下里面的文件夹和文件。</p>
<p>你会很快注意到，在工作目录检出的 Git 当前版本代码中，有<strong>大量</strong>的文件并且包含许多非常长看起来很复杂的代码。</p>
<p>显然当前的 Git 版本代码库太大了，很难让单个开发人员在短时间内熟悉它。</p>
<p>让我们使用以下命令检出 Git 的初始提交代码来简化这事情：</p>
<pre><code class="language-sh">git log --reverse
</code></pre>
<p>列表逆序（即与最新日期在前相反）显示了从 Git 第一次提交代码到现在的提交日志。列表里第一次提交的 ID 是 <code>e83c5163316f89bfbde7d9ab23ca2e25604af290</code>。</p>
<p>通过运行命令以下命令把第一次提交的内容检出到你的工作目录：</p>
<pre><code class="language-sh">git checkout e83c5163316f89bfbde7d9ab23ca2e25604af290
</code></pre>
<p>这会让 <a href="https://initialcommit.com/blog/what-is-git-head">Git 进入 <em>分离头指针状态</em></a> ，并把 Git 的源代码检出到你的工作目录。</p>
<p>现在运行 <code>ls</code> 命令列出所有文件，注意里面只有 10 个文件真正包含代码（第 11 个只是 README）。中级开发人员完全可以理解这些文件中的代码。</p>
<p><strong>注意：</strong> 如果你使用的是 Baby Git 仓库，则需要运行命令 <code>git checkout master</code> 来放弃分离的头部，然后移回 master 分支。这将使你能够查看所有描述 Git 的代码如何逐行工作的行内注释！</p>
<h2 id="cgit">一些重要的 C 语言概念将帮助你理解 Git 的代码</h2>
<p>在深入研究 Git 的代码之前，重新了解整个代码库中出现的一些 C 语言编程概念会对你有所帮助。</p>
<h3 id="c">C 语言头文件</h3>
<p>C 语言头文件是一个扩展名为 <code>.h</code> 的代码文件。头文件用于存储开发人员希望使用 <code>#include "headerFile.h"</code> 指令将其包括在多个 <code>.c</code> 源代码文件中的变量，函数和其他 C 语言对象。</p>
<p>如果你熟悉用 Python 或 Java 导入文件，那么这是一个类似的过程。</p>
<h3 id="c">C 语言函数原型（或函数签名）</h3>
<p>一个函数原型或签名告诉 C 语言编译器有关函数定义的信息 —— 函数名称、参数数量、参数类型和返回值类型，但无需提供函数体。它们帮助 C 语言编译器在有函数体的情况下调用函数识别函数属性。</p>
<p>下面是一个关于函数原型的例子：</p>
<pre><code class="language-c">int multiplyNumbers(int a, int b);
</code></pre>
<h3 id="c">C 语言的宏</h3>
<p>C 语言中的宏本质上是一个基本变量，在 C 语言程序中的代码编译之前先进行处理。宏是使用 <code>#define</code> 指令创建的，例如：</p>
<pre><code class="language-c">#define TESTMACRO asdf
</code></pre>
<p>这将创建一个名为 <code>TESTMACRO</code> 的宏，其值为 <code>asdf</code>。在代码中使用占位符 <code>TESTMACRO</code> 的任何地方，它将被预处理器（在代码编译之前）替换为值 <code>asdf</code>。</p>
<p>宏通常在以下几种情况使用：</p>
<ul>
<li>作为一个 true/false 的开关检查宏是否定义</li>
<li>替换在代码中的多个位置出现的简单整数或字符串值</li>
<li>替换在代码中的多个位置出现的简单（通常为单行）代码段</li>
</ul>
<p>宏是方便的工具，因为它们使开发人员可以更新一行代码影响代码在多个位置的行为。</p>
<h3 id="c">C 语言结构体</h3>
<p>C 语言中的结构体是一组属性的集合组成的单个对象。</p>
<p>你可能熟悉 Java 和 Python 等语言中的类，结构体其实就是类的前身，它可以被看作是一个不包含方法的原始类。</p>
<pre><code class="language-c">struct person {

	int person_id;
	char *first_name;
	char *last_name;

};
</code></pre>
<p>上面这个结构体代表一个由 ID 属性、名字属性、姓氏属性组成的人，可以通过以下方式实例化和初始化一个变量：</p>
<pre><code class="language-c">struct person jacob = { 1, "Jacob", "Stopak" };
</code></pre>
<p>结构体属性取值通过 <code>.</code> 操作完成：</p>
<pre><code class="language-c">jacob.person_id
jacob.first_name
jacob.last_name
</code></pre>
<h3 id="c">C 语言中的指针</h3>
<p>指针就是变量的内存地址，该内存地址用于存储变量的值。</p>
<p>可以使用 <code>&amp;</code> 符号获取指向现有变量的指针，并将其存储在以 <code>*</code> 符号声明的指针变量中：</p>
<pre><code class="language-c">int age = 21;

int* age_pointer = &amp;age;
</code></pre>
<p>上面这段代码定义了一个<code>age</code> 变量，并给其赋值为 21 。然后定义了一个整数型的指针变量叫 <code>age_pointer</code>，再使用 <code>&amp;</code> 获得 <code>age</code> 变量的内存地址存储在指针 <code>age_pointer</code> 中。</p>
<p>指针也可以通过使用 * 被解引用（即获得存储在内存地址中的值）。</p>
<pre><code class="language-c">int new_age = *age_pointer + 10;
</code></pre>
<p>继续前面的示例，我们使用 <code>*age_pointer</code> 的语法获取指针 <code>age_pointer</code> 内存地址存储的值（21），然后加上 10，把新值 31 赋值给变量 <code>new_age</code>。</p>
<p>现在我们对 C 语言的简单回顾就完成了，让我们回到 Git 的代码吧！</p>
<h2 id="git">Git 代码库结构概述</h2>
<p>Git 初次提交的代码由 10 个相关的代码文件组成，让我们简要从下面两个文件开始讨论：</p>
<ul>
<li>Makefile</li>
<li>cache.h</li>
</ul>
<p>我们首先讨论 <code>Makefile</code> 和 <code>cache.h</code>，因为它们有一点点特殊。</p>
<p><code>Makefile</code> 是一个构建文件，其中包含一组用于将其他源代码文件构建为可执行文件的命令。</p>
<p>当你从命令行运行 <code>make all</code> 命令时，这个 <code>Makefile</code> 文件将会编译源代码并生成 Git 命令的相关可执行文件。如果你感兴趣，我写了一份 <a href="https://initialcommit.com/blog/Learn-Git-Makefile">深入了解 Git 构建的指南</a>。</p>
<p><strong>注意</strong> 如果你确实像我推荐的那样想在本地编译 Git 的源码，那么你需要使用上面我提到的版本 Baby Git，因为我做了一些调整让 Git 的源代码可以在现代操作系统上编译。</p>
<p>接下来是 <code>cache.h</code> 文件，这是 Baby Git 唯一的头文件。如上所述，头文件定义了剩下 <code>.c</code> 源代码文件中使用的许多函数签名、结构体、宏以及其他设置。如果你感到好奇，我写了一篇 <a href="https://initialcommit.com/blog/Learn-Git-Header-Files">深入了解 Git 头文件的指南</a>。</p>
<p>其余 8 个代码文件都是 <code>.c</code> 源代码文件：</p>
<ul>
<li><code>init-db.c</code></li>
<li><code>update-cache.c</code></li>
<li><code>read-cache.c</code></li>
<li><code>write-tree.c</code></li>
<li><code>commit-tree.c</code></li>
<li><code>read-tree.c</code></li>
<li><code>cat-file.c</code></li>
<li><code>show-diff.c</code></li>
</ul>
<p>每个文件（<code>read-cache.c</code> 除外）均以包含该代码的 Git 命令命名，你可能对其中的某些文件很熟悉。比如 <code>init-db.c</code> 文件包含用于初始化新 Git 仓库的 <code>init-db</code> 命令的代码。你可能已经猜到了，这是 <code>git init</code> 命令的前身。</p>
<p>实际上每个 <code>.c</code> 文件（<code>read-cache.c</code> 除外）都包含原始的 8 个 Git 命令之一的代码，构建过程将编译每个文件并为每个文件创建一个可执行文件（具有匹配的名称）。将这些可执行文件添加到文件系统路径后，即可像执行任何现代 Git 命令一样执行它们。</p>
<p>因此使用 <code>make all</code> 命令编译代码后，将生成以下可执行文件：</p>
<ul>
<li><code>init-db</code>：初始化一个新的 Git 仓库，相当于 <code>git init</code></li>
<li><code>update-cache</code>：添加一个新文件到暂存区，相当于 <code>git add</code></li>
<li><code>write-tree</code>：根据当前索引内容在 Git 仓库中创建树对象（即目录结构）</li>
<li><code>commit-tree</code>：在 Git 仓库中创建一个新的提交对象。相当于 <code>git commit</code></li>
<li><code>read-tree</code>：从 Git 仓库中打印出树（即目录结构）的内容</li>
<li><code>cat-file</code>：从 Git 仓库中检索对象的内容，并将其存储在当前目录中的临时文件中。相当于 <code>git show</code></li>
<li><code>show-diff</code>：显示索引中暂存的文件与文件系统中存在的这些文件的当前版本之间的差异。相当于 <code>git diff</code>。</li>
</ul>
<p>这些命令按顺序分别执行，类似于现代 Git 命令作为标准开发工作流程的一部分执行的方式。</p>
<p>我们尚未讨论的一个文件是 <code>read-cache.c</code>。该文件包含一组其他 <code>.c</code> 源代码文件用于从 Git 仓库中检索信息的辅助函数。</p>
<p>现在我们已经接触到了 Git 最初提交中的每个重要文件，让我们讨论一些让 Git 起作用的核心编程概念。</p>
<h2 id="git">Git 核心概念的实现</h2>
<p>在这部分中，我们将讨论 Git 用于实现其魔力的以下编程概念，以及它们在 Git 的原始代码中是如何实现的：</p>
<ul>
<li>文件压缩</li>
<li>哈希函数</li>
<li>Git 对象</li>
<li>当前目录缓存（暂存区）</li>
<li>内容寻址数据库（对象数据库）</li>
</ul>
<h3 id="">文件压缩</h3>
<p>文件压缩（也称为缩放）用于 Git 中的存储和提高性能。当 Git 需要通过网络传输这些文件时，这会减小 Git 存储在磁盘上文件的大小并提高数据检索的速度。</p>
<p>这很重要，因为 Git 的本地和网络操作需要尽可能快。作为数据检索过程的一部分，Git 对文件进行解压缩或扩展以获取其内容。</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/03/image-37.png" alt="image-37" width="600" height="400" loading="lazy"></p>
<p>Source: <a href="https://initialcommit.com/blog/Learn-Git-Guidebook-For-Developers-Chapter-2">https://initialcommit.com/blog/Learn-Git-Guidebook-For-Developers-Chapter-2</a></p>
<p>在 Git 的原始代码中使用流行的 <code>zlib.h</code> C 语言库实现了文件压缩和解压缩，该库包含用于压缩和解压缩内容的函数、结构体和属性。具体来说，<code>Zlib</code> 库定义了一个结构体 <code>z_stream</code> 用于保存要压缩或扩展的内容。</p>
<p>下面的 <code>zlib</code> 库函数用于<em>初始化</em>一个流以进行压缩和解压缩，它们分别是：</p>
<pre><code class="language-c">/*
 * Initializes the internal `z_stream` state
 * for compression at `level`, which indicates
 * scale of speed versuss compression on a
 * scale from 0-9. Sourced from &lt;zlib.h&gt;.
 */
deflateInit(z_stream, level);

/*
 * Initializes the internal `z_stream` state for
 * decompression. Sourced from &lt;zlib.h&gt;.
 */
inflateInit(z_stream);
</code></pre>
<p>下面的 <code>zlib</code> 库函数用于执行实际的压缩和解压缩操作</p>
<pre><code class="language-c">/*
 * Compresses as much data as possible and stops
 * when the input buffer becomes empty or the
 * output buffer becomes full. Sourced from &lt;zlib.h&gt;.
 */
deflate(z_stream, flush);

/*
 * Decompresses as much data as possible and stops
 * when the input buffer becomes empty or the
 * output buffer becomes full. Sourced from &lt;zlib.h&gt;.
 */
inflate(z_stream, flush);
</code></pre>
<p>实际的压缩、解压缩过程要比这复杂得多，并且涉及设置压缩流的几个参数，但是我们在这里不做更多详细介绍。</p>
<p>接下来，我们将讨论哈希函数的概念以及如何在 Git 的源代码中实现它们。</p>
<h3 id="">哈希函数</h3>
<p>哈希函数是一种可以轻松将输入转换为唯一输出但反转该操作非常困难或不可能的函数。换句话说，它是一种 <strong>单向函数</strong>，在当今的技术下不可能使用哈希函数的输出来推断用于生成该输出的输入。</p>
<p>Git 使用哈希函数，特别是用 SHA-1 哈希函数为我们让 Git 跟踪的文件生成唯一标识符。</p>
<p>作为开发人员，我们使用文本编辑器对正在使用的代码库中的代码文件进行更改，并在某些时候告诉 Git 跟踪这些更改。此时，Git 使用这些文件更改信息作为哈希函数的输入。</p>
<p>哈希函数的输出称为一个 <strong>哈希值</strong>。哈希值是一个长度为 40 个字符的十六进制值数，例如 <code>47a013e660d408619d894b20806b1d5086aab03b</code>。</p>
<p><img src="https://initialcommit.com/img/initialcommit/figure5.png" alt="Git hash function" title="Git hash function" width="600" height="400" loading="lazy"></p>
<p>Source: <a href="https://initialcommit.com/blog/Learn-Git-Guidebook-For-Developers-Chapter-2">https://initialcommit.com/blog/Learn-Git-Guidebook-For-Developers-Chapter-2</a></p>
<p>Git 将这些哈希值用于各种目的，我们将在以下各节中看到它们。</p>
<h3 id="git">Git 对象</h3>
<p>Git 使用简单数据模型（一个结构化的相关对象集）来实现其功能。 这些对象是信息块，这些信息块使 Git 能够跟踪对代码库文件的更改。 Git 使用的三种对象类型是：</p>
<ul>
<li>数据对象</li>
<li>树对象</li>
<li>提交对象</li>
</ul>
<p>让我们按顺序逐个讨论。</p>
<h4 id="blob">Blob</h4>
<h4 id="">数据对象</h4>
<p>Blob 是 <strong>B</strong>inary <strong>L</strong>arge <strong>OB</strong>ject（数据对象）的缩写形式，当使用 <code>update-cache &lt;filename.ext&gt;</code> 命令（<code>git add</code> 的前身）告诉 Git 跟踪文件时，Git 使用该文件的压缩内容创建一个新的数据对象。</p>
<p>Git 获取文件的内容并使用我们上面描述的 <code>zlib</code> 函数对其进行压缩，再将此压缩后的内容用作 SHA-1 哈希函数的输入，这会创建一个 40 个字符的哈希，Git 会使用该哈希来识别相关的数据对象。</p>
<p>最后，Git 将数据对象作为二进制文件保存在名为 <strong>对象数据库</strong> 的特殊文件夹中（稍后会详细介绍）。数据对象文件的名称是生成的哈希，数据对象文件的内容是使用 <code>update-cache</code> 命令添加的压缩文件内容。</p>
<h4 id="">树对象</h4>
<p>树对象用于把多个数据对象在添加到 Git 的时候就组织到一起，它们还用于将数据对象与文件名（以及其他文件元数据，如权限）相关联，因为数据对象除了提供哈希和压缩的二进制文件内容外不提供任何信息。</p>
<p>比如说，如果使用 <code>update-cache</code> 命令添加了两个更改的文件，则将创建一棵包含这些文件的哈希值以及每个数据对象所对应的文件名的树。</p>
<p>Git 接下来要做的事情非常有趣，因此请注意， Git 使用 <strong>树本身的内容</strong> 作为 SHA-1 哈希函数的输入生成 40 个字符的哈希。该哈希用于标识树对象，Git 将其保存在与保存数据对象相同的特殊文件夹，即我们将在稍后讨论的对象数据库中。</p>
<h4 id="">提交对象</h4>
<p>比起数据对象和树对象，你可能对提交对象更熟悉。一个提交对象表示由 Git 保存的一组文件更改，以及有关更改的描述性信息，例如提交消息，作者的姓名和提交的时间戳。</p>
<p>在 Git 的源代码中，提交对象是运行 <code>commit-tree &lt;tree-hash&gt;</code> 命令的结果，生成的提交对象包括指定的树对象（记住，该树对象表示通过映射到其文件名的一个或多个数据对象表示文件更改的集合），以及上一段中提到的描述性信息。</p>
<p>像数据对象和树对象一样， Git 通过使用 SHA-1 哈希函数对提交的内容进行哈希处理并将其保存在对象数据库中。重要的是，每个提交对象还包含其父提交的哈希。 这样提交就形成了一条链，Git 可以使用它来表示项目的历史记录。</p>
<h3 id="">当前目录缓存（暂存区）</h3>
<p>你可能知道 Git 的暂存区就是使用 <code>git add</code> 命令后更改文件等待使用 <code>git commit</code> 提交所在的位置，但是暂存区到底是什么呢？</p>
<p>在 Git 的原始版本中，暂存区被称为 <strong>当前目录缓存</strong>，当前目录缓存只是一个存储在资源库中的二进制文件，路径为 <code>.dircache/index</code>。</p>
<p>如上一节所述，在使用 <code>update-cache</code> (<code>git add</code>) 命令将更改的文件添加到 Git 之后，Git 会计算与这些更改关联的数据对象和树对象，然后将与暂存文件关联的生成的树对象添加到 <code>index</code> 文件中。</p>
<p>之所以称为 <strong>缓存</strong>，是因为它只是保留已进行的更改在提交之前的临时存储位置，当用户通过运行<code>commit-tree</code>命令进行提交时，当前目录缓存可以提供对应的树，和其他提交信息，比如用于 Git 创建新提交对象的提交消息。</p>
<p>这时候，只是删除了 <code>index</code> 文件，为新更改暂存腾出空间。</p>
<h3 id="">内容寻址数据库（对象数据库）</h3>
<p>对象数据库是 Git 的主要存储位置，我们上面讨论的所有对象（数据对象，树对象和提交对象）都存储在对象数据库中。在 Git 的原始版本中，对象数据库只是一个目录，路径是 <code>.dircache/objects/</code>。</p>
<p>当 Git 通过诸如 <code>update-cache</code>，<code>write-tree</code> 和 <code>commit-tree</code>（<code>git add</code> 和 <code>git commit</code> 的前身）之类的操作创建对象时，这些对象将被压缩，再进行哈希，然后存储在对象数据库中。</p>
<p>每个对象的名称都是其内容的哈希值，这也是对象数据库为什么也叫作 <strong>内容寻址数据库</strong> 的原因。每块内容（数据对象、树对象或者提交对象）都基于从内容本身生成的标识符进行存储和检索。</p>
<p>现代版本的 Git 的工作方式几乎相同。不同之处在于现代版本的 Git 通过使用更有效的方法（尤其是与通过网络进行数据传输有关的方法）已经对存储格式进行了优化，但是基本原理是相同的。</p>
<h2 id="">总结</h2>
<p>在本文中我们讨论了 Git 代码的原始版本，以突出显示如何阅读现有代码可以帮助提高你的编码技能。</p>
<p>我们介绍了以这种方式学习为什么 Git 是一个的好项目的原因，以及如何访问 Git 的代码，并回顾了一些相关的 C 语言编程概念。 最后，我们提供了 Git 原始代码库结构的概述，并深入探讨了 Git 代码所依赖的一些概念。</p>
<h2 id="">下一步</h2>
<p>如果你有兴趣了解有关 Git 代码的更多信息，<a href="https://initialcommit.com/store/baby-git-guidebook-for-developers">我们编写了一本指南，你可以在此处查看</a>。 这本书详细介绍了 Git 的原始 C 语言代码，并直接说明了该代码是怎么工作的。</p>
<p>我鼓励所有开发人员探索开源社区去尝试找到你感兴趣的高质量项目，这些项目的代码库你可以在几分钟内克隆完。</p>
<p>花一些时间来探究一下代码，你可能会学到一些从未想到的东西。</p>
<!--kg-card-end: markdown--><p>原文：<a href="https://www.freecodecamp.org/news/boost-programming-skills-read-git-code/">Boost Your Programming Skills by Reading Git's Code</a>，作者：<a href="https://www.freecodecamp.org/news/author/initialcommit/">Jacob Stopak</a></p> ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
