# Git版本控制 [Git Bash] ## 1. Git安裝 windows 下載網址: https://goo.gl/jXGhWT * 下載後可以到cmd去檢查是否安裝成功 git --version **若找不到檔案要記得去更改環境變數** Git\bin & Git\mingw64\libexec\git-core ``` C:\Users\ASUS>git --version - git version 2.32.0.windows.2 ``` <br> ### 執行Git Bash 1. 先查詢自己在哪個目錄 <font color="9C3119">**$ pwd**</font> 2. 可以使用 <font color="9C3119">**$ ls** </font>來查詢目錄底下的資料 3. 移動到要使用的資料夾底下 <font color="9C3119">**$ cd C:\Users\ASUS\Desktop** </font> 4. <font color="9C3119">**$ clear** </font> 可以清空整個log 5. 接著,我們可以**初始化一個新的 Repository** 或者**複製一個既有的 Repository** <br> ## 2. 創建倉儲 ### Git初始化 使用 Git 來追蹤(track)現有的專案 * 首先進入專案的資料夾,執行<font color="9C3119">**$ git init** </font>,初始化 git repository ( 倉庫 ) ,這個命令將會建立一個名為 .git 的子資料夾,其中包含 Git 所有必需的倉儲檔案,也就是 Git 倉儲的骨架。 ``` $ git init ``` <br> <font size ="5px">**a. 只想抓取特定分支的程式開發**</font> 只想抓取遠端 develop 分支裡的程式到 local 進行開發 ### 建立並切換分支 ``` $ git checkout -b develop ``` <br> ### 建立遠端帳號 在 git bash 建立一個遠端倉儲 remote,<font color="9C3119"> **$ git remote add remote名字 網址** </font> 建立一個remote叫做 laynotena,選擇要上傳的資料夾.git (資料夾不存在的話會自動新增) ``` $ git remote add laynotena https://github.com/laynotena/Test.git ``` <br> ### 初次從遠端下載檔案 <font size ="4px">**$ git pull**</font> <font color="9C3119"> **$ git pull [remote] [branch]** </font> 可以把遠端的資料拉到 local 進行開發 ``` $ git pull laynotena develop ``` ![](https://i.imgur.com/4spUyuz.png) 此時 git 會認定 local 端的 repository 和遠端的 repository 為同一個 repository <font color="9C3119"> **$ git log** </font>的紀錄會完全和遠端相同 ![](https://i.imgur.com/4AJH4ZN.png) <br> <font size ="5px">**b. 從遠端 clone 程式**</font> ``` $ git clone https://github.com/laynotena/JavaZoo.git ``` 這指令將會建立名為「JavaZoo」的資料夾,並在這個資料夾下初始化一個 .git 資料夾,從遠端倉儲拉取所有資料,並且取出(checkout)專案中最新的版本。 進入新建立的 JavaZoo 資料夾後將會看到專案的檔案都在裡面了,等待進行後續的開發或使用。 若要將 repo clone 到「JavaZoo」以外名字的資料夾: ``` $ git clone https://github.com/laynotena/JavaZoo.git test ``` <br> <font size ="5px">**其他方法**</font> ### 建立分支 如果沒有分支想要產生分支,可以用<font color="9C3119">**$ git branch** </font> ``` $ git branch <branchname> ``` ### 查看分支 如果想要查看現有分支,可以使用 <font color="9C3119">**$ git branch** </font> 得到現有分支列表,* 則表示當前所在的分支 ``` $ git branch ``` ### 切換分支 git clone 預設都會在 master branch,如果想要選擇其他的分支 (例如:development) 可以用<font color="9C3119">**$ git checkout** </font>,注意,checkout 之後原本目錄下的檔案會被 git 置換成該版本底下的紀錄 ! ``` $ git checkout development ``` <br> ## 3. 版本控制 ### $ git status 目標資料夾裡的資料分為兩種:<font color="F73D28">**未追蹤 (untracked)**</font>、 <font color="76AF23"> **追蹤中(tracking)** </font> 其中,追蹤中的資料又可以分為 **unmodified**、**modified**、**staged** 我們可以用 <font color="9C3119">**$ git status** </font> 來確認資料夾底下的資料狀態 假設資料尚未有更動: ``` $ git status - On branch master nothing to commit, working tree clean - ``` <br> ![](https://i.imgur.com/s8HnMko.png) <br> **加入未追蹤的資料** * untracked的資料 新增一個Test.txt檔,git 會發現一個未追蹤的檔案(Untracked files) ``` $ git status - On branch master Untracked files: (use "git add <file>..." to include in what will be committed) Test.txt nothing added to commit but untracked files present (use "git add" to track) ``` <br> ### $ git add <font color="9C3119"> **$ git add** </font>用來「**開始追蹤**」檔案、「**預存**」檔案以及做一些其它的事 未追蹤的資料可以通過多次<font color="9C3119"> **$ git add** </font>指令來追蹤完所有你想要追蹤的檔案 或者 使用<font color="9C3119"> **$ git add -f --all** </font>將目前所在的資料夾裡,所有的檔案的改變 強制加入版本管理 ``` $ git add Test.txt ``` 此時加入的資料全部皆為 **unmodified** 的狀態,在 git 開始追蹤資料後,資料尚未有改寫的更動 <br> **改動後的資料** 假設我們對資料有做更動,則資料狀態會改為 **modified** ![](https://i.imgur.com/d1FjgU9.png =550x) 需要再次執行<font color="9C3119"> **$ git add** </font> 來完成預存 **staged** ``` $ git add Test.txt ``` ![](https://i.imgur.com/xFQoU2j.png =450x) 此時資料的狀態改動為staged 如果想讓資料回到 unstaged , 可以執行<font color="9C3119"> **$ git rest** </font> 再回到上一步 <br> ### $ git commit -m "加入註解" **提交檔案到Repo** 當改動的最後,我們會提交資料的快照給倉儲做紀錄,commit會一次提交所有的改動,不需要每做一筆更動就commit一次。 ``` $ git commit -m "add chage to Test.txt" - [master 580dc77] add chage to Test.txt 1 file changed, 1 insertion(+), 2 deletions(-) ``` 此時,所有的檔案都會回到 **unmodified** 的狀態 ``` $ git status - On branch master nothing to commit, working tree clean ``` * 註解修改 如果想要在 local 端修改最後一次 commit 的註解,可以用 <font color="9C3119"> **$ git commit --amend -m** </font> ``` $ git commit --amend -m "New commit message." ``` 如果已經 commit 到遠端上了,記得要強迫 push 到遠端上更改紀錄 (不建議) ``` git push --force <remoteName> <branchName> ``` ### $ git add .gitignore 如果有檔案不想讓 Git 自動加入,也不希望它們被顯示為未追蹤,可以新建一個名為 .gitignore 的檔案,再把檔案名稱加入文件裡。 ``` $ git add .gitignore ``` 使用 vim 編輯文件 ``` $vim .gitignore ``` vim指令 | 指令 | 說明 | 備註 | | ---- | ---------------------- | ----------------------------- | | i | 進入編輯畫面 | insert | | ESC | 退出編輯畫面或取消指令 | 返回指令畫面 | | :wq! | 存檔並退出 | 加 ! 表示強制存檔,也可以不加 | ``` 輸入 i 進到編輯頁面後,複製貼上需要忽略的檔名 ``` ![](https://i.imgur.com/XkT4XWA.png) ``` 輸入 ESC 退出編輯畫面,輸入 :wq! 完成退出 ``` 也可以使用其他語法忽略檔案 | 語法 | 說明 | | ------------ | ---------------------------------------------------- | | *.[oa] | #忽略任何副檔名為「.o」或「.a」的檔案 | | *~ | # 忽略所有檔名以波浪號(~)結尾的檔案 | | *.a | # 不要追蹤檔名為 .a 結尾的檔案 | | !lib.a | # 但是要追蹤 lib.a,即使上面已指定忽略所有的 .a 檔案 | | /TODO | # 只忽略根目錄下的 TODO 檔案,不包含子目錄下的 TODO | | build/ | # 忽略 build/ 目錄下所有檔案 | | doc/*.txt | # 忽略 doc/notes.txt,但不包含 doc/server/arch.txt | | doc/**/*.pdf | # 忽略所有在 doc/ 目錄底下的 .pdf 檔案 | ### $ git rm 使用 <font color="9C3119"> **$ git rm -f** </font> 後面加上檔案名稱可以刪除檔案 ![](https://i.imgur.com/HV5grqm.png) ![](https://i.imgur.com/lDXTIxY.png) 不是真的想把這個檔案刪掉,只是不想讓這個檔案再被 Git 控管了」的話,可以加上 --cached 參數: ``` $ git rm Test.txt --cached - rm 'Test.txt' ``` <br> ## 4. 版本修改 ### $ git log <font color="9C3119"> **$ git log** </font> 可以讓我們查看commit的紀錄,輸入 Q 可以退出log ![](https://i.imgur.com/zyRLbuG.png) 以本次commit紀錄為例,其中 580dc 一長串就是這次commit的編號,我們可以再以這個編號做更深入的查詢 <br> ### $ git show 在 <font color="9C3119"> **$ git show** </font> 後面加入需要查詢的編號就可以看到完整的改動 ![](https://i.imgur.com/DIVJHzV.png) <br> ### $ git reset 將已經追蹤但尚未 commit 的檔案,狀態從已追蹤改為尚未追蹤 <br> ### $ git reverse 將尚未追蹤的檔案全部回復成上一版 log 紀錄的檔案 ### $ git revert 將程式回復到前一版的狀態,git log 會顯示一筆回復的 log <br> ### $ git reset --hard 在 <font color="9C3119"> **$ git show** </font> 後面加入編號就能讓檔案回復到當初的版本,$ git log 裡的紀錄也會消失不見 ``` $ git reset --hard 580dc ``` <br> ### $ git git reflog 如果事後又需要改動,<font color="9C3119"> **$ git reflog** </font>可以再查詢commit紀錄 ![](https://i.imgur.com/JOFk5Xe.png) <br> ## 5. 遠端協同工作 ### **查詢remote** 名稱 ``` $ git remote - laynotena ``` 網址 ``` $ git remote -v - laynotena https://github.com/laynotena/Test.git (fetch) laynotena https://github.com/laynotena/Test.git (push) ``` ### **重新命名remote** ``` $ git remote rename pb laynotena ``` ### **刪除remote** ``` $ git remote rm laynotena ``` <br> ### 將程式上傳遠端 在上傳程式之前請務必確認 local log 的記錄為遠端的最新版本,否則記錄會有衝突 * 第一次上傳若 git 還沒有追蹤特定的遠端分支可以使用 使用 git push --set-upstream [remote name] [branch name] 追蹤遠端的分支 ``` $ git push --set-upstream laynotena master ``` <font color="9C3119"> **$ git push** </font> 可以把本地的資料上傳到遠端 ex. 把資料push到 laynotena的mater ``` $ git push laynotena master ``` ![](https://i.imgur.com/6SsNA0D.png) 之後的改動也都會有紀錄 ![](https://i.imgur.com/NaHtJ0E.png) <br> ### 更新遠端的記錄到 local :bulb: pull = fetch + merge 1. <font color="9C3119">**$ git fetch** </font> 會新增一個名為 FETCH_HEAD 的分支,得到 git 上最新版本的 repo 2. 如果想要合併的話可以用 <font color="9C3119">**$ git merge 其他分支名稱** </font> 將其他分支併入目前的分支。 而分支合併又分為 fast-forward 和 non fast forward,差別在於 git log 是否能分辨哪些改動是分支執行的,假設 分支 test 新增了 commit A 和 B * fast forward 的 git log : 0 ➜ A ➜ B * non fast forward 的 git log : 0 ➜ A(test) ➜ B(test) ➜ merge branch 'test' log 會寫下 A 和 B 的 commit 都是 test branch 做的,然後再和 master 合併,這樣在開發的時候比較容易釐清問題,哪些功能是哪些分支執行的等等 3. <font color="9C3119">**$ git pull** </font> 會直接拿到最新版的資料並且和現在路徑底下的程式合併更新,在開發的時候較不建議這麼使用,以避免覆蓋資料 ``` $ git fetch $ git merge test --no-ff [non fast forward] $ git merge --ff test [強制 fast forward] $ git pull ``` ### Azure Pull Request * 正常PR流程,local -> CICD(branch) -> dev(branch) -> master(branch) 情境解說: 在 Azure 上要從 CICD PR 到 dev 的時候,操作不慎 PR 到 master 了 正確處理流程: 按還原(會建立分支 merge 回 master),再從 master merge 回 CICD, 從 CICD pull 回 local,再重新從 local push 回 CICD,再重新 pull request 其他情境: CICD 不慎 PR 到 master 後,又在 CICD 上 commit 新的更新,且和前一次 pr 到 master 做更改的是同一個檔案、不同的變異,就會產生衝突 正確處理流程: 建立一個新的分支,手動合併,解決衝突 ###### tags: `Git`