繁体   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