網路上教學廢話好多好煩。
沒人想看你把一堆 commit 版本號打出來,我還要一個一個對你在講哪個 commit,有夠蠢。
剛開始學 git 的時候東一篇西一篇就是不知道完整的流程,每個步驟都要上網查,光這篇文章的資訊可能就分散在四五個不同頁面很浪費時間,一開始只想先能動,之後遇到問題再說,所以這篇以能動起來為準,並且給出多個基礎指令,至少出現問題知道怎麼查。
原理篇
git是一個版本管理工具,實際使用時有三個層面,分別是你的硬碟、本地儲存庫 (git)、遠端儲存庫 (github/gitlab)。你的硬碟什麼版本都不知道只放檔案當前狀態,儲存庫儲存所有版本,遠端儲存庫是最後同步共享的地方。
撰寫程式時,commit 提交到本地儲存庫,push 到遠端讓大家看。
檔案狀態(可先跳過)
以下修改自官方說明:三種狀態
Git 會把你的檔案標記為三種主要的狀態:已修改modified、已預存staged、已提交committed。
- 己修改 => 檔案被修改但尚未預存(處於工作目錄 working directory 中)。
- 已預存 => 檔案將會被存到預存區,準備被提交(git add 後放在預存區 staging area)。
- 已提交 => 檔案己安全地存在你的本地儲存庫(commit 後的狀態)。
(Working Dir) participant B as 已預存 Staged
(Staging Area) participant C as 已提交 Committed
(Local Repo) participant D as 已推送 Pushed
(Remote Repo) A ->> B: git add B ->> C: git commit C ->> D: git push
版本狀態(可先跳過)
Git 可以看作一顆樹,每次 commit 都有獨一無二的 hash,並且指向上次的 commit 以紀錄每次版本變更,可新建分支功能,可以作為功能開發/修復緊急 bug 使用。
基礎指令篇
1. 初始化
git init
2. 索引檔案
git add <file-name>
git add . # 索引全部檔案
git reset <file-name> # 移除索引檔案
git reset # 移除全部索引
3. 提交版本並附註
到這步就可以跑起基本的 git 了。
git commit -m <comments>
4. 查看狀態
git status
git log
5. 分支
當你工作變複雜一條分支不夠用就會用到這些。
git branch # 查看
git branch <name> # 新建
git checkout <name> # 切換
git branch -D <name> # 刪除
git branch -m <old-name> <new-name> # 改名
git merge "NAME" # 合併
上傳到 Github
1. SSH
- 產生ssh金鑰
- (Optional) 隱藏信箱Setting>Email勾選 “Block command line pushes that expose my email”,如要隱藏信箱,請到
https://api.github.com/users/你的github名稱
查看下面需要的 ID - 設定名稱及信箱,如不需隱藏信箱則直接打自己的信箱
git config --global user.name "NAME"
git config --global user.email "{ID}+{username}@users.noreply.github.com"
- 上傳
git push -u origin main
- (選用) 新建的 git 連接既有的 github repo
git remote add origin git@github.com:your-username/your-repo.git
ssh -T git@github.com
git remote set-url origin git@github.com:ZhenShuo2021/ZhenShuo2021.github.io.git
2. (Optional) GPG
請直接看 利用 GPG 簽署 git commit 的教學。
如果要隱藏信箱在 GPG 設定時需使用剛剛設定的 noreply 信箱。
如果已經有 GPG key,可以用以下指令刪除:
git config --global --unset-all user.signingkey
還原工作階段1
# 軟重置:只刪 commit
git reset --soft <hash>
# 混合重置:預設方式,刪 commit 和 add
git reset --mixed <hash>
# 硬重置:連你的寫的程式都刪了
git reset --hard <hash>
- [進階] 新增部分commit Git Cherry Pick
# Apply 特定 commit 到當前分支
git cherry-pick <commit-hash>
# 可以連續挑選多個 commit
git cherry-pick <commit-hash1> <commit-hash2> ...
正式工作篇
By 码农高天
一開始都一樣
git clone xxx.git # 拉取遠端儲存庫
git checkout -b <my-feature> # 新建分支進行工作
git add <file>
git commit -m <comments>
# git push origin <my-feature>
因為遠端更新,所以回到 main branch 同步遠端的新 commit,之後 rebase2 main branch,這樣就可以push。
git checkout main # 回到main分支
git pull origin main # 從遠端倉庫更新到main分支到本地
git checkout <my-feature> # 回到feature分支
git rebase main # 把"feature"的更新接到main之後
git push -f origin <my-feature> # 推送到遠端
接下來可以:
- Pull request 請求合併
- Squash and merge 合併並整合為一個commit
- Delete branch 刪除合併完的分支
遠端都處理好剛剛的分支後,刪除 branch 再同步 main branch。
git checkout main
git branch -D <my-feature>
git pull origin main
完整版的架構圖:
Workdir participant ST as 預存
Staging participant CO as 本地儲存庫
Local Repo participant RM as 遠端儲存庫
Remote Repo Note over WD: 1. git clone xxx.git RM->>WD: 複製儲存庫到本地 Note over WD: 2. git checkout -b my-feature WD->>WD: 創建並切換到新分支 Note over ST: 3. git add file WD->>ST: 將檔案添加到預存區 Note over CO: 4. git commit -m comments ST->>CO: 提交更改 Note over RM: 5. (Optional) git push origin my-feature CO->>RM: 推送分支到遠端 Note over WD: 6. git checkout main WD->>WD: 切換到 main 分支 Note over WD: 7. git pull origin main RM->>WD: 更新 main 分支到本地 Note over WD: 8. git checkout my-feature WD->>WD: 切換回 feature 分支 Note over WD: 9. git rebase main WD->>WD: 基於 main 分支接上 feature 分支 Note over RM: 10. git push -f origin my-feature WD->>RM: 推送更新到遠端
別用 git pull?
By Philomatics
原理是避免 git pull 產生一堆無用的 merge conflict。其實這和码农高天的用法是一樣的,只是合併成 git pull –rebase。如果沒衝突那很好,有衝突則 git rebase –abort 回復再做一般的 git pull。
rebase vs cherry-pick
Rebase: 將一個分支的所有變更移到另一個分支的頂端,用於保持線性歷史
Cherry-pick: 提取單個 commit 到另一個分支,用於只需要特定更改的情況
選用:
Rebase 移動整個分支,cherry-pick 只移動單個 commit
Rebase 用於整合分支,cherry-pick 用於選擇性地應用更改