{"componentChunkName":"component---src-templates-blog-post-js","path":"/git/","result":{"data":{"site":{"siteMetadata":{"title":"😏","author":"thoamsy"}},"markdownRemark":{"id":"096abcb3-34c3-5285-954e-c86d6f5297f4","html":"<p>因为 Git 的操作实在太多，但是有些操作在很多时候又很重要，所以写一篇文章记录一下那些容易被忽略, 又较为常用的命令。</p>\n<p><strong>git 是饭桶的意思，因为 Linus 的自嘲</strong></p>\n<h2 id=\"git-init\" style=\"position:relative;\"><a href=\"#git-init\" aria-label=\"git init permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>git init</h2>\n<p><code class=\"language-text\">git init [directory]</code>：指定文件夹创建，这样就不需要先 <code class=\"language-text\">cd</code> 再 <code class=\"language-text\">git init</code></p>\n<p><code class=\"language-text\">git init --bare</code>: 创建一个只能做查看记录，拉代码，不能编辑的 git 工作区，一般用于发布分支，或者一个中心化的仓库。如果观察这个文件夹的结构的话，会发现，它们直接将 <code class=\"language-text\">.git</code> 文件夹的内容，<strong>平铺开来</strong>，放置于根目录。</p>\n<h2 id=\"git-clone\" style=\"position:relative;\"><a href=\"#git-clone\" aria-label=\"git clone permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>git clone</h2>\n<p><code class=\"language-text\">git clone --depth=1 repo</code> 可以指定 clone 下来的仓库的提交数。对于临时改一些代码，不关心历史提交的情况下，这个命令大大减少了 clone 的时间</p>\n<p><code class=\"language-text\">git clone --branch=foo repo</code> 只拉取某一个分支。如果想学习开源项目，只关心 master 下的记录，这个命令是个不错的选择。</p>\n<h2 id=\"git-config\" style=\"position:relative;\"><a href=\"#git-config\" aria-label=\"git config permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>git config</h2>\n<p>这里需要关注的命令不多，有一个值得注意的概念：<code class=\"language-text\">git config --global</code> 会将配置存与 <code class=\"language-text\">~/.gitconfig</code> 路径下，而默认操作(—local) 将配置保存在 <code class=\"language-text\">./.git/config</code> 下</p>\n<p><code class=\"language-text\">git config --global alias.[xxx] yyy</code> 这个命令可以通过输入 <code class=\"language-text\">git xxx</code> 来取代 <code class=\"language-text\">git yyy</code>。</p>\n<h2 id=\"git-add\" style=\"position:relative;\"><a href=\"#git-add\" aria-label=\"git add permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>git add</h2>\n<p><code class=\"language-text\">git add --all</code> 将所有的改动全部添加到缓存区， 包括没有被 tracked 的</p>\n<p><code class=\"language-text\">git add -i</code> 一个交互式的添加操作，不是那么的常用。而且子命令太多了，完全搞不懂是干嘛的</p>\n<h2 id=\"git-commit\" style=\"position:relative;\"><a href=\"#git-commit\" aria-label=\"git commit permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>git commit</h2>\n<p><code class=\"language-text\">git commit --amend</code>, 用于修改上一次的提交记录（类似于 <code class=\"language-text\">git rebase -i</code> 的子功能）。不过需要注意的是，因为这个会修改 commit 的 SHA.</p>\n<p>如果之前改动之前已经将 repo 推到了 remote repo，就必须要先 <code class=\"language-text\">git pull</code> 然后再 <code class=\"language-text\">git push</code>, 这样反而拜拜增加了两个没用的 commit log. 除非远程仓库没有开启<em>分支保护</em>功能，这样就可以使用 <code class=\"language-text\">git push -f</code> 来覆盖远程分支。在使用 -f 的时候，请保证这个分支没有其他人同时在修改。</p>\n<h2 id=\"git-stash\" style=\"position:relative;\"><a href=\"#git-stash\" aria-label=\"git stash permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>git stash</h2>\n<p>算是切分支神器。工作中我经常遇到手头在解决某个事情的时候，突然碰到突如其来的情况需要紧急处理，但是手头上的工作又不适合做一个 commit 的话，就可以用到这个它。</p>\n<p><code class=\"language-text\">git stash apply</code> 相比 <code class=\"language-text\">git stash pop</code> 的区别是，它再使用后仍然会存在于 <code class=\"language-text\">stash list</code> 中，可以用于其他的分支。就有点像 Stack 中，直接取 Stack Top 和 Pop 后取返回值的区别。</p>\n<p><code class=\"language-text\">git stash</code> 只会 stash 被 <em>tracked or added</em> 的文件。可以使用 <code class=\"language-text\">git stash -u</code> 将未被 track 的文件。<code class=\"language-text\">git stash -a</code> 会添加当前被修改的所有的文件，包括在 ignore 下的。</p>\n<p><code class=\"language-text\">git stash save [message]</code> 和直接 stash 不同，如果直接使用 <code class=\"language-text\">git stash</code> ，这次 stash 的名字会直接以当前最新的提交的 title 来命名。这样可能会有些困惑，因为并没有描述清楚这个 stash 到底做了什么。这在一段时间后，可能就懵逼咯。所以可以使用这个命令添加描述性的标题</p>\n<p><code class=\"language-text\">git stash pop [index]</code> 添加 index 就不需要按照 stack 的顺序来选择 stash。而 index 的值可以对应 <code class=\"language-text\">git stash list</code> 下的 <em>stash@{n}</em></p>\n<p><code class=\"language-text\">git shash show [-p] [index]</code> 仅仅看到列表还不够，还需要看到某个 stash 到底改变了什么。就可以使用这个命令，其他添加 -p 选项，可以获得和 git diff 一样更为全面的信息。</p>\n<p><code class=\"language-text\">git stash -p</code> 这个命令和 <code class=\"language-text\">git stash -p</code> 很像，很针对每一个文件的每一个 chunk 来提问，是否需要被 stash。算是为完美主义者准备的工具吧，无聊的时候可以试一下，反正我是头晕。</p>\n<p><span\n      class=\"gatsby-resp-image-wrapper\"\n      style=\"position: relative; display: block; margin-left: auto; margin-right: auto;  max-width: 800px;\"\n    >\n      <a\n    class=\"gatsby-resp-image-link\"\n    href=\"/static/eb4e4ce53ad8ec1c9ced561cd3b1279e/f4281/stash-p.png\"\n    style=\"display: block\"\n    target=\"_blank\"\n    rel=\"noopener\"\n  >\n    <span\n    class=\"gatsby-resp-image-background-image\"\n    style=\"padding-bottom: 43.99999999999999%; position: relative; bottom: 0; left: 0; background-image: url('data:image/svg+xml,%3csvg%20xmlns=\\'http://www.w3.org/2000/svg\\'%20width=\\'400\\'%20height=\\'176\\'/%3e'); background-size: cover; display: block;\"\n  ></span>\n  <picture>\n        <source\n          data-srcset=\"/static/eb4e4ce53ad8ec1c9ced561cd3b1279e/ba381/stash-p.webp 200w,\n/static/eb4e4ce53ad8ec1c9ced561cd3b1279e/7f61c/stash-p.webp 400w,\n/static/eb4e4ce53ad8ec1c9ced561cd3b1279e/d00b9/stash-p.webp 800w,\n/static/eb4e4ce53ad8ec1c9ced561cd3b1279e/adbc1/stash-p.webp 1016w\"\n          sizes=\"(max-width: 800px) 100vw, 800px\"\n          type=\"image/webp\"\n        />\n        <source\n          srcset=\"/static/eb4e4ce53ad8ec1c9ced561cd3b1279e/772e8/stash-p.png 200w,\n/static/eb4e4ce53ad8ec1c9ced561cd3b1279e/e17e5/stash-p.png 400w,\n/static/eb4e4ce53ad8ec1c9ced561cd3b1279e/5a190/stash-p.png 800w,\n/static/eb4e4ce53ad8ec1c9ced561cd3b1279e/f4281/stash-p.png 1016w\"\n          sizes=\"(max-width: 800px) 100vw, 800px\"\n          type=\"image/png\"\n        />\n        <img\n          class=\"gatsby-resp-image-image lazyload\"\n          data-src=\"/static/eb4e4ce53ad8ec1c9ced561cd3b1279e/5a190/stash-p.png\"\n          alt=\"stash p\"\n          title=\"stash p\"\n          loading=\"lazy\"\n          style=\"width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;\"\n        />\n      </picture>\n  </a>\n    </span></p>\n<p><code class=\"language-text\">git stash branch &lt;branch-name&gt; [stash]</code> 为了防止有些时候一旦 pop 了某个 stash，导致冲突的话，可以通过将这个 stash 应用在一个新的分支来缓解问题。</p>\n<h2 id=\"git-log\" style=\"position:relative;\"><a href=\"#git-log\" aria-label=\"git log permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>git log</h2>\n<p><code class=\"language-text\">git log --stat</code> 用于显示某次 commit，针对一个文件行数的增加和减少，文件名的修改情况。\n<code class=\"language-text\">git log -p</code> 会显示某次 commit 的 diff 状态\n<code class=\"language-text\">git log --author=&lt;name&gt;</code> 快速过滤某个 author 的提交次数\n<code class=\"language-text\">git log -n&lt;count&gt;</code> 显示最近 count 个提交</p>\n<h2 id=\"git-tag\" style=\"position:relative;\"><a href=\"#git-tag\" aria-label=\"git tag permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>git tag</h2>\n<p>Git 中有两种 tag：<em>annotated and lightweight tags</em>\n前者会包括一些注释信息，来进一步解释这个 tag 的作用，而后者就仅仅只是一个 tag 的名字。</p>\n<p><code class=\"language-text\">git tag &lt;name&gt;</code> 会创建一个 lightweight tag</p>\n<p><code class=\"language-text\">git tag -a &lt;name&gt;</code> 则会创建一个 annotated tag，之后会弹出 git 默认的编辑器，用于描述注释</p>\n<p><code class=\"language-text\">git tag list -l &lt;pattern&gt;</code> 通过 pattern 过滤 tag list</p>\n<p><code class=\"language-text\">git tag -d &lt;tagname&gt;</code> 删除 tag</p>\n<p><code class=\"language-text\">git tag -f [other]</code> replace 一个 tag 以其相关信息</p>\n<p>同时，还可以 checkout 某个 tag，但这其实相当于跳转到创建该 tag 的 commit 上，进入 <em>detached HEAD state</em>。这个时候最好不要修改代码，或者先创建新分支</p>","frontmatter":{"title":"The Junior Git","spoiler":null,"image":null,"date":"2018/08/12"}}},"pageContext":{"slug":"/git/","previous":{"fields":{"slug":"/vscode/"},"frontmatter":{"title":"使用 VSCode 搭建一个很爽的前端环境","image":null,"spoiler":null}},"next":{"fields":{"slug":"/browser/"},"frontmatter":{"title":"Inside look at modern web browser（翻译）","image":null,"spoiler":"谷歌搬砖"}}}}}