工作以後發現是git指令常常忘記又要一直查,所以這邊整理我遇到的問題。
退版
- 我有很多不需要的改動,要怎麼清空
- 只清空「working directory 的改動」:
git restore .- staged(已 git add)
- 尚未staged
- modified(已追蹤檔案被改) // ⇐ 只刪掉這個
- untracked(新檔案)
- 連 staging area 也一起清:
git reset --hard HEAD- staged(已 git add) // ⇐ 刪掉這個
- 尚未staged
- modified(已追蹤檔案被改) // ⇐ 刪掉這個
- untracked(新檔案)
- 連 untracked 檔案也一起刪(最乾淨)
git reset --hard HEAD + git clean -fd- staged(已 git add) // ⇐ 刪掉這個
- 尚未staged
- modified(已追蹤檔案被改) // ⇐ 刪掉這個
- untracked(新檔案)// ⇐ 刪掉這個,透過git clean -fd
- 只清空「working directory 的改動」:
- 把 file.txt 的內容,強制換成 <hash> 這個 commit 裡的版本
git checkout <hash> -- file.txt git restore --source=<hash> file.txt // 這是新版 Git 推薦的用法,比 checkout 更安全 - 不小心commit不需要的檔案,想把檔案從版本控制中完全移除
git rm --cached <file> git commit - 暴力退版:把你的整個工作目錄、暫存區(index)、HEAD 全部強制回到指定的 commit 狀態,之後的修改全部丟掉
git reset --hard <hash> // 小心使用,非常暴力 - 把不小心 commit 的檔案還原到「commit 前的乾淨狀態」但「把最新內容留在工作目錄」
git reset --soft HEAD~1- 當前 commit 被取消(回到 commit 前)
- 你的檔案內容全部保留
- 之前加進 staging 的檔案仍在 staging area,你可以自行 unstage 或調整
Fetch & Pull
- git fetch是只fetch當前branch的upstream branch還是全部都會fetch? Answer: 全部的upstream branch都會fetch
- 問題同上,那git pull呢? Answer: git pull = git fetch + git merge <目前 branch 的 upstream branch>,所以是全部的branch都會fetch,只會merge「目前 branch 所追蹤的 upstream branch」
情境
我目前在dev branch上已經有一些modified file,但是同事在遠端開了新branch,我需要改成在同事的遠端新branch後續開發,我可以怎麼把本地更新成遠端狀態,然後再把我目前的改動apply上去?
Case 1. dev branch還沒有commit
-
確認狀態
git branch --show-current // 應該顯示 dev git remote -v // 確認你用的是對的遠端(通常叫 origin) -
現在有 modified file,最安全就是先 stash。
git stash push -u -m "看要打什麼訊息"Note:
- -u 表示—include-untracked
- push可以省略不過留著會讓語意更清楚,直接
git stash(沒有 subcommand)是快捷寫法
-
把遠端最新狀態抓下來(包含新 branch)
git fetch --all --prune git branch -r // 應該要看到遠端新 branch: origin/feature/new-branch -
切到「遠端新 branch」並建立本地追蹤分支
git switch -c feature/new-branch --track origin/feature/new-branch git branch // 應該要在feature/new-branch上 git log --oneline // 應該要看到HEAD -> feature/new-branch, origin/feature/new-branch git status // 乾淨 -
把剛剛的改動套回來
git stash apply // apply不會立刻刪掉 stash,比較安全 git status // 應該又回到第一步驟的狀態 > 如果有衝突:Git 會標出 conflict 檔案。 > 修改衝突後 git add <衝突檔案...> git status // 直到 status 不再顯示 unmerged paths > 確定都沒問題後,再把 stash 刪掉 git stash drop git stash list // 不見了 -
提交新的改動 add, commit, push
Case 2. dev branch已經commit
跟Case 1的差異是dev branch 上已經 commit 過一些改動,目標把「dev 上新增的 commit」搬到「遠端新 branch」後面。
-
確認目前狀態
git branch --show-current # 應顯示 dev git status # working tree 應為乾淨 git log --oneline確認重點:
- 改動都已經是 commit
- 沒有殘留 modified / staged 檔案
-
抓取遠端最新狀態(包含新 branch)
git fetch --all --prune git branch -r // 應該要看到 origin/feature/new-branch -
(可選)建立本地追蹤分支
不是必要,但可讓 branch 關係更清楚git branch feature/new-branch origin/feature/new-branch -
將 dev 上的 commit rebase 到遠端新 branch 上
git checkout dev git rebase origin/feature/new-branchrebase 在做什麼?
- 找出
dev相對於原本 base 的 commit - 將這些 commit:
- 一個一個重新套用
- 接在
origin/feature/new-branch後面
結果示意:
origin/feature/new-branch --- B1 --- B2 \ D1 --- D2 (原本在 dev 的 commit) - 找出
-
若發生衝突 Git 會在衝突處停下來。 正確處理流程:
# 手動解衝突 git add <衝突檔案...> git rebase --continue⚠️ 注意事項:
- 不要執行
git commit - 不要執行
git merge - 直到出現:Successfully rebased and updated refs/heads/dev.
- 不要執行
-
驗證 rebase 結果
git log --oneline // `dev` 的 commit全部接在 `origin/feature/new-branch` 之後 -
後續處理方式:改成在 feature/new-branch 繼續開發
git checkout -B feature/new-branch git push --force-with-lease origin feature/new-branch適合情境:
dev只是暫時中繼- 後續開發以
feature/new-branch為主