- HEAD: HEAD 是一個 reference,它是指向目前所 checkout 的 commit,其實就是你目前所在的 commit。在 commit tree 中,HEAD 總是指向最近的一次commit。
git log
用於查看最新 commit 紀錄,可指定顯示的筆數。
git log --oneline -<number>
# 能顯示多少條就顯示多少條
git log --oneline
# 只顯示最新五條
git log --oneline -5
顯示結果:
# $git log --oneline -5
e295702 (HEAD -> main) A
21582f6 B
79e280f C
b51ec3b D
ad7f577 E
按 q
離開 git log
基本指令
# 查看 remote
git remote -v
# 新增 remote repo
git remote add origin <repo>
# 查看當前 working tree
git status
# 新增全部 changes 到暫存區
git add .
# 將暫存區的 changes 提交
git commit -m "msg"
# 將 commit 推上 remote repo,分支名稱為 <branch_name>
git push origin <branch_name>
git branch
# 列出分支列表
git branch -a
# 新增
git branch A
# 刪除本地分支
git branch -d A
# 刪除遠程分支
git push origin --delete A
# 切換
git checkout A
git merge
git merge 用於將 A 分支上的修改合併到 B 分支。
假設要將分支 A 的修改合併到分支 develop 可以這麼操作:
git checkout A
git add .
git commit -m "test"
git checkout develop
git merge A
快轉模式(Fast-forward)
快轉模式合併是 Git 中的一種合併策略(也是預設的模式),它通常發生在以下情況:
- 你在一個分支上進行了一些提交。
- 在進行合併操作之前,目標分支(通常是 main 分支)沒有新的提交。
在這種情況下,Git可以簡單地將目標分支 HEAD 前進到與您目前分支的最新提交相同的地方,而不需要建立一個新的 commit。
特性包括:
- 不會建立新的合併提交,因為沒有衝突需要解決。
- 歷史記錄看起來非常線性,就好像沒有進行合併操作一樣。
- 通常用於將特性分支的變更合併到主分支,以保持主分支的更新。
舉例來說,現在 dev 分支 HEAD 在 c4,而 master 分支的 HEAD 在 C2。
此時我們可以透過 git merge
的方式將 master 的 HEAD 前進到 C4,並且不需要新增額外的合併 commit。
git checkout master
git merge dev
git rebase
和 git merge 類似都是合併操作,但 git rebase 會修改歷史 commit,它會使分支移動到不同的 Commit 重新定義基準點。
合併版本
git checkout branch1
# 將 mater 當成基準點
git rebase master
當基準點改變就需要重新生成 commit 的 SHA-1 值,所以原本的 e3475, 76d12 在修改基準點後變成了 3a2e2, e45ch
修改歷史 commit
$ git rebase -i HEAD~3
取消 rebase 操作
git rebase 指令會導致 Commit 的 SHA-1 值改變,因此不能直接使用 git reset HEAD^–hard 的方式回到合併前的狀態。
需要先使用 git reflog
找回 rebase 操作時 commit 的 SHA-1 值,找到後再使用 git reset <commit> --hard
回到 rebase 前的狀態。
# $git reflog
...
153ab21 (master) HEAD@{3}: rebase: checkout master
b274b5a HEAD@{4}: checkout: moving from master to branch1
...
# $git reset b274b5a --hard
HEAD is now at b274b5a
或者也可以直接使用 git reset ORIG_HEAD --hard
回到 rebase 前的狀態。
ORIG_HEAD 會記錄「危險操作」之前 HEAD 的位置。例如分支合併或是 Reset 之類的都算是所謂的「危險操作」。
git revert & git reset
revert
: 是在「不破壞歷史紀錄」的前提下撤回指定 commit,並新增一個 revert 的 commit。reset --hard
: 此種模式完全不保留原始 commit 結點的任何資訊,會連同資料夾中實體檔案內容都進行重置,也就是直接將工作區、暫緩區及 git 目錄都重置成目標Reset結點的資料內容。reset --soft
: 此模式下會保留工作區資料內容,不會異動到目前所有的實體檔案內容;也會保留暫緩區資料內容,讓暫緩區與 git 目錄資料內容是一致的。
revert
revert 是在「不破壞歷史紀錄」的前提下撤回指定 commit。
以下方 commit 紀錄為例,指令 git revert HEAD~2
會撤回 study 的這個 commit 紀錄,並新增一個 commit Revert "study"
# git log --oneline
c0479f5 (HEAD -> main) day
0199749 study
0a38bea third
1ae88ed second
fa3d5af first
# git revert HEAD~
# git log --oneline
fd5db43 (HEAD -> main) Revert "study"
c0479f5 day
0199749 study
0a38bea third
1ae88ed second
fa3d5af first
如果想回到撤回 study 之前,直接 git reset --hard c0479f5
,這樣 study 就回來了
reset –hard
git reset --hard
# 回到 HEAD 的前 1 個版本 commit
git reset --hard HEAD~
# 回到 HEAD 的前 2 個版本 commit
git reset --hard HEAD~2
# 回到 HEAD 的前 3 個版本 commit
git reset --hard HEAD~3
...
以下面的 commit 紀錄為例:
HEAD~
是21582f6
HEAD~2
是79e280f
HEAD~3
是ad7f577
# $git log --oneline -5
e295702 (HEAD -> main) A
21582f6 B
79e280f C
b51ec3b D
ad7f577 E
不小心使用 hard 模式 Reset 了某個 Commit,救得回來嗎?
git log --oneline
查看 commit 紀錄
c0479f5 (HEAD -> main) day
0199749 study
0a38bea third
1ae88ed second
fa3d5af first
git reset --hard HEAD~2
回到前 2 個版本,log紀錄少了0199749
,c0479f5
0a38bea (HEAD -> main) third
1ae88ed second
fa3d5af first
git reset --hard <commit id>
就可以恢復被 reset 過的 commit
c0479f5 (HEAD -> main) day
0199749 study
0a38bea third
1ae88ed second
fa3d5af first
只需要記住 commit SHA-1 就可以將 HEAD 重新設回被 reset 過的 commit,完整流程如下:
# $git log --oneline
c0479f5 (HEAD -> main) day
0199749 study
0a38bea third
1ae88ed second
fa3d5af first
# $git reset --hard HEAD~2
HEAD is now at 0a38bea third
# $git log --oneline
0a38bea (HEAD -> main) third
1ae88ed second
fa3d5af first
# $git reset --hard c0479f5
HEAD is now at c0479f5 day
# $git log --online
c0479f5 (HEAD -> main) day
0199749 study
0a38bea third
1ae88ed second
fa3d5af first
找回 commit SHA-1 值
可以使用 git reflog
HEAD 有移動的時候就會紀錄(切分支或者reset都會移動HEAD),可以在這裡查看 reset 之前的 commit SHA-1:
0a38bea HEAD@{1}: reset: moving to HEAD~2
c0479f5 (HEAD -> main) HEAD@{2}: commit: day
0199749 HEAD@{3}: commit: study
0a38bea HEAD@{4}: commit: third
1ae88ed HEAD@{5}: commit: second
fa3d5af HEAD@{6}: commit (initial): first
git reset --hard c0479f5
就可以回到 reset HEAD~2 前的 HEAD
git cherry-pick
可以選擇並將指定的 commit 從一個分支應用到另一個分支。
git cherry-pick <commit-hash>
git cherry-pick 對於以下情況很有用:
- 合併特定的 commit:選擇合併一個或多個 commit,而不是將整個分支合併到目前分支。
- 修復錯誤:如果在一個分支上發現了錯誤,而這個錯誤在另一個分支上已經修復就可以用
git cherry-pick
來將修復的 commit 引入到當前分支,而無需合併整個分支。
Q&A
正在重訂基底
這表示 Git 正在進行 rebase 操作(git rebase
)。
解決方式
- 強制退出:執行
git rebase --abort
終止 rebase,這將會復原分支到 rebase 開始前的狀態。 - 完成rebase:解完 conflicts ->
git add & git rebase --continue
-> 繼續解直到沒有 conflicts -> git push
fatal: not a valid object name: ‘main’
可能是因為新 repo 沒有文件所導致的。
解決方式
# 新增文件
git add .
git commit -m "log"
git branch -a
# 這時候就會出現 main 分支了
You have divergent branches and need to specify how to reconcile them
git push 失敗
git pull 失敗
這是因為 pull 分支之前進行過 merge 合併更新分支操作,而其他人在你之前已經 push 過一個版本,導致版本不一致。
解決方式:git config pull.rebase false
skipped previously applied commit xxx
skipped previously applied commit xxx
hint: use --reapply-cherry-picks to include skipped commits.
hint: Disable this message with "git config advice.skippedCherryPicks false"
解決方式:git rebase --reapply-cherry-picks
git rebase –continue: Please enter the commit message for your changes
git rebase --continue
出現:
feat: A
# Please enter the commit messagefor your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
#
# interactive rebase in progress; onto 16832f7
# Last command done (1 command done):
# pick 7b45117 feat: A
# Next commands to do (5 remaining commands):
# pick 474bdfd B
# pick 58b9193 C
# You are currently rebasing branch 'feat/demo' on '16832f7'.
#
# Changes to be committed:
# ....
解決方式::wq
退出