提交記錄我們的工作歷史記錄,提交自身是一成不變的。Git提供了幾個工具和命令,抓門用來幫助修改完善版本庫中的提交。
實際工作中存在很多情況需要我們去修改或返工某個提交或者整個提交序列:
1,可以在某個問題變為遺留問題之前修復它;
2,可以大而全面的變更分解為一系列小而專的提交;
3,刪除以外提交的調試代碼;
4,在不破壞構建需求的情況下重新排列提交序列;
5,可以將提交調整為一個更合乎邏輯的序列;
一般而言,如果能讓提交更簡潔和利於理解,應該區更改提交或提交序列。
作為一般原則,只要沒有其他協同工作人員已經獲取了你的版本庫的副本,你就可以自由地修改或完善版本庫中的提交歷史。
換言之,只要沒人有版本庫中某個分支的副本,你就可以修改該分支。如果一個分支已經公開了,並且可能已經存在於其他版本庫中了,那就不應該退歷史提交進行修改。
使用 git reset 命令
git reset 命令會調整 HEAD 引用指向給定的提交。默認情況下還會 更新暫存區 以匹配給定的提交。
根據需要,git reset 命令也可以 修改工作區 以呈現給定提交代表的項目修訂版本。
git reset 命令是具有”破壞性的“,它可以覆蓋並銷毀 工作區 的修改。然而,此命令的重點為 HEAD,暫存區 和 工作區 建立與恢復狀態。
git reste 命令有三個主要選項:--soft,--mixed 和 --hard。
git reset--soft [commit]
--soft 選項會將 HEAD 引用指向給定的commit。暫存區 和 工作區 的內容保存不變。
git reset --mixed [commit]
--mixed 是默認選項,會將 HEAD 指向給定的commit,暫存區 會跟着改變以符合給定commit的目錄樹(tree)。但是 工作區 的內容保持不變。
git reset --hard [commit]
--hard 選項會將 HEAD 引用指向給定的commit,暫存區 會跟着改變以符合給定commit的目錄樹(tree),並且,工作去 也會跟着改變以反映給定提交標識的目錄樹(tree)。
git reset 選項的影響范圍
選項 | HEAD | 暫存區 | 工作區 |
--soft | 是 | 否 | 否 |
--mixed | 是 | 是 | 否 |
--hard | 是 | 是 | 是 |
使用 git revert 命令
該命令用於 引入一個新的提交 來抵消指定提交的影響。git revert 命令不會修改版本庫中現存的歷史記錄。相反,它會往歷史記錄中添加新的提交。
git revert 最常見的用途是“撤銷”可能深埋在歷史記錄中的某個提交的影響。如下圖中,在 master 分支上,出於某種原因,提交 D 被視為有缺陷的:
一個簡單的方法是執行 git revert 命令。git revert master~3 #commit D,下標從0開始。
其中提交 D' 是提交 D 的逆轉。
reset,revert 和 checkout 的困惑!
三條Git命令 reset,revert,checkout 的確很讓人困惑,因為它們都執似乎類型的操作。
不過,也有一些很好的指引和規則,指明每條命令應在何時使用。
1,如果你相切換到不同的分支,使用 git checkout。當前分支 和 HEAD 引用都會變為匹配給定分支的頭。
2,git reset 命令不會改變分支,它只會重置當前分支的 HEAD 引用,並且有可能會改變 暫存區 和 工作區的狀態。
3,git revert 命令作用於全部提交,而不是文件。如果其他的協同工作的人員已經克隆的你的版本庫或者獲取了一些提交,那么修改提交歷史記錄就有很多影響。在這種情況下,不應該使用修改版本庫中歷史記錄的命令。相反,應該使用 git revert 命令。
修改最新提交
改變當前分支的最近一次提交的最簡單方法之一是使用 git commit --amend。該命令會彈出編輯器會話,可以在里面修改提交信息,甚至是元信息(--author 可以改變提交的作者)。
使用 git commit --amend 來修改最近提交的效果會是下面的兩張圖片所顯示的效果:
提交 C 的實質依然是相同的,但它已經被修改成 C' 。HEAD 引用已經從舊的提交 C 指向替代的引用 C' 。
變基提交
git rebase 命令用來改變一串提交是以什么為基礎的。此命令至少需要提交將遷往的分支名。默認情況下,不在目標分支中的當前分支提交會變基。
說白了,就是改變一個分支的起始分支基點。它最常用的作用就是“保持我們正在開發的一系列提交相對於另一個分支是最新的,那通常是 master 分支或者來自另一個版本庫的追蹤分支”。
例如下面圖片的示例:有兩個分支正在開發。最初,分支 topic 是從 master 分支 的提交 B 處開始的。但是一段時間后 master 分支已經進展到了提交 E。
可以改寫提交讓分支 topic 基於最新的提交 E 而不是 提交 B。可以這樣來操作:
git checkout topic #檢出topic分支
git rebase master #變基為master最新的提交
或者
git rebase master topic
這種情況下,使用 git rebase 命令通常成為向前移植(forward porting)。在Git中做一個向前或者向后移植的變基都可以使用 git rebase 實現。
git rebase 命令也是使用 --onto 選項把 一整條分支 整個移植到不同的分支上。
分支 feature 是基於 分支 maint 的提交 Y 的。現在想把 feature 分支整個從 manit 分支遷移到 master 分支,操作命令為:git rebase --noto master maint^ feature #找准基點就行
變基操作是從各自原始位置遷移到新的提交基礎。因此,每個移動的提交都有可能會出現沖突。如果發現沖突 git rebase 命令會臨時掛起進程以便我們來解決沖突,沖突的解決方式和合並的沖突解決方式一樣。一旦所有沖突都解決了,並且索引項已經更新了,就可以使用 git rebase --continue 命令恢復變基操作。
最后,如果你臨時發現不應該進行變基操作,就可以使用 git rebase --abort 來中止操作,並把版本庫恢復到發出 git rebase 命令之前的狀態。