# 路人起步-邁向前端工程師-從零開始理解Git
## Git是什麼
Git是一個是一個免費的、開源的工具,是一個版本控制系統軟體,可以從官網直接下載到本機電腦,它可以幫助軟體開發過程更順暢。Git好比一個管家,我們可以透過Git對程式碼進行分散式的版本修改控制([Git is a free and open source distributed version control system](https://git-scm.com/))。
## 為什麼要使用Git
- **備份管理好輕鬆**
一個功能/軟體/網站/App......的開發過程,需要管理不同階段的程式碼修改,沒有Git以前,我們得拷貝數個檔案、用日期命名、新增拷貝一堆資料夾在自己的電腦上備份,再一一上傳到遠端料庫更新,有時還要擔心上傳的檔案會不小心與協作夥伴彼此覆蓋。
- **管家幫你監視倉庫**
Git就像是一個管家,我們把所有專案開發的程式碼放在一個倉庫中,在這個倉庫內所發生的所有繁雜修改過程,都可以託管給這個管家,命令它隨時檢視、回報異動等等,再由Git幫我們跑腿,把這個倉庫內產生的所有紀錄,傳送到另一個遠端的倉庫。
- **回心轉意改到好**
傳送到遠端的好處是當我們發展程式碼到某個階段,有時候發現行不通覺得以前寫得更好時,我們可以請Git幫我們從遠端的倉庫(Remote Repository)召喚回來某個節點當時的狀態紀錄,再從這個指定狀態持續發展。
- **本地倉庫與遠端倉庫**
除此之外,我有我的倉庫,我的同事也會有他的倉庫,如果我們兩邊傳送到遠端的東西重疊了,例如:兩個檔名相同但是內容有差異的檔案,也就是發生衝突,Git管家也會警示,等待我和同事判斷處理方式後(例如:兩者合併後皆保留或是只留其一......),才會真正送入遠端數據庫,就不會搞不清楚遠端數據庫的資料到底是誰的或是哪個才是最新版。
Git管家會紀錄所有的更動,讓合作夥伴能知道每次程式碼修改的原因與位置,團隊協作起來更省事。
## Git 和 Github的差別
Git不是Github
- Git是一個軟體,可以進行版本控制;
- Github是一個網站空間,可作為遠端數據庫,提供程式碼上傳代管。
- Git 和 Github有連結,是因為我們主動指定把本機上的檔案傳送到Github空間上,他們的關係才生效的。
我們可以把本機端數據庫(Local Repository)中的檔案,透過Git這個工具上傳到Github這個遠端數據庫(Remote Repository)上備份與紀錄。(得先給Github一把公鑰,讓它認識你的電腦是哪一台)
簡單來說,我本機上有一個專案倉庫,在Github上我建立了另一個==名稱相同==的倉庫,我透過Git這個工具,讓檔案在兩者之間傳輸。
## Git的安裝與資料夾初始化:建立本機倉庫並邀請管家進駐
You can take a local ==
== that is currently **not under version control**, and ==turn it into== a Git ==repository==.
1. 到[官方網站](https://git-scm.com/)下載軟體
2. 使用Command Line的方式,在本機上任意位置新增一個資料夾,並命名為``hello_git``
```
mkdir hello_git
```
3. 要讓這個普通的資料夾``hello_git``成為專案倉庫,需要對他進行git的初始化。於``hello_git``的路徑之下,輸入
```
git init
```
初始化的目的是讓 Git 開始對這個資料夾進行版本控制,也就是邀請Git管家進入管理這個倉庫。
4. 輸入``ls -a`` 查看``hello_git``是否已經有``.git``隱藏資料夾的進駐
看到``.git``的存在就表示這個資料夾已經初始化成功,此時``hello_git``再也不是一個普通的靜態資料夾,它現在同時擁有三個狀態:
- 工作目錄(Working Directory)
- 索引清單待命區(Staging Area)
- 本地數據庫(Local Repository)
5. 辨識預設的主線:``main``
與此同時,在Command Line軟體介面中會看到``hello_git``路徑名稱後方多了``(main)``標籤,表示``hello_git``初始化的同時,也預設產生了一個名為``main``的主要``branch``(分支)。

> 分支(branch)是什麼
``main``這個branch好比一個專案的主線任務。同一個Repository中可以有多個branch,也就是除了主線,還可以存在多個支線任務。
> 例如:開發一個購物網站,中途需要研發測試3個新功能/修改,所以從主線身上開了3個分支,各自命名為:signIn_button、fav_list、price_tag,
> 最後只採用price_tag的分支要正式上線,
> 此時就可以只把``price_tag``合併到``main``之中。(把小分支合併到主線分支)
> 主線branch其實不一定得叫做``main``,你也可以把它改成任何其他名稱,只是``main``這個名稱是預設的而且很直覺理解。
> 預設的branch名稱以前叫做master,但是[自2020開始10月新Git儲存庫的預設命名,以main來取代原本的master。](https://www.ithome.com.tw/news/140094)
## 取得SSH金鑰並上傳到GitHub讓它認識你的電腦
1. 先去Github上註冊一個新的帳號
2. 在Github上新增一個名稱與本機相同的公開Repository
3. SSH Key有兩種:公鑰與私鑰。公鑰要丟上去給GitHub讓它認識我們的電腦,私鑰留在本機中。
4. 在Mac環境中,進入根目錄之下的``.ssh``資料夾中(如果沒有就自己新增一個)
```
cd ~/ .ssh
```

6. 輸入以下指令取得SSH Key,雙引號內的email要輸入當初註冊Github的同一個
```
ssh-keygen -t rsa -C"your_email@youremail.com"
```
7. 產生完畢後資料夾內會產生``id_rsa`` 和``id_rsa.pub``兩個檔案,有``.pub``的是公鑰,使用``cat``指令取得公鑰內容並複製貼到Github上
```
cat id_rsa.pub
```
8. 到Github>Settings>SSH keys 頁面中,點選「New SSH key」輸入title,並把剛才複製的公鑰內容貼上,再按「add SSH Key」


## 將Github指定為遠端數據庫
由於我們已經在本機上新增過一個本地Repository,現在需要將本地Push給遠端的Github。
回到剛才在Github開創的Repository上,點選「code」頁籤,點選「SSH」,此時會Github會自動顯示出類似網址的東西。依照Github頁面上的 ``…or push an existing repository from the command line``之下,複製相對應的指令貼到終端機上,就能完成本機Loca Repository和Github遠端Remote Repository的連結。讓兩個倉庫相通了。
## Branch新增
先新增一個名為``dev``的新Branch
```
git branch dev
```
## Branch的切換
1. 使用``git checkout`` 指令從``main``切換至``dev``branch
```
git checkout dev
```
2. 在main branch 和 dev branch 各新增數個檔案且以便比較兩者狀態差異
- main:``I am master.md``、hello.txt、hi.txt
- dev :``hello_branch.md``、hello.txt、hi.txt
- 將新增異動commit至Local Repository,給予描述讓人知道異動的意義
```
git commit -m "有意義的描述文字"
```
> 無論是main還是dev都是在``hello-git``資料夾路徑內,但是當branch切換時,路徑內的檔案也會跟著切換。可以觀察到圖形介面在分支切換時會閃爍一下:

## Branch的衝突與合併
假如不同分支中出現「相同檔名但是內容不同的檔案」,要把分支合併為一條時,Git會因為不曉得該保留誰與內容取捨,而出現衝突。
- 在``main``branch中也新增一個``hello_branch.md``,並在檔案內輸入「main's hello branch」等文字內容。而``dev``branch中的``hello_branch.md``內中的文字則是「dev's hello branch」。兩者不同內文以作區分。
- 將這次的檔案新增添加至 staging area 中
```
git add hello_branch.md
```
- 將異動添加至Local Repository並給予描述
```
git commit -m "add hello_branch.md to main"
```
- 現在兩條分支各擁有的檔案如下:
【main】
- * ``i am master.md``
- * ``hello_branch.md``
- * ``hello.txt``
- * ``hi.txt``
【dev】
- * ``hello_branch.md``
- * ``hello.txt``
- * ``hi.txt``
> 比較可發現,``i am master.md`` 只有main分支有所以合併不會有衝突,而``hello.txt``和``hi.txt``因為內容相同,所以合併時也不會有取捨問題的衝突,但是``hello_branch.md``不僅兩邊的分支都有出現,同名但是檔案內容不同,這樣在分支合併時就會出現取捨衝突。
- 在main分支下,使用``git merge dev ``試圖將dev分支合併至main中會出現衝突警告。

- 用``git status``檢查,顯示因為兩邊都有「hello_branch.md」所以未合併。所以我們要先解決檔案內容不一致的狀態。

- 使用VS code 開啟``hello_branch.md``比對兩個同名檔案內容差異之處並修正。這次的做法是把兩個檔案內原本的內文都註解掉,並打上新的文字儲存,讓檔案內容整合在一起。


- 修改完後``hello_branch.md``內容後,一樣要把異動add至索引清單
```
git add hello_branch.md
```
- 使用``git status``再去查看就會發現檔名變成綠色字

- 再次執行commit讓合併生效
```
commit -m "merge dev branch"
```

## 名詞清單
* repository:數據庫
* main:本地數據庫(logcal repo)main是預設別名
* origin:遠端數據庫 (remote repo)origin是預設別名
* git init:讓Git對資料夾進行初始化
* git status:查看狀態,檢查是否有任何待辦事項或是衝突
* git add:將檔案加入索引清單。從此檔案中只要有任何修改都會被git追蹤(track)。
> 如果在工作目錄(Working Directory)新增一個檔案,但沒有加到索引清單內,用``git status``檢查,會列出紅字的檔名,表示此檔案存在但是未被追蹤。直到使用``git add``將檔案加入代辦索引清單之後,再次``git status``檢查狀態,檔名便會顯示為綠字,表示已被追蹤。
* git commit -m "字串":將目前所做的改變加至本地數據庫(Local Repository)且字串中可輸入任何文字用以說明異動原因。
* git log:查看目前為止所有的動作紀錄
* git branch <name>:新增一個指定名稱的新branch。
> 例如:``git branch dev`` 就是新增一個名為dev的branch
* git branch:列出所有branch。
> 前面有``*``者表示是目前所屬Branch
* git checkout <branch名稱>:切換至指定名稱的branch