Git 是一個(gè)開(kāi)源的分布式版本控制系統(tǒng),用于敏捷高效地處理任何或小或大的項(xiàng)目。現(xiàn)在有很多的公司都在使用,我的公司也使用了 Git。學(xué)會(huì) Git 幾乎成了開(kāi)發(fā)者的必備技能,有很多的求職者在簡(jiǎn)歷里面都會(huì)寫(xiě)上熟練 Git ,但是,你真的都懂嗎?
最近,項(xiàng)目的分支規(guī)范變了,當(dāng)我們使用新的分支規(guī)范時(shí)出現(xiàn)了問(wèn)題,不能創(chuàng)建分支,也不能提交。我仔細(xì)觀察了一下報(bào)錯(cuò),發(fā)現(xiàn)是因?yàn)槲覀冃碌姆种б?guī)范在分支名稱的最前面加了一個(gè)路由,而這個(gè)路由曾經(jīng)是我們使用的一個(gè)分支,導(dǎo)致本應(yīng)該在新建分支時(shí)在 .git 目錄上新建一個(gè)文件夾,而現(xiàn)在那個(gè)路由存在而且是個(gè)文件導(dǎo)致了報(bào)錯(cuò)。
首先,說(shuō)一下問(wèn)題可能發(fā)生的場(chǎng)景。
- 本地和遠(yuǎn)程已經(jīng)存在分支 test 時(shí),當(dāng)我們新建 test/staging 分支時(shí),會(huì)報(bào) fatal: cannot lock ref 'refs/heads/test/staging': 'refs/heads/test' exists; cannot create 'refs/heads/test/staging'。
前提:當(dāng)本地不存在 test 分支,我們新建了一個(gè) test/staging 分支。
- 當(dāng)向遠(yuǎn)程 push 時(shí),就會(huì)報(bào)! [remote rejected] test/staging -> test/staging (cannot lock ref 'refs/heads/test/staging': 'refs/heads/test' exists; cannot create 'refs/heads/test/staging')。
- 當(dāng)向遠(yuǎn)程 push 時(shí),會(huì)報(bào) error: update_ref failed for ref 'refs/remotes/origin/test/staging': cannot lock ref 'refs/remotes/origin/test/staging': 'refs/remotes/origin/test' exists; cannot create 'refs/remotes/origin/test/staging'。
為什么會(huì)報(bào)錯(cuò)呢?
問(wèn)題原因
根據(jù)報(bào)錯(cuò)提示,我們可以想到是由于建立分支的名稱出錯(cuò),test 已經(jīng)存在。
可我們新建的是 test/staging 分支,不是 test 分支?
這是由于 Git 建立分支時(shí)會(huì)在 'refs/remotes' 下按路徑建立文件,test 分支存在的話,就是存在了名為 test 的文件。而我們?cè)偈褂妹钚陆?test/staging 分支時(shí),會(huì)建立一個(gè)名為 test 的文件夾,并在文件夾下建立一個(gè)名為 staging 的文件,因此發(fā)生了沖突而報(bào)錯(cuò)。
也就是說(shuō)在 refs/remotes 下的 test 是個(gè)文件,而當(dāng)我們?cè)俅涡陆?test 文件夾的時(shí)候就與 test 同名的文件產(chǎn)生了沖突,從而導(dǎo)致了報(bào)錯(cuò)。
我們終于找到了報(bào)錯(cuò)的原因。
我們?cè)僭敿?xì)看一下上面的三個(gè)場(chǎng)景的報(bào)錯(cuò):
場(chǎng)景1:無(wú)法新建分支
我們首先查看本地的分支,發(fā)現(xiàn)已經(jīng)存在 test 分支,刪除 test 分支后再次嘗試新建,這時(shí)已經(jīng)可以新建分支,此報(bào)錯(cuò)已解決。
場(chǎng)景2:remote rejected
遠(yuǎn)端拒絕,通過(guò)查看遠(yuǎn)端分支,發(fā)現(xiàn)遠(yuǎn)端存在 test 分支,因此刪去 test 分支,再次嘗試解決此報(bào)錯(cuò)。
場(chǎng)景3:update_ref failed
本地分支跟遠(yuǎn)程分支不匹配。
Git 工程的 .git/refs 目錄下跟蹤的 git 分支,在 git push 的時(shí)候,與遠(yuǎn)端的 refs 對(duì)比發(fā)現(xiàn)不同,所以導(dǎo)致 git push 報(bào)錯(cuò)。
解決方法
既然已經(jīng)知道了原因,那我們趕緊解決它!
刪除本地的 test 分支(如果沒(méi)有請(qǐng)忽略)。
刪除遠(yuǎn)端的 test 分支(如果沒(méi)有請(qǐng)忽略)。
備份好修改的代碼。
cd 到 .git/refs/remotes/origin 路徑下。
- 刪除報(bào)錯(cuò)的分支。
此時(shí),如果我們?cè)俅螄L試 push ,會(huì)提示:error: update_ref failed for ref 'refs/remotes/origin/test/staging': cannot update the ref 'refs/remotes/origin/test/staging': unable to append to '.git/logs/refs/remotes/origin/test/staging': Not a directory
這是因?yàn)楦?ref 時(shí)出錯(cuò),test 是個(gè)文件并不是目錄。可以 cd 到 .git/logs/refs/remotes/origin 路徑下刪除 test 文件來(lái)解決。
- 切換到其它的分支(不要在報(bào)錯(cuò)分支上,切換到其它的分支)。
- 拉取遠(yuǎn)程分支(git fetch -p)。
- 執(zhí)行 git pull 操作,查看是否正常。
- 刪除報(bào)錯(cuò)的分支(git branch -D *)。
- 檢出報(bào)錯(cuò)分支(git checkout *)。
- 查看分支操作是否正常(git pull)。
- 將備份好的修改的代碼合并過(guò)來(lái)。
現(xiàn)在,cannot create 'refs/remotes/origin/*' 報(bào)錯(cuò)已經(jīng)圓滿地解決了,我們可以放心地提代碼了。
我將此次處理地經(jīng)過(guò)記錄在此,希望可以幫助其它同樣遇到這個(gè)問(wèn)題的小伙伴節(jié)省些時(shí)間,也希望可以幫助更多的小伙伴了解 Git 分支。