###### tags: `學習` # Git & GitHub 學習紀錄 ## **為何要使用Git ?** * ### **目的** **Git**為一"**版本控制工具**",顧名思義可以用來控制所儲存的檔案內容當前的版本。以白話的方式來說,就是可以將檔案的每個階段儲存,並在要必要時調整回需要用的版本。 * ### **跟一般存檔有什麼不同處?** 一般的另存新檔是將整個檔案內容完整儲存下來成為一個新的檔案,這麼做一方面很占空間,另一方面並不會記錄檔案中修改過了哪些內容,等於每一次儲存的皆是一個全新的檔案。 而透過Git儲存當前的版本,只會記錄做出的修改內容,並不會將整個完整的檔案都存下來,這樣既節省了空間,也能清楚看出每個版本之間做了哪些的調整。 * ### **Git & GitHub** Git跟GitHub是兩個截然不同的東西。 **Git**是將檔案的各個版本儲存到**本地的資料庫**,也就是儲存到當前使用的裝置內。 **GitHub**則是一個**遠程的資料庫**,可以將本地資料庫內的檔案傳送到GitHub上,供他人參考或修改;這樣不僅方便團隊開發項目,也減少了因失誤而造成檔案版本的遺失。 ## **Git 操作介面** Git大致能通過**指令**(**Command**)及**圖形化介面**(**GUI**)兩種操作模式來執行操作,而本篇文章只會單獨講解指令模式的操作方式。 * ### Download Git 透過[連結](https://git-scm.com/downloads)可以進入Git官網下載應用程式,順利下載完後即可在桌面按滑鼠右鍵選擇想要使用的Git操作介面。 ![](https://i.imgur.com/JX9uFDs.png) ## **Git基本指令操作** * ### BASH介面 本次使用的是Git內的**BASH**指令介面來操作,而通過先前介紹得知,git的操作有分為對**本地資料庫**的工作也有對**遠程資料庫**的工作,以下分別介紹兩者的一些基礎功能及其指令: + ### ***本地資料庫:*** 1. ****本地資料庫初始化:**** command : `git init` ^[注]^首先進入BASH介面,接著開啟欲存檔案版本之資料夾(最好是一個新的資料夾,來代表本當次開發項目),接著輸入`git init`指令,此目的為在當前檔案夾內創一個.git目錄,而其內部為本地資料庫之相關子目錄及文件;git init意義上有點像是將當前資料夾初始化為一個repository,這個repository空間之後可以用來存放git點。 另外,因為.git檔不會在圖形化介面的資料夾內顯示,所以若想看此目錄是否創建成功,可以透過`ls -lA`或`ll .git/`指令來查看此目錄相關資訊。 2. ****設置簽名:**** command: `git config`或`git config --global` ^[注]^設置簽名的目的是當版本做出變動時,可以留有記錄是誰修改到了當前版本,這樣在多人協同開發時方便察看,也不易被惡意修改。 而兩指令的差別在於,`git config --global`為在當前系統使用者(比方Windows的User)範圍內,使用Git做任何事皆透過此資訊;而`git config`則是只能在專案內設定,但也就只對此專案有效。 指令使用方式如下: ``` git config user.name 【輸入自己設定的使用者名稱】 git config user.email 【輸入自己的e-mail】 ``` ``` git config --global user.name 【輸入自己設定的使用者名稱】 git config --global user.email 【輸入自己的e-mail】 ``` 3. ****添加版本到本地庫:**** command:`git add`跟`git commit -m` ^[注]^當已把需要儲存版本的檔案(新的檔案)放入當前資料夾中,此時檔案並未以版本方式儲存,也就是資料夾中雖然可以看到放入了新的檔案,但是在git分支點上並未將目前的狀態(添加新檔案後的狀態)記錄下來;可以通過`git status`指令看出,有哪些檔案是有修改過的,但是卻還沒將最新的"狀態"存放在repository內。 因此需先將檔案透過`git add`指令添加到暫存,再通過`git commit -m`將當前暫存內版本提交進入本地資料庫,才順利完成版本的儲存。 指令使用方式如下: ``` git add 【輸入檔案名稱】 git commit -m "【輸入此版本之說明or註解】" 【提交之檔案名】 ``` ![](https://i.imgur.com/kbnaDPo.png) :::info ^p.s^ git status 是用來看當前狀態有哪些檔案是還沒有加到repository 或是檔案內容有修改過卻也還沒紀錄狀態的情況,都會顯示出來(比較 工作區跟local repository) **untracked** : 新"加入"的檔案(跟"修改過"的檔案不一樣,也代表之前沒有提交過),且尚未被加到"暫存區"內。 **modified** : 檔案內容有"修改"過(代表之前有提交過),但還沒將修改過後的狀態存放在"暫存區"的檔案。 ![](https://i.imgur.com/QJqX7GI.png) ![](https://i.imgur.com/FSZq55D.png) ::: 4. ****所有版本總攬查看:**** command:`git log`或`git reflog` ^[注]^若檔案經過多次的修改,並且每次皆有養成提交的好習慣,可以通過`git log`或`git reflog`來查看該檔案之前所有儲存過的版本。 5. ****版本的前後移動:**** command:`git reset --hard` ^[注]^在先前的版本總攬能看到每個版本前方皆有一串對應的[哈希值](https://blockbar.io/blockchain/hash%E6%98%AF%E4%BB%80%E9%BA%BC-what-is-hash/)(Hush table),此串值就像是每個不同版本的地址一樣;而再透過`git reset --hard`指令配合使用,便可將當前的檔案調整回想要的版本狀態,方便需要時使用。 指令使用方式如下: ``` git reset --hard 【輸入欲前往版本之哈希值】 ``` :::danger **< reset 跟 checkout 的差異 >** - reset : reset HEAD^ => HEAD切到上一個點,但保留全部的branch不會刪除。 reset HEAD^ --hard => HEAD切到上一個點,且新的HEAD點後的branch全部刪除。 - checkout \<Hush> : 只動HEAD,master(branch)不動。 ::: :::info **< master概念 >** master為默認branch,其特點有以下幾點 - 創新repository時,還沒有commit點, =>建立第一個commit點時,會把HEAD指向master,master指向commit點。 - 使用clone時,會把repository的HEAD切到remote的master上 ^ex:^ ![](https://i.imgur.com/2cWXlFQ.png =400x) ![](https://i.imgur.com/j6Fzv4D.png =400x) - 通常來說在專案開發中,"master"為最主要核心,其他branch為圍繞著master在做的。 ::: :::danger **< master 跟 HEAD 的差異 >** 像"master"、"branch1"、"branch2"...都是分支名稱(branch), 而HEAD是一指標,會指向分支名稱(branch), HEAD用意是在使用一些git command(^ex:^git clone、git commit...etc)時, HEAD指向的branch代表被執行動作的分支點。 \- 簡單來說 - **master** : 只是一種branch名稱,取名master讓開發者知道專案的核心內容。 **HEAD** : 代表當前版本在哪一branch上。 ::: 6. ****版本的分支:**** command:`git branch` ^[注]^當一個版本的檔案要開發時,可能每個開發者各自開發的是檔案中不同的部分,此時可以使用分支的功能進行,一方面讓眾多開發者可以在同一時間各自開發同一檔案,另一方面若有其中一個項目失敗了,只需將其分支刪除即可,並不會影響到其他分支。 創建分支方式如下: ``` git branch 【輸入分支名稱】 ``` :::info **< branch 概念 >** 比起將branch想成一個"分支點",更應該看成是一"串"分支, ^ex:^ ![](https://i.imgur.com/ovCQ80Y.png =400x) (master意義上為1->2->3,而不是只有3而已) ::: :::info **< 創建branch概念圖 >** ![](https://i.imgur.com/A9uL2nq.png =300x) => ![](https://i.imgur.com/BYQjfxa.png =300x) ::: 7. ****查看分支:**** command:`git branch -v` ^[注]^可以透過`git branch -v`指令查看該檔案當前所有的分支項目,並且能透過綠色的分支名知道當前在哪一個分支上。 8. ****切換分支:**** command:`git checkout` ^[注]^當要開啟另一分支內容進行開發時,使用`git checkout`指令來切換到欲開發之分支。 另外,要記得分支進行開發過後,一樣要提交到本地資料庫。 切換分支方式如下: ``` git checkout 【欲切換到之分支名】 ``` :::info **< checkout branch概念圖 >** ![](https://i.imgur.com/BYQjfxa.png =300x) => ![](https://i.imgur.com/NVaqkJ9.png =300x) ::: :::warning 另外,也可以用`git branch -b <branch名稱>`來將"創建branch"及"checkout branch"兩項合併為一個動作 ::: :::info 而之後將切換到新的branch做commit後,HEAD就會帶著新的branch移動了。 ![](https://i.imgur.com/NVaqkJ9.png =300x) => ![](https://i.imgur.com/lGpHkbE.png =330x) 這時如果checkout回原本的branch(這邊以切回master為例),再進行一次commit,則會像以下狀況 ![](https://i.imgur.com/MyB2EWY.png =330x) ::: :::info **< 刪除branch概念 >** `git branch -d <branch名稱>` - HEAD指向的branch不能刪除;若想刪除當前HEAD所指向的branch,需先用checkout把HEAD指向其他地方。 - 因為Git中的branch只是一個引用(branch名稱是代替一長串的Hash值),所以刪除branch的動作也不會刪掉任何的commit(只會刪掉引用)。 - 而所謂的"引用",是指存在.git目錄中,Git工作時通過這些文本文件內容來判斷"引用指向哪個Hash值" ^ex:^ ref: refs/heads/branch3 -> da39a3ee5e6b4b0d3255bfef95601890afd80709 ::: 9. ****合併分支:**** command:`git merge` ^[注]^欲將分支合併回原版本上,或是要將兩分支合併,可以使用`git merge`指令,但要注意,要先切換到被合併/被修改的分支上,再執行此指令。 而執行的結果是將合併上來的分支內容,存入當前所在的被合併分支檔內。 合併方式如下: ``` git merge 【欲合併上來的分支名】 ``` 10. ****合併分支的衝突:**** 當欲合併的兩分支皆修改了檔案內容,並且修改的為相同一個部分,這樣會造成不知道要以哪一分支的修改為主的衝突其況。 此時通過開啟原檔案,裡面會說明兩分支衝突的部分,只要將衝突部分直接修改到最終想要的結果,並提交到本地資料庫即可。 其中要注意,修改完後的提交指令,後方不需要帶檔案名。 提交方式如下: ``` git commit -m "【輸入版本之說明or註解】" ``` + ### ***遠程資料庫:*** 遠程資料庫一部分工作是在[**GitHub**](https://github.com/) 上執行的,因此須先到GitHub網站上註冊會員;註冊完成後便可回到BASH執行遠程操作。 1. ****連接遠程庫地址:**** command:`git remote add ` ^[注]^透過此一指令,可以記錄遠程資料庫的連結,這樣就不用在每次使用遠程資料庫的時候都要重新輸入一次。 遠程資料庫的連結能在GitHub內資料庫的頁面中找到,我們先使用HTTP的方式連結,如下圖: ![](https://i.imgur.com/feaQvJh.png) 複製後將連結貼到我們的`git remote`指令後: ``` git remote add 【幫此遠程資料庫連結取名】【複製的連結】 ``` ^p.s^通常我們會將遠程資料庫取名為"origin"。 這樣以後就可以用所取的連結名來代替一長串的遠程資料庫連結。 2. ****檢查當前所有的遠程資料庫連結:**** command:`git remote -v` 透過此指令可以看到當前本地資料庫內已連結了哪些的遠程資料庫。 3. ****推送到遠程資料庫**** command:`git push` 將檔案或修改的版本推送到遠程資料庫時,使用`git push`指令,推送完成便將本地資料庫內的檔案版本順利更新到遠程。 其中要注意,若我們不是欲推送的遠程資料庫內成員,需先透過隊內成員從GitHub邀請,再從自己的GitHub進入連結來加入團隊。 指令使用方式如下: ``` git push 【遠程連結別名】【欲推送給遠程的local分支名】 p.s : 若使用"-u"在指令中 => git push -u 【遠程連結別名】【欲推送給遠程的local分支名】 代表將預設的remote設定為【遠程連結別名】,這樣在之後若不特別指定remote, 都會將其推送到預設的【遠程連結別名】上,這樣之後要push到remote的 repository時,只要使用git push即可,不需要將後面的 【遠程連結別名】【欲推送給遠程的local分支名】都打出來。 ``` 4. ****克隆遠程版本資料**** command:`git clone` 當想使用在GitHub上看到的資料時,可以透過`git clone`指令,配合頁面提供的HTTP連結,來將他人遠程資料庫內的資料複製一份到自己的本地庫內作使用。 而複製結束後,此指令也自動的初始化了本地資料庫,也自動創建了遠程資料庫別名。 指令使用方式如下: ``` git clone 【複製之他人遠程資料庫連結】 ``` 5. ****拉取修改完的遠程版本資料**** command:`git fetch` 將修改完的遠程資料庫內版本資料下載到本地資料庫,但此時尚未修改本地資料庫內資料,此目的是為了能讓我們確認修改的內容無誤,在進行更改。 指令使用方式如下: ``` git fetch 【遠程連結別名】 【遠程分支名】 ``` 6. ****修改本地版本資料**** command:`git merge` 將遠程內容修改到本地資料內容上。 指令使用方式如下: ``` git merge 【遠程連結別名】/【遠程分支名】 ``` 7. ****拉取跟修改同時執行**** command:`git pull` 此一指令是將`git fetch`跟`git merge`兩個指令同時執行,較為方便但也缺少了檢查的步驟。 指令使用方式如下: ``` git pull 【遠程連結別名】 【遠程分支名】 ``` ## **GitHub基本操作** * ### 跨團隊(Fork) ****使用時機:**** 當使用者不能進入該團隊直接修改內容時,需先在自己的倉庫copy一份,再到自己的本地庫修改,順利修改後再push到自己的遠程資料庫上,最後跟原團隊申請修改原內容。 ****操作步驟:**** (1)先進入欲使用資料之團隊GitHub頁面,點選右上角"fork"按鈕,完成後左上角可以看到當前倉庫所有人是自己,但下方也有顯示來自誰的倉庫。 (2) 接著拉到本地資料庫進行修改,修改完成後push回自己的遠程資料庫。 (3)在修改完的GitHub倉庫頁面上,點選"pull requests"鍵跟"create pull requests"鍵,來跟原團隊申請修改原檔的要求,然後可以透過message給原團隊說明內容。 (4)原團隊在GitHub上點選"pull requests"鍵,可以看到申請內容跟message;另外,也需透過"commits"跟"files change"去看被做了哪些修改;若確認沒問題,點選對話頁面的"merge pull request"鍵(輸入內容為類似-m "..."之說明內容),完成後在原團隊的遠程資料庫內容就修改完成。 * ### SSH登錄 ****使用時機:**** 因用http登錄可能每次使用都要輸入一次passward,所以SSH較為省事,但一次只可操作一個帳號。 ****操作步驟:**** (1)在BASH內使用`cd ~`指令進入家用戶目錄 (2)`rm -r .ssh/`刪除之前的ssh目錄 (3)使用`ssh-keygen -t rsa -C 【輸入GitHub email address】`指令來生成一個新ssh資料夾 (4)`cd .ssh/`進入ssh目錄,輸入`ll`可看內容 (5)ssh目錄內容有id-rsa跟id-rsa.pub兩檔,使用指令`cat id-rsa.pub`開啟id-rsa.pub來copy內容 (6)到GitHub頁面的SSH and GPG keys點選"new keys",輸入自己決定的title,然後貼上剛剛複製的id-rsa.pub內容 (7)再回到BASH的本地工作區內,用`git remote add 【新建連結名】【ssh link】`,其中輸入的新建連結名為自己取的,方便呼叫時使用;而ssh link為GitHub頁面資料庫中的"clone or download"內所複製下來的。 (8)使用`git push 【新建連結名】【遠程分支名】`指令,這樣之後要push時,只要向【新建連結名】push,不需登錄,即可完成。 ## **小結** 本篇只介紹了一些Git常用的基本功能,可以透過[此處連結](https://git-scm.com/book/zh-tw/v2/Git-%E5%9F%BA%E7%A4%8E-%E5%8F%96%E5%BE%97%E4%B8%80%E5%80%8B-Git-%E5%80%89%E5%84%B2)了解更多不同功能的操作方式,方便之後開發時做使用。