1. 程式人生 > >Git 實用操作:撤銷 Commit 提交

Git 實用操作:撤銷 Commit 提交

有的時候,改完程式碼提交 commit 後發現寫得實在太爛了,連自己的都看不下去,與其修改它還不如丟棄重寫。怎麼操作呢? ## 使用 reset 撤銷 如果是最近提交的 commit 要丟棄重寫可以用 `reset` 來操作。比如你剛寫了一個 commit: ![](https://img2020.cnblogs.com/blog/191097/202009/191097-20200910092533145-695768189.gif) 寫完回頭看了看,你覺得不行這得重新寫。那麼你可以用 `reset --hard` 來撤銷這條 commit。 ```shell git reset --hard HEAD^ ``` HEAD^ 表示往回數一個位置的 commit`,上篇剛說過。 因為你要撤銷最新的一個 commit,所以你需要恢復到它的父 commit ,也就是 `HEAD^`。那麼在這行之後,你要丟棄的最新一條就被撤銷了: ![](https://img2020.cnblogs.com/blog/191097/202009/191097-20200910092549144-344639557.gif) 不過,就像圖上顯示的,你被撤銷的那條提交併沒有消失,只是你不再用到它了。如果你在撤銷它之前記下了它的 SHA-1 碼,那麼你還可以通過 SHA-1 來找到他它。 ## 使用 rebase -i 撤銷 假如有一個 commit,你在剛把它寫完的時候並沒有覺得它不好,可是在之後又寫了幾個提交以後,你突然靈光一現:哎呀,那個 commit 不該寫,我要撤銷! 不是最新的提交,就不能用 `reset --hard` 來撤銷了。這種情況的撤銷,就要用之前介紹過的一個指令互動式變基:`rebase -i`。 之前介紹過,互動式變基可以用來修改某些舊的 commit。其實除了修改提交,它還可以用於撤銷提交。比如下面這種情況: ![](https://img2020.cnblogs.com/blog/191097/202009/191097-20200910092603126-1202224802.jpg) 你想撤銷倒數第二條 commit,那麼可以使用 `rebase -i`: ```shell git rebase -i HEAD^^ ``` Git 引導到選擇要操作的 commit 頁面: ```bash pick 310154e 第 N-2 次提交 pick a5f4a0d 第 N-1 次提交 # Rebase 710f0f8..a5f4a0d onto 710f0f8 # # Commands: # p, pick = use commit # r, reword = use commit, but edit the commit message # e, edit = use commit, but stop for amending # s, squash = use commit, but meld into previous commit # f, fixup = like "squash", but discard this commit's log message # x, exec = run command (the rest of the line) using shell # b, break = stop here (continue rebase later with 'git rebase --continue') # d, drop = remove commit ... ``` 在上篇中,講到要修改哪個 commit 就把哪個 commit 前面的 `pick` 改成 `edit`。而如果你要撤銷某個 commit ,做法就更加簡單粗暴一點:直接刪掉這一行就好(使用 `d` 命令)。 ```bash pick a5f4a0d 第 N-1 次提交 # Rebase 710f0f8..a5f4a0d onto 710f0f8 # # Commands: # p, pick = use commit # r, reword = use commit, but edit the commit message # e, edit = use commit, but stop for amending # s, squash = use commit, but meld into previous commit # f, fixup = like "squash", but discard this commit's log message # x, exec = run command (the rest of the line) using shell # b, break = stop here (continue rebase later with 'git rebase --continue') # d, drop = remove commit ... ``` 把這一行刪掉就相當於在 rebase 的過程中跳過了這個 commit,從而也就把這個 commit 丟棄了。 ![](https://img2020.cnblogs.com/blog/191097/202009/191097-20200910092622138-779754005.gif) 如果你通過 `git log` 檢視,就會發現之前的倒數第二條 commit 已經不在了。 ## 使用用 rebase --onto 撤銷 除了用互動式 rebase,你還可以用 `rebase --onto` 來更簡便地撤銷提交。 rebase 加上 `--onto` 選項之後,可以指定 rebase 的「起點」。一般的 rebase, 的「起點」是自動選取的,選取的是當前 commit 和目標 commit 在歷史上的交叉點。 例如下面這種情況: ![](https://img2020.cnblogs.com/blog/191097/202009/191097-20200910092634974-2046959811.jpg) 如果在這裡執行: ```shell git rebase 第3個commit ``` 那麼 Git 會自動選取 `3` 和 `5` 的歷史交叉點 `2` 作為 rebase 的起點,依次將 `4` 和 `5` 重新提交到 `3` 的路徑上去。 而 `--onto` 引數,就可以額外給 rebase 指定它的起點。例如同樣以上圖為例,如果我只想把 `5` 提交到 `3` 上,不想附帶上 `4`,那麼我可以執行: ```shell git rebase --onto 第3個commit 第4個commit branch1 ``` 選項 `--onto` 引數後面有三個附加引數:目標 commit、起點 commit(注意:rebase 的時候會把起點排除在外)、終點 commit。所以上面這行指令就會從 `4` 往下數,拿到 `branch1` 所指向的 `5`,然後把 `5` 重新提交到 `3` 上去。 ![](https://img2020.cnblogs.com/blog/191097/202009/191097-20200910092645804-1468481916.gif) 同樣的,你也可以用 `rebase --onto` 來撤銷提交: ```shell git rebase --onto HEAD^^ HEAD^ branch1 ``` 上面這行程式碼的意思是:以倒數第二個 commit 為起點(起點不包含在 rebase 序列裡),`branch1` 為終點,rebase 到倒數第三個 commit 上。 也就是這樣: ![](https://img2020.cnblogs.com/blog/191097/202009/191097-20200910092656287-140128602.gif) ## 總結 撤銷最近一次的 commit 直接使用 `reset --hard`,撤銷過往歷史提交。方法有兩種: 1. 用 `git rebase -i` 在編輯介面中刪除想撤銷的 commit 2. 用 `git rebase --onto` 在 rebase 命令中直接剔除想撤銷的 commit 這有兩種理念是一樣的,即在 rebase 的過程中去掉想撤銷的 commit,讓它消失在歷