無法建立遠端分支
今早同學遇到一個問題,發現某個分支怎麼推都推不上去,甚至是加了 -f
參數也一樣推不動,先來還原一下案發現場:
$ git branch
feature/cch
* master
$ git push origin feature/cch
Total 0 (delta 0), reused 0 (delta 0)
remote: error: cannot lock ref 'refs/heads/feature/cch': 'refs/heads/feature' exists; cannot create 'refs/heads/feature/cch'
To /tmp/repo
! [remote rejected] feature/cch -> feature/cch (failed to update ref)
error: failed to push some refs to '/tmp/repo'
已經確定 remote 上並沒有 feature/cch
這個分支,但為什麼推不上去…在這之前,我們得先了解一下分支到底是什麼玩意兒。
分支其實是…
很多剛接觸 Git 的人,會以為「分支」是像樹枝或觸手一樣從本體(master)伸出去的,但在「為你自己學 Git」一書中也跟大家介紹過,Git 的分支就像貼紙一樣的概念,它會黏著某個 Commit,而它本身就是一個大小為 40 Bytes 的檔案,就這樣而已。
也就是說,當你每開一個分支,你的硬碟空間就少了 40 個 Bytes 的空間。
即然知道它是一個 40 個 Bytes 的檔案,那它放在哪裡?它就躺每個專案的 .git/refs/heads
目錄裡:
再比對一下我目前的分支:
$ git branch
feature/cch
* master
不難發現所謂的「分支」,其實是以檔案的方式存放在這個目錄裡。
建立分支
即然知道建立分支就是在 .git/refs/heads
裡建立檔案(或目錄),讓我們暫時跳離 Git,先來看看這個狀況:
$ ls -al
total 0
drwxr-xr-x 2 kaochenlong wheel 64 Oct 1 14:03 .
drwxrwxrwt 19 root wheel 608 Oct 1 14:03 ..
現在目錄是空的,我試著建立一個叫做 cch
的檔案:
$ touch cch
$ ls -al
total 0
drwxr-xr-x 3 kaochenlong wheel 96 Oct 1 14:04 .
drwxrwxrwt 19 root wheel 608 Oct 1 14:03 ..
-rw-r--r-- 1 kaochenlong wheel 0 Oct 1 14:04 cch
看起來一切正常,然後再試著建立 cch
這個「目錄」:
$ mkdir cch
mkdir: cch: File exists
咦?沒辦法建立目錄?我是要建立目錄啊,跟我說「檔案已存在」做什麼?
事實上,對作業系統來說,「目錄」也只是一種比較特別的「檔案」,所以當你試著要在同一個目錄底下建立同名字的目錄的時候,作業系統會給你「檔案已存在」的訊息。
這跟在 Git 建立分支有什麼關係?我們前面才提到建立分支其實就是建立檔案(或目錄),所以如果我這樣做:
$ git branch feature
我先建立一個叫做 feature
的分支,接著再來試著建立 feature/cch
分支:
$ git branch feature/cch
fatal: cannot lock ref 'refs/heads/feature/cch': 'refs/heads/feature' exists; cannot create 'refs/heads/feature/cch'
這樣建立分支就失敗了,而且 Git 給你的訊息是 'refs/heads/feature' exists
,就是跟你說那個「檔案」已經存在,你不能在已經有 feature
檔案的情況下,再建一個叫做 feature
的目錄了。
再回頭看看一開始推不上去的訊息:
$ git push origin feature/cch
Total 0 (delta 0), reused 0 (delta 0)
remote: error: cannot lock ref 'refs/heads/feature/cch': 'refs/heads/feature' exists; cannot create 'refs/heads/feature/cch'
To /tmp/repo
! [remote rejected] feature/cch -> feature/cch (failed to update ref)
error: failed to push some refs to '/tmp/repo'
中間那段訊息有覺得面熟嗎?看起來就是這個問題了。後來問了一下,果然是有其它同學在 remote 上有先建立了一個叫做 feature
的遠端分支,所以後面要推 feature/*
的人就推不上去了。
至於為什麼會有同學推了一個叫做 feature
的分支上去,這又是另一個故事了 :)
Comments