可能在多人開發的環境,加上很多分支的關係,
不小心沒有控管好,沒有合併好或者有人改變倉庫過往的提交等等,
這些行為都有可能讓我們的 git 分支出問題。
我們現在已經學過基礎,並且也開始實戰應用,那就來見招拆招了。
當然,你確定倉庫是最正確的,同時你也沒有要保留什麼提交或分支,可以直接砍掉重新 clone 一份回來就好了。
有點像是作業系統遇到問題就直接重灌或還原,完全不想管發生了什麼事。
然後很快的這樣的狀況又發生了,於是我們沒有學到一些更深入的知識,只會重灌跟還原而已。
好了,每個人可以選擇面對問題與解決它的方式。
我們這邊是要針對 case 擅用我們的 git 技能來解決問題。
一樣先看狀態:
$ git status
On branch master
Your branch and 'origin/master' have diverged,
and have 2 and 3 different commits each, respectively.
(use "git pull" to merge the remote branch into yours)
nothing to commit, working tree clean
如果看到 diverged
發散這個字大概有點不妙了。
他告訴我們:
- 你處在 master 主分支
- 你的分支現在跟遠端倉庫的分支各走各的道
- 分別有 2 與 3 個提交不同,需要處理
好,那我們再來看一下現在的 log 前幾條
$ git log -3 --oneline
64de2b1 (HEAD -> master) 修改桌曆連結為2021桌曆
f4c41e4 公文建檔成功後顯示原本之檔名
1cc9971 self\settings.php 前台語後台登入驗證方法,在 header(Location;...) 加上 d
ie 函數。
從上面的 log 當中,我們沒有發現 origin/master 遠端倉庫的 master HEAD,
所以它才會說,現在我們各走各的路。
再來,我們看一下遠端倉庫的 log:
$ git log -4 --oneline origin/master
73a89ff (origin/master, origin/HEAD) 修改桌曆連結為2021桌曆
506d863 公文建檔成功後顯示原本之檔名
fa19f83 Auth class 在 sql 數值加上單引號
1cc9971 self\settings.php 前台語後台登入驗證方法,在 header(Location;...) 加上 d
ie 函數。
我們又發現了幾件事:
- 前面兩個 commit 內容看起來兩邊好像一樣,但 commit id 是不同的
- 本地的第 3 個 commit 等於遠端的第 4 個 commit
- 本地少了一個 commit 也就是遠端的第 3 個
那如果從 commit 沒看出這些差別怎麼辦?
或者不同的點非常的遙遠,例如幾十幾百個 commit 那種,我們不可能一一去比對。
沒關係,我們再來思考一下剛剛 local status 告訴我們的數字 2 and 3 吧。
通常我的經驗是:
- 前面的數字表示本地跟遠端的差別
- 後面的數字表示遠端跟本地的差別
其實就是主體不同而已,以這個案例來講,就是說:
- 本地往前 2 個版本可以對到遠端的相同版本
- 遠端往前 3 個版本可以對到本地的相同版本
通常遠端倉庫是對的情況下,我們就是處理本地端的部分就好。
那如果是要調整遠端倉庫的話,可以使用 git checkout origin/master
切到遠端分支處理。
這一次,我們也是排除暴力強拉強推法。
知道問題後就比較有方向了。
首先,最懶的方法就是 git pull origin master
把倉庫拉回來 merge 就是了
這樣看起來好像解決問題了,可是呢…
$ git pull origin master
省略
$ git status
On branch master
Your branch is ahead of 'origin/master' by 3 commits.
(use "git push" to publish your local commits)
nothing to commit, working tree clean
變成本地領先了 3 個 commit 了,我們看一下紀錄:
$ git log -8 --oneline
abfa4bb (HEAD -> master) Merge branch 'master' of 192.168.1.8:/web/repo
64de2b1 修改桌曆連結為2021桌曆
f4c41e4 公文建檔成功後顯示原本之檔名
73a89ff (origin/master, origin/HEAD) 修改桌曆連結為2021桌曆
506d863 公文建檔成功後顯示原本之檔名
fa19f83 Auth class 在 sql 數值加上單引號
1cc9971 self\settings.php 前台語後台登入驗證方法,在 header(Location;...) 加上 d
ie 函數。
f7f48a0 修正需簽核假單導錯頁面問題
果然多了 3 個 commit 也就是一個 merge 跟兩個之前我們發現的提交內容一樣但其實 commit id 不同的紀錄,
雖然原本漏掉的 commit 已經補回來了,但這樣會有三個問題:
- commit 很醜,會有一直重複的狀況還有 merge
- 因為領先 3 個 commit 以後推拉專案永遠都會一直 merge merge merge
- 以後每次看紀錄的時候,前面那三個都會先看到才會看到實際新的 commit
當然這些你都不在意的話,我也沒意見,反正專案是完整的就是了。
以前我也是這樣解決這種問題的,當時其實也搞不清楚到底 pull 回來 git 都做了什麼。
反正專案完整就好了,現在我不這麼想,應該真正去了解問題然後排除它。
其實要使用拉回來的方式來處理也不是不行,但要接著把問題處理完,也就是多了 3 個 commit 這一塊。
由上面的 commit 可以知道:
commit 73a89ff (origin/master, origin/HEAD)
這是第 4 個 commit 也是 origin/master 遠端倉庫所在的 commit,
由這個 commit 以下看起來 commit 都是完整的,那我們就放棄前面多出來的 3 個 commit 就好了
$ git reset --hard 73a89ff
HEAD is now at 73a89ff 修改桌曆連結為2021桌曆
$ git status
On branch master
Your branch is up to date with 'origin/master'.
nothing to commit, working tree clean
$ git log -1 --oneline
73a89ff (HEAD -> master, origin/master, origin/HEAD) 修改桌曆連結為2021桌曆
看到 HEAD 三個狀態才放心,表示問題解決了。
故事還沒完,這邊,我們回到還沒有 pull 回來的狀況,我想提供另外一種解法:
$ git reset --hard 64de2b1
HEAD is now at 64de2b1 修改桌曆連結為2021桌曆
$ git status
On branch master
Your branch and 'origin/master' have diverged,
and have 2 and 3 different commits each, respectively.
(use "git pull" to merge the remote branch into yours)
nothing to commit, working tree clean
$ git log -3 --oneline
64de2b1 (HEAD -> master) 修改桌曆連結為2021桌曆
f4c41e4 公文建檔成功後顯示原本之檔名
1cc9971 self\settings.php 前台語後台登入驗證方法,在 header(Location;...) 加上 d
ie 函數。
嘿嘿,沒錯,我們又回來了。
既然往前退兩個版可以先跟遠端倉庫找到相同的 commit,
那我們就先退回去:
$ git reset --hard HEAD~~
HEAD is now at 1cc9971 self\settings.php 前台語後台登入驗證方法,在 header(Locat
ion;...) 加上 die 函數。
$ git log -2 --oneline
1cc9971 (HEAD -> master) self\settings.php 前台語後台登入驗證方法,在 header(Loc
ation;...) 加上 die 函數。
f7f48a0 修正需簽核假單導錯頁面問題
$ git status
On branch master
Your branch is behind 'origin/master' by 3 commits, and can be fast-forwarded.
(use "git pull" to update your local branch)
nothing to commit, working tree clean
因為我們回到了與遠端倉庫一樣擁有的 commit,
但這個 commit 並不是 origin/master origin/HEAD 也就是並非倉庫最新的 commit,
git 告訴我們落後了 3 個 commit, 這時候把遠端倉庫拉回來補上這些漏掉的 commit 就解了:
$ git pull origin master
省略
$ git status
On branch master
Your branch is up to date with 'origin/master'.
nothing to commit, working tree clean
$ git log -2 --oneline
73a89ff (HEAD -> master, origin/master, origin/HEAD) 修改桌曆連結為2021桌曆
506d863 公文建檔成功後顯示原本之檔名
好了,我們總結一下,其實這兩種處理方式只是順序的不同而已啦。
我喜歡第二種解法的原因是每次看到 merge 都會覺得很煩,好像就是告訴我什麼東西弄錯了一樣,
心裡都會有點不踏實,第二種解法不會有 merge 出現。
希望你們也跟我一樣覺得解 git 問題就像是在玩遊戲一樣有趣。