[英]Updating a git repo blindly, possibly to a different branch
作為部署自動化的一部分,我有一個使用表單命令創建的本地git存儲庫
git clone --single-branch -b $BRANCH $REMOTE $PATH
自動化有時需要從遠程執行進一步的更改,這可能涉及更改分支。 自動化沒有狀態; 它知道分支應該是什么,但不知道它是什么。 此外,此存儲庫中永遠不應存在任何本地更改,但會發生錯誤。
我正在尋找一個命令或命令序列,它將具有與擦除存儲庫並重新克隆它相同的整體效果,但這將最大限度地減少在常見情況下重新下載的數據量(即$BRANCH
具有沒有改變, git pull
會做一個快進合並)。
大部分方法都很簡單:只需確認一些內容然后運行git fetch
等。作為一種proto-type shell腳本:
cd ... # the place you want to test.
# note that `git-sh-setup` (below) demands
# that this be the top of the repository.
git rev-parse --verify HEAD >/dev/null || exit 1
(這驗證它實際上是一個git存儲庫)
branch=$(git symbolic-ref --short HEAD) || exit 1
(這測試當前檢出哪個分支,如果有的話;它失敗並且fatal: ref HEAD is not a symbolic ref
如果HEAD被分離,則fatal: ref HEAD is not a symbolic ref
;如果需要,使用-q
精煉並使用不同的錯誤)
if ! git rev-parse --verify refs/remotes/$remote/$branch >/dev/null 2>&1; then
echo "$remote/$branch does not exist" 1>&2
exit 1
fi
(這確保有一個遙控器/原點/主人或其他什么,拼寫出refs/remotes/
只是為了一般偏執 - 隨意刪除refs/remotes/
從這些)
ahead=$(git rev-list --count refs/remotes/$remote/$branch..$branch)
if [ $ahead -gt 0 ]; then
echo "$branch is ahead of $remote/$branch by $ahead commit(s)" 1>&2
exit 1
fi
(這可以確保本地$ branch上沒有提交上游不存在的提交)
. $(git --exec-path)/git-sh-setup # for require_clean_work_tree
require_clean_work_tree "update from remote"
(這在某種程度上是可選的,它取決於您希望樹要求干凈的嚴格程度,但下一位假設“干凈”)
git fetch $remote +refs/heads/$branch:refs/remotes/$remote/$branch
(這會更新$ remote / $ branch以匹配當前在遙控器上的實際內容,無論存儲在存儲庫中的任何fetch =
行)
git reset --hard refs/remotes/$remote/$branch
(這最后一步移動$branch
,我們已經確認我們已經確認,它指向與新更新的$remote/$branch
相同的提交,並且還將工作目錄內容替換為來自新更新的post的內容 -獲取分支)。
如果上述某些步驟失敗(“退出1”位,可能需要根據您的目的進行修改),那么您將重新進行重新克隆。
如果你願意讓本地存儲庫增長(有更多分支),你可以放棄上面的大部分內容,只需使用適當的refspec運行git fetch
,和/或將refspec添加到與遠程關聯的fetch =
行。 (添加git clean -fdx
刪除不應該出現的任何文件,並注意git reset --hard
一步將刪除1項 ,不應該存在任何承諾 。)
特別是, git clone --single-branch
所做的是修改給定遠程的獲取行 。 例如:
git clone --single-branch -b foo git://...
克隆repo並像往常一樣檢出分支foo
,但不是將.git/config
條目留給origin
讀取:
[remote "origin"]
url = git://...
fetch = +refs/heads/*:refs/remotes/origin/*
它取代了fetch
行,所以你改為:
fetch = +refs/heads/foo:refs/remotes/origin/foo
這意味着未來的git fetch
操作 - 請記住, git pull
只是git fetch
然后是merge或rebase-limit本身,用於引入更新本地refs/remotes/origin/foo
所需的對象,反映refs/heads/foo
(branch foo)在遙控器上,而不是那些refs/remotes/origin/*
(通過第一個*
反映refs/remotes/origin/*
上的所有分支)。
如果您現在希望使用+refs/heads/bar:refs/remotes/origin/bar
更新+refs/heads/bar:refs/remotes/origin/bar
(就像您克隆了該分支一樣),您只需在[remote "origin"]
或] fetch =
行下添加或替換它即可。 [remote "origin"]
。
如果分支共享大量歷史記錄,這將通過重新克隆來節省大量數據傳輸,但當然您將在本地存儲庫中使用foo
和bar
對象。 如果分支的歷史記錄很少,那么重新開始就沒什么代價(除非你當然轉回去 )。
1除了分支的reflog中留下的痕跡。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.