cover

深入淺出進階 Git 指令:分支管理、合併策略與版本還原全攻略

如果你已經掌握了 Git 基本指令,那恭喜你,你已經可以用 Git 做日常的版本管理了。但是,真實世界的開發可沒那麼簡單,對吧?

這篇文章要介紹一些常用的進階 Git 指令,主要涵蓋分支管理、合併衝突、版本回退等操作。這些指令在日常開發中超實用,學會了能讓你更有效率地管理版本控制,也能讓你在團隊協作時更得心應手。

flowchart TB
    subgraph 分支管理
        A[查看分支 branch -a] --> B[創建分支 checkout -b]
        B --> C[重命名 branch -m]
        B --> D[刪除 branch -d/-D]
        B --> E[推送 push origin]
    end
    subgraph 合併與衝突
        F[merge] --> G[--no-ff 保持歷史]
        F --> H[解決衝突 mergetool]
        F --> I[放棄合併 --abort]
    end
    subgraph 還原與重置
        J[reset --soft] --> K[保留暫存區]
        L[reset --mixed] --> M[保留工作目錄]
        N[reset --hard] --> O[全部回退]
        P[revert] --> Q[生成新提交]
    end

分支管理

查看所有分支

git branch -a

這條指令會列出所有本地和遠端的分支。想知道你的 repo 裡到底有多少分支?跑一下就知道了。

顯示分支詳細信息

git branch -vv

這會顯示每個分支的最新提交以及追蹤的遠端分支,超方便用來了解每個分支的狀態。特別是當你同時在好幾個分支上工作的時候,這個指令簡直是救命恩人。


創建並切換到新分支

git checkout -b new-branch-name

這條指令會創建一個新的分支並立即切換到該分支,方便快速開始新功能的開發。基本上每天開工第一件事就是開個新分支。


刪除本地分支

git branch -d branch-name

如果該分支有未合併的變更,可以強制刪除:

git branch -D branch-name

記住,小寫 -d 是安全刪除(會檢查有沒有未合併的東西),大寫 -D 是強制刪除(不管三七二十一直接砍)。平時用 -d 就好,除非你很確定要放棄那個分支上的所有工作。


重命名分支

git branch -m new-branch-name

這會把當前分支重命名。打錯分支名稱的時候特別好用。


推送新分支到遠端

git push origin new-branch-name

把本地新分支推送到遠端倉庫,這樣團隊成員就能看到並使用你的分支了。


合併與衝突解決

合併分支

git merge branch-name

把指定分支合併到當前分支。

使用 --no-ff 保持合併歷史

git merge --no-ff branch-name

這樣可以保留合併歷史,便於追蹤分支的合併情況。什麼意思呢?預設的 merge 如果可以 fast-forward 就不會產生合併 commit,加了 --no-ff 會強制產生一個合併 commit,讓你的 git log 更清楚地看到「這裡合併了一個分支進來」。

想深入了解 merge 和 rebase 的差別?看看 Merge vs Rebase 的差異與應用


解決合併衝突

當合併出現衝突時,Git 會標記出衝突部分。別慌,手動解決後再提交就好了:

git add conflicted-file
git commit

使用合併工具自動解決衝突

git mergetool

這會啟動你配置的合併工具,幫助你更直觀地解決衝突。VS Code 的內建合併工具就很好用。


放棄合併

git merge --abort

如果合併過程不如預期,或者衝突太多你暫時不想處理,用這個指令直接放棄合併,回到合併前的狀態。沒什麼好丟臉的,策略性撤退也是一種智慧。


還原與重置

還原單個文件

git checkout -- filename

這會把文件還原到上次提交的狀態。注意,這個操作是不可逆的,還原後你的修改就找不回來了。


回退提交

如果你需要撤銷最近的提交,但保留變更,可以用:

git reset --soft HEAD^

如果要撤銷最近兩次提交:

git reset --soft HEAD~2

如果要徹底撤銷變更並回到提交前的狀態(小心使用!):

git reset --hard HEAD^

重置的影響

這三個模式的差別搞清楚很重要:

  • --soft:只回退提交,保留暫存區和工作目錄的變更。就像是把 commit 拆開來,但你改的東西都還在。
  • --mixed(默認):回退提交並重置暫存區,但保留工作目錄的變更。改的東西還在,但需要重新 git add
  • --hard:回退提交並重置暫存區和工作目錄,所有未提交的變更將被刪除。這個最危險,用之前三思!

還原遠端提交

git revert commit-hash

這會生成一個新的提交來撤銷指定的提交,而且不會影響提交歷史。這是在公共分支上撤銷變更最安全的方式,因為它不會重寫歷史。


進階的 rebase 操作

交互式 rebase

git rebase -i HEAD~3

這可以讓你重新排序、修改或合併最近的提交,保持提交歷史的整潔。比如你連續做了三個小 commit,想合併成一個有意義的 commit,就可以用這個。

解決 rebase 衝突

  1. 當出現衝突時,手動編輯衝突文件以解決問題。
  2. 添加解決後的文件:
git add conflicted-file
  1. 繼續 rebase:
git rebase --continue

rebase vs merge

  • Rebase:重寫提交歷史,使歷史更線性,適合在私有分支上使用。
  • Merge:保留分支歷史,適合在公共分支上使用,能清楚看到分支的合併點。

選擇合適的方法取決於團隊的工作流程和需求。這部分內容在 Merge vs Rebase 的差異與應用 有更詳細的說明。


其他進階操作

cherry-pick 指定提交

git cherry-pick commit-hash

選擇一個提交並把它應用到當前分支。適用於你想從一個分支挑選特定變更到另一個分支的情況。比如同事在 A 分支上修了一個 bug,你的 B 分支也需要這個修復,就可以直接 cherry-pick 過來。


stash 暫存進階用法

保存帶有訊息的 stash

git stash save "描述訊息"

查看所有 stash 條目

git stash list

應用特定 stash

git stash apply stash@{index}

彈出 stash(應用並刪除)

git stash pop

刪除特定 stash

git stash drop stash@{index}

stash 就像是一個臨時的「口袋」,你可以把還沒做完的東西先塞進口袋裡,等處理完其他事情再拿出來繼續做。


reflog 檢查所有 Git 操作

git reflog

顯示你所有 Git 操作的歷史記錄,方便查找回退點。即使你用 reset --hard 搞砸了什麼,reflog 通常還能救你一命。它就像是 Git 的「黑盒子」,記錄了你做過的所有操作。


log --graph 視覺化提交歷史

git log --graph --oneline --all

這會顯示一個圖形化的提交歷史,方便理解分支和合併的過程。在終端機裡看到漂亮的分支圖,感覺就很 pro 對吧?


diff --staged 比較已暫存的文件變更

git diff --staged

比較已經 git add 到暫存區的變更。在提交前跑一下這個指令檢查內容,是個好習慣。


tag 標記版本

創建輕量標籤

git tag v1.0.0

創建註釋標籤

git tag -a v1.0.0 -m "Release version 1.0.0"

推送標籤

git push origin v1.0.0

標籤通常用在版本發佈的時候,讓你能快速找到某個版本對應的程式碼。更多關於版本發佈的內容,可以看 Release 管理


實際案例

多人協作中的 rebase 使用

在多人協作的專案中,使用 rebase 可以保持提交歷史的整潔。例如,當你在功能分支上工作,需要把最新的 main 分支變更整合過來,可以用:

git checkout feature-branch
git rebase main

這樣可以把 feature-branch 的提交基於最新的 main 分支,避免不必要的合併提交。

使用 stash 管理臨時變更

當你正在處理一個功能,但需要切換到另一個分支修復緊急問題,可以用 stash 暫存當前變更:

git stash save "正在開發新功能"
git checkout urgent-fix
# 修復問題並提交
git checkout feature-branch
git stash pop

這樣可以方便地在不同任務間切換,而不會丟失未完成的工作。


延伸閱讀