<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>auberginewly‘s blog</title>
  
  
  <link href="https://auberginewly.site/atom.xml" rel="self"/>
  
  <link href="https://auberginewly.site/"/>
  <updated>2025-07-02T06:22:03.297Z</updated>
  <id>https://auberginewly.site/</id>
  
  <author>
    <name>auberginewly</name>
    
  </author>
  
  <generator uri="https://hexo.io/">Hexo</generator>
  
  <entry>
    <title>互联网产品我们该怎么去做</title>
    <link href="https://auberginewly.site/2025/07/02/25_about_product/"/>
    <id>https://auberginewly.site/2025/07/02/25_about_product/</id>
    <published>2025-07-02T05:34:06.000Z</published>
    <updated>2025-07-02T06:22:03.297Z</updated>
    
    <content type="html"><![CDATA[<blockquote><p>在高速发展的互联网浪潮中，<strong>产品经理</strong>扮演着至关重要的角色，他们是连接用户、技术、市场与商业价值的枢纽。要成为一名优秀的互联网产品经理，不仅需要扎实的产品知识，更需要高超的沟通协作能力。</p></blockquote><h1 id="互联网产品的核心特性"><a href="#互联网产品的核心特性" class="headerlink" title="互联网产品的核心特性"></a>互联网产品的核心特性</h1><p>理解互联网产品的本质是产品经理的基石。它们普遍具备以下特点：</p><ul><li><strong>敏捷开发与快速迭代</strong>：互联网产品强调“小步快跑”，通过快速发布、持续验证来适应市场变化和用户需求，不断优化。</li><li><strong>用户体验至上</strong>：在激烈的市场竞争中，卓越的<strong>用户体验（UX）是产品能否吸引并留住用户的关键。这包括信息架构</strong>、<strong>交互设计</strong>和<strong>视觉设计</strong>的方方面面。</li><li><strong>数据驱动决策</strong>：互联网产品从上线伊始便会产生海量数据。产品经理必须学会利用数据分析工具，解读<strong>活跃用户（DAU）</strong>、<strong>留存率</strong>、<strong>转化率</strong>、<strong>GMV</strong>等<strong>核心指标</strong>，通过数据洞察用户行为，指导产品优化。</li><li><strong>规模效应与网络效应</strong>：许多互联网产品，特别是社交和平台类产品，随着用户数量的增长，其价值会呈几何级数增长，形成强大的壁垒。</li><li><strong>技术依赖性</strong>：互联网产品与技术紧密相连，产品经理虽不需成为技术专家，但应具备足够的技术理解力，以便与研发团队高效沟通。</li><li><strong>多元变现模式</strong>：互联网产品的盈利模式多样，如广告、订阅服务、电商佣金、增值服务等，产品经理需清晰其商业逻辑。</li></ul><h1 id="产品经理的核心技能"><a href="#产品经理的核心技能" class="headerlink" title="产品经理的核心技能"></a>产品经理的核心技能</h1><p>要驾驭互联网产品的复杂性，产品经理需要掌握一系列核心技能：</p><ul><li><strong>用户研究与画像</strong>：深入理解目标用户群，通过用户访谈、问卷调查等方式，构建精准的<strong>用户画像</strong>。熟悉<strong>AARRR模型</strong>（获取、激活、留存、收益、推荐），指导用户增长策略。</li><li><strong>产品设计与原型</strong>：能够将抽象需求转化为具象的设计方案。熟练使用原型工具（如Figma、Sketch），进行高保真原型设计，并理解设计原则。</li><li><strong>数据分析与指标解读</strong>：善用各类<strong>分析工具</strong>，从海量数据中提炼洞察，通过数据验证假设，优化产品功能。</li><li><strong>竞品分析</strong>：不仅要分析竞品的<strong>功能</strong>，更要深挖其<strong>产品定位</strong>、<strong>商业模式</strong>、<strong>运营策略</strong>及<strong>优劣势</strong>，从中学习并寻找自身产品的差异化。</li><li><strong>增长黑客思维</strong>：以<strong>小投入</strong>、<strong>高效率</strong>的方式实现<strong>用户增长</strong>和<strong>产品传播</strong>，将产品融入营销和增长的各个环节。</li><li><strong>项目管理</strong>：在快速迭代的环境下，产品经理需具备强大的<strong>项目管理</strong>能力，有效地<strong>协调研发、设计、运营</strong>等各方资源，确保项目按计划推进。</li></ul><h1 id="实践与案例分析"><a href="#实践与案例分析" class="headerlink" title="实践与案例分析"></a>实践与案例分析</h1><p>理论学习是基础，但实践和案例分析才是提升产品能力的加速器。</p><ul><li><strong>使用与拆解产品</strong>：深入体验各类热门互联网产品，并尝试从产品经理的视角进行<strong>拆解分析</strong>：<ul><li>这个产品解决了什么问题？面向哪些用户？</li><li>它的<strong>核心功能</strong>是什么？用户路径如何？</li><li>它的<strong>商业模式</strong>是什么？</li><li>有哪些值得借鉴的<strong>交互或设计</strong>？</li><li>如果有机会优化，你会怎么做？</li></ul></li><li><strong>活跃于行业社区</strong>：加入<strong>PMCAFF</strong>、<strong>人人都是产品经理</strong>等线上社区，参与讨论，了解行业热点，从同行经验中学习。</li><li><strong>关注行业报告与媒体</strong>：定期阅读权威<strong>行业报告</strong>和科技<strong>媒体</strong>，掌握最新趋势和创新案例。</li></ul><h1 id="互联网产品经理的沟通协作艺术"><a href="#互联网产品经理的沟通协作艺术" class="headerlink" title="互联网产品经理的沟通协作艺术"></a>互联网产品经理的沟通协作艺术</h1><p>成功的互联网产品离不开高效的团队协作。产品经理作为核心枢纽，需要与研发、运营、设计团队建立信任，有效沟通，共同推动产品发展。</p><h3 id="与研发团队的沟通协作"><a href="#与研发团队的沟通协作" class="headerlink" title="与研发团队的沟通协作"></a>与研发团队的沟通协作</h3><p>研发团队是产品落地的基石。产品经理需要确保：</p><ul><li><strong>需求明确性</strong>：提供清晰、完整、无歧义的 PRD（产品需求文档）或用户故事，包含功能描述、业务逻辑、异常处理、数据埋点等细节。</li><li><strong>技术可行性与成本</strong>：在需求阶段就与研发充分讨论，评估技术实现难度、潜在风险及预估开发周期，避免不切实际的需求。</li><li><strong>优先级</strong>：共同明确需求优先级，确保研发资源投入到最有价值的功能上。</li><li><strong>进度同步与Bug管理</strong>：定期沟通项目进展，及时解决开发中的问题，并规范Bug提报和处理流程。</li><li><strong>早期介入与敏捷方法</strong>：邀请研发在产品规划初期参与讨论，利用<strong>敏捷开发</strong>（如Scrum）的机制，如站会、迭代评审、回顾会，保持高效沟通和透明度。</li><li><strong>技术分享与相互尊重</strong>：产品经理适度了解技术栈，理解研发挑战，并始终尊重他们的专业意见。</li></ul><h3 id="与运营团队的沟通协作"><a href="#与运营团队的沟通协作" class="headerlink" title="与运营团队的沟通协作"></a>与运营团队的沟通协作</h3><p>运营团队是产品与用户之间的桥梁。产品经理应：</p><ul><li><strong>明确产品价值与特点</strong>：确保运营充分理解产品的核心价值、目标用户和独特卖点，以便有效推广。</li><li><strong>倾听用户反馈与活动需求</strong>：积极收集运营团队提供的用户反馈，并评估各类<strong>活动需求</strong>对产品的价值。</li><li><strong>提供数据支持</strong>：了解运营对数据监控的需求，在产品设计中预留好<strong>数据埋点</strong>。</li><li><strong>及时同步版本更新</strong>：让运营团队了解新功能和优化点，以便他们进行用户引导。</li><li><strong>共同制定用户增长策略</strong>：与运营团队将产品和运营目标对齐，共同关注用户增长、活跃度、转化率等核心指标。</li></ul><h3 id="与设计团队的沟通协作"><a href="#与设计团队的沟通协作" class="headerlink" title="与设计团队的沟通协作"></a>与设计团队的沟通协作</h3><p>设计团队将抽象需求转化为具象的用户界面和交互体验。产品经理需要：</p><ul><li><strong>明确用户体验目标</strong>：清晰阐述产品解决的痛点、场景和期望的用户体验，而非直接指定设计方案。</li><li><strong>提供用户画像与场景</strong>：帮助设计师理解用户需求和行为模式。</li><li><strong>明确功能优先级与信息架构</strong>：与设计师共同确定合理的信息架构和页面布局。</li><li><strong>遵循设计原则与规范</strong>：确保产品风格一致性。</li><li><strong>迭代与评审</strong>：对设计稿进行评审，提供建设性反馈，确保设计方案符合产品和用户需求。</li><li><strong>保持开放与共创</strong>：鼓励设计师发挥创意，并对他们的专业建议保持开放态度，共同关注用户反馈。</li></ul><h1 id="建立高效沟通协作的关键"><a href="#建立高效沟通协作的关键" class="headerlink" title="建立高效沟通协作的关键"></a>建立高效沟通协作的关键</h1><ul><li><strong>清晰的沟通目标</strong>：每次沟通都应明确要解决的问题和达成的共识。</li><li><strong>换位思考</strong>：理解每个团队的工作性质、目标与挑战。</li><li><strong>建立信任</strong>：真诚沟通，言出必行，承担责任。</li><li><strong>主动性与反馈闭环</strong>：产品经理需主动发起沟通，并确保所有反馈都有明确的接收、处理和回复机制。</li><li><strong>善用工具</strong>：利用项目管理（Jira, Trello）、协作文档（Confluence）、原型（Figma）等工具提升效率。</li></ul><h1 id="Conclusion"><a href="#Conclusion" class="headerlink" title="Conclusion"></a>Conclusion</h1><p><strong>洞察 设计 协作 增长</strong></p><p>其实这个学期下来感知最大的就是，产品给我的感觉很泛，我没有去了解它的具体，只是模仿前人的状态去尽力当好一个好“产品”，泛是其职业特性决定的，产品要求从业者具备很强的<strong>通用性、学习能力和适应性</strong>。虽然概念很泛，但其核心价值始终在于<strong>发现并解决用户问题，通过产品实现商业价值</strong>。我想我也在尝试优化自己的不足，在泛泛之中能握得确切的实践经验。</p><blockquote><p>上述文字是我觉得需要的几个关键点让 AI 优化了一下表述，其实如果让我说产品是什么，我不是很答得上来，但是让我慢下来梳理，我发现，它是一个很不一样的存在。</p></blockquote>]]></content>
    
    
      
      
    <summary type="html">&lt;blockquote&gt;
&lt;p&gt;在高速发展的互联网浪潮中，&lt;strong&gt;产品经理&lt;/strong&gt;扮演着至关重要的角色，他们是连接用户、技术、市场与商业价值的枢纽。要成为一名优秀的互联网产品经理，不仅需要扎实的产品知识，更需要高超的沟通协作能力。&lt;/p&gt;
&lt;/blockquot</summary>
      
    
    
    
    
    <category term="产品" scheme="https://auberginewly.site/tags/%E4%BA%A7%E5%93%81/"/>
    
  </entry>
  
  <entry>
    <title>实现 butterfly 主题 hexo 博客内嵌 html 预览形式</title>
    <link href="https://auberginewly.site/2025/05/01/24_HTMLpreview/"/>
    <id>https://auberginewly.site/2025/05/01/24_HTMLpreview/</id>
    <published>2025-05-01T15:44:48.000Z</published>
    <updated>2025-05-01T16:28:24.766Z</updated>
    
    <content type="html"><![CDATA[<h1 id="缘由"><a href="#缘由" class="headerlink" title="缘由"></a>缘由</h1><p>最近想开始写点关于 50projects50days 的小 demo，但是只贴代码的话未免有点太单调，如果能显示出预览页面是不是更好玩，于是在梦神提到了 iframe 可以内嵌 html 的形式，我就去想怎么可以把本地未部署的 html 代码内嵌到我的博客文章当中并且单独可以渲染互动。</p><h1 id="步骤"><a href="#步骤" class="headerlink" title="步骤"></a>步骤</h1><h2 id="step1-在-source-文件夹下新建-demo-文件夹存放我的代码文件"><a href="#step1-在-source-文件夹下新建-demo-文件夹存放我的代码文件" class="headerlink" title="step1 在 source 文件夹下新建 demo 文件夹存放我的代码文件"></a>step1 在 source 文件夹下新建 demo 文件夹存放我的代码文件</h2><p>于是在这里可以放置我的代码文件<br><img src="/../images/image-20250502000449574.png" alt="image-20250502000449574"></p><h2 id="step2-在-hexo-的-config-yml配置文件当中修改忽略-demo-文件夹"><a href="#step2-在-hexo-的-config-yml配置文件当中修改忽略-demo-文件夹" class="headerlink" title="step2 在 hexo 的_config.yml配置文件当中修改忽略 demo 文件夹"></a>step2 在 hexo 的<code>_config.yml</code>配置文件当中修改忽略 demo 文件夹</h2><p>在<code>_config.yml</code>配置文件里这么写：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">skip_render:</span><br><span class="line">  - demo/**/*</span><br></pre></td></tr></table></figure><p>意思是告诉 Hexo：不要去渲染 <code>source/demo/</code> 下的内容，而是<strong>原样复制</strong>到 <code>public/demo/</code> 中。</p><h2 id="step3-如果你的-html-是外联-css-与-js"><a href="#step3-如果你的-html-是外联-css-与-js" class="headerlink" title="step3 如果你的 html 是外联 css 与 js"></a>step3 如果你的 html 是外联 css 与 js</h2><p>保证引用使用 相对路径 写：</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">link</span> <span class="attr">rel</span>=<span class="string">&quot;stylesheet&quot;</span> <span class="attr">href</span>=<span class="string">&quot;./style.css&quot;</span>&gt;</span></span><br></pre></td></tr></table></figure><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">script</span> <span class="attr">src</span>=<span class="string">&quot;./script.js&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br></pre></td></tr></table></figure><h2 id="step4-在博客文章的-markdown-中直接写-iframe-可以被浏览器渲染出来"><a href="#step4-在博客文章的-markdown-中直接写-iframe-可以被浏览器渲染出来" class="headerlink" title="step4 在博客文章的 markdown 中直接写 iframe 可以被浏览器渲染出来"></a>step4 在博客文章的 markdown 中直接写 iframe 可以被浏览器渲染出来</h2><p>为了兼容性，最好加上 <code>sandbox</code> 或 <code>allow</code> 属性控制 iframe 权限，例如：</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">iframe</span> <span class="attr">src</span>=<span class="string">&quot;/demo/my-first-demo/index.html&quot;</span></span></span><br><span class="line"><span class="tag">        <span class="attr">width</span>=<span class="string">&quot;100%&quot;</span> <span class="attr">height</span>=<span class="string">&quot;500&quot;</span></span></span><br><span class="line"><span class="tag">        <span class="attr">frameborder</span>=<span class="string">&quot;0&quot;</span></span></span><br><span class="line"><span class="tag">        <span class="attr">sandbox</span>=<span class="string">&quot;allow-scripts allow-same-origin&quot;</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">iframe</span>&gt;</span></span><br></pre></td></tr></table></figure><p>这里的 src 替换成自己的 html 的相对路径。</p><h2 id="step5-如果遇到渲染页面包含博客框架错误需使用hexo-clean清理缓存再上传"><a href="#step5-如果遇到渲染页面包含博客框架错误需使用hexo-clean清理缓存再上传" class="headerlink" title="step5 如果遇到渲染页面包含博客框架错误需使用hexo clean清理缓存再上传"></a>step5 如果遇到渲染页面包含博客框架错误需使用<code>hexo clean</code>清理缓存再上传</h2><p>不然就会出现像这样套娃的形式：</p><p><img src="/../images/image-20250502001536070.png" alt="image-20250502001536070"></p><h1 id="测试"><a href="#测试" class="headerlink" title="测试"></a>测试</h1><p>如果不想引用 html 文件而是想直接渲染：</p><blockquote><p>注意HTML 不允许 iframe 内嵌原始内容块</p></blockquote><p>HTML 的 <code>&lt;iframe&gt;</code> 是一个「独立文档容器」，它 <strong>只能加载一个 URL 地址作为 <code>src</code></strong>，不能直接在 iframe 标签中写入结构性的内容（比如 <code>&lt;h1&gt;</code>、<code>&lt;p&gt;</code> 等）——那种做法属于 <code>&lt;iframe srcdoc=&quot;...&quot;&gt;</code>。</p><p>直接把 HTML 内容写入 iframe 的 <code>srcdoc</code> 属性，代码如下：</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">iframe</span> </span></span><br><span class="line"><span class="tag">  <span class="attr">srcdoc</span>=<span class="string">&quot;</span></span></span><br><span class="line"><span class="string"><span class="tag">    &lt;div style=&#x27;border:1px dashed gray; padding:1em; margin:1em 0;&#x27;&gt;</span></span></span><br><span class="line"><span class="string"><span class="tag">      &lt;h1&gt;It works!&lt;/h1&gt;</span></span></span><br><span class="line"><span class="string"><span class="tag">      &lt;p&gt;你可以直接把这段代码放在 Markdown 文件中。&lt;/p&gt;</span></span></span><br><span class="line"><span class="string"><span class="tag">    &lt;/div&gt;</span></span></span><br><span class="line"><span class="string"><span class="tag">  &quot;</span></span></span><br><span class="line"><span class="tag">  <span class="attr">width</span>=<span class="string">&quot;100%&quot;</span> <span class="attr">height</span>=<span class="string">&quot;200&quot;</span> <span class="attr">frameborder</span>=<span class="string">&quot;0&quot;</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">iframe</span>&gt;</span></span><br></pre></td></tr></table></figure><p>效果如下：</p><iframe   srcdoc="    <div style='border:1px dashed gray; padding:1em; margin:1em 0;'>      <h1>It works!</h1>      <p>你可以直接把这段代码放在 Markdown 文件中。</p>    </div>  "  width="100%" height="200" frameborder="0"></iframe><p>浏览器会渲染一个 iframe，里面显示你写的 <code>div</code> 和内容，没有外部引用页面。</p><blockquote><p>注意：</p><p><code>srcdoc=&quot;...&quot;</code> 中的 HTML 要是 <strong>单行字符串</strong>，不能换行，属性值里的 <code>&quot;</code> 要改成 <code>&#39;</code> 或使用 HTML 实体（否则 Markdown 渲染或浏览器会解析出错）。</p><p>某些老旧浏览器（如 IE）不支持 <code>srcdoc</code>，现代浏览器完全支持。</p></blockquote><p>如果你要展示结构内容，不依赖 iframe，其实直接这样写更干净：</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">style</span>=<span class="string">&quot;border:1px dashed gray; padding:1em; margin:1em 0;&quot;</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">h1</span>&gt;</span>It works!<span class="tag">&lt;/<span class="name">h1</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">p</span>&gt;</span>你可以直接把这段代码放在 Markdown 文件中。<span class="tag">&lt;/<span class="name">p</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br></pre></td></tr></table></figure><p>效果这样：</p><div style="border:1px dashed gray; padding:1em; margin:1em 0;">  <h1>It works!</h1>  <p>你可以直接把这段代码放在 Markdown 文件中。</p></div><h1 id="成功嵌入预览"><a href="#成功嵌入预览" class="headerlink" title="成功嵌入预览"></a>成功嵌入预览</h1><p><img src="/../images/image-20250502001629537.png" alt="image-20250502001629537"></p><p>成功了喵，还可以在这个上面玩（）</p>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;缘由&quot;&gt;&lt;a href=&quot;#缘由&quot; class=&quot;headerlink&quot; title=&quot;缘由&quot;&gt;&lt;/a&gt;缘由&lt;/h1&gt;&lt;p&gt;最近想开始写点关于 50projects50days 的小 demo，但是只贴代码的话未免有点太单调，如果能显示出预览页面是不是更好玩，于是</summary>
      
    
    
    
    <category term="琐碎问题解决" scheme="https://auberginewly.site/categories/%E7%90%90%E7%A2%8E%E9%97%AE%E9%A2%98%E8%A7%A3%E5%86%B3/"/>
    
    
    <category term="CS" scheme="https://auberginewly.site/tags/CS/"/>
    
    <category term="frontend" scheme="https://auberginewly.site/tags/frontend/"/>
    
  </entry>
  
  <entry>
    <title>50projects50days（持续更新）</title>
    <link href="https://auberginewly.site/2025/04/29/23_50projects50days_is_updating/"/>
    <id>https://auberginewly.site/2025/04/29/23_50projects50days_is_updating/</id>
    <published>2025-04-28T17:41:20.000Z</published>
    <updated>2025-05-04T15:45:27.539Z</updated>
    
    <content type="html"><![CDATA[<h1 id="第一个-扩展卡片"><a href="#第一个-扩展卡片" class="headerlink" title="第一个 扩展卡片"></a>第一个 扩展卡片</h1><h2 id="demo"><a href="#demo" class="headerlink" title="demo"></a>demo</h2><iframe src="/demo/50projects50days/1_expandcards/index.html"        width="100%" height="500"        frameborder="0"        sandbox="allow-scripts allow-same-origin"></iframe><h1 id="第二个-步骤器"><a href="#第二个-步骤器" class="headerlink" title="第二个 步骤器"></a>第二个 步骤器</h1><h2 id="demo-1"><a href="#demo-1" class="headerlink" title="demo"></a>demo</h2><iframe src="/demo/50projects50days/2_step/index.html"        width="100%" height="500"        frameborder="0"        sandbox="allow-scripts allow-same-origin"></iframe><h1 id="第三个-旋转导航"><a href="#第三个-旋转导航" class="headerlink" title="第三个 旋转导航"></a>第三个 旋转导航</h1><h2 id="demo-2"><a href="#demo-2" class="headerlink" title="demo"></a>demo</h2><iframe src="/demo/50projects50days/3_rotating_navigation/index.html"        width="100%" height="500"        frameborder="0"        sandbox="allow-scripts allow-same-origin"></iframe>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;第一个-扩展卡片&quot;&gt;&lt;a href=&quot;#第一个-扩展卡片&quot; class=&quot;headerlink&quot; title=&quot;第一个 扩展卡片&quot;&gt;&lt;/a&gt;第一个 扩展卡片&lt;/h1&gt;&lt;h2 id=&quot;demo&quot;&gt;&lt;a href=&quot;#demo&quot; class=&quot;headerlink&quot; </summary>
      
    
    
    
    <category term="学习笔记" scheme="https://auberginewly.site/categories/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/"/>
    
    
    <category term="CS" scheme="https://auberginewly.site/tags/CS/"/>
    
    <category term="frontend" scheme="https://auberginewly.site/tags/frontend/"/>
    
  </entry>
  
  <entry>
    <title>2025.4 第四周</title>
    <link href="https://auberginewly.site/2025/04/28/22_2025-4-week4/"/>
    <id>https://auberginewly.site/2025/04/28/22_2025-4-week4/</id>
    <published>2025-04-28T09:08:59.000Z</published>
    <updated>2025-04-28T17:43:33.390Z</updated>
    
    <content type="html"><![CDATA[<h1 id="这一周干了什么"><a href="#这一周干了什么" class="headerlink" title="这一周干了什么"></a>这一周干了什么</h1><p>研究了下 github desktop 确实图形化可以简化一堆 git 的命令。<br>把前端三剑客大致的过完了，然后想给 50projects50days 每天来一个？<br>还开了一点点的 go 的基础。<br>一些练习都上传到了我的 github 仓库里。<br>然后快速入门了下区块链和 web3 的知识，联系到了金融。<br>还写了篇稿子联系产品设计进行分享。<br>传送门：<br><a href="https://ncuhomer.feishu.cn/wiki/R5I7wR9jkiOW1ckl5pwcbT9knfd?from=from_copylink">Web3 产品设计的另一种打开方式</a></p><h1 id="没干的"><a href="#没干的" class="headerlink" title="没干的"></a>没干的</h1><p>就是说给博客评论配置图床失败，后面有时间再看看喵。<br>高数线代大物落下了好多进度哇。<br>还有算法颓废，有点对这个抗拒啊喂。<br>还有一个月就要来的雅思还没开始准备。<br>后面可能就是暂且把 go 搁置，然后前端的练习，其他的方向的学习，绩点以及我的雅思还有四级。</p><h1 id="这周的状态"><a href="#这周的状态" class="headerlink" title="这周的状态"></a>这周的状态</h1><p>其实这周的状态很糟糕我得说，之前天天熬夜还暴饮暴食，哎哎，然后整个人非常的郁闷和压力，于是乎还写了篇抱怨的博客，简直是觉得自己好无力。我喜欢把一些博客先挂着但是没学，比如 pytorch 关于机器学习那一块的，还有 sql 之类的，都是搁置的，感觉时间不够用哇诶。<br>还是得调整下状态，或许可以加一些运动进入到日常当中？<br>晚安喵。</p>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;这一周干了什么&quot;&gt;&lt;a href=&quot;#这一周干了什么&quot; class=&quot;headerlink&quot; title=&quot;这一周干了什么&quot;&gt;&lt;/a&gt;这一周干了什么&lt;/h1&gt;&lt;p&gt;研究了下 github desktop 确实图形化可以简化一堆 git 的命令。&lt;br&gt;把前端三剑客</summary>
      
    
    
    
    <category term="周报" scheme="https://auberginewly.site/categories/%E5%91%A8%E6%8A%A5/"/>
    
    
    <category term="一些想法" scheme="https://auberginewly.site/tags/%E4%B8%80%E4%BA%9B%E6%83%B3%E6%B3%95/"/>
    
  </entry>
  
  <entry>
    <title>明明什么也没干但是很累</title>
    <link href="https://auberginewly.site/2025/04/27/21_boring/"/>
    <id>https://auberginewly.site/2025/04/27/21_boring/</id>
    <published>2025-04-27T08:10:47.000Z</published>
    <updated>2025-04-27T09:09:02.621Z</updated>
    
    <content type="html"><![CDATA[<h1 id="最近还是很多烦心事"><a href="#最近还是很多烦心事" class="headerlink" title="最近还是很多烦心事"></a>最近还是很多烦心事</h1><p>比如家园的 hack 部分我感觉我好像做的不足，比如我的产品分享会哔哩吧啦讲了 50 分钟耗尽了心力，比如学会了在 English 和中文当中添加空格，比如我想学一些技术之类相关的东西，比如最基础的前后端或者其他感兴趣的技术，感觉都很有趣哇，但是我好累。绩点，语言成绩，技术，产品的钻研，我的娱乐就是去找好吃的，然后躺着，看天花板，然后半夜 emo，导致我的作息非常的颠倒，前两个礼拜基本上就是凌晨三四点睡的，纯粹是不知道怎么入睡，然后早 上12 点爬起来或者干脆只睡 3 个小时左右，然后上个礼拜五我就开始头痛了，然后下午的课直接请假了，很多东西都还没来得及干完，感觉一直被 ddl 赶着跑，然后我的状态很颓废。</p><h1 id="现在的我"><a href="#现在的我" class="headerlink" title="现在的我"></a>现在的我</h1><p>我现在整个人不知道怎么去排解，盯着电脑左看看右看看，然后一种酸涩与无奈就会涌上心头，然后怪罪自己为什么我不会做这些东西，为什么我这么废物，一种自负到极致的心理，看起来很变态，平时和我的聊天隐隐约约可以感受到这种心理，现在写着这篇不知道干什么的文章的时候，我正在上高数课，我就是完全人在课上但是不听讲的状态，大物，线代都是，然后作业全是抄的，但是我不能把绩点丢了，高考失利的你你愿意吗，所以我拼命这样的意义是什么，但是回过头来你拼命了什么呢我请问了。感觉阴阴的天像一块巨石压在我的胸口，我的呼吸也跟不上来，双手发抖，由不得不的怪罪自己，我到底为什么。为什么。为什么。<br>都没学懂我是不是很笨，什么都做不来我是不是很蠢。<br>我好崩溃啊<br>好想刀了自己<br>我活着干什么<br>是不是走了就不用忍受这样的心理了</p>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;最近还是很多烦心事&quot;&gt;&lt;a href=&quot;#最近还是很多烦心事&quot; class=&quot;headerlink&quot; title=&quot;最近还是很多烦心事&quot;&gt;&lt;/a&gt;最近还是很多烦心事&lt;/h1&gt;&lt;p&gt;比如家园的 hack 部分我感觉我好像做的不足，比如我的产品分享会哔哩吧啦讲了 50</summary>
      
    
    
    
    <category term="想法" scheme="https://auberginewly.site/categories/%E6%83%B3%E6%B3%95/"/>
    
    
    <category term="一些想法" scheme="https://auberginewly.site/tags/%E4%B8%80%E4%BA%9B%E6%83%B3%E6%B3%95/"/>
    
  </entry>
  
  <entry>
    <title>Golang——从入门到入土</title>
    <link href="https://auberginewly.site/2025/04/25/20_Golang_journey/"/>
    <id>https://auberginewly.site/2025/04/25/20_Golang_journey/</id>
    <published>2025-04-25T03:31:12.000Z</published>
    <updated>2025-04-25T16:39:37.166Z</updated>
    
    <content type="html"><![CDATA[<h1 id="开发环境"><a href="#开发环境" class="headerlink" title="开发环境"></a>开发环境</h1><p>Go 官网下载地址：<a href="https://golang.org/dl/">https://golang.org/dl/</a></p><p>Go 官方镜像站（推荐）：<a href="https://golang.google.cn/dl/">https://golang.google.cn/dl/</a></p><h2 id="IDE"><a href="#IDE" class="headerlink" title="IDE"></a>IDE</h2><p>vscode 或者 goland</p><p>个人是新手觉得 goland 比较省事</p><h1 id="语法"><a href="#语法" class="headerlink" title="语法"></a>语法</h1><h2 id="第一个-go-程序"><a href="#第一个-go-程序" class="headerlink" title="第一个 go 程序"></a>第一个 go 程序</h2><p>关于导入与使用</p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// hello.go</span></span><br><span class="line"><span class="keyword">package</span> main <span class="comment">// 程序的包名</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> <span class="string">&quot;fmt&quot;</span></span><br><span class="line"><span class="keyword">import</span> <span class="string">&quot;time&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// import语句用于引入其他包，fmt是格式化输出的包</span></span><br><span class="line"><span class="comment">// 也可以引入其他包，如math、strings等</span></span><br><span class="line"><span class="comment">// 也可以引入自定义的包，如&quot;myapp/mypackage&quot;</span></span><br><span class="line"><span class="comment">// 也可以引入多个包，如</span></span><br><span class="line"><span class="comment">// import (</span></span><br><span class="line"><span class="comment">// &quot;fmt&quot;</span></span><br><span class="line"><span class="comment">// &quot;math&quot;</span></span><br><span class="line"><span class="comment">// &quot;strings&quot;</span></span><br><span class="line"><span class="comment">// )</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123; <span class="comment">// 函数的&#123; 和函数名在同一行，否则编译错误</span></span><br><span class="line"><span class="comment">// main函数是程序的入口，分号可加可不加，建议是不加</span></span><br><span class="line">fmt.Println(<span class="string">&quot;hello world&quot;</span>)</span><br><span class="line"></span><br><span class="line">time.Sleep(<span class="number">1</span> * time.Second) <span class="comment">// 暂停1秒</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="var-变量"><a href="#var-变量" class="headerlink" title="var 变量"></a>var 变量</h2><p>变量的声明<br><code>:=</code>简短声明变量，类型自动推导对应的数据类型<br><code>:=</code>只能在函数内部使用，不能在函数外部使用<br>其他的可以看看注释部分</p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 1_test1_var.go</span></span><br><span class="line"><span class="keyword">package</span> main  </span><br><span class="line">  </span><br><span class="line"><span class="keyword">import</span> <span class="string">&quot;fmt&quot;</span>  </span><br><span class="line">  </span><br><span class="line"><span class="comment">// 全局变量声明只能用 var 关键字  </span></span><br><span class="line"><span class="keyword">var</span> ga <span class="type">int</span> = <span class="number">100</span> <span class="comment">// 全局变量声明，默认值是0  </span></span><br><span class="line"><span class="keyword">var</span> gb = <span class="number">200</span>  </span><br><span class="line">  </span><br><span class="line"><span class="comment">// 全局变量声明，类型自动推导对应的数据类型  </span></span><br><span class="line"><span class="comment">// gc := 300  </span></span><br><span class="line"><span class="comment">// := 只能在函数内部使用，不能在函数外部使用  </span></span><br><span class="line">  </span><br><span class="line"><span class="comment">// 四种变量声明方式  </span></span><br><span class="line">  </span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;  </span><br><span class="line">    <span class="comment">// 1. 声明变量 默认的值是0  </span></span><br><span class="line">    <span class="keyword">var</span> a <span class="type">int</span>  </span><br><span class="line">    fmt.Println(<span class="string">&quot;a =  &quot;</span>, a)           <span class="comment">// Println 打印变量的值  </span></span><br><span class="line">    fmt.Printf(<span class="string">&quot;type of a = %T\n&quot;</span>, a) <span class="comment">// %T 打印变量的类型 // Printf 格式化输出  </span></span><br><span class="line">  </span><br><span class="line">    <span class="comment">// 2. 声明变量并赋值  </span></span><br><span class="line">    <span class="keyword">var</span> b <span class="type">int</span> = <span class="number">100</span>  </span><br><span class="line">    fmt.Println(<span class="string">&quot;b = &quot;</span>, b)  </span><br><span class="line">    fmt.Printf(<span class="string">&quot;type of b = %T\n&quot;</span>, b) <span class="comment">// %T 打印变量的类型  </span></span><br><span class="line">  </span><br><span class="line">    <span class="comment">// 3. 声明变量并赋值，类型自动推导对应的数据类型  </span></span><br><span class="line">    <span class="keyword">var</span> c = <span class="number">200</span>  </span><br><span class="line">    fmt.Println(<span class="string">&quot;c = &quot;</span>, c)  </span><br><span class="line">    fmt.Printf(<span class="string">&quot;type of c = %T\n&quot;</span>, c) <span class="comment">// %T 打印变量的类型  </span></span><br><span class="line">  </span><br><span class="line">    <span class="keyword">var</span> cc = <span class="string">&quot;abcd&quot;</span>  </span><br><span class="line">    fmt.Printf(<span class="string">&quot;cc = %s, type of cc = %T\n&quot;</span>, cc, cc) <span class="comment">// %s 打印字符串类型的变量  </span></span><br><span class="line">  </span><br><span class="line">    <span class="comment">// 4. 简短声明变量，类型自动推导对应的数据类型  </span></span><br><span class="line">    d := <span class="number">300</span> <span class="comment">// := 是简短声明变量的方式，既初始化也赋值  </span></span><br><span class="line">    fmt.Println(<span class="string">&quot;d = &quot;</span>, d)  </span><br><span class="line">    fmt.Printf(<span class="string">&quot;type of d = %T\n&quot;</span>, d) <span class="comment">// %T 打印变量的类型  </span></span><br><span class="line">  </span><br><span class="line">    f := <span class="string">&quot;abc&quot;</span>  </span><br><span class="line">    fmt.Printf(<span class="string">&quot;f = %s, type of f = %T\n&quot;</span>, f, f) <span class="comment">// %s 打印字符串类型的变量  </span></span><br><span class="line">  </span><br><span class="line">    g := <span class="number">3.14</span>  </span><br><span class="line">    fmt.Printf(<span class="string">&quot;g = %f, type of g = %T\n&quot;</span>, g, g) <span class="comment">// %f 打印浮点数类型的变量  </span></span><br><span class="line">  </span><br><span class="line">    <span class="comment">// 打印全局变量  </span></span><br><span class="line">    fmt.Println(<span class="string">&quot;ga = &quot;</span>, ga)  </span><br><span class="line">    fmt.Printf(<span class="string">&quot;type of ga = %T\n&quot;</span>, ga) <span class="comment">// %T 打印变量的类型  </span></span><br><span class="line">    fmt.Println(<span class="string">&quot;gb = &quot;</span>, gb)  </span><br><span class="line">    fmt.Printf(<span class="string">&quot;type of gb = %T\n&quot;</span>, gb) <span class="comment">// %T 打印变量的类型  </span></span><br><span class="line">    <span class="comment">//fmt.Println(&quot;gc = &quot;, gc)  </span></span><br><span class="line">    <span class="comment">//fmt.Printf(&quot;type of gc = %T\n&quot;, gc) // %T 打印变量的类型  </span></span><br><span class="line">  </span><br><span class="line">    <span class="comment">// 5. 多个变量声明  </span></span><br><span class="line">    <span class="keyword">var</span> x, y, z <span class="type">int</span> = <span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>  </span><br><span class="line">    fmt.Println(<span class="string">&quot;x = &quot;</span>, x)  </span><br><span class="line">    fmt.Println(<span class="string">&quot;y = &quot;</span>, y)  </span><br><span class="line">    fmt.Println(<span class="string">&quot;z = &quot;</span>, z)  </span><br><span class="line">  </span><br><span class="line">    <span class="keyword">var</span> xx, yy = <span class="number">100</span>, <span class="string">&quot;abcde&quot;</span>  </span><br><span class="line">    fmt.Println(<span class="string">&quot;xx = &quot;</span>, xx, <span class="string">&quot;yy = &quot;</span>, yy)  </span><br><span class="line">  </span><br><span class="line">    <span class="comment">// 6. 多行变量声明  </span></span><br><span class="line">    <span class="keyword">var</span> (  </span><br><span class="line">       vv <span class="type">int</span>  = <span class="number">100</span>  </span><br><span class="line">       jj <span class="type">bool</span> = <span class="literal">true</span>  </span><br><span class="line">    )  </span><br><span class="line">    fmt.Println(<span class="string">&quot;vv = &quot;</span>, vv, <span class="string">&quot;jj = &quot;</span>, jj)  </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="常量-const-与枚举递增-iota"><a href="#常量-const-与枚举递增-iota" class="headerlink" title="常量 const 与枚举递增 iota"></a>常量 const 与枚举递增 iota</h2><p>常量（const）声明，只读属性<br>const 来定义枚举类型<br>可以在 const() 添加关键字 iota，每行的 iota 都会累积 1，第一行 iota 的值是 0<br>枚举的值都符合 iota 的规则 </p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 1_test2_const.go</span></span><br><span class="line"><span class="keyword">package</span> main  </span><br><span class="line">  </span><br><span class="line"><span class="keyword">import</span> <span class="string">&quot;fmt&quot;</span>  </span><br><span class="line">  </span><br><span class="line"><span class="comment">// const 来定义枚举类型  </span></span><br><span class="line"><span class="comment">//const (  </span></span><br><span class="line"><span class="comment">//  // 可以在 const() 添加关键字 iota，每行的 iota 都会累积 1，第一行 iota 的值是 0//  // 第二行 iota 的值是 1，第三行 iota 的值是 2//  // 以此类推  </span></span><br><span class="line"><span class="comment">//  // iota 只能在 const() 中使用，不能在其他地方使用  </span></span><br><span class="line"><span class="comment">//  BEIJING   = iota // iota = 0  </span></span><br><span class="line"><span class="comment">//  SHANGHAI         // iota = 1  </span></span><br><span class="line"><span class="comment">//  GUANGZHOU        // iota = 2  </span></span><br><span class="line"><span class="comment">//)  </span></span><br><span class="line">  </span><br><span class="line"><span class="keyword">const</span> (  </span><br><span class="line">    <span class="comment">// 可以在 const() 添加关键字 iota，每行的 iota 都会累积 1，第一行 iota 的值是 0    // 第二行 iota 的值是 1，第三行 iota 的值是 2    // 以此类推  </span></span><br><span class="line">    <span class="comment">// iota 只能在 const() 中使用，不能在其他地方使用，只有在 const 里有累加效果  </span></span><br><span class="line">    BEIJING   = <span class="number">10</span> * <span class="literal">iota</span> <span class="comment">// iota = 0  </span></span><br><span class="line">    SHANGHAI              <span class="comment">// iota = 1  </span></span><br><span class="line">    GUANGZHOU             <span class="comment">// iota = 2  </span></span><br><span class="line">)  </span><br><span class="line">  </span><br><span class="line"><span class="keyword">const</span> (  </span><br><span class="line">    a, b = <span class="literal">iota</span> + <span class="number">1</span>, <span class="literal">iota</span> + <span class="number">2</span>  </span><br><span class="line">    c, d  </span><br><span class="line">    e, f  </span><br><span class="line">  </span><br><span class="line">    g, h = <span class="literal">iota</span> * <span class="number">2</span>, <span class="literal">iota</span> * <span class="number">3</span>  </span><br><span class="line">    i, j  </span><br><span class="line">    <span class="comment">// 下面的值都符合 iota 的规则  </span></span><br><span class="line">)  </span><br><span class="line">  </span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;  </span><br><span class="line">    <span class="comment">// 常量（const）声明，只读属性  </span></span><br><span class="line">    <span class="keyword">const</span> length <span class="type">int</span> = <span class="number">10</span>  </span><br><span class="line">  </span><br><span class="line">    fmt.Println(<span class="string">&quot;length = &quot;</span>, length)  </span><br><span class="line">  </span><br><span class="line">    <span class="comment">// length = 100 // 常量不能被修改  </span></span><br><span class="line">  </span><br><span class="line">    fmt.Println(<span class="string">&quot;BEIJING = &quot;</span>, BEIJING)  </span><br><span class="line">    fmt.Println(<span class="string">&quot;SHANGHAI = &quot;</span>, SHANGHAI)  </span><br><span class="line">    fmt.Println(<span class="string">&quot;GUANGZHOU = &quot;</span>, GUANGZHOU)  </span><br><span class="line">  </span><br><span class="line">    fmt.Println(<span class="string">&quot;a = &quot;</span>, a, <span class="string">&quot;b = &quot;</span>, b)  </span><br><span class="line">    fmt.Println(<span class="string">&quot;c = &quot;</span>, c, <span class="string">&quot;d = &quot;</span>, d)  </span><br><span class="line">    fmt.Println(<span class="string">&quot;e = &quot;</span>, e, <span class="string">&quot;f = &quot;</span>, f)  </span><br><span class="line">    fmt.Println(<span class="string">&quot;g = &quot;</span>, g, <span class="string">&quot;h = &quot;</span>, h)  </span><br><span class="line">    fmt.Println(<span class="string">&quot;i = &quot;</span>, i, <span class="string">&quot;j = &quot;</span>, j)  </span><br><span class="line">    <span class="comment">// iota 的值是 0  </span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="函数-function"><a href="#函数-function" class="headerlink" title="函数 function"></a>函数 function</h2><p>注意返回值类型在后边，没有的话会报错<br>返回可以返回单个值，多个值，有形参的，也可以匿名的</p><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 1_test3_function.go</span></span><br><span class="line"><span class="keyword">package</span> main  </span><br><span class="line">  </span><br><span class="line"><span class="keyword">import</span> <span class="string">&quot;fmt&quot;</span>  </span><br><span class="line">  </span><br><span class="line"><span class="comment">// 返回单个值  </span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">foo1</span><span class="params">(a <span class="type">string</span>, b <span class="type">int</span>)</span></span> <span class="type">int</span> &#123; <span class="comment">// 注意 int 返回值在后边，没有的话会报错  </span></span><br><span class="line">    fmt.Println(<span class="string">&quot;a = &quot;</span>, a)  </span><br><span class="line">    fmt.Println(<span class="string">&quot;b = &quot;</span>, b)  </span><br><span class="line">  </span><br><span class="line">    c := <span class="number">100</span>  </span><br><span class="line">  </span><br><span class="line">    <span class="keyword">return</span> c  </span><br><span class="line">&#125;  </span><br><span class="line">  </span><br><span class="line"><span class="comment">// 返回多个值，匿名的  </span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">foo2</span><span class="params">(a <span class="type">string</span>, b <span class="type">int</span>)</span></span> (<span class="type">int</span>, <span class="type">int</span>) &#123; <span class="comment">// 注意 int 返回值在后边，没有的话会报错  </span></span><br><span class="line">    fmt.Println(<span class="string">&quot;a = &quot;</span>, a)  </span><br><span class="line">    fmt.Println(<span class="string">&quot;b = &quot;</span>, b)  </span><br><span class="line">  </span><br><span class="line">    <span class="keyword">return</span> <span class="number">666</span>, <span class="number">777</span>  </span><br><span class="line">&#125;  </span><br><span class="line">  </span><br><span class="line"><span class="comment">// 返回多个值，有形参名称的  </span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">foo3</span><span class="params">(a <span class="type">string</span>, b <span class="type">int</span>)</span></span> (c <span class="type">int</span>, d <span class="type">int</span>) &#123; <span class="comment">// 注意 int 返回值在后边，没有的话会报错  </span></span><br><span class="line">    fmt.Println(<span class="string">&quot;---- foo3 ----&quot;</span>)  </span><br><span class="line">    fmt.Println(<span class="string">&quot;a = &quot;</span>, a)  </span><br><span class="line">    fmt.Println(<span class="string">&quot;b = &quot;</span>, b)  </span><br><span class="line">  </span><br><span class="line">    <span class="comment">// c,d 属于 foo3 的形参，返回形参变量默认初始化的值为 0    // c,d 的作用域空间是 foo3 整个函数体的&#123;&#125;空间  </span></span><br><span class="line">    fmt.Println(<span class="string">&quot;c = &quot;</span>, c)  </span><br><span class="line">    fmt.Println(<span class="string">&quot;d = &quot;</span>, d)  </span><br><span class="line">    <span class="comment">// 给有名称的返回值变量赋值  </span></span><br><span class="line">    c = <span class="number">100</span>  </span><br><span class="line">    d = <span class="number">200</span>  </span><br><span class="line">  </span><br><span class="line">    <span class="keyword">return</span>  </span><br><span class="line">&#125;  </span><br><span class="line">  </span><br><span class="line"><span class="comment">// 返回 int 共用，此写法类似 3func foo4(a string, b int) (c, d int) &#123; // 注意 int 返回值在后边，没有的话会报错  </span></span><br><span class="line">    fmt.Println(<span class="string">&quot;---- foo4 ----&quot;</span>)  </span><br><span class="line">    fmt.Println(<span class="string">&quot;a = &quot;</span>, a)  </span><br><span class="line">    fmt.Println(<span class="string">&quot;b = &quot;</span>, b)  </span><br><span class="line">  </span><br><span class="line">    <span class="comment">// 给有名称的返回值变量赋值  </span></span><br><span class="line">    c = <span class="number">100</span>  </span><br><span class="line">    d = <span class="number">200</span>  </span><br><span class="line">  </span><br><span class="line">    <span class="keyword">return</span>  </span><br><span class="line">&#125;  </span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;  </span><br><span class="line">    c := foo1(<span class="string">&quot;abc&quot;</span>, <span class="number">100</span>)  </span><br><span class="line">  </span><br><span class="line">    fmt.Println(<span class="string">&quot;c = &quot;</span>, c)  </span><br><span class="line">  </span><br><span class="line">    ret1, ret2 := foo2(<span class="string">&quot;111&quot;</span>, <span class="number">222</span>)  </span><br><span class="line">    fmt.Println(<span class="string">&quot;ret1 = &quot;</span>, ret1, <span class="string">&quot; ret2 = &quot;</span>, ret2)  </span><br><span class="line">  </span><br><span class="line">    ret1, ret2 = foo3(<span class="string">&quot;abc&quot;</span>, <span class="number">100</span>)  </span><br><span class="line">    fmt.Println(<span class="string">&quot;ret1 = &quot;</span>, ret1, <span class="string">&quot; ret2 = &quot;</span>, ret2)  </span><br><span class="line">  </span><br><span class="line">    ret1, ret2 = foo4(<span class="string">&quot;abd&quot;</span>, <span class="number">300</span>)  </span><br><span class="line">    fmt.Println(<span class="string">&quot;ret1 = &quot;</span>, ret1, <span class="string">&quot; ret2 = &quot;</span>, ret2)  </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="import-导包路径问题"><a href="#import-导包路径问题" class="headerlink" title="import 导包路径问题"></a>import 导包路径问题</h2><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// lib1/lib1.go</span></span><br><span class="line"><span class="keyword">package</span> lib1  </span><br><span class="line">  </span><br><span class="line"><span class="keyword">import</span> <span class="string">&quot;fmt&quot;</span>  </span><br><span class="line">  </span><br><span class="line"><span class="comment">// 当前lib1包提供的api  </span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">Lib1Test</span><span class="params">()</span></span> &#123;  </span><br><span class="line">    fmt.Println(<span class="string">&quot;lib1Test()...&quot;</span>)  </span><br><span class="line">&#125;  </span><br><span class="line">  </span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">init</span><span class="params">()</span></span> &#123;  </span><br><span class="line">    fmt.Println(<span class="string">&quot;lib1.init()...&quot;</span>)  </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// lib2/lib2.go</span></span><br><span class="line"><span class="keyword">package</span> lib2  </span><br><span class="line">  </span><br><span class="line"><span class="keyword">import</span> <span class="string">&quot;fmt&quot;</span>  </span><br><span class="line">  </span><br><span class="line"><span class="comment">// 当前lib2包提供的api  </span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">Lib2Test</span><span class="params">()</span></span> &#123;  </span><br><span class="line">    fmt.Println(<span class="string">&quot;lib2Test()...&quot;</span>)  </span><br><span class="line">&#125;  </span><br><span class="line">  </span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">init</span><span class="params">()</span></span> &#123;  </span><br><span class="line">    fmt.Println(<span class="string">&quot;lib2.init()...&quot;</span>)  </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 1_main.go</span></span><br><span class="line"><span class="keyword">package</span> main  </span><br><span class="line">  </span><br><span class="line"><span class="keyword">import</span> (  </span><br><span class="line">    <span class="string">&quot;go_learning/5_init/lib1&quot;</span>  </span><br><span class="line">    <span class="string">&quot;go_learning/5_init/lib2&quot;</span>)  </span><br><span class="line">  </span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;  </span><br><span class="line">    lib1.Lib1Test()  </span><br><span class="line">    lib2.Lib2Test()  </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="注意一定要有-go-mod-的存在，不然-go-会去-gopath-里找包然后报错"><a href="#注意一定要有-go-mod-的存在，不然-go-会去-gopath-里找包然后报错" class="headerlink" title="注意一定要有 go.mod 的存在，不然 go 会去 gopath 里找包然后报错"></a>注意一定要有 go.mod 的存在，不然 go 会去 gopath 里找包然后报错</h3><p>这里是gpt的解答：<br>在 Go 中，如果没有 <code>go.mod</code> 文件，Go 会根据 <strong><code>GOPATH</code> 模式</strong> 来查找包，而不是使用 <strong>Go Modules</strong>（模块化依赖管理）。这是 Go 1.11 之前的行为，而现代 Go 项目通常推荐使用 Go Modules。</p><hr><h3 id="为什么没有-go-mod-会去其他路径找包？"><a href="#为什么没有-go-mod-会去其他路径找包？" class="headerlink" title="为什么没有 go.mod 会去其他路径找包？"></a><strong>为什么没有 <code>go.mod</code> 会去其他路径找包？</strong></h3><ol><li><p><strong>历史行为（GOPATH 模式）</strong>：</p><ul><li>在 Go Modules 引入之前（Go 1.11 之前），Go 依赖 <code>GOPATH</code> 环境变量来管理包。</li><li>所有第三方包和本地项目都必须放在 <code>$GOPATH/src</code> 下，编译器会从 <code>GOPATH</code> 中查找包。</li></ul></li><li><p><strong>查找顺序</strong>：</p><ul><li>如果没有 <code>go.mod</code>，Go 会按以下顺序查找包：<ol><li><strong>标准库</strong>（如 <code>fmt</code>、<code>net/http</code> 等，位于 <code>GOROOT/src</code>）。</li><li><strong><code>GOPATH/src</code> 目录</strong>：尝试在 <code>$GOPATH/src/go_learning/5_init/lib1</code> 中查找包。</li><li><strong>当前目录</strong>（但通常不适用，除非是相对路径导入）。</li></ol></li></ul></li><li><p><strong>你的错误信息分析</strong>：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">1_main.go:4:2: package go_learning/5_init/lib1 is not in std (/opt/homebrew/opt/go/libexec/src/go_learning/5_init/lib1)</span><br></pre></td></tr></table></figure><ul><li>编译器在标准库（<code>std</code>）和 <code>GOPATH</code> 中都没找到 <code>go_learning/5_init/lib1</code>，因此报错。</li></ul></li></ol><hr><h3 id="解决方法"><a href="#解决方法" class="headerlink" title="解决方法"></a><strong>解决方法</strong></h3><h4 id="1-启用-Go-Modules（推荐）"><a href="#1-启用-Go-Modules（推荐）" class="headerlink" title="1. 启用 Go Modules（推荐）"></a>1. <strong>启用 Go Modules（推荐）</strong></h4><p>在项目根目录（如 <code>go_learning/</code>）下运行：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">go mod init go_learning</span><br></pre></td></tr></table></figure><p>这会生成 <code>go.mod</code> 文件，之后 Go 会基于模块路径解析本地包，不再依赖 <code>GOPATH</code>。</p><h4 id="2-检查包路径"><a href="#2-检查包路径" class="headerlink" title="2. 检查包路径"></a>2. <strong>检查包路径</strong></h4><p>确保导入路径与模块名一致。例如：</p><ul><li>如果 <code>go.mod</code> 声明 <code>module go_learning</code>，则导入应为：<figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> <span class="string">&quot;go_learning/5_init/lib1&quot;</span></span><br></pre></td></tr></table></figure></li></ul><h4 id="3-避免依赖-GOPATH"><a href="#3-避免依赖-GOPATH" class="headerlink" title="3. 避免依赖 GOPATH"></a>3. <strong>避免依赖 <code>GOPATH</code></strong></h4><ul><li>现代 Go 项目应始终使用 <code>go.mod</code>，避免将代码放在 <code>$GOPATH/src</code> 下。</li></ul><hr><h3 id="关键区别：GOPATH-vs-Go-Modules"><a href="#关键区别：GOPATH-vs-Go-Modules" class="headerlink" title="关键区别：GOPATH vs Go Modules"></a><strong>关键区别：GOPATH vs Go Modules</strong></h3><table><thead><tr><th>特性</th><th>GOPATH 模式</th><th>Go Modules 模式</th></tr></thead><tbody><tr><td>依赖管理</td><td>代码必须放在 <code>$GOPATH/src</code></td><td>任意目录，通过 <code>go.mod</code> 管理</td></tr><tr><td>导入路径</td><td>从 <code>GOPATH/src</code> 开始查找</td><td>基于模块名（<code>module xxx</code>）</td></tr><tr><td>版本控制</td><td>手动管理</td><td>通过 <code>go.mod</code> 和 <code>go.sum</code></td></tr><tr><td>本地包引用</td><td>必须符合 <code>GOPATH</code> 结构</td><td>支持相对路径或模块路径</td></tr></tbody></table><hr><h3 id="总结"><a href="#总结" class="headerlink" title="总结"></a><strong>总结</strong></h3><ul><li><strong>没有 <code>go.mod</code></strong>：Go 回退到 <code>GOPATH</code> 模式，导致编译器去 <code>GOPATH/src</code> 或标准库中查找包。</li><li><strong>正确做法</strong>：始终使用 <code>go mod init</code> 初始化项目，确保依赖和本地包能被正确解析。</li></ul><p>如果仍有问题，请检查项目结构和 <code>go.mod</code> 内容，或提供更多上下文进一步分析。</p><h3 id="同时调用的方法和参数也要是大写的首字母，不然不能通过-import-调用"><a href="#同时调用的方法和参数也要是大写的首字母，不然不能通过-import-调用" class="headerlink" title="同时调用的方法和参数也要是大写的首字母，不然不能通过 import 调用"></a>同时调用的方法和参数也要是大写的首字母，不然不能通过 import 调用</h3><ul><li><strong>大写</strong>：允许跨包访问（类似 <code>public</code>）。</li><li><strong>小写</strong>：仅限当前包内使用（类似 <code>private</code>）。</li></ul>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;开发环境&quot;&gt;&lt;a href=&quot;#开发环境&quot; class=&quot;headerlink&quot; title=&quot;开发环境&quot;&gt;&lt;/a&gt;开发环境&lt;/h1&gt;&lt;p&gt;Go 官网下载地址：&lt;a href=&quot;https://golang.org/dl/&quot;&gt;https://golang.org/</summary>
      
    
    
    
    <category term="学习笔记" scheme="https://auberginewly.site/categories/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/"/>
    
    
    <category term="CS" scheme="https://auberginewly.site/tags/CS/"/>
    
    <category term="GO" scheme="https://auberginewly.site/tags/GO/"/>
    
  </entry>
  
  <entry>
    <title>关于web3的那些事</title>
    <link href="https://auberginewly.site/2025/04/22/19_about_web3/"/>
    <id>https://auberginewly.site/2025/04/22/19_about_web3/</id>
    <published>2025-04-22T07:17:39.000Z</published>
    <updated>2025-04-22T16:06:13.275Z</updated>
    
    <content type="html"><![CDATA[<h1 id="web1与web2"><a href="#web1与web2" class="headerlink" title="web1与web2"></a>web1与web2</h1><p>web1只读，类似于在互联网上看报刊的那种程度，典型的公司例如新浪、搜狐之类，可以阅读的一种形式。<br>web2是可读可写，具体一些就是可以创造内容的形式，可以点赞评论可以发表意见可以互动的形式，典型就是2004年 facebook 的诞生，后续衍生出一系列类似形式的产物，微博、b 站、抖音、知乎、滴滴等等。<br>如此web2就形成了一个目前互联网公司的一种商业模式：</p><ul><li>免费、便宜的服务吸引用户</li><li>获得用户数据</li><li>靠推送广告赚钱<br>但是这种形式多了之后，用户信息反而变得更加稀缺，互联网公司不能再局限于这种形式，于是就到了web3的形式。</li></ul><h1 id="基于区块链的web3"><a href="#基于区块链的web3" class="headerlink" title="基于区块链的web3"></a>基于区块链的web3</h1><p>所以从web1与web2走来之后，web3基于区块链，不光可以读取信息，创造信息，还能拥有自己的信息，就好像是在网络世界里的一个独立的经济系统。<br>以区块链为底层架构逻辑，衍生出一整套与现实隔离的经济体系，不需要中央管理者（去中心化），而是通过自己的激励机制让它维护与运行，还可以由此自己升级，它拥有自己的货币，自己的组织形式，自己的服务模式。</p><h1 id="加密货币"><a href="#加密货币" class="headerlink" title="加密货币"></a>加密货币</h1><p>区块链自主运行，需要一个体系来激励大家自主的维护这个体系的运行，这个就是加密货币，可以把加密货币理解成区块链系统当中的一个 token（令牌）。<br>理解比特币，就是矿工在区块链上打包信息，维持这个区块链的运行，打包好了信息，就在交易的过程中抽取部分比特币作为奖励。<br>其实每个人都可以建立自己的区块链，代码也可以进行复制粘贴，每一条区块链上都会有一种加密货币，作为它的原生代币，用的人多了，认可的人多了，代币就会涨价，类似于这个区块链代表的股票，越多人认可这个区块链，这个区块链上的代币就越值钱。<br>由此，这个币就有了投资的属性，大家对其的相信程度，取决于背后能不能编出一套好的故事，加密货币这种东西不受中心控制，就满足了炒作的特点，同时也利用了人们不劳而获的那种心理，所以推上了风口浪尖。</p><h1 id="交易平台"><a href="#交易平台" class="headerlink" title="交易平台"></a>交易平台</h1><p>现实当中转钱或者交易股票，需要去到银行或者交易所这种地方，加密货币的市值目前很高，同时每天不计其数的交易也在发生，于是乎，交易平台应运而生。<br>做的比较大的就是类似币安（binance）之类的平台，同时也衍生出了一系列的市场与产品，并且树立了自己的行业地位。<br>同时当交易规模发展到一定地步之后，就有一些制度创新，并且生成自己的金融体系来增加币圈的货币流动性，于是，DeFi 产生了。</p><h1 id="DeFi——Decentralized-Finance-去中心化金融"><a href="#DeFi——Decentralized-Finance-去中心化金融" class="headerlink" title="DeFi——Decentralized Finance 去中心化金融"></a>DeFi——Decentralized Finance 去中心化金融</h1><p>它不需要像银行、券商、清算所，在中间作为中介机构，大部分创新都是把现有金融体系当中的业务搬到了币圈：</p><ul><li>加密货币的借贷</li><li>加密货币的保险</li><li>加密货币的清算</li><li>加密货币的金融衍生品</li><li>杠杆交易</li></ul><h1 id="稳定币-Stablecoin"><a href="#稳定币-Stablecoin" class="headerlink" title="稳定币 Stablecoin"></a>稳定币 Stablecoin</h1><p>不论对于 DeFi 还是 web3 一个重大创新就是稳定币 Stablecoin 的出现。<br>加密货币有一个问题就是波动太大了，稳定币的作用就是一比一与美元绑定，相当于在web3的世界持有美元，也不用担心其价格过山车，提心吊胆的。这样不论对于投资者还是 web3 公司，都是一个非常大的激励。<br>一些比较大的稳定币，泰达币（Tenther) 、Coinbase 的 USDC、Binance 的 BUSD 的交易量都很高。<br>泰达币（Tenther）交易量远超比特币与以太坊，等等。<br>稳定币背后的算法也不大一样，有一些百分百与美元绑定，比如 USDC，BUSD。还有一些是算法稳定币，并不是完全抵押，存在一些风险，例如 Luna。</p><h1 id="以太坊-Ethereum"><a href="#以太坊-Ethereum" class="headerlink" title="以太坊 Ethereum"></a>以太坊 Ethereum</h1><p>区块链一开始好比公开账本，记录一些交易信息，而 2015 之后以太坊的出现，出现了一个叫智能合约（Smart Comtract）的东西，可以记录信息，还可以运行程序。<br>于是可以写出去中心化的自动运行的程序，就是去中心化应用（Decentralized Apps），也称为 DApps。（理论上可以把现有所有的 app 搬到区块链上bushi）<br>于是以智能合约还有区块链作为底层架构，不光是网络世界，现实世界还有很多东西都可以重构。<br>简而言之，去中心化的版本，把数据内容的归属权全部都归于用户自己。<br>不只以太坊一家，比较大的公链如 BNB Chain、Polygon、Polkadot、Cardano 之类，都相对以太坊而言有不同程度的侧重。<br>应用场景可以不断扩展，区块链不只是交易体系、货币机器了。</p><h1 id="NFT-Non-Fungible-Token-非同质化代币"><a href="#NFT-Non-Fungible-Token-非同质化代币" class="headerlink" title="NFT Non-Fungible Token 非同质化代币"></a>NFT Non-Fungible Token 非同质化代币</h1><p>NFT 可以简单理解为数字世界的版权概念，数字技术可以复制，但是有了这个版权之后呢，就不要类似什么权威机构的认证了，也可以分清楚是谁的。<br>于是你可以知道：</p><blockquote><p>稀缺，可以讲好品牌故事的东西，就是相当理想的投资品。</p></blockquote><h2 id="交易"><a href="#交易" class="headerlink" title="交易"></a>交易</h2><p>虽然规模比不上上述所讲的加密货币，但是也相当的客可观，目前最大的公司也就是 OpenSea。<br>NFT 不光可以用来投资炒作，还可以用来产生出独一无二的数字藏品，并作为一种营销的手段，就像之前的无聊猿。只要有热度有流量就可以拉新用户与用户互动，从中获益。</p><h1 id="游戏"><a href="#游戏" class="headerlink" title="游戏"></a>游戏</h1><p>web3 当中游戏和普通游戏最大的区别，拥有自己的经济体系，有自己的加密货币来作为流通货币，无论什么元素，都可以放在区块链上变成 NFT，让虚拟的系统一下变得无比真实，因为这里面的东西都可以在现实世界换真金白银，游戏越火，玩的人越多，NFT 就越值钱。（点名csgo）<br>出名的有 Sandbox 之类，那 web3 的游戏和元宇宙的游戏可以这么理解，元宇宙（meta）要构建在 web3 的基础之上，因为 web3 的游戏与钱那些东西挂钩，于是乎 web3 的游戏并不是纯粹的游戏，而是”赚钱“。<br>也叫做 GameFi。如果游戏可持续可不断交易，那就不是一个虚拟未知的庞氏骗局，反之亦然。<br>但是，不可置否，游戏是 web3 当中非常重要的一个部分了。</p><h1 id="其他区块链实现的"><a href="#其他区块链实现的" class="headerlink" title="其他区块链实现的"></a>其他区块链实现的</h1><ul><li>区块链与物联网<ul><li>连接区块链与现实世界的数据</li><li>去中心化的存储<br>但是 web3 现实与理想差距还很远，有技术上的问题，也有人性上的问题。</li></ul></li></ul><h1 id="人性对投机的渴望"><a href="#人性对投机的渴望" class="headerlink" title="人性对投机的渴望"></a>人性对投机的渴望</h1><p>作为普通人，我可以通过买币，拥有币来成为这些未来可能潜力巨大项目的天使投资人，这些投机的心态，让币、NFT 的价格被炒的很高。<br>现实当中当你有个想法创业，形成雏形、融资、发展、融资、发展循环，直到上市股票在二级市场交易，但是在 web3 当中有想法就可以立马发行属于自己的代币，直接跳过那些繁琐的步骤直接 ipo。<br>还没想好怎么发展，这边股票就流通炒作了，回报的速度非常之快。<br>比之前的互联网公司三五年的发展还要之迅速，同时会吸引大量人才涌入这个赛道，周期越短，风险越小，roi就越高。就像前文提及的加密货币的股票属性，相信的人越多，它越涨。</p><blockquote><p>人才 资本 关注度</p></blockquote><p>泡沫经济。<br>市值蒸发。<br>惨绝人寰。</p><blockquote><p>DYOR Do Your Own Research</p></blockquote><p>做好你自己的研究，在时代的风口，不要被吹跑。</p>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;web1与web2&quot;&gt;&lt;a href=&quot;#web1与web2&quot; class=&quot;headerlink&quot; title=&quot;web1与web2&quot;&gt;&lt;/a&gt;web1与web2&lt;/h1&gt;&lt;p&gt;web1只读，类似于在互联网上看报刊的那种程度，典型的公司例如新浪、搜狐之类，可以阅</summary>
      
    
    
    
    <category term="学习笔记" scheme="https://auberginewly.site/categories/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/"/>
    
    
    <category term="SQL" scheme="https://auberginewly.site/tags/SQL/"/>
    
    <category term="CS" scheme="https://auberginewly.site/tags/CS/"/>
    
    <category term="区块链" scheme="https://auberginewly.site/tags/%E5%8C%BA%E5%9D%97%E9%93%BE/"/>
    
  </entry>
  
  <entry>
    <title>快速入门区块链</title>
    <link href="https://auberginewly.site/2025/04/22/18_about_blockchain/"/>
    <id>https://auberginewly.site/2025/04/22/18_about_blockchain/</id>
    <published>2025-04-22T02:11:37.000Z</published>
    <updated>2025-04-22T17:12:58.761Z</updated>
    
    <content type="html"><![CDATA[<h1 id="缘由"><a href="#缘由" class="headerlink" title="缘由"></a>缘由</h1><p>区块链（Blockchain）技术源于<a href="https://bitcoin.org/en/">比特币</a>。在比特币中，为了保证每笔交易可信并不可篡改，中本聪发明了区块链，它通过后一个区块对前一个区块的引用，并以加密技术保证了区块链不可修改。<br>随着比特币的逐渐发展，人们发现区块链本质上其实是一个分布式的，不可篡改的数据库，天生具有可验证、可信任的特性，它不但可用于支持比特币，也可用于数字身份验证，清算业务等传统的必须由第三方介入的业务，从而降低交易成本。</p><h1 id="比特币"><a href="#比特币" class="headerlink" title="比特币"></a>比特币</h1><p>比特币是一种数字货币，数字货币是基于数学加密原理构建的不可伪造的货币系统，而比特币是第一个基于数学加密原理构建的分布式数字货币系统，比特币使用区块链技术实现了数字货币的可信支付。</p><ul><li>世界上最早的纸币出现在中国宋朝，称为“交子”。纸币的发行机制决定了必须由政府发行，并且强行推广使用，因此纸币又称法币。</li><li>电子货币本质上仍然是法币，它仍然是由央行发行，只是以计算机技术把货币以实体纸币形式的流通变成了银行计算机系统的存款。和纸币相比，电子货币具有更高的流动性。我们每天使用的网上银行、支付宝、微信支付等，都是这种方式。</li><li>而比特币作为一种数字货币，它和电子货币不同的是，比特币不需要一个类似银行的中央信任机构，就可以通过全球P2P网络进行发行和流通，这一点听上去有点不可思议，但比特币正是一种通过密码学理论建立的不可伪造的货币系统。</li></ul><h2 id="比特币解决的问题"><a href="#比特币解决的问题" class="headerlink" title="比特币解决的问题"></a>比特币解决的问题</h2><p>比特币通过技术手段解决了现金电子化以后交易的清结算问题。</p><p>可以这么理解，传统的金融行业的交易是基于中央数据库的数据增减进行的，这些交易高度依赖专业的开发和运维人员，以及完善的风控机制。</p><p>总的来说，比特币具有以下特点：</p><ul><li>创建了无需信任中心的货币发行机制；</li><li>发行数量由程序决定，无法随意修改；</li><li>交易账本完全公开可追溯，不可篡改；</li><li>密码学理论保证货币防伪造，防双花；</li><li>数字签名机制保证交易完整可信，不可抵赖和撤销。</li></ul><p>即为<code>点对点的电子现金系统</code>。</p><h2 id="区块链的原理"><a href="#区块链的原理" class="headerlink" title="区块链的原理"></a>区块链的原理</h2><p>区块链就是一个不断增长的全网总账本，每个完全节点都拥有完整的区块链，并且，节点总是信任最长的区块链，伪造区块链需要拥有超过51%的全网算力。</p><p>区块链不可篡改。</p><p>区块链是由一个一个区块构成的有序链表，每一个区块都记录了一系列交易，并且，每个区块都指向前一个区块，从而形成一个链条：</p><p><img src="/../images/image-20250422103656007.png" alt="image-20250422103656007"></p><p>每一个区块上都有唯一的哈希标识，称为区块哈希，区块通过记录上一个区块的哈希来指向上一个区块：</p><p><img src="/../images/image-20250422103810831.png" alt="image-20250422103810831"></p><p>每一个区块上面还有Merkle哈希用来确保该区块的所有交易记录无法被篡改，区块链中的主要数据就是一系列交易，第一条交易通常是Coinbase交易，也就是矿工的挖矿奖励，后续交易都是用户的交易。</p><p>Coinbase交易是每个区块中的第一笔交易，没有输入（UTXO来源），由矿工创建，用于生成新的比特币。</p><p>比特币网络通过Coinbase交易实现货币发行，是系统中新比特币进入流通的唯一方式。Coinbase奖励需100区块确认（约16小时）后才可花费，防止双花攻击。交易哈希固定为<code>0000000000000000000000000000000000000000000000000000000000000000</code>。矿工可在coinbase字段添加任意信息（如创世区块包含《泰晤士报》头版标题）。</p><p>这种设计将货币发行与网络安全维护深度绑定，通过经济激励实现去中心化网络的自我维持，是比特币经济模型的核心创新之一。</p><h3 id="哈希算法"><a href="#哈希算法" class="headerlink" title="哈希算法"></a>哈希算法</h3><p>哈希算法，又称散列算法，它是一个单向函数，可以把任意长度的输入数据转化为固定长度的输出：<br>$$<br>h &#x3D; \mathbf{H}(x)<br>$$<br>我们通常用十六进制表示哈希输出。</p><p>类似的，Git 的 commit 每一次也生成的是哈希算法。</p><p>例如，对<code>morning</code>和<code>bitcoin</code>两个输入进行某种哈希运算，得到的结果是固定长度的数字：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">H(&quot;morning&quot;) = c7c3169c21f1d92e9577871831d067c8</span><br><span class="line">H(&quot;bitcoin&quot;) = cd5b1e4947e304476c788cd474fb579a</span><br></pre></td></tr></table></figure><p>因为哈希算法是一个单向函数，要设计一个安全的哈希算法，就必须满足：通过输入可以很容易地计算输出，但是，反过来，通过输出无法反推输入，只能暴力穷举。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">H(&quot;???????&quot;) = c7c3169c21f1d92e9577871831d067c8</span><br><span class="line">H(&quot;???????&quot;) = cd5b1e4947e304476c788cd474fb579a</span><br></pre></td></tr></table></figure><p>根据输出反推输入，只能暴力穷举。</p><h3 id="哈希碰撞"><a href="#哈希碰撞" class="headerlink" title="哈希碰撞"></a>哈希碰撞</h3><ul><li>安全的哈希算法要满足另外一个条件：碰撞率低。</li></ul><p>碰撞是指，如果两个输入数据不同，却恰好计算出了相同的哈希值，那么我们说发生了碰撞。</p><p>因为输入数据长度是不固定的，所以输入数据是一个无限大的集合，而输出数据长度是固定的，所以，输出数据是一个有限的集合。把一个无限的集合中的每个元素映射到一个有限的集合，就必然存在某些不同的输入得到了相同的输出。</p><p>哈希碰撞的本质是把无限的集合映射到有限的集合时必然会产生碰撞。我们需要计算的是碰撞的概率。很显然，碰撞的概率和输出的集合大小相关。输出位数越多，输出集合就越大，碰撞率就越低。</p><ul><li>安全的哈希算法满足还有一个条件：输出无规律。</li></ul><p>输入数据任意一个bit（某个字节的某一个二进制位）的改动，会导致输出完全不同，从而让攻击者无法逐步猜测输入，只能依赖暴力穷举来破解：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">H(&quot;hello-1&quot;) = 970db54ab8a93b7173cb48f55e67fd2c</span><br><span class="line">H(&quot;hello-2&quot;) = 8284353b768977f05ac600baad8d3d17</span><br></pre></td></tr></table></figure><p>关于哈希算法的作用：</p><p>如果两个输入的哈希相同，我们认为两个输入是相同的。</p><p>验证是否被篡改：</p><p>如果输入的内容就是文件内容，而两个文件的哈希相同，说明文件没有被修改过。当我们从网站上下载一个非常大的文件时，我们如何确定下载到本地的文件和官方网站发布的原始文件是完全相同，没有经过修改的呢？哈希算法就体现出了作用：我们只需要计算下载到本地的文件哈希，再和官方网站给出的哈希对比，如果一致，说明下载文件是正确的，没有经过篡改，如果不一致，则说明下载的文件肯定被篡改过。</p><p>大多数软件的官方下载页面会同时给出该文件的哈希值，以便让用户下载后验证文件是否被篡改。</p><p>和文件类似，如果两份数据的哈希相同，则几乎可以100%肯定，两份数据是相同的。</p><p>比特币使用哈希算法来保证所有交易不可修改，就是计算并记录交易的哈希，如果交易被篡改，那么哈希验证将无法通过，说明这个区块是无效的。</p><h3 id="常用哈希算法"><a href="#常用哈希算法" class="headerlink" title="常用哈希算法"></a>常用哈希算法</h3><table><thead><tr><th>哈希算法</th><th>输出长度(bit)</th><th>输出长度(字节)</th></tr></thead><tbody><tr><td>MD5</td><td>128 bit</td><td>16 bytes</td></tr><tr><td>RipeMD160</td><td>160 bits</td><td>20 bytes</td></tr><tr><td>SHA-1</td><td>160 bits</td><td>20 bytes</td></tr><tr><td>SHA-256</td><td>256 bits</td><td>32 bytes</td></tr><tr><td>SHA-512</td><td>512 bits</td><td>64 bytes</td></tr></tbody></table><p>而比特币当中使用的两种哈希算法是 SHA-256 和 RipeMD160。</p><p>SHA-256的理论碰撞概率是：尝试2的130次方的随机输入，有99.8%的概率碰撞。注意2130是一个非常大的数字，大约是1361万亿亿亿亿。以现有的计算机的计算能力，是不可能在短期内破解的。</p><p>这里还有两种计算方式：</p><ul><li>一种是对数据进行两次SHA-256计算，这种算法在比特币协议中通常被称为hash256或者dhash。</li><li>另一种算法是先计算SHA-256，再计算RipeMD160，这种算法在比特币协议中通常被称为hash160。</li></ul><p>不同哈希算法计算结果：</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span></span><br><span class="line">    bitcoin = <span class="built_in">require</span>(<span class="string">&#x27;bitcoinjs-lib&#x27;</span>),</span><br><span class="line">    createHash = <span class="built_in">require</span>(<span class="string">&#x27;create-hash&#x27;</span>);</span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">standardHash</span>(<span class="params">name, data</span>) &#123;</span><br><span class="line">    <span class="keyword">let</span> h = <span class="title function_">createHash</span>(name);</span><br><span class="line">    <span class="keyword">return</span> h.<span class="title function_">update</span>(data).<span class="title function_">digest</span>();</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">hash160</span>(<span class="params">data</span>) &#123;</span><br><span class="line">    <span class="keyword">let</span> h1 = <span class="title function_">standardHash</span>(<span class="string">&#x27;sha256&#x27;</span>, data);</span><br><span class="line">    <span class="keyword">let</span> h2 = <span class="title function_">standardHash</span>(<span class="string">&#x27;ripemd160&#x27;</span>, h1);</span><br><span class="line">    <span class="keyword">return</span> h2;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">hash256</span>(<span class="params">data</span>) &#123;</span><br><span class="line">    <span class="keyword">let</span> h1 = <span class="title function_">standardHash</span>(<span class="string">&#x27;sha256&#x27;</span>, data);</span><br><span class="line">    <span class="keyword">let</span> h2 = <span class="title function_">standardHash</span>(<span class="string">&#x27;sha256&#x27;</span>, h1);</span><br><span class="line">    <span class="keyword">return</span> h2;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> s = <span class="string">&#x27;bitcoin is awesome&#x27;</span>;</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;ripemd160 = &#x27;</span> + <span class="title function_">standardHash</span>(<span class="string">&#x27;ripemd160&#x27;</span>, s).<span class="title function_">toString</span>(<span class="string">&#x27;hex&#x27;</span>));</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;  hash160 = &#x27;</span> + <span class="title function_">hash160</span>(s).<span class="title function_">toString</span>(<span class="string">&#x27;hex&#x27;</span>));</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;   sha256 = &#x27;</span> + <span class="title function_">standardHash</span>(<span class="string">&#x27;sha256&#x27;</span>, s).<span class="title function_">toString</span>(<span class="string">&#x27;hex&#x27;</span>));</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;  hash256 = &#x27;</span> + <span class="title function_">hash256</span>(s).<span class="title function_">toString</span>(<span class="string">&#x27;hex&#x27;</span>));</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>计算结果如下：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">ripemd160 = 46c047bd035afb64dad2293cba29994a95b8b216</span><br><span class="line">  hash160 = fe56649aa4f8fdb1edf6b88d2d41f3c1f72cf431</span><br><span class="line">   sha256 = 23d4a09295be678b21a5f1dceae1f634a69c1b41775f680ebf8165266471401b</span><br><span class="line">  hash256 = 1c78f53758ac96f43b99ed080f36327d2a823c4df4fa094e59b006d945bbb84d</span><br></pre></td></tr></table></figure><p>SHA-256、RipeMD160、hash256 和 hash160 的结果如上述所示。</p><h3 id="区块链不可篡改特性"><a href="#区块链不可篡改特性" class="headerlink" title="区块链不可篡改特性"></a>区块链不可篡改特性</h3><p>区块本身记录的主要数据就是一系列交易，所以，区块链首先要保证任何交易数据都不可修改。</p><h4 id="Merkle-Hash"><a href="#Merkle-Hash" class="headerlink" title="Merkle Hash"></a>Merkle Hash</h4><p>在区块的头部，有一个Merkle Hash字段，它记录了本区块所有交易的Merkle Hash：</p><p><img src="/../images/image-20250422113608115.png" alt="image-20250422113608115"></p><p>Merkle Hash是把一系列数据的哈希根据一个简单算法变成一个汇总的哈希。</p><p>假设一个区块有4个交易，我们对每个交易数据做dhash，得到4个哈希值<code>a1</code>，<code>a2</code>，<code>a3</code>和<code>a4</code>：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">a1 = dhash(tx1)</span><br><span class="line">a2 = dhash(tx2)</span><br><span class="line">a3 = dhash(tx3)</span><br><span class="line">a4 = dhash(tx4)</span><br></pre></td></tr></table></figure><p>注意到哈希值也可以看做数据，所以可以把<code>a1</code>和<code>a2</code>拼起来，<code>a3</code>和<code>a4</code>拼起来，再计算出两个哈希值<code>b1</code>和<code>b2</code>：</p><p><img src="/../images/image-20250422113744600.png" alt="image-20250422113744600"></p><p>最后，把<code>b1</code>和<code>b2</code>这两个哈希值拼起来，计算出最终的哈希值，这个哈希就是Merkle Hash：</p><p><img src="/../images/image-20250422113800380.png" alt="image-20250422113800380"></p><p>但是交易不是偶数个怎么办？</p><p>只有3个交易时，第一个和第二个交易的哈希<code>a1</code>和<code>a2</code>可以拼起来算出<code>b1</code>，第三个交易只能算出一个哈希<code>a3</code>，这个时候，就把a3直接复制一份，算出<code>b2</code>，这样，我们也能最终计算出Merkle Hash：</p><p><img src="/../images/image-20250422113832328.png" alt="image-20250422113832328"></p><p>如果有5个交易，我们可以看到，<code>a5</code>被复制了一份，以便计算出<code>b3</code>，随后<code>b3</code>也被复制了一份，以便计算出<code>c2</code>。总之，在每一层计算中，如果有单数，就把最后一份数据复制，最后一定能计算出Merkle Hash：</p><p><img src="/../images/image-20250422113849105.png" alt="image-20250422113849105"></p><p>从Merkle Hash的计算方法可以得出结论：修改任意一个交易哪怕一个字节，或者交换两个交易的顺序，都会导致Merkle Hash验证失败，也就会导致这个区块本身是无效的，所以，Merkle Hash记录在区块头部，它的作用就是保证交易记录永远无法修改。</p><h4 id="Block-Hash"><a href="#Block-Hash" class="headerlink" title="Block Hash"></a>Block Hash</h4><p>区块本身用Block Hash——也就是区块哈希来标识。但是，一个区块自己的区块哈希并没有记录在区块头部，而是通过计算区块头部的哈希得到的：</p><p><img src="/../images/image-20250422113953387.png" alt="image-20250422113953387"></p><p>区块头部的Prev Hash记录了上一个区块的Block Hash，这样，可以通过Prev Hash追踪到上一个区块。</p><p>由于下一个区块的Prev Hash又会指向当前区块，这样，每个区块的Prev Hash都指向自己的上一个区块，这些区块串起来就形成了区块链。</p><p>区块链的第一个区块（又称创世区块）并没有上一个区块，因此，它的Prev Hash被设置为<code>00000000...000</code>。Coinbase 就这么结合起来了。</p><p>如果一个恶意的攻击者修改了一个区块中的某个交易，那么Merkle Hash验证就不会通过。所以，他只能重新计算Merkle Hash，然后把区块头的Merkle Hash也修改了。这时，我们就会发现，这个区块本身的Block Hash就变了，所以，下一个区块指向它的链接就断掉了。</p><p><img src="/../images/image-20250422114120316.png" alt="image-20250422114120316"></p><p>由于比特币区块的哈希必须满足一个难度值，因此，攻击者必须先重新计算这个区块的Block Hash，然后，再把后续所有区块全部重新计算并且伪造出来，才能够修改整个区块链。</p><p>在后面的挖矿中，我们会看到，修改一个区块的成本就已经非常非常高了，要修改后续所有区块，这个攻击者必须掌握全网51%以上的算力才行，所以，修改区块链的难度是非常非常大的，并且，由于正常的区块链在不断增长，同样一个区块，修改它的难度会随着时间的推移而不断增加。</p><h2 id="P2P（peer-to-peer）交易原理"><a href="#P2P（peer-to-peer）交易原理" class="headerlink" title="P2P（peer to peer）交易原理"></a>P2P（peer to peer）交易原理</h2><p>比特币的交易是一种无需信任中介参与的P2P（Peer-to-peer）交易。就是可理解成一种点对点的交易。</p><p>传统交易需要一个中间商确保交易安全性例如银行，因为银行记录了交易双方的账户资金，能保证在一笔交易中，要么保证成功，要么交易无效，不存在一方到账而另一方没有付款的情况。</p><p>但是在比特币这种去中心化的P2P网络中，并没有一个类似银行这样的信任机构存在，要想在两个节点之间达成交易，就必须实现一种在零信任的情况下安全交易的机制。</p><p>创建交易有两种方法：</p><ul><li>B 和 A 希望达成一笔交易，一种创建交易的方法是 A 声称 B 给了他1万块钱，显然这是不可信的。</li><li>B 声称他给了 A 一万块钱，只要能验证这个声明确实是 B 作出的，并且 B 真的有1万块钱，那么这笔交易就被认为是有效的。</li></ul><h3 id="数字签名"><a href="#数字签名" class="headerlink" title="数字签名"></a>数字签名</h3><p>如何确认这个声明是 B 做出的，这就要用到数字签名，而且不可篡改。</p><p>在比特币交易中，付款方就是通过数字签名来证明自己拥有某一笔比特币，并且，要把这笔比特币转移给指定的收款方。</p><p>使用签名是为了验证某个声明确实是由某个人做出的。例如，在付款合同中签名，可以通过验证笔迹的方式核对身份。</p><p>用密码学理论设计的数字签名算法比验证笔迹更加可信。</p><p>使用数字签名时，每个人都可以自己生成一个秘钥对，这个秘钥对包含一个私钥和一个公钥：私钥被称为 Secret Key 或者 Private Key，私钥必须严格保密，不能泄漏给其他人；公钥被称为 Public Key，可以公开给任何人。</p><p>当某人想发送一个什么签名消息的时候，他可以用私钥对消息进行签名，然后，把消息、签名和自己的公钥发送出去。</p><p>其他任何人都可以通过他的公钥对这个签名进行验证，如果验证通过，可以肯定，该消息是他发出的。</p><p>所以类似在线支付、电子商务等领域，数字签名的应用有很大的作用：</p><ul><li>签名不可伪造，因为私钥只有签名人自己知道，所以其他人无法伪造签名。</li><li>消息不可篡改，如果原始消息被人篡改了，那么对签名进行验证将失败。</li><li>签名不可抵赖，如果对签名进行验证通过了，那么，该消息肯定是由签名人自己发出的，他不能抵赖自己曾经发过这一条消息。</li></ul><blockquote><p>数字签名：防伪造，防篡改，防抵赖。</p></blockquote><h3 id="数字签名算法"><a href="#数字签名算法" class="headerlink" title="数字签名算法"></a>数字签名算法</h3><p>常用的数字签名算法有：RSA算法，DSA算法和ECDSA算法。</p><p>比特币采用的签名算法是椭圆曲线签名算法：ECDSA，使用的椭圆曲线是一个已经定义好的标准曲线secp256k1：<br>$$<br>y^{2} &#x3D; x^{3} + 7<br>$$</p><p>长这样：</p><p><img src="/../images/image-20250422115819953.png" alt="image-20250422115819953"></p><p>比特币采用的ECDSA签名算法需要一个私钥和公钥组成的秘钥对：私钥本质上就是一个1～ $2^{256}$ 的随机数，公钥是由私钥根据ECDSA算法推算出来的，通过私钥可以很容易推算出公钥，所以不必保存公钥，但是，通过公钥无法反推私钥，只能暴力破解。</p><p>比特币的私钥是一个随机的非常大的256位整数。它的上限，确切地说，比 $2^{256}$ 要稍微小一点：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">0xFFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFE BAAE DCE6 AF48 A03B BFD2 5E8C D036 4140</span><br></pre></td></tr></table></figure><p>而比特币的公钥是根据私钥推算出的两个256位整数。</p><p>可以这么类比，公钥就是银行卡号，私钥就是银行卡密码。</p><p>但是银行卡号是确定的，密码可以修改，然而比特币私钥（密码）事先确定，然后计算出公钥（卡号），卡号是由密码通过ECDSA算法推导出来的，密码不可以更改，更改了密码之后相当于所有的东西都改了，不是原本的那一版东西了。</p><p>由于比特币账本是全网公开的，所以，任何人都可以根据公钥查询余额，但是，不知道持卡人是谁。</p><p>这就是比特币的匿名特性。</p><blockquote><p>私钥不能丢失，丢失了之后里面对应的比特币也丢失了。</p></blockquote><p>忘记银行卡密码可以拿身份证到银行重新设置一个密码，因为密码是存储在银行的计算机中的，而比特币的P2P网络不存在中央节点，私钥只有持有人自己知道，因此，丢失了私钥，对应的比特币就永远无法花费。如果私钥泄露，别人就可以花费对应公钥的比特币，而且无法追回。</p><p>比特币私钥的安全性在于如何生成一个安全的256位的随机数。<em>不要试图自己想一个随机数</em>，而是应当使用编程语言提供的<em>安全随机数</em>算法，但绝对不能使用<em>伪随机数</em>。</p><blockquote><p>绝不能自己想一个私钥或者使用伪随机数创建私钥。</p></blockquote><h4 id="伪随机数"><a href="#伪随机数" class="headerlink" title="伪随机数"></a>伪随机数</h4><p>伪随机数是指通过确定性算法生成的看似随机但实际上可预测的数字序列。它们在计算机科学和统计学中广泛应用。</p><p>主要特点</p><ol><li><strong>确定性</strong>：由算法生成，给定相同的初始条件（种子）会产生相同的序列</li><li><strong>统计特性</strong>：具有良好的统计随机性（均匀分布、独立性等）</li><li><strong>周期性</strong>：所有伪随机数生成器最终都会重复其序列</li></ol><p>常见生成算法</p><ol><li>线性同余法 (LCG)</li></ol><p>最简单的伪随机数生成方法，公式为：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Xₙ₊₁ = (a × Xₙ + c) mod m</span><br></pre></td></tr></table></figure><p>其中Xₙ是序列中的第n个数，a、c、m是精心选择的常数。</p><ol start="2"><li>梅森旋转算法 (Mersenne Twister)</li></ol><p>现代广泛使用的算法，特点：</p><ul><li>周期极长(2^19937-1)</li><li>623维均匀分布</li><li>速度快</li></ul><ol start="3"><li>密码学安全伪随机数生成器 (CSPRNG)</li></ol><p>如Fortuna、Yarrow等，用于加密场景，具有：</p><ul><li>不可预测性</li><li>即使部分序列被知道也无法推断其他部分</li></ul><p>应用领域</p><ul><li>模拟与建模</li><li>计算机游戏</li><li>数值分析</li><li>统计抽样</li><li>加密系统（需使用CSPRNG）</li></ul><p>与真随机数的区别</p><table><thead><tr><th>特性</th><th>伪随机数</th><th>真随机数</th></tr></thead><tbody><tr><td>生成方式</td><td>算法计算</td><td>物理现象</td></tr><tr><td>可预测性</td><td>可预测</td><td>不可预测</td></tr><tr><td>重现性</td><td>可重现</td><td>不可重现</td></tr><tr><td>速度</td><td>快</td><td>相对慢</td></tr></tbody></table><p>在大多数计算应用中，伪随机数已足够，但在加密等安全敏感领域通常需要真随机数。</p><h3 id="比特币钱包"><a href="#比特币钱包" class="headerlink" title="比特币钱包"></a>比特币钱包</h3><p>比特币钱包实际上就是帮助用户管理私钥的软件。因为比特币的钱包是给普通用户使用的，它有几种分类：</p><ul><li>本地钱包：是把私钥保存在本地计算机硬盘上的钱包软件，如<a href="https://electrum.org/">Electrum</a>；</li><li>手机钱包：和本地钱包类似，但可以直接在手机上运行，如<a href="https://bitpay.com/">Bitpay</a>；</li><li>在线钱包：是把私钥委托给第三方在线服务商保存；</li><li>纸钱包：是指把私钥打印出来保存在纸上；</li><li>脑钱包：是指把私钥记在自己脑袋里。</li></ul><blockquote><p>不建议使用脑钱包（）</p></blockquote><p>和银行账户不同，比特币网络没有账户的概念，任何人都可以从区块链查询到任意公钥对应的比特币余额，但是，并不知道这些公钥是由谁持有的，也就无法根据用户查询比特币余额。</p><p>作为用户，可以生成任意数量的私钥-公钥对，公钥是接收别人转账的地址，而私钥是花费比特币的唯一手段，钱包程序可以帮助用户管理私钥-公钥对。</p><h3 id="交易"><a href="#交易" class="headerlink" title="交易"></a>交易</h3><p>在区块链当中，每一个区块都至少记录了一笔交易，一笔交易就是把一定金额的比特币从一个输入转入到一个输出，实际记录的是双方的公钥地址。</p><p>当小红有两笔收入时，一笔<code>2.0</code>，一笔<code>1.5</code>，她想给小白转<code>3.5</code>比特币时，就不能单用一笔输出，她必须把两笔钱合起来再花掉，这种情况就是一个交易对应多个输入和1个输出：</p><p><img src="/../images/image-20250422131832223.png" alt="image-20250422131832223"></p><p>如果存在找零，这笔交易就既包含多个输入也包含多个输出：</p><p><img src="/../images/image-20250422131844251.png" alt="image-20250422131844251"></p><p>在实际的交易中，输入比输出要稍微大一点点，这个差额就是隐含的交易费用，交易费用会算入当前区块的矿工收入中作为矿工奖励的一部分：</p><p><img src="/../images/image-20250422131856913.png" alt="image-20250422131856913"></p><p>计算出的交易费用：</p><p>交易费用 &#x3D; 输入 - 输出 &#x3D; (2.0 + 1.5) - (2.99 + 0.49) &#x3D; 3.5 - 3.48 &#x3D; 0.02</p><p>比特币实际的交易记录是由一系列交易构成，每一个交易都包含一个或多个输入，以及一个或多个输出。</p><p>未花费的输出被称为 UTXO：Unspent Transaction Output。</p><p>当我们要简单验证某个交易的时候，例如，对于交易<code>f36abd</code>，它记录的输入是<code>3f96ab</code>，索引号是<code>1</code>（索引号从<code>0</code>开始，<code>0</code>表示第一个输出，<code>1</code>表示第二个输出，以此类推），我们就根据<code>3f96ab</code>找到前面已发生的交易，再根据索引号找到对应的输出是<code>0.5</code>个比特币，所以，这笔交易的输入总计是<code>0.5</code>个比特币，输出分别是<code>0.4</code>个比特币和<code>0.09</code>个比特币，隐含的交易费用是<code>0.01</code>个比特币：</p><p><img src="/../images/image-20250422131956698.png" alt="image-20250422131956698"></p><p>比特币的交易有一定的成本存在付给矿工，和银行转账手续费，即维护或者运行电子交易模式存在一定的成本异曲同工。</p><h3 id="私钥"><a href="#私钥" class="headerlink" title="私钥"></a>私钥</h3><p>在比特币中，私钥本质上就是一个256位的随机整数。我们以JavaScript为例，演示如何创建比特币私钥。</p><p>在JavaScript中，内置的Number类型使用56位表示整数和浮点数，最大可表示的整数最大只有<code>9007199254740991</code>。其他语言如Java一般也仅提供64位的整数类型。要表示一个256位的整数，可以用数组来模拟。<a href="https://github.com/bitcoinjs">bitcoinjs</a>使用<a href="https://github.com/cryptocoinjs/bigi">bigi</a>这个库来表示任意大小的整数。</p><p>下面的代码演示了通过<code>ECPair</code>创建一个新的私钥后，表示私钥的整数就是字段<code>d</code>，我们把它打印出来：</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> bitcoin = <span class="built_in">require</span>(<span class="string">&#x27;bitcoinjs-lib&#x27;</span>);</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> keyPair = bitcoin.<span class="property">ECPair</span>.<span class="title function_">makeRandom</span>();</span><br><span class="line"><span class="comment">// 打印私钥:</span></span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;private key = &#x27;</span> + keyPair.<span class="property">d</span>);</span><br><span class="line"><span class="comment">// 以十六进制打印:</span></span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;hex = &#x27;</span> + keyPair.<span class="property">d</span>.<span class="title function_">toHex</span>());</span><br><span class="line"><span class="comment">// 补齐32位:</span></span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;hex = &#x27;</span> + keyPair.<span class="property">d</span>.<span class="title function_">toHex</span>(<span class="number">32</span>));</span><br></pre></td></tr></table></figure><p>每次打印结果都不一样：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">private key = 41331959824821034980258191057666381818244956280198868196301393762546465594490</span><br><span class="line">hex = 5b610f6c059c45e441908d8417dcc7298027ce9b3ee53874eecc944cbb035c7a</span><br><span class="line">hex = 5b610f6c059c45e441908d8417dcc7298027ce9b3ee53874eecc944cbb035c7a</span><br></pre></td></tr></table></figure><p>随机的<code>ECPair</code>，每次生成的私钥都是不同的。</p><p>256位的整数通常以十六进制表示，使用<code>toHex(32)</code>我们可以获得一个固定64字符的十六进制字符串。注意每两个十六进制字符表示一个字节，因此，64字符的十六进制字符串表示的是32字节&#x3D;256位整数。</p><p>想要记住一个256位的整数是非常困难的，并且，如果记错了其中某些位，这个记错的整数仍然是一个<em>有效的私钥</em>，因此，比特币有一种对私钥进行编码的方式，这种编码方式就是带校验的<a href="https://zh.wikipedia.org/wiki/Base58">Base58编码</a>。</p><p>对私钥进行Base58编码有两种方式，一种是非压缩的私钥格式，一种是压缩的私钥格式，它们分别对应非压缩的公钥格式和压缩的公钥格式。</p><p>具体地来说，&#x3D;&#x3D;非压缩&#x3D;&#x3D;的私钥格式是指在32字节的私钥前添加一个<code>0x80</code>字节前缀，得到33字节的数据，对其计算4字节的校验码，附加到最后，一共得到37字节的数据：</p><p><img src="/../images/image-20250422135908712.png" alt="image-20250422135908712"></p><p>对这37字节的数据进行Base58编码，得到总是以<code>5</code>开头的字符串编码，这个字符串就是我们需要非常小心地保存的私钥地址，又称为钱包导入格式：WIF（Wallet Import Format），整个过程如下图所示（理解一下就好了，不用深入）：</p><p><img src="/../images/image-20250422140632552.png" alt="image-20250422140632552"></p><p>可以使用<a href="https://github.com/bitcoinjs/wif">wif</a>这个库实现WIF编码：</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> wif = <span class="built_in">require</span>(<span class="string">&#x27;wif&#x27;</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">// 十六进制表示的私钥:</span></span><br><span class="line"><span class="keyword">let</span> privateKey = <span class="string">&#x27;0c28fca386c7a227600b2fe50b7cae11ec86d3bf1fbe471be89827e19d72aa1d&#x27;</span>;</span><br><span class="line"><span class="comment">// 对私钥编码:</span></span><br><span class="line"><span class="keyword">let</span> encoded = wif.<span class="title function_">encode</span>(</span><br><span class="line">        <span class="number">0x80</span>, <span class="comment">// 0x80前缀</span></span><br><span class="line">        <span class="title class_">Buffer</span>.<span class="title function_">from</span>(privateKey, <span class="string">&#x27;hex&#x27;</span>), <span class="comment">// 转换为字节</span></span><br><span class="line">        <span class="literal">false</span> <span class="comment">// 非压缩格式</span></span><br><span class="line">);</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(encoded);</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>打印结果如下：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">5HueCGU8rMjxEXxiPuD5BDku4MkFqeZyd4dZ1jvhTVqvbTLvyTJ</span><br></pre></td></tr></table></figure><p>另一种压缩格式的私钥编码方式，与非压缩格式不同的是，&#x3D;&#x3D;压缩&#x3D;&#x3D;的私钥格式会在32字节的私钥前后各添加一个<code>0x80</code>字节前缀和<code>0x01</code>字节后缀，共34字节的数据，对其计算4字节的校验码，附加到最后，一共得到38字节的数据：</p><p><img src="/../images/image-20250422141024228.png" alt="image-20250422141024228"></p><p>对这38字节的数据进行Base58编码，得到总是以<code>K</code>或<code>L</code>开头的字符串编码，整个过程如下图所示：</p><p><img src="/../images/image-20250422141039663.png" alt="image-20250422141039663"></p><p>通过代码实现压缩格式的WIF编码如下：</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> wif = <span class="built_in">require</span>(<span class="string">&#x27;wif&#x27;</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">// 十六进制表示的私钥:</span></span><br><span class="line"><span class="keyword">let</span> privateKey = <span class="string">&#x27;0c28fca386c7a227600b2fe50b7cae11ec86d3bf1fbe471be89827e19d72aa1d&#x27;</span>;</span><br><span class="line"><span class="comment">// 对私钥编码:</span></span><br><span class="line"><span class="keyword">let</span> encoded = wif.<span class="title function_">encode</span>(</span><br><span class="line">        <span class="number">0x80</span>, <span class="comment">// 0x80前缀</span></span><br><span class="line">        <span class="title class_">Buffer</span>.<span class="title function_">from</span>(privateKey, <span class="string">&#x27;hex&#x27;</span>), <span class="comment">// 转换为字节</span></span><br><span class="line">        <span class="literal">true</span> <span class="comment">// 压缩格式</span></span><br><span class="line">);</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(encoded);</span><br></pre></td></tr></table></figure><p>打印结果如下：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">KwdMAjGmerYanjeui5SHS7JkmpZvVipYvB2LJGU1ZxJwYvP98617</span><br></pre></td></tr></table></figure><p>目前，非压缩的格式几乎已经不使用了。bitcoinjs提供的<code>ECPair</code>总是使用压缩格式的私钥表示：</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span></span><br><span class="line">    bitcoin = <span class="built_in">require</span>(<span class="string">&#x27;bitcoinjs-lib&#x27;</span>),</span><br><span class="line">    <span class="title class_">BigInteger</span> = <span class="built_in">require</span>(<span class="string">&#x27;bigi&#x27;</span>);</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span></span><br><span class="line">    priv = <span class="string">&#x27;0c28fca386c7a227600b2fe50b7cae11ec86d3bf1fbe471be89827e19d72aa1d&#x27;</span>,</span><br><span class="line">    d = <span class="title class_">BigInteger</span>.<span class="title function_">fromBuffer</span>(<span class="title class_">Buffer</span>.<span class="title function_">from</span>(priv, <span class="string">&#x27;hex&#x27;</span>)),</span><br><span class="line">    keyPair = <span class="keyword">new</span> bitcoin.<span class="title class_">ECPair</span>(d);</span><br><span class="line"><span class="comment">// 打印WIF格式的私钥:</span></span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(keyPair.<span class="title function_">toWIF</span>());</span><br></pre></td></tr></table></figure><p>第八行的 ECPair 函数就是使用压缩格式私钥，打印结果也一样：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">KwdMAjGmerYanjeui5SHS7JkmpZvVipYvB2LJGU1ZxJwYvP98617</span><br></pre></td></tr></table></figure><h3 id="公钥和地址"><a href="#公钥和地址" class="headerlink" title="公钥和地址"></a>公钥和地址</h3><h4 id="公钥"><a href="#公钥" class="headerlink" title="公钥"></a>公钥</h4><p>比特币的公钥是根据私钥计算出来的。</p><p>私钥本质上是一个256位整数，记作<code>k</code>。根据比特币采用的ECDSA算法，可以推导出两个256位整数，记作<code>(x, y)</code>，这两个256位整数即为非压缩格式的公钥。</p><p>由于ECC曲线的特点，根据非压缩格式的公钥<code>(x, y)</code>的<code>x</code>实际上也可推算出<code>y</code>，但需要知道<code>y</code>的奇偶性，因此，可以根据<code>(x, y)</code>推算出<code>x&#39;</code>，作为压缩格式的公钥。</p><p>缩格式的公钥实际上只保存<code>x</code>这一个256位整数，但需要根据<code>y</code>的奇偶性在<code>x</code>前面添加<code>02</code>或<code>03</code>前缀，<code>y</code>为偶数时添加<code>02</code>，否则添加<code>03</code>，这样，得到一个1+32&#x3D;33字节的压缩格式的公钥数据，记作<code>x&#39;</code>。</p><p>注意压缩格式的公钥和非压缩格式的公钥是可以互相转换的，但均不可反向推导出私钥。</p><p>非压缩格式的公钥目前已很少使用，原因是非压缩格式的公钥签名脚本数据会更长。</p><p>根据私钥推算出公钥：</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> bitcoin = <span class="built_in">require</span>(<span class="string">&#x27;bitcoinjs-lib&#x27;</span>);</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span></span><br><span class="line">    wif = <span class="string">&#x27;KwdMAjGmerYanjeui5SHS7JkmpZvVipYvB2LJGU1ZxJwYvP98617&#x27;</span>,</span><br><span class="line">    ecPair = bitcoin.<span class="property">ECPair</span>.<span class="title function_">fromWIF</span>(wif); <span class="comment">// 导入私钥</span></span><br><span class="line"><span class="comment">// 计算公钥:</span></span><br><span class="line"><span class="keyword">let</span> pubKey = ecPair.<span class="title function_">getPublicKeyBuffer</span>(); <span class="comment">// 返回Buffer对象</span></span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(pubKey.<span class="title function_">toString</span>(<span class="string">&#x27;hex&#x27;</span>)); <span class="comment">// 02或03开头的压缩公钥</span></span><br></pre></td></tr></table></figure><p>打印结果如下：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">2d0de0aaeaefad02b8bdc8a01a1b8b11c696bd3d66a2c5f10780d95b7df42645c</span><br></pre></td></tr></table></figure><p>构造出<code>ECPair</code>对象后，即可通过<code>getPublicKeyBuffer()</code>以<code>Buffer</code>对象返回公钥数据。</p><h4 id="地址"><a href="#地址" class="headerlink" title="地址"></a>地址</h4><p>要特别注意，比特币的地址并不是公钥，而是公钥的哈希，即从公钥能推导出地址，但从地址不能反推公钥，因为哈希函数是单向函数。</p><p>以压缩格式的公钥为例，从公钥计算地址的方法是，首先对1+32&#x3D;33字节的公钥数据进行Hash160（即先计算SHA256，再计算RipeMD160），得到20字节的哈希。然后，添加<code>0x00</code>前缀，得到1+20&#x3D;21字节数据，再计算4字节校验码，拼在一起，总计得到1+20+4&#x3D;25字节数据：</p><p><img src="/../images/image-20250422150511498.png" alt="image-20250422150511498"></p><p>对上述25字节数据进行Base58编码，得到总是以<code>1</code>开头的字符串，该字符串即为比特币地址，整个过程如下：</p><p><img src="/../images/image-20250422150526699.png" alt="image-20250422150526699"></p><p>使用JavaScript实现公钥到地址的编码如下：</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> bitcoin = <span class="built_in">require</span>(<span class="string">&#x27;bitcoinjs-lib&#x27;</span>);</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span></span><br><span class="line">    publicKey = <span class="string">&#x27;02d0de0aaeaefad02b8bdc8a01a1b8b11c696bd3d66a2c5f10780d95b7df42645c&#x27;</span>,</span><br><span class="line">    ecPair = bitcoin.<span class="property">ECPair</span>.<span class="title function_">fromPublicKeyBuffer</span>(<span class="title class_">Buffer</span>.<span class="title function_">from</span>(publicKey, <span class="string">&#x27;hex&#x27;</span>)); <span class="comment">// 导入公钥</span></span><br><span class="line"><span class="comment">// 计算地址:</span></span><br><span class="line"><span class="keyword">let</span> address = ecPair.<span class="title function_">getAddress</span>();</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(address); <span class="comment">// 1开头的地址</span></span><br></pre></td></tr></table></figure><p>打印结果如下：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">1LoVGDgRs9hTfTNJNuXKSpywcbdvwRXpmK</span><br></pre></td></tr></table></figure><p>计算地址的时候，不必知道私钥，可以直接从公钥计算地址，即通过<code>ECPair.fromPublicKeyBuffer</code>构造一个不带私钥的<code>ECPair</code>即可计算出地址。</p><p>要注意，对非压缩格式的公钥和压缩格式的公钥进行哈希编码得到的地址，都是以<code>1</code>开头的，因此，从地址本身并无法区分出使用的是压缩格式还是非压缩格式的公钥。</p><p>以<code>1</code>开头的字符串地址即为比特币收款地址，可以安全地公开给任何人。</p><p>仅提供地址并不能让其他人得知公钥。通常来说，公开公钥并没有安全风险。实际上，如果某个地址上有对应的资金，要花费该资金，就需要提供公钥。如果某个地址的资金被花费过至少一次，该地址的公钥实际上就公开了。</p><p>私钥、公钥以及地址还有钱包的推导关系如下：</p><p><img src="/../images/image-20250422150735426.png" alt="image-20250422150735426"></p><h3 id="签名"><a href="#签名" class="headerlink" title="签名"></a>签名</h3><p>签名算法是使用私钥签名，公钥验证的方法，对一个消息的真伪进行确认。如果一个人持有私钥，他就可以使用私钥对任意的消息进行签名，即通过私钥<code>sk</code>对消息<code>message</code>进行签名，得到<code>signature</code>：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">signature = sign(message, sk);</span><br></pre></td></tr></table></figure><p>签名的目的是为了证明，该消息确实是由持有私钥<code>sk</code>的人发出的，任何其他人都可以对签名进行验证。验证方法是，由私钥持有人公开对应的公钥<code>pk</code>，其他人用公钥<code>pk</code>对消息<code>message</code>和签名<code>signature</code>进行验证：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">isValid = verify(message, signature, pk);</span><br></pre></td></tr></table></figure><p>如果验证通过，则可以证明该消息确实是由持有私钥<code>sk</code>的人发出的，并且未经过篡改。</p><p>数字签名算法在电子商务、在线支付这些领域有非常重要的作用，因为它能通过密码学理论证明：</p><ol><li>签名不可伪造，因为私钥只有签名人自己知道，所以其他人无法伪造签名；</li><li>消息不可篡改，如果原始消息被人篡改了，对签名进行验证将失败；</li><li>签名不可抵赖，如果对签名进行验证通过了，签名人不能抵赖自己曾经发过这一条消息。</li></ol><p>简单地说来，数字签名可以防伪造，防篡改，防抵赖。</p><p>对消息进行签名，实际上是对消息的哈希进行签名，这样可以使任意长度的消息在签名前先转换为固定长度的哈希数据。对哈希进行签名相当于保证了原始消息的不可伪造性。</p><p>我们来看看使用ECDSA如何通过私钥对消息进行签名。关键代码是通过<code>sign()</code>方法签名，并获取一个<code>ECSignature</code>对象表示签名：</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> bitcoin = <span class="built_in">require</span>(<span class="string">&#x27;bitcoinjs-lib&#x27;</span>);</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span></span><br><span class="line">    message = <span class="string">&#x27;a secret message!&#x27;</span>, <span class="comment">// 原始消息</span></span><br><span class="line">    hash = bitcoin.<span class="property">crypto</span>.<span class="title function_">sha256</span>(message), <span class="comment">// 消息哈希</span></span><br><span class="line">    wif = <span class="string">&#x27;KwdMAjGmerYanjeui5SHS7JkmpZvVipYvB2LJGU1ZxJwYvP98617&#x27;</span>,</span><br><span class="line">    keyPair = bitcoin.<span class="property">ECPair</span>.<span class="title function_">fromWIF</span>(wif);</span><br><span class="line"><span class="comment">// 用私钥签名:</span></span><br><span class="line"><span class="keyword">let</span> signature = keyPair.<span class="title function_">sign</span>(hash).<span class="title function_">toDER</span>(); <span class="comment">// ECSignature对象</span></span><br><span class="line"><span class="comment">// 打印签名:</span></span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;signature = &#x27;</span> + signature.<span class="title function_">toString</span>(<span class="string">&#x27;hex&#x27;</span>));</span><br><span class="line"><span class="comment">// 打印公钥以便验证签名:</span></span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;public key = &#x27;</span> + keyPair.<span class="title function_">getPublicKeyBuffer</span>().<span class="title function_">toString</span>(<span class="string">&#x27;hex&#x27;</span>));</span><br></pre></td></tr></table></figure><p>打印结果如下：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">signature = 304402205d0b6e817e01e22ba6ab19c0ab9cdbb2dbcd0612c5b8f990431dd0634f5a96530220188b989017ee7e830de581d4e0d46aa36bbe79537774d56cbe41993b3fd66686</span><br><span class="line">public key = 02d0de0aaeaefad02b8bdc8a01a1b8b11c696bd3d66a2c5f10780d95b7df42645c</span><br></pre></td></tr></table></figure><p><code>ECSignature</code>对象可序列化为十六进制表示的字符串。</p><p>在获得签名、原始消息和公钥的基础上，可以对签名进行验证。验证签名需要先构造一个<em>不含</em>私钥的<code>ECPair</code>，然后调用<code>verify()</code>方法验证签名：</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> bitcoin = <span class="built_in">require</span>(<span class="string">&#x27;bitcoinjs-lib&#x27;</span>);</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> signAsStr = <span class="string">&#x27;304402205d0b6e817e01e22ba6ab19c0&#x27;</span></span><br><span class="line">              + <span class="string">&#x27;ab9cdbb2dbcd0612c5b8f990431dd063&#x27;</span></span><br><span class="line">              + <span class="string">&#x27;4f5a96530220188b989017ee7e830de5&#x27;</span></span><br><span class="line">              + <span class="string">&#x27;81d4e0d46aa36bbe79537774d56cbe41&#x27;</span></span><br><span class="line">              + <span class="string">&#x27;993b3fd66686&#x27;</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span></span><br><span class="line">    signAsBuffer = <span class="title class_">Buffer</span>.<span class="title function_">from</span>(signAsStr, <span class="string">&#x27;hex&#x27;</span>),</span><br><span class="line">    signature = bitcoin.<span class="property">ECSignature</span>.<span class="title function_">fromDER</span>(signAsBuffer), <span class="comment">// ECSignature对象</span></span><br><span class="line">    message = <span class="string">&#x27;a secret message!&#x27;</span>, <span class="comment">// 原始消息</span></span><br><span class="line">    hash = bitcoin.<span class="property">crypto</span>.<span class="title function_">sha256</span>(message), <span class="comment">// 消息哈希</span></span><br><span class="line">    pubKeyAsStr = <span class="string">&#x27;02d0de0aaeaefad02b8bdc8a01a1b8b11c696bd3d66a2c5f10780d95b7df42645c&#x27;</span>,</span><br><span class="line">    pubKeyAsBuffer = <span class="title class_">Buffer</span>.<span class="title function_">from</span>(pubKeyAsStr, <span class="string">&#x27;hex&#x27;</span>),</span><br><span class="line">    pubKeyOnly = bitcoin.<span class="property">ECPair</span>.<span class="title function_">fromPublicKeyBuffer</span>(pubKeyAsBuffer); <span class="comment">// 从public key构造ECPair</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 验证签名:</span></span><br><span class="line"><span class="keyword">let</span> result = pubKeyOnly.<span class="title function_">verify</span>(hash, signature);</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;Verify result: &#x27;</span> + result);</span><br></pre></td></tr></table></figure><p>注意上述代码只引入了公钥，并没有引入私钥。</p><p>比特币对交易数据进行签名和对消息进行签名的原理是一样的，只是格式更加复杂。对交易签名确保了只有持有私钥的人才能够花费对应地址的资金。</p>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;缘由&quot;&gt;&lt;a href=&quot;#缘由&quot; class=&quot;headerlink&quot; title=&quot;缘由&quot;&gt;&lt;/a&gt;缘由&lt;/h1&gt;&lt;p&gt;区块链（Blockchain）技术源于&lt;a href=&quot;https://bitcoin.org/en/&quot;&gt;比特币&lt;/a&gt;。在比特币中，为了保</summary>
      
    
    
    
    <category term="学习笔记" scheme="https://auberginewly.site/categories/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/"/>
    
    
    <category term="SQL" scheme="https://auberginewly.site/tags/SQL/"/>
    
    <category term="CS" scheme="https://auberginewly.site/tags/CS/"/>
    
    <category term="区块链" scheme="https://auberginewly.site/tags/%E5%8C%BA%E5%9D%97%E9%93%BE/"/>
    
  </entry>
  
  <entry>
    <title>使用 vercel+twikoo 给 butterfly 主题 hexo 博客配置评论区</title>
    <link href="https://auberginewly.site/2025/04/21/17_Configure_the_comment_area/"/>
    <id>https://auberginewly.site/2025/04/21/17_Configure_the_comment_area/</id>
    <published>2025-04-21T11:50:44.000Z</published>
    <updated>2025-04-21T14:07:27.340Z</updated>
    
    <content type="html"><![CDATA[<h1 id="配置缘由"><a href="#配置缘由" class="headerlink" title="配置缘由"></a>配置缘由</h1><p>想到有些时候别人看到我的博客可能会有一些想法，于是乎我就想着把博客的评论区想着怎么配置一下，之前因为没有服务器，所以我就想试试看 giscus 来配置，但是似乎登录有 github 的限制还有就是有的时候没办法链接上评论，于是乎我就试试看了 vercel+twikoo 的组合来给 butterfly 主题 hexo 博客配置评论区，下面是配置过程。</p><h1 id="配置过程"><a href="#配置过程" class="headerlink" title="配置过程"></a>配置过程</h1><h2 id="申请-MongoDB-Atlas-账号"><a href="#申请-MongoDB-Atlas-账号" class="headerlink" title="申请 MongoDB Atlas 账号"></a>申请 MongoDB Atlas 账号</h2><blockquote><p>MongoDB Atlas 是 MongoDB Inc 提供的 MongoDB 数据库托管服务。免费账户可以永久使用 500 MiB 的数据库，足够存储 Twikoo 评论使用。</p></blockquote><p>注册 <a href="https://www.mongodb.com/cloud/atlas/register">MongoDB Atlas</a><br>可以创建免费的数据库。</p><p><img src="/../images/b0996dc1df624f4513cd929db22077ce.png" alt="b0996dc1df624f4513cd929db22077ce"></p><p>位置就在 aws 的 HK。</p><p>然后开始创建用户，点击这个 connect 就可以。</p><p><img src="/../images/image-20250421212326899.png" alt="image-20250421212326899"></p><p>这里填写你的 username 和 password，然后点击 create database user。</p><p><img src="/../images/image-20250421212346405.png" alt="image-20250421212346405"></p><p>然后点叉叉关掉这个页面，接下来配置 Network Access。</p><p><img src="/../images/image-20250421220723885.png" alt="image-20250421220723885"></p><p>接下来在 Network Access 页面点击 Add IP Address 添加网络白名单。因为 Vercel 的出口地址不固定，所以我们这里 Access List Entry 输入 <code>0.0.0.0/0</code>（允许所有 IP 地址的连接）。</p><p><img src="/../images/d289d901319f6f418b29c45b22941a84.png" alt="d289d901319f6f418b29c45b22941a84"></p><p>回到 clusters 这里点击 connect，然后连接方式选择 Drivers。</p><p><img src="/../images/450c6947ca08fbe62a962d1bcbbc478e.png" alt="450c6947ca08fbe62a962d1bcbbc478e"></p><p>Driver 选择 Node.js 版本选择 6.7 or later，然后在终端安装 mongodb 数据库，将连接字符串中的 <code>&lt;username&gt;:&lt;password&gt;</code> <strong>修改为</strong>刚刚创建的数据库 <code>用户名:密码</code>。到这里，你应该把那一段：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">auberginewly:&lt;db_passward&gt;</span><br></pre></td></tr></table></figure><p>替换成自己的：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">username:passward</span><br></pre></td></tr></table></figure><p><img src="/../images/6ffdcca404dc304487e1b9cf4318ddc9.png" alt="6ffdcca404dc304487e1b9cf4318ddc9"></p><blockquote><p>注意：连接字符串包含了连接到 MongoDB 数据库的所有信息，<strong>一旦泄露会导致评论被任何人添加、修改、删除，并有可能获取你的 SMTP、图床 token 等信息。请妥善记录这一字符串</strong>，之后需要填入到 Twikoo 的部署平台里。</p></blockquote><h2 id="在-vercel-里部署-twikoo"><a href="#在-vercel-里部署-twikoo" class="headerlink" title="在 vercel 里部署 twikoo"></a>在 vercel 里部署 twikoo</h2><p>传送门<a href="https://vercel.com/new/clone?repository-url=https://github.com/twikoojs/twikoo/tree/main/src/server/vercel-min">一键部署 twikoo 到 vercel</a></p><p>要确保之前没有这个仓库叫这个名字，不然会有冲突。</p><p><img src="/../images/image-20250421205845405.png" alt="image-20250421205845405"></p><p>等待部署一会。</p><p><img src="/../images/image-20250421205743967.png" alt="image-20250421205743967"></p><p>然后我们来添加环境变量 MONGODB_URI，这里我们进入 settings 的 environment variables 里面进行设置。</p><p><img src="/../images/93a32b965f820c63181755399b89a853.png" alt="93a32b965f820c63181755399b89a853"></p><p>key 值设置 MONGODB_URI，value 值就设置之前复制的那一串：</p><p><img src="/../images/image-20250421210156974.png" alt="image-20250421210156974"></p><p><img src="/../images/22081b71ff5abb3a71b7680e7ed823b3.png" alt="22081b71ff5abb3a71b7680e7ed823b3"></p><p>然后添加完毕，点击 save，进入到 deployment protection，把 vercel authentication 设置成 disabled。</p><p><img src="/../images/fc0996319ba20c2f632f49d21ae28e48.png" alt="fc0996319ba20c2f632f49d21ae28e48"></p><p>然后进入到 deployments 这里，进行 redeploy，等待重新部署完毕，就可以了。</p><p><img src="/../images/ac3076f66b9cc9b29a325a18edbd4d80.png" alt="ac3076f66b9cc9b29a325a18edbd4d80"></p><p>然后就会显示：</p><p><img src="/../images/image-20250421210858447.png" alt="image-20250421210858447"></p><p>云函数运行正常，然后我们可以进行下一步接入 hexo 了。</p><p>记得保存自己的 vercel domain，在这里：</p><p><img src="/../images/image-20250421211128636.png" alt="image-20250421211128636"></p><h2 id="接入-hexo"><a href="#接入-hexo" class="headerlink" title="接入 hexo"></a>接入 hexo</h2><p>打开 butterfly 主题的配置文件<code>_config.yml</code>，找到<code>comments</code>，然后按照如下图修改：</p><p><img src="/../images/image-20250421211355151.png" alt="image-20250421211355151"></p><p>把 use 修改为 Twikoo。</p><p>然后找到 twikoo 模块，按照下面修改配置：</p><p><img src="/../images/image-20250421211510132.png" alt="image-20250421211510132"></p><blockquote><p>envId 就是上面说的 vercel domain 部分，复制过来就好了，注意 yml 文件配置，冒号与后边的配置信息必须有一个空格的间隔，不然会报错。还有 visitor 应该修改为 true，我这里有点问题。</p></blockquote><p>然后重启 hexo，就可以看到评论区了耶。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">hexo g</span><br><span class="line">hexo d</span><br></pre></td></tr></table></figure><h1 id="效果如图"><a href="#效果如图" class="headerlink" title="效果如图"></a>效果如图</h1><p><img src="/../images/image-20250421211852762.png" alt="image-20250421211852762"></p><h1 id="配置完毕"><a href="#配置完毕" class="headerlink" title="配置完毕"></a>配置完毕</h1><p>后续可以看看怎么个其他方式的优化，因为我这里是没有自己的服务器所以选择使用 vercel，还有 mangodb 数据库免费的 512 mb 对于评论区完全够用了，希望能帮助到你。</p>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;配置缘由&quot;&gt;&lt;a href=&quot;#配置缘由&quot; class=&quot;headerlink&quot; title=&quot;配置缘由&quot;&gt;&lt;/a&gt;配置缘由&lt;/h1&gt;&lt;p&gt;想到有些时候别人看到我的博客可能会有一些想法，于是乎我就想着把博客的评论区想着怎么配置一下，之前因为没有服务器，所以我就想试</summary>
      
    
    
    
    <category term="琐碎问题解决" scheme="https://auberginewly.site/categories/%E7%90%90%E7%A2%8E%E9%97%AE%E9%A2%98%E8%A7%A3%E5%86%B3/"/>
    
    
    <category term="博客配置" scheme="https://auberginewly.site/tags/%E5%8D%9A%E5%AE%A2%E9%85%8D%E7%BD%AE/"/>
    
  </entry>
  
  <entry>
    <title>2025.4 第三周</title>
    <link href="https://auberginewly.site/2025/04/21/16_2025-4-week3/"/>
    <id>https://auberginewly.site/2025/04/21/16_2025-4-week3/</id>
    <published>2025-04-20T18:38:30.000Z</published>
    <updated>2025-04-28T09:06:27.235Z</updated>
    
    <content type="html"><![CDATA[<h1 id="周报小结"><a href="#周报小结" class="headerlink" title="周报小结"></a>周报小结</h1><h2 id="blog"><a href="#blog" class="headerlink" title="blog"></a>blog</h2><p>给博客配置了静态域名和rss订阅，可以看看我之前的文章。</p><h2 id="学习"><a href="#学习" class="headerlink" title="学习"></a>学习</h2><p>详细深入了解了一下git的用法和github关联，就是github desktop和gitee俩远程库那种的推送还没了解详细，可以看看之前的文章。<br>本来想开sql的学习，奈何发现时间不大够。<br>还有课内摆了没怎么学，哎，要考大物了，继续突击，下礼拜要好好把课内捡回来了。</p><h2 id="大创结稿"><a href="#大创结稿" class="headerlink" title="大创结稿"></a>大创结稿</h2><p>赶稿与ppt终于改了一版又一版，截稿等待结果咯。</p><h2 id="后续想干的"><a href="#后续想干的" class="headerlink" title="后续想干的"></a>后续想干的</h2><p>写完cursor使用指北。<br>quickstart in pytorch机器学习深度学习及其方向。<br>前后端基础的学习，与产品去中心化的分享。</p>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;周报小结&quot;&gt;&lt;a href=&quot;#周报小结&quot; class=&quot;headerlink&quot; title=&quot;周报小结&quot;&gt;&lt;/a&gt;周报小结&lt;/h1&gt;&lt;h2 id=&quot;blog&quot;&gt;&lt;a href=&quot;#blog&quot; class=&quot;headerlink&quot; title=&quot;blog&quot;&gt;&lt;/a</summary>
      
    
    
    
    <category term="周报" scheme="https://auberginewly.site/categories/%E5%91%A8%E6%8A%A5/"/>
    
    
    <category term="一些想法" scheme="https://auberginewly.site/tags/%E4%B8%80%E4%BA%9B%E6%83%B3%E6%B3%95/"/>
    
  </entry>
  
  <entry>
    <title>cursor使用指北</title>
    <link href="https://auberginewly.site/2025/04/19/15_About_Using_Cursor/"/>
    <id>https://auberginewly.site/2025/04/19/15_About_Using_Cursor/</id>
    <published>2025-04-19T08:39:49.000Z</published>
    <updated>2025-04-21T08:39:34.887Z</updated>
    
    <content type="html"><![CDATA[<h1 id="下载与设置"><a href="#下载与设置" class="headerlink" title="下载与设置"></a>下载与设置</h1><p>官网 <a href="https://www.cursor.com/cn">https://www.cursor.com/cn</a></p><h2 id="终端启动配置"><a href="#终端启动配置" class="headerlink" title="终端启动配置"></a>终端启动配置</h2><p>因为我之前有设置<code>.code</code>或者<code>code</code>启动vscode，所以这边是设置了<code>cursor</code>来快捷启动cursor。</p><h2 id="安装中文插件"><a href="#安装中文插件" class="headerlink" title="安装中文插件"></a>安装中文插件</h2><p><img src="/../images/image-20250419170638991.png" alt="image-20250419170638991"></p><h1 id="核心功能"><a href="#核心功能" class="headerlink" title="核心功能"></a>核心功能</h1><h2 id="tab补全"><a href="#tab补全" class="headerlink" title="tab补全"></a>tab补全</h2><p>光标预测，tab补全。</p><h2 id="agent-ask-manualk"><a href="#agent-ask-manualk" class="headerlink" title="agent&#x2F;ask&#x2F;manualk"></a>agent&#x2F;ask&#x2F;manualk</h2><p>Cursor 是一个为程序员设计的 AI 编程编辑器，它的 <code>agent/ask/manual</code> 模式，是三种不同的交互方式，用来控制 AI 如何与你的代码协作。下面是这三种模式的区别和用途：</p><hr><h3 id="🧠-1-agent-模式（自动代理模式）"><a href="#🧠-1-agent-模式（自动代理模式）" class="headerlink" title="🧠 1. agent 模式（自动代理模式）"></a>🧠 1. <code>agent</code> 模式（自动代理模式）</h3><p><strong>作用：AI 自动分析并主动修改代码，像“自动驾驶”。</strong></p><ul><li>你只需要输入一句目标（如“优化这段代码的性能”），它会自动扫描当前文件甚至项目上下文，判断应该怎么改，然后<strong>直接帮你修改代码</strong>。</li><li>适合你信任 AI、希望它自己动手的情况。</li></ul><p><strong>典型用途：</strong></p><ul><li>重构一段复杂代码</li><li>修复 bug</li><li>实现一个小功能</li><li>自动写测试代码</li></ul><hr><h3 id="💬-2-ask-模式（提问模式）"><a href="#💬-2-ask-模式（提问模式）" class="headerlink" title="💬 2. ask 模式（提问模式）"></a>💬 2. <code>ask</code> 模式（提问模式）</h3><p><strong>作用：AI 像“答疑助手”，它不会修改代码，只会回答问题或解释。</strong></p><ul><li>你问：“这段代码是干嘛的？” 它就解释。</li><li>你说：“帮我写个 for 循环模板。” 它就写个代码片段出来，不会动你当前文件。</li><li>你自己决定要不要把回答贴进去。</li></ul><p><strong>典型用途：</strong></p><ul><li>看不懂别人的代码，想请 AI 翻译</li><li>想让它列出一个实现思路、代码片段，但不想让它自动改项目</li></ul><hr><h3 id="✍️-3-manual-模式（手动模式）"><a href="#✍️-3-manual-模式（手动模式）" class="headerlink" title="✍️ 3. manual 模式（手动模式）"></a>✍️ 3. <code>manual</code> 模式（手动模式）</h3><p><strong>作用：你自己选中代码片段，告诉 AI 应该改哪里，它</strong>只看你选中的部分**。**</p><ul><li>AI 只分析你手动选择的代码块，不会读整个文件上下文，修改范围也有限。</li><li>修改建议出来后，你手动选择是否替换原代码。</li></ul><p><strong>适合：</strong></p><ul><li>小范围快速编辑</li><li>对 AI 不太放心、怕它“乱动”时</li><li>做精准控制，比如“只改这个函数，不动别的”</li></ul><hr><h3 id="简单总结："><a href="#简单总结：" class="headerlink" title="简单总结："></a>简单总结：</h3><table><thead><tr><th>模式</th><th>控制程度</th><th>修改行为</th><th>适合场景</th></tr></thead><tbody><tr><td><code>agent</code></td><td>最自动</td><td>直接修改代码</td><td>自动修复、重构、实现功能</td></tr><tr><td><code>ask</code></td><td>最安全</td><td>不修改代码</td><td>提问、解释、获取示例</td></tr><tr><td><code>manual</code></td><td>半自动</td><td>可选修改</td><td>精准修改、代码片段替换</td></tr></tbody></table><hr><p>如果你正在用 Cursor 写代码，建议：</p><ul><li>熟悉 <code>ask</code> 模式，随时提问查资料</li><li>用 <code>manual</code> 模式做小改动</li><li>用 <code>agent</code> 模式快速完成重复、结构性任务（比如“把这段代码转成 TypeScript”）</li></ul><h3 id="快捷键"><a href="#快捷键" class="headerlink" title="快捷键"></a>快捷键</h3><p>cmd+I agent模式<br>cmd+L ask模式</p><h2 id="模型推荐"><a href="#模型推荐" class="headerlink" title="模型推荐"></a>模型推荐</h2><h3 id="综合领域问答理解-ask"><a href="#综合领域问答理解-ask" class="headerlink" title="综合领域问答理解 ask"></a>综合领域问答理解 ask</h3><p>gpt-4o</p><h3 id="代码-agent暂时只支持Claude模型"><a href="#代码-agent暂时只支持Claude模型" class="headerlink" title="代码 agent暂时只支持Claude模型"></a>代码 agent暂时只支持Claude模型</h3><p>claude 3.7 sonnet<br>gemini 2.5 pro</p><blockquote><p>复杂功能拆解，一步步喂给agent，提取上下文，还可以运行一些终端的命令之类。<br>简单功能问ask就好了，速度快一些。</p></blockquote><h2 id="关于-菜单"><a href="#关于-菜单" class="headerlink" title="关于@菜单"></a>关于@菜单</h2><p><img src="/../images/image-20250419174226865.png" alt="image-20250419174226865"></p><ul><li>文件&#x2F;文件夹</li><li>代码</li><li>文档</li><li>Git</li><li>历史对话</li><li>cursor规则</li><li>终端</li><li>Linter errors</li><li>Linting 指的是<strong>通过专用的分析软件对 源代码 进行分析，查找出源代码中存在的语法和样式错误的过程</strong>。</li></ul><h3 id="Docs文档"><a href="#Docs文档" class="headerlink" title="Docs文档"></a>Docs文档</h3><p>可以添加链接然后存文档</p><p><img src="/../images/image-20250419184244787.png" alt="image-20250419184244787"></p><p>输入链接</p><p><img src="/../images/image-20250419184310824.png" alt="image-20250419184310824"><br>即可</p><blockquote><p>注意引用文档的不同。<br>例如 <a href="https://docs.cursor.com/">https://docs.cursor.com/</a> 会引用当前这个页面的文档及其子文档，但 <a href="https://docs.cursor.com/">https://docs.cursor.com</a> 只会引用当前的文档。<br>就是最后一个斜杠有无的区别。</p></blockquote><p>临时链接解析上下文可以直接<code>@+链接地址</code></p>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;下载与设置&quot;&gt;&lt;a href=&quot;#下载与设置&quot; class=&quot;headerlink&quot; title=&quot;下载与设置&quot;&gt;&lt;/a&gt;下载与设置&lt;/h1&gt;&lt;p&gt;官网 &lt;a href=&quot;https://www.cursor.com/cn&quot;&gt;https://www.cursor.</summary>
      
    
    
    
    <category term="学习笔记" scheme="https://auberginewly.site/categories/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/"/>
    
    
    <category term="CS" scheme="https://auberginewly.site/tags/CS/"/>
    
  </entry>
  
  <entry>
    <title>Quickstart in Pytorch</title>
    <link href="https://auberginewly.site/2025/04/19/14_Quickstart-in-Pytorch/"/>
    <id>https://auberginewly.site/2025/04/19/14_Quickstart-in-Pytorch/</id>
    <published>2025-04-19T05:01:06.000Z</published>
    <updated>2025-04-21T08:39:31.771Z</updated>
    
    
    
    
    <category term="学习笔记" scheme="https://auberginewly.site/categories/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/"/>
    
    
    <category term="LLM" scheme="https://auberginewly.site/tags/LLM/"/>
    
  </entry>
  
  <entry>
    <title>4.18 小记_人能感受多少回夏天</title>
    <link href="https://auberginewly.site/2025/04/18/13_4-18_about_summer/"/>
    <id>https://auberginewly.site/2025/04/18/13_4-18_about_summer/</id>
    <published>2025-04-18T05:23:11.000Z</published>
    <updated>2025-04-21T08:39:27.876Z</updated>
    
    <content type="html"><![CDATA[<blockquote><p>于是我开始思考，人可以感受多少个夏天。 </p></blockquote><p><img src="/../images/IMG_2504.png" alt="IMG_2504"></p><p>偶然葱郁的绿荫和夏至未至的前奏突然响起，会有一种淡淡的遗憾映入眼帘，然后我开始思考，人到底能感受多少个夏天，在太阳升顶的午后，长夏默默，什么话也不说，就这样和眩晕的白昼对坐，绿色翻涌成夏，每每的四月开始翻涌的热浪，某一刻，内心就会被一种名为夏天的感受填满。</p><blockquote><p>对于中国孩子的夏天。</p></blockquote><p><img src="/../images/IMG_2505.png" alt="IMG_2505"></p><p>关于夏天的特殊情结，要从十几岁的每次升学的毕业说起，在每年冬日过后，随着白昼的慢慢拉长，温度的慢慢攀升，像蜿蜒的爬山虎，在某一刻透出最苍翠的绿色，撒下属于它的那一片阴翳，每一次夏天夏天的悄悄靠近，都在一些重要的节点，小升初，中考，高考，毕业，18岁之前的每一个重大的转折，三年之约，好像都在某一个回忆深刻的夏天。</p><p>还记得20年6月某天晚自习的傍晚，霞光的层次分明鲜艳，那年初二，还没什么其他的顾虑，就是写写题目，聊聊天，坐在操场上畅想明媚的未来，一切都好像刚刚开始，一切都好像还来得及，有明确的目标，和想象里光明的以后。</p><p>那天的晚霞belike：<br><img src="/../images/IMG_5307.JPG" alt="IMG_5307"></p><p>于是呀，在每一年的夏天，随着风扇呼呼的转动，压力和温度一并升高，每天照例的晚自习和考试，偶尔汗浸透了试卷的一角，字迹随着化开，闷热的空气被带着流动起来，我们都为着同一个目标不断前行，在无数重复的日夜里得以觅见点点星光，在重复的罅隙当中试图全力揭开最后那个属于自己的答案。</p><blockquote><p>那些夏天，西瓜，汽水，冰棒，空调，风扇。</p><p>蝉鸣，白云，晚风，小巷。</p></blockquote><p><img src="/../images/IMG_2506.png" alt="IMG_2506"></p><p>好像每个夏天都有几次闷热，几场暴雨，几次毫无防备的炙烤，对于十几岁夏天详细的记忆已经不清晰了，它不再真切，好像所有的经历的一切都是一场幻觉，但是都停留在海马体的记忆当中，每每想起那种感觉，就像是午后在老式的小巷里，摇椅上，阳光稀稀落落透过密密麻麻的树叶，闪着斑斑点点的摇曳的光晕，偶尔的几声狗吠，小卖部老板的蒲扇，一切慢下来，一切富有生机，好像，都在向上走。</p><p>去年高考完了，没很理想，那个夏天是把自己关禁闭的，很多时候都在胡思乱想，要是回到高考前几天，是不是就可以考好一点呢，万一重来，重来就好了。</p><blockquote><p>夏天的爱太没天赋，稍有不慎就炙烤万物。</p></blockquote><p>有的时候晴空万里，有的时候乌云密布，然后暴雨如瀑，长夜散尽，又热烈如初。人好像总是在不断试错的过程当中成长的，还没学会细水长流，还没学会如何留白，白天总是发呆，夜晚总是焦虑空洞，我在这个专业，是不是不合适，好像总是学不懂那些高深的技术，一切都是那么的新奇与未知，一次次的受挫与熬夜，把曾经那个少年意气风发的棱角消磨殆尽，湮灭消失。没有切实的目的，对于工作与求学的迷茫，如同夏日的晚风，来回吹拂，但它并不停留。</p><blockquote><p>人生是旷野，不是轨道。</p></blockquote><p>高中作文常常引用的一句话，其实至今也没明白它深层的内核。但是19岁大一的我会时时刻刻想，为什么我会这么累。回头看看自己干了什么，提笔就是虚无。每天忙忙碌碌，但是精神是低迷的，完全没有中学时代的那股干劲和毅力，那段时间，我怀念的，是那种确定性带来的安全感，一切都安排好了，桌上的课程表，起起伏伏的月考成绩，统一的下课铃声，亘古不变的周测，就连烦恼也是标准的：怎么我又考砸了，今天又没买到好吃的…像是一列按照轨道行进的火车，轰隆轰隆，朝着目的地慢慢前进。</p><p>但是现在，我被丢到了荒野上。就业？读研？摆烂？入党？卷技术？卷绩点？各种比赛？学不懂的算法？或者追求喜爱的东西？评判的标准多样化，必须舍弃一些东西，但是带着高中的学生思维，我竟然迷茫了，我真的喜欢这个专业吗，我真的适合这个专业吗，我拼命的去争取，绩点，比赛，入党，看起来十分的可笑，就像在跑步机上不断的狂奔，回看发现自己停留在原地不动。</p><p>真的很搞笑。</p><blockquote><p>我想回高中。</p></blockquote><p>汗流浃背，但是什么都没获得。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"># 我想回到那个目标明确的日子</span><br><span class="line"># 我想有人替我做决定</span><br><span class="line"># 我想再体验一次&#x27;只要听话就能被夸奖&#x27;的简单逻辑</span><br></pre></td></tr></table></figure><p>困住我的，不是大学，是那个还在用高中规则玩游戏的自己，是还没转变的学生思维，是沉浸在高考考砸道心破碎一心保研的自己。我还在等待那份<code>标准答案</code>，等待谁给我发的<code>人生考卷</code>，仿佛还可以像从前那样，用中性笔在泛黄的考卷上狠狠的写下解，然后酣畅淋漓的推算，那些在梦中的数学大题，物理题，可是啊少年，成年的世界没有统一的命题，也没有监考老师，这些既是残酷，也是浪漫。</p><p>高中的好学生，也要是叛逆的少年，那些好学生的品质，你该抛弃了。你现在需要的是，在没人督促的时候寻找方向，在志愿落空，考砸的时候，不再把高考的失败作为失败，重新定义成功，或者允许自己暂时当一个<code>逃兵</code>，躺平一段时间，思考<code>我为什么会焦虑</code>列出<code>我到底应该干什么</code>。</p><blockquote><p>或许，我们从来就不是想回到过去，只是还没学会享受这种<code>失控的自由</code>。</p></blockquote><p>那个在数学试卷上写下<code>解</code>和密密麻麻工工整整步骤的女孩，现在需要更大的勇气，在某处写下<code>我的未来我做主</code>和<code>我应该干什么</code>。<br>后面跟着什么都行，<code>我要点奶茶发呆一会</code> <code>我要去散散心</code> 为什么不可以呢？</p><blockquote><p>大概，夏季与我们的生命曾经真的是同一质地。</p></blockquote><p>许许多多虚无缥缈的东西，都是旁枝末节，都是那些，午后睡醒睡眼惺忪越想越淡的梦境。最后，还是回归当下，做一些切实的事情，过具体的日子，在什么时候就去做属于自己的事情，过去的就让他过去吧，无论是好是坏，它都是你人生当中不可或缺的经历，未来的时候回望现在，也显得弥足珍贵呢。夏天的任务就是过完夏天，享受蝉鸣，绿叶，鲜花，骄阳，白云，长长的散步，微风掠过的发梢，让日子按部就班的进行，让命运温柔的推动自己前进，每天一点点的进步，就很厉害了呀。</p><blockquote><p>人生的考场早就换了试卷，但是我还握着已经写完的铅笔。</p></blockquote><p>窗外的绿色沙沙作响，4月中旬的30度和赶不完的ddl，近代史课躲在抽屉里写的博客，是属于我的大学的第一个初夏。</p><blockquote><p>关于夏天 ABOUT SUMMER</p></blockquote><p>在这个下午的小记，耳机里的夏至未至，总带着一些遗憾与淡淡的平静，把一些放下，暂时性的逃离吧。</p><hr><p>叹口气，继续前行啦。加油呀。<br>拍张照吧，3、2、1，茄子！<br>2025&#x2F;初夏&#x2F;thoughts</p>]]></content>
    
    
      
      
    <summary type="html">&lt;blockquote&gt;
&lt;p&gt;于是我开始思考，人可以感受多少个夏天。 &lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img src=&quot;/../images/IMG_2504.png&quot; alt=&quot;IMG_2504&quot;&gt;&lt;/p&gt;
&lt;p&gt;偶然葱郁的绿荫和夏至未至的前奏突然响起，会有一种</summary>
      
    
    
    
    <category term="想法" scheme="https://auberginewly.site/categories/%E6%83%B3%E6%B3%95/"/>
    
    
    <category term="一些想法" scheme="https://auberginewly.site/tags/%E4%B8%80%E4%BA%9B%E6%83%B3%E6%B3%95/"/>
    
  </entry>
  
  <entry>
    <title>给butterfly主题的hexo博客配置rss订阅</title>
    <link href="https://auberginewly.site/2025/04/18/12_RssConfiguration/"/>
    <id>https://auberginewly.site/2025/04/18/12_RssConfiguration/</id>
    <published>2025-04-17T17:53:19.000Z</published>
    <updated>2025-04-21T08:39:24.876Z</updated>
    
    <content type="html"><![CDATA[<h1 id="配置缘由"><a href="#配置缘由" class="headerlink" title="配置缘由"></a>配置缘由</h1><p>突然某学长晚上提到关于rss订阅，以前还没了解过这个东西，于是迅速的了解了一下，RSS 的全称是 Really Simple Syndication（简易信息聚合），它是一种消息来源的格式规范，网站可以按照这种格式规范提供文章的标题、摘要、全文等信息给订阅用户，用户可以通过订阅不同网站 RSS 链接的方式将不同的信息源进行聚合，在一个工具里阅读这些内容。</p><p>简单来说，RSS 就是一种订阅某个网站内容更新的协议。这种略显「古老」的协议在社交媒体和聚合阅读的冲击下日渐式微，大多数人都不知道这个东西的存在了，更者在算法推荐为各大厂商盈利的当下，rss的订阅显得有那么一些反算法。</p><p>但是rss的阅读精简模式可以让我们专注于想要阅读的内容，在信息裹挟的洪流下可以精准迅速的获得想要的内容，像是一种在pick的过程，捣鼓捣鼓还是很好玩的。</p><h1 id="配置步骤"><a href="#配置步骤" class="headerlink" title="配置步骤"></a>配置步骤</h1><h2 id="step1-下载hexo支持的rss插件"><a href="#step1-下载hexo支持的rss插件" class="headerlink" title="step1 下载hexo支持的rss插件"></a>step1 下载hexo支持的rss插件</h2><p>hexo的rss插件，叫<strong>hexo-generator-feed</strong>，在hexo文件夹终端下载插件</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm install hexo-generator-feed --save</span><br></pre></td></tr></table></figure><h2 id="step2-根目录配置"><a href="#step2-根目录配置" class="headerlink" title="step2 根目录配置"></a>step2 根目录配置</h2><p>然后在根目录中的_config.yml中添加如下配置</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">feed:  </span><br><span class="line">  enable: true  </span><br><span class="line">  type: atom  </span><br><span class="line">  path: atom.xml  </span><br><span class="line">  limit: 0</span><br></pre></td></tr></table></figure><p><strong>官网还说明了一些其他的参数，如：</strong></p><ul><li>enable: 默认开启可以省略</li><li>type: RSS的类型(atom&#x2F;rss2)</li><li>path: 文件路径，默认是 atom.xml&#x2F;rss2.xml</li><li>limit: 展示文章的数量,使用 0 或则 false 代表展示全部</li><li>hub: 如果使用不到可以为空</li><li>content: （可选）设置 true 可以在 RSS 文件中包含文章全部内容，默认：false</li><li>content_limit: （可选）摘要中使用的帖子内容的默认长度。 仅在内容设置为false且未显示自定义帖子描述时才使用。</li><li>content_limit_delim :（可选）如果content_limit用于缩短帖子内容，则仅在达到字符限制之前在此分隔符的最后一次出现处剪切。默认不使用。</li><li>icon: (可选）自定义图标。默认为主配置中指定的电子邮件头像。</li><li>autodiscovery: 添加提要自动发现，默认开启</li><li>template : 自定义模板路径。该文件用于生成 xml 文件</li></ul><h2 id="step3-主题配置"><a href="#step3-主题配置" class="headerlink" title="step3 主题配置"></a>step3 主题配置</h2><p>然后去主题的_config.yml中添加配置</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">rss:</span> <span class="string">/atom.xml</span></span><br></pre></td></tr></table></figure><p>这样你在用hexo g生成静态网页的时候会在public文件夹中（也就是你静态网页文件夹中）生成一个rss2.xml文件</p><h2 id="step4-添加主页rss按钮（可选）"><a href="#step4-添加主页rss按钮（可选）" class="headerlink" title="step4 添加主页rss按钮（可选）"></a>step4 添加主页rss按钮（可选）</h2><p>如果你想让别人知道你的RSS链接，可以在主题中的social中添加如下配置（就是在那侧边栏个人资料下面添加一个图标并链接到你的RSS文件）</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">fas fa-rss:</span> <span class="string">/atom.xml</span> <span class="string">||</span> <span class="string">RSS</span> <span class="string">||</span> <span class="string">&#x27;#ee802f&#x27;</span></span><br></pre></td></tr></table></figure><p>并且添加了rss的橘黄配色（）</p><h1 id="re"><a href="#re" class="headerlink" title="re"></a>re</h1><p>好晚了，迅速结束配置，过几天再来捣鼓rss阅读器，感觉很好玩的样子ahh</p>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;配置缘由&quot;&gt;&lt;a href=&quot;#配置缘由&quot; class=&quot;headerlink&quot; title=&quot;配置缘由&quot;&gt;&lt;/a&gt;配置缘由&lt;/h1&gt;&lt;p&gt;突然某学长晚上提到关于rss订阅，以前还没了解过这个东西，于是迅速的了解了一下，RSS 的全称是 Really Simple</summary>
      
    
    
    
    <category term="琐碎问题解决" scheme="https://auberginewly.site/categories/%E7%90%90%E7%A2%8E%E9%97%AE%E9%A2%98%E8%A7%A3%E5%86%B3/"/>
    
    
    <category term="博客配置" scheme="https://auberginewly.site/tags/%E5%8D%9A%E5%AE%A2%E9%85%8D%E7%BD%AE/"/>
    
  </entry>
  
  <entry>
    <title>SQL学习笔记</title>
    <link href="https://auberginewly.site/2025/04/16/11_LearnSQLNotes/"/>
    <id>https://auberginewly.site/2025/04/16/11_LearnSQLNotes/</id>
    <published>2025-04-16T12:51:49.000Z</published>
    <updated>2025-04-21T08:39:19.810Z</updated>
    
    <content type="html"><![CDATA[<h1 id="在macos上安装mysql"><a href="#在macos上安装mysql" class="headerlink" title="在macos上安装mysql"></a>在macos上安装mysql</h1>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;在macos上安装mysql&quot;&gt;&lt;a href=&quot;#在macos上安装mysql&quot; class=&quot;headerlink&quot; title=&quot;在macos上安装mysql&quot;&gt;&lt;/a&gt;在macos上安装mysql&lt;/h1&gt;</summary>
      
    
    
    
    <category term="学习笔记" scheme="https://auberginewly.site/categories/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/"/>
    
    
    <category term="SQL" scheme="https://auberginewly.site/tags/SQL/"/>
    
    <category term="CS" scheme="https://auberginewly.site/tags/CS/"/>
    
  </entry>
  
  <entry>
    <title>关于解决每次hexo部署后CNAME被清除导致域名与仓库解绑和简化hexo的部署命令</title>
    <link href="https://auberginewly.site/2025/04/16/10_CNAME_Fix_&amp;_Hexo_Deploy_Shortcut/"/>
    <id>https://auberginewly.site/2025/04/16/10_CNAME_Fix_&amp;_Hexo_Deploy_Shortcut/</id>
    <published>2025-04-16T04:26:43.000Z</published>
    <updated>2025-04-21T08:39:15.444Z</updated>
    
    <content type="html"><![CDATA[<h1 id="问题起源"><a href="#问题起源" class="headerlink" title="问题起源"></a>问题起源</h1><p>在我昨天给博客绑定一个自己的域名之后，我发现每次写完文章进行部署上传的时候，执行以下命令之后:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">hexo d</span><br><span class="line">hexo g</span><br></pre></td></tr></table></figure><p>用<code>auberginewly.site</code>访问不了我的博客，然后就去设置里githubpages查看，发现我绑定的domain被清空了，这就导致每次部署上传之后我都要手动与自己的域名绑定，相当的麻烦，于是我想着怎么解决下这个问题，顺便实现了下怎么样去简化部署的命令，下面是步骤。</p><h1 id="为什么绑定的domain会被清空？"><a href="#为什么绑定的domain会被清空？" class="headerlink" title="为什么绑定的domain会被清空？"></a>为什么绑定的domain会被清空？</h1><p>大概率是 Hexo 每次部署（<code>hexo g &amp;&amp; hexo d</code>）的时候，把 GitHub Pages 仓库里的 <code>CNAME</code>文件覆盖或删除了，导致绑定的自定义域名（如 <code>auberginewly.site</code>）失效。</p><h2 id="背景小科普"><a href="#背景小科普" class="headerlink" title="背景小科普"></a>背景小科普</h2><p>GitHub Pages 绑定自定义域名时，会在你的仓库根目录生成一个名为 <code>CNAME</code> 的文件，里面只写着你的域名（如 <code>auberginewly.site</code>）。<strong>如果这个文件被删除或不在部署后的文件夹中，域名就会失效。</strong></p><h2 id="解决方法"><a href="#解决方法" class="headerlink" title="解决方法"></a>解决方法</h2><p>进入你的 Hexo 项目目录</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">cd</span> your-hexo-folder</span><br></pre></td></tr></table></figure><p>创建一个 <code>source/CNAME</code> 文件，内容是<code>auberginewly.site</code>(替换成你自己的域名)</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">echo</span> <span class="string">&#x27;auberginewly.site&#x27;</span> &gt; <span class="built_in">source</span>/CNAME</span><br></pre></td></tr></table></figure><p>确保 <code>.gitignore</code> 没有忽略 <code>CNAME</code> 文件。<br>然后执行：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">hexo clean</span><br><span class="line">hexo g</span><br><span class="line">hexo d</span><br></pre></td></tr></table></figure><p>这样 Hexo 每次生成静态文件时都会把 <code>CNAME</code> 文件一并部署上去，GitHub Pages 的绑定就不会断了，也不用费劲心思的每次手动部署了。</p><h1 id="自动化脚本简化hexo部署"><a href="#自动化脚本简化hexo部署" class="headerlink" title="自动化脚本简化hexo部署"></a>自动化脚本简化hexo部署</h1><p>如果你想让 Hexo 部署流程更加自动化，避免每次都手动确认和添加 <code>CNAME</code> 文件，可以通过编写一个简单的自动化脚本来实现。下面是步骤：</p><h2 id="创建部署脚本"><a href="#创建部署脚本" class="headerlink" title="创建部署脚本"></a>创建部署脚本</h2><p>在 Hexo 项目根目录创建一个 <code>deploy.sh</code> 脚本文件：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">touch</span> deploy.sh</span><br></pre></td></tr></table></figure><p>我的系统是macos，如果是windows的话应该是<code>deploy.bat</code>脚本文件，取决于不同的操作系统，我的脚本如下：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta prompt_">#</span><span class="language-bash">!/bin/bash</span></span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">切换到 Hexo 项目根目录</span></span><br><span class="line">cd &quot;$(dirname &quot;$0&quot;)&quot;</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">确保 CNAME 文件存在</span></span><br><span class="line">if [ ! -f source/CNAME ]; then</span><br><span class="line">    echo &quot;auberginewly.site&quot; &gt; source/CNAME</span><br><span class="line">    echo &quot;CNAME 文件已自动创建&quot;</span><br><span class="line">fi</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">执行 Hexo 构建和部署</span></span><br><span class="line">echo &quot;开始构建和部署...&quot;</span><br><span class="line">npx hexo g</span><br><span class="line">npx hexo d</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">部署完成后，只清理 public 文件夹，保留 db.json</span></span><br><span class="line">echo &quot;部署完成，开始删除 public 目录...&quot;</span><br><span class="line">rm -rf public</span><br><span class="line"></span><br><span class="line">echo &quot;部署和清理完成！&quot;</span><br></pre></td></tr></table></figure><p>因为不会nano编辑器，我直接选择在文本里编辑，可以使用vim或者nano编辑器进行命令行的编辑：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 可以进行选择的使用</span></span><br><span class="line">nano deploy.sh <span class="comment"># nano</span></span><br><span class="line">vi deploy.sh <span class="comment"># vim</span></span><br></pre></td></tr></table></figure><h2 id="赋予脚本执行权限-linux或者macos适用"><a href="#赋予脚本执行权限-linux或者macos适用" class="headerlink" title="赋予脚本执行权限(linux或者macos适用)"></a>赋予脚本执行权限(linux或者macos适用)</h2><p>如果你在 Linux 或 macOS 上，可以通过以下命令赋予脚本执行权限：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">chmod</span> +x deploy.sh</span><br></pre></td></tr></table></figure><p>然后你就可以运行 <code>./deploy.sh</code> 来完成部署。</p><h2 id="简化部署过程"><a href="#简化部署过程" class="headerlink" title="简化部署过程"></a>简化部署过程</h2><p>每次你运行 <code>./deploy.sh</code>，它会先检查 <code>CNAME</code> 文件是否存在，如果不存在会自动创建，然后再进行构建和部署。这样你就不用每次都担心 <code>CNAME</code> 文件的问题，整个流程更为流畅。</p><h2 id="进一步简化——使用-alias-命令简化"><a href="#进一步简化——使用-alias-命令简化" class="headerlink" title="进一步简化——使用 alias 命令简化"></a>进一步简化——使用 <code>alias</code> 命令简化</h2><p>可以在你的 macOS 上创建一个 <strong>命令别名</strong>，使得每次部署只需要一个简单的命令。</p><h3 id="打开你的终端配置文件（例如-bash-profile-或-zshrc，具体取决于你使用的-shell）"><a href="#打开你的终端配置文件（例如-bash-profile-或-zshrc，具体取决于你使用的-shell）" class="headerlink" title="打开你的终端配置文件（例如 .bash_profile 或 .zshrc，具体取决于你使用的 shell）"></a>打开你的终端配置文件（例如 <code>.bash_profile</code> 或 <code>.zshrc</code>，具体取决于你使用的 shell）</h3><p>我这里的是<code>.zshrc</code>，使用命令打开文件（我这里是使用<code>zsh</code>）：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">nano ~/.zshrc</span><br></pre></td></tr></table></figure><p>有小朋友要问了，<code>zsh</code>是什么？？</p><h4 id="关于zsh"><a href="#关于zsh" class="headerlink" title="关于zsh"></a>关于<code>zsh</code></h4><p>Zsh（Z Shell）是一种功能强大的Unix shell，它是Bash（Bourne Again Shell）的一种替代品，并且在许多方面有所增强。Zsh 提供了丰富的功能，包括：</p><ol><li><p><strong>自动补全</strong>：Zsh 能够智能地完成命令、文件路径、命令参数等的自动补全，比 Bash 更加灵活。</p></li><li><p><strong>插件和主题支持</strong>：Zsh 允许用户安装插件和主题，常见的插件管理器是 <code>oh-my-zsh</code>，它大大增强了 Zsh 的可用性和外观。</p></li><li><p><strong>高级路径展开</strong>：Zsh 具有强大的文件路径和通配符扩展功能。</p></li><li><p><strong>历史管理</strong>：Zsh 能够更加智能地管理命令历史，并支持在历史中查找和搜索。</p></li><li><p><strong>自定义功能</strong>：Zsh 支持高度的自定义，包括快捷键、变量、命令别名等。</p></li><li><p><strong>更多的内建命令和选项</strong>：Zsh 提供了许多内建命令，能够更方便地进行文件操作、字符串处理等。</p></li></ol><p>由于其易用性和强大功能，Zsh 成为很多开发者和系统管理员的首选shell之一。</p><h3 id="修改或添加-hexo-别名"><a href="#修改或添加-hexo-别名" class="headerlink" title="修改或添加 hexo 别名"></a>修改或添加 <code>hexo</code> 别名</h3><p>修改或添加以下行来让 <code>hexo</code> 成为你的部署命令：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">alias</span> hexo=<span class="string">&quot;cd ~/your-hexo-folder &amp;&amp; ./deploy.sh&quot;</span></span><br></pre></td></tr></table></figure><p>记得将 <code>~/your-hexo-folder</code> 替换成你实际的 Hexo 项目路径喔。</p><h3 id="保存并加载配置"><a href="#保存并加载配置" class="headerlink" title="保存并加载配置"></a>保存并加载配置</h3><p>保存后，通过以下命令让修改生效：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">source</span> ~/.zshrc</span><br></pre></td></tr></table></figure><h3 id="于是你得到了"><a href="#于是你得到了" class="headerlink" title="于是你得到了"></a>于是你得到了</h3><p>如果设置了 <code>alias hexo</code>，你只需在任何地方输入：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">hexo</span><br></pre></td></tr></table></figure><p>它就会自动的进入到hexo的根目录当中并进行部署上传（记得把魔法关了）。</p><h3 id="一个小问题"><a href="#一个小问题" class="headerlink" title="一个小问题"></a>一个小问题</h3><p>但是我这样简化部署上传流程之后，发现我想创建新markdown博客的时候，这个命令:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">hexo new <span class="string">&quot;your-post-name&quot;</span></span><br></pre></td></tr></table></figure><p>它失效了，不会帮我在_post目录下创建新的文档而是运行deploy的脚本，我找了半天也没想到怎么解决，要么就把之前简化的步骤全删了，然后我就了解到了这个：</p><h4 id="执行npx命令"><a href="#执行npx命令" class="headerlink" title="执行npx命令"></a>执行<code>npx</code>命令</h4><p>使用 <code>npx</code> 来确保使用的是当前项目中安装的 Hexo，而不是全局安装的 Hexo。这样能够避免由于路径问题造成的执行错误。</p><h4 id="关于npx"><a href="#关于npx" class="headerlink" title="关于npx"></a>关于<code>npx</code></h4><p>在使用 Hexo 时，<code>npx</code> 和全局安装的 <code>hexo</code> 命令之间有一些区别，下面详细解释它们的工作原理和为什么使用 <code>npx</code> 可以帮助避免一些潜在问题。</p><h5 id="1-npx-命令："><a href="#1-npx-命令：" class="headerlink" title="1. npx 命令："></a>1. <code>npx</code> 命令：</h5><ul><li><strong><code>npx</code> 是一个来自 <code>npm</code> 的命令行工具</strong>，它通常用于执行在 <code>node_modules</code> 目录中的本地依赖包，或者在没有全局安装的情况下直接执行某个命令。</li><li>当你运行 <code>npx hexo</code> 时，它会优先执行 <strong>项目本地安装</strong> 的 Hexo 版本（即项目中的 <code>node_modules/hexo</code>），如果没有安装本地 Hexo，它会尝试下载并执行它。</li><li><code>npx</code> 会确保你使用的是项目特定版本的 Hexo，而不是全局安装的 Hexo。这样，你的项目始终使用与项目配置兼容的 Hexo 版本，避免因为版本不匹配而导致问题。</li></ul><h5 id="2-全局安装的-hexo-命令："><a href="#2-全局安装的-hexo-命令：" class="headerlink" title="2. 全局安装的 hexo 命令："></a>2. 全局安装的 <code>hexo</code> 命令：</h5><ul><li>如果你使用全局安装的 Hexo，执行 <code>hexo</code> 命令时，它会使用全局安装的 Hexo 版本（即通过 <code>npm install -g hexo-cli</code> 安装的版本）。</li><li>全局安装的 Hexo 可能与项目中的 Hexo 版本不同，尤其是当你在不同的项目中使用 Hexo 时，全局安装的 Hexo 可能不是项目所需的特定版本。</li><li>这样可能会导致一些版本兼容性问题，尤其是在使用特定插件或者不同 Hexo 版本时。</li></ul><h5 id="区别总结："><a href="#区别总结：" class="headerlink" title="区别总结："></a>区别总结：</h5><ul><li><strong>使用 <code>npx hexo</code></strong>：确保使用的是当前项目中的 Hexo 版本（从 <code>node_modules</code> 目录中读取）。这样可以避免因为全局安装的 Hexo 版本不同而导致的潜在问题。</li><li><strong>使用全局安装的 <code>hexo</code> 命令</strong>：使用的是全局安装的 Hexo 版本，这可能与项目中的版本不同，导致不一致或者不兼容的情况。</li></ul><h5 id="为什么使用-npx-hexo-更好？"><a href="#为什么使用-npx-hexo-更好？" class="headerlink" title="为什么使用 npx hexo 更好？"></a>为什么使用 <code>npx hexo</code> 更好？</h5><ol><li><strong>版本一致性</strong>：<code>npx hexo</code> 确保每次执行命令时都使用与项目相同版本的 Hexo，避免全局安装的 Hexo 版本不同步的问题。</li><li><strong>避免路径问题</strong>：有时全局安装的 Hexo 路径可能不对，尤其是在你使用多个项目时。<code>npx</code> 会确保命令从项目根目录中的 <code>node_modules</code> 目录执行，避免了路径配置错误的风险。</li><li><strong>无需全局安装 Hexo</strong>：如果你的项目中有本地安装 Hexo，就不需要全局安装它，避免了全局和局部依赖的冲突。</li></ol><h5 id="实际操作："><a href="#实际操作：" class="headerlink" title="实际操作："></a>实际操作：</h5><p>如果你有一个 Hexo 项目，并且在项目目录中执行 <code>npx hexo new &quot;test-post&quot;</code>，它会使用项目中的 Hexo 版本创建一个新文章。如果你使用全局安装的 <code>hexo new</code>，它可能会使用不同版本的 Hexo，这可能导致意外的行为，特别是当你升级或更改项目 Hexo 配置时。因此，推荐使用 <code>npx</code>，确保每次都使用与项目相匹配的 Hexo 版本。</p><h4 id="所以解决方式如下"><a href="#所以解决方式如下" class="headerlink" title="所以解决方式如下"></a>所以解决方式如下</h4><p>就是每次在<code>hexo new &quot;page&quot;</code>前加上一个<code>npx</code>，使用项目中的 Hexo 版本创建一个新文章，避免与脚本的冲突产生。</p><h3 id="关于删除脚本"><a href="#关于删除脚本" class="headerlink" title="关于删除脚本"></a>关于删除脚本</h3><p>我之前发现了上面的那个问题之后，直接把<code>deploy.sh</code>丢到废纸篓里，结果发现<code>hexo</code>、<code>hexo d</code>、<code>hexo g</code>、<code>hexo new &quot;pages&quot;</code>这些命令全部失效了，并且报错：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">zsh: no such file or directory: ./deploy.sh</span><br></pre></td></tr></table></figure><p>当前所在目录里找不到名为 <code>deploy.sh</code> 的文件，但执行了一个指向它的命令。说明 <strong>可能还残留了一些配置</strong> 指向这个脚本，我们一步步来解决它。</p><h4 id="检查-zshrc-是否还存在-alias-指向-deploy-sh"><a href="#检查-zshrc-是否还存在-alias-指向-deploy-sh" class="headerlink" title="检查 .zshrc 是否还存在 alias 指向 deploy.sh"></a>检查 <code>.zshrc</code> 是否还存在 <code>alias</code> 指向 <code>deploy.sh</code></h4><p>在终端输入：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">nano ~/.zshrc</span><br></pre></td></tr></table></figure><p>然后看看里面有没有这类语句：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">alias</span> deploy=<span class="string">&quot;./deploy.sh&quot;</span></span><br><span class="line"><span class="built_in">alias</span> hexo=<span class="string">&quot;./deploy.sh&quot;</span></span><br><span class="line"><span class="built_in">alias</span> hexo=<span class="string">&quot;cd ~/xxx &amp;&amp; ./deploy.sh&quot;</span></span><br></pre></td></tr></table></figure><p>如果有，就<strong>删掉或者注释掉（在前面加 <code>#</code>）</strong>。<br>然后按 <code>Ctrl + O</code> 保存，<code>Enter</code> 确认，<code>Ctrl + X</code> 退出。<br>最后，重新加载配置：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">source</span> ~/.zshrc</span><br></pre></td></tr></table></figure><h4 id="删除-deploy-sh-别名缓存（如果之前跑过-alias）"><a href="#删除-deploy-sh-别名缓存（如果之前跑过-alias）" class="headerlink" title="删除 deploy.sh 别名缓存（如果之前跑过 alias）"></a>删除 <code>deploy.sh</code> 别名缓存（如果之前跑过 alias）</h4><p>在终端里执行下面这个命令，彻底清除当前会话里的 <code>hexo</code> 和 <code>deploy</code> 别名（如果有）：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">unalias</span> hexo</span><br><span class="line"><span class="built_in">unalias</span> deploy</span><br></pre></td></tr></table></figure><p>如果不确定当前有没有残留 alias 设置，可以运行这个命令查一下：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">alias</span> | grep deploy</span><br><span class="line"><span class="built_in">alias</span> | grep hexo</span><br></pre></td></tr></table></figure><p>如果还看到指向 <code>./deploy.sh</code> 的 alias，那说明 alias 没清干净，需要删 <code>.zshrc</code> 里那一行。<br>可以执行这个命令之后试一下：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">hexo d</span><br></pre></td></tr></table></figure><p>或者用 npm 的方式：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm run deploy</span><br></pre></td></tr></table></figure><h1 id="FINISH"><a href="#FINISH" class="headerlink" title="FINISH"></a>FINISH</h1><p>至此，每次hexo部署后CNAME被清除导致域名与仓库解绑和简化hexo的部署命令的问题就解决了，所遗留的暂时性解决方案就是<code>npx hexo new &quot;page&quot;</code>，但是在此之后就不用手动添加域名了，记录一下解决问题的过程，希望对遇到相同问题的人有帮助。</p><ul><li>re:累了喵，吃饭去了。</li></ul>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;问题起源&quot;&gt;&lt;a href=&quot;#问题起源&quot; class=&quot;headerlink&quot; title=&quot;问题起源&quot;&gt;&lt;/a&gt;问题起源&lt;/h1&gt;&lt;p&gt;在我昨天给博客绑定一个自己的域名之后，我发现每次写完文章进行部署上传的时候，执行以下命令之后:&lt;/p&gt;
&lt;figure cl</summary>
      
    
    
    
    <category term="琐碎问题解决" scheme="https://auberginewly.site/categories/%E7%90%90%E7%A2%8E%E9%97%AE%E9%A2%98%E8%A7%A3%E5%86%B3/"/>
    
    
    <category term="博客配置" scheme="https://auberginewly.site/tags/%E5%8D%9A%E5%AE%A2%E9%85%8D%E7%BD%AE/"/>
    
  </entry>
  
  <entry>
    <title>记录一下第一次给hexo静态博客配置域名</title>
    <link href="https://auberginewly.site/2025/04/15/9_hexo_domain_name/"/>
    <id>https://auberginewly.site/2025/04/15/9_hexo_domain_name/</id>
    <published>2025-04-15T09:55:49.000Z</published>
    <updated>2025-04-21T08:39:12.362Z</updated>
    
    <content type="html"><![CDATA[<h1 id="为什么配置域名？"><a href="#为什么配置域名？" class="headerlink" title="为什么配置域名？"></a>为什么配置域名？</h1><p>因为我原来博客的默认就是github的仓库名<br><code>auberginewly.github.io</code><br>感觉没什么特色而且不科学上网无法访问<br>所以存在一些限制<br>于是想试试看配置域名和做一些加速服务（还没实现）</p><ul><li>可能考虑cloudflare（过时&#x2F;速度慢）或者netlify部署？</li></ul><h1 id="那么如何配置呢？"><a href="#那么如何配置呢？" class="headerlink" title="那么如何配置呢？"></a>那么如何配置呢？</h1><h2 id="step1-购买属于自己的域名"><a href="#step1-购买属于自己的域名" class="headerlink" title="step1 购买属于自己的域名"></a>step1 购买属于自己的域名</h2><p>购买域名的话可以去华为云，阿里云，腾讯云等等的去购买，但是都需要实名认证，我是去腾讯云上买的<code>auberginewly.site</code>，价格是230元&#x2F;10年，感觉还挺划算（）</p><h2 id="step2-配置DNS服务器"><a href="#step2-配置DNS服务器" class="headerlink" title="step2 配置DNS服务器"></a>step2 配置DNS服务器</h2><p>我是直接使用腾讯云自动推荐的</p><p><img src="/../images/image-20250415181940149.png" alt="image-20250415181940149"></p><h2 id="step3-进行DNS解析"><a href="#step3-进行DNS解析" class="headerlink" title="step3 进行DNS解析"></a>step3 进行DNS解析</h2><p>这些dns是指向githubpages的，但是由于一些限制，我的域名这里只能添加两条记录，但是也可以使用。<br><img src="/../images/image-20250415182149890.png" alt="image-20250415182149890"></p><p><img src="/../images/image-20250415182211184.png" alt="image-20250415182211184"></p><h2 id="step4-进行githubpages设置"><a href="#step4-进行githubpages设置" class="headerlink" title="step4 进行githubpages设置"></a>step4 进行githubpages设置</h2><p><img src="/../images/image-20250415182606247.png" alt="image-20250415182606247"></p><ul><li>打开pages</li><li>然后确保仓库的分支正确</li><li>填写你的域名</li><li>打开https服务<br>做完这些步骤之后可能需要等待一会，因为要确认下你域名的dns，可能需要几小时不等，之后你就可以通过你的域名访问个人博客的pages了。</li></ul><h2 id="step5-确认"><a href="#step5-确认" class="headerlink" title="step5 确认"></a>step5 确认</h2><p>按道理来讲，一般会在仓库里生成一个纯文本文件CNAME<br>里面记录了你的域名</p><p><img src="/../images/image-20250415184241474.png" alt="image-20250415184241474"></p><p><img src="/../images/image-20250415184257973.png" alt="image-20250415184257973"><br>如果没有的话<br>可以去这里create new file</p><p><img src="/../images/image-20250415184352736.png" alt="image-20250415184352736"></p><h2 id="关于CNAME"><a href="#关于CNAME" class="headerlink" title="关于CNAME"></a>关于CNAME</h2><p>好问题！我们来简单通俗地解释一下：</p><h3 id="🌐-什么是-CNAME？"><a href="#🌐-什么是-CNAME？" class="headerlink" title="🌐 什么是 CNAME？"></a>🌐 什么是 CNAME？</h3><p>CNAME 是 <strong>Canonical Name</strong> 的缩写，中文叫“别名记录”。<br>它的作用是：<br>👉 <strong>让一个域名指向另一个域名</strong></p><hr><h3 id="🧠-举个例子更好懂："><a href="#🧠-举个例子更好懂：" class="headerlink" title="🧠 举个例子更好懂："></a>🧠 举个例子更好懂：</h3><p>假设你在 GitHub Pages 上建了一个网站，地址是：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">auberginewly.github.io</span><br></pre></td></tr></table></figure><p>你买了一个自己的域名：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">auberginewly.site</span><br></pre></td></tr></table></figure><p>你想让大家访问 <code>auberginewly.site</code> 的时候，其实跳转去 GitHub 上的站点，那就要做“域名绑定”。</p><p>这时候：</p><ul><li><p>你会在 GitHub 仓库里添加一个叫 <code>CNAME</code> 的<strong>文件</strong>，内容是：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">auberginewly.site</span><br></pre></td></tr></table></figure><p>👈 GitHub 通过这个文件知道你的自定义域名。</p></li><li><p>你也可以在域名服务商那边设置一个 <strong>CNAME DNS记录</strong>（如果你想配置子域名，比如 <code>www.auberginewly.site</code>）</p></li></ul><hr><h3 id="🧩-CNAME-有两种常见用途："><a href="#🧩-CNAME-有两种常见用途：" class="headerlink" title="🧩 CNAME 有两种常见用途："></a>🧩 CNAME 有两种常见用途：</h3><table><thead><tr><th>用途</th><th>描述</th></tr></thead><tbody><tr><td>GitHub 仓库里的 <code>CNAME</code> 文件</td><td>告诉 GitHub Pages：我要绑定这个域名</td></tr><tr><td>DNS 设置中的 CNAME 记录</td><td>告诉浏览器：访问这个域名时，跳转到另一个域名（比如 github.io）</td></tr></tbody></table><hr><h3 id="✅-如何使用？"><a href="#✅-如何使用？" class="headerlink" title="✅ 如何使用？"></a>✅ 如何使用？</h3><p>如果你只想用 <code>auberginewly.site</code>：</p><ul><li>✅ 你只需要在 GitHub 仓库里加一个[[ ]]<code>CNAME</code> 文件</li><li>✅ DNS 添加 A 记录，不用设置 CNAME DNS记录</li></ul><h1 id="adds"><a href="#adds" class="headerlink" title="adds"></a>adds</h1><p>另外，域名配置就到此为止了，想要使用加速服务，租一台服务器并备案反向代理镜像，或者把博客部署在其他国内的代码托管平台，后续再跟进喵。</p><ul><li>re:耗时一节线代课，配置域名（）</li></ul>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;为什么配置域名？&quot;&gt;&lt;a href=&quot;#为什么配置域名？&quot; class=&quot;headerlink&quot; title=&quot;为什么配置域名？&quot;&gt;&lt;/a&gt;为什么配置域名？&lt;/h1&gt;&lt;p&gt;因为我原来博客的默认就是github的仓库名&lt;br&gt;&lt;code&gt;auberginewly.g</summary>
      
    
    
    
    <category term="琐碎问题解决" scheme="https://auberginewly.site/categories/%E7%90%90%E7%A2%8E%E9%97%AE%E9%A2%98%E8%A7%A3%E5%86%B3/"/>
    
    
    <category term="博客配置" scheme="https://auberginewly.site/tags/%E5%8D%9A%E5%AE%A2%E9%85%8D%E7%BD%AE/"/>
    
  </entry>
  
  <entry>
    <title>macos在2k外接显示器强制开启HiDPi</title>
    <link href="https://auberginewly.site/2025/04/15/8_macos_2k_HiDPi/"/>
    <id>https://auberginewly.site/2025/04/15/8_macos_2k_HiDPi/</id>
    <published>2025-04-15T01:17:22.000Z</published>
    <updated>2025-04-21T08:39:09.204Z</updated>
    
    <content type="html"><![CDATA[<h1 id="问题所在"><a href="#问题所在" class="headerlink" title="问题所在"></a>问题所在</h1><p>基于macos的特性，其在4k分辨率之下的屏幕上没有做hidpi的适配，字体模糊，所以需要一些手段强制开启。</p><h1 id="参考资料"><a href="#参考资料" class="headerlink" title="参考资料"></a>参考资料</h1><p><a href="https://zhuanlan.zhihu.com/p/187530765">https://zhuanlan.zhihu.com/p/187530765</a><br><a href="https://blog.csdn.net/ningmoon/article/details/136141656">https://blog.csdn.net/ningmoon/article/details/136141656</a><br>但是第二篇资料当中<br>指令在m系列芯片的mac上不适用</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ioreg -lw0 | grep IODisplayPrefsKey | grep -o &#x27;/[^/]\+&quot;$&#x27;</span><br></pre></td></tr></table></figure><p>如图<br><img src="/../images/image-20250415091823460.png" alt="image-20250415091823460"><br>但是发现了更简便的开启方法 且不用关闭sip带来风险</p><h1 id="那就是github上开源项目betterdisplay"><a href="#那就是github上开源项目betterdisplay" class="headerlink" title="那就是github上开源项目betterdisplay"></a>那就是github上开源项目betterdisplay</h1><p><a href="https://github.com/waydabber/BetterDisplay">https://github.com/waydabber/BetterDisplay</a><br>下载dmg<br><img src="/../images/image-20250415091841018.png" alt="image-20250415091841018"><br>目前我的版本是v3.3.4<br><img src="/../images/image-20250415092257273.png" alt="image-20250415092257273">拖拽安装<br>系统设置里选择1920* 1080<br><img src="/../images/image-20250415092333667.png" alt="image-20250415092333667"><br>开启高分辨率 即可强制开启hidpi且保证字体的大小正常<br>不会像默认的2560 1440 那么小了</p>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;问题所在&quot;&gt;&lt;a href=&quot;#问题所在&quot; class=&quot;headerlink&quot; title=&quot;问题所在&quot;&gt;&lt;/a&gt;问题所在&lt;/h1&gt;&lt;p&gt;基于macos的特性，其在4k分辨率之下的屏幕上没有做hidpi的适配，字体模糊，所以需要一些手段强制开启。&lt;/p&gt;
&lt;h1</summary>
      
    
    
    
    <category term="琐碎问题解决" scheme="https://auberginewly.site/categories/%E7%90%90%E7%A2%8E%E9%97%AE%E9%A2%98%E8%A7%A3%E5%86%B3/"/>
    
    
  </entry>
  
  <entry>
    <title>win11下anaconda的虚拟环境配置问题</title>
    <link href="https://auberginewly.site/2025/04/15/7_win11_anaconda_Virtual_environment%20configuration_issues/"/>
    <id>https://auberginewly.site/2025/04/15/7_win11_anaconda_Virtual_environment%20configuration_issues/</id>
    <published>2025-04-15T01:08:32.000Z</published>
    <updated>2025-04-21T08:39:05.393Z</updated>
    
    <content type="html"><![CDATA[<h1 id="下载anaconda"><a href="#下载anaconda" class="headerlink" title="下载anaconda"></a>下载anaconda</h1><p><a href="https://www.anaconda.com/">https://www.anaconda.com</a></p><h1 id="然后配置"><a href="#然后配置" class="headerlink" title="然后配置"></a>然后配置</h1><h2 id="修改虚拟环境默认在c盘"><a href="#修改虚拟环境默认在c盘" class="headerlink" title="修改虚拟环境默认在c盘"></a>修改虚拟环境默认在c盘</h2><p>修改配置文件路径<br>“C:\Users\wlyy\.condarc”<br><img src="/../images/image-20250415091142236.png" alt="image-20250415091142236"><br>修改在文件后加上</p><p><img src="/../images/image-20250415091216626.png" alt="image-20250415091216626"></p><p>这样创建虚拟环境就在指定路径下面</p><h2 id="创建虚拟环境并配置需要的包"><a href="#创建虚拟环境并配置需要的包" class="headerlink" title="创建虚拟环境并配置需要的包"></a>创建虚拟环境并配置需要的包</h2><p>&#x3D;&#x3D;已换源&#x3D;&#x3D;</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">conda create --name myenv python=3.10.13 -c https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main/</span><br><span class="line"></span><br><span class="line">conda activate myenv <span class="comment">#激活 myenv可以替换成简单的项目的名字 我用的是ai_test</span></span><br><span class="line"></span><br><span class="line">conda install numpy=1.26.4 -c https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main/</span><br><span class="line">conda install pandas=2.2.2 -c https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main/</span><br><span class="line">conda install scikit-learn=1.5.1 -c https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main/</span><br><span class="line">conda --no-plugins install matplotlib=3.9.2 -c https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main/</span><br><span class="line">conda --no-plugins install seaborn=0.13.2 -c https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main/</span><br><span class="line">conda --no-plugins install tensorflow=2.10.0 -c https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main/</span><br><span class="line">conda --no-plugins install jupyter=1.0.0 -c https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main/</span><br></pre></td></tr></table></figure><p>退出环境</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">conda deactivate</span><br></pre></td></tr></table></figure><p>进入</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">conda activate xxx(虚拟环境名字)</span><br></pre></td></tr></table></figure><p>&#x3D;&#x3D;安装这些包的时候记得一定要进入到虚拟环境当中 不要在base里安装了 这些纯纯无用功&#x3D;&#x3D;</p><h2 id="CondaValueError-You-have-chosen-a-non-default-solver-backend-libmamba-but-it-was-not-recognized-Choose-one-of-classic-报错"><a href="#CondaValueError-You-have-chosen-a-non-default-solver-backend-libmamba-but-it-was-not-recognized-Choose-one-of-classic-报错" class="headerlink" title="CondaValueError: You have chosen a non-default solver backend (libmamba) but it was not recognized. Choose one of: classic 报错"></a>CondaValueError: You have chosen a non-default solver backend (libmamba) but it was not recognized. Choose one of: classic 报错</h2><p>解决方式<br>如果不想使用 <code>libmamba</code><br>强制切换默认解析器</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line"><span class="comment"># 临时使用 classic（仅当前命令生效）</span></span><br><span class="line">conda install --solver=classic 你的包名</span><br><span class="line"></span><br><span class="line"><span class="comment"># 永久切换回 classic</span></span><br><span class="line">conda config --<span class="built_in">set</span> solver classic</span><br></pre></td></tr></table></figure><p>这样就解决了报错</p><h2 id="在pycharm里配置conda环境找不到conda环境-这个离谱问题需要离谱的解决方式"><a href="#在pycharm里配置conda环境找不到conda环境-这个离谱问题需要离谱的解决方式" class="headerlink" title="在pycharm里配置conda环境找不到conda环境 这个离谱问题需要离谱的解决方式"></a>在pycharm里配置conda环境找不到conda环境 这个离谱问题需要离谱的解决方式</h2><p><a href="https://blog.csdn.net/m0_73262230/article/details/144005565">https://blog.csdn.net/m0_73262230/article/details/144005565</a><br>参考<br><img src="/../images/image-20250415091253429.png" alt="image-20250415091253429"><br>settings添加解释器</p><p><img src="/../images/image-20250415091317800.png" alt="image-20250415091317800"><br>选择现有的<br>然后选择conda.bat<br>再选择创建好的虚拟环境<br>就可以了</p><h1 id="一个报错-导致无法运行出对比的窗口"><a href="#一个报错-导致无法运行出对比的窗口" class="headerlink" title="一个报错 导致无法运行出对比的窗口"></a>一个报错 导致无法运行出对比的窗口</h1><p>OMP: Error #15: Initializing libiomp5md.dll, but found libiomp5 already initialized. OMP: Hint This means that multiple copies of the OpenMP runtime have been linked into the program. That is dangerous, since it can degrade performance or cause incorrect results. The best thing to do is to ensure that only a single OpenMP runtime is linked into the process, e.g. by avoiding static linking of the OpenMP runtime in any library. As an unsafe, unsupported, undocumented workaround you can set the environment variable KMP_DUPLICATE_LIB_OK&#x3D;TRUE to allow the program to continue to execute, but that may cause crashes or silently produce incorrect results. For more information, please see <a href="http://www.intel.com/software/products/support/">http://www.intel.com/software/products/support/</a>.</p><p>参考的解决方式<br><a href="https://blog.csdn.net/peacefairy/article/details/110528012">https://blog.csdn.net/peacefairy/article/details/110528012</a><br>使用的方法一解决的<br>在虚拟环境其中找到了俩libiomp5md.dll<br>做好了路径和备份</p><p><img src="/../images/image-20250415091433748.png" alt="image-20250415091433748"></p><p><img src="/../images/image-20250415091511742.png" alt="image-20250415091511742"></p><p><img src="/../images/image-20250415091535353.png" alt="image-20250415091535353"></p><p>然后删除了第二个<br>运行<br>恢复正常<br><img src="/../images/image-20250415091605432.png" alt="image-20250415091605432"><br>可以成功预测 试验成功<br><img src="/../images/image-20250415091619427.png" alt="image-20250415091619427"><br>这个是之前的报错的</p>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;下载anaconda&quot;&gt;&lt;a href=&quot;#下载anaconda&quot; class=&quot;headerlink&quot; title=&quot;下载anaconda&quot;&gt;&lt;/a&gt;下载anaconda&lt;/h1&gt;&lt;p&gt;&lt;a href=&quot;https://www.anaconda.com/&quot;&gt;ht</summary>
      
    
    
    
    <category term="琐碎问题解决" scheme="https://auberginewly.site/categories/%E7%90%90%E7%A2%8E%E9%97%AE%E9%A2%98%E8%A7%A3%E5%86%B3/"/>
    
    
    <category term="LLM" scheme="https://auberginewly.site/tags/LLM/"/>
    
  </entry>
  
  <entry>
    <title>typora 破解</title>
    <link href="https://auberginewly.site/2025/04/15/6_typora_cracked/"/>
    <id>https://auberginewly.site/2025/04/15/6_typora_cracked/</id>
    <published>2025-04-15T01:08:13.000Z</published>
    <updated>2025-04-21T08:39:01.924Z</updated>
    
    <content type="html"><![CDATA[<h1 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h1><p><a href="https://blog.csdn.net/theaipower/article/details/145144461">https://blog.csdn.net/theaipower/article/details/145144461</a><br>后面的部分可以不用改<br>因为我改了之后会跳走<br>打不开typora</p>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;参考&quot;&gt;&lt;a href=&quot;#参考&quot; class=&quot;headerlink&quot; title=&quot;参考&quot;&gt;&lt;/a&gt;参考&lt;/h1&gt;&lt;p&gt;&lt;a href=&quot;https://blog.csdn.net/theaipower/article/details/145144461&quot;&gt;h</summary>
      
    
    
    
    <category term="琐碎问题解决" scheme="https://auberginewly.site/categories/%E7%90%90%E7%A2%8E%E9%97%AE%E9%A2%98%E8%A7%A3%E5%86%B3/"/>
    
    
  </entry>
  
  <entry>
    <title>Git学习笔记</title>
    <link href="https://auberginewly.site/2025/04/14/5_LearnGitNotes/"/>
    <id>https://auberginewly.site/2025/04/14/5_LearnGitNotes/</id>
    <published>2025-04-14T08:52:13.000Z</published>
    <updated>2025-04-21T08:38:58.926Z</updated>
    
    <content type="html"><![CDATA[<h1 id="安装配置"><a href="#安装配置" class="headerlink" title="安装配置"></a>安装配置</h1><ul><li>安装git</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">brew install git</span><br></pre></td></tr></table></figure><ul><li>配置git</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">git config --global user.name <span class="string">&quot;Your Name&quot;</span></span><br><span class="line">git config --global user.email <span class="string">&quot;email@example.com&quot;</span></span><br></pre></td></tr></table></figure><ul><li><p>因为Git是分布式版本控制系统，所以，每个机器都必须自报家门：你的名字和Email地址。你也许会担心，如果有人故意冒充别人怎么办？这个不必担心，首先我们相信大家都是善良无知的群众，其次，真的有冒充的也是有办法可查的。</p></li><li><p>注意<code>git config</code>命令的<code>--global</code>参数，用了这个参数，表示你这台机器上所有的Git仓库都会使用这个配置，当然也可以对某个仓库指定不同的用户名和Email地址。</p></li></ul><h1 id="创建版本库"><a href="#创建版本库" class="headerlink" title="创建版本库"></a>创建版本库</h1><ul><li>什么是版本库呢？版本库又名仓库（Repository），你可以简单理解成一个目录，这个目录里面的所有文件都可以被Git管理起来，每个文件的修改、删除，Git都能跟踪，以便任何时刻都可以追踪历史，或者在将来某个时刻可以“还原”。</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">cd</span> /Users/wly</span><br><span class="line"><span class="built_in">mkdir</span> learngit</span><br><span class="line"><span class="built_in">cd</span> learngit</span><br><span class="line"><span class="built_in">pwd</span></span><br></pre></td></tr></table></figure><p>然后就会显示</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">/Users/wly/learngit</span><br></pre></td></tr></table></figure><p>可以看到这个<code>pwd</code>显示当前目录</p><ul><li><code>git init</code> 可以把这个目录变成Git可以管理的仓库</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">提示： 使用 <span class="string">&#x27;master&#x27;</span> 作为初始分支的名称。这个默认分支名称可能会更改。要在新仓库中</span><br><span class="line">提示： 配置使用初始分支名，并消除这条警告，请执行：</span><br><span class="line">提示：</span><br><span class="line">提示： git config --global init.defaultBranch &lt;名称&gt;</span><br><span class="line">提示：</span><br><span class="line">提示： 除了 <span class="string">&#x27;master&#x27;</span> 之外，通常选定的名字有 <span class="string">&#x27;main&#x27;</span>、<span class="string">&#x27;trunk&#x27;</span> 和 <span class="string">&#x27;development&#x27;</span>。</span><br><span class="line">提示： 可以通过以下命令重命名刚创建的分支：</span><br><span class="line">提示：</span><br><span class="line">提示： git branch -m &lt;name&gt;</span><br><span class="line">已初始化空的 Git 仓库于 /Users/wly/learngit/.git/</span><br></pre></td></tr></table></figure><ul><li><p>空的仓库（empty Git repository）</p></li><li><p>多了一个<code>.git</code>的目录</p><ul><li>这个目录是Git来跟踪管理版本库的</li><li>&#x3D;&#x3D;不要轻易改动w&#x3D;&#x3D;</li></ul></li><li><p>如果你没有看到<code>.git</code>目录，那是因为这个目录默认是隐藏的，用<code>ls -ah</code>命令就可以看见</p></li><li><p><img src="/../images/image-20250414200913285.png" alt="image-20250414200913285"></p></li><li><p>这样就看到了</p></li></ul><h2 id="把文件添加到版本库"><a href="#把文件添加到版本库" class="headerlink" title="把文件添加到版本库"></a>把文件添加到版本库</h2><p>注意喵：</p><ul><li>首先这里再明确一下，所有的版本控制系统，其实只能跟踪文本文件的改动，比如TXT文件，网页，所有的程序代码等等，Git也不例外。版本控制系统可以告诉你每次的改动，比如在第5行加了一个单词“Linux”，在第8行删了一个单词“Windows”。而图片、视频这些二进制文件，虽然也能由版本控制系统管理，但没法跟踪文件的变化，只能把二进制文件每次改动串起来，也就是只知道图片从100KB改成了120KB，但到底改了啥，版本控制系统不知道，也没法知道。</li><li>不幸的是，Microsoft的Word格式是二进制格式，因此，版本控制系统是没法跟踪Word文件的改动的，前面我们举的例子只是为了演示，如果要真正使用版本控制系统，就要以纯文本方式编写文件。</li><li>因为文本是有编码的，比如中文有常用的GBK编码，日文有Shift_JIS编码，如果没有历史遗留问题，强烈建议使用标准的UTF-8编码，所有语言使用同一种编码，既没有冲突，又被所有平台所支持。</li><li>使用Windows的童鞋要特别注意：千万不要使用Windows自带的<strong>记事本</strong>编辑任何文本文件。原因是Microsoft开发记事本的团队使用了一个非常弱智的行为来保存UTF-8编码的文件，他们自作聪明地在每个文件开头添加了0xefbbbf（十六进制）的字符，你会遇到很多不可思议的问题，比如，网页第一行可能会显示一个“?”，明明正确的程序一编译就报语法错误，等等，都是由记事本的弱智行为带来的。建议你下载<a href="https://code.visualstudio.com/">Visual Studio Code</a>代替记事本，不但功能强大，而且免费！</li><li>编写一个txt</li><li><code>vi readme.txt</code> esc退出编辑 <code>:wq!</code> 保存退出</li><li><code>readme.txt</code>如下：</li></ul><figure class="highlight txt"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">Git is a version control system.</span><br><span class="line">Git is free software.</span><br></pre></td></tr></table></figure><ul><li>一定要放在learngit的目录下面，子目录也行。</li><li>接下来把这个文件放到git仓库当中去：</li></ul><p>添加add</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git add readme.txt</span><br></pre></td></tr></table></figure><p>提交commit</p><ul><li>-m是本次提交的说明，就相当于写了注释，这次提交是为了干什么</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git commit -m <span class="string">&quot;wrote a readme file&quot;</span></span><br></pre></td></tr></table></figure><p><img src="/../images/image-20250414201749673.png" alt="image-20250414201749673"></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">[master（根提交） 6e8be91] wrote a readme file</span><br><span class="line"> 1 file changed, 2 insertions(+)</span><br><span class="line"> create mode 100644 readme.txt</span><br></pre></td></tr></table></figure><ul><li><code>git commit</code>命令执行成功后会告诉你，<code>1 file changed</code>：1个文件被改动（我们新添加的readme.txt文件）；<code>2 insertions</code>：插入了两行内容（readme.txt有两行内容）。<br>另外为什么Git添加文件需要<code>add</code>，<code>commit</code>一共两步呢？因为<code>commit</code>可以一次提交很多文件，所以你可以多次<code>add</code>不同的文件，比如：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">$ git add file1.txt</span><br><span class="line">$ git add file2.txt file3.txt</span><br><span class="line">$ git commit -m <span class="string">&quot;add 3 files.&quot;</span></span><br></pre></td></tr></table></figure><h1 id="时光机穿梭-git-stutus-随时查看工作区状态"><a href="#时光机穿梭-git-stutus-随时查看工作区状态" class="headerlink" title="时光机穿梭 git stutus 随时查看工作区状态"></a>时光机穿梭 git stutus 随时查看工作区状态</h1><p>修改readme.txt后</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">git status</span><br><span class="line">位于分支 master</span><br><span class="line">尚未暂存以备提交的变更：</span><br><span class="line">  （使用 <span class="string">&quot;git add &lt;文件&gt;...&quot;</span> 更新要提交的内容）</span><br><span class="line">  （使用 <span class="string">&quot;git restore &lt;文件&gt;...&quot;</span> 丢弃工作区的改动）</span><br><span class="line">修改：     readme.txt</span><br><span class="line"></span><br><span class="line">提交为空，但是存在尚未跟踪的文件（使用 <span class="string">&quot;git add&quot;</span> 建立跟踪）</span><br></pre></td></tr></table></figure><ul><li><code>git status</code>命令可以让我们时刻掌握仓库当前的状态，上面的命令输出告诉我们，<code>readme.txt</code>被修改过了，但还没有准备提交的修改。</li><li>看看具体修改了什么内容<code>git diff xx</code></li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">git diff readme.txt</span><br><span class="line">diff --git a/readme.txt b/readme.txt</span><br><span class="line">index 46d49bf..9247db6 100644</span><br><span class="line">--- a/readme.txt</span><br><span class="line">+++ b/readme.txt</span><br><span class="line">@@ -1,2 +1,2 @@</span><br><span class="line">-Git is a version control system.</span><br><span class="line">+Git is a distributed version control system.</span><br><span class="line"> Git is free software.</span><br></pre></td></tr></table></figure><ul><li>然后<code>git add</code> <code>git status</code> <code>git commit -m &quot;xx&quot;</code> <code>git status</code>可以添加 确认状态 再上传commit</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">git commit -m <span class="string">&quot;add distributed&quot;</span></span><br><span class="line">[master 9d6f833] add distributed</span><br><span class="line"> 1 file changed, 1 insertion(+), 1 deletion(-)</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">git status</span><br><span class="line">位于分支 master</span><br><span class="line">无文件要提交，干净的工作区</span><br></pre></td></tr></table></figure><h2 id="版本回退"><a href="#版本回退" class="headerlink" title="版本回退"></a>版本回退</h2><p>再次修改readme.txt</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">git add readme.txt</span><br><span class="line">git commit -m <span class="string">&quot;append GPL&quot;</span></span><br><span class="line">[master f1db449] append GPL</span><br><span class="line"> 1 file changed, 1 insertion(+), 1 deletion(-)</span><br></pre></td></tr></table></figure><p>可以理解下git的commit作为虚拟机的快照<br>游戏存档之类的<br><code>git log</code>查看最近提交的日志</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line">git <span class="built_in">log</span></span><br><span class="line">commit f1db449a9da173805d7170f023cf5f4f86e895a8 (HEAD -&gt; master)</span><br><span class="line">Author: auberginewly &lt;3127221787@qq.com&gt;</span><br><span class="line">Date:   Mon Apr 14 21:14:39 2025 +0800</span><br><span class="line"></span><br><span class="line">    append GPL</span><br><span class="line"></span><br><span class="line">commit 17c1986de12e570396e2460494f6060d3bd0b5aa</span><br><span class="line">Author: auberginewly &lt;3127221787@qq.com&gt;</span><br><span class="line">Date:   Mon Apr 14 20:46:03 2025 +0800</span><br><span class="line"></span><br><span class="line">    commit</span><br><span class="line"></span><br><span class="line">commit 9d6f833c3fbf1865ba68726f2e8efe4dc2ffc594</span><br><span class="line">Author: auberginewly &lt;3127221787@qq.com&gt;</span><br><span class="line">Date:   Mon Apr 14 20:41:16 2025 +0800</span><br><span class="line"></span><br><span class="line">    add distributed</span><br><span class="line"></span><br><span class="line">commit 6e8be91f1b3351246c8d2fb9b1c4822230b1db56</span><br><span class="line">Author: auberginewly &lt;3127221787@qq.com&gt;</span><br><span class="line">Date:   Mon Apr 14 20:17:35 2025 +0800</span><br><span class="line"></span><br><span class="line">    wrote a readme file</span><br></pre></td></tr></table></figure><ul><li>如果觉得输出的内容太多，可以这么修改<code>--pretty=oneline</code></li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">git <span class="built_in">log</span> --pretty=oneline</span><br><span class="line">f1db449a9da173805d7170f023cf5f4f86e895a8 (HEAD -&gt; master) append GPL</span><br><span class="line">17c1986de12e570396e2460494f6060d3bd0b5aa commit</span><br><span class="line">9d6f833c3fbf1865ba68726f2e8efe4dc2ffc594 add distributed</span><br><span class="line">6e8be91f1b3351246c8d2fb9b1c4822230b1db56 wrote a readme file</span><br></pre></td></tr></table></figure><p><img src="/../images/image-20250414212003903.png" alt="image-20250414212003903"></p><ul><li>和SVN不一样，Git的<code>commit id</code>不是1，2，3……递增的数字，而是一个SHA1计算出来的一个非常大的数字，用十六进制表示，而且你看到的<code>commit id</code>和我的肯定不一样，以你自己的为准。为什么<code>commit id</code>需要用这么一大串数字表示呢？因为Git是分布式的版本控制系统，后面我们还要研究多人在同一个版本库里工作，如果大家都用1，2，3……作为版本号，那肯定就冲突了。</li></ul><h3 id="把readme-txt版本回退"><a href="#把readme-txt版本回退" class="headerlink" title="把readme.txt版本回退"></a>把readme.txt版本回退</h3><p>每提交一个新版本，实际上Git就会把它们自动串成一条时间线。<br>首先，Git必须知道当前版本是哪个版本，在Git中，用<code>HEAD</code>表示当前版本，也就是最新的提交，上一个版本就是<code>HEAD^</code>，上上一个版本就是<code>HEAD^^</code>，当然往上100个版本写100个<code>^</code>比较容易数不过来，所以写成<code>HEAD~100</code>。</p><ul><li>回退<code>git reset</code></li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">git reset --hard HEAD^</span><br><span class="line">HEAD 现在位于 17c1986 commit</span><br></pre></td></tr></table></figure><ul><li>参数<ul><li><code>--hard</code>参数有啥意义？<code>--hard</code>会回退到上个版本的已提交状态</li><li>而<code>--soft</code>会回退到上个版本的未提交状态</li><li><code>--mixed</code>会回退到上个版本已添加但未提交的状态</li><li>现在，先放心使用<code>--hard</code>。</li></ul></li></ul><p>看readme.txt的内容，回退了。</p><p><img src="/../images/image-20250415084711754.png" alt="image-20250415084711754"><br>其实还可以继续回退到之前的版本<br>但是查看版本库</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line">git <span class="built_in">log</span></span><br><span class="line">commit 17c1986de12e570396e2460494f6060d3bd0b5aa (HEAD -&gt; master)</span><br><span class="line">Author: auberginewly &lt;3127221787@qq.com&gt;</span><br><span class="line">Date:   Mon Apr 14 20:46:03 2025 +0800</span><br><span class="line"></span><br><span class="line">    commit</span><br><span class="line"></span><br><span class="line">commit 9d6f833c3fbf1865ba68726f2e8efe4dc2ffc594</span><br><span class="line">Author: auberginewly &lt;3127221787@qq.com&gt;</span><br><span class="line">Date:   Mon Apr 14 20:41:16 2025 +0800</span><br><span class="line"></span><br><span class="line">    add distributed</span><br><span class="line"></span><br><span class="line">commit 6e8be91f1b3351246c8d2fb9b1c4822230b1db56</span><br><span class="line">Author: auberginewly &lt;3127221787@qq.com&gt;</span><br><span class="line">Date:   Mon Apr 14 20:17:35 2025 +0800</span><br><span class="line"></span><br><span class="line">    wrote a readme file</span><br></pre></td></tr></table></figure><p>之前的记录已经找不到了捏<br>办法其实还是有的，只要上面的命令行窗口还没有被关掉，你就可以顺着往上找啊找啊，找到那个<code>append GPL</code>的<code>commit id</code>是<code>f1db449a9da173805d7170f023cf5f4f86e895a8</code>，于是就可以指定回到未来的某个版本：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git reset --hard f1db4</span><br></pre></td></tr></table></figure><p>再看readme.txt的文本</p><p><img src="/../images/image-20250415085227078.png" alt="image-20250415085227078"></p><h3 id="Git在内部有个指向当前版本的HEAD指针"><a href="#Git在内部有个指向当前版本的HEAD指针" class="headerlink" title="Git在内部有个指向当前版本的HEAD指针"></a>Git在内部有个指向当前版本的<code>HEAD</code>指针</h3><p>git版本回退速度非常快<br>当你回退版本的时候，Git仅仅是把HEAD从指向<code>append GPL</code></p><p><img src="/../images/image-20250415085527078.png" alt="image-20250415085527078"></p><p><strong>然后顺便把工作区的文件更新了。所以你让<code>HEAD</code>指向哪个版本号，你就把当前版本定位在哪。</strong></p><ul><li>如果找不到新版本的commit id怎么办</li><li><code>git reflog</code>用来记录你的每一次命令</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">git reflog</span><br><span class="line">f1db449 (HEAD -&gt; master) HEAD@&#123;0&#125;: reset: moving to f1db4</span><br><span class="line">17c1986 HEAD@&#123;1&#125;: reset: moving to HEAD^</span><br><span class="line">f1db449 (HEAD -&gt; master) HEAD@&#123;2&#125;: commit: append GPL</span><br><span class="line">17c1986 HEAD@&#123;3&#125;: commit: commit</span><br><span class="line">9d6f833 HEAD@&#123;4&#125;: commit: add distributed</span><br><span class="line">6e8be91 HEAD@&#123;5&#125;: commit (initial): wrote a readme file</span><br></pre></td></tr></table></figure><h2 id="工作区和暂存区"><a href="#工作区和暂存区" class="headerlink" title="工作区和暂存区"></a>工作区和暂存区</h2><p>Git和其他版本控制系统如SVN的一个不同之处就是有暂存区的概念。</p><h3 id="工作区（Working-Directory）"><a href="#工作区（Working-Directory）" class="headerlink" title="工作区（Working Directory）"></a>工作区（Working Directory）</h3><p>在电脑里可以看到的目录，learngit文件夹就是一个工作区。</p><h3 id="版本库（Repository）"><a href="#版本库（Repository）" class="headerlink" title="版本库（Repository）"></a>版本库（Repository）</h3><p>工作区有一个隐藏目录<code>.git</code>，这个不算工作区，而是Git的版本库。<br>Git的版本库里存了很多东西，其中最重要的就是称为stage（或者叫index）的暂存区，还有Git为我们自动创建的第一个分支<code>master</code>，以及指向<code>master</code>的一个指针叫<code>HEAD</code>。<br><img src="/../images/image-20250415094644162.png" alt="image-20250415094644162"><br>文件添加到版本库</p><ul><li><code>git add</code>把文件添加进去，添加到暂存区stage</li><li><code>git commit</code>提交更改，实际上就是把暂存区的所有内容提交到当前分支master<br>因为我们创建Git版本库时，Git自动为我们创建了唯一一个<code>master</code>分支，所以，现在，<code>git commit</code>就是往<code>master</code>分支上提交更改。<br>&#x3D;&#x3D;需要提交的文件修改通通放到暂存区，然后，一次性提交暂存区的所有修改。&#x3D;&#x3D;</li></ul><h4 id="进行一些修改"><a href="#进行一些修改" class="headerlink" title="进行一些修改"></a>进行一些修改</h4><p>readme.txt<br>加一个LICENSE文本文件</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">git status</span><br><span class="line">位于分支 master</span><br><span class="line">尚未暂存以备提交的变更：</span><br><span class="line">  （使用 <span class="string">&quot;git add &lt;文件&gt;...&quot;</span> 更新要提交的内容）</span><br><span class="line">  （使用 <span class="string">&quot;git restore &lt;文件&gt;...&quot;</span> 丢弃工作区的改动）</span><br><span class="line">修改：     readme.txt</span><br><span class="line"></span><br><span class="line">未跟踪的文件:</span><br><span class="line">  （使用 <span class="string">&quot;git add &lt;文件&gt;...&quot;</span> 以包含要提交的内容）</span><br><span class="line">LICENSE.txt</span><br><span class="line"></span><br><span class="line">修改尚未加入提交（使用 <span class="string">&quot;git add&quot;</span> 和/或 <span class="string">&quot;git commit -a&quot;</span>）</span><br></pre></td></tr></table></figure><p>使用<code>git add</code>把readme.txt和LICENSE都添加到stage</p><p><img src="/../images/image-20250415095928954.png" alt="image-20250415095928954"><br>使用<code>git commit</code>把暂存区的东西都提交到分支上</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">git status</span><br><span class="line">位于分支 master</span><br><span class="line">无文件要提交，干净的工作区</span><br></pre></td></tr></table></figure><p>一旦提交后，如果你又没有对工作区做任何修改，那么工作区就是“干净”的</p><p><img src="/../images/image-20250415100101925.png" alt="image-20250415100101925"></p><p>变成了这样喵</p><h2 id="管理修改"><a href="#管理修改" class="headerlink" title="管理修改"></a>管理修改</h2><p>Git比其他版本控制系统设计得优秀，因为Git跟踪并管理的是修改，而非文件。<br>修改readme.txt</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">cat</span> readme.txt</span><br><span class="line">Git is a distributed version control system.</span><br><span class="line">Git is free software distributed under the GPL.</span><br><span class="line">Git has a mutable index called stage.</span><br><span class="line">Git tracks changes.</span><br></pre></td></tr></table></figure><p>add</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">git add readme.txt</span><br><span class="line">git status</span><br><span class="line">位于分支 master</span><br><span class="line">要提交的变更：</span><br><span class="line">  （使用 <span class="string">&quot;git restore --staged &lt;文件&gt;...&quot;</span> 以取消暂存）</span><br><span class="line">修改：     readme.txt</span><br></pre></td></tr></table></figure><p>再次修改readme.txt commit</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">git commit -m <span class="string">&quot;git tracks changes&quot;</span></span><br><span class="line"></span><br><span class="line">[master da65a0b] git tracks changes</span><br><span class="line"> 1 file changed, 1 insertion(+)</span><br></pre></td></tr></table></figure><p>查看状态</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">git status</span><br><span class="line">位于分支 master</span><br><span class="line">尚未暂存以备提交的变更：</span><br><span class="line">  （使用 <span class="string">&quot;git add &lt;文件&gt;...&quot;</span> 更新要提交的内容）</span><br><span class="line">  （使用 <span class="string">&quot;git restore &lt;文件&gt;...&quot;</span> 丢弃工作区的改动）</span><br><span class="line">修改：     readme.txt</span><br><span class="line"></span><br><span class="line">修改尚未加入提交（使用 <span class="string">&quot;git add&quot;</span> 和/或 <span class="string">&quot;git commit -a&quot;</span>）</span><br></pre></td></tr></table></figure><p>&#x3D;&#x3D;你看，我们前面讲了，Git管理的是修改，当你用<code>git add</code>命令后，在工作区的第一次修改被放入暂存区，准备提交，但是，在工作区的第二次修改并没有放入暂存区，所以，<code>git commit</code>只负责把暂存区的修改提交了，也就是第一次的修改被提交了，第二次的修改不会被提交。&#x3D;&#x3D;<br>用<code>git diff HEAD -- readme.txt</code>命令可以查看工作区和版本库里面最新版本的区别</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">git diff HEAD -- readme.txt</span><br><span class="line">diff --git a/readme.txt b/readme.txt</span><br><span class="line">index 76d770f..9a8b341 100644</span><br><span class="line">--- a/readme.txt</span><br><span class="line">+++ b/readme.txt</span><br><span class="line">@@ -1,4 +1,4 @@</span><br><span class="line"> Git is a distributed version control system.</span><br><span class="line"> Git is free software distributed under the GPL.</span><br><span class="line"> Git has a mutable index called stage.</span><br><span class="line">-Git tracks changes.</span><br><span class="line">+Git tracks changes of files.</span><br><span class="line">\ No newline at end of file</span><br></pre></td></tr></table></figure><p>第二次修改没提交</p><h2 id="撤销修改"><a href="#撤销修改" class="headerlink" title="撤销修改"></a>撤销修改</h2><p><code>git checkout -- file</code>可以撤销工作区的修改，file是文件名</p><ul><li>一种是<code>readme.txt</code>自修改后还没有被放到暂存区，现在，撤销修改就回到和版本库一模一样的状态；</li><li>一种是<code>readme.txt</code>已经添加到暂存区后，又作了修改，现在，撤销修改就回到添加到暂存区后的状态。</li><li>让这个文件回到最近一次<code>git commit</code>或<code>git add</code>时的状态。<br>注意：</li><li><code>git checkout -- file</code>命令中的<code>--</code>很重要，没有<code>--</code>，就变成了“切换到另一个分支”的命令，我们在后面的分支管理中会再次遇到<code>git checkout</code>命令。<br>命令<code>git reset HEAD &lt;file&gt;</code>可以把暂存区的修改撤销掉（unstage），重新放回工作区<br><code>git reset</code>命令既可以回退版本，也可以把暂存区的修改回退到工作区。当我们用<code>HEAD</code>时，表示最新的版本。</li></ul><h2 id="删除文件"><a href="#删除文件" class="headerlink" title="删除文件"></a>删除文件</h2><p><img src="/../images/image-20250415113421129.png" alt="image-20250415113421129"></p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">rm</span> test.txt</span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">git status</span><br><span class="line">位于分支 master</span><br><span class="line">尚未暂存以备提交的变更：</span><br><span class="line">  （使用 <span class="string">&quot;git add/rm &lt;文件&gt;...&quot;</span> 更新要提交的内容）</span><br><span class="line">  （使用 <span class="string">&quot;git restore &lt;文件&gt;...&quot;</span> 丢弃工作区的改动）</span><br><span class="line">修改：     .DS_Store</span><br><span class="line">修改：     readme.txt</span><br><span class="line">删除：     test.txt</span><br><span class="line"></span><br><span class="line">修改尚未加入提交（使用 <span class="string">&quot;git add&quot;</span> 和/或 <span class="string">&quot;git commit -a&quot;</span>）</span><br></pre></td></tr></table></figure><h3 id="选择1-从版本库当中删除文件"><a href="#选择1-从版本库当中删除文件" class="headerlink" title="选择1 从版本库当中删除文件"></a>选择1 从版本库当中删除文件</h3><p><code>git rm</code> 删掉<br><code>git commit</code> 提交</p><p><img src="/../images/image-20250415113754948.png" alt="image-20250415113754948"></p><h3 id="选择2-删错了-但是版本库里还有-可以恢复"><a href="#选择2-删错了-但是版本库里还有-可以恢复" class="headerlink" title="选择2 删错了 但是版本库里还有 可以恢复"></a>选择2 删错了 但是版本库里还有 可以恢复</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git checkout -- test.txt</span><br></pre></td></tr></table></figure><h3 id="注意"><a href="#注意" class="headerlink" title="注意"></a>注意</h3><p>先手动删除文件，然后使用<code>git rm &lt;file&gt;</code>和<code>git add&lt;file&gt;</code>效果是一样的。</p><h1 id="远程仓库"><a href="#远程仓库" class="headerlink" title="远程仓库"></a>远程仓库</h1><p>Git是分布式版本控制系统，同一个Git仓库，可以分布到不同的机器上。怎么分布呢？最早，肯定只有一台机器有一个原始版本库，此后，别的机器可以“克隆”这个原始版本库，而且每台机器的版本库其实都是一样的，并没有主次之分。</p><h2 id="github"><a href="#github" class="headerlink" title="github"></a>github</h2><p>由于你的本地Git仓库和GitHub仓库之间的传输是通过SSH加密的，所以，需要一点设置：</p><ul><li>第1步：创建SSH Key。在用户主目录下，看看有没有.ssh目录，如果有，再看看这个目录下有没有<code>id_rsa</code>和<code>id_rsa.pub</code>这两个文件，如果已经有了，可直接跳到下一步。如果没有，打开Shell（Windows下打开Git Bash），创建SSH Key：</li></ul><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ssh-keygen -t rsa -C <span class="string">&quot;youremail@example.com&quot;</span></span><br></pre></td></tr></table></figure><p>在用户主目录里找到<code>.ssh</code>目录，里面有<code>id_rsa</code>和<code>id_rsa.pub</code>两个文件，这两个就是SSH Key的秘钥对，<code>id_rsa</code>是私钥，不能泄露出去，<code>id_rsa.pub</code>是公钥，可以放心地告诉任何人。</p><ul><li>第2步：登陆GitHub，打开“Account settings”，“SSH Keys”页面，然后，点“Add SSH Key”，填上任意Title，在Key文本框里粘贴<code>id_rsa.pub</code>文件的内容。<br><img src="/../images/image-20250415120304134.png" alt="image-20250415120304134"></li></ul><h2 id="注意-1"><a href="#注意-1" class="headerlink" title="注意"></a>注意</h2><p>为什么GitHub需要SSH Key呢？因为GitHub需要识别出你推送的提交确实是你推送的，而不是别人冒充的，而Git支持SSH协议，所以，GitHub只要知道了你的公钥，就可以确认只有你自己才能推送。<br>当然，GitHub允许你添加多个Key。假定你有若干电脑，你一会儿在公司提交，一会儿在家里提交，只要把每台电脑的Key都添加到GitHub，就可以在每台电脑上往GitHub推送了。<br>最后友情提示，在GitHub上免费托管的Git仓库，任何人都可以看到喔（但只有你自己才能改）。所以，不要把敏感信息放进去。<br>如果你不想让别人看到Git库，有两个办法，一个是交点保护费，让GitHub把公开的仓库变成私有的，这样别人就看不见了（不可读更不可写）。<br>另一个办法是自己动手，搭一个Git服务器，因为是你自己的Git服务器，所以别人也是看不见的。</p><h2 id="添加远程库"><a href="#添加远程库" class="headerlink" title="添加远程库"></a>添加远程库</h2><p>本地git仓库 远程github也有git仓库 两个仓库进行同步 </p><h3 id="github创建一个库"><a href="#github创建一个库" class="headerlink" title="github创建一个库"></a>github创建一个库</h3><h3 id="在本地的github仓库里执行以下命令"><a href="#在本地的github仓库里执行以下命令" class="headerlink" title="在本地的github仓库里执行以下命令"></a>在本地的github仓库里执行以下命令</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git remote add origin git@github.com:auberginewly/learngit.git</span><br></pre></td></tr></table></figure><p>让本地库关联远程库<br>添加后，远程库的名字就是<code>origin</code>，这是Git默认的叫法，也可以改成别的，但是<code>origin</code>这个名字一看就知道是远程库。</p><h3 id="把本地库所有内容推送到远程库上"><a href="#把本地库所有内容推送到远程库上" class="headerlink" title="把本地库所有内容推送到远程库上"></a>把本地库所有内容推送到远程库上</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">git push -u origin master</span><br><span class="line">枚举对象中: 23, 完成.</span><br><span class="line">对象计数中: 100% (23/23), 完成.</span><br><span class="line">使用 8 个线程进行压缩</span><br><span class="line">压缩对象中: 100% (19/19), 完成.</span><br><span class="line">写入对象中: 100% (23/23), 2.11 KiB | 2.11 MiB/s, 完成.</span><br><span class="line">总共 23（差异 6），复用 0（差异 0），包复用 0（来自  0 个包）</span><br><span class="line">remote: Resolving deltas: 100% (6/6), <span class="keyword">done</span>.</span><br><span class="line">remote: </span><br><span class="line">remote: Create a pull request <span class="keyword">for</span> <span class="string">&#x27;master&#x27;</span> on GitHub by visiting:</span><br><span class="line">remote:      https://github.com/auberginewly/learngit/pull/new/master</span><br><span class="line">remote: </span><br><span class="line">To github.com:auberginewly/learngit.git</span><br><span class="line"> * [new branch]      master -&gt; master</span><br><span class="line">分支 <span class="string">&#x27;master&#x27;</span> 设置为跟踪 <span class="string">&#x27;origin/master&#x27;</span>。</span><br></pre></td></tr></table></figure><p>把本地库的内容推送到远程，用<code>git push</code>命令，实际上是把当前分支<code>master</code>推送到远程。由于远程库是空的，我们第一次推送<code>master</code>分支时，加上了<code>-u</code>参数，Git不但会把本地的<code>master</code>分支内容推送的远程新的<code>master</code>分支，还会把本地的<code>master</code>分支和远程的<code>master</code>分支关联起来，在以后的推送或者拉取时就可以简化命令。</p><h3 id="after"><a href="#after" class="headerlink" title="after"></a>after</h3><p>从现在起，只要本地作了提交，就可以通过命令：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git push origin master</span><br></pre></td></tr></table></figure><p>把本地<code>master</code>分支的最新修改推送至GitHub</p><h3 id="删除远程库（解除关联）"><a href="#删除远程库（解除关联）" class="headerlink" title="删除远程库（解除关联）"></a>删除远程库（解除关联）</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git remote -v</span><br></pre></td></tr></table></figure><p>可以查看远程库信息</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git remote <span class="built_in">rm</span> origin</span><br></pre></td></tr></table></figure><p>删除远程库 实际上是解除了本地库和远程库绑定的联系<br>但是要删除在github上的远程库的时候 还是需要在github上进行操作</p><h2 id="从远程克隆库"><a href="#从远程克隆库" class="headerlink" title="从远程克隆库"></a>从远程克隆库</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git <span class="built_in">clone</span> xxx</span><br></pre></td></tr></table></figure><p>Git支持多种协议，默认的<code>git://</code>使用<code>ssh</code>，但也可以使用<code>https</code>等其他协议。<br>使用<code>https</code>除了速度慢以外，还有个最大的麻烦是每次推送都必须输入口令，但是在某些只开放<code>http</code>端口的公司内部就无法使用<code>ssh</code>协议而只能用<code>https</code>。<br><code>ssh</code>最快<br>eg</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">git <span class="built_in">clone</span> https://github.com/auberginewly/learngit.git</span><br><span class="line">git <span class="built_in">clone</span> git@github.com:auberginewly/learngit.git</span><br></pre></td></tr></table></figure><h1 id="分支管理"><a href="#分支管理" class="headerlink" title="分支管理"></a>分支管理</h1><h2 id="创建与合并分支"><a href="#创建与合并分支" class="headerlink" title="创建与合并分支"></a>创建与合并分支</h2><h3 id="理解分支"><a href="#理解分支" class="headerlink" title="理解分支"></a>理解分支</h3><p>每次提交，Git都把它们串成一条时间线，这条时间线就是一个分支。截止到目前，只有一条时间线，在Git里，这个分支叫主分支，即<code>master</code>分支。<code>HEAD</code>严格来说不是指向提交，而是指向<code>master</code>，<code>master</code>才是指向提交的，所以，<code>HEAD</code>指向的就是当前分支。<br>一开始的时候，<code>master</code>分支是一条线，Git用<code>master</code>指向最新的提交，再用<code>HEAD</code>指向<code>master</code>，就能确定当前分支，以及当前分支的提交点：</p><p><img src="/../images/image-20250416110532632.png" alt="image-20250416110532632"><br>每次提交，<code>master</code>分支都会向前移动一步，这样，随着你不断提交，<code>master</code>分支的线也越来越长。<br>当我们创建新的分支，例如<code>dev</code>时，Git新建了一个指针叫<code>dev</code>，指向<code>master</code>相同的提交，再把<code>HEAD</code>指向<code>dev</code>，就表示当前分支在<code>dev</code>上：</p><p><img src="/../images/image-20250416110616054.png" alt="image-20250416110616054"><br>你看，Git创建一个分支很快，因为除了增加一个<code>dev</code>指针，改改<code>HEAD</code>的指向，工作区的文件都没有任何变化！<br>不过，从现在开始，对工作区的修改和提交就是针对<code>dev</code>分支了，比如新提交一次后，<code>dev</code>指针往前移动一步，而<code>master</code>指针不变：<br><img src="/../images/image-20250416111131790.png" alt="image-20250416111131790"></p><p>假如我们在<code>dev</code>上的工作完成了，就可以把<code>dev</code>合并到<code>master</code>上。Git怎么合并呢？最简单的方法，就是直接把<code>master</code>指向<code>dev</code>的当前提交，就完成了合并：<br><img src="/../images/image-20250416110805007.png" alt="image-20250416110805007"><br>所以Git合并分支也很快！就改改指针，工作区内容也不变！<br>合并完分支后，甚至可以删除<code>dev</code>分支。删除<code>dev</code>分支就是把<code>dev</code>指针给删掉，删掉后，我们就剩下了一条<code>master</code>分支：</p><p><img src="/../images/image-20250416111223784.png" alt="image-20250416111223784"></p><h3 id="命令"><a href="#命令" class="headerlink" title="命令"></a>命令</h3><p>创建并切换到dev分支</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git checkout -b dev</span><br></pre></td></tr></table></figure><p><img src="/../images/image-20250416113008370.png" alt="image-20250416113008370"><br>相当于这两个命令的合并</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">git branch dev</span><br><span class="line">git checkout dev</span><br></pre></td></tr></table></figure><p>然后可以使用<code>git branch</code> 查看命令</p><p><img src="/../images/image-20250416113208584.png" alt="image-20250416113208584"></p><p>对readme.txt做出一些修改<br>添加</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Creating a new branch is quick.</span><br></pre></td></tr></table></figure><p>添加并提交</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">git add readme.txt</span><br><span class="line">git commit -m <span class="string">&quot;branch test&quot;</span></span><br><span class="line">[dev 06d9c0b] branch <span class="built_in">test</span></span><br><span class="line"> 1 file changed, 2 insertions(+), 1 deletion(-)</span><br></pre></td></tr></table></figure><p>到这里对dev的工作就结束了，然后我们切换回master分支</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">git checkout master</span><br><span class="line">M.DS_Store</span><br><span class="line">切换到分支 <span class="string">&#x27;master&#x27;</span></span><br><span class="line">您的分支与上游分支 <span class="string">&#x27;origin/master&#x27;</span> 一致。</span><br></pre></td></tr></table></figure><p>然后查看readme.txt</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">cat</span> readme.txt</span><br><span class="line">Git is a distributed version control system.</span><br><span class="line">Git is free software distributed under the GPL.</span><br><span class="line">Git has a mutable index called stage.</span><br><span class="line">Git tracks changes.</span><br></pre></td></tr></table></figure><p>添加的修改没了</p><p><img src="/../images/image-20250416113701993.png" alt="image-20250416113701993"></p><p>因为那个提交是在<code>dev</code>分支上，而<code>master</code>分支此刻的提交点并没有变<br>我们把<code>dev</code>分支的工作成果合并到<code>master</code>分支上</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">git merge dev</span><br><span class="line">更新 5c9937b..06d9c0b</span><br><span class="line">Fast-forward</span><br><span class="line"> readme.txt | 3 ++-</span><br><span class="line"> 1 file changed, 2 insertions(+), 1 deletion(-)</span><br></pre></td></tr></table></figure><p><code>git merge</code>命令用于合并指定分支到当前分支。合并后，再查看<code>readme.txt</code>的内容，就可以看到，和<code>dev</code>分支的最新提交是完全一样的。<br>注意到上面的<code>Fast-forward</code>信息，Git告诉我们，这次合并是“快进模式”，也就是直接把<code>master</code>指向<code>dev</code>的当前提交，所以合并速度非常快。<br>当然，也不是每次合并都能<code>Fast-forward</code>，还有其他方式的合并。<br>合并完成后，就可以放心地删除<code>dev</code>分支：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">git branch -d dev</span><br><span class="line">已删除分支 dev（曾为 06d9c0b）。</span><br></pre></td></tr></table></figure><p>然后查看分支</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">git branch</span><br><span class="line">* master</span><br></pre></td></tr></table></figure><p>只剩下master了</p><h4 id="为什么要创建多个分支？"><a href="#为什么要创建多个分支？" class="headerlink" title="为什么要创建多个分支？"></a>为什么要创建多个分支？</h4><p>因为创建、合并和删除分支非常快，所以Git鼓励你使用分支完成某个任务，合并后再删掉分支，这和直接在<code>master</code>分支上工作效果是一样的，但过程更安全。</p><h4 id="补充：switch"><a href="#补充：switch" class="headerlink" title="补充：switch"></a>补充：switch</h4><p>我们注意到切换分支使用<code>git checkout &lt;branch&gt;</code>，而前面讲过的撤销修改则是<code>git checkout -- &lt;file&gt;</code>，同一个命令，有两种作用，确实有点令人迷惑。</p><p>实际上，切换分支这个动作，用<code>switch</code>更科学。因此，最新版本的Git提供了新的<code>git switch</code>命令来切换分支，创建 并 切换 到新的<code>dev</code>分支，可以使用：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git switch -c dev</span><br></pre></td></tr></table></figure><p>直接切换到 已有 的<code>master</code>分支，可以使用：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git switch master</span><br></pre></td></tr></table></figure><p>switch比checkout更好理解</p><h2 id="解决冲突"><a href="#解决冲突" class="headerlink" title="解决冲突"></a>解决冲突</h2><p>当Git无法自动合并分支时，就必须首先解决冲突。解决冲突后，再提交，合并完成。<br>解决冲突就是把Git合并失败的文件手动编辑为我们希望的内容，再提交。</p><p>准备好新的feature1分支</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">git switch -c feature1</span><br><span class="line">Switched to a new branch <span class="string">&#x27;feature1&#x27;</span></span><br></pre></td></tr></table></figure><p>先修改readme.txt最后一行为</p><figure class="highlight txt"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Creating a new branch is quick AND simple.</span><br></pre></td></tr></table></figure><p>添加并提交变化</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">git add readme.txt</span><br><span class="line">git commit -m <span class="string">&quot;AND simple&quot;</span></span><br><span class="line">[feature1 50fc8c9] AND simple</span><br><span class="line"> 1 file changed, 1 insertion(+), 1 deletion(-)</span><br></pre></td></tr></table></figure><p>切换到master分支</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">git switch master</span><br><span class="line">M.DS_Store</span><br><span class="line">切换到分支 <span class="string">&#x27;master&#x27;</span></span><br><span class="line">您的分支领先 <span class="string">&#x27;origin/master&#x27;</span> 共 1 个提交。</span><br><span class="line">  （使用 <span class="string">&quot;git push&quot;</span> 来发布您的本地提交）</span><br></pre></td></tr></table></figure><p>Git还会自动提示我们当前<code>master</code>分支比远程的<code>master</code>分支要超前1个提交<br>在<code>master</code>分支上把<code>readme.txt</code>文件的最后一行改为：</p><figure class="highlight txt"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Creating a new branch is quick &amp; simple.</span><br></pre></td></tr></table></figure><p>提交</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">git add readme.txt </span><br><span class="line">git commit -m <span class="string">&quot;&amp; simple&quot;</span></span><br><span class="line">[master 91d9f4f] &amp; simple</span><br><span class="line"> 1 file changed, 1 insertion(+), 1 deletion(-)</span><br></pre></td></tr></table></figure><p>现在master分支和feature1分支都有了各自的提交</p><p>likethis</p><p><img src="/../images/image-20250416164227241.png" alt="image-20250416164227241"><br>这种情况下，Git无法执行“快速合并”，只能试图把各自的修改合并起来，但这种合并就可能会有冲突，比如：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">git merge feature1</span><br><span class="line">自动合并 readme.txt</span><br><span class="line">冲突（内容）：合并冲突于 readme.txt</span><br><span class="line">自动合并失败，修正冲突然后提交修正的结果。</span><br></pre></td></tr></table></figure><p>Git告诉我们，<code>readme.txt</code>文件存在冲突，必须手动解决冲突后再提交。<code>git status</code>也可以告诉我们冲突的文件:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line">git status</span><br><span class="line">位于分支 master</span><br><span class="line">您的分支领先 <span class="string">&#x27;origin/master&#x27;</span> 共 2 个提交。</span><br><span class="line">  （使用 <span class="string">&quot;git push&quot;</span> 来发布您的本地提交）</span><br><span class="line"></span><br><span class="line">您有尚未合并的路径。</span><br><span class="line">  （解决冲突并运行 <span class="string">&quot;git commit&quot;</span>）</span><br><span class="line">  （使用 <span class="string">&quot;git merge --abort&quot;</span> 终止合并）</span><br><span class="line"></span><br><span class="line">未合并的路径：</span><br><span class="line">  （使用 <span class="string">&quot;git add &lt;文件&gt;...&quot;</span> 标记解决方案）</span><br><span class="line">双方修改：   readme.txt</span><br><span class="line"></span><br><span class="line">尚未暂存以备提交的变更：</span><br><span class="line">  （使用 <span class="string">&quot;git add &lt;文件&gt;...&quot;</span> 更新要提交的内容）</span><br><span class="line">  （使用 <span class="string">&quot;git restore &lt;文件&gt;...&quot;</span> 丢弃工作区的改动）</span><br><span class="line">修改：     .DS_Store</span><br><span class="line"></span><br><span class="line">修改尚未加入提交（使用 <span class="string">&quot;git add&quot;</span> 和/或 <span class="string">&quot;git commit -a&quot;</span>）</span><br></pre></td></tr></table></figure><p>我们可以直接查看readme.txt的内容：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">cat</span> readme.txt </span><br><span class="line">Git is a distributed version control system.</span><br><span class="line">Git is free software distributed under the GPL.</span><br><span class="line">Git has a mutable index called stage.</span><br><span class="line">Git tracks changes of files.</span><br><span class="line">&lt;&lt;&lt;&lt;&lt;&lt;&lt; <span class="string">HEAD</span></span><br><span class="line"><span class="string">Creating a new branch is quick &amp; simple.</span></span><br><span class="line"><span class="string">=======</span></span><br><span class="line"><span class="string">Creating a new branch is quick AND simple.</span></span><br><span class="line"><span class="string">&gt;&gt;&gt;&gt;&gt;&gt;&gt; feature1</span></span><br></pre></td></tr></table></figure><p>Git用<code>&lt;&lt;&lt;&lt;&lt;&lt;&lt;</code>，<code>=======</code>，<code>&gt;&gt;&gt;&gt;&gt;&gt;&gt;</code>标记出不同分支的内容，我们修改如下后保存：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">Git is a distributed version control system.</span><br><span class="line">Git is free software distributed under the GPL.</span><br><span class="line">Git has a mutable index called stage.</span><br><span class="line">Git tracks changes of files.</span><br><span class="line">Creating a new branch is quick and simple.</span><br></pre></td></tr></table></figure><p>再提交：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">git add readme.txt </span><br><span class="line">git commit -m <span class="string">&quot;conflict fixed&quot;</span></span><br><span class="line">[master 0ed33be] conflict fixed</span><br></pre></td></tr></table></figure><p>现在，<code>master</code>分支和<code>feature1</code>分支变成了下图所示：</p><p><img src="/../images/image-20250416164456103.png" alt="image-20250416164456103"><br>用带参数的<code>git log</code>也可以看到分支的合并情况：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">git <span class="built_in">log</span> --graph --pretty=oneline --abbrev-commit</span><br><span class="line">*   0ed33be (HEAD -&gt; master) conflict fixed</span><br><span class="line">|\  </span><br><span class="line">| * 50fc8c9 (feature1) AND simple</span><br><span class="line">* | 91d9f4f &amp; simple</span><br><span class="line">|/  </span><br><span class="line">* 06d9c0b branch <span class="built_in">test</span></span><br><span class="line">* 5c9937b (origin/master) Remove test.txt</span><br><span class="line">* 5e9d9fd Add test.txt</span><br><span class="line">* da65a0b git tracks changes</span><br><span class="line">* 2fb0cae understand how stage works</span><br><span class="line">* f1db449 append GPL</span><br><span class="line">* 17c1986 commit</span><br><span class="line">* 9d6f833 add distributed</span><br><span class="line">* 6e8be91 wrote a readme file</span><br></pre></td></tr></table></figure><p>最后，删除<code>feature1</code>分支：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">git branch -d feature1</span><br><span class="line">已删除分支 feature1（曾为 50fc8c9）。</span><br></pre></td></tr></table></figure><p>用<code>git log --graph</code>命令可以看到分支合并图。</p><h4 id="关于一个参数的解释"><a href="#关于一个参数的解释" class="headerlink" title="关于一个参数的解释"></a>关于一个参数的解释</h4><p>这条命令：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git <span class="built_in">log</span> --graph --pretty=oneline --abbrev-commit</span><br></pre></td></tr></table></figure><p>我们可以拆成三部分来解释，每个参数都有它的作用：</p><hr><h5 id="1-graph"><a href="#1-graph" class="headerlink" title="1. --graph"></a>1. <code>--graph</code></h5><ul><li><p>作用：<strong>用 ASCII 字符画出分支和合并的图示</strong>，比如：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">* commit A</span><br><span class="line">|\</span><br><span class="line">| * commit B</span><br><span class="line">|/</span><br><span class="line">* commit C</span><br></pre></td></tr></table></figure><p>这个图示能直观地看到分支的结构，比如哪儿合并了、哪儿分支了。</p></li></ul><hr><h5 id="2-pretty-oneline"><a href="#2-pretty-oneline" class="headerlink" title="2. --pretty=oneline"></a>2. <code>--pretty=oneline</code></h5><ul><li><p>作用：<strong>让每个 commit 显示成一行</strong>，只包含：</p><ul><li>提交的哈希值（默认是完整的，但配合 <code>--abbrev-commit</code> 就是简写的）</li><li>提交信息（commit message）</li></ul><p>显示示例：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">a1b2c3d 修复登录页面bug</span><br><span class="line">4d5e6f7 添加用户注册功能</span><br></pre></td></tr></table></figure></li></ul><hr><h5 id="3-abbrev-commit"><a href="#3-abbrev-commit" class="headerlink" title="3. --abbrev-commit"></a>3. <code>--abbrev-commit</code></h5><ul><li>作用：<strong>缩短提交哈希值</strong>，只显示前几位（一般是前 7 位）</li><li>比如完整哈希是：<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">a1b2c3d4e5f67890123456789abcdef12345678</span><br></pre></td></tr></table></figure>使用这个参数后只显示：<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">a1b2c3d</span><br></pre></td></tr></table></figure></li></ul><hr><h5 id="总结一句话："><a href="#总结一句话：" class="headerlink" title="总结一句话："></a>总结一句话：</h5><blockquote><p>这条命令会以「一行一个提交、缩短哈希值、带有分支图」的形式，显示 Git 提交历史，简洁直观，非常适合快速查看分支结构和提交信息。</p></blockquote><h2 id="分支管理策略"><a href="#分支管理策略" class="headerlink" title="分支管理策略"></a>分支管理策略</h2><p>通常，合并分支时，如果可能，Git会用<code>Fast forward</code>模式，但这种模式下，删除分支后，会丢掉分支信如果要强制禁用<code>Fast forward</code>模式，Git就会在merge时生成一个新的commit，这样，从分支历史上就可以看出分支信息。</p><p>创建并切换dev分支</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">git switch -c dev</span><br><span class="line">切换到一个新分支 <span class="string">&#x27;dev&#x27;</span></span><br></pre></td></tr></table></figure><p>修改readme.txt并将其提交到一个新的commit上</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">git add readme.txt </span><br><span class="line">git commit -m <span class="string">&quot;add merge&quot;</span></span><br><span class="line">[dev 10684e3] add merge</span><br><span class="line"> 1 file changed, 1 insertion(+)</span><br></pre></td></tr></table></figure><p>切换回master</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">git switch master</span><br><span class="line">M.DS_Store</span><br><span class="line">切换到分支 <span class="string">&#x27;master&#x27;</span></span><br><span class="line">您的分支领先 <span class="string">&#x27;origin/master&#x27;</span> 共 4 个提交。</span><br><span class="line">  （使用 <span class="string">&quot;git push&quot;</span> 来发布您的本地提交）</span><br></pre></td></tr></table></figure><p>禁用fast forward合并dev分支</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">git merge --no-ff -m <span class="string">&quot;merge with no-ff&quot;</span> dev</span><br><span class="line">Merge made by the <span class="string">&#x27;ort&#x27;</span> strategy.</span><br><span class="line"> readme.txt | 1 +</span><br><span class="line"> 1 file changed, 1 insertion(+)</span><br></pre></td></tr></table></figure><p>请注意<code>--no-ff</code>参数，表示禁用<code>Fast forward</code>，因为本次合并要创建一个新的commit，所以加上<code>-m</code>参数，把commit描述写进去。<br>用<code>git log</code>看看分支历史</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line">git <span class="built_in">log</span> --graph --pretty=oneline --abbrev-commit</span><br><span class="line">*   9a4ed3f (HEAD -&gt; master) merge with no-ff</span><br><span class="line">|\  </span><br><span class="line">| * 10684e3 (dev) add merge</span><br><span class="line">|/  </span><br><span class="line">*   0ed33be conflict fixed</span><br><span class="line">|\  </span><br><span class="line">| * 50fc8c9 AND simple</span><br><span class="line">* | 91d9f4f &amp; simple</span><br><span class="line">|/  </span><br><span class="line">* 06d9c0b branch <span class="built_in">test</span></span><br><span class="line">* 5c9937b (origin/master) Remove test.txt</span><br><span class="line">* 5e9d9fd Add test.txt</span><br><span class="line">* da65a0b git tracks changes</span><br><span class="line">* 2fb0cae understand how stage works</span><br><span class="line">* f1db449 append GPL</span><br><span class="line">* 17c1986 commit</span><br><span class="line">* 9d6f833 add distributed</span><br><span class="line">* 6e8be91 wrote a readme file</span><br></pre></td></tr></table></figure><p>合并分支时，加上<code>--no-ff</code>参数就可以用普通模式合并，合并后的历史有分支，能看出来曾经做过合并，而<code>fast forward</code>合并就看不出来曾经做过合并。</p><p><img src="/../images/image-20250416180242643.png" alt="image-20250416180242643"><br>不使用<code>Fast forward</code>模式，merge后就像这样</p><h3 id="分支策略应用"><a href="#分支策略应用" class="headerlink" title="分支策略应用"></a>分支策略应用</h3><p>在实际开发中，我们应该按照几个基本原则进行分支管理：<br>首先，<code>master</code>分支应该是非常稳定的，也就是仅用来发布新版本，平时不能在上面干活；<br>那在哪干活呢？干活都在<code>dev</code>分支上，也就是说，<code>dev</code>分支是不稳定的，到某个时候，比如1.0版本发布时，再把<code>dev</code>分支合并到<code>master</code>上，在<code>master</code>分支发布1.0版本；<br>你和你的小伙伴们每个人都在<code>dev</code>分支上干活，每个人都有自己的分支，时不时地往<code>dev</code>分支上合并就可以了。<br>所以，团队合作的分支看起来就像这样：</p><p><img src="/../images/image-20250416180350995.png" alt="image-20250416180350995"></p><h2 id="Bug分支"><a href="#Bug分支" class="headerlink" title="Bug分支"></a>Bug分支</h2><p>软件开发中会有bug的产生，git当中分支相当的强大，每个bug都可以通过一个新的临时分支来修复，修复后，合并分支，然后将临时分支删除。<br>如果当你接到一个修复一个代号101的bug的任务时，很自然地，你想创建一个分支<code>issue-101</code>来修复它，但是，等等，当前正在<code>dev</code>上进行的工作还没有提交，但是必须尽快修复bug，这个时候，Git还提供了一个<code>stash</code>功能，可以把当前工作现场“储藏”起来，等以后恢复现场后继续工作：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">git stash</span><br><span class="line">保存工作目录和索引状态 WIP on dev: 10684e3 add merge</span><br></pre></td></tr></table></figure><p>这个时候查看状态就是干净的</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">git status</span><br><span class="line">位于分支 dev</span><br><span class="line">无文件要提交，干净的工作区</span><br></pre></td></tr></table></figure><p>首先确定要在哪个分支上修复bug，假定需要在<code>master</code>分支上修复，就从<code>master</code>创建临时分支：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">git checkout master </span><br><span class="line">切换到分支 <span class="string">&#x27;master&#x27;</span></span><br><span class="line">您的分支领先 <span class="string">&#x27;origin/master&#x27;</span> 共 6 个提交。</span><br><span class="line">  （使用 <span class="string">&quot;git push&quot;</span> 来发布您的本地提交）</span><br><span class="line">git checkout -b issue-101</span><br><span class="line">切换到一个新分支 <span class="string">&#x27;issue-101&#x27;</span></span><br></pre></td></tr></table></figure><p>修改并提交</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">git add readme.txt</span><br><span class="line">git commit -m <span class="string">&quot;fixed text&quot;</span></span><br><span class="line">[issue-101 ebea9af] fixed text</span><br><span class="line"> 1 file changed, 1 insertion(+), 1 deletion(-)</span><br></pre></td></tr></table></figure><p>修改完，切换到master分支，并且删除issue-101分支：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">git switch master</span><br><span class="line">git merge --no-ff -m <span class="string">&quot;merged bug fix 101&quot;</span> issue-101</span><br><span class="line">切换到分支 <span class="string">&#x27;master&#x27;</span></span><br><span class="line">您的分支领先 <span class="string">&#x27;origin/master&#x27;</span> 共 6 个提交。</span><br><span class="line">  （使用 <span class="string">&quot;git push&quot;</span> 来发布您的本地提交）</span><br><span class="line">Merge made by the <span class="string">&#x27;ort&#x27;</span> strategy.</span><br><span class="line"> readme.txt | 2 +-</span><br><span class="line"> 1 file changed, 1 insertion(+), 1 deletion(-)</span><br></pre></td></tr></table></figure><p>切换回dev干活</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">git switch dev</span><br><span class="line">git status</span><br><span class="line">切换到分支 <span class="string">&#x27;dev&#x27;</span></span><br><span class="line">位于分支 dev</span><br><span class="line">无文件要提交，干净的工作区</span><br></pre></td></tr></table></figure><p>刚刚存的工作现场去哪了？用<code>git stash list</code>命令看看：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">git stash list</span><br><span class="line">stash@&#123;0&#125;: WIP on dev: 10684e3 add merge</span><br></pre></td></tr></table></figure><p>工作现场还在，Git把<code>stash</code>内容存在某个地方了，但是需要恢复一下，有两个办法：<br>一是用<code>git stash apply</code>恢复，但是恢复后，<code>stash</code>内容并不删除，你需要用<code>git stash drop</code>来删除；<br>另一种方式是用<code>git stash pop</code>，恢复的同时把<code>stash</code>内容也删了：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">git stash pop</span><br><span class="line">位于分支 dev</span><br><span class="line">尚未暂存以备提交的变更：</span><br><span class="line">  （使用 <span class="string">&quot;git add &lt;文件&gt;...&quot;</span> 更新要提交的内容）</span><br><span class="line">  （使用 <span class="string">&quot;git restore &lt;文件&gt;...&quot;</span> 丢弃工作区的改动）</span><br><span class="line">修改：     .DS_Store</span><br><span class="line"></span><br><span class="line">修改尚未加入提交（使用 <span class="string">&quot;git add&quot;</span> 和/或 <span class="string">&quot;git commit -a&quot;</span>）</span><br><span class="line">丢弃了 refs/stash@&#123;0&#125;（4455b2d53e9e9b84dbb19082057f620a67cbad26）</span><br></pre></td></tr></table></figure><p>这个时候再查看，就没有任何stash暂存工作区的内容了</p><p><img src="/../images/image-20250416184434140.png" alt="image-20250416184434140"><br>你可以多次<code>stash</code>，恢复的时候，先用<code>git stash list</code>查看，然后恢复指定的<code>stash</code>，用命令：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git stash apply stash@&#123;0&#125;</span><br></pre></td></tr></table></figure><p>在<code>master</code>分支上修复了bug后，我们要想一想，<code>dev</code>分支是早期从<code>master</code>分支分出来的，所以，这个bug其实在当前<code>dev</code>分支上也存在。那怎么在<code>dev</code>分支上修复同样的bug？<br>复制<code>3e0825f fix bug 101</code>这个提交所做的修改，并不是把整个<code>master</code>分支merge过来。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">git cherry-pick 3e0825f</span><br><span class="line">[master 870ac6e] merged bug fix 101</span><br><span class="line">Date: Wed Apr 16 18:54:32 2025 +0800</span><br></pre></td></tr></table></figure><p>这两个commit只是改动相同，但确实是两个不同的commit。用<code>git cherry-pick</code>，我们就不需要在<code>dev</code>分支上手动再把修bug的过程重复一遍。既然可以在<code>master</code>分支上修复bug后，在<code>dev</code>分支上可以“重放”这个修复过程，那么直接在<code>dev</code>分支上修复bug，然后在<code>master</code>分支上“重放”行不行？当然可以，不过你仍然需要<code>git stash</code>命令保存现场，才能从<code>dev</code>分支切换到<code>master</code>分支。</p><h2 id="Feature分支"><a href="#Feature分支" class="headerlink" title="Feature分支"></a>Feature分支</h2><p>软件开发中，总有无穷无尽的新的功能要不断添加进来。<br>添加一个新功能时，你肯定不希望因为一些实验性质的代码，把主分支搞乱了，所以，每添加一个新功能，最好新建一个feature分支，在上面开发，完成后，合并，最后，删除该feature分支。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">git switch -c xx</span><br><span class="line">git add xx</span><br><span class="line">git status</span><br><span class="line">git commit -m <span class="string">&quot;xx&quot;</span></span><br><span class="line">git switch dev </span><br><span class="line"><span class="comment"># 合并</span></span><br><span class="line"><span class="comment"># 如果不合并 强行删除</span></span><br><span class="line">git branch -D xx</span><br></pre></td></tr></table></figure><h2 id="多人协作"><a href="#多人协作" class="headerlink" title="多人协作"></a>多人协作</h2><p>当你从远程仓库克隆时，实际上Git自动把本地的<code>master</code>分支和远程的<code>master</code>分支对应起来了，并且，远程仓库的默认名称是<code>origin</code>。<br>要查看远程库的信息，用<code>git remote</code>，或者<code>git remote -v</code></p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">git remote</span><br><span class="line">origin</span><br><span class="line">git remote -v </span><br><span class="line">origingit@github.com:auberginewly/learngit.git (fetch)</span><br><span class="line">origingit@github.com:auberginewly/learngit.git (push)</span><br></pre></td></tr></table></figure><p>上面显示了可以抓取和推送的<code>origin</code>的地址。如果没有推送权限，就看不到push的地址。</p><h3 id="推送分支"><a href="#推送分支" class="headerlink" title="推送分支"></a>推送分支</h3><p>推送分支，就是把该分支上的所有本地提交推送到远程库。推送时，要指定本地分支，这样，Git就会把该分支推送到远程库对应的远程分支上：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">git push origin master</span><br><span class="line">git push origin dev</span><br></pre></td></tr></table></figure><p>1</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">git push origin master</span><br><span class="line">枚举对象中: 23, 完成.</span><br><span class="line">对象计数中: 100% (23/23), 完成.</span><br><span class="line">使用 8 个线程进行压缩</span><br><span class="line">压缩对象中: 100% (21/21), 完成.</span><br><span class="line">写入对象中: 100% (21/21), 1.67 KiB | 1.67 MiB/s, 完成.</span><br><span class="line">总共 21（差异 16），复用 0（差异 0），包复用 0（来自  0 个包）</span><br><span class="line">remote: Resolving deltas: 100% (16/16), completed with 2 <span class="built_in">local</span> objects.</span><br><span class="line">To github.com:auberginewly/learngit.git</span><br><span class="line">   5c9937b..870ac6e  master -&gt; master</span><br></pre></td></tr></table></figure><p>2</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"> git push origin dev</span><br><span class="line"></span><br><span class="line">枚举对象中: 2, 完成.</span><br><span class="line">对象计数中: 100% (2/2), 完成.</span><br><span class="line">使用 8 个线程进行压缩</span><br><span class="line">压缩对象中: 100% (2/2), 完成.</span><br><span class="line">写入对象中: 100% (2/2), 285 字节 | 285.00 KiB/s, 完成.</span><br><span class="line">总共 2（差异 1），复用 0（差异 0），包复用 0（来自  0 个包）</span><br><span class="line">remote: Resolving deltas: 100% (1/1), <span class="keyword">done</span>.</span><br><span class="line">remote: </span><br><span class="line">remote: Create a pull request <span class="keyword">for</span> <span class="string">&#x27;dev&#x27;</span> on GitHub by visiting:</span><br><span class="line">remote:      https://github.com/auberginewly/learngit/pull/new/dev</span><br><span class="line">remote: </span><br><span class="line">To github.com:auberginewly/learngit.git</span><br><span class="line"> * [new branch]      dev -&gt; dev</span><br></pre></td></tr></table></figure><p>但是，并不是一定要把本地分支往远程推送，那么，哪些分支需要推送，哪些不需要呢？</p><ul><li><code>master</code>分支是主分支，因此要时刻与远程同步；</li><li><code>dev</code>分支是开发分支，团队所有成员都需要在上面工作，所以也需要与远程同步；</li><li>bug分支只用于在本地修复bug，就没必要推到远程了，除非老板要看看你每周到底修复了几个bug；</li><li>feature分支是否推到远程，取决于你是否和你的小伙伴合作在上面开发。<br>总之，就是在Git中，分支完全可以在本地自己藏着玩，是否推送，视你的心情而定！</li></ul><h3 id="抓取分支"><a href="#抓取分支" class="headerlink" title="抓取分支"></a>抓取分支</h3><p>多人协作时，大家都会往<code>master</code>和<code>dev</code>分支上推送各自的修改。<br>模拟多人协作，在同一台电脑另外一个目录下clone<br><img src="/../images/image-20250416201413521.png" alt="image-20250416201413521"></p><p><img src="/../images/image-20250416201808989.png" alt="image-20250416201808989"></p><p>但是只能看到默认分支</p><p><img src="/../images/image-20250416205734127.png" alt="image-20250416205734127"></p><p>我这里是main<br>要在<code>dev</code>分支上开发，就必须创建远程<code>origin</code>的<code>dev</code>分支到本地<br>在<code>dev</code>上继续修改，然后，时不时地把<code>dev</code>分支<code>push</code>到远程</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">git add env.txt</span><br><span class="line">git commit -m <span class="string">&quot;add env.txt&quot;</span></span><br><span class="line">[dev 8d5d9cc] add env.txt</span><br><span class="line"> 1 file changed, 1 insertion(+)</span><br><span class="line"> create mode 100644 env.txt</span><br><span class="line">git push origin dev</span><br><span class="line">枚举对象中: 4, 完成.</span><br><span class="line">对象计数中: 100% (4/4), 完成.</span><br><span class="line">使用 8 个线程进行压缩</span><br><span class="line">压缩对象中: 100% (2/2), 完成.</span><br><span class="line">写入对象中: 100% (3/3), 264 字节 | 264.00 KiB/s, 完成.</span><br><span class="line">总共 3（差异 1），复用 0（差异 0），包复用 0（来自  0 个包）</span><br><span class="line">remote: Resolving deltas: 100% (1/1), completed with 1 <span class="built_in">local</span> object.</span><br><span class="line">To github.com:auberginewly/learngit.git</span><br><span class="line">   9a03df8..8d5d9cc  dev -&gt; dev</span><br></pre></td></tr></table></figure><p>如果这个时候另外一个人也想推送，先用<code>git pull</code>把最新的提交从<code>origin/dev</code>抓下来，然后，在本地合并，解决冲突，再推送。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">git branch --set-upstream-to=origin/dev dev <span class="comment"># 指定本地dev与远程联系</span></span><br><span class="line">Branch <span class="string">&#x27;dev&#x27;</span> <span class="built_in">set</span> up to track remote branch <span class="string">&#x27;dev&#x27;</span> from <span class="string">&#x27;origin&#x27;</span>.</span><br><span class="line">git pull <span class="comment"># 再pull</span></span><br><span class="line">remote: Enumerating objects: 7, <span class="keyword">done</span>.</span><br><span class="line">remote: Counting objects: 100% (7/7), <span class="keyword">done</span>.</span><br><span class="line">remote: Compressing objects: 100% (2/2), <span class="keyword">done</span>.</span><br><span class="line">remote: Total 6 (delta 1), reused 3 (delta 1), pack-reused 0 (from 0)</span><br><span class="line">展开对象中: 100% (6/6), 1.09 KiB | 222.00 KiB/s, 完成.</span><br><span class="line">来自 github.com:auberginewly/learngit</span><br><span class="line">   9a03df8..8d5d9cc  dev        -&gt; origin/dev</span><br><span class="line"> * [新分支]          main       -&gt; origin/main</span><br><span class="line">已经是最新的。</span><br></pre></td></tr></table></figure><p>如果有合并冲突，手动解决之后在push<br>参考解决冲突那一小节</p><h2 id="Rebase"><a href="#Rebase" class="headerlink" title="Rebase"></a>Rebase</h2><p>多人在同一个分支上协作时，很容易出现冲突。即使没有冲突，后push的不得不先pull，在本地合并，然后才能push成功，然后分支就会乱成一坨狗屎。<br>Git有一种称为<code>rebase</code>的操作，有人把它翻译成“变基”。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git rebase</span><br></pre></td></tr></table></figure><p>可以让原来分叉的提交变成一条直线，Git把本地的提交“挪动”了位置，这就是rebase操作的特点：把分叉的提交历史“整理”成一条直线，看上去更直观，缺点是本地的分叉提交已经被修改过，远程分支的提交历史也是一条直线。</p><h1 id="标签管理"><a href="#标签管理" class="headerlink" title="标签管理"></a>标签管理</h1><h2 id="创建标签"><a href="#创建标签" class="headerlink" title="创建标签"></a>创建标签</h2><p>Git中打标签先切换到需要打标签的分支上</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git checkout xxx</span><br></pre></td></tr></table></figure><p>然后打标签</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git tag &lt;name&gt;</span><br></pre></td></tr></table></figure><p>使用<code>git tag</code>可以查看所有的标签<br>默认的标签打在最新的commit上面<br>如果需要打给其他的commit的标签<br>找到历史提交的commit id，然后打上就可以了</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git tag &lt;tag name&gt; &lt;commit <span class="built_in">id</span>&gt;</span><br></pre></td></tr></table></figure><p>一个commit可以对应多个tags<br>标签不是按时间顺序列出，而是按字母排序的，可以用<code>git show &lt;tagname&gt;</code>查看标签信息。<br>还可以创建带有说明的标签，用<code>-a</code>指定标签名，<code>-m</code>指定说明文字，eg：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git tag -a v0.1 -m <span class="string">&quot;version 0.1 released&quot;</span> 1094adb</span><br></pre></td></tr></table></figure><p>用命令<code>git show &lt;tagname&gt;</code>可以看到说明文字<br>注意</p><blockquote><p>标签总是和某个commit挂钩。如果这个commit既出现在master分支，又出现在dev分支，那么在这两个分支上都可以看到这个标签。</p></blockquote><h2 id="操作标签"><a href="#操作标签" class="headerlink" title="操作标签"></a>操作标签</h2><p>删除</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git tag -d &lt;tag name&gt;</span><br></pre></td></tr></table></figure><p>因为创建的标签都只存储在本地，不会自动推送到远程。所以，打错的标签可以在本地安全删除。<br>如果要推送某个标签到远程，使用命令<code>git push origin &lt;tagname&gt;</code><br>或者，一次性推送全部尚未推送到远程的本地标签</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git push origin --tags</span><br></pre></td></tr></table></figure><p>如果标签已经推送到远程，要删除远程标签就麻烦一点，先从本地删除：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git tag -d &lt;tag name&gt;</span><br></pre></td></tr></table></figure><p>然后从远程删除 也是push 格式如下</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git push origin :refs/tags/&lt;tag name&gt;</span><br></pre></td></tr></table></figure><h1 id="关于使用github"><a href="#关于使用github" class="headerlink" title="关于使用github"></a>关于使用github</h1><ul><li>在GitHub上，可以任意Fork开源仓库；</li><li>自己拥有Fork后的仓库的读写权限；</li><li>可以推送pull request给官方仓库来贡献代码。</li></ul><h1 id="关于使用gitee"><a href="#关于使用gitee" class="headerlink" title="关于使用gitee"></a>关于使用gitee</h1><p>&#x2F;&#x2F; 待更新 可以同时连接多个远程仓库</p><h1 id="自定义Git"><a href="#自定义Git" class="headerlink" title="自定义Git"></a>自定义Git</h1><h2 id="修改git的颜色让其更醒目"><a href="#修改git的颜色让其更醒目" class="headerlink" title="修改git的颜色让其更醒目"></a>修改git的颜色让其更醒目</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git config --global color.ui <span class="literal">true</span></span><br></pre></td></tr></table></figure><h2 id="给git配置名字和邮箱"><a href="#给git配置名字和邮箱" class="headerlink" title="给git配置名字和邮箱"></a>给git配置名字和邮箱</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># Set global username</span></span><br><span class="line">git config --global user.name <span class="string">&quot;your_username&quot;</span></span><br><span class="line"><span class="comment"># Set global email</span></span><br><span class="line">git config --global user.email <span class="string">&quot;your_email@example.com&quot;</span></span><br></pre></td></tr></table></figure><p><code>--global</code>全局</p><h2 id="忽略特殊文件"><a href="#忽略特殊文件" class="headerlink" title="忽略特殊文件"></a>忽略特殊文件</h2><p>有些时候，你必须把某些文件放到Git工作目录中，但又不能提交它们，比如保存了数据库密码的配置文件，每次<code>git status</code>都会显示<code>Untracked files ...</code>，添加<code>.gitignore</code>文件，然后把要忽略的文件名填进去，Git就会自动忽略这些文件。<br>注意喔</p><blockquote><p><code>.gitignore</code>文件本身应该提交给Git管理，这样可以确保所有人在同一项目下都使用相同的<code>.gitignore</code>文件。</p></blockquote><p>不需要从头写<code>.gitignore</code>文件，GitHub已经为我们准备了各种配置文件，只需要组合一下就可以使用了。所有配置文件可以直接在线浏览：<a href="https://github.com/github/gitignore">GitHub&#x2F;gitignore</a></p><blockquote><p>忽略文件的原则是：</p><ol><li>忽略操作系统自动生成的文件，比如缩略图等；</li><li>略编译生成的中间文件、可执行文件等，也就是如果一个文件是通过另一个文件自动生成的，那自动生成的文件就没必要放进版本库，比如Java编译产生的<code>.class</code>文件；</li><li>自己的带有敏感信息的配置文件，比如存放口令的配置文件。</li></ol></blockquote><p>假设你在Windows下进行Python开发，Windows会自动在有图片的目录下生成隐藏的缩略图文件，如果有自定义目录，目录下就会有<code>Desktop.ini</code>文件，因此你需要忽略Windows自动生成的垃圾文件：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"># Windows:</span><br><span class="line">Thumbs.db</span><br><span class="line">ehthumbs.db</span><br><span class="line">Desktop.ini</span><br></pre></td></tr></table></figure><p>然后，继续忽略Python编译产生的<code>.pyc</code>、<code>.pyo</code>、<code>dist</code>等文件或目录：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"># Python:</span><br><span class="line">*.py[cod]</span><br><span class="line">*.so</span><br><span class="line">*.egg</span><br><span class="line">*.egg-info</span><br><span class="line">dist</span><br><span class="line">build</span><br></pre></td></tr></table></figure><p>加上你自己定义的文件，最终得到一个完整的<code>.gitignore</code>文件，内容如下：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"># Windows:</span><br><span class="line">Thumbs.db</span><br><span class="line">ehthumbs.db</span><br><span class="line">Desktop.ini</span><br><span class="line"></span><br><span class="line"># Python:</span><br><span class="line">*.py[cod]</span><br><span class="line">*.so</span><br><span class="line">*.egg</span><br><span class="line">*.egg-info</span><br><span class="line">dist</span><br><span class="line">build</span><br><span class="line"></span><br><span class="line"># My configurations:</span><br><span class="line">db.ini</span><br><span class="line">deploy_key_rsa</span><br></pre></td></tr></table></figure><p>然后把<code>.gitignore</code>也提交到Git，检验<code>.gitignore</code>的标准是<code>git status</code>命令是不是说<code>working directory clean</code>。<br>有时候，想添加一个文件到Git，但发现添加不了，原因是这个文件被<code>.gitignore</code>忽略了：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">git add App.class</span><br><span class="line">The following paths are ignored by one of your .gitignore files:</span><br><span class="line">App.class</span><br><span class="line">Use -f <span class="keyword">if</span> you really want to add them.</span><br></pre></td></tr></table></figure><p>如果你确实想添加该文件，可以用<code>-f</code>强制添加到Git：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git add -f App.class</span><br></pre></td></tr></table></figure><p>或者你发现，可能是<code>.gitignore</code>写得有问题，需要找出来到底哪个规则写错了，可以用<code>git check-ignore</code>命令检查(别忘了-v哦)</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">git check-ignore -v App.class</span><br><span class="line">.gitignore:3:*.classApp.class</span><br></pre></td></tr></table></figure><p>Git会告诉我们，<code>.gitignore</code>的第3行规则忽略了该文件，于是我们就可以知道应该修订哪个规则。<br>还有些时候，当我们编写了规则排除了部分文件时：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"># 排除所有.开头的隐藏文件:</span><br><span class="line">.*</span><br><span class="line"># 排除所有.class文件:</span><br><span class="line">*.class</span><br></pre></td></tr></table></figure><p>但是我们发现<code>.*</code>这个规则把<code>.gitignore</code>也排除了，并且<code>App.class</code>需要被添加到版本库，但是被<code>*.class</code>规则排除了。</p><p>虽然可以用<code>git add -f</code>强制添加进去，但有强迫症还是希望不要破坏<code>.gitignore</code>规则，这个时候，可以添加两条例外规则：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"># 排除所有.开头的隐藏文件:</span><br><span class="line">.*</span><br><span class="line"># 排除所有.class文件:</span><br><span class="line">*.class</span><br><span class="line"></span><br><span class="line"># 不排除.gitignore和App.class:</span><br><span class="line">!.gitignore</span><br><span class="line">!App.class</span><br></pre></td></tr></table></figure><p>把指定文件排除在<code>.gitignore</code>规则外的写法就是<code>!</code>+文件名，所以，只需把例外文件添加进去即可。</p><blockquote><p>另外，可以通过<a href="https://michaelliao.github.io/gitignore-online-generator/">GitIgnore Online Generator</a>在线生成<code>.gitignore</code>文件并直接下载。</p></blockquote><p>还有一点</p><blockquote><p><code>.gitignore</code>文件放哪放Git仓库根目录下，但其实一个Git仓库也可以有多个<code>.gitignore</code>文件，<code>.gitignore</code>文件放在哪个目录下，就对哪个目录（包括子目录）起作用。</p></blockquote><p>就像这样<br><img src="/../images/image-20250417004137441.png" alt="image-20250417004137441"></p><ul><li><code>.gitignore</code>文件本身要放到版本库里，并且可以对<code>.gitignore</code>做版本管理！</li></ul><h2 id="配置别名"><a href="#配置别名" class="headerlink" title="配置别名"></a>配置别名</h2><p>我们只需要敲一行命令，告诉Git，以后<code>st</code>就表示<code>status</code>：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git config --global alias.st status</span><br></pre></td></tr></table></figure><p>还有其他简写命令：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">$ git config --global alias.co checkout</span><br><span class="line">$ git config --global alias.ci commit</span><br><span class="line">$ git config --global alias.br branch</span><br></pre></td></tr></table></figure><p>以后提交就可以简写</p><blockquote><p><code>--global</code>参数是全局参数，也就是这些命令在这台电脑的所有Git仓库下都有用。</p></blockquote><h3 id="实用的别名配置"><a href="#实用的别名配置" class="headerlink" title="实用的别名配置"></a>实用的别名配置</h3><p>命令<code>git reset HEAD file</code>可以把暂存区的修改撤销掉（unstage），重新放回工作区。既然是一个unstage操作，就可以配置一个<code>unstage</code>别名：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git config --global alias.unstage <span class="string">&#x27;reset HEAD&#x27;</span></span><br></pre></td></tr></table></figure><p>当你敲入命令：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git unstage test.py</span><br></pre></td></tr></table></figure><p>实际上Git执行的是：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git reset HEAD test.py</span><br></pre></td></tr></table></figure><p>再者<br>配置一个<code>git last</code>，让其显示最后一次提交信息：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git config --global alias.last <span class="string">&#x27;log -1&#x27;</span></span><br></pre></td></tr></table></figure><p>这样，用<code>git last</code>就能显示最近一次的提交：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">git last</span><br><span class="line">commit adca45d317e6d8a4b23f9811c3d7b7f0f180bfe2</span><br><span class="line">Merge: bd6ae48 291bea8</span><br><span class="line">Author: Michael Liao &lt;askxuefeng@gmail.com&gt;</span><br><span class="line">Date:   Thu Aug 22 22:49:22 2013 +0800</span><br><span class="line"></span><br><span class="line">    merge &amp; fix hello.py</span><br></pre></td></tr></table></figure><p>可以丧心病狂地把<code>lg</code>配置成：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git config --global alias.lg <span class="string">&quot;log --color --graph --pretty=format:&#x27;%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)&lt;%an&gt;%Creset&#x27; --abbrev-commit&quot;</span></span><br></pre></td></tr></table></figure><p><img src="/../images/image-20250417005541162.png" alt="image-20250417005541162"></p><h3 id="配置文件"><a href="#配置文件" class="headerlink" title="配置文件"></a>配置文件</h3><p>配置Git的时候，加上<code>--global</code>是针对当前用户起作用的，如果不加，那只针对当前的仓库起作用。<br>配置文件放哪了？每个仓库的Git配置文件都放在<code>.git/config</code>文件中：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">cat</span> .git/config </span><br><span class="line">[core]</span><br><span class="line">repositoryformatversion = 0</span><br><span class="line">filemode = <span class="literal">true</span></span><br><span class="line">bare = <span class="literal">false</span></span><br><span class="line">logallrefupdates = <span class="literal">true</span></span><br><span class="line">ignorecase = <span class="literal">true</span></span><br><span class="line">precomposeunicode = <span class="literal">true</span></span><br><span class="line">[remote <span class="string">&quot;origin&quot;</span>]</span><br><span class="line">url = git@github.com:auberginewly/learngit.git</span><br><span class="line">fetch = +refs/heads/*:refs/remotes/origin/*</span><br><span class="line">[branch <span class="string">&quot;master&quot;</span>]</span><br><span class="line">remote = origin</span><br><span class="line">merge = refs/heads/master</span><br></pre></td></tr></table></figure><p>而当前用户的Git配置文件放在用户主目录下的一个隐藏文件<code>.gitconfig</code>中：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">cat</span> ~/.gitconfig</span><br><span class="line">[user]</span><br><span class="line">name = auberginewly</span><br><span class="line">email = xxxxxx@qq.com</span><br><span class="line">[color]</span><br><span class="line">ui = <span class="literal">true</span></span><br><span class="line">[<span class="built_in">alias</span>]</span><br><span class="line">lg = <span class="built_in">log</span> --color --graph --pretty=format:<span class="string">&#x27;%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)&lt;%an&gt;%Creset&#x27;</span> --abbrev-commit</span><br><span class="line">unstage = reset HEAD</span><br></pre></td></tr></table></figure><p>别名就在<code>[alias]</code>后面，要删除别名，直接把对应的行删掉即可。<br>配置别名也可以直接修改这个文件，如果改错了，可以删掉文件重新通过命令配置，或者直接删掉配置文件错误的那一行。</p><h2 id="搭建git服务器"><a href="#搭建git服务器" class="headerlink" title="搭建git服务器"></a>搭建git服务器</h2><p>参考：<a href="https://blog.csdn.net/qq_47553403/article/details/120596743">https://blog.csdn.net/qq_47553403/article/details/120596743</a><br>虽然但是还没用到（）</p><h1 id="GitGui——使用SourceTree"><a href="#GitGui——使用SourceTree" class="headerlink" title="GitGui——使用SourceTree"></a>GitGui——使用SourceTree</h1><p>&#x2F;&#x2F; 待更新 图形化操作</p><h1 id="一些总结"><a href="#一些总结" class="headerlink" title="一些总结"></a>一些总结</h1><p><img src="/../images/gitsheets.png" alt="gitsheets"></p>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;安装配置&quot;&gt;&lt;a href=&quot;#安装配置&quot; class=&quot;headerlink&quot; title=&quot;安装配置&quot;&gt;&lt;/a&gt;安装配置&lt;/h1&gt;&lt;ul&gt;
&lt;li&gt;安装git&lt;/li&gt;
&lt;/ul&gt;
&lt;figure class=&quot;highlight bash&quot;&gt;&lt;table&gt;&lt;</summary>
      
    
    
    
    <category term="学习笔记" scheme="https://auberginewly.site/categories/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/"/>
    
    
    <category term="CS" scheme="https://auberginewly.site/tags/CS/"/>
    
    <category term="GIT" scheme="https://auberginewly.site/tags/GIT/"/>
    
  </entry>
  
  <entry>
    <title>2025.4 第二周</title>
    <link href="https://auberginewly.site/2025/04/14/4_2025-4-week2/"/>
    <id>https://auberginewly.site/2025/04/14/4_2025-4-week2/</id>
    <published>2025-04-13T18:20:54.000Z</published>
    <updated>2025-04-28T09:06:19.140Z</updated>
    
    <content type="html"><![CDATA[<h1 id="周报的开始"><a href="#周报的开始" class="headerlink" title="周报的开始"></a>周报的开始</h1><p>一直很想找一个机会有可以周报的分享形式</p><p>直到现在</p><p><img src="/../images/image-20250414023739548.png" alt="image-20250414023739548"></p><p>这个点了终于把这想配的多年的博客给配的7788了</p><p>于是想了想 我可以写一点什么呢</p><h1 id="这一周干了什么"><a href="#这一周干了什么" class="headerlink" title="这一周干了什么"></a>这一周干了什么</h1><h2 id="在家园"><a href="#在家园" class="headerlink" title="在家园"></a>在家园</h2><p>作为春招进产品组的新人</p><p>第一个项目是hackathon的idea构想</p><p>然后就是调研、产品需求文档PRD、原型图figma</p><p>大致耗时4天</p><p>认识了几个研发佬 感觉团队做项目还是很有意思的</p><h2 id="大创"><a href="#大创" class="headerlink" title="大创"></a>大创</h2><p>写了市场分析和前景方向 并完成了初稿</p><h2 id="coding"><a href="#coding" class="headerlink" title="coding"></a>coding</h2><p>下了goland并想着怎么配下go环境版本切换之类的</p><ul><li><p>可以看看go的官方文档捏 这个土拨鼠好可爱ww</p></li><li><p><a href="https://go-lang.org.cn/doc/tutorial/">https://go-lang.org.cn/doc/tutorial/</a></p></li></ul><p>continue ai插件</p><p>github copilot学生包申请</p><p>后续有时间会去学习backend的</p><p>等我哇</p>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;周报的开始&quot;&gt;&lt;a href=&quot;#周报的开始&quot; class=&quot;headerlink&quot; title=&quot;周报的开始&quot;&gt;&lt;/a&gt;周报的开始&lt;/h1&gt;&lt;p&gt;一直很想找一个机会有可以周报的分享形式&lt;/p&gt;
&lt;p&gt;直到现在&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/../image</summary>
      
    
    
    
    <category term="周报" scheme="https://auberginewly.site/categories/%E5%91%A8%E6%8A%A5/"/>
    
    
    <category term="一些想法" scheme="https://auberginewly.site/tags/%E4%B8%80%E4%BA%9B%E6%83%B3%E6%B3%95/"/>
    
  </entry>
  
  <entry>
    <title>基础算法之排序</title>
    <link href="https://auberginewly.site/2025/04/13/3_Ordering_of_the_underlying_algorithms/"/>
    <id>https://auberginewly.site/2025/04/13/3_Ordering_of_the_underlying_algorithms/</id>
    <published>2025-04-12T18:55:31.000Z</published>
    <updated>2025-04-21T08:38:51.864Z</updated>
    
    <content type="html"><![CDATA[<h1 id="为什么要开始这个章节"><a href="#为什么要开始这个章节" class="headerlink" title="为什么要开始这个章节"></a>为什么要开始这个章节</h1><p>蓝桥杯捐款了，痛定思痛开始好好学算法，太丢脸了ww</p><p>跟着acwing的y神继续学！！！！！</p><p>加油加油www</p><h1 id="排序的本质理解"><a href="#排序的本质理解" class="headerlink" title="排序的本质理解"></a>排序的本质理解</h1><ul><li>快排：把两边切开分别排序，再切开递归，本质是分治</li></ul><h1 id="快速排序"><a href="#快速排序" class="headerlink" title="快速排序"></a>快速排序</h1><h2 id="代码"><a href="#代码" class="headerlink" title="代码"></a>代码</h2><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">def</span> <span class="title function_">quick_sort</span>(<span class="params">arr</span>): <span class="comment"># 定义快排的函数，输入为一个数组</span></span><br><span class="line">    <span class="keyword">if</span> <span class="built_in">len</span>(arr) &lt;= <span class="number">1</span>:</span><br><span class="line">        <span class="keyword">return</span> arr <span class="comment"># 判断输入的数组如果小于等于一个元素就返回本身不用排序</span></span><br><span class="line">    pivot = arr[ <span class="built_in">len</span>(arr) // <span class="number">2</span> ] <span class="comment"># 定义一个参照的元素povit为arr列表中间元素</span></span><br><span class="line">    left = [x <span class="keyword">for</span> x <span class="keyword">in</span> arr <span class="keyword">if</span> x &lt; pivot] <span class="comment"># left列表如果x比参照pivot小就把其输入到其中</span></span><br><span class="line">    middle = [x <span class="keyword">for</span> x <span class="keyword">in</span> arr <span class="keyword">if</span> x == pivot] <span class="comment"># middle就是pivot</span></span><br><span class="line">    right = [x <span class="keyword">for</span> x <span class="keyword">in</span> arr <span class="keyword">if</span> x &gt; pivot] <span class="comment"># right列表如果x比参照pivot大就把其输入到其中</span></span><br><span class="line">    <span class="keyword">return</span> quick_sort(left) + middle + quick_sort(right) <span class="comment"># 递归左右直到排序完全并返回</span></span><br><span class="line">    </span><br><span class="line">n = <span class="built_in">int</span>(<span class="built_in">input</span>()) <span class="comment"># 输入数组长度并转换为int</span></span><br><span class="line">arr = <span class="built_in">list</span>(<span class="built_in">map</span>(<span class="built_in">int</span>,<span class="built_in">input</span>().split())) <span class="comment"># 输入数组元素以空格分开并全部为int形成列表</span></span><br><span class="line"></span><br><span class="line">sorted_arr = quick_sort(arr) <span class="comment"># 把快排结果储存在sorted_arr当中</span></span><br><span class="line"><span class="built_in">print</span>(<span class="string">&quot; &quot;</span>.join(<span class="built_in">map</span>(<span class="built_in">str</span>,sorted_arr))) <span class="comment"># 以空格的形式输出字符串列表</span></span><br></pre></td></tr></table></figure><h2 id="一些python的用法更新"><a href="#一些python的用法更新" class="headerlink" title="一些python的用法更新"></a>一些python的用法更新</h2><ul><li><p>一些需要注意的用法</p><ul><li><p>列表推导式</p><p>好的，这个问题非常关键！让我们深入理解列表推导式的语法，特别是为什么 <code>for</code> 前面有一个 <code>x</code>。</p><h3 id="列表推导式的基本结构"><a href="#列表推导式的基本结构" class="headerlink" title="列表推导式的基本结构"></a>列表推导式的基本结构</h3><p>列表推导式的基本结构如下：</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">[expression <span class="keyword">for</span> item <span class="keyword">in</span> iterable <span class="keyword">if</span> condition]</span><br></pre></td></tr></table></figure><ul><li><strong><code>expression</code></strong>：这是你希望每个元素变成的样子，或者说是处理每个元素的结果。通常这是你想要生成的结果。</li><li><strong><code>item</code></strong>：这是迭代过程中的每个元素，代表你从 <code>iterable</code> 中获取的元素。</li><li><strong><code>iterable</code></strong>：这是你要遍历的对象，通常是一个列表、元组、字符串等。</li><li><strong><code>condition</code></strong>（可选）：这是一个过滤条件，只有满足这个条件的元素才会被包含在最终的列表中。</li></ul><h3 id="为什么第一个-for-前有一个-x？"><a href="#为什么第一个-for-前有一个-x？" class="headerlink" title="为什么第一个 for 前有一个 x？"></a>为什么第一个 <code>for</code> 前有一个 <code>x</code>？</h3><p>在你的代码中：</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">left = [x <span class="keyword">for</span> x <span class="keyword">in</span> arr <span class="keyword">if</span> x &lt; pivot]</span><br></pre></td></tr></table></figure><ul><li><strong>第一个 <code>x</code></strong> 是 <strong>表达式部分</strong>。它表示你希望列表推导式结果中的每个元素应该是什么。这里，<code>x</code> 代表你希望新列表中的每个元素直接是 <code>arr</code> 中小于 <code>pivot</code> 的元素。</li><li><strong><code>for x in arr</code></strong> 是 <strong>迭代部分</strong>，表示你要遍历 <code>arr</code> 中的每个元素，并将它们赋值给 <code>x</code> 。</li><li><strong><code>if x &lt; pivot</code></strong> 是 <strong>过滤条件部分</strong>，它表示你只想把那些小于 <code>pivot</code> 的元素放入新列表 <code>left</code>。</li></ul><h3 id="解释-x-for-x-in-arr-部分"><a href="#解释-x-for-x-in-arr-部分" class="headerlink" title="解释 x for x in arr 部分"></a>解释 <code>x for x in arr</code> 部分</h3><ul><li><code>for x in arr</code> 表示遍历 <code>arr</code> 数组中的每一个元素，并将当前的元素赋值给 <code>x</code>。这个 <code>x</code> 是一个 <strong>占位符</strong>，代表当前的元素。</li><li>在列表推导式中，<code>x</code> 会出现在 <strong><code>for</code> 语句前</strong>，它表示生成的新列表中每一个元素的值。换句话说，<strong><code>x</code> 是你要生成的新列表中的元素</strong>。</li></ul><h3 id="举个例子"><a href="#举个例子" class="headerlink" title="举个例子"></a>举个例子</h3><p>假设 <code>arr = [3, 6, 8, 10, 1, 2, 1]</code>，<code>pivot = 6</code>。执行这行代码时：</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">left = [x <span class="keyword">for</span> x <span class="keyword">in</span> arr <span class="keyword">if</span> x &lt; <span class="number">6</span>]</span><br></pre></td></tr></table></figure><p><strong>执行步骤</strong>：</p><ol><li><code>x</code> 会依次取 <code>arr</code> 中的每个元素：<ul><li><code>x = 3</code>，满足 <code>3 &lt; 6</code>，所以 <code>3</code> 被加入到 <code>left</code>。</li><li><code>x = 6</code>，不满足 <code>6 &lt; 6</code>，所以 <code>6</code> 不被加入。</li><li><code>x = 8</code>，不满足 <code>8 &lt; 6</code>，所以 <code>8</code> 不被加入。</li><li><code>x = 10</code>，不满足 <code>10 &lt; 6</code>，所以 <code>10</code> 不被加入。</li><li><code>x = 1</code>，满足 <code>1 &lt; 6</code>，所以 <code>1</code> 被加入到 <code>left</code>。</li><li><code>x = 2</code>，满足 <code>2 &lt; 6</code>，所以 <code>2</code> 被加入到 <code>left</code>。</li><li><code>x = 1</code>，满足 <code>1 &lt; 6</code>，所以 <code>1</code> 被加入到 <code>left</code>。</li></ul></li></ol><p>最终，<code>left</code> 变成了 <code>[3, 1, 2, 1]</code>。</p><h3 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h3><p>第一个 <code>x</code> 代表了我们想要生成的新列表中的元素。它位于 <code>for</code> 语句之前，因为它定义了列表推导式的“输出”，即新的列表中的元素是什么。而 <code>for x in arr</code> 则是指定我们遍历 <code>arr</code> 数组并从中选取元素 <code>x</code>。</p></li><li><p><code>list()</code> 函数</p><p>Python 中的 <code>list()</code> 也是一个内置函数，用于将其他可迭代对象（如元组、字符串、字典等）转换为列表。</p></li><li><p><code>join</code> 是 Python 字符串类型的一个方法，用于将 <strong>可迭代对象</strong>（如列表、元组、集合等）中的元素连接成一个字符串，并且你可以指定一个 <strong>分隔符</strong>，这个分隔符会插入到每两个元素之间。</p><h3 id="join-方法的基本语法："><a href="#join-方法的基本语法：" class="headerlink" title="join 方法的基本语法："></a><code>join</code> 方法的基本语法：</h3><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">separator.join(iterable)</span><br></pre></td></tr></table></figure><ul><li><strong><code>separator</code></strong>：指定连接符，即在每个元素之间插入的字符串。可以是任何字符串（例如空格、逗号、下划线等）。</li><li><strong><code>iterable</code></strong>：这是你想要连接的可迭代对象（如列表、元组、集合等）。它的元素通常需要是字符串类型，或者可以通过 <code>str()</code> 转换为字符串。</li></ul><h3 id="join-方法的工作原理："><a href="#join-方法的工作原理：" class="headerlink" title="join 方法的工作原理："></a><code>join</code> 方法的工作原理：</h3><ol><li><code>join</code> 方法将遍历 <code>iterable</code> 中的每个元素。</li><li>然后，它会将元素连接成一个字符串，每个元素之间使用指定的 <code>separator</code> 作为分隔符。</li><li>最终返回一个新的连接后的字符串。</li></ol><h3 id="示例："><a href="#示例：" class="headerlink" title="示例："></a>示例：</h3><ol><li><p><strong>基本使用：</strong><br>假设我们有一个字符串列表，想要将它们通过空格连接成一个字符串。</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">words = [<span class="string">&quot;Hello&quot;</span>, <span class="string">&quot;world&quot;</span>, <span class="string">&quot;Python&quot;</span>]</span><br><span class="line">result = <span class="string">&quot; &quot;</span>.join(words)</span><br><span class="line"><span class="built_in">print</span>(result)</span><br></pre></td></tr></table></figure><p>输出：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Hello world Python</span><br></pre></td></tr></table></figure><p>这里，<code>&quot; &quot;</code> 是分隔符，它将列表中的元素用空格连接起来。</p></li><li><p><strong>使用其他分隔符：</strong><br>你可以指定不同的分隔符，如逗号、下划线等。</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">words = [<span class="string">&quot;apple&quot;</span>, <span class="string">&quot;banana&quot;</span>, <span class="string">&quot;cherry&quot;</span>]</span><br><span class="line">result = <span class="string">&quot;, &quot;</span>.join(words)</span><br><span class="line"><span class="built_in">print</span>(result)</span><br></pre></td></tr></table></figure><p>输出：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">apple, banana, cherry</span><br></pre></td></tr></table></figure><p>这里，<code>&quot;, &quot;</code> 是分隔符，元素之间用逗号加空格连接。</p></li><li><p><strong>没有分隔符：</strong><br>如果你不想在元素之间添加任何分隔符，可以使用空字符串 <code>&quot;&quot;</code>。</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">words = [<span class="string">&quot;H&quot;</span>, <span class="string">&quot;e&quot;</span>, <span class="string">&quot;l&quot;</span>, <span class="string">&quot;l&quot;</span>, <span class="string">&quot;o&quot;</span>]</span><br><span class="line">result = <span class="string">&quot;&quot;</span>.join(words)</span><br><span class="line"><span class="built_in">print</span>(result)</span><br></pre></td></tr></table></figure><p>输出：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Hello</span><br></pre></td></tr></table></figure><p>这里，空字符串 <code>&quot;&quot;</code> 作为分隔符，将列表中的元素直接连接成一个没有空格的字符串。</p></li><li><p><strong>连接数字（需要转换为字符串）：</strong><br>如果列表中的元素是非字符串类型（例如数字），你需要将它们转换为字符串类型。可以使用 <code>map(str, iterable)</code> 来实现转换。</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">numbers = [<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>, <span class="number">4</span>]</span><br><span class="line">result = <span class="string">&quot;-&quot;</span>.join(<span class="built_in">map</span>(<span class="built_in">str</span>, numbers))</span><br><span class="line"><span class="built_in">print</span>(result)</span><br></pre></td></tr></table></figure><p>输出：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">1-2-3-4</span><br></pre></td></tr></table></figure><p>这里，<code>map(str, numbers)</code> 会将每个数字转换为字符串，然后再用 <code>&quot;-&quot;</code> 连接它们。</p></li><li><p><strong>处理空列表：</strong><br>如果列表是空的，<code>join</code> 方法会返回一个空字符串。</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">empty_list = []</span><br><span class="line">result = <span class="string">&quot; &quot;</span>.join(empty_list)</span><br><span class="line"><span class="built_in">print</span>(result)  <span class="comment"># 输出 &#x27;&#x27;</span></span><br></pre></td></tr></table></figure></li></ol><h3 id="总结："><a href="#总结：" class="headerlink" title="总结："></a>总结：</h3><ul><li><strong><code>join</code></strong> 方法是将一个可迭代对象中的元素连接成一个字符串，元素之间用指定的分隔符连接。</li><li>它的语法是：<code>separator.join(iterable)</code>，其中 <code>separator</code> 是你希望使用的连接符。</li><li><code>join</code> 适用于字符串类型的元素，若元素是其他类型（如数字），需要先将其转换为字符串。</li></ul><p>这个方法非常高效，尤其是当你需要连接大量字符串时，它比直接使用 <code>+</code> 更高效。</p></li><li><p>map 把字符串列表转换为整数</p></li><li><p>其他用法</p></li><li><p><code>map()</code> 是 Python 中的一个内置函数，用于 <strong>将一个函数应用到可迭代对象（如列表、元组等）中的每个元素</strong>，并返回一个迭代器，包含了应用函数后的结果。</p><h3 id="map-的基本语法："><a href="#map-的基本语法：" class="headerlink" title="map() 的基本语法："></a><code>map()</code> 的基本语法：</h3><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">map</span>(function, iterable, ...)</span><br></pre></td></tr></table></figure><ul><li><strong><code>function</code></strong>：一个函数，可以是内置的函数、lambda 表达式或用户定义的函数，表示你希望应用于每个元素的操作。</li><li><strong><code>iterable</code></strong>：一个可迭代对象（如列表、元组、字符串等），<code>map()</code> 会将 <code>function</code> 应用到其中的每个元素。</li><li>如果有多个可迭代对象作为参数，<code>map()</code> 会将它们一一配对，并将 <code>function</code> 应用到对应元素的组合上。</li></ul><h3 id="map-的工作流程："><a href="#map-的工作流程：" class="headerlink" title="map() 的工作流程："></a><code>map()</code> 的工作流程：</h3><ol><li><code>map()</code> 会将传入的 <code>function</code> 应用到 <code>iterable</code> 中的每一个元素。</li><li>它返回一个 <strong>迭代器</strong>，而不是直接返回一个列表（如果需要可以通过 <code>list()</code> 或 <code>tuple()</code> 等转换为具体的类型）。</li><li>你可以使用 <code>for</code> 循环或 <code>list()</code> 函数来遍历这个迭代器，获取每个元素的结果。</li></ol><h3 id="示例：-1"><a href="#示例：-1" class="headerlink" title="示例："></a>示例：</h3><ol><li><p><strong>简单的例子：</strong></p><p>假设我们有一个列表，想将其中的每个数字乘以 2。</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">numbers = [<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>, <span class="number">4</span>, <span class="number">5</span>]</span><br><span class="line">result = <span class="built_in">map</span>(<span class="keyword">lambda</span> x: x * <span class="number">2</span>, numbers)</span><br><span class="line"><span class="built_in">print</span>(<span class="built_in">list</span>(result))</span><br></pre></td></tr></table></figure><p>输出：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">[2, 4, 6, 8, 10]</span><br></pre></td></tr></table></figure><ul><li>这里，<code>lambda x: x * 2</code> 是一个匿名函数，表示对每个元素执行 <code>x * 2</code> 操作。</li><li><code>map()</code> 会将这个操作应用到 <code>numbers</code> 列表中的每个元素。</li><li>由于 <code>map()</code> 返回的是一个迭代器，我们使用 <code>list()</code> 将其转换为列表，并打印输出。</li></ul></li><li><p><strong>将字符串转换为数字：</strong></p><p>如果你有一个包含数字字符串的列表，想将它们转换为整数：</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">str_numbers = [<span class="string">&quot;1&quot;</span>, <span class="string">&quot;2&quot;</span>, <span class="string">&quot;3&quot;</span>, <span class="string">&quot;4&quot;</span>]</span><br><span class="line">result = <span class="built_in">map</span>(<span class="built_in">int</span>, str_numbers)</span><br><span class="line"><span class="built_in">print</span>(<span class="built_in">list</span>(result))</span><br></pre></td></tr></table></figure><p>输出：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">[1, 2, 3, 4]</span><br></pre></td></tr></table></figure><ul><li>这里，<code>int</code> 是一个内置函数，它将每个字符串转换为整数。</li><li><code>map(int, str_numbers)</code> 会把 <code>str_numbers</code> 列表中的每个字符串应用 <code>int</code> 函数，得到一个整数列表。</li></ul></li><li><p><strong>多个可迭代对象：</strong></p><p><code>map()</code> 也可以接受多个可迭代对象。如果传入多个可迭代对象，<code>map()</code> 会将它们的元素按位置进行配对，并将 <code>function</code> 应用于每一组元素。例如：</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">numbers1 = [<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>]</span><br><span class="line">numbers2 = [<span class="number">4</span>, <span class="number">5</span>, <span class="number">6</span>]</span><br><span class="line">result = <span class="built_in">map</span>(<span class="keyword">lambda</span> x, y: x + y, numbers1, numbers2)</span><br><span class="line"><span class="built_in">print</span>(<span class="built_in">list</span>(result))</span><br></pre></td></tr></table></figure><p>输出：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">[5, 7, 9]</span><br></pre></td></tr></table></figure><ul><li>这里，<code>map()</code> 会将 <code>numbers1</code> 和 <code>numbers2</code> 中对应位置的元素配对：<code>(1, 4)</code>, <code>(2, 5)</code>, <code>(3, 6)</code>，然后对每一对元素应用 <code>lambda x, y: x + y</code>，即将它们相加。</li></ul></li></ol><h3 id="map-返回的是一个迭代器"><a href="#map-返回的是一个迭代器" class="headerlink" title="map() 返回的是一个迭代器"></a><code>map()</code> 返回的是一个迭代器</h3><p>需要注意的是，<code>map()</code> 返回的是一个 <strong>迭代器</strong>，不是一个列表。因此，在使用时，我们通常需要用 <code>list()</code> 函数将其转换为列表，或者使用 <code>for</code> 循环来遍历。</p><h3 id="例子总结："><a href="#例子总结：" class="headerlink" title="例子总结："></a>例子总结：</h3><ol><li><p><strong>应用函数到每个元素：</strong></p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">numbers = [<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>]</span><br><span class="line">result = <span class="built_in">map</span>(<span class="keyword">lambda</span> x: x * <span class="number">2</span>, numbers)</span><br><span class="line"><span class="built_in">print</span>(<span class="built_in">list</span>(result))  <span class="comment"># 输出 [2, 4, 6]</span></span><br></pre></td></tr></table></figure></li><li><p><strong>将字符串转换为数字：</strong></p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">str_numbers = [<span class="string">&quot;10&quot;</span>, <span class="string">&quot;20&quot;</span>, <span class="string">&quot;30&quot;</span>]</span><br><span class="line">result = <span class="built_in">map</span>(<span class="built_in">int</span>, str_numbers)</span><br><span class="line"><span class="built_in">print</span>(<span class="built_in">list</span>(result))  <span class="comment"># 输出 [10, 20, 30]</span></span><br></pre></td></tr></table></figure></li><li><p><strong>多个可迭代对象：</strong></p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">nums1 = [<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>]</span><br><span class="line">nums2 = [<span class="number">4</span>, <span class="number">5</span>, <span class="number">6</span>]</span><br><span class="line">result = <span class="built_in">map</span>(<span class="keyword">lambda</span> x, y: x + y, nums1, nums2)</span><br><span class="line"><span class="built_in">print</span>(<span class="built_in">list</span>(result))  <span class="comment"># 输出 [5, 7, 9]</span></span><br></pre></td></tr></table></figure></li></ol><h3 id="总结：-1"><a href="#总结：-1" class="headerlink" title="总结："></a>总结：</h3><ul><li><code>map()</code> 是一个高效的函数式编程工具，能够将一个函数应用到多个元素上，并返回一个新的迭代器。</li><li>它通常用于将某种操作应用于一个或多个可迭代对象的每个元素，像是转换数据类型、数学运算等。</li><li>返回值是一个迭代器，你可以使用 <code>list()</code>、<code>tuple()</code> 或直接迭代它来获取结果。</li></ul><p>希望这个解释能帮你理解 <code>map()</code> 的使用！</p></li></ul></li></ul><h1 id="归并排序"><a href="#归并排序" class="headerlink" title="归并排序"></a>归并排序</h1>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;为什么要开始这个章节&quot;&gt;&lt;a href=&quot;#为什么要开始这个章节&quot; class=&quot;headerlink&quot; title=&quot;为什么要开始这个章节&quot;&gt;&lt;/a&gt;为什么要开始这个章节&lt;/h1&gt;&lt;p&gt;蓝桥杯捐款了，痛定思痛开始好好学算法，太丢脸了ww&lt;/p&gt;
&lt;p&gt;跟着acw</summary>
      
    
    
    
    <category term="学习笔记" scheme="https://auberginewly.site/categories/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/"/>
    
    
    <category term="算法" scheme="https://auberginewly.site/tags/%E7%AE%97%E6%B3%95/"/>
    
  </entry>
  
  <entry>
    <title>Mac利用homebrew进行多版本Go切换</title>
    <link href="https://auberginewly.site/2025/04/13/2_Mac_homebrew_Go_switch/"/>
    <id>https://auberginewly.site/2025/04/13/2_Mac_homebrew_Go_switch/</id>
    <published>2025-04-12T18:45:46.000Z</published>
    <updated>2025-04-21T08:38:44.534Z</updated>
    
    <content type="html"><![CDATA[<h1 id="管理go版本"><a href="#管理go版本" class="headerlink" title="管理go版本"></a>管理go版本</h1><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">go version <span class="comment"># 查看当前go版本</span></span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">brew install go@x.xx <span class="comment"># 安装指定版本go</span></span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">brew <span class="built_in">unlink</span> go <span class="comment"># 解除已有的链接</span></span><br></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">brew <span class="built_in">link</span> --force go@x.xx <span class="comment"># 建立到x.xx版本的新链接</span></span><br></pre></td></tr></table></figure><p>这样就可以用brew来切换go版本了</p><p>解决了喵</p>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;管理go版本&quot;&gt;&lt;a href=&quot;#管理go版本&quot; class=&quot;headerlink&quot; title=&quot;管理go版本&quot;&gt;&lt;/a&gt;管理go版本&lt;/h1&gt;&lt;figure class=&quot;highlight bash&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutt</summary>
      
    
    
    
    <category term="琐碎问题解决" scheme="https://auberginewly.site/categories/%E7%90%90%E7%A2%8E%E9%97%AE%E9%A2%98%E8%A7%A3%E5%86%B3/"/>
    
    
    <category term="CS" scheme="https://auberginewly.site/tags/CS/"/>
    
    <category term="GO" scheme="https://auberginewly.site/tags/GO/"/>
    
  </entry>
  
  <entry>
    <title>关于我</title>
    <link href="https://auberginewly.site/2025/04/04/1_about_me/"/>
    <id>https://auberginewly.site/2025/04/04/1_about_me/</id>
    <published>2025-04-04T11:39:13.000Z</published>
    <updated>2025-07-02T05:31:13.690Z</updated>
    
    <content type="html"><![CDATA[<h1 id="关于我"><a href="#关于我" class="headerlink" title="关于我"></a>关于我</h1><ul><li><p>某末2网安专业在读大一学生</p></li><li><p>在某学生工作室产品部门</p></li><li><p>上大学前没有接触过计算机</p></li><li><p>所了解的不多 但是会慢慢学习</p></li><li><p>高考发挥失常选手</p></li></ul><h1 id="关于博客"><a href="#关于博客" class="headerlink" title="关于博客"></a>关于博客</h1><ul><li>配置过三次</li><li>大一上hexo（失败）</li><li>寒假gridea（编辑限制）</li><li>大一下hexo<ul><li>主题首先是instapaer 但是代码行有限制</li><li>于是使用了butterfly</li><li>草率的配置了一下（）</li><li>后续待优化ing</li></ul></li></ul><h1 id="想要干的事情"><a href="#想要干的事情" class="headerlink" title="想要干的事情"></a>想要干的事情</h1><h2 id="关于专业"><a href="#关于专业" class="headerlink" title="关于专业"></a>关于专业</h2><ul><li>打过ctf 仅限于了解一些浅薄的misc 并没有坚持下去<ul><li>如果有机会可以继续ctf之旅</li></ul></li><li>以后不一定走网安方向（？<ul><li>或许吧，多摸索摸索</li></ul></li></ul><h2 id="关于选择"><a href="#关于选择" class="headerlink" title="关于选择"></a>关于选择</h2><ul><li>目前是想保研（maybe？</li><li>但是感觉不如就业啊（）</li><li>但是什么技术都不会 还得学习</li></ul><h2 id="关于想学习的"><a href="#关于想学习的" class="headerlink" title="关于想学习的"></a>关于想学习的</h2><ul><li>machinelearning<ul><li>kaggle（？</li></ul></li><li>stuck<ul><li>frontend</li><li>backend</li></ul></li><li>security<ul><li>？</li></ul></li><li>产品<ul><li><a href="https://www.woshipm.com/">https://www.woshipm.com</a></li></ul></li></ul><h1 id="碎碎念"><a href="#碎碎念" class="headerlink" title="碎碎念"></a>碎碎念</h1><ul><li>re:感觉时间过的好快啊，马上大二了还什么都不会</li><li>re:还是得把时间安排好不然老大徒伤悲哎哎</li></ul>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;关于我&quot;&gt;&lt;a href=&quot;#关于我&quot; class=&quot;headerlink&quot; title=&quot;关于我&quot;&gt;&lt;/a&gt;关于我&lt;/h1&gt;&lt;ul&gt;
&lt;li&gt;&lt;p&gt;某末2网安专业在读大一学生&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;在某学生工作室产品部门&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;</summary>
      
    
    
    
    <category term="想法" scheme="https://auberginewly.site/categories/%E6%83%B3%E6%B3%95/"/>
    
    
    <category term="一些想法" scheme="https://auberginewly.site/tags/%E4%B8%80%E4%BA%9B%E6%83%B3%E6%B3%95/"/>
    
  </entry>
  
</feed>
