{"action":"created","issue":{"url":"https://api.github.com/repos/Jisuanke/tech-exp/issues/13","repository_url":"https://api.github.com/repos/Jisuanke/tech-exp","labels_url":"https://api.github.com/repos/Jisuanke/tech-exp/issues/13/labels{/name}","comments_url":"https://api.github.com/repos/Jisuanke/tech-exp/issues/13/comments","events_url":"https://api.github.com/repos/Jisuanke/tech-exp/issues/13/events","html_url":"https://github.com/Jisuanke/tech-exp/issues/13","id":124997440,"number":13,"title":"如何优雅地合并多个 Commit","user":{"login":"JasinYip","id":7105264,"avatar_url":"https://avatars1.githubusercontent.com/u/7105264?v=3","gravatar_id":"","url":"https://api.github.com/users/JasinYip","html_url":"https://github.com/JasinYip","followers_url":"https://api.github.com/users/JasinYip/followers","following_url":"https://api.github.com/users/JasinYip/following{/other_user}","gists_url":"https://api.github.com/users/JasinYip/gists{/gist_id}","starred_url":"https://api.github.com/users/JasinYip/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/JasinYip/subscriptions","organizations_url":"https://api.github.com/users/JasinYip/orgs","repos_url":"https://api.github.com/users/JasinYip/repos","events_url":"https://api.github.com/users/JasinYip/events{/privacy}","received_events_url":"https://api.github.com/users/JasinYip/received_events","type":"User","site_admin":false},"labels":[{"id":200916916,"url":"https://api.github.com/repos/Jisuanke/tech-exp/labels/%E7%BB%8F%E9%AA%8C%E5%88%86%E4%BA%AB","name":"经验分享","color":"207de5","default":false}],"state":"open","locked":false,"assignee":null,"assignees":[],"milestone":null,"comments":0,"created_at":"2016-01-05T16:12:43Z","updated_at":"2017-06-15T09:19:31Z","closed_at":null,"body":"大家都知道 Git 是一种分布式的版本控制工具。正因为它有「分布式」这个特性，所以理论上我们其实可以不需要连接网络，就可以进行版本管理。然而，在实际上这是不可能的，因为你还需要上网查 Git 的 中种命令（逃\n\n---\n\n哈哈，玩笑开完，进入正题吧！\n\n我为什么要写这篇文章呢？因为实在太多同学跑来问我「**到底怎么合并 commit？**」了，每次都重复讲一遍这种做法完全不符合程序猿的风格啊！\n\n那么，就先让我们来看这么一个情况，我们执行以下命令获得四个 Commit：\n\n``` shell\nmkdir test\ncd test\n\ngit init\n\necho \"0\" >> a\ngit add a\ngit commit -m \"Commit-0\"\n\necho \"1\" >> a\ngit add a\ngit commit -m \"Commit-1\"\n\necho \"2\" >> a\ngit add a\ngit commit -m \"Commit-2\"\n\necho \"3\" >> a\ngit add a\ngit commit -m \"Commit-3\"\n```\n\n我们可以看到 Git 的历史长成这样：\n\n```\n* b1b8189 - (HEAD -> master) Commit-3\n* 5756e15 - Commit-2\n* e7ba81d - Commit-1\n* 5d39ff2 - Commit-0\n```\n\n那么问题来了，如何把 `e7ba81d(Commit-1)`、`5756e15(Commit-2)`、`b1b8189(Commit-3)` 合并到一起，并且只保留 `e7ba81d(Commit-1)` 的 Git message `Commit-1` 呢？\n\n这个时候我们就要祭出我们这篇文章的主角—— `git rebase -i` 了！\n_这里我不想直接搬出写文档的那套，把所有的选项都介绍完，我们就把这次要用到的讲一下。_\n\n`-i` 实际上就是 `--interactive` 的简写，在使用 `git rebase -i` 时，我们要在后面再添加一个参数，这个参数应该是 **最新的一个想保留的 Commit**。这句话读起来有点坳口，所以这个情况下通常需要举个例子。就我们前面提到的那个例子中，这个「最新的一个想保留的 Commit」就是 `5d39ff2(Commit-0)`，于是我们的命令看起来就长这样：\n\n``` shell\ngit rebase -i 5d39ff2\n```\n\n当然，我们也可以通过 `HEAD~3` 来指定该 Commit：\n\n``` shell\ngit rebase -i HEAD~3\n```\n\n按下回车后，我们会进入到这么一个界面：\n\n```\npick e7ba81d Commit-1\npick 5756e15 Commit-2\npick b1b8189 Commit-3\n\n# Rebase 5d39ff2..b1b8189 onto 5d39ff2 (3 command(s))\n#\n# Commands:\n# p, pick = use commit\n# r, reword = use commit, but edit the commit message\n# e, edit = use commit, but stop for amending\n# s, squash = use commit, but meld into previous commit\n# f, fixup = like \"squash\", but discard this commit's log message\n# x, exec = run command (the rest of the line) using shell\n#\n# These lines can be re-ordered; they are executed from top to bottom.\n#\n# If you remove a line here THAT COMMIT WILL BE LOST.\n#\n# However, if you remove everything, the rebase will be aborted.\n#\n# Note that empty commits are commented out\n```\n\n前面三行是我们需要操作的三个 Commit，每行最前面的是对该 Commit 操作的 Command。关于每个 Command 具体做什么，下面的注释写得非常清楚。为了完成我们的需求，我们可以关注到这两个命令：\n\n```\ns, squash = use commit, but meld into previous commit\nf, fixup = like \"squash\", but discard this commit's log message\n```\n\n为了让大家看得更明白，我不厌其烦地翻译一下：\n- `squash`：使用该 Commit，但会被合并到前一个 Commit 当中\n- `fixup`：就像 `squash` 那样，但会抛弃这个 Commit 的 Commit message\n\n看样子两个命令都可以完成我们的需求，那么让我们先试一下 `squash`！由于我们是想把三个 Commit 都合并在一起，并且使 Commit Message 写成 `Commit-1`，所以我们需要把 `5756e15(Commit-2)` 和 `b1b8189(Commit-3)` 前面的 `pick` 都改为`squash`，于是它看起来像这样：\n\n```\npick e7ba81d Commit-1\nsquash 5756e15 Commit-2\nsquash b1b8189 Commit-3\n```\n\n当然，因为我很懒，所以通常我会使用它的缩写：\n\n```\npick e7ba81d Commit-1\ns 5756e15 Commit-2\ns b1b8189 Commit-3\n```\n\n完成后，使用 `:wq` 保存并退出。这个时候，我们进入到了下一个界面：\n\n```\n# This is a combination of 3 commits.\n# The first commit's message is:\nCommit-1\n\n# This is the 2nd commit message:\n\nCommit-2\n\n# This is the 3rd commit message:\n\nCommit-3\n\n# Please enter the commit message for your changes. Lines starting\n# with '#' will be ignored, and an empty message aborts the commit.\n#\n# Date:      Tue Jan 5 23:27:22 2016 +0800\n#\n# rebase in progress; onto 5d39ff2\n# You are currently editing a commit while rebasing branch 'master' on '5d39ff2'.\n#\n# Changes to be committed:\n#   modified:   a\n```\n\n通过下面的注释，我们可以知道，这里其实就是一个编写 Commit Message 的界面，带 `#` 的行会被忽略掉，其余的行就会作为我们的新 Commit Message。为了完成我们的需求，我们修改成这样：\n\n```\nCommit-1\n\n# Please enter the commit message for your changes. Lines starting\n# with '#' will be ignored, and an empty message aborts the commit.\n#\n# Date:      Tue Jan 5 23:27:22 2016 +0800\n#\n# rebase in progress; onto 5d39ff2\n# You are currently editing a commit while rebasing branch 'master' on '5d39ff2'.\n#\n# Changes to be committed:\n#   modified:   a\n```\n\n使用 `:wq` 后，再看一下我们的 log：\n\n```\n* 2d7b687 - (HEAD -> master) Commit-1\n* 5d39ff2 - Commit-0\n```\n\n任务完成！\n\n---\n\n至于 `fixup` 怎么用，我觉得大家现在应该已经知道了，因为我已经展示过 `squash` 的用法了，相信你再去看一下上面的 `fixup` 的解释就能明白了。\n\n那么这篇文章就这样粗略地讲了一下 `git rebase -i` 的最基础的用法，希望能帮助到大家，有任何问题可以直接在评论里问我吧~\n"},"comment":{"url":"https://api.github.com/repos/Jisuanke/tech-exp/issues/comments/308677077","html_url":"https://github.com/Jisuanke/tech-exp/issues/13#issuecomment-308677077","issue_url":"https://api.github.com/repos/Jisuanke/tech-exp/issues/13","id":308677077,"user":{"login":"jaysimon","id":14191159,"avatar_url":"https://avatars3.githubusercontent.com/u/14191159?v=3","gravatar_id":"","url":"https://api.github.com/users/jaysimon","html_url":"https://github.com/jaysimon","followers_url":"https://api.github.com/users/jaysimon/followers","following_url":"https://api.github.com/users/jaysimon/following{/other_user}","gists_url":"https://api.github.com/users/jaysimon/gists{/gist_id}","starred_url":"https://api.github.com/users/jaysimon/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jaysimon/subscriptions","organizations_url":"https://api.github.com/users/jaysimon/orgs","repos_url":"https://api.github.com/users/jaysimon/repos","events_url":"https://api.github.com/users/jaysimon/events{/privacy}","received_events_url":"https://api.github.com/users/jaysimon/received_events","type":"User","site_admin":false},"created_at":"2017-06-15T09:19:31Z","updated_at":"2017-06-15T09:19:31Z","body":"Q:最好能说明一下最后的a文件时什么样的状态，处在commit 几的状态"}}
{"actor":{"display_login":"jaysimon"}}