【问题标题】:How to know local repo is different from remote repo, without fetch?如何知道本地仓库与远程仓库不同,没有获取?
【发布时间】:2014-02-17 04:30:24
【问题描述】:

我有数十个 repos,如果发生任何差异,我的脚本应该更新它们,新提交,新标签,新分支。在我的情况下,数十个 repos 的 Fetch 有点慢,我想知道是否有任何快速命令可以满足我的要求。

【问题讨论】:

  • 自动更新对实时服务器不利
  • 没有fetch,您的git 不知道远程存储库的状态。任何不执行fetch 的解决方案(例如diff 针对完整的远程URL)至少与fetch 一样慢,因为它仍然需要检索远程存储库的状态。
  • @Ianzz 当然,您可以只查看远程头,看看是否有变化,而无需实际取包。

标签: git-remote git-diff git


【解决方案1】:

您无权访问origin 服务器

你不能只使用git

编辑

根据另一个答案,git ls-remote 可能对您有用。

但是,由于您必须ls-remote 所有存储库,如果您的问题是网络延迟,ls-remote 将无法解决。


您可以访问origin 服务器

  1. 在服务器上的存储库中有写入时设置挂钩。该钩子会将 repo 标记为已修改。例如,您可以在服务器的某处创建一个repo_name__MODIFIED 文件)。
  2. 在更新 repo 之前,检查 repo 是否被修改。对于给定的示例,检查文件repo_name__MODIFIED 是否存在于服务器上。
  3. 如果 repo 被修改,在更新 repo 之前,将其标记为未修改(就在获取之前)。在我们的示例中,只需删除服务器上的 repo_name__MODIFIED 文件即可。

注意

为什么提取时间这么长? git 只会获取新的提交,如果origin 没有修改,应该很快!

【讨论】:

  • 实际上我的构建机器会获取数十个 repos 以获取最新代码,单次获取速度很快,但获取的总时间(网络请求)持续了几分钟。这对于构建机器来说是糟糕的或糟糕的设计
  • 好的。那你觉得我的解决方案怎么样?您可以访问原始服务器吗?如果您需要更多信息,我可以进一步开发。
  • 我可以访问源站,我理解你的解决方案,值得一试,谢谢。
【解决方案2】:

如果您已使用 git clonegit remote add $REMOTE_NAME $REMOTE_URL 设置本地存储库,则将本地分支与远程分支进行比较所需的所有信息(在您上次使用 git fetch 时)已经存在。

如果您设置了远程跟踪分支,git status 会告诉您与您正在跟踪的远程分支是否存在差异,如下所示。

$ git status
On branch master
Your branch is behind 'origin/master' by 1 commit, and can be fast-forwarded.
  (use "git pull" to update your local branch)

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

        modified:   perl/Makefile.am

no changes added to commit (use "git add" and/or "git commit -a")

还有一个可解析的形式:

$ git status --porcelain -b
## master...origin/master [behind 1]
 M perl/Makefile.am

【讨论】:

  • 这不适用于由其他人推送的新标签。我认为 git-status 仅适用于当前工作树。
【解决方案3】:

您可以使用git ls-remote 管道命令来获取遥控器的状态,而无需获取。

这里,让我们使用 git 本身作为一个轻量级数据库,来跟踪远程的状态。

将以下内容放入脚本中;为方便起见,您可以稍后将其作为 git 别名 shell 函数启用。在你的仓库中运行。

REMOTE_SUM=$(git ls-remote --tags --heads 2>/dev/null | git hash-object --stdin)
if git cat-file -e $REMOTE_SUM
then
    echo Remote check-summed up-to-date.
else
    echo Remote changed, fetching...
    git ls-remote --tags --heads 2>/dev/null | \
        git hash-object -w --stdin &>/dev/null
    git fetch
fi

一些必要的错误检查被省略了,为了清晰起见,代码被复制了。

说明

使用git ls-remote --tags --heads 列出所有远程提示会生成如下输出:

从 /home/user/tmp/repo2 777201715768a4d82f374f7224e68164a916ac1f 裁判/头/酒吧 78981922613b2afb6025042ff6bd878ac1994e85 裁判/负责人/大师 ...

反过来,我们通过git hash-object --stdin 将远程repo 的上述图片散列为单个散列,并通过在git 中使用git cat-file -e 查询散列来检查我们之前是否见过它。如果我们还没有看到它,那么远程图片一定已经改变了,我们首先在 git 中使用git hash-object -w 记录它,以适应远程拉取和提交之间的竞争,然后继续获取远程。

可以将此与 git 预取功能集成:pre-fetch hook functionality in git,但这超出了此答案的范围。

附录

请注意,以上内容会在 git 中生成松散的对象,偶尔需要使用 git gc 进行垃圾收集,并且可能会显式使用 --prune

此外,只要提交不是故意重新排列以使分支提示保持不变,上述内容就应该有效。这将是 / 非常罕见 / 并且违反了 git 更改推送状态的准则,但是,嘿,可能发生的最糟糕的事情是你跳过了一次获取。

另请注意,ls-remote 在单个遥控器上工作。要使用多个遥控器,您必须通过生成带有git remote show 的遥控器列表来扩展脚本并依次使用每个遥控器。

【讨论】:

  • 听起来不错!如果我强制推送到远程,它有效吗?当然不是变基。
  • 是的,分支名称只是提示的绰号,即对象树中的顶级提交。您可以看到 ls-remote 列出了这些提示,当您强制推送提示时,提示会发生变化,远程的快照会看起来不同,散列到不同的散列值,因此第一次调用时会运行完整的提取,然后没有后续。
猜你喜欢
  • 2018-02-06
  • 2012-06-26
  • 2018-12-05
  • 2016-01-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-04-07
  • 1970-01-01
相关资源
最近更新 更多