###### tags: `Git` # Git ## 在windows安裝Git 在 Windows 中安裝 Git 也有很多種方式。 最正式的安裝程式在 Git 官方網站可供下載。 你只需要連到 http://git-scm.com/download/win 然後下載就會自動開始。 請注意這是一個名為 Git for Windows 的專案,與 Git 本身是互相獨立的。如果你需要更多資料,請查閱 http://git-for-windows.github.io/ 另一個安裝 Git 的簡單方法就是直接安裝 GitHub for Window。 這個安裝程式內已經預設提供 Git 的命令列版本和圖形化工具。 而且它也能夠完美搭配 Powershell,設定實體憑證快取和完整的 CRLF 設定。你可以直接從 GitHub for Windows下載,網址在 http://windows.github.com `$ git clone https://user:password@gitserver.com.tw/git/xxxx.git` ## git credential manager(GCM) 儲存在User/.git-credentials ``` # 設定自動儲存帳號與密碼,原本 Git 支援 store 將帳密存在 User/.git-credentials,但它是明碼的 (很危險) $ git config --global credential.helper store ``` 儲存在User/.git-credential-cache ``` # 你可以透過以下指令啟用這個設定 ( 預設在第一次輸入密碼後會快取 900 秒,也就是 15 分鐘 ) git config --global credential.helper cache ``` ``` # 如果要設定密碼快取 1 個小時,可改用以下指令 git config --global credential.helper 'cache --timeout 36000' ``` 下載並執行最新的 適用于 Windows 的 Git 安裝程式,其中包括 Git 認證管理員。 請務必啟用 Git Credential Manager 安裝選項。 ![](https://hackmd.io/_uploads/SyrXr0QZ6.png) 安裝完成後可以在git上執行以下指令 ``` # 設定管理 $ git config --global credential.helper manager ``` 將密碼儲存在 Windows 作業系統內建的 Windows Credential Store 儲存區中 (認證管理員)。 ![](https://hackmd.io/_uploads/rkTcEAXb6.png) 如果你這時跑去 GitHub 查看 Personal access tokens 頁面 ( https://github.com/settings/tokens ),就會發現這裡被自動新增了一筆 Personal access tokens 金鑰,這是你剛剛在輸入認證時 Git Credential Manager for Windows 幫你呼叫 GitHub API 自動建立的! ![](https://hackmd.io/_uploads/ByXBYC7Za.png) 這個意思也就是說,你剛剛儲存在 Windows Credential Store 儲存區的認證資訊,並不是儲存你真正在 GitHub 的帳號密碼,而是更安全的 個人存取金鑰 (Personal access tokens) ,你隨時都可以從線上刪除此金鑰,因此安全性大增! 以下是 Git Credential Manager for Windows 擴充出來的設定 ``` # 用以關閉任何互動式的操作 $ git config --global credential.interactive never ``` ``` # 如果要關閉每次登入 Visual Studio Team Services 時都會自動跳出 Microsoft Account 與 Azure AD 的選擇視窗,指名只要用 Azure AD 進行驗證 $ git config --global credential.authority Azure ``` ``` # 如果要關閉不必要的服務帳戶驗證 (service account credential validation),可以輸入以下命令進行設定 $ git config --global credential.validate false ``` ## detached HEAD @Vincentl92 ### 什麼是detached HEAD? HEAD 是一個「指向某一個分支的指標」,你可以把 HEAD 當做「目前所在的分支」看待。 正常情况下,HEAD 會指向某一個分支,而分支會指向某一個 Commit。但 HEAD 偶爾會發生「沒有指到某個分支」的情況,這個狀態的 HEAD 便稱之「detached HEAD」。 可能發生這個狀態的原因有: 1. 使用 Checkout 指令直接跳到某個 Commit,而那個 Commit 剛好目前沒有分支指著它。 1. Rebase 的過程其實也是處於不斷的 detached HEAD 狀態。 1. 切換到某個遠端分支的時候。 ![](https://hackmd.io/_uploads/SJsCIRXZa.png) 使用 Checkout 指令切換至 add cat 1 那個 Commmit: ```bsah $ git checkout cd82f29 You are in 'detached HEAD' state. You can look around, make experimental changes and commit them, and you can discard any commits you make in this state without impacting any branches by performing another checkout. If you want to create a new branch to retain commits you create, you may do so (now or later) by using -b with the checkout command again. Example: git checkout -b <new-branch-name> HEAD is now at cd82f29... add cat 1 ``` 現在的狀態是這樣: ![](https://hackmd.io/_uploads/By85D0QWp.png) 這時候試著進行一次 Commit: ```bash $ touch no-head.html $ git add no-head.html $ git commit -m "add a no-head file" [detached HEAD b6d204e] add no-head file 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 no-head.html ``` 這時候的狀態會變這樣: ![](https://hackmd.io/_uploads/ryWQlJEZp.png) 現在這個 Commit(b6d204e)還「沒有名字」,更正確的說是還沒有分支指向它,目前僅有 HEAD 指著它而已。 這有什麼影響嗎?影響就是當我的 HEAD 回到其它分支之後,這個 Commit 就不容易被找到(除非你有記下這個 Commit 的 SHA-1 值),如果一直沒人來找它,過久了之後就會被 Git 啟動的資源回收機制給收掉了。 所以,如果還想留下這個 Commit,就給它一個分支指著它就行了。如果你剛好就在這個 Commit 上的話: ```bash $ git branch tiger ``` 或是明確的跟 Git 說幫你建立一個分支指向某個 Commit: ```bash $ git branch tiger b6d204e ``` 雖然剛建完分支,當下的狀態還是處於 detached HEAD,不過不用太擔心,這個 Commit 以後就可以透過 tiger 這個分支來找到它了。你也可以使用 Checkout 指令配合 -b 參數,建立分支後直接切換: ```bash $ git checkout -b tiger b6d204e Switched to a new branch 'tiger' ``` ### 為什麼切換到遠端的分支也會是這個狀態? 前面提到當 HEAD 沒有指到某個分支的時候,它會呈現 detached 狀態。事實上,更正確的說,應該是說「當 HEAD 沒有指到某個『本地』的分支」就會呈現這個狀態。舉例來說,有一個我剛從自己的 GitHub 帳號 Clone 下來的專案,我使用 git branch 指令檢視目前的分支: ```bash $ git branch --remote origin/HEAD -> origin/master origin/master origin/refactoring ``` 使用 --remote 或 -r 參數可以顯示遠端的分支,當我試著切換到 origin/refactoring 這個分支的時候: ```bash $ git checkout origin/refactoring Note: checking out 'origin/refactoring'. You are in 'detached HEAD' state. You can look around, make experimental changes and commit them, and you can discard any commits you make in this state without impacting any branches by performing another checkout. If you want to create a new branch to retain commits you create, you may do so (now or later) by using -b with the checkout command again. Example: git checkout -b <new-branch-name> HEAD is now at 1ec82d7... refactored ``` 變成 detached HEAD 狀態了。要切換到遠端分支而不呈現 detached HEAD 狀態,可以加上 --track 或 -t 參數: ```bash $ git checkout -t origin/refactoring Branch refactoring set up to track remote branch refactoring from origin. Switched to a new branch 'refactoring' ``` 這樣就切過去了,那個 -t 參數是指會在本機建立一個名為追蹤分支(tracking branch)的東西。或是簡單一點直接把前面的 origin 拿掉: ```bash $ git checkout refactoring Branch refactoring set up to track remote branch refactoring from origin. Switched to a new branch 'refactoring' ``` 參考資料:https://gitbook.tw/chapters/faq/detached-head ## reflog @Vincentl92 ### 什麼是reflog 在使用 Git 版控的過程中,有很多機會會產生「版本歷史紀錄」,我說的並不是單純的 git log 顯示版本紀錄,而是原始且完整的變更歷史紀錄。這些紀錄版本變更有個基本原則:【只要你透過指令修改了任何參照(ref)的內容,或是變更任何分支的 HEAD 參照內容,就會建立歷史紀錄】。也因為這個原則,所以指令名稱才會稱為 reflog,因為是改了 ref (參照內容) 才引發的 log (紀錄)。 例如我們拿 git checkout 命令還切換不同的分支,這個切換的過程由於會修改 .git\HEAD 參照的內容,所以也會產生一個歷史紀錄,如下圖示: ![](https://hackmd.io/_uploads/rk6QuJ4bT.png) 還有哪些動作會導致產生新的 reflog 紀錄呢?以下幾個動作你可以參考,但其實可以不用死記,記住原則就好了: 1. commit 1. checkout 1. pull 1. push 1. merge 1. reset 1. clone 1. branch 1. rebase 1. stash 除此之外,每一個分支、每一個暫存版本(stash),都會有自己的 reflog 歷史紀錄,這些資料也全都會儲存在 .git\logs\refs\ 資料夾下。 在查詢歷史紀錄時,你也可以針對特定分支(Branch)進行查詢,僅顯示特定分支的變更歷史紀錄,如下圖示: ![](https://hackmd.io/_uploads/S1sYuy4ZT.png) ### 使用reflog救回hard reset的某個commit ```bash $ git log --oneline e12d8ef (HEAD -> master) add database.yml in config folder 85e7e30 add hello 657fce7 add container abb4f43 update index page cef6e40 create index page cc797cd init commit ``` 上面共計有六次 Commit。首先要先建立一個觀念,不管是用什麼模式進行 Reset,Commit 就是 Commit,並不會因為你 Reset 它然後就消失了。假設我們先用hard模式的 reset 指令倒退 2 步: ```bash $ git reset HEAD~2 --hard HEAD is now at 657fce7 add container ``` 不僅 Commit 看起來不見了,檔案也消失了。接著可使用 reflog 指令來看一下紀錄: ```bash $ git reflog 657fce7 (HEAD -> master) HEAD@{0}: reset: moving to HEAD~2 e12d8ef (origin/master, origin/HEAD, cat) HEAD@{1}: checkout: moving from cat to master e12d8ef (origin/master, origin/HEAD, cat) HEAD@{2}: checkout: moving from master to cat ``` 當 HEAD 有移動的時候(例如切換分支或是 reset 都會造成 HEAD 移動),Git 就會在 Reflog 裡記上一筆。從上面的這三筆記錄看起來大概可以猜得出來最近三次 HEAD 的移動,而最後一次的動作就是 Reset。所以如果想要取消這次的 Reset,就是「Reset 到它 Reset 前的那個 Commit」(很像饒口令)。在這個例子就是 e12d8ef,所以只要這樣: ```bash $ git reset e12d8ef --hard ``` 就可以把剛剛 hard reset 的東西再次撿回來了。 參考資料: https://gitbook.tw/chapters/using-git/restore-hard-reset-commit https://github.com/doggy8088/Learn-Git-in-30-days/blob/master/zh-tw/16.md ## Git Flow @StanShih 一種分支合併策略 (方法論),由於Git分支非常便宜,合併也非常容易,所以才透過分支的方式建議 ### 使用前提須知 - 須了解 Git 的分支使用方式 - 開發流程擁有多重部署環境 (Dev-Stage-Prod) - 熟悉 Git-Flow 指令操作 (也支援圖形化介面操作)  ### 好處 - 支援平行開發 (Parallel Development) - 便於協同作業 (Collaboration) - 分階段釋出版本 (Release Staging) - 支援緊急修復任務 (Support for Emergency hotfixes) - 簡化合併與分支的指令操作 (但還是可能遇到衝突需要解決) ### 分支的用途 #### master/main 主要分支 - 【正式環境】使用的原始碼 – 最穩定的原始碼版本 #### develop 支援分支 - 【開發環境】使用的原始碼 - 負責整合不同功能的分支回來 #### Feature branch 功能分支 - 開發主要功能的分支 - 必須從 develop 建立分支,且須合併回 develop 分支 - <p style="font-size: 32px;font-color=">Feature branch週期不可過長</p> ex: `feature-<name>` #### Release branch 發行分支 ex: `release-<name>` - 【測試環境】使用的原始碼  - 必須從 develop 建立分支,且須合併回 master 分支 - 負責將 develop 整合過的版本放上測試環境之用 - 整合【開發環境】到【測試環境】之用,整合時可以做些微調,如果測試成功就會再合併進 master 分支,並執行上線程序 - 可用做專案 QA 品質確保或整合測試的專用分支 #### Hotfix branch 修補分支 ex: `hotfix-<name>` - 主要用來緊急修復正式環境的程式問題 - 必須從 master 建立分支,與同時合併回 develop 與 master 分支  ### 流程圖 ![](https://hackmd.io/_uploads/BkwJD0mW6.png) ## 檔案狀態 @jj-xt3IISSqJHOLC-qLIng ![](https://hackmd.io/_uploads/SJOmQ07-p.png) 1. **untracked**:檔案一開始都在這個狀態。 2. **unmodified**:經由指令將untracked的檔案加入追蹤,或是,staged狀態的檔案經由commit,會到這個狀態。另外在這狀態的檔案可以藉由指令來取消追蹤。 3. **modified**:檔案只要有改變就會到這個狀態,無論是在unmodified或是staged狀態。藉由指令可以放棄這些變更,回到之前的狀態。 4. **staged**:在這個狀態的檔案,通常就是要準備要提交到新的版本中了。在此狀態的檔案一經過更改就會回到modified狀態。 ### 初始化 使用 git init 可在目前的目錄下初始化一個 git repository。 若需要建立一個沒有工作目錄 (working directory) 的 repository,可以使用 git init --bare 來初始化,所建立的 repository 僅有 git 容器內容,通常用於 repository server。 ![](https://hackmd.io/_uploads/Bknq1gNWp.png) ### 將檔案加入追蹤 在工作目錄 (working directory) 下,git 不會自動追蹤新建立的檔案,必須透過 git add 指令先將檔案納入容器索引 (index) 才能 commit 進版本庫中。 在一個新的版本庫中新增一個檔案,並使用 git status 查看版本庫狀態。Git 會提示發現新的檔案,但是不會自動列入追蹤。 ``` $ echo "Hellow World" > new.txt $ git status # On branch master # # Initial commit # # Untracked files: # (use "git add <file>..." to include in what will be committed) # new.txt nothing added to commit but untracked files present (use "git add" to track) ``` 使用 git add 將檔案列入追蹤後,git 會顯示檔案預計在下一次提交時送出。 ``` $ git status # On branch master # # Initial commit # # Changes to be committed: # (use "git rm --cached <file>..." to unstage) # # new file: new.txt # ``` <font color="red">**git add**</font> 指令後方除了檔名之外,也可以使用目錄名稱或是萬用字元當作輸入: **git add .**:將目前所在目錄下的所有檔案 (包含子目錄) 加入追蹤。 **git add \*.c**:將所有以「.c」結尾的檔案 (不包含子目錄) 加入追蹤。 **git add -p**:將目前所在目錄下的所有檔案的更改之處逐一顯示出來,並讓使用者確認是否要加入追蹤。 ### commit Commit的觀念:在完成一個功能或是修改一個功能後就commit,並且這次commit的程式碼是要能夠正常運行的。 如果一次commit多個功能,對於版本追蹤會有不好的影響,使用者會無法明確的知道是從哪一部份開始出錯。 輸入`git commit`之後 會有一個編輯介面供使用者輸入commit message 或直接輸入`git commit -m 'New function or something modified'` 要注意的是使用單引號包住commit message而非雙引號(?) ### 將檔案取消追蹤 在程式碼的編輯或編譯過程中,會出現一些不需要追蹤的檔案,例如:執行檔(*.exe)、object file(*.o)、vi的暫存檔(*.swp)、gedit的暫存檔(*.*~)等。 git提供一個檔案幫助管理哪些檔案不需被追蹤,為`.gitignore`。在git中通常不會有`.gitignore`,必須由使用者新增並編輯。 只要在`.gitignore`中條列不想追蹤的檔案,並將`.gitignore`commit上去即可。若想要在`.gitignore`中輸入單行註解,以#開頭。 :first commit: 如果已經確定該repo實作的內容,可以先針對repo建立`.gitignore`檔,對於管理上比較方便。 ``` #.gitignore data.txt ``` Repository ``` - .git - temp - data.txt - abc.txt - data.txt ``` 修改`.gitignore`檔案內容 ``` #.gitignore **/data.txt ``` ![](https://hackmd.io/_uploads/H1FmC0Qb6.png) ### 刪除檔案並取消追蹤 `git rm <filename>`直接取消追縱後,可以看到檔案已經被刪除了。 ``` $ cat first.dat first caca $ git rm first.dat rm 'first.dat' $ git status # On branch master # Changes to be committed: # (use "git reset HEAD <file>..." to unstage) # # deleted: first.dat # ``` 如果刪錯要救援也沒有問題 `git reset HEAD <filename>`:回復到unstaged(modified或unmodified)狀態。 `git checkout -- <filename>`:回復到unmodified狀態。就可以看到檔案已經回來了。此外,這個指令還可以放棄前次commit之後所有的變更,如果功能被寫爛了,想要重寫的話,這個指令很受用。 ## SourceTree **SourceTree** 是一個免費且流行的 Git **圖形用戶界面 (GUI)** 工具,由Atlassian開發和維護。它的主要功能是幫助開發人員更容易地使用和管理 Git 倉庫,而不必依賴命令行界面。以下是 SourceTree 的一些主要特點和功能: 1. **視覺化界面**: SourceTree 提供了一個直觀的界面,用戶可以輕鬆地查看和管理他們的 Git 倉庫,包括提交、分支、合併等操作。 2. **多倉庫支持**: 你可以輕鬆地管理多個 Git 倉庫,並在 SourceTree 中切換它們,這對於同時參與多個項目的開發人員來說很方便。 3. **圖形化的合併和分支操作**: SourceTree 提供了強大的合併和分支工具,允許你輕鬆地創建新分支,進行合併操作,解決合併衝突等。 4. **歷史查看**: 你可以查看倉庫的提交歷史,並輕鬆比較不同版本之間的變更。 5. **代碼標籤和註釋**: 你可以對提交添加標籤和註釋,以更容易地識別和管理重要的提交。 6. **Stash 功能**: 你可以使用 SourceTree 的 Stash 功能,將未提交的更改存儲起來,以便在不同分支之間切換時輕鬆應對。 7. **Git Flow 集成**: SourceTree 支持 Git Flow 工作流程,使你可以更容易地管理特性分支、發布分支等。 8. **平台支持**: SourceTree 提供了 Windows 和 macOS 版本,因此你可以在不同的操作系統上使用它。 ![](https://hackmd.io/_uploads/r1iHvJN-p.png) ## 指令 即使在develop分支下,可以建立一個新分支issue12345,且這個分支會從master切出 ```bash user@localhost (develop) $ git checkout -b issue12345 origin/master ``` ## GitHub Flow @zziHmmCeQri8qjRffpi4Pg Github Flow是一個適合15–20人左右團隊,在部署上自動化且一天之類需要多次部署的開發(持續發布)。 github比git有多兩個服務,一個是fork,另一個是pull request(簡稱PR),還新增issue tracking用法; 先有一個共有的遠端倉庫(remote repository),然後各自用fork把遠端倉庫fork回到自己的倉庫。開發好後,再利用PR回去共有的遠端倉庫,審核過後merge進master。 ![](https://hackmd.io/_uploads/r19YU0mWp.png) 1.在 master 建立分支來新增功能 2.開始開發功能 3.發 PR (Pull Request) 申請合併 4.討論與檢視程式碼 5.部署(Deploy) 6.合併(Merge) 規範 *任何在 master 上的 commit 都是可以部署的 *假使程式碼需要討論,請 PR 後在 comment 進行討論 ![](https://hackmd.io/_uploads/r1BDPyVZa.png) ![](https://hackmd.io/_uploads/H13dwkVb6.png) ![](https://hackmd.io/_uploads/SJf9D1NbT.png) ![](https://hackmd.io/_uploads/r1I3D1VZp.png) ![](https://hackmd.io/_uploads/rJ26PkNZT.png) ![](https://hackmd.io/_uploads/BJo1uy4-a.png) ## Local Repository額外探討(不學也沒關係) Amber ![](https://hackmd.io/_uploads/ryBcx1EZ6.png) ``` $ find .git/objects -type f //取得objects底下取得該內容與頭資訊的 SHA-1 校驗和 .git/objects/d6/70460b4b4aece5915caf5c68d12f560a9fe3e4 //前兩個字元為名稱的子目錄,並以 (校驗和) 剩下 38 個字元為檔命名 (保存至子目錄下)。 //先建立該檔案index $ git update-index --add --cacheinfo 100644 \ 83baae61804e65cc73a7201a7252750c76066a30 test.txt //創建tree $ git write-tree d8329fc1cc938780ffdd9f94e0d364e0ea74f579 $ git cat-file -p d8329fc1cc938780ffdd9f94e0d364e0ea74f579 100644 blob 83baae61804e65cc73a7201a7252750c76066a30 test.txt ``` ### 物件 ``` $ git cat-file -t <sha-1 value> #顯示該sha1 value是屬於那一種物件 $ git cat-file -p <sha-1 value> #顯示該sha1 value物件的內容 ``` - tree 儲存資料的結構以及檔名 - blob 每當git add檔案的時候,就會產生一個blob物件。這個物件會紀錄檔案的內容,但不會紀錄檔名 ※當你只新增一個空的資料夾的話,git status是不會有變化的。 這也就是因為git裡面的blob object紀錄的是檔案的內容,但資料夾根本沒內容! - commit 進行commit後會出現的一個物件,他紀錄了一些有關每次commit需要有的資訊 - tag Tag Object就像是可以貼在git object上的標籤。 一般可以用來標記不同的版本、狀況 ![](https://hackmd.io/_uploads/H1Bc70QZT.png) ### 範例 ![](https://hackmd.io/_uploads/SJVnt1VWT.png) ![](https://hackmd.io/_uploads/rJYN01Nb6.png) ## Git分支 @SEANWEI Git 中最主要的一項武器就是分支 Branch 的功能了。我們可以藉由開多個分支,同時開發不同的功能並且互不影響。在最開始的時候我們會有一個主要分支叫做 master or main(開始是 master,由於這個字帶一點歧視的味道所以慢慢開始用main 來代替),要做新的功能又不想影響主線的時候,我們就可以開新的分支。 實際的例子:假如你今天在開發一個新功能開發到一半,突然發現線上的版本有個 bug 要緊急修復,那你就可以開新的分支來處理 bug,這樣就不會影響到正在開發的功能。 ![](https://hackmd.io/_uploads/SJbsvCmb6.png) 分支 Branch 的基本用法 1. 查看現有的分支可以用 git branch 2. 切換分支 git switch(checkout) [branch name] 3. 新增分支 git branch [new branch name] 或是 git checkout -b [new branch name] 4. 刪除分支 git branch -d [branch name](大寫D可以強制刪掉) ### 分支 branch 合併操作 1. merge 篇 在使用 merge 合併分支的時候,git 預設會以 fast-forward 的模式進行,那什麼是 fast-forward 和 no-fast-forward 呢?我們來看以下的動圖範例: ▍fast-forward #### 先切換到主分支 ``` $ git checkout master ``` #### 使用 fast-forward ``` $ git merge <branch> ``` ![](https://hackmd.io/_uploads/BkSPFkVZp.gif) Gif 來源:CS Visualized ▍no-fast-forward #### 先切換到主分支 ``` $ git checkout master ``` #### 使用 no-fast-forward ``` $ git merge <branch> --no-ff ``` ![](https://hackmd.io/_uploads/Hykht1EWT.gif) Gif 來源:CS Visualized 可以很清楚的看到同樣都是 merge,使用 no-fast-forward 的模式,會長出小耳朵,可以讓成員在日後很清楚辨識不同的 commit 歷程所包含的功能有哪些,但是過多的小耳朵反而會造成混亂,所以就會需要 fast-forward 用來 merge 些較不重要的 commit,像是零碎的 bug fix,保持 git commit 的乾淨。 2. rebase 篇 ▍功能一:合併版本 Rebase 是 “Re-” 與 “Base” 的複合字,這裡的 “Base” 代表「基礎版本」的意思,表示你想要重新修改特定分支的「基礎版本」,把另外一個分支的變更,當成我這個分支的基礎。 # 切換至 branch1 分支: git checkout branch1 # 然後執行 Rebase 動作,把 master 當成我們的基礎版本: ``` git rebase master ``` ![](https://hackmd.io/_uploads/BJg0FyV-6.gif) Gif 來源:CS Visualized ▍功能二:修改歷史 commit 紀錄 除上述功能外,rebase 還能用來修改特定分支線上任何一個版本的版本資訊 ``` $ git rebase -i HEAD~3 ``` ![](https://hackmd.io/_uploads/SyLBcJEWT.gif) Gif 來源:CS Visualized 使用 rebase 之前,一定要先問問自己「有沒有人也在使用這個分支」,如果有的話,請非常小心使用,因為 rebase 會改變歷史紀錄。 關於更詳細的 rebase -i 操作可以參考此篇:修正 commit 過的版本歷史紀錄 Part 5 ### 使用 merge 與 rebase 時機 如果 branch 是私有分支,rebase 可以有效幫你「重整版本」來保持 commit 紀錄是呈線性整齊,而如果是共有分支則使用 merge fast-forward 或 merge no–fast-forward,來避免修改到同事的歷史紀錄。 參考資料 https://github.com/stan-shih/githubpractice https://www.maxlist.xyz/2020/05/02/git-merge-rebase/ ## Difference between Git and SVN * Platform Architecture: distributed vs centralized * Branching Structure: commit vs directory * Speed: fast vs slow * History: local vs server * License: Open vs Open @Shen