盲目更新git回购协议,可能更新到其他分支机构

盲目更新git回购协议,可能更新到其他分支机构,git,branching-and-merging,Git,Branching And Merging,作为部署自动化的一部分,我有一个本地git存储库,它是使用以下命令创建的 git clone --single-branch -b $BRANCH $REMOTE $PATH 自动化有时需要从远程获取进一步的更改,这可能涉及分支的更改。自动化没有状态;它知道树枝应该是什么,但不知道它是什么。此外,此存储库中不应该有任何本地更改,但会发生错误 我正在寻找一个命令或命令序列,它将具有与清除存储库并重新克隆它相同的总体效果,但这将最大限度地减少在常见情况下重新下载的数据量,即$BRANCH未更改,g

作为部署自动化的一部分,我有一个本地git存储库,它是使用以下命令创建的

git clone --single-branch -b $BRANCH $REMOTE $PATH
自动化有时需要从远程获取进一步的更改,这可能涉及分支的更改。自动化没有状态;它知道树枝应该是什么,但不知道它是什么。此外,此存储库中不应该有任何本地更改,但会发生错误


我正在寻找一个命令或命令序列,它将具有与清除存储库并重新克隆它相同的总体效果,但这将最大限度地减少在常见情况下重新下载的数据量,即$BRANCH未更改,git pull将进行快进合并。

最简单的方法是:确认几件事,然后运行git fetch等。作为一种原型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
git reset --hard refs/remotes/$remote/$branch
这将测试当前签出的分支(如果有);致命失败:如果头部分离,则ref HEAD不是符号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
这可以确保有一个remotes/origin/master或其他任何东西,拼写出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=行

branch=$(git symbolic-ref --short HEAD) || exit 1
git reset --hard refs/remotes/$remote/$branch
最后一步将$branch移动到与新更新的$remote/$branch相同的提交位置,并用新更新的post fetch分支中的内容替换工作目录内容

如果上述某些步骤未能通过exit 1位(出于您的目的可能需要修改),那么您将返回到重新克隆

如果您愿意让本地存储库增加更多分支,那么您可以放弃上面的大部分内容,只需使用适当的refspec运行git fetch,和/或将该refspec添加到与远程存储库关联的fetch=行中。添加git clean-fdx以删除任何不应该存在的文件,并注意git reset-hard步骤将删除任何不应该存在的提交

特别是,git clone-single branch所做的是修改给定远程服务器的获取行。例如:

git clone --single-branch -b foo git://...
像往常一样克隆repo并签出分支foo,但不是将.git/config条目留给origin读取:

它将替换提取行,因此您可以:

    fetch = +refs/heads/foo:refs/remotes/origin/foo
这意味着未来的git fetch操作请记住,git pull只是git fetch,然后是merge或rebase,将其自身限制为带来更新远程上本地refs/remotes/origin/foo反射refs/heads/foo分支foo所需的对象,而不是refs/remotes/origin/*通过第一个*反映远程上的所有分支

如果您现在希望使用+refs/heads/bar:refs/remotes/origin/bar进行更新,就像您克隆了该分支一样,只需将其添加或替换为[remote origin]下的a或fetch=行即可

如果分支共享大量历史记录,这将通过重新克隆节省大量数据传输,当然您最终会在本地存储库中同时使用foo和bar对象。如果分支机构几乎没有共享历史,那么重新开始的成本很低,除非您曾经切换回原来的位置


1分支的重日志中留下的痕迹除外。

如果$branch恰好是一个标记而不是分支,那么所有这些是否仍然有效?否,或者至少,没有一些修改就不行。标记位于refs/Tags/name空间中,默认情况下git fetch以一种特殊的方式复制它们。