<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>版本控制 on Leanku 的博客</title><link>https://www.leanku.com/tags/%E7%89%88%E6%9C%AC%E6%8E%A7%E5%88%B6/</link><description>Recent content in 版本控制 on Leanku 的博客</description><generator>Hugo</generator><language>zh-cn</language><lastBuildDate>Mon, 17 Apr 2023 00:00:00 +0000</lastBuildDate><atom:link href="https://www.leanku.com/tags/%E7%89%88%E6%9C%AC%E6%8E%A7%E5%88%B6/index.xml" rel="self" type="application/rss+xml"/><item><title>Git 撤销与恢复实战：Reset、Restore、Revert、Stash 与 Reflog</title><link>https://www.leanku.com/post/devops/git-reset-restore-revert-stash-reflog/</link><pubDate>Mon, 17 Apr 2023 00:00:00 +0000</pubDate><guid>https://www.leanku.com/post/devops/git-reset-restore-revert-stash-reflog/</guid><description>&lt;p&gt;Git 开发过程中最常见的问题之一就是「改错了怎么办」。&lt;/p&gt;&#10;&lt;p&gt;代码还没有提交，想撤销修改；已经 &lt;code&gt;commit&lt;/code&gt;，想重新整理；代码已经推送到远程仓库，想安全撤销；临时需要切换分支，但当前代码又不想提交；甚至执行了一次 &lt;code&gt;reset --hard&lt;/code&gt; 后发现重要 Commit 不见了。&lt;/p&gt;&#10;&lt;p&gt;这些问题看起来都是「撤销」，但对应的 Git 操作完全不同。&lt;/p&gt;&#10;&lt;p&gt;Git 官方将 &lt;code&gt;reset&lt;/code&gt;、&lt;code&gt;restore&lt;/code&gt; 和 &lt;code&gt;revert&lt;/code&gt; 明确区分为三个不同的命令：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&#10;&lt;p&gt;&lt;code&gt;restore&lt;/code&gt; 主要恢复工作区或暂存区中的文件。&lt;/p&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&#10;&lt;p&gt;&lt;code&gt;reset&lt;/code&gt; 可以移动当前分支的 &lt;code&gt;HEAD&lt;/code&gt;，因此会改变当前分支历史。&lt;/p&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&#10;&lt;p&gt;&lt;code&gt;revert&lt;/code&gt; 不删除原来的 Commit，而是创建新的 Commit 来抵消之前的修改。&lt;/p&gt;&#10;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;再结合 &lt;code&gt;stash&lt;/code&gt; 和 &lt;code&gt;reflog&lt;/code&gt;，基本可以覆盖日常开发中绝大多数「撤销与恢复」场景。&lt;/p&gt;&#10;&lt;h2 id="先建立一个判断标准"&gt;先建立一个判断标准&lt;/h2&gt;&#10;&lt;p&gt;遇到问题时，不要第一时间执行：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git reset --hard&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;先判断当前代码处于什么状态。&lt;/p&gt;&#10;&lt;p&gt;可以把常见场景整理成下面这张表：&lt;/p&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;场景&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;推荐操作&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;修改了文件，但还没有 &lt;code&gt;add&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;git restore&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;已经 &lt;code&gt;add&lt;/code&gt;，想取消暂存&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;git restore --staged&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;已经 Commit，想修改最近一次提交&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;git commit --amend&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;本地 Commit 想回退&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;git reset&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;已经推送的 Commit 想撤销&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;git revert&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;临时保存当前未完成代码&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;git stash&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;reset --hard&lt;/code&gt; 后发现 Commit 不见了&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;git reflog&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;误删本地分支&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;git reflog&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;p&gt;理解这张表，比记住几十个 Git 参数更重要。&lt;/p&gt;</description></item><item><title>Git 实战：分支、Merge、Rebase 与冲突解决</title><link>https://www.leanku.com/post/devops/git-branch-merge-rebase-conflict/</link><pubDate>Sun, 16 Apr 2023 00:00:00 +0000</pubDate><guid>https://www.leanku.com/post/devops/git-branch-merge-rebase-conflict/</guid><description>&lt;p&gt;Git 真正难的地方并不是记住几个命令，而是理解「分支为什么存在」「Merge 和 Rebase 到底有什么区别」以及「出现冲突以后应该怎么处理」。&lt;/p&gt;&#10;&lt;p&gt;日常开发中，一个项目通常同时存在多个功能开发、Bug 修复和版本发布任务。如果所有人都直接修改同一个分支，很快就会出现代码互相覆盖、提交历史混乱以及难以追踪的问题。&lt;/p&gt;&#10;&lt;p&gt;Git 的分支机制解决了这个问题。开发者可以从主分支创建独立分支，在自己的分支上完成开发，然后通过 Merge 或 Rebase 将代码重新整合到目标分支。&lt;/p&gt;&#10;&lt;p&gt;本文不从 Git 的基础命令开始，而是直接从实际开发流程理解 Git 分支、Merge、Rebase 和冲突处理。&lt;/p&gt;&#10;&lt;h2 id="git-分支到底是什么"&gt;Git 分支到底是什么&lt;/h2&gt;&#10;&lt;p&gt;Git 中的分支本质上是指向某个 Commit 的引用。&lt;/p&gt;&#10;&lt;p&gt;例如项目最开始只有一条 &lt;code&gt;main&lt;/code&gt;：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;A --- B --- C&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ↑&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; main&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;开发新功能时创建 &lt;code&gt;feature/login&lt;/code&gt;：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;A --- B --- C&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ↑&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; main&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ↑&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; feature/login&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;继续开发后：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;A --- B --- C --- D --- E&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ↑ ↑&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; main feature/login&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;此时 &lt;code&gt;main&lt;/code&gt; 并没有发生变化，&lt;code&gt;feature/login&lt;/code&gt; 在自己的提交历史上继续向前发展。&lt;/p&gt;</description></item></channel></rss>