# Git 技術整理 ###### tags: `Git` [![](https://img.shields.io/badge/dynamic/json?color=orange&label=總觀看人數&query=%24.viewcount&url=https://hackmd.io/H9-tQkHnQv6F3mJRAKB_Og%2Finfo)]() > [name=AndyChiang] [time=Sun, Jan 17, 2021 3:15 PM] [color=#00CDAF] 我看的教學:[六角Git & GitHub 教學手冊](https://w3c.hexschool.com/git/cfdbd310) ## Git ### 認識Git 簡單講,Git可以幫你記下哪些時候,做了哪些變更,並可以隨時回頭看原先的版本,避免開一堆副本搞得眼花撩亂。 [Git下載流程](https://w3c.hexschool.com/git/3f9497cd) 而SourseTree則是讓Git視覺化,方便使用。 [SourseTree載點](https://www.sourcetreeapp.com/) ### 使用終端機 使用終端機才能真正學會Git的指令,以及理解什麼指令在做什麼事情。 * Win:*Git Bash* * Mac:*終端機* #### 常用終端機指令 | Windows | MacOS / Linux | 說明 | | -------- | ------------- | --- | |cd [路徑] |cd [路徑] |前往資料夾路徑| |cd |pwd |取得目前所在的位置| |dir |ls |顯示資料夾裡的檔案| |mkdir |mkdir |新增資料夾| |無指令 |touch |開新檔案| |copy |cp |複製檔案| |move |mv |移動檔案| |del |rm |刪除檔案| |cls |clear |清除畫面上的內容| ### 設定個人資料 * 輸入姓名:`git config --global user.name "your name"` * 輸入個人的 email:`git config --global user.email "your email"` * 查詢 git 設定內容:`git config --list` ### 基本架構 ![](https://i.imgur.com/fFyIqfZ.jpg) ### Git 建立本地數據庫 ``` git init ``` 想要建立本地數據庫時: 1. 先在你的電腦新增一個資料夾 2. 終端機輸入這個指令`cd <該資料夾的路徑>` 3. 輸入`git init`指令 #### 查詢當前狀態 ``` git status ``` 可以知道檔案目前的狀態,git的狀態有以下圖片的這四種。 ![](https://i.imgur.com/mK28whI.png) #### 將檔案加入索引 ``` git add <檔案名稱> ``` 比較常用的是`git add .`,將所有檔案全部加入索引。 #### 提交新版本 ``` git commit -m "<填寫版本資訊>" ``` 目前在索引內的檔案會被提交成一個新版本,填寫版本資訊則是為了在你未來回頭看的時候,知道這次commit在幹嘛。 #### 查詢版本 ``` git log ``` 你如果得到以下回饋,代表你有成功commit上去了。 ``` commit b6c3c771cd8939bcd25a8c50089fdf0cd3eab98d (HEAD -> master) Author: 你的姓名 <你的 Email> Date: 你的版本更新時間 版本資訊 ``` ### Git 建立遠端數據庫 #### 兩個熱門的遠端數據庫比較 * [GitHub](https://github.com/):擁有 GitHub Pages 功能,可擁有私人數據庫,免費方案是 3 人以下,適合想要有一個公開對外網站的團隊。 * [Bitbucket](https://bitbucket.org/product/pricing):可擁有私人數據庫,免費方案是五人以下團隊,適合公司專案的小型團隊。 **我這裡都用GitHub當作練習** 基本上要連上遠端數據庫有兩種方式,兩種都差不多。 1. 先建立好本地端,建立新的遠端,然後本地端綁上遠端,將本地的檔案push上去。 2. 先建立好遠端,然後clone(之後講)遠端在自己電腦,直接在clone下來的資料夾內新增你的檔案,git會自動幫你連上遠端。 #### 本地數據庫綁定遠端數據庫 ``` git remote add <遠端數據庫簡稱> <url> // ex: git remote add origin <url> ``` 遠端數據庫簡稱,預設為origin。 #### 推送到遠端數據庫 ``` git push <數據庫簡稱> <分支名稱> // ex: git push origin main ``` #### 複製遠端數據庫 ``` git clone <複製的網址> ``` 1. 在你的GitHub遠端數據庫,找到下圖的這個連結: ![](https://i.imgur.com/f5st0yV.png =60%x) 2. 終端機先cd到想要複製的資料夾位置,然後輸入`clone`。(**注意!不會產生新的資料夾**) 3. 會自動綁定遠端數據庫 #### 抓取遠端更新 ``` git fetch ``` 會發生在多人協作時,如果遠端的進度比本地端還要前面,這個指令就會將遠端資料抓下來,並更新再本地端,`git fetch`之後會長這樣: ![](https://i.imgur.com/69mbj0E.png) 你會發現本地的master還在原先的位置。 #### 本地同步更新 ``` git pull ``` 其實 **git pull = git fetch + git merge** 也就是說, `git pull` 就是在 `git fetch` 後,將 master 給 `merge` 到 origin/master 而已,結束後長這樣: ![](https://i.imgur.com/4Y9pzKw.png) ### Git 分支 #### HEAD ##### HEAD的相對位置 * 往前推一個版本:`HEAD^`,幾個`^`就往前推幾個版本。 * 往前推N個版本:`HEAD^N` `^`也可以替換為`~` ##### HEAD脫離 ``` git checkout <目前分支的commit SHA-1碼> ``` ![](https://i.imgur.com/NkdIR4z.png) #### ORIG_HEAD Git會幫你紀錄上一個HEAD的位置,因此在做一些危險操作時,可以使用`ORIG_HEAD`退回上一步。 #### 移動HEAD位置 ``` git checkout <分支名稱/commit SHA-1碼> ``` HEAD就是目前指向的版本,透過此指令可以移動到想要的位置。 ![](https://i.imgur.com/NM0c6mH.png) #### 建立分支 ``` git branch <分支名稱> ``` 如此一來,就會多出一個新的分支,初始的位置就是當前HEAD的位置。如果想在新分支上新增commit,記得用`git checkout` 切換到新的分支上喔! ![](https://i.imgur.com/7jll23f.png) ##### 直接移動分支位置 ``` git branch -f <分支名稱> <HEAD的相對位置/commit SHA-1碼> ``` * 相對位置:HEAD的相對位置 * 絕對位置:版本名稱 #### 合併分支 ``` git merge <分支名稱> ``` 此指令會將當前分支,合併到`git merge <>`輸入的分支中。 常見作法如下: 1. 先`git checkout`切換至較舊的分支 2. 輸入`git merge <較新的分支>` 3. 完成合併後,較舊的分支便有較新分支的commit ##### 合併-快轉模式 ![](https://i.imgur.com/pSK5hjr.png) 當master沒有作任何更動時合併到dev,此時不會產生新的commit,這種情況我們稱為==快轉模式==,當然反之就有非快轉模式。 ##### 合併-非快轉模式 ![](https://i.imgur.com/rq5i7cu.png) 當master在分支之後有新的更動時,便會產生兩條相異的分支,**此時合併會產生新的commit**(如圖上C6),我們稱為==非快轉模式==。 ##### `--no-ff` ``` git merge dev --no-ff ``` 如果想要將master合併到dev上,卻又不想發生==快轉模式==,就要加入這個指令。 ![](https://i.imgur.com/cTiJd1N.png =60%x) ##### 另一種合併方式 ``` git rebase <分支名稱> ``` ![](https://i.imgur.com/jb3IyGv.png =60%x) `rebase`的概念是,因為上圖 cat 和 dog 兩條分支都源自於 master ,所以當我們使用`rebase`時,Git就會先複製一份 cat 的分支,然後重新給予commit編號並接在 dog 的後面。如此一來便合併便不會產生新的commit,而 cat 舊的commit則會在保留一段時間後,被Git回收。 要如何復原? 會用到之後講的 `reflog` 或者是 `reset ORIG_HEAD`。 但注意,使用rebase容易搞混,因此不推薦使用。 這裡提供一個方便的工具,學習如何活用Git分支:[Learn Git Branching](https://learngitbranching.js.org/?NODEMO=&locale=zh_TW) #### 本地分支衝突 並不是每次合併都是順順利利的,**當兩條分支修改同一行Code時**,就會發生衝突。 可能會遇到這種情況... ![](https://i.imgur.com/s3eDc2a.png) master和dev兩條分支同時更改了h1的樣式,系統便會提示出現衝突: ``` ❯ git merge dev Auto-merging all.css CONFLICT (content): Merge conflict in all.css Automatic merge failed; fix conflicts and then commit the result. ``` **那麼,如何解決衝突?** 1. checkout 到 master 後,輸入 `git merge dev` 2. 發生衝突,all.css 變成 ==Unmerged== 狀態 3. 修改 all.css 後,重新加入到索引 `git add all.css` 4. 透過 `git status` 指令觀察,是否可以重新提交 5. 輸入 `git commit` 提交,並撰寫 commit 訊息,完成本次合併 #### 遠端協作分支衝突 這件事會常發生在多人協作的時候... 1. A和B協作,A先push上共同GitHub 2. B後來也要push上GitHub,於是她需要先把檔案給pull下來 3. 但B發現A的檔案和他的發生衝突了!! **那麼,如何解決衝突?** 1. B必須先修正衝突,commit一個新的在本地端 2. 然後push上GitHub,在原先A檔案的後面 ![](https://i.imgur.com/kL6enJT.jpg =60%x) ### Git 還原 #### 還原版本,且保留檔案 ``` git reset <HEAD的相對位置/commit SHA-1碼> ``` #### 還原版本,且不想保留檔案 ``` git reset <HEAD的相對位置/commit SHA-1碼> --hard ``` #### reset vs. checkout * reset:帶著HEAD指向的分支移動至指定版本,HEAD脫離時無法使用。 * checkout:移動HEAD,不會帶動分支移動。 #### 還原你的還原 人總是會手賤犯錯,如果不小心還原了不想還原的版本時該怎麼辦? ``` git reflog ``` 會顯示出先前的所有動作,複製復原的那次commit編號,再**reset**回去就好了,git都會幫你做紀錄,無須擔心檔案會不見啦。 #### 紀錄還原 ``` git revert <commit SHA-1碼> ``` Git 會幫你還原這個commit更新的內容,但他不會幫你刪除,而是在新增一個還原後的commit(當然SHA-1碼也是新的)。 #### 還原時機統整 ##### 新增檔案時,檔案還沒加入追蹤,想清空工作目錄 * 顯示要被清除的檔案:`git clean -n` * 強制清除檔案:`git clean -f` ##### 檔案已加入追蹤,想還原工作目錄 * 單一檔案指令 :`git checkout -- <file>` * 全部檔案指令:`git checkout .` ##### 檔案加入到索引,想退到工作目錄 * 指令:`git reset HEAD` ### Git 暫存 如果你A專案正寫到一半,突然老闆叫你修B專案的Bug,該怎麼辦? A專案還沒寫完又不能commit! 這時就該用到`git stash`了。 stach類似stack的概念,最後加入的記錄會在頂端({0})。 #### 暫存儲存當前目錄 ``` git stash ``` #### 瀏覽 git stash 列表 ``` git stash list ``` #### 還原暫存 ``` git stash pop ``` #### 清除最新暫存 ``` git stash drop ``` #### 清除全部暫存 ``` git stash clear ``` #### 指定特定暫存紀錄 ``` <stash指令> stash@{n} //n就是list上的編碼 ``` [IT邦邦忙 - git stash 暫存檔案](https://ithelp.ithome.com.tw/articles/10220982) ## GitHub ### `README.md`(說明文件) 使用MarkDown語法,會直接顯示說明文件在專案底下。 #### 為圖片加上超連結 ``` [![google]](https://google.com) [google]:http://www.google.com/img/logo.jpg "GoogleLogo" ``` ### 插入GitHub倉庫內的圖片 ``` https://github.com/ 你的使用者名稱 / 你的專案名 / raw / 分支名 / 存放圖片的資料夾 / 該資料夾下的圖片 ``` ### GitHub Page(靜態網頁) 這個地方可以展示你的網頁!(但只有靜態網頁) 1. 建立一個本地數據庫,存著你的靜態網頁 2. 跟這之前的教學,在GitHub上建立一個遠端數據庫,並且將綁上本地端。 3. push檔案上GitHub 4. 成功後,到**GitHub數據庫>Settings>GitHub Pages**,**sourse選擇master**,如下圖 ![](https://i.imgur.com/uSHt56Z.png) 5. 完成後,再回到GitHub Pages,你會看到如圖的畫面,表示你成功了,網址要記好,它就是你靜態網頁的網址。 ![](https://i.imgur.com/p8eQ6ze.png) 6. 若要更新內容,只要修改完後commit+push新的版本上來就好了。 我的範例 1. [個人小履歷](https://andychiangsh.github.io/myResume_v1/200904_%E6%88%91%E7%9A%84%E5%B1%A5%E6%AD%B7) 2. [甜點商家官網](https://andychiangsh.github.io/SweetShopWebsite/main02.htm) ### `.gitignore`(忽略檔案) 這個檔案要新增在你的專案裡面,功能是讓記錄在`.gitignore`內的檔案不會被版本控制,通常是用於插件,格式為: ``` index.html/ color.css ``` 這樣一來,`index.html/color.css`這兩個檔案就不會有版本控制了。 `git status`可以查詢哪些檔案被忽略。 ### PR(Pull requests) 當你在逛GitHub時,看到A的程式碼寫的不錯,但有一點小錯誤,你想幫他修改,該怎麼做? 1. 此專案的左上角會有一個==fork==按鈕,點選將此專案插入一份到自己的GitHub中。 ![](https://i.imgur.com/7jyXU5b.png) 2. 將自己GitHub上的專案`clone`到自己的電腦。 3. 修正程式碼 4. push上自己的GitHub 5. 然後選擇Pull requests>New pull request>Create pull request,輸入修正訊息後按確定。 ![](https://i.imgur.com/kG2JmYJ.png) 6. 此時A那端就會收到你的pull request了,他看過如果覺得沒問題,他就會`merge`,並且加入一個merge過後的commit。 7. 你寫的程式碼就會出現在A的專案中了! ### GitHub Flow GitHub Flow是一個由GitHub所規範的一個流程,許多團隊都會導入這套流程,讓開發順利進行。 #### 流程 1. clone 遠端資料。 2. 在 master 建立分支來新增功能。 3. 開始開發功能。 4. 發 PR (Pull Request) 申請合併。 5. 討論與檢視程式碼。 6. 部署(Deploy)。 7. 合併(Merge)。 #### 規範 1. 任何在 master 上的 commit 都是可以部署的。 2. 假使程式碼需要討論,請 PR 後在 comment 進行討論。 3. 如果想開發功能,務必新開分支。 [Understanding the GitHub flow](https://guides.github.com/introduction/flow/) ## 補充連結 * [在開源時代的興起下,如何透過License共享並保有權益](https://progressbar.tw/posts/61) * [從自由軟體到開放原始碼,了解共享經濟的資源交換模式](https://progressbar.tw/posts/62) ## 進階補充 ### GitHub desktop vs. SourseTree #### GitHub desktop * 優點:與GitHub連結良好(廢話,就是GitHub自己推出的),檔案可預設以VScode開啟。 * 缺點:沒有視覺化分支,沒有還原 #### SourseTree * 優點:有視覺化分支,還原容易,有簡體中文,但還是覺得英文比較好XD * 缺點:好像沒缺點(? [GitHub desktop和SourseTree比較](https://iter01.com/567668.html) ### VScode Git 外掛 其實VScode上也有外掛可以使用git指令,基本的add、commit、push都可以,優點是如果你本身就是用VScode寫程式,不需要額外開其他程式,但缺點是沒有圖形化介面,可能會搞不清楚現在的branch長怎樣? ### SSH金鑰 除了HTTP外的另外一種連接GitHub方式,因為有一組公鑰和私鑰做雙重身分認證,比起HTTP更加安全。 設定SSH的步驟有點複雜,這裡就不贅述了,可以參考以下網址: [SourceTree 連接 GitHub, Bitbucket (使用 SSH) 於 Windows](http://codeplanet.me/archives/2014/11/sourcetree-connect-github-bitbucket-use-ssh-on-windows/)