今天 pull 程式碼的時候碰到以下問題(隱去了一些公司敏感資訊):

XXX@CN-00012645 MINGW64 /c/Gerrard/Workspace/XXX (master)
$ git pull
error: cannot lock ref 'refs/remotes/origin/feature/hy78861': is at d4244546c8cc3827491cc82878a23c708fd0401d but expected a6a00bf2e92620d0e06790122bab5aeee01079bf
From ssh://XXX
! a6a00bf2e92..f34729ba17a feature/hy78861 -> origin/feature/hy78861 (unable to update local ref)

這裡首先是你的 feature/hy78861 這個分支出現了問題,由於你現在在 master 分支,如果只需要拉下來 master 的程式碼,那可以用以下命令作為替代(第一個解決方案):

XXX@CN-00012645 MINGW64 /c/Gerrard/Workspace/XXX (master)
$ git pull origin master
From ssh://XXX
* branch master -> FETCH_HEAD
......
Current branch master is up to date.
  • 由於 git pull 會把所有 remote 的資訊全部拉下來,包括那個出錯的分支 feature/hy78861,所以只 pull 你需要的分支資訊就可以了。
  • 這是一個治標的辦法,這樣一來你每一次 pull 都需要帶上分支資訊,沒辦法一鍵同步所有的遠端分支資訊。

要治本需要了解問題的根本原因,看上面的 log 資訊,應該是分支索引 id 的資訊紊亂。

所以我們先搜一下 a6a00bf2e92620d0e06790122bab5aeee01079bf 的資訊:

XXX@CN-00012645 MINGW64 /c/Gerrard/Workspace/XXX (master)
$ grep -ri 'a6a00bf2e92620d0e06790122bab5aeee01079bf'
.git/info/refs:a6a00bf2e92620d0e06790122bab5aeee01079bf refs/remotes/origin/feature/hy78861
.git/logs/refs/remotes/origin/feature/HY78861:214f906ff67841712d6082f1a471cae91385cf2c a6a00bf2e92620d0e06790122bab5aeee01079bf XXX 1616051165 +0800 pull: fast-forward
.git/logs/refs/remotes/origin/feature/HY78861:a6a00bf2e92620d0e06790122bab5aeee01079bf d4244546c8cc3827491cc82878a23c708fd0401d XXX 1623054120 +0800 pull: forced-update
.git/packed-refs:a6a00bf2e92620d0e06790122bab5aeee01079bf refs/remotes/origin/feature/hy78861

然後搜一下 d4244546c8cc3827491cc82878a23c708fd0401d 的資訊:

XXX@CN-00012645 MINGW64 /c/Gerrard/Workspace/XXX (master)
$ grep -ri 'd4244546c8cc3827491cc82878a23c708fd0401d'
.git/logs/refs/remotes/origin/feature/HY78861:efaa737003ebf53deb81ba78cf62d395a6a03a0b d4244546c8cc3827491cc82878a23c708fd0401d XXX 1614914234 +0800 pull: fast-forward
.git/logs/refs/remotes/origin/feature/HY78861:d4244546c8cc3827491cc82878a23c708fd0401d f9650914c7a0fd3987a0dc106824d99c435297e3 XXX 1615431235 +0800 pull: storing head
.git/logs/refs/remotes/origin/feature/HY78861:c62e20a4c3a8a3860a915a8559cbf167da18a16f d4244546c8cc3827491cc82878a23c708fd0401d XXX 1616051205 +0800 pull: fast-forward
.git/logs/refs/remotes/origin/feature/HY78861:c62e20a4c3a8a3860a915a8559cbf167da18a16f d4244546c8cc3827491cc82878a23c708fd0401d XXX 1623053561 +0800 fetch: fast-forward
.git/logs/refs/remotes/origin/feature/HY78861:a6a00bf2e92620d0e06790122bab5aeee01079bf d4244546c8cc3827491cc82878a23c708fd0401d XXX 1623054120 +0800 pull: forced-update
.git/refs/remotes/origin/feature/HY78861:d4244546c8cc3827491cc82878a23c708fd0401d

最後再去 Gerrit 倉庫,看一下這個 repo 的分支資訊(我把一些資訊抹掉了):

問題顯然出在 feature/HY78861 和 feature/hy78861 上面,推測根本原因是:

  • 這兩個 feature branch 都是在外國的同事建立的,他們的工作環境是 Linux 系統,而中國的工作環境是 Linux 系統,再加上他們可能做了些不知道什麼的騷操作,由於系統差異導致問題。

我們重新觀察錯誤資訊:

cannot lock ref 'refs/remotes/origin/feature/hy78861': is at d4244546c8cc3827491cc82878a23c708fd0401d

看一下我們的本地檔案 C:\Gerrard\Workspace\XXX\.git\refs\remotes\origin\feature\HY78861(注意這裡是大寫),檔案內容是 :

  • d4244546c8cc3827491cc82878a23c708fd0401d

顯然這就是錯誤裡面定位的內容,那麼是不是把這個檔案裡面的內容改成 expected 就行了呢?

很可惜,失敗了:

XXX@CN-00012645 MINGW64 /c/Gerrard/Workspace/EXXX (master)
$ git pull
From ssh://XXX
+ a6a00bf2e92...d4244546c8c feature/HY78861 -> origin/feature/HY78861 (forced update)
error: cannot lock ref 'refs/remotes/origin/feature/hy78861': is at d4244546c8cc3827491cc82878a23c708fd0401d but expected a6a00bf2e92620d0e06790122bab5aeee01079bf
! a6a00bf2e92..f34729ba17a feature/hy78861 -> origin/feature/hy78861 (unable to update local ref)

這裡檔案中的資訊,被強制從 a6a00bf2e92620d0e06790122bab5aeee01079bf 復原成了 d4244546c8cc3827491cc82878a23c708fd0401d。

這裡我們總結一下問題:

  • HY78861 分支 remote 上的 id 是 d4244546c8cc3827491cc82878a23c708fd0401d
  • hy78861 分支 remote 上的 id 是 f34729ba17a48c9628dff31f8c6720843c6d1a74
  • id a6a00bf2e92620d0e06790122bab5aeee01079bf 來源未知,可能就是由於外國同事的某些騷操作引起的,可能是一個過期的 id 值,後來被上面的某一個覆蓋了
  • C:\Gerrard\Workspace\XXX\.git\refs\remotes\origin\feature 這個檔案目錄下面,由於 Windows 系統的關係,只能存在 HY78861 或者 hy78861 兩個檔案之一

所以我們這裡就有方案了:

  1. 根據上面的記錄,保證 HY78861 和 hy78861 的分支對映關係正確,一共兩處:packed-refs 和 info/refs。
  2. C:\Gerrard\Workspace\XXX\.git\refs\remotes\origin\feature 這個目錄下面,保留一個 hy78864 或者 HY78864 檔案,裡面的內容隨意,因為在執行 git pull 命令時會被覆蓋。
  3. 如果是 HY78864,內容會變成 d4244546c8cc3827491cc82878a23c708fd0401d;如果是 hy78861,內容會變成 f34729ba17a48c9628dff31f8c6720843c6d1a74。

最後,git pull 執行成功

XXX@CN-00012645 MINGW64 /c/Gerrard/Workspace/XXX (master)
$ git pull
From ssh://XXX
+ f34729ba17a...d4244546c8c feature/HY78861 -> origin/feature/HY78861 (forced update)
Already up to date.
Current branch master is up to date.