# 路人起步-邁向前端工程師-從零開始理解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``(分支)。 ![](https://i.imgur.com/hd5CHOG.jpg =50%x) > 分支(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 ``` ![](https://i.imgur.com/FfRA8w2.jpg =60%x) 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」 ![](https://i.imgur.com/YwpW88T.jpg) ![](https://i.imgur.com/2xcrRKC.jpg) ## 將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切換時,路徑內的檔案也會跟著切換。可以觀察到圖形介面在分支切換時會閃爍一下: ![](https://i.imgur.com/akQJocJ.gif) ## 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中會出現衝突警告。 ![](https://i.imgur.com/6OufNVH.jpg) - 用``git status``檢查,顯示因為兩邊都有「hello_branch.md」所以未合併。所以我們要先解決檔案內容不一致的狀態。 ![](https://i.imgur.com/S1sR4RP.jpg) - 使用VS code 開啟``hello_branch.md``比對兩個同名檔案內容差異之處並修正。這次的做法是把兩個檔案內原本的內文都註解掉,並打上新的文字儲存,讓檔案內容整合在一起。 ![](https://i.imgur.com/PmEwxFA.jpg) ![](https://i.imgur.com/QpQfijf.jpg) - 修改完後``hello_branch.md``內容後,一樣要把異動add至索引清單 ``` git add hello_branch.md ``` - 使用``git status``再去查看就會發現檔名變成綠色字 ![](https://i.imgur.com/vdyuOXj.jpg) - 再次執行commit讓合併生效 ``` commit -m "merge dev branch" ``` ![](https://i.imgur.com/p6LnTfY.jpg =80%x) ## 名詞清單 * 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