[教學] git應用-我的 commit 亂掉了 - 討論區

[教學] git應用-我的 commit 亂掉了

visibility文章瀏覽次數 69 reply_all文章回覆數 0

特種兵

特種兵圖像(預設)

2020-09-24 10:23:07

From:211.23.21.202

可能在多人開發的環境,加上很多分支的關係,

不小心沒有控管好,沒有合併好或者有人改變倉庫過往的提交等等,

這些行為都有可能讓我們的 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 問題就像是在玩遊戲一樣有趣。