Skip to content

Commit

Permalink
fixes #29
Browse files Browse the repository at this point in the history
  • Loading branch information
doggy8088 committed Nov 18, 2023
1 parent dbccf5f commit 1293ff1
Show file tree
Hide file tree
Showing 4 changed files with 92 additions and 108 deletions.
100 changes: 46 additions & 54 deletions zh-cn/18.md
Original file line number Diff line number Diff line change
@@ -1,26 +1,22 @@
第 18 天:修正 commit 过的版本历史记录 Part 1
=============================================================
# 第 18 天:修正 commit 过的版本历史记录 Part 1

当你使用 Git 进行版本控制时,我们会利用 `git commit` 建立许多版本,由于 Git 属分布式版本控制机制,对于版本控制方面没有太多的权限设计,跟其他如 Subversion 或 TFVC 这类版控系统相比,Git 提供更多「修正版本记录」的机制,让你在「分享」版本给其他人的时候,能够预先做个整理。

版本控制的基本原则
-------------------
## 版本控制的基本原则

我们在进行版本控制时,无论是 Git, Subversion 或 TFVC 都一样,维持一个良好的版本记录有助于我们追踪每个版本的更新历程 (当有需要做这件事的时候)。以我个人的经验,我们很难有机会,也不太想去追踪我们某个项目中软件开发的进程,我们许多项目累积的版本记录数量有多达数千笔,谁会有这种闲工夫去追查历史呢?

然而实际上,当软件的臭虫(Bug)发生的时候,我们会需要去追踪特定臭虫的历史记录,以查出该臭虫真正发生的原因,这个时候就是版本控制带来最大价值的时候。
然而实际上,当软件的臭虫 (Bug) 发生的时候,我们会需要去追踪特定臭虫的历史记录,以查出该臭虫真正发生的原因,这个时候就是版本控制带来最大价值的时候。

也因此,要怎样维持一个好的「版本记录」也是非常重要的,这边有一些控制原则可以分享给大家:

* 做一个小功能修改就建立版本,这样才容易追踪变更
* 千万不要累积一大堆修改后才建立一个「大版本」
* 有逻辑、有顺序的修正功能,确保相关的版本修正可以按顺序提交(commit),这样才便于追踪
* 有逻辑、有顺序的修正功能,确保相关的版本修正可以按顺序提交 (commit),这样才便于追踪

不过,人非圣贤、孰能无过,哪个人能确保团队所有人都能时时刻刻照着上述原则进行版控?哪个人不是「想到哪改到哪」呢?这样的要求变得有点緣木求魚、不切实际。所以,我们需要有一套「修改版本」的机制,让版本提交到远端服务器上的时候,就已经是完美的版本状态。


修正 commit 历史记录的理由
---------------------------
## 修正 commit 历史记录的理由

到目前为止,我还没提到关于「远端仓库」的细节,所以大部分的 Git 操作都还专注在本地端,也就是在工作目录下的版本管控,这个仓库就位于你的 `.git/` 目录下。然而,之后我们即将提到「远端仓库」的应用,到时就不只一个人拥有仓库,所需要注意的细节也就更多。

Expand All @@ -30,17 +26,16 @@

所以,到底什么样的使用情境会需要去修改版本记录呢?以下几点各位可以参考看看。

假设我们现在有 [A] -> [B] -> [C] 三个版本:
假设我们现在有 \[A] -> \[B] -> \[C] 三个版本:

* 可能 [C] 版本你发现 commit 错了,必须删除这一版本所有变更
* 你可能 commit 了之后才发现 [C] 这个版本其实只有测试代码,你也想删除他
* 可能 \[C] 版本你发现 commit 错了,必须删除这一版本所有变更
* 你可能 commit 了之后才发现 \[C] 这个版本其实只有测试代码,你也想删除他
* 其中有些版本的记录消息有错字,你想修改消息文字,但不影响文件的变更历程
* 你可能想把这些版本的 commit 顺序调整为 [A] -> [C] -> [B],让版本演进更有逻辑性
* 你发现 [B] 这个版本忘了加入一个重要的文件就 commit 了,你想事后補救这次变更
* 你可能想把这些版本的 commit 顺序调整为 \[A] -> \[C] -> \[B],让版本演进更有逻辑性
* 你发现 \[B] 这个版本忘了加入一个重要的文件就 commit 了,你想事后補救这次变更
* 在你打算「分享」分支出去时,发现了代码有瑕疵,你可以修改完后再分享出去

修正 commit 历史记录的注意事项
-----------------------------
## 修正 commit 历史记录的注意事项

Git 保留了「修改版本历史记录」的机制,主要是希望你能在「自我控制版本」到了一定程度后,自己整理一下版本记录的各种信息,好让你将版本「发布」出去后,让其他人能够更清楚的理解你对这些版本到底做了哪些修改。

Expand All @@ -51,46 +46,49 @@ Git 保留了「修改版本历史记录」的机制,主要是希望你能在
* 你可以任意修改某个支线上的版本,只要你还没「分享」给其他人
* **当你「分享」特定分支给其他人之后,这些「已分享」的版本历史记录就別再改了!**

准备本日练习用的版本库
----------------------
## 准备本日练习用的版本库

之前我们曾在【第 04 天:常用的 Git 版本控制指令】学过 `git reset` 的用法,主要用来 **重置目前的工作目录**。不过,相同的指令,也可以用来修正版本历史记录。

在开始说明前,我们一样先用以下指令建立一个练习用的工作目录与本地仓库:

mkdir git-reset-demo
cd git-reset-demo
git init
```sh
mkdir git-reset-demo
cd git-reset-demo
git init

echo. > a.txt
git add .
git commit -m "Initial commit (a.txt created)"
echo. > a.txt
git add .
git commit -m "Initial commit (a.txt created)"

echo 1 > a.txt
git add .
git commit -m "Update a.txt!"
echo 1 > a.txt
git add .
git commit -m "Update a.txt!"

echo 1 > b.txt
git add .
git commit -m "Add b.txt!"
echo 1 > b.txt
git add .
git commit -m "Add b.txt!"
```

![image](figures/18/01.png)

以上建立了三个版本,执行 `git log` 的结果如下图示:

![image](figures/18/02.png)


删除最近一次的版本
-------------------
## 删除最近一次的版本

我们参考上图,用文字表达这三个版本的顺序如下:

[83a841] > [0576e0] > [aef2a5]
```txt
[83a841] > [0576e0] > [aef2a5]
```

现在,我想把最后一个版本删除,变成:

[83a841] > [0576e0]
```txt
[83a841] > [0576e0]
```

那么,你可以执行 `git reset --hard "HEAD^"` 即可删除 `HEAD` 这个版本:
**请注意**:在「命令提示字元下」 `^` 是特殊符号,所以必须用雙引号括起来!
Expand All @@ -99,12 +97,11 @@ Git 保留了「修改版本历史记录」的机制,主要是希望你能在

此时你可以看见,原本的最新版被删除了,那是因为刚刚我们执行 `git reset --hard "HEAD^"` 这个动作,把 `HEAD` 指向的位址改到了前一个版本 ( `HEAD^` ),所以你打 `git log` 就看不到这个版本了。

事实上,原本你感觉被删除的版本,其实一直储存在 Git 的物件储存区(object storage)里,也就是这笔资料一直躺在 `.git\objects\` 目录下。我们还是可以用 `git show 83a841` 取得该版本 ( 即 commit 物件 ) 的详细资料:
事实上,原本你感觉被删除的版本,其实一直储存在 Git 的物件储存区 (object storage) 里,也就是这笔资料一直躺在 `.git\objects\` 目录下。我们还是可以用 `git show aef2a5` 取得该版本 (即 commit 物件) 的详细资料:

![image](figures/18/04.png)

删除最近一次的版本,但保留最后一次的变更
------------------------------------
## 删除最近一次的版本,但保留最后一次的变更

还记得吗?无论你对 Git 仓库做了什么事,都是可以还原的,只要执行 `git reset --hard ORIG_HEAD` 即可。

Expand All @@ -116,8 +113,7 @@ Git 保留了「修改版本历史记录」的机制,主要是希望你能在

这代表着,你可以保留最后一次的变更,再加上一些变更后,重新执行 `git commit` 一次,并重新设定一个新的记录消息。

重新提交一次最后一个版本 (即 `HEAD` 版本)
-----------------------------------------
## 重新提交一次最后一个版本 (即 `HEAD` 版本)

如果你发现不小心执行了 `git commit` 动作,但还有些文件忘了加进去 (`git add [filepath]`) 或只是记录消息写错,想重新補上的话,直接执行 `git commit --amend` 即可。这个动作,会把目前记录在索引中的变更文件,全部添加到当前最新版之中,并且要求你修改原本的记录消息。

Expand All @@ -129,38 +125,34 @@ Git 保留了「修改版本历史记录」的机制,主要是希望你能在

我把记录消息修改成以下文字,并且存档后退出,版本就会建立完成:

Add b.txt!
Add c.txt!
```txt
Add b.txt!
Add c.txt!
```

执行的结果如下,但最值得注意的是,最新版的 `HEAD` 已经是完全不同的 commit 物件了,所以用 `git log` 所看到的 commit 物件绝对名称跟之前已经不一样了。

![image](figures/18/08.png)

今日小结
-------
## 今日小结

今天简单的学到如何对【最新版】(`HEAD`)进行版本的变更,大多用在不小心 `git commit` 错的情況,事实上还会有更多调整版本历史记录的方式,这些会在之后的文章中出现。
今天简单的学到如何对【最新版】(`HEAD`) 进行版本的变更,大多用在不小心 `git commit` 错的情況,事实上还会有更多调整版本历史记录的方式,这些会在之后的文章中出现。

我重新整理一下本日学到的 Git 指令与参数:

* git reset --hard "HEAD^"
* git reset --soft "HEAD^"
* git reset --hard ORIG_HEAD
* git reset --hard ORIG\_HEAD
* git commit --amend

参考连结
-------
## 参考连结

* [git-reset(1) Manual Page](https://www.kernel.org/pub/software/scm/git/docs/git-reset.html)

---



-------
* [回目录](README.md)
* [前一天:关于合并的基本观念与使用方式](17.md)
* [下一天:设定 .gitignore 忽略清单](19.md)

-------


---
Binary file modified zh-cn/figures/18/04.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
100 changes: 46 additions & 54 deletions zh-tw/18.md
Original file line number Diff line number Diff line change
@@ -1,26 +1,22 @@
第 18 天:修正 commit 過的版本歷史紀錄 Part 1
=============================================================
# 第 18 天:修正 commit 過的版本歷史紀錄 Part 1

當你使用 Git 進行版本控管時,我們會利用 `git commit` 建立許多版本,由於 Git 屬分散式版本控管機制,對於版本控管方面沒有太多的權限設計,跟其他如 Subversion 或 TFVC 這類版控系統相比,Git 提供更多「修正版本記錄」的機制,讓你在「分享」版本給其他人的時候,能夠預先做個整理。

版本控管的基本原則
-------------------
## 版本控管的基本原則

我們在進行版本控管時,無論是 Git, Subversion 或 TFVC 都一樣,維持一個良好的版本紀錄有助於我們追蹤每個版本的更新歷程 (當有需要做這件事的時候)。以我個人的經驗,我們很難有機會,也不太想去追蹤我們某個專案中軟體開發的進程,我們許多專案累積的版本紀錄數量有多達數千筆,誰會有這種閒工夫去追查歷史呢?

然而實務上,當軟體的臭蟲(Bug)發生的時候,我們會需要去追蹤特定臭蟲的歷史紀錄,以查出該臭蟲真正發生的原因,這個時候就是版本控管帶來最大價值的時候。
然而實務上,當軟體的臭蟲 (Bug) 發生的時候,我們會需要去追蹤特定臭蟲的歷史紀錄,以查出該臭蟲真正發生的原因,這個時候就是版本控管帶來最大價值的時候。

也因此,要怎樣維持一個好的「版本紀錄」也是非常重要的,這邊有一些控管原則可以分享給大家:

* 做一個小功能修改就建立版本,這樣才容易追蹤變更
* 千萬不要累積一大堆修改後才建立一個「大版本」
* 有邏輯、有順序的修正功能,確保相關的版本修正可以按順序提交(commit),這樣才便於追蹤
* 有邏輯、有順序的修正功能,確保相關的版本修正可以按順序提交 (commit),這樣才便於追蹤

不過,人非聖賢、孰能無過,哪個人能確保團隊所有人都能時時刻刻照著上述原則進行版控?哪個人不是「想到哪改到哪」呢?這樣的要求變得有點緣木求魚、不切實際。所以,我們需要有一套「修改版本」的機制,讓版本提交到遠端伺服器上的時候,就已經是完美的版本狀態。


修正 commit 歷史紀錄的理由
---------------------------
## 修正 commit 歷史紀錄的理由

到目前為止,我還沒提到關於「遠端儲存庫」的細節,所以大部分的 Git 操作都還專注在本地端,也就是在工作目錄下的版本管控,這個儲存庫就位於你的 `.git/` 目錄下。然而,之後我們即將提到「遠端儲存庫」的應用,到時就不只一個人擁有儲存庫,所需要注意的細節也就更多。

Expand All @@ -30,17 +26,16 @@

所以,到底甚麼樣的使用情境會需要去修改版本紀錄呢?以下幾點各位可以參考看看。

假設我們現在有 [A] -> [B] -> [C] 三個版本:
假設我們現在有 \[A] -> \[B] -> \[C] 三個版本:

* 可能 [C] 版本你發現 commit 錯了,必須刪除這一版本所有變更
* 你可能 commit 了之後才發現 [C] 這個版本其實只有測試程式碼,你也想刪除他
* 可能 \[C] 版本你發現 commit 錯了,必須刪除這一版本所有變更
* 你可能 commit 了之後才發現 \[C] 這個版本其實只有測試程式碼,你也想刪除他
* 其中有些版本的紀錄訊息有錯字,你想修改訊息文字,但不影響檔案的變更歷程
* 你可能想把這些版本的 commit 順序調整為 [A] -> [C] -> [B],讓版本演進更有邏輯性
* 你發現 [B] 這個版本忘了加入一個重要的檔案就 commit 了,你想事後補救這次變更
* 你可能想把這些版本的 commit 順序調整為 \[A] -> \[C] -> \[B],讓版本演進更有邏輯性
* 你發現 \[B] 這個版本忘了加入一個重要的檔案就 commit 了,你想事後補救這次變更
* 在你打算「分享」分支出去時,發現了程式碼有瑕疵,你可以修改完後再分享出去

修正 commit 歷史紀錄的注意事項
-----------------------------
## 修正 commit 歷史紀錄的注意事項

Git 保留了「修改版本歷史紀錄」的機制,主要是希望你能在「自我控管版本」到了一定程度後,自己整理一下版本紀錄的各種資訊,好讓你將版本「發布」出去後,讓其他人能夠更清楚的理解你對這些版本到底做了哪些修改。

Expand All @@ -51,46 +46,49 @@ Git 保留了「修改版本歷史紀錄」的機制,主要是希望你能在
* 你可以任意修改某個支線上的版本,只要你還沒「分享」給其他人
* **當你「分享」特定分支給其他人之後,這些「已分享」的版本歷史紀錄就別再改了!**

準備本日練習用的版本庫
----------------------
## 準備本日練習用的版本庫

之前我們曾在【第 04 天:常用的 Git 版本控管指令】學過 `git reset` 的用法,主要用來 **重置目前的工作目錄**。不過,相同的指令,也可以用來修正版本歷史紀錄。

在開始說明前,我們一樣先用以下指令建立一個練習用的工作目錄與本地儲存庫:

mkdir git-reset-demo
cd git-reset-demo
git init
```sh
mkdir git-reset-demo
cd git-reset-demo
git init

echo. > a.txt
git add .
git commit -m "Initial commit (a.txt created)"
echo. > a.txt
git add .
git commit -m "Initial commit (a.txt created)"

echo 1 > a.txt
git add .
git commit -m "Update a.txt!"
echo 1 > a.txt
git add .
git commit -m "Update a.txt!"

echo 1 > b.txt
git add .
git commit -m "Add b.txt!"
echo 1 > b.txt
git add .
git commit -m "Add b.txt!"
```

![image](figures/18/01.png)

以上建立了三個版本,執行 `git log` 的結果如下圖示:

![image](figures/18/02.png)


刪除最近一次的版本
-------------------
## 刪除最近一次的版本

我們參考上圖,用文字表達這三個版本的順序如下:

[83a841] > [0576e0] > [aef2a5]
```txt
[83a841] > [0576e0] > [aef2a5]
```

現在,我想把最後一個版本刪除,變成:

[83a841] > [0576e0]
```txt
[83a841] > [0576e0]
```

那麼,你可以執行 `git reset --hard "HEAD^"` 即可刪除 `HEAD` 這個版本:
**請注意**:在「命令提示字元下」 `^` 是特殊符號,所以必須用雙引號括起來!
Expand All @@ -99,12 +97,11 @@ Git 保留了「修改版本歷史紀錄」的機制,主要是希望你能在

此時你可以看見,原本的最新版被刪除了,那是因為剛剛我們執行 `git reset --hard "HEAD^"` 這個動作,把 `HEAD` 指向的位址改到了前一個版本 ( `HEAD^` ),所以你打 `git log` 就看不到這個版本了。

事實上,原本你感覺被刪除的版本,其實一直儲存在 Git 的物件儲存區(object storage)裡,也就是這筆資料一直躺在 `.git\objects\` 目錄下。我們還是可以用 `git show 83a841` 取得該版本 ( 即 commit 物件 ) 的詳細資料:
事實上,原本你感覺被刪除的版本,其實一直儲存在 Git 的物件儲存區 (object storage) 裡,也就是這筆資料一直躺在 `.git\objects\` 目錄下。我們還是可以用 `git show aef2a5` 取得該版本 (即 commit 物件) 的詳細資料:

![image](figures/18/04.png)

刪除最近一次的版本,但保留最後一次的變更
------------------------------------
## 刪除最近一次的版本,但保留最後一次的變更

還記得嗎?無論你對 Git 儲存庫做了什麼事,都是可以還原的,只要執行 `git reset --hard ORIG_HEAD` 即可。

Expand All @@ -116,8 +113,7 @@ Git 保留了「修改版本歷史紀錄」的機制,主要是希望你能在

這代表著,你可以保留最後一次的變更,再加上一些變更後,重新執行 `git commit` 一次,並重新設定一個新的紀錄訊息。

重新提交一次最後一個版本 (即 `HEAD` 版本)
-----------------------------------------
## 重新提交一次最後一個版本 (即 `HEAD` 版本)

如果你發現不小心執行了 `git commit` 動作,但還有些檔案忘了加進去 (`git add [filepath]`) 或只是紀錄訊息寫錯,想重新補上的話,直接執行 `git commit --amend` 即可。這個動作,會把目前紀錄在索引中的變更檔案,全部添加到當前最新版之中,並且要求你修改原本的紀錄訊息。

Expand All @@ -129,38 +125,34 @@ Git 保留了「修改版本歷史紀錄」的機制,主要是希望你能在

我把紀錄訊息修改成以下文字,並且存檔後退出,版本就會建立完成:

Add b.txt!
Add c.txt!
```txt
Add b.txt!
Add c.txt!
```

執行的結果如下,但最值得注意的是,最新版的 `HEAD` 已經是完全不同的 commit 物件了,所以用 `git log` 所看到的 commit 物件絕對名稱跟之前已經不一樣了。

![image](figures/18/08.png)

今日小結
-------
## 今日小結

今天簡單的學到如何對【最新版】(`HEAD`)進行版本的變更,大多用在不小心 `git commit` 錯的情況,事實上還會有更多調整版本歷史紀錄的方式,這些會在之後的文章中出現。
今天簡單的學到如何對【最新版】(`HEAD`) 進行版本的變更,大多用在不小心 `git commit` 錯的情況,事實上還會有更多調整版本歷史紀錄的方式,這些會在之後的文章中出現。

我重新整理一下本日學到的 Git 指令與參數:

* git reset --hard "HEAD^"
* git reset --soft "HEAD^"
* git reset --hard ORIG_HEAD
* git reset --hard ORIG\_HEAD
* git commit --amend

參考連結
-------
## 參考連結

* [git-reset(1) Manual Page](https://www.kernel.org/pub/software/scm/git/docs/git-reset.html)

---



-------
* [回目錄](README.md)
* [前一天:關於合併的基本觀念與使用方式](17.md)
* [下一天:設定 .gitignore 忽略清單](19.md)

-------


---
Binary file modified zh-tw/figures/18/04.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 1293ff1

Please sign in to comment.