簡體   English   中英

盲目更新git repo,可能是另一個分支

[英]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"]

如果分支共享大量歷史記錄,這將通過重新克隆來節省大量數據傳輸,但當然您將在本地存儲庫中使用foobar對象。 如果分支的歷史記錄很少,那么重新開始就沒什么代價(除非你當然轉回去 )。


1除了分支的reflog中留下的痕跡。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM