### GDSC NYUST x 資訊創客社
<br>
### 軟體開發工具入門讀書會
#### Git課程
<br>
#### 2023/10/23 (Mon) 19:00 - 21:00
#### 講師:楊鈞元 Charles
#### 本次課程影片:
<img src="" height="200px">
---
## 前言
----
### 軟體開發工具入門讀書會
### VS Code & Node.js 課程
<br>
課程影片:[⚒️YouTube後製中]()
簡報連結:[🔗HackMD](https://hackmd.io/@GDSC-NYUST/SkiZJXPZ6/%2FkpG3SBCFQU6OPl-gK-R0eQ)
----
### GDSC社課
### Topic 1 - Class 3 Git & GitHub
<br>
課程影片:[⚒️YouTube後製中]()
簡報連結:[🔗HackMD](https://hackmd.io/@GDSC-NYUST/rJKqKU1gp/%2FJzrJyqfBQhuR9t1Q7OX73w)
---
## 環境說明
----
以 Linux ( WSL ) 及 VS Code 進行 Git 管理
<br>
如何安裝WSL:[🔗Linux課程](https://youtu.be/8awPH5tUko8)
----
Ubuntu 預設即有Git
Debian 可能會尚未安裝

----
Debian / Ubuntu 系統安裝方式
```=
sudo apt update
sudo apt install git
```

<br>
確認是否安裝成功
```=
git --version
```
---
## 安裝VS Code Extension
----
- [Git Graph](https://marketplace.visualstudio.com/items?itemName=mhutchie.git-graph)

- [git-commit-plugin](https://marketplace.visualstudio.com/items?itemName=redjue.git-commit-plugin)

----
修改自定義commit模板
```=
cd ~/.vscode-server/extensions/redjue.git-commit-plugin-1.2.1/out/config
sudo rm -f commit-type.js && sudo wget https://github.com/Charles5277/git-commit-plugin/raw/main/__fix_config/commit-type.js --no-check-certificate
sudo rm -f commit-detail.js && sudo wget https://github.com/Charles5277/git-commit-plugin/raw/main/__fix_config/commit-detail.js --no-check-certificate
```
---
## Git Branch
----
從2022/10開始
Github的預設分支主線由master改為main
Git預設仍為master
( 未建立Branch直接進行Commit )

----
### 查看現有的分支
```= git
git branch -a
```
----
在git init後直接查看,不會有分支

----

----
### 創建分支
使用 **`git branch <新分支名稱>`** 創建分支
這個新分支會以當前HEAD指到的位置作為起點
```= git
git branch dev
git switch dev
```
<br>
或使用 **`git switch -c <新分支名稱>`**
可以直接在創建後同時將HEAD指過去
```= git
git switch -c main
```
<br>
```
*新增後尚未commit,也不會在git branch -a跟git graph中看到
```
----
#### 使用 Git Graph 創建分支
<br>
對指定commit右鍵新增分支
|||
|-|-|

----
#### 使用 Git Graph 創建分支
<br>
取名字 & 是否要順便移動過去
|||
|-|-|

----
### 更改分支名稱
**`git branch -m <舊分支名稱> <新分支名稱>`**
```= git
git branch -m dev test
```
----
#### 使用 Git Graph 更改分支名稱
|||
|-|-|


----


----
### 刪除分支
```= git
// 一般刪除,若有未合併的節點會停下詢問,避免節點遺失
git branch -d <分支名稱>
```
```= git
// 強制刪除,無視節點遺失
// 但HEAD當前指的Branch用此方法也刪除不了
// 需要先移動到其他分支
git branch -D <分支名稱>
```
----
#### 使用 Git Graph 刪除分支

詢問是否要強制刪除

----
### 節點遺失 ( unreachable commits )
若因為強制刪除導致節點遺失
我們稱這些節點為unreachable commits
即無法抵達的commits
後續會介紹如何救回這種節點
---
## Git Switch
----
### HEAD介紹
----
Commit節點像是大富翁格子
每個Branch像是不同的角色棋子
但Branch會紀錄自己擁有的每一格紀錄
HEAD就是手指
| HEAD指dev | HEAD指main | HEAD指節點上|
| --- | --- | --- |
||||
|||
----
### 移動HEAD
----
使用 **`git switch <分支名稱>`**
```= git
git switch dev
git switch main
```
使用 **`git switch -d <節點hash值>`**
```= git
git switch -d 0b5d9580c43c05ac7513237aaaaf0abe5d24029c
```
----
#### 如何取得節點的hash值
```= git
git log
// 或者
git reflog
```
透過以上兩個指令判斷 (後面會解釋)
----
#### 如何取得節點的hash值
直接透過Git Graph,最右側commit欄即為hash

```
大部分git指令提供這種長度的hash縮寫即可
```
----
#### 如何取得節點的hash值
<br>
針對某個commit右鍵,直接複製完整hash

----
使用 Git Graph

```
checkout有switch跟restore的功能
有些舊教學或套件會習慣使用checkout
只要看得懂,會使用即可
為了避免混淆,我們以switch跟restore分開示範
```
----
使用 VS Code
|||
|-|-|
|||

----
#### 補充展示
[🔗HEAD指向commit跟branch的差別](https://hackmd.io/@GDSC-NYUST/rJKqKU1gp/%2FJzrJyqfBQhuR9t1Q7OX73w#HEAD%E6%8C%87%E5%90%91commit%E8%B7%9Fbranch%E7%9A%84%E5%B7%AE%E5%88%A5)
---
### Git Reflog
----
#### Reflog概念說明
Reflog紀錄所有變更(包含分支和 HEAD)的歷史
最常用於恢復意外刪除的分支或提交
或確認 Git 操作歷史是否如期
----
#### git log與git reflog

```
最上面是最新的操作紀錄
越往下越舊,可透過方向鍵上下移動
按Q可以離開檢視
```
----
#### git graph查看詳情

----
#### 情境題

```= git
git switch main
git branch -D dev
```


----
```= git
git reflog
```

剛才先switch到main,才進行刪除
因此我們可以回到他之前的節點
```= git
git switch -d 6a89645
```


----
再建立Branch指向這個commit

---
### Git Merge
----
#### 指令展示
<br>
[🔗Git Merge筆記](https://hackmd.io/JzrJyqfBQhuR9t1Q7OX73w#git-merge)
[🔗線上練習Git Merge](https://learngitbranching.js.org/?locale=zh_TW)
----
#### 透過Git Graph

----
#### 合併衝突

----
顯示衝突
|||
|-|-|
|||
----
比較變更
|||
|-|-|

```
*無法直接在此處修改
即將到來的變更:
如果指定的分支內容直接覆寫當前分支,這個檔案會受到怎樣的影響
```
----
使用內嵌顯示
|||
|-|-|
|||
```
*無法直接在此處修改
```
----
使用 **在合併編輯器中編輯**
|||
|-|-|

```
傳入:唯讀,merge進來的分支,相較於共同parent帶來的變更
目前:唯讀,當前分支,相較於共同parent帶來的變更
結果:可編輯,預設為共同parent的狀態,會即時顯示預覽變更
```
----
手動新增內容
|||
|-|-|
||
|
----
重設為基底
|||
|-|-|

----
重設為基底
|||
|-|-|

```
點擊重設為基底,會清空手動變更,讓你重新處理
*按了又想反悔,可以用Ctrl + Z
```
----
切換衝突點
|||
|-|-|

```
*利用上、下箭頭移動到其他衝突點
```
----
完成衝突處理
|||
|-|-|

```
處理所有衝突,直到顯示變成0個剩餘衝突
```
----
完成衝突處理
|||
|-|-|

```
點擊右下角完成合併
```
----
中途想停止合併
~~有內鬼,終止交易!~~
```= git
git merge --abort
```
---
## Git Cherry-Pick
----

使用 **`git cherry-pick <hash>`**
```= git
git cherry-pick 5940b3432b84f25956aea26c41781443dfcd0731
```
```
可以理解為跟merge一樣,但只合併一個指定的commit
一樣可能遇到衝突,一樣可以用 git cherry-pick --abort 中止操作
```
----
#### 搭配 Git Graph
針對commit直接右鍵選擇


```
由於時間有限,此處就不詳細展開Record Origin
以及No Commit的意義,大家可以自行嘗試,遇到問題在Discord提出
```
----
更多補充
```
git cherry-pick <start-hash>..<end-hash>
> 將start到end的commit都擷取
git cherry-pick <hash> -e <target-branch>
> 將指定commit單獨複製到指定分支上 (而非當前分支)
git cherry-pick --no-commit <commit-hash>
> 將指定的commit變更套用到當前stage區,而非直接套用提交
```
<br>
延伸閱讀
[🔗Git Cherry Pick 的後遺症](https://blog.darkthread.net/blog/git-cherry-pick-cons/)
---
## Git Restore
----
### 捨棄檔案變更
使用 **`git restore <file_name>`**
```
將檔案的變更捨棄(只限定未放到stage區的workdir變更)
預設即為-W (worktree)
因此 git restore -W <file_name>的效果是一樣的
```
白話文👇

----
### 取消 git add
使用 **`git restore -S <file_name>`**
```
將檔案從stage區移回workdir(但內容變更不改變)
相當於取消git add
```
白話文👇
|||
|-|-|
||
|
----
### 捨棄單一檔案的變更
使用 **`git restore <檔名>`**
白話文👇
|||
|-|-|

----
### 捨棄所有檔案的變更
使用 **`git restore .`**
白話文👇
|||
|-|-|

```
指令要達到"捨棄所有檔案",包含未追蹤的檔案較為複雜,也較危險
此處就不展示,若使用VS Code想選擇同等的 "捨棄所有檔案" 功能
請確保所有變更都真的不要了
```
----
### 把暫存區的變更殺掉
使用 **`git restore -W -S <file_name>`**
```
一次完成從stage區直接捨棄變更
```
```
由於太危險,VS Code的圖形介面沒有直接提供這個按鈕
需要先取消暫存變更 (Unstage Changes)
才能將檔案移除
```
----
#### 從其他commit拿檔案
比cherry-pick更狠
使用 **`git restore -s <hash/branch> <file_name>`**
```
抓某個commit版本的指定檔案到目前的workdir
```
<br>
```
同cherry-pick的問題,一樣需要謹慎使用,不要為了方便破壞專案易維護性
```
---
## Git Reset
----
### 取消最近一次的commit
使用 **`git reset HEAD~`**
或
使用 **`git reset HEAD^`**
----
### 取消當前branch的多筆commit
使用 **`git reset HEAD~數字`**
或
使用 **`git reset HEAD~..~`**
例如想要取消3筆
```
git reset HEAD~~~
或
git reset HEAD~3
```
----
### reset後捨棄變更
一般reset後
原本最新的變更會退回到worktree的workdir
若確定退回後不需要這些變更紀錄
使用 **`git reset HEAD~ --hard`**
----
### 當前branch直接投奔到其他位置
當我們要讓當前branch強行變更到指定位置
可以使用 **`git reset <hash>`**
或
使用 **`git reset <branch_name>`**
將當前branch直接變更為指定commit的狀態
同樣可以選用 `--hard` 將原本位置的檔案變更捨棄
----
#### 搭配 Git Graph

```
直接對想要的位置右鍵,使用 Reset current branch to this Commit 即可
```
----
#### 搭配 Git Graph

```
Soft:提交過的commit放到暫存區、當前worktree保留,
Mixed:提交過的commit放到工作目錄、當前stage清除、workdir保留
Hard:提交過的跟當前變更都不要了,直接變成目標的狀態
```
```
指令預設採Mixed模式,可以改指定`--hard`或`--soft`
```
----
#### 參考閱讀:
<br>
[🔗剛才的 Commit 後悔了,想要拆掉重做…](https://gitbook.tw/chapters/using-git/reset-commit)
----
#### 補充
<br>
git reset除了重置到指定狀態以外
還有很多活用的技巧
由於篇幅關係
此處簡單介紹回退commit及模式差別
實務用法可以在課後作業進行練習與思考
<br>
---
### Git Rebase
----
### rebase的意義
<br>
rebase中文翻譯成重訂基底,主要有2個功能
1. 濃縮commit
2. 將目前分支整根接到其他分支上
----
### 濃縮commit
當我們在同一條branch上commit太多次
想把一部分的commit合併成一個時
可以使用 **`git rebase -i HEAD~數字`**
```
同樣可以使用 git rebase --abort 取消操作
```
----
### 濃縮commit
||||
|-|-|-|
|||
```
等同git rebase -i HEAD~3
```
```
選擇的那個commit不包含在可編輯區
```
----
### 濃縮commit

|
----
#### rebase 參數

----
#### rebase 參數
簡單解釋4個比較常用的
```
pick:保留Commit
drop:刪除Commit,會捨棄這個Commit所紀錄的變更
reword:保留Commit,並修改這個Commit的訊息,但不影響裡面包含的檔案
squash:將這個Commit合併到前一個,用於濃縮多個小的連續Commit合併成1個
```
----
#### 進行濃縮

```
修改後存檔 (Ctrl + S),再關閉分頁
```
```
注意!
在互動模式的紀錄由上而下是從最舊到最新
跟 Git Graph 所呈現的結果是相反的。
```
----
#### 進行濃縮

```
我利用commit的模板工具,產生了我想要修改的訊息內容
但你會發現,此時無法直接按提交鈕
你必須將內容複製到文件,並取代原本的訊息
不要的內容都註解或刪除
```
----
#### 進行濃縮

```
像這樣,完成後一樣存檔,關閉分頁
```
----
#### 完成濃縮

```
若執行完成沒有立刻更新,可以手動按右上角的refresh鈕
```
----
### 移植當前分支到其他分支
|||
|-|-|
|||
```
等同 git rebase branch
```
----
### 移植當前分支到其他分支
||||
|-|-|-|
||||
```
搭配interactive也能在rebase階段如同濃縮的用法
在移植的過程中濃縮,或更改commit訊息
```
----
#### 補充
<br>
git rebase 又更加強大而複雜了
同樣由於篇幅關係
需要各位在課後作業多加練習
遇到問題請盡量提出!
<br>
---
## 延伸閱讀
----
### Git Revert
----
將某個版本否決
[🔗Git Revert筆記](https://hackmd.io/JzrJyqfBQhuR9t1Q7OX73w?view#git-revert)
----
### Git Stash
----
將當前Worktree打包暫存
[🔗Git Stash筆記](https://hackmd.io/JzrJyqfBQhuR9t1Q7OX73w?view#git-stash)
---
## 學習資源
[🔗Charles HackMD - Git筆記 (GDSC複本)](https://hackmd.io/JzrJyqfBQhuR9t1Q7OX73w?both#git-command)
[🔗W3Hexschool - Git & GitHub 教學手冊](https://w3c.hexschool.com/git/cfdbd310)
[🔗為你自己學 Git - 情境狀況實戰](https://gitbook.tw/)
[🔗Learn Git Branching - 線上Branch操作練習](https://learngitbranching.js.org/?locale=zh_TW)
---
## Q & A 時間
----
## 下一次課程
### 10/25 (Wed) GitHub課程
金鑰交換, 遠端備份, Issue, Pull Request
GitHub Actions, GitHub Project...
---
## 回家作業
<br>
⚒️製作中
請Follow Discord 或影片下方說明欄
{"slideOptions":"{\"transition\":\"concave\",\"allottedMinutes\":100}","title":"Git 課程","contributors":"[{\"id\":\"f8142aa2-66aa-4867-821d-2f1ffff7a7ba\",\"add\":21252,\"del\":8626}]","description":"課程影片:⚒️YouTube後製中簡報連結:🔗HackMD"}