--- title: 'Git 使用 - 遠端' disqus: kyleAlien --- Git 使用 - 遠端 === ## OverView of Content 參考該[**文章**](https://zlargon.gitbooks.io/git-tutorial/content/branch/),並實做,並依序 Git 使用 - 基礎 [TOC] ## 分支 - branch 一直以來我們都是在一個叫 **master** 的分之上提交 Patch,以下我們新增一個檔案並且重新建立 Git,它就會提示我們目前在 master 上 * **初始化 Git init 時,分支 master 也會被創建出來** ```shell= git init git status ``` > ![](https://i.imgur.com/fOE42fc.png) * 分支的功能在於,**任何的 Patch 都可以有自己的分支**,我們**可以新增刪除分支,並且平行開發不會相互引響**,**分支修正完成後還可以合併回 master 主分支**,想要簡單測試時也可以迅速分支出來,==以下是 commit tree 的概念圖== > ![](https://i.imgur.com/feNCOaf.png) ### 查看分支 - branch * **指令式**、**UI 圖形界面**查詢兩種 1. 指令式 ```shell= # 查看目前分支 git branch ``` 可以看到目前分支在 master 上 > ![](https://i.imgur.com/a8OvczE.png) 2. Gitk 圖形 UI 圖形界面 **Gitk 是內建於 git 的圖形化界面工具**,有一些版本當安裝好 git 時它就存在了,而也一些需要使用指令另外安裝 ```shell= # 安裝 gitk 指令 sudo apt install -y gitk # 背景執行 gitk gitk --all & ``` > ![](https://i.imgur.com/UxyoaM2.png) :::danger 當你提交新的 Patch 時 Gitk 並不會自己更新,必須要使 `F5` 刷新界面 ::: ### 建立/切換/刪除分支 | 指令 | 功能 | | -------- | -------- | | git branch | 查看所有的分支 | | git branch <new branch name\> | **建立** 新的分支 | | git checkout <branch name\> | **切換** 分支 | | git checkout -b <new branch name\> | **建立 & 切換**分支,**將兩個動作和為一個指令** (滿好用的) | | git checkout -b <new branch name\> <commit_id\> | **功能同上,但是可以另外指定 Patch id,在該 Patch 上建立** (滿好用的) | | git branch -f <branch name\> <commit_id\> | f 是 force 強制的意思,**在指定的 patch 上建立 branch**,若該 branch 以存在則切換過去(轉換 branch) | | git branch -D <branch name\> | **刪除** 指定分支,**不能在要刪除的分支上** | 1. **git branch <new branch name\>** 建立新的分支 ```shell= # 建立新分支,取名為 bugFix git branch bugFix # 查詢全部分支 git branch ``` > ![](https://i.imgur.com/FgQBcP8.png) 2. **git checkout <branch name\>** 切換分支 ```shell= # 切換分支 git checkout fixBug ``` 使用 `Shift + F5` 刷新 Gitk 界面,會發現 **bugFix 變粗體字**(有點不明顯) > ![](https://i.imgur.com/BAYj76p.png) 3. 在新的分支,提交新的 Patch ```shell= git status # 新增檔案 git add myDebug.d # 新分支上提交新 Patch git commit -m "add File of myDebug.d" # 查看 log git log --oneline ``` 在 log 中可以看到 HEAD 已經移動到 bugFix,Gitk 字體轉為粗體並且 **目前所在的分支節點會呈現黃色點** > ![reference link](https://i.imgur.com/RePpyLw.png) 4. 在 fixBug 再次提交新的 Patch,最後移動回 master 分支上並做提交 ```shell= # fixBug 分支上提交,使用分號 `;` 連續做多種不同的動作 touch boy.txt; git add boy.txt; git commit -m "add boy.txt File" # 移動分支到 master 上 git checkout master # 創建、新增並提交新的 Patch 在 master 中 touch eye.txt; git add eye.txt; git commit -m "add eye.txt File" touch nose.txt; git add nose.txt; git commit -m "add nose.txt File" ``` 這樣就可以從 gitk 中看出分支的差異 > ![](https://i.imgur.com/9FWxK9q.png) 5. **git checkout -b <branch name\>**,創建分之並切換 ```shell= # 查看所有的分支 git branch # 新增分支並切換 git checkout -b feature # 查看結果 git branch ``` > ![](https://i.imgur.com/0BXVopU.png) 6. **git branch -f <branch name\> <commit_id\>**,在指定 Patch 上新增分支 ```shell= # 在 `add Alien in num.txt` 上建立新的分支,該分支上的 id 為 29d7d18 git branch -f tmp 29d7d18 # 查看指定分支上的 log (查看 tmp 分支上的 log 訊息) git log tmp --oneline # 移動 tmp 分支到 `add Pan in num.txt` git branch -f tmp 2acb117 ``` > ![](https://i.imgur.com/QaA4hOo.png) 7. git branch -D <branch name\> 刪除分支 ```shell= # 刪除 tmp 分支 git branch -D tmp ``` > ![](https://i.imgur.com/iPhZ6zs.png) ### Patch 的表示法 **要先了解到 ==branch & HEAD 是可以分開的==,我們可以單獨移動 `HEAD` or `Branch`** :::success * Patch 的表示法 1. commit ID (指定) 2. HEAD 代表目前所在的 Patch (以 HEAD 來相對比較出 Patch) 3. Branch Name (該 branch 最後的 Patch) 4. 在 HEAD or Branch Name 後面加上 ^ or ~n 來表示相對位置 ::: | 指令 | 描述 | | -------- | -------- | | git checkout <commit_id\> | **移動 HEAD 的位置** | 1. git checkout <commit_id\> 移動 HEAD 位置;[**HEAD**](https://hackmd.io/VY9jmfpMSySSKdPWQsigpg?view#HEAD-%E9%97%9C%E9%8D%B5%E5%AD%97) 代表目前所在 patch 的位置(點) 大部分 HEAD 都會和某個 branch 重疊在一起(像是 master 分支),但仍然可以單獨移動 HEAD 的 ```shell= # 移動 HEAD git checkout 29d7d18 # log git log --oneline # 查看所有的 branch git branch ``` > ![](https://i.imgur.com/PY6soLi.png) 原來的 branch 並未移動,並且會提醒目前 HEAD 所在的 Patch ID 在哪裡 > ![](https://i.imgur.com/JppQXXB.png) :::info * 之前使用 **reset --hard <commit_id\> 指令其實改變了 master 分支位置**,**使用 checkout <commit_id\> 指令可以讓 HEAD 脫離 master 任意移動到其他 Patch 之上** ::: 2. 使用 [**amend**](https://hackmd.io/VY9jmfpMSySSKdPWQsigpg?view#%E4%BF%AE%E6%94%B9%E3%80%81%E8%A8%82%E6%AD%A3-Patch) 修改目前 HEAD 的提交標題,在查分支 & log 狀況 ```shell= # 改變目前所在的 Patch 標題描述 git commit --amend -m "Fix By checkout, Add Alien in num.txt" # 查看 branch git branch # log git log --oneline ``` **使用 amend 後多了一個新的 Patch ID (尚未有分支,下面步驟會在創建一個分支給這次的修改)** > ![reference link](https://i.imgur.com/KXzVQUF.png) 3. [**cherry-pick**](https://hackmd.io/VY9jmfpMSySSKdPWQsigpg?view#%E7%A7%BB%E9%99%A4%E5%96%AE%E5%80%8B-Patch) 一個 Patch 進來 ```shell= # 使用 branch Name 作為相對位置,並移動到剛剛 amend 的檔案 git cherry-pick bugFix^ git log --oneline ``` > ![](https://i.imgur.com/AHWCPuq.png) 4. 使用 git checkout -b <new branch name\> (**建立 & 切換**分支,**將兩個動作和為一個指令**) ```shell= # 建立新分支 git checkout -b testCheckout ``` > ![](https://i.imgur.com/1ngU6de.png) ### 創建 branch 資料夾 * 前面有說到單獨創建 branch 分支,而我們可以針對 branch 開新的資料夾,並在該資料夾之下創建分支 ```shell= # git branch <資料夾>/<分支名> # 在 TEST 資料夾下創建 Hello 分支 git branch TEST/Hello git branch -v ``` > ![](https://i.imgur.com/BLntfH5.png) ### 合併分支 cherry-pick、merge、rebase * 合併分支有幾種方式 | 方式 | 描述 | | -------- | -------- | | **cherry-pick** | 一個一個移動,實際上來說它並不算是合併 | | **rebase** | 充新定義分支的基準點,**git rebase <主要分支\> <將要被合併分支\>,要特別注意是 ==誰 rebase 誰==** | | **Merge** | **切換到 要合併的分支,再使用 git merge <將要被合併分支\>,會保有原本 branch 資訊** | 1. 新增檔案到 bugFix 分支 ```shell= # 切換分支到 bugFix git checkout bugFix # 新增檔案並提交 echo "Fix Finish" >> boy.txt ; git add -u; git commit -m "Fix Big Finish" # log git log --oneline ``` 這是目前的分支 > ![](https://i.imgur.com/fSSi2vB.png) 2. **使用 cherry-pick** 把 bugFix 分支中所有的 Patch 移動到 master 分支上 ```shell= # 查看分支上所有的 ID git log --oneline # 切換回 master 分支 git checkout master # 分別取出 cherry-pick,從舊的加到新的 git cherry-pick 8c46944 f872c4f 8972ed4 ``` 使用 cherry-pick 一個一個移動 > ![](https://i.imgur.com/qOQxTso.png) 3. **使用 rebase 真正的合併分支到主分支**(它會整理分支並合併,不會留下原本分支) :::success * rebase 作為一個犧牲者~ 由它自己來決定要合併進去的分支,合併完後自己的分支就不復存在 ::: ```shell= # 移動 branch 到 bugFix 分支 git checkout bugFix # 將 bugFix 分支合併到 master 之後 git rebase master # 上面兩行可以改為一行,master 接續 bugFix # git rebase master bugFix git log --oneline # 查看目前分支狀況 git branch ``` * 結果圖 1 > ![](https://i.imgur.com/pTZo0dH.png) * 結果圖 2 可以從 log 中看到 fixBug 全部移動到 master 之後了 > ![](https://i.imgur.com/QRXyW6w.png) :::success * 也可以合併部份的 Patch 而不是整個分支 ```shell= git checkout bugFix # 把 bugFix 的所有 Patch 掛到 master 前一個節點的後面 git rebase master^ ``` ![](https://i.imgur.com/iWnBHWT.png) ::: ## 遠端設定 以下將會使用 GitHub 作為範例,所以必須要先有 [**GitHub**](https://github.com/) 帳號 ### GitHub 新增專案 * 新增專案 1. 按右上角的 +,選擇 New repository > ![](https://i.imgur.com/VIxDLsG.png) 2. 輸入 Repository name 也可以輸入一些描述 3. 這裡 **先不要** 勾選 "Initialize this repository with a README" 4. 點擊 Create repository 就會創建出一個新專案了 > ![](https://i.imgur.com/5Xj30VP.png) 5. 創建出專案後可以看到它有**兩種連線方式 SSH、Https 兩者是使用不同的加密協定**,也可以看到下方有提示如何操作該倉庫的指令 > ![](https://i.imgur.com/dzoWyWx.png) :::info * SSH、Https 兩種連線的差異在 Https 每一次連線都需要輸入一次 username、password,而 SSH 則不需要,以下示範 SSH 連線的方式 ::: ### 本地 SSH 設定 * 在 Ubuntu 中 ssh 通常會在用戶的主資料夾中 ~/.ssh (隱藏資料夾),在該資料夾下生成 rsa 非對稱加密的 key,[**rsa**](https://hackmd.io/M5PlGj6_TEiHok7IK5A2LA?view#Https-%E8%AB%8B%E6%B1%82%E9%81%8E%E7%A8%8B) 是**非對稱加密,會有兩把 key(公鑰、私鑰),使用公鑰加密、私鑰解密** ```shell= # 移動到 .ssh 資料夾 cd ~/.ssh # 生成 rsa 非對稱加密的兩把 key ssh-keygen -t rsa ``` 使用 `man ssh-keygen` 可以查看到如何生成 rsa key > ![](https://i.imgur.com/WrMLwJX.png) 生成 key 的過程中沒有特別設定就一直按 enter 就好,之後就會在該資料夾下生成公鑰、私鑰,如果之前生成 rsa key 過則會被覆蓋 > ![](https://i.imgur.com/yKjzO8v.png) ### 遠端連線 * 在 GitHub 上設定公鑰,公鑰是每個人都可以取得的,但是單單有公鑰也無法解開通訊加密,所以可以公佈在 GitHub 上 `Setting` -> `SSH and GPG keys` -> `New SSH key` > ![](https://i.imgur.com/hxZDRh3.png) * 使用 cat 查看剛剛生成的 `id_rsa.pub` **公鑰,==私鑰不可以給別人==**,複製到 key 欄位並點擊 Add SSH key 儲存 > ![](https://i.imgur.com/34RoH6T.png) * 測試 SSH 連線 ```shell= ssh -T git@github.com ``` 可用 `man ssh` 查看 T 的操作 > ![](https://i.imgur.com/DSN9B6S.png) :::info 第一次連線它會出現無法辨別主機真實性,輸入 yes 不用特別在意 > ![](https://i.imgur.com/6wJFgcD.png) ::: ## 遠端操作 ### 設定 URL - remote * 在上面新增專案後,底要有一個提示要如何使用指令 push 到倉庫中,其中就使用到了 **remote** > ![](https://i.imgur.com/z6C3qWr.png) | 指令格式 | 功能 | | -------- | -------- | | git remote add <name\> <repo_url\> | 新增遠端 url 指令,並為此 url 取別名 | | git remote -v | 看所有的 remote url | | git remote rename <目標名稱> <新名稱> | 修改之前取的名稱 | | git remote remove <目標名稱> | 移除 url | 1. 新增 url,url 可以是本地的地址,也可以有多個 url ```shell= # 新增遠端 url git remote add helloGitHub git@github.com:kyle861550/Hello_GitHub.git # 查看 git remote -v ``` > ![](https://i.imgur.com/p8tb76t.png) 2. 修改名稱 rename ```shell= # 改 url 別名為 gitHub git remote rename helloGitHub gitHub # 查看 git remote -v ``` > ![](https://i.imgur.com/0w7zHlu.png) 3. 刪除 remove ```shell= # 新增一個本地 url git remote add local ~/桌面/EnjoyGit/ # 查看 git remote -v # 移除 git remote remove local # 查看 git remote -v ``` > ![](https://i.imgur.com/7uIyYhI.png) ### 上傳分支 - push * Git 在上傳程式碼到 server 時,**必須是以==分支為單位==** | 指令格式 | 功能 | | -------- | -------- | | git push <url 別名> <分支名稱> | 上傳分支 (不須 checkout 到指定分支上傳) | | git branch -a | -a 也就是 --all,可以查看所有的分支,**包括遠端分支** | | git log <分支名稱> | 可以透過 log 指令查看指定分支的 log(包括遠端) | 1. 上傳分支 **git push <url 別名> <分支名稱>**,指定我們剛剛建立的 url 別名,還有需要上傳的分支 ```shell= # 上傳 master 分支 到 gitHub(url 別名) 倉庫 git push gitHub master # 查看所有的分支 git branch -a # 查看遠端 log git log remotes/gitHub/master --oneline ``` 查看分支實會看到遠端分支(紅色字),如果遠端沒有 master 這個分支時就會自己新增 >![](https://i.imgur.com/mkpklHc.png) 網頁重整就可以看到 master 分支 > ![](https://i.imgur.com/vfriT5W.png) 在 gitk 這個 UI 界面也可以看到遠端分支,遠端分支的內容會與 server 上的內容一致 > ![](https://i.imgur.com/HyNONcL.png) 查看遠端分支 log > ![](https://i.imgur.com/lNIaRZw.png) 2. 上傳分支 bugFix 分支(我刪除了舊的合併 bugFix 分支,並且建立新的 bugFix 分支,該分支建立在某個 Patch 上) ```shell= # 上傳 bugFix 分支 git push gitHub bugFix # 查看所有的分支 git branch -a ``` 上傳前後在 gitk 的比較 > ![](https://i.imgur.com/jSZC7GC.png) 網站刷新後就會看到新的 branch > ![](https://i.imgur.com/cUe7YzE.png) 3. **更新 master branch**,先更新本地端的 master 分支(新增 Patch) ```shell= # 切換分支 git checkout master # 查看分支 git branch # 查看 master 分支 log git log --oneline # 修改 boy.txt 檔案並提交 Patch echo "YoYo" >> boy.txt; git add -u; git commit -m "Update boy.txt File" # 上傳更新 master 分支 git push gitHub master ``` 前後對比上傳前後遠端的差異 > ![](https://i.imgur.com/7S8Irbw.png) ### 追蹤遠端 - set-upstream * 參數 `-u` 等同於 `--set-upstream`,**設定 upstream 可以使分支開始追蹤遠端分支**,使用 git status 時就會 Git 就會比較遠端 & 本地的 commit 差異 :::info 只需要一次 git push -u <遠端分支名> <本地分支名> 成功後,之後只需要使用 git push 就可以直接上傳分支 ::: | 指令 | 功能 | | -------- | -------- | | git push -u <url\ 別名> <本地分支名> | 上傳並設定分支 upstream | | git branch -u <url\ 別名>/<遠端分支名> | 設定遠端 upstream,**使用 git status 會顯示追蹤的訊息** | | git branch --unset-upstream | 取消追蹤遠端分支 | 1. **git push -u <遠端分支名> <本地分支名>**,遠端分支名 可以使用 remote -v 查詢 ```shell= # stream 設定 and 上傳 git push -u gitHub master # 同上功能 git push --set-upstream gitHub master # 切換到 master git checkout master # 上傳 git push ``` > ![](https://i.imgur.com/thSWmqR.png) 2. **git branch -u <url 別名>/<遠端分支名>**,設定遠端 upstream,git status 就會改變 ```shell= git checkout master # stream 設定到 gitHub/master 分支 git branch -u gitHub/master git status ``` > ![](https://i.imgur.com/tCBOS9i.png) :::info * git branch -u gitHub/master master 可以合併指令,這樣就不用切換到 master 分支去操作 * `Your branch is up to date with 'gitHub/master'` 代表本機端的 master 與遠端的內容分支一致 ::: 3. 本地新增移除 Patch,讓遠端 master & 本地 master 發生差異 ```shell= git checkout master # 本地新增 Patch touch localPatch_1; git add .; git commit -m local_Patch_1 git status git log --oneline ``` `Your branch is ahead of 'gitHub/master' by 1 commit` 代表目前本地分支領先遠端 gitHub/master 分支一個 Patch > ![](https://i.imgur.com/W1Hil1V.png) > ![](https://i.imgur.com/kd51e25.png) ```shell= git checkout master # 退回前 3 Patch git reset --hard HEAD~3 # git reset --hard HEAD~3 master 同上功能 git status ``` `Your branch is behind 'gitHub/master' by 2 commits, and can be fast-forwarded.` 代表本地分支落後遠端 gitHub/master 分支 2 個 Patch > ![](https://i.imgur.com/Lgf9pAX.png) 4. **git branch --unset-upstream** ```shell= # git checkout master # 取消分支追蹤 # git branch --unset-upstream git branch --unset-upstream master git status ``` > ![](https://i.imgur.com/6tq08XW.png) ### 下載/複製專案 - clone * 在 github 上可以透過 clone 找到遠端 https or ssh 的下載連結 > ![](https://i.imgur.com/2Hqs0Qj.png) | 指令 | 功能 | | -------- | -------- | | git clone <遠端 url/> | 下載專案 | | git clone <遠端 url/> -b <branch name\> | 下載指定分支 | | git clone <遠端 URL\> <folder name/path\> | 下載到指定位子 | | git clone <本地 project\> | 建立專案副本 | 1. 下載遠端專案 ```shell= mkdir clone cd clone # clone 遠端分支 git clone git@github.com:kyle861550/Hello_GitHub.git # clone 下來的資料夾名稱就是 github 上的專案名稱 ls Hello_GitHub/ ``` 下載下來後查看所有的分支,會發現多了 HEAD 分支`remotes/origin/HEAD -> origin/master` ,`remotes/origin/HEAD` 是專案的預設分支,而後面指向的是預設分支 master > ![](https://i.imgur.com/Fj3kLj6.png) :::info git remote 預設名稱為 origin (git remote rename 可以修改名稱) ::: ### 同步遠端分支 - fetch/pull * 當遠端已經被其他人更新時,會發生自己的 Patch 無法 push 上去,會產生衝突而導致 rejected (如下圖) > ![](https://i.imgur.com/akvncXi.png) | 指令 | 功能 | | -------- | -------- | | git fetch <remote name\>/<remote branch name\> | 更新 **"指定"** 分支,fetch 後可以在 gitk 上看到遠端的更新 | | git fetch --all | 更新所有的分支 | | git remote update | 相當於 git fetch --all 的功能,它會更新所有分支 | | git pull <remote name & bramch\> <本地 branch name\>| **同步分支,==預設使用 merge==** | | git pull --rebase <remote name\> <本地 branch name\> | **git 使用 rebase 來解決衝突** | 1. 首先先在 remote 端,也就是 github 上手動添加一個 RemoteFile2 檔案 > ![](https://i.imgur.com/BHRjXbr.png) 添加後的 GitHub 顯示 > ![](https://i.imgur.com/qZjTveW.png) 2. 在本地添加一個檔案 `three.txt`,並提交一個 commit,最後一起推送 ```shell= # 添加 & 提交本地 Commit & 推送 touch four.txt; echo >> three.txt Hello Git 4; git add .; git commit -m "add four.txt file"; git push ``` **因為更遠端不同步,所以產生衝突,被遠端拒絕(rejected)** > ![](https://i.imgur.com/BLGHGqW.png) 3. 執行 `fetch`:**發生衝突後第一件事,是 fetch 遠端 Git** ```shell= # fetch master 分支 git fetch origin master ``` > ![](https://i.imgur.com/sR1UzTA.png) 使用 fetch 後,再用 gitk 就可以看到遠端的差異 (很丑不好看) > ![](https://i.imgur.com/iMy0299.png) 4. 執行 `pull`:同步分支,將遠端資料與本地資料同步(這過程可能會稱圖) ```shell= #如果有設定 upstream 可以使用 git status 看到與遠端的差異 git status ``` 本地 diverged(發散),有一個不同的 Patch,並且它會提示要使用 pull 更新 > ![](https://i.imgur.com/mKLl3YR.png) ```shell= # 如果沒有設定 upstream # 要使用 git pull origin master master (遠端 master -> 本地 master) git pull # pull 指令如同以下指令 git fetch origin # 更新 git merge remotes/origin/master # 將當前分支合併到 遠端 master ``` 由於發生版本衝突,必須手動解決 (默認使用 Merge),以下由於沒有改動到相同文件,所以直接儲存退出 > ![](https://i.imgur.com/UhuD8Hb.png) 解決完稱衝突後 > ![](https://i.imgur.com/7ds22Yh.png) Gitk 差異,可以看到它會產生 **Merge Path** (又稱為 **Merge History**) > ![](https://i.imgur.com/baD4jy4.png) 查看 log 可以看到 Merge branches 資訊(以下是 merge 本地端 master & remote 端 master) ```shell= git log --oneline ``` > ![](https://i.imgur.com/HeoXMzA.png) :::info * 衝突也可以選用 rebase 解決 衝突使用 rebase 解決,它將本地 master 重新 rebase 到遠端之後 ```shell= # git pull #若是沒有使用 upstream 就必須設定 remote&branch git pull --rebase origin master ``` > ![](https://i.imgur.com/tLt8Ekw.png) ::: 6. 執行 `push`:別忘了我們之前在本地鎖新增的 `four.txt` 這個 Patch,記得把它 push 出去 ```shell= #若是沒有使用 upstream 就必須設定 remote&branch # git push origin master master git push ``` > ![](https://i.imgur.com/llpvWvM.png) 在 Git 上我們就可以看到 four.txt 這個檔案 > ![](https://i.imgur.com/l7tYRfY.png) Gitk 上也更新遠端到 master,同步完成 ! > ![](https://i.imgur.com/QrxBUD3.png) ## 進階功能 ### 追溯檔案 - blame | 指令格式 | 功能 | | -------- | -------- | | git blame <option\> <指定檔案\> | 可以追溯指定檔案,該檔案中的更改紀錄 & 更改者 | ```shell= # 追溯 Git.txt 檔案紀錄 git blame Git.txt # 行數(-n) + 原檔案名稱 (-f) git blame -n -f --color-lines first.txt # --color-lines 每行間格顏色 git blame -n -f --color-lines first.txt ``` > ![](https://i.imgur.com/PTPrLjq.png) ### 緩存資料 - stash * **緩存尚未 Commit 之前的所有資料,add 前、後的也可以,==不包括未追總檔案==**,這個指令十分的方便,可以在任何時候存入,並放入你所需的檔案中(中途 checkout 放置到其他的 Patch 也可以) | 指令格式 | 功能 | | -------- | -------- | | git stash | 儲存一個暫存資料,並回復為上一次 Patch 並未改動的狀態 | | git stash list | 查看所有 stash | | git stash apply <指定 stash or 不指定\> | 拉出 stash 套上目前的 Patch,**並未刪除 stash** | | git stash pop 指定 stash or 不指定\> | 拉出 stash 套上目前的 Patch,**並刪除 stash** | | git drop <刪除指定 stash\> | 刪除指定 stash 紀錄 | | git stash clear | 清除所有 stash | 1. 添加新檔案 & 改動 ```shell= # 添加 touch Git.txt; # 改動 echo >> first.txt "test stash" # 查看狀態 git status ``` > ![](https://i.imgur.com/s5pzKIm.png) 2. 儲存暫存檔案 ```shell= # 儲存暫存 git stash git status # 查看 stash git stash list ``` :::danger 無法儲存未追蹤檔案(Untracked files) > ![](https://i.imgur.com/qtoPaOv.png) ::: > ![](https://i.imgur.com/o3zgYLd.png) 3. 套用 stash:以下使用 apply(不刪除 stash) ```shell= # 套用最新 stash(當然也可以指定) git stash apply # 功能同上 git status apply stash@{0} # 查看狀態 git status ``` > ![](https://i.imgur.com/Q6JGKoG.png) 4. 刪除 stash ```shell= # 查看 stash list git stash list # 刪除指定 stash git stash drop stash@{1} git stash list # 刪除全部 stash git stash clear git stash list ``` > ![](https://i.imgur.com/lAeEXhc.png) ### 標籤 - tag * 在需要的地方添加標籤 tag,這個 tag 也可以使用 gradle 獲取,**它的功能與 branch 很像,但是差異是在 branch 可以不斷更新,==Tag 無法更新,通常使用在正式版的本的 master Patch 上==** | 指令格式 | 功能 | | -------- | -------- | | git tag | 查看所有的 Tag | | git tag <tag name\> <commit id\> | 打標籤在指定 Patch 上 | | git tag -a -m <描述字句\> <tag name\> <commit id\> | 功能如上,但是添加了 Message 訊息在 tag 上 | | git tag -d <tag 名稱\> | 刪除指定 Tag | | git push --tags | 推送 **全部** Tag | | git push <url 代稱\> <Tag 名稱\> | 推送指定 Tag 至 GitHub | 1. 建立 tag ```shell= # 查看 log git log --oneline # 建立 tag git tag First_Tag 6e37ebb # 查看 tag git tag ``` 在 gitk 上面也可以看到新增了 tag > ![](https://i.imgur.com/jjCTaNL.png) 2. Message Tag ```shell= # 新 tag 加上 message_something 描述 git tag -a -m message_something Second_Tag 7eade50 git tag ``` > ![](https://i.imgur.com/gSOe32d.png) 3. 刪除 tag ```shell= # 刪除 Second_Tag git tag -d Second_Tag git tag ``` > ![reference link](https://i.imgur.com/04Vzx4b.png) 4. 推送 remote Tag ```shell= # 推送全部 tag git push --tags # 推送指定 tags git push First_Tag ``` > ![](https://i.imgur.com/IDC1AmF.png) 5. 刪除 remote Tag,**==刪除遠端必須先刪除本地標籤==** ```shell= # 刪除本地標籤 git tag -d First_Tag # 刪除遠端 git push origin :refs/tags/First_Tag ``` > ![reference link](https://i.imgur.com/THJnsOw.png) ## Ubuntu 本地倉庫 學習如何在本地創建一個 git 本地倉庫 (當前環境在 Ubuntu) 首先當然是要有 git 對應套件 ```shell= sudo apt install git-core ``` ### 建立本地倉庫 1. 我們在 `/opt` 目錄下創建一個 git 目錄,再創建一個自己的目錄 :::info * opt 目錄 ([**Ubuntu目錄介紹**](https://hackmd.io/MtOap5UaR7KcJpdTisc75g?view#%E8%B3%87%E6%96%99%E5%A4%BE%E4%BB%8B%E7%B4%B9)) 默認為空目錄,給主機而外安裝軟體所擺放的目錄 ::: ```shell= # 移動到 opt 目錄 cd /opt # 創建 git 資料夾 sudo mkdir git cd git # 創建 local_remote 資料夾 sudo mkdir local_remote # --bare 就是共享 sudo git init --bare ``` > ![](https://i.imgur.com/K6NqOoV.png) 2. 為了讓遠端當檔案可以被寫入,有兩種方法 (則依即可) * 將該目錄底下的資料夾內容全部改為可執行 ```shell= # -R 是遞歸該目錄底下所有的檔案 sudo chmod +777 -R local_remote ``` > ![](https://i.imgur.com/wmOVERo.png) * 改變該目錄所屬者 ```shell= # 查看當前使用者 whoami # 改變該資料夾擁有者 sudo chown -R alien local_remote ``` > ![](https://i.imgur.com/MVqDyFe.png) ### 開啟 ssh 服務器 1. 安裝 ssh 套件 ```shell= sudo apt install openssl-server ``` 2. 創建本地 ssh key ```shell= cd ~ sudo mkdir .ssh cd .ssh # 產生 ssh public key (用來加密) ssh-keygen ``` 3. 測試 ssh 服務是否開啟 ```shell= # -e 是所有的進程 # grep 是字串過濾 ps -e | grep ssh ``` > ![](https://i.imgur.com/6JJ7o4B.png) 4. 若 ssh 沒有啟動則使用指令啟動 ssh (也可以使用 systemdctl 來啟動服務) ```shell= # etc 目錄是應用的配置 sudo /etc/init.d/ssh start ``` > ![](https://i.imgur.com/eNBTGen.png) ### 測試 push 到本地 1. 在本地做一個簡單的 git 提交 ```shell= mkdir -p test cd test/ # 初始化 git 倉庫 git init . # 輸出一個 HelloWorld.txt 檔案 echo HelloWorld >> HelloWorld.txt # 添加所有檔案 git add . # 本地提交一個紀錄 git commit -m "feat: add test file of HelloWorld.txt" ``` > ![](https://i.imgur.com/PquhlDa.png) 2. 添加遠端 remote 地址 :::success * 本地 ip 預設是 `127.0.0.1`,若要查詢的話可以使用 ifconfig 指令 > ![](https://i.imgur.com/MNdrE40.png) ::: 儲存本地網路對應的地址 ```shell= git remote add origin ssh://127.0.0.1:/opt/git/local_remote/ ``` 3. push 本地 git 到自己建立的本地遠端;成功透過 ssh 上傳資料到本地倉庫 ```shell= git push --set-upstream origin master ``` > ![](https://i.imgur.com/oJsGyWj.png) ## Appendix & FAQ :::info ::: ###### tags: `Git`