---
# System prepended metadata

title: Git 學習紀錄
tags: [Git]

---

---
title: 'Git 學習紀錄'
disqus: hackmd
---
## Git基礎
### Git指令練習網站 
* `https://github.com/pcottle/learnGitBranching`

### VsCode 安裝Git相關套件
* Git Graph
* Git History
* GitLens — Git supercharged

### 常用git log
*  git log --oneline --graph
    * --oneline : 是 --pretty=oneline --abbrev-commit 的簡短用法
    * --graph : 以 ASCII 在 log 輸出旁邊畫出分支的分歧及合併。
* git log 參數參考網址：http://jamestw.logdown.com/posts/238719-advanced-git-log
---
### 修改最近一次的commit紀錄
* git commit \-\-amend -m "XXXXX"
* git commit \-\-amend 
    *   沒有加上 **-m** 會跳出一個視窗來編輯訊息(vim編輯器)


---
### 追加調整內容( test.txt ) 到最近一次的commit
1. git add test.txt 
2. git commit --amend --no-edit
    * --no-edit:不編輯commit訊息
3. git push -f ：強制覆蓋遠端分支
---
### git 復原檔案
*  git checkout xxx 復原該份檔案
*  git checkout . 復原所有檔案
    *  概念：拿暫存區的檔案，覆蓋至工作區
*  git checkout HEAD~2 xxx 
    *  拿兩個版本前的檔案，覆蓋至當前工作目錄，同時修改暫存區的內容
---

### 將commit 拆掉重做
* git **reset e12d8ef^**
    * 表示指向**e12d8ef**這個commit的前一次
    * git reset **HEAD^** \ git reset **master^**
    * **指定退回哪個commit** : git reset  f55f49d
        * --mixed` 模式(`預設`)，將目前commit至f55f49d中所修改的東西，全部退至**工作目錄**

---
### Commit拆出來的檔案
* `--mixed` 模式(`預設`)：
    * 丟回**工作目錄**
    * 暫存區的檔案丟掉，但不會動工作目錄的檔案，Commit拆出來的檔案會留在工作目錄，但不會留在暫存區
* `--soft` 模式：
    * 工作目錄、暫存區都不會被丟掉，只有HEAD移動
    * Commit拆出來的檔案會直接放在**暫存區**
* `--hard` 模式：
    * 將工作目錄、暫存區都丟棄，直接退回該commit時的狀態
---
### 救回 hard模式下，reset的某個commit
    1. git log -g \ git reflog : 查看紀錄
    2. 找到該commit的SHA-1碼
    3. git reset --hard 0929fe2 ＃指向0929fe2，同時會復原該0929fe2 之前所做的commit紀錄
---
### HARD 是什麼東西？
* 是一個指標，指向某一個分支 
* 通常把HEAD當作「目前所在分支」
---
### 只Commit 一個檔案的部分內容
* git add -p ：
    * 選y：將整個檔案已修改的部分全部加入到暫存區
    * 選e：只想送出部分修改到暫存區，會開啟一個編輯器
        * 將不想加入的部分，刪除後，離開即可
---

### 當前用戶信息
* 基礎指令：git **config** 
* 顯示當前使用的**所有 Git 配置**：git config --list
    * **當前倉庫**配置：git config **--local** --list 
    * **全局**配置：git config **--global** --list 
    * **系統範圍**配置：git config **--system** --list 
* 查看**當前用戶信息**： 
    * git config `user.name`
    * git config `user\.email`
* **全局配置用戶信息**：
    * git config **--global** `user.name`
    * git config **--global** `user.email`
* **全局**更改
    * git config --global `user.name` "Your Name"
    * git config --global `user.email` "your.email@example.com"
* **當前倉庫**更改
    * git config `user.name` "Your Name"
    * git config `user.email` "your.email@example.com"

##  分支基礎
### 常用指令
* git branch 查看分支
* git branch cat  新增分支 >> 名為cat
* git branch -m cat tiger 分支改名 >> 將分支名cat，修改成tiger
* git branch -M main 分支改名
* git branch -d tiger 刪除分支 >> 將分支 tiger刪除
    * 如果tiger 分支還沒有被完全合併，會出現提示訊息：The bracnh "tiger" is not fully merged
* git branch -D tiger 強制刪除分支
* git checkout  tiger 切換成tiger分支
* git checkout -b  sister 創建並切換成 sister 分支
___
### 概念：
1. 分支只是指向某一個Commit的指標(重要)
2. 分支只是指向某ㄧ個commit，刪除指標並不會讓commit消失 
3. 分支合併：合併「分支指向的那個Commit」=> 合併Commit(合併分支)
---
### git 切換分支
* 做了兩件事
    1. 更新暫存區、工作目錄：該分支會指向那個Commit的內容來更新，但在分支切換前所做的修改則還是會停留在工作目錄
    2. 變更HEAD位置
---
### git 如果調整到一半切換分支會發生什麼事情
 * 狀況：目前在tiger分支，修改index.html(modified)、增加cat3.html(Untracked)
* git checkout master
    * 確認 index.html的修改、cat3.html的增加是否還存在
    * 結果：index.html的修改、cat3.html的增加 都停留在工作目錄，不受分支切換的影響
* 使用 git stash 來暫存狀態，在切換分支
___
### git stash 暫存目前狀態
* 使用git stash
    * git stash -u 可以包括 untracked的狀態
* 還原暫存 git stash pop
* 瀏覽 git stash 列表 git stash list
    * 最後存的檔案會在最上面喲！也就是 stash{0}
* 清除最新暫存 git stash drop
    * 指定刪除的暫存 git stah drop stash{0} 刪除第一個暫存
* 清除全部暫存 git stash clear 
---
### git merge xxx 合併分支
* 狀況：master 合併tiger分支，目前tiger新增cat1.html\cat2.html
* 步驟：
    1. 切換成master分支：git checkout master
    2. 合併tiger分支：git merge tiger
* 合併後結果：master 分支增加cat1.html\cat2.html
* tiger 分支來自master，合併分支時 >> git會自動選用「快轉模式」合併
* 不使用快轉模式：git merge `--no-ff`  xxx
___
### git merge XX 合併分支-2
* 將tiger分支與dog分支合併
    * tiger分支與dog分支 來自master分支
    * git會產生一個額外的commit來處理
        * 這個commit會指向二個commit，標記來自哪兩個分支
* 步驟
    1. git checkout tiger
    2. git merge dog
        > Merge made by the 'recursive' stragtegy.
                 dog1.html   | 0
                 dog2.html   | 0 
        2 files changed, 0 insertions(+),0 deletion(-)
        create mode 100644 dog1.html
        create mode 100644 dog2.html
    3. 編輯合併的訊息(自動出現Vim編輯器)
    4. 離開編輯，完成合併
* tiger 會指向新的commit，內容來自dog分支
* Commit會指向cat跟dog分支
    * HEAD會隨著tiger分支前進，dog分支的HEAD停留在原地
---
### 取消分支合併
* 指令: git merge --abort
---
### 救回沒有合併的分支
* 目標：刪除tiger分支後，救回tiger分支
* 步驟：
    1. git branch -D tiger #刪除tiger分支，並提示是否要刪除未合併的分支(-d)
        * 紀錄刪除訊息：Deleted branch tiger (was 705804d).
    2. git branch new_tiger 705804d ＃建一個新分支，指向705804d這個commit
* 分支概念：分支只是指向某ㄧ個commit，刪除指標並不會讓commit消失 

### 另一種合併方式(rebase)
* git rebase：重新定義分支的參考基準
    * base：你這分支從哪裡生出來的
* rebase：等於修改歷史基礎    
* 組合 new_tiger 與 dog 分支 <font color="#9400d3"> ＃兩個分支的base都是master分支</font>
* 步驟：
    1. git checkout new_tiger
    2. git rebase dog <font color="#9400d3">#將dog分支當做我新的參考基準</font>
    >First, rewinding head to replay your work on top of it...
Applying: cat1 test1
Applying: cat2 test2
    3. 將new_tiger分支會接到dog分支上面
* rebase與merge的明顯差異：rebase合併分支的話，Ｇit不會特別做出一個專門用來合併的Commit

### Rebase 概念
* 流程圖
```mermaid
graph TD

A[b174a5]-->B[c68537]
C[28a76d HEAD\tiger]-->D[32bc96]-->E[053fb2 dog]-->F[b69eb6]
B-->G[e12d8e Master]-->H[XXXX]
F-->G
style A fill:#f6e6a1,color:#008000
style B fill:#f6e6a1,color:#008000
style G color:#f00
style E color:#f00
style C color:#f00
style D color:#007fff
```
* 說明
    1. 「先拿c68537這個commit接到053fb2這個commit上」，因為c68537的原本的上一層Commit是<font color="#f00">e12d8e</font>，現在要接到<font color="#f00">053fb2</font>上，需要<font color="#f00">重新計算</font>這個Commit(<font color="#008000">c68537</font>)的SHA-1值，重新計算的值是<font color="#007fff">32bc96</font>
    2. <font color="#008000">b174a5</font>要接到32bc96上面，重新計算的SHA-1值是<font color="#007fff">28a76d</font>
    3. 原本tiger是指向b17a5這個Commit，<font color="#9400d3">現在要改指向</font>最後做出來那一個新的Commit(<font color="#007fff">28a76d</font>)
* 舊的commit(b174a5\c68537)
    * 未立即被刪除，有一天會被git的回收機制處理掉
* 誰Rebase誰有差？
    * 會使commit的歷史順序不同

### 取消Rebase
1. 使用Reflog:查看紀錄
    1. git reflog 
    :::info
    bd578fa (HEAD -> new_tiger) HEAD@{0}: rebase finished: returning to refs/heads/new_tiger
    bd578fa (HEAD -> new_tiger) HEAD@{1}: rebase: cat2 test2
    54eb930 HEAD@{2}: rebase: cat1 test1
    92efbb7 (dog) HEAD@{3}: rebase: checkout dog
    705804d HEAD@{4}: checkout: moving from master to new_tiger 
    :::
    2. 發現到：705804d HEAD@{4}: checkout: moving from master to new_tiger <font color="#008000">=></font> <font color="#9400d3">做rebase前的最後動作</font>
    3. git reset 705804d --hard 回到rebase前的狀態
2. 使用ORID_HEAD
    * ORID_HEAD：特別紀錄點，會紀錄危險操作
    * 分支合併、Rebase都是「危險操作」
    * 步驟：
        1. git checkout dog
        2. git rebase new_tiger
        3. git reset <font color="#f00">ORIG_HEAD</font> --hard <font color="#9400d3">＃回到rebase前的狀態</font>
3. rebase發生衝突時，取消rebase
    * git rebase --abort

### 合併發生衝突的處理
* 需求：將new_tiger分支與dog分支合併
    * 針對各分支的index.html相同位置，做出調整，以便觸發合併衝突
* 步驟：
    1. git checkout new_tiger
    2. git merge dog <font color="#f00">#發生衝突</font>
        :::danger
        uto-merging index.html
        CONFLICT (content): Merge conflict in index.html
        Automatic merge failed; fix conflicts and then commit the result.
        :::
    3. git status
        :::info
        <font color="#000000">On branch new_tiger
        You have unmerged paths.
        (fix conflicts and run \"git commit\")
        (use \"git merge --abort\" to abort the merge)
        Changes to be committed:</font>
        <font color="#008000">new file:   dog1.html
          new file:   dog2.html</font>
        <font color="#000000">Unmerged paths:</font>
         <font color="#000000">(use "git add  &lt;file&gt; ..." to mark resolution)</font>
        <font color="#f00">both modified:   index.html</font>
        ::: 
    4. 分支衝突處理：<font color="#f00">對 index.html做內容選擇</font>，是要用new_tiger分支或dog分支的內容
    5. 處理完後：git <font color="#f00">add</font> index.html
    6. 完成分支合併：git commit `-m` "xxxx"
* git reset ORIG_HEAD `--hard`  <font color="#9400d3">＃解除merge合併</font>

### Rebase 衝突處理
* 需求：new_tiger 重新定義基準 git rebase dog
* 發生衝途：rebase過程會中斷
* 步驟：
    1. git checkout new_tiger
    2. git rebase dog <font color="#f00">#發生衝突</font>
        :::danger 
       <font color="#000000"> First, rewinding head to replay your work on top of it...
        Applying: cat1 test1
        Applying: cat2 test2
        Applying: TEST merge ERROR car
        Using index info to reconstruct a base tree...
           <font color="#f00">M       index.html</font>
        Falling back to patching base and 3-way merge...
        Auto-merging index.html
        CONFLICT (content): Merge conflict in index.html
           <font color="#f00"> error: Failed to merge in the changes.</font>
        Patch failed at 0003 TEST merge ERROR car
           <font color="#e6b800"> hint: Use 'git am --show-current-patch' to see the failed patch</font>
        Resolve all conflicts manually, mark them as resolved with
           <font color="#008000">"git add/rm &lt;conflicted_files&gt;"</font>, <font color="#007fff">then run "git rebase --continue".</font>
            You can instead skip this commit: run "git rebase --skip".</font>
           To abort and get back to the state before "git rebase", run "git rebase --abort".</font>
        :::
    3. 處理發生衝突的檔案：處理index.html
    4. 處理完後：git add index.html
    5. 繼續Rebase(完成)：git rebase --continue

### 非文字檔發生衝突（Merge）
* 狀況：new_tiger分支合併dog分支，各分支都有一個同名的圖片檔
* 步驟：
    1. git checkout new_tiger <font color="#f00">#發生衝突</font>
        :::danger
        <font color="#000000">warning: <font color="#f00">Cannot merge binary files: testimage.png </font>(HEAD vs. dog)
        CONFLICT (add/add): Merge conflict in testimage.png
        Auto-merging testimage.png
            Automatic merge failed; fix conflicts and then commit the result.        </font>
        :::
    2. git status
        :::info
        On branch new_tiger
        You have unmerged paths.
        (fix conflicts and run "git commit")
        (use "git merge --abort" to abort the merge)
        Changes to be committed:
        <font color="#008000">new file:   dog1.html
            new file:   dog2.html</font>
        Unmerged paths:
        (use "git add &lt;file&gt;..." to mark resolution)
        <font color="#f00">both added:      testimage.png</font>
        :::
    3. 選擇要使用new_tiger或dog分支的圖片
        * 使用new_tiger分支：git checkout <font color="#f00">--ours</font> testimage.png
        * 使用dog分支：git checkout <font color="#f00">--theirs</font> testimage.png
    4. 處理完後：git <font color="#f00">add</font> testimage.png
    5. 完成分支合併：git commit -m "xxxx"
    
### 從過去的某一個commit開啟分支
* 流程圖
```mermaid
graph TD
A[921fbb7f]-->B[4cbf089b]
C[705804d4]-->D[ab7eca6c]
B-->G[4f559e1b]-->H[bea0a519]-->I[0929fe29]
D-->G
style H fill:#f00
```
* 狀況：從bea0a519，開啟一個新分支
* 法一：
    1. 切換至bea0a519 Commit：git checkout bea0a519
    2. 建立切換至bird分支：git checkout -d bird
* 法二：git branch bird bea0a519
    
    
## 修改歷史紀錄
### 修改歷史訊息
* 需求：dbfccb4的訊息(cat) 調整
    * 訊息調整，<font color="#f00"> git會產生新的Commit來代替舊的</font>
* 步驟：
    1. git rebase -i a2e0040  <font color="#9400d3">＃選擇rebase的切入點</font>
    :::info
     <font color="#000000">  pick dbfccb4 cat
     pick d07dee5 dog1
   pick 0aaeb33 dog2 
           </font>
    :::
    2. 編輯跳出的視窗，使用reword指令
     :::info
    <font color="#000000">  <font color="#f00"> reword</font> dbfccb4 cat
     pick d07dee5 dog1
   pick 0aaeb33 dog2 
           </font>
    :::
    3. 離開Vim編輯後，開始進行Rebase，會跳出Vim來編輯新Commit訊息
        * 將cat  調整成 new cat 
    4. 存檔離開後，完成Commit的訊息調整
### 將多個Commit合併為一個Commit
* 流程圖
```mermaid
graph TD
A[639b2f8]-->B[ef30bbd]-->C[a91ced5]-->D[8b5ee11]-->E[b226606]-->F[a2e0040]
style A fill:#008000
style B fill:#008000
style C fill:#007fff
style D fill:#007fff        
style E fill:#007fff
```
* 將639b2f8和ef30bbd合併為一個commit、8b5ee11和b226606合併一個一個commit
    * 注意：互動模式的紀錄由上而下是從舊到新
* 步驟
    1. git rebase -i a2e0040  <font color="#9400d3">＃選擇rebase的切入點</font>
        :::info
         <font color="#000000">pick b226606 cat1
        pick 8b5ee11 cat2
        pick a91ced5 edd1
        pick ef30bbd dog1
             pick 639b2f8 dog2 
               </font>
        :::
    2. 編輯跳出的視窗，使用squash指令
        :::info
         <font color="#000000">pick b226606 cat1
             <font color="#f00">squash</font> 8b5ee11 cat2
             <font color="#f00">squash</font> a91ced5 edd1
        pick ef30bbd dog1
             <font color="#f00">squash</font> 639b2f8 dog2 
               </font>
        :::
    3. 上面的修改會發生下列的事
        1. 639b2f8會跟前一個Commit ef30bbd 合併 
        2. a91ced5跟 8b5ee11合併，再跟前一個Commit b226606 合併
    4. 離開Vim編輯後，開始進行Rebase，會跳出Vim來編輯新Commit訊息
        * 有兩個合併Commit的操作，需要做兩次的Commit的訊息編輯(編輯第一個Commit訊息)
        * 編輯Commit的訊息 >> Git會產生新的Commit來代替舊Commit
* 新流程圖
```mermaid
graph TD
A[4984b96]-->B[dbfccb4]-->C[a2e0040]
style A fill:#008000
style B fill:#007fff
```  
* b226606\8b5ee11\a91ced5 合併後的commit => dbfccb4
* 639b2f8\639b2f8 合併後的commit => 4984b96
    
###  將一個Commit拆解成多個Commit
* 需求：拆解4984b96這個Commit
* 步驟：
    1. git rebase -i a2e0040 <font color="#9400d3">＃選擇rebase的切入點</font>
    :::info
    <font color="#000000"> pick dbfccb4 cat
        pick 4984b96 dog</font>
    :::
    2. 編輯跳出的視窗，使用edit指令 
    :::info
    <font color="#000000"> pick dbfccb4 cat
        <font color="#f00">edit</font> 4984b96 dog</font>
    :::
    3. 拆Commit：git reset HEAD^  <font color="#9400d3">＃當前HEAD的位置是在4984b96這個Commit</font>
    4. 發現 dog1.txt\dog2.txt，拆出<font color="#008000">是放在工作區</font>且<font color="#007fff">Untracked狀態</font>
    5. 將上面這兩個檔案分別Commit
    6. 繼續rebase(完成)：git rebase --countinue
    
### 在某些Commit之間再加新的Commit
* 需求：在b6a5fbd(dog1)跟dbfccb4(cat)這兩個Commit之間，在多增加兩個Commit
* 步驟：
    1. git reabse -i a2e0040 <font color="#9400d3">＃選擇rebase的切入點</font>
    :::info
    <font color="#000000">  <font color="#9400d3">pick dbfccb4 cat</font>
        <font color="#9400d3">pick b6a5fbd dog1</font>
  pick fd3cf39 dog2</font>
    :::
    2. 編輯跳出的視窗，使用edit指令 <font color="#9400d3">＃需停在dbfccb4 cat</font>
    :::info
    <font color="#000000">  <font color="#f00">edit</font> dbfccb4 cat
  pick b6a5fbd dog1
  pick fd3cf39 dog2</font>
    :::
    3. 添加兩份檔案，並分別Commit
    4. 繼續rebase(完成)：git rebase --countinue
### 調整Commit順序
* 將1b632fb(dog1)\6060645(dog2)移動至dbfccb4(cat)後面
* 步驟：
    1. git rebase -i a2e0040 <font color="#9400d3">＃選擇rebase的切入點</font>
        :::info
        <font color="#000000">  pick dbfccb4 cat
         pick 8ca3152 edd1
         pick 6060645 dog1
         pick 1b632fb dog2</font>
        :::
    2. 編輯跳出的視窗，調整Commit順序
    <font color="#000000">  pick dbfccb4 cat
      <font color="#f00">  pick 6060645 dog1
      pick 1b632fb dog2</font>
   pick 8ca3152 edd1</font>
    3. 存檔離開後，完成Commit順序調整
### 刪除某些Commit
*  需求：刪除有dog訊息的Commit
* 步驟：
    1. git reabse -i a2e0040 <font color="#9400d3">＃選擇rebase的切入點</font>
        :::info
        <font color="#000000">  pick dbfccb4 cat
        pick bd27a88 dog1
        pick 3206c6d dog2
        pick 82ab1ab edd1</font>
        :::
    2. 編輯跳出的視窗，使用<font color="#008000">drop指令</font>或<font color="#007fff">刪除該行</font>
        :::info
        <font color="#000000">  pick dbfccb4 cat</fon> 
        <font color="#000000"> drop 3206c6d dog2</font>
        pick 82ab1ab edd1</font>
        :::
    3. 存檔離開後，完成Commit的刪除
### Revert 指令
* 概念：做一個新Commit，來取消不要的Commit
* 需求：取消最後這次的Commit(dog3)
    * git revert HEAD --no-edit
* 取消Revert
    * 法ㄧ：再開一次revert >> git revert HEAD --no-edit
    * 法二：使用reset >> git reset HEAD^ --hard
### 什麼時候使用Revert
* 使用時機：多人協作專案
    * 團隊的開發政策，可能無法使用reset
    * 使用Revert指令做出一個「取消」的操作，對其他人來說不算是「修改歷史」，而是新增一個Commit 
* Reset\Rebase\Revert 差別
    
| 指令 | 改變歷史紀錄 | 說明 |
| -------- | -------- | -------- |
| Reset    | 是   | 把⽬前的狀態設定成某個指定的 Commit 的狀態，通常適⽤於尚未推出去的 Commit。     |
| Rebase     | 是     | 不管是新增、修改、刪除 Commit 都相當⽅便，⽤來整理、編輯還沒有推出去的 Commit 相當⽅便，但通常也只適⽤於尚未推出去的 Commit。    |
| Revert     | 否     | 新增⼀個 Commit 來反轉（或說取消）另⼀個 Commit 的內容，原本的Commit 依舊還是會保留在歷史紀錄中。雖然會因此⽽增加 Commit 數，但通常比較適⽤於已經推出去的 Commit，或是不允許使⽤ Reset 或   Rebase 之修改歷史紀錄的指令的場合。  |
## 標籤 Tag
### 使用標籤
* 標籤：「標籤（tag）」是⼀個指向某⼀個 Commit 的指標。
    * 當做貼紙⼀樣看待，它就是貼在某個 Commit上的東⻄。
* 什麼時候使用標籤？：通常在開發軟體有完成特定的⾥程碑，例如軟體版號 1.0.0 或是 beta-release 之類的，這時候就很適合使⽤標籤做標記。
* 有兩種標籤：
    * 輕量標籤（lightweight tag）=> 個⼈使⽤或是暫時標記⽤途
    * 有附註標籤（annotated tag）=>  是軟體版號之類的⽤途
    * 差異：訊息量的不同
    * 展現標籤訊息指令： git show  <font color="#996b1f"> 標籤名</font> <font color="#9400d3">=></font> git <font color="#f00">show</font>  <font color="#996b1f"> big_cats</font>
    
#### 輕量標籤（lightweight tag）
* 概念：為輕量標籤僅是⼀個指向某個 Commit 的指標， <font color="#f00"> 沒有含有其
    它的資訊</font>， <font color="#9400d3">所以 Git 比較推薦使⽤有附註的標籤（annotated tag）</font>。
* 需求：在44e9fe1(add lion and tiger)上，打上一個big_cats的標籤
    * 指令：git  <font color="#f00"> tag</font> <font color="#996b1f">  big_cats</font> <font color="#008000">44e9fe1 </font>
* git歷史紀錄 git log --oneline
    :::info
    <font color="#000000">  9c5fd18 (HEAD -> master) add fish 1
    e62a0b0 add pig1
        <font color="#f00">44e9fe1 <font color="#996b1f"> (tag: big_cats)</font> add lion and tiger</font>
        1683520 dog3</font>
    :::
#### 有附註標籤（annotated tag）
* 需求：在e62a0b0(add pig1)上，打上一個big_pigs的標籤，並加上訊息 "Big Pigs are comming"
    * 指令：git <font color="#f00">tag</font> <font color="#996b1f"> big_pigs </font><font color="#008000"> e62a0b0</font> <font color="#f00">-a -m "Big Pigs are comming" </font>    
        * -a：請 Git 幫你建立有附註的標籤
        * -m：在做⼀般的 Commit ⼀樣輸入的訊息

#### 刪除標籤
* 需求：刪除<font color="#996b1f"> big_cats</font>這個標籤
    * 指令：git tag <font color="#f00">-d</font> <font color="#996b1f"> big_cats </font>
        * <font color="#f00">-d</font>：刪除標籤
        * 刪除後訊息： Deleted tag 'big_cats' (was 44e9fe1)
    
## 其它常見狀況題與冷知識
### ⼿邊的⼯作做到⼀半，臨時要切換到別的任務
* 法一：Commit目前進度
    * 步驟：
        1. git add --all
        2. git commit -m "not finish yet"
        3. git reset HEAD^
* 法二：使用Stash
    * 目前new_tiger分支狀態 git status
        :::info
        <font color="#000000">  On branch new_tiger
            Changes not staged for commit:
      (use "git add &lt;file&gt;..." to update what will be committed)
      (use "git restore &lt;file&gt;..." to discard changes in working directory)
           &emsp; <font color="#f00">modified:   cat1.hml
           &emsp; modified:   cat2.hml
            &emsp; modified:   index.html</font>

        no changes added to commit (use "git add" and/or "git commit -a")</font>
        :::
    * 步驟：
        1. git <font color="#f00">stash</font>  <font color="#9400d3">#將上述檔案的修改先「存」起來</font>
            * <font color="#008000">Untracked 狀態</font>的檔案 <font color="#9400d3">沒有辦法被Stash</font>， <font color="#f00">需要額外使用 -u 參數</font>
        2. git status 確認狀態
            :::info 
            <font color="#000000"> On branch new_tiger
                nothing to commit, working tree clean</font>
            :::
    * 檔案存到那邊去？
        * git stash --list
             * stash@{0}: WIP on new_tiger: fe4d60e TEST
             * stash@{0} 是這個Stash的代名詞
* 撿Stash回來用
    1. 確認目前Stash 列表 git stash --list
    2. git stash <font color="#f00">pop </font>stash@{0}
        * pop：將stash@{0}拿出來，套用在目前的分支上，並將剛套用過的Stash刪除
        * 如果沒有指定套用的Stash，會從編號最小的開始
* 刪除Stash：git stash <font color="#f00">drop</font> stash@{0}
* 套用Stash：git stash <font color="#f00">apply</font>  stash@{0}
* 套用＋刪除Stash：git stash <font color="#f00">pop </font>stash@{0}
        
### 去除某一個檔案 filter-branch
* 需求：去除config/daatbase.yml
* 使用filter-branch：git filter-branch --tree-filter "rm -f config/daatbase.yml"   

### 回復剛剛filter-branch 造成的結果
* 指令：git reset refs/original/refs/heads/master --hard   
    
### 撿別的分支的Commit過來合併  cherry-pick
* 概念：不是將原有的Commit剪過來貼上，而是比較像是複製Commit的內容過來
    * 接到new_tiger的內容需要重新計算，產生新的Commit
    * 原本fish分支的Commit不會有變化，還是在原來的地方
        * 需求：挑選fish分支的<font color="#008000">62451b2(add whale)</font>和<font color="#007fff">38d07c7(dd dolphin)</font>，合併至new_tiger分支
        * 指令：git <font color="#f00">cherry-pick</font> 38d07c7 62451b2
        
### 撿過來但不先合併
* 需求：撿過來的Commit，<font color="#f00">先放置在暫存區</font>
* 添加 <font color="#f00">--no-commit</font>參數：git cherry-pick <font color="#f00">--no-commit</font> <font color="#008000">38d07c7  </font>
        
### 怎麼樣把檔案真正的從 Git 裡移掉
* 需求：完全刪除config/database.yml
* 步驟：
    1. 添加 <font color="#f00">-f參數</font>： git filter-branch <font color="#f00">-f </font>--tree-filter <font color="#9400d3">"rm -f config/database.yml"</font>
    2. 處理資源回收的事項
        1. rm .git/refs/original/refs/heads/master
            * 清除備份點
        2. git reflog expire --all --expire=now 
            * 要求 Reflog 現在立刻過期（不然預設要等 30 天）
        3. git fsck --unreachable
            * 看到很多 Unreachable 的物件
        4. git gc --prune=now
            * 啟動 Git 的資源回收機制
    3. 檢查⼀下是否都清除  git fsck
        :::info
        <font color="#000000">Checking object directories: 100% (256/256), done.
            Checking objects: 100% (16/16), done.</font>
        :::
### 本地分支更名 to 遠端分支
* 前提：**確認該分支本地是否有或為最新**
* 步驟：
    1. 本地分支更名：`git branch -m oldName newName`
    2. 刪除遠端分支：`git push --delete origin oldName `
        * 或至gitlab\gitHub 將遠端分支刪除
    3. 將更名後的分支推上：`git push -u origin newName`

### 遠端分支更名 to 本地分支更名
* 步驟： 
    1. 本地分支更名：git branch -m oldName newName
    2. 設定目前分支的上游分支：git branch **-u** origin/dev
    

        
### 遠端倉庫-操作
* 查看當前遠程倉庫：git remote **-v**
* 添加倉庫：git remote **add** \<remote_name> \<remote_url>
* 刪除倉庫：git remote **remove** \<remote_name>
* **調整**：
    * **倉庫名**(`remote_name`)：git remote **rename** \<old_name> \<new_name>
    * **倉庫**(`remote_url`)：git remote **set-url** \<remote_name> \<new_remote_url>
 
 
### 修改舊有的commit
* 使用 **rebase**
* **情境**：當前有3個commit 需要 **對第一個commit** 增加\修改內容
    * **commit**：
        * **abc123** - 第一個提交
        * def456 - 第二個提交
        * ghi789 - 第三個提交（`最新的提交`）
    * 向第一個提交 `abc123` 增加内容
* 步驟：
    1. git rebase -i HEAD~**3**
        * HEAD~3 表示對最近 3 個提交進行變基。
    3. 編輯**目標**提交
        * 編輯器會開啟一個**commit列表**，顯示以下內容：
            ```
            pick abc123 First commit
            pick def456 Second commit
            pick ghi789 Third commit
            ```
        * 將第一個commit **pick** 改為 **edit**  
            ```
            edit abc123 First commit
            pick def456 Second commit
            pick ghi789 Third commit
            ```
            *  **pick** abc123 First commit => **edit** abc123 First commit
        * **儲存並退出編輯器**
    3. **修改第一個提交**：
        * rebase將**暫停在第一個提交**，終端將提示類似以下信息
            ```
            Stopped at abc123... First commit
            You can now amend the commit.
            ```
        * **添加修改**：git add  \<file1\> \<file2\> 
        * **提交修改**：使用 **--amend** 選項
            * `git commit --amend`
    4. **繼續rebase**：git rebase `--continue`
    5. **循環 3/4的操作**，直到rebase完成
    6. 强制推送（如果已推送到遠端）：git pusg -f
* **中斷**：`git rebase --abort`

### origin/dev被rabase或force push後的處理
* 情境：
    * `dev分支`被rabase或force push
    * 當前有`f1` \ `f2`分支從`dev分支`中**切出**
* 說明：
    * 本地的 `dev` 已經跟遠端歷史**不再共享共同祖先** (diverged)
    * 因此你必須重設它，並且讓下游分支（`f1`, `f2`）**重新 rebase 到新的 dev 上**
* 作法：`f1` \ `f2`分支要手動 rebase 到新的基準(base)上
    * 每個對應的分支都要個別手動調整
* 步驟：
    1. **更新遠端資訊**
        * git fetch origin
    2. rebase `f1分支`
        * git **checkout** `f1`
        * git **rebase** `origin/dev`
    3. rebase `f2分支`
        * git **checkout** `f2`
        * git **rebase** `origin/dev`
    4. 處理dev
        * git **checkout** dev
        * git **reset** --hard `origin/dev`
            * 把本地的`dev分支`**強制重設**成跟`遠端的dev`**一模一樣**
    5. 處理`f1` \ `f2`分支的遠端 => rebase強制推送
        * git push -f origin f1
        * git push -f origin f2
        * 若擔心風險，可以在 rebase 前備份：
            * git branch backup/f1 f1
            * git branch backup/f2 f2
### 本地分支與遠端分支有衝突
* **遠端分支為主**，二種方式：
    * git pull `--rebase`
        * **底層邏輯**：
            1. 將本地commit暫時移除
            2. 拉取遠端最新的commit
            3. 把本地commit套用在最新的遠端上
        * 需要處理衝突
    * git pull origin \<brancj-name
        * 將遠端分支的commit merge到本地，**產生一個新的merge commit**
* **本地分支為主**，強推
    * git push -f
## git config 常見設定
* 使用者資訊
    * git config --global user.name "你的名字"
    * git config --global user.email "你的信箱"
* 編碼設定
    * git config --global i18n.commitEncoding utf-8
    * git config --global i18n.logOutputEncoding utf-8
* 編輯器設定
    * 使用 git commit 時會開啟 VSCode 編輯 commit 訊息
        * git config --global core.editor "code --wait"
*  憑證儲存方式
    *  git config --global credential.helper store     # 儲存純文字憑證
    *  git config --global credential.helper cache     # 暫存憑證（預設 15 分鐘）
    *  git config --global credential.helper manager   # Windows 使用者
    *  git config --global credential.helper osxkeychain  # macOS 使用者
*  顯示log美化
    *  git config --global alias.lg "log --oneline --graph --decorate --all"
*  設定換行符號（跨平台）
    *  git config --global core.autocrlf input   # macOS / Linux
    *  git config --global core.autocrlf true    # Windows

###### tags: `Git`
