## 前言 這篇文章主要紀錄我學習git的過程及分享,會介紹Git基本概念還有本地端基本指令的操作,主要是面向初次使用git的使用者 > 以下內容主要參考chatgpt、bard、bing回答進行修改 ## Git 介紹 Git 是一種分散式版本控制系統,用於跟蹤文件和文件夾的更改。它允許用戶創建、提交和推送更改到遠程存儲庫(remote repository),或者直接在本地工作。 ### 版本控制的原理 版本控制是一種記錄文件歷史狀態的方法,可以讓用戶回溯、比較和還原不同版本的文件。版本控制系統可以分為集中式和分散式兩種類型。 ![image](https://hackmd.io/_uploads/ByEukSWwa.png) >圖片出處:[Scriptcrunch](https://scriptcrunch.com/295/) #### GIT分散式版本控制 - 分散式版本控制系統,如 Git,是指每個用戶都有一個完整的文件和歷史記錄的副本,稱為本地倉庫(repository)。 - 用戶可以在本地進行各種操作,如創建、提交、分支、合併等,而不需要聯網 - 用戶還可以與其他用戶的倉庫進行同步,通過推送(push)和拉取(pull)操作來交換修改 - 分散式版本控制系統的優點是速度快,支持離線工作,分支管理靈活,缺點是學習曲線較陡,命令較多,衝突解決較複雜 #### SUBVERSION(SVN)集中式版本控制 - 集中式版本控制系統,如 SVN,是指所有的文件和歷史記錄都存儲在一個中央服務器上,用戶需要聯網才能訪問和操作 - 用戶可以從服務器上簽出(checkout)最新的文件,或者提交(commit)自己的修改到服務器上 - 集中式版本控制系統的優點是管理簡單,權限控制容易,缺點是依賴於網絡和服務器的可用性,且不支持本地操作 #### Git(分散式) vs SVN(集中式) Git 和 SVN 都是目前最流行的兩種版本控制系統,它們各有優缺點,適用於不同的場景和需求。以下是它們的一些主要功能的差異和比較: | 特點 | Git | SVN | |--------------------------------|----------------------------|---------------------------------| | 存儲方式 | 分散式 | 集中式 | | 文件和歷史記錄存儲位置 | 本地倉庫 | 中央服務器 | | 存儲依賴性 | 不需要聯網 | 需要聯網 | | 操作 | 創建、提交、分支、合併等 | 簽出、提交 | | 本地操作 | 支持本地操作 | 不支持本地操作 | | 管理簡單性 | 學習曲線較陡 | 管理簡單 | | 權限控制 | 相對複雜 | 容易 | | 離線工作 | 支持離線工作 | 不支持離線工作 | | 分支管理 | 靈活且強大的分支管理 | 較簡單且較受限制 | | 衝突解決 | 較複雜 | 較簡單 | | 速度 | 快速 | 一般速度 | ### Git 的重要性 - 它提供了可靠的版本控制,開發人員可以使用 Git 來跟踪他們的代碼更改。這樣,如果他們不小心刪除了或修改了某些代碼,他們可以輕鬆回滾到以前的版本。 - 它支持多人協作,團隊可以使用 Git 來協作開發軟體。這樣,每個開發人員都可以在自己的本地工作,然後將更改推送到中央存儲庫。 - 可移植性強,可以與不同的遠端儲存庫協作,像是GitHub、GitLab等。 --- ## Git指令介紹 ### `init` - `init`是Git版本控制系統中的一個重要指令,它用於初始化一個全新的Git存儲庫(repository) - 當您想要開始使用Git來跟蹤和管理代碼版本時,通常需要在項目目錄中運行git init來創建一個新的Git存儲庫 ```git= git init //初始化新的Git存儲庫 ``` - 執行前 : ![image](https://hackmd.io/_uploads/S1KIkL-D6.png) - 執行後 : ![image](https://hackmd.io/_uploads/rJyqkUZDT.png) --- ### `config` - `config` 指令用於設定Git的配置選項,這些設定控制Git的各種方面,包括用戶信息、顏色顯示、命令別名等 - Git配置有三種作用範圍:本地(local)、全域(global)和系統(system) - 不同的作用範圍影響Git配置的適用範圍 #### 本地(Local)配置 - 作用範圍:僅適用於當前倉庫。 - 使用場景:當你想為特定的倉庫設定特殊的配置,例如特定的用戶名或電子郵件地址。 - 設定方式:在Git倉庫目錄中使用 git config --local。 - 配置文件位置:.git/config 於當前倉庫目錄中。 #### 全域(Global)配置 - 作用範圍:適用於用戶的所有倉庫。 - 使用場景:當你想設定通用於所有倉庫的配置,如用戶名和電子郵件。 - 設定方式:使用 git config --global。 - 配置文件位置:一般位於用戶主目錄下的 .gitconfig 或 .config/git/config 文件。 #### 系統(System)配置 - 作用範圍:適用於系統中所有用戶的所有倉庫。 - 使用場景:通常由系統管理員進行設定,用於設定整個系統級別的Git配置。 - 設定方式:使用 git config --system。 - 配置文件位置:依賴於Git安裝的位置,通常是 /etc/gitconfig。 #### 使用範例 - 設定本地用戶名:`git config --local user.name "Your Name"` - 設定全域電子郵件:`git config --global user.email "your_email@example.com"` - 設定系統級的核查模式:`git config --system core.fsckObjects true` - 透過 `git config --<local or global or system> --list` 可以查看不同範圍的配置 #### 注意事項: - 如果同一設定在多個作用範圍都存在,Git會按照以下優先順序選擇:本地 > 全域 > 系統 - 對於沒有管理員權限的普通用戶,建議主要使用本地和全域配置 - 修改系統配置需要管理員權限,並會影響到系統上所有用戶的Git操作 --- ### `status` - `status` 指令是 Git 中一個非常常用和重要的指令,它提供了關於當前倉庫狀態的詳細信息 - 這個指令主要用於顯示工作目錄和暫存區的狀態,幫助用戶了解哪些更改已經被暫存(staged)、哪些更改還沒有被暫存,以及哪些文件還沒有被Git追蹤 #### 使用 git status 的主要特點: 1. 未暫存的更改(Unstaged Changes): - 這部分顯示自上次提交(commit)後,工作目錄中已修改但尚未暫存的文件。 - 這些更改需要使用 git add 指令來暫存。 2. 暫存的更改(Staged Changes): - 這部分顯示已經使用 git add 暫存,但還未提交的更改。 - 這些更改將會被包含在下一次提交中。 3. 未追蹤的文件(Untracked Files): - 這些是Git之前沒有紀錄的新文件。 - 可以使用 git add 將它們加入暫存區,使其成為被追蹤的文件。 4. 分支信息: - git status 通常會在開頭顯示當前所在的分支和它與上游分支(通常是遠端分支)的差異,如"ahead"或"behind"。 5. 建議的Git指令: - 在某些情況下,git status 會提供一些有用的指令建議,比如如何暫存更改或如何回退到上一個提交狀態。 #### 情境演練: 1. `git init` 後新增一個file1.txt - `git status`因為file1.txt 還沒加入到暫存區,會顯示未追蹤的文件(Untracked Files) ![image](https://hackmd.io/_uploads/Hyx_5IWD6.png) 2. 將file1.txt 透過`git add`加入到暫存區 - `git status`file1.txt 加入到暫存區,會被包含在下次`commit` ![image](https://hackmd.io/_uploads/r1eOs8bvp.png) 3. `git commit`提供後,新增file2.txt,同時修改file1.txt 內容 - 修改的file1.txt 會變成modified且Unstaged Changes狀態 - 新增的file2.txt 則是untracked file ![image](https://hackmd.io/_uploads/rycba8Zw6.png) 4. `git add`兩個檔案會修改成Staged Changes - file1.txt 上次提交時已存在所以是modified - file2.txt 上次提交時不存在所以是new ![image](https://hackmd.io/_uploads/HyWOp8Wwp.png) --- ### `add` - `add` 是 Git 版本控制系統中一個核心的指令,用於將修改過的文件添加到暫存區(staging area - 這是進行提交(commit)之前的一個重要步驟,因為只有暫存的更改才會被包含在下一次提交中。 #### 主要功能 1. 暫存修改: - 將工作目錄中的修改(包括新文件和修改過的文件)添加到暫存區。 - 只有暫存的更改才會被下一次的 git commit 捕捉。 2. 更新暫存區: - 如果一個文件已經被追蹤(之前已經提交過),git add 可以用來將新的修改添加到暫存區。 3. 開始追蹤新文件: - 對於新建的未追蹤文件,使用 git add 可以開始追蹤這個文件。 #### 使用方式 1. 將單個文件添加到暫存區: ```git= git add file1.txt //這將file1.txt中的修改添加到暫存區中,使它們準備好被提交 ``` ![image](https://hackmd.io/_uploads/rkUblI-P6.png) 2. 將多個文件添加到暫存區: ```git= git add file1.txt file2.txt //這將file1.txt中的修改添加到暫存區中,使它們準備好被提交 ``` 3. 將目錄中的所有修改添加到暫存區: ```git= git add <目錄名> //這會將指定目錄下的所有更改(包括子目錄)添加到暫存區。 ``` 4. 將所有修改添加到暫存區: ```git= git add . //使用.代表當前目錄,這將將所有修改和新增的文件添加到暫存區。 ``` 5. 互動式添加(Interactive Add): ```git= git add -i //這個模式允許您一個接一個地檢視文件更改,並選擇是否將它們添加到暫存區。 ``` #### 注意事項 - `git add` 不會影響倉庫中的提交歷史,它僅將更改添加到暫存區 - 使用 `git add` 之後,如果對暫存的文件進行了進一步的修改,需要再次執行 `git add` 來更新暫存區的內容 - 對於已被刪除的文件,使用 `git add` 可以將這個刪除操作添加到暫存區 --- ### `rm` - `git rm` 是 Git 中的一個命令,用於從工作目錄和索引(暫存區)中移除文件 - 這個命令不僅從 Git 的追蹤列表中刪除文件,還會從工作目錄中刪除該文件,使其不再出現在未來的提交中。 #### 主要功能 1. 從工作目錄和暫存區移除文件: - 使用 `git rm` 會同時從當前的工作目錄和暫存區中刪除指定的文件。 2. 準備文件刪除的提交: - 這個命令將刪除操作暫存,準備將這些更改包含在下一次提交中。 - 例如:使用 `git rm` 命令移除工作目錄中的文件之後,將這次刪除操作暫存(staged)以便進行下一次的提交(commit),用於記錄和追蹤對文件系統所做的更改。 3. 停止追蹤文件,但保留在工作目錄: - 使用 `--cached` 選項可以讓 Git 停止追蹤該文件,但文件仍然保留在您的工作目錄中。 #### 使用方式 1. 刪除單個文件: ```git= git rm <文件名> //例如,git rm file.txt 會從 Git 中移除 file.txt 並將此更改暫存。 ``` - 單純使用`rm` 刪除檔案 ![image](https://hackmd.io/_uploads/S1buvvWPT.png) - `rm` 像`add`一樣可以包含在commit ![image](https://hackmd.io/_uploads/BJQFDwbva.png) 2. 刪除多個文件: ```git= git rm <文件1> <文件2> ... //這樣可以一次刪除多個文件。 ``` 3. 使用萬用字符刪除多個文件: ```git= git rm '*.txt' //這會刪除所有以 .txt 結尾的文件。 ``` 5. 僅從 Git 中移除,但保留文件在工作目錄中: ```git= git rm --cached <文件名> //這個命令會從 Git 的追蹤列表中移除文件,但不會從工作目錄中刪除它。 ``` #### 注意事項: - 使用 `git rm` 前確保您確實想要刪除這些文件。一旦提交後,這些文件就會從 Git 歷史中刪除。 - 如果只是想從暫存區移除更改(而不是從工作目錄中刪除文件),應該使用 `git reset`。 - 在執行 `git rm` 之後,需要進行提交操作以將這些更改永久記錄到版本歷史中。 - `git rm` 是一個強大的工具,適用於當您需要從版本控制中完全移除文件時。正確使用此命令可以幫助保持您的倉庫乾淨和有序。 --- ### `commit` `git commit` 是用於將更改從暫存區提交到 Git 倉庫中的命令。這個步驟記錄了版本歷史的快照,並允許開發者為所做的更改提供描述性消息。 #### 基本用法 ```git= git commit -m "提交信息" ``` - `-m "提交信息"`: 提交時附帶的消息,用於解釋這次提交所包含的更改。 #### 常用選項 - **添加所有更改(包括新文件和刪除的文件)到提交中** ```git= git commit -a -m "提交信息" ``` `-a` 選項自動將所有已追蹤的修改和刪除的文件添加到暫存區。 - **使用文本編輯器撰寫提交信息** ```git= git commit ``` 如果不使用 `-m` 選項,Git 將打開配置的文本編輯器,讓您在那裡撰寫提交消息。 - **更改上一次提交** ```git= git commit --amend ``` 如果需要更正最後一次提交的消息或更改,可以使用 `--amend` 選項。 - **跳過暫存區** ```git= git commit -am "提交信息" ``` 結合 `-a` 和 `-m` 選項可以跳過 `git add` 步驟,直接將所有已追蹤的文件更改提交。 #### 注意事項 - 前提:在使用 `git commit` 之前,需要先使用 `git add` 將想要提交的更改加入暫存區。 - 提交消息的重要性:良好的提交消息對於瞭解項目歷史和更改原因至關重要。 #### 操作範例 1. 這個例子先將 `file1.txt` 添加到暫存區,然後進行提交,並為這次提交提供了一個簡短的描述 2. 接著在目錄中新增一個 `file2.txt`檔案並添加到暫存區,然後進行提交,並為這次提交提供了一個簡短的描述 ```git= git add file1.txt git commit -m "修正了 file1.txt 中的錯誤" git add file2.txt git commit -m "新增 file2.txt" ``` - file1.txt 提交前 ![image](https://hackmd.io/_uploads/SyfyrQZDp.png) - file2.txt 提交後,會新增兩個commit object ![image](https://hackmd.io/_uploads/BylVr7bvT.png) ### branch - `branch` 指令在 Git 中用於管理分支,包括創建、列出、重命名和刪除分支 - 分支使得同時在多個不同的功能上工作變得更加容易。 #### 常用選項 - 創建分支 ```git= git branch <分支名稱> ``` 創建一個新的分支,但不會自動切換到該分支。 - 列出所有分支 ```bash= git branch ``` 列出倉庫中的所有本地分支。當前分支會以星號 (*) 標記。 - 切換分支 ```bash= git checkout <分支名稱> ``` 切換到指定的分支。 - 創建並切換到新分支 ```bash= git checkout -b <分支名稱> ``` 創建一個新的分支並立即切換到該分支。 #### 重命名分支 - 當前分支重命名 ```bash= git branch -m <新分支名稱> ``` - 非當前分支重命名 ```bash= git branch -m <舊分支名稱> <新分支名稱> ``` #### 刪除分支 - 刪除本地分支 ```bash= git branch -d <分支名稱> ``` `-d` 選項用於安全刪除,只能刪除已合併到上游的分支。 - 強制刪除本地分支 ```bash= git branch -D <分支名稱> ``` `-D` 是 `-d` 的強制版本,可以刪除尚未合併的分支。 #### 注意事項 - 在創建或切換分支之前,最好保證工作目錄是乾淨的(沒有未提交的更改)。 - 刪除分支前,確保不再需要該分支上的更改,特別是未合併的分支。 #### 範例 - 目標 : 建立一個bugfix branch,並checktout到該branch 進行提交 - 初始狀態 ![image](https://hackmd.io/_uploads/SyfyrQZDp.png) - `git branch bugFix` :創建名為 `bugFix` 的新分支 ![image](https://hackmd.io/_uploads/r1s-DQ-Dp.png) - `git checkout bugFix` : checktout到 `bugFix` 分支 ![image](https://hackmd.io/_uploads/SJxED7-wp.png) - `git checkout bugFix` : 在 `bugFix` 分支進行提交 ![image](https://hackmd.io/_uploads/HynvvQ-wp.png) ### `merge` - `git merge` 指令用於將兩個或多個開發歷史合併在一起。 - 這通常用於將一個分支的更改合併到另一個分支中。 #### 基本合併 ```bash= git merge <分支名稱> ``` - 將指定分支的更改合併到當前分支。 - 需要先切換到目標分支,然後執行此命令。 #### 合併時解決衝突 - 如果合併過程中出現衝突,Git 會標記出衝突的文件。 - 需要手動解決這些衝突,然後繼續合併過程。 #### 合併策略 - **Fast-forward 合併**: - 如果被合併分支是目標分支的直接後續,Git 將進行快進合併,簡單地更新指針。 - **Three-way 合併**: - 如果分支歷史有所偏離,Git 將創建一個新的合併提交。 #### 避免快進合併 ```bash= git merge --no-ff <分支名稱> ``` - 使用 `--no-ff` 選項可以強制創建一個新的合併提交,即使快進合併是可能的。 #### 合併提交 - 完成合併後,如果進行了 three-way 合併,Git 將創建一個新的合併提交。 #### 注意事項 - 在合併之前,確保您的工作目錄是乾淨的(無未提交的更改)。 - 在合併重要分支之前,建議進行備份。 - 解決衝突時,謹慎操作,以免丟失重要更改。 #### 示範 1. 建立新的 `branch`,叫做 `bugFix` 2. 用 `git checkout bugFix` 切換到 `bugFix branch`並進行修改後`commit` ![image](https://hackmd.io/_uploads/HynvvQ-wp.png) 3. `git checkout` 切換回 `main branch`並進行修改後`commit` ![image](https://hackmd.io/_uploads/ryjw97bDT.png) 4. 執行`git merge bugFix` 將 `bugFix branch` `merge` 到 `main branch` 5. 這時會產生新的`commit object` `C4`,`main branch` 會指向`C4` `bugFix` 仍然指向`C2`,執行`git branch -f master C4`可以讓`bugFix`指向`C4` ![image](https://hackmd.io/_uploads/HyPztQ-vp.png) ### `rebase` - `git rebase` 是 Git 中的一個強大工具,用於重寫提交歷史,通過將一系列提交從一個分支上轉移到另一個基底分支上 - `rebase` 是 `merge branch` 的第二種方法`rebase` 就是取出一連串的 `commit`,"複製"它們,然後把它們接在別的地方 - `rebase` 的優點是可以建立更線性的 `commit history`, repo 中的 commit log 或者是 commit history 會更加簡潔好看 #### 基本重排 ```bash= git rebase <基底分支> ``` - 將當前分支的更改重新應用於指定的 `<基底分支>` 上。 - 這會使得當前分支的提交在基底分支的最新提交之上。 #### 互動式重排 ```bash= git rebase -i <基底分支> ``` - 啟動互動模式,允許用戶選擇每個提交要進行的操作(如重排、刪除、修改等)。 #### 使用 `rebase` 進行衝突解決 - 在 `rebase` 過程中,如果遇到衝突,需要手動解決這些衝突,然後繼續重排過程。 #### 中斷重排 ```bash= git rebase --abort ``` - 如果重排過程中遇到問題,可以使用此命令中斷重排。 #### 完成重排 ```bash= git rebase --continue ``` - 在解決衝突後,使用此命令繼續重排過程。 #### 注意事項 - `git rebase` 會改變提交歷史,應謹慎使用,尤其是對於已經推送到共享倉庫的分支。 - 在進行重排之前,確保您的工作目錄是乾淨的(無未提交的更改)。 - 不建議在公共分支上使用 `rebase`,因為它會重寫歷史。 #### 示範 1. 建立 `bugFix branch`並`commit` 2. `checktout`回 `main branch` 再 `commit` ![image](https://hackmd.io/_uploads/BySnq7-PT.png) 4. 再次`checktout`到 `bugFix branch`,接著執行`git rebase main` 讓這個 `bugFix branch` 延續到 `main branch` 上 ![image](https://hackmd.io/_uploads/HyDgimWwp.png) 5. `checktout`到 `main branch`,接著執行`git rebase bugFix`,會執行`fast-forward merge` ![image](https://hackmd.io/_uploads/BJKNQo-Pp.png) ## 總結 這篇文章簡單介紹了分散式與集中式版本控制系統的區別,還有git 在本地端的指令介紹與實際操作,git 還有遠程倉庫的操作與更多進階功能,礙於篇幅有限就待之後文章繼續介紹 ## 參考資料 - https://learngitbranching.js.org/?locale=zh_TW - https://github.com/k88hudson/git-flight-rules/blob/master/README_zh-TW.md - https://scriptcrunch.com/295/ - chatgpt - bard - bing ai