【问题标题】:how to reset a git working tree to an updated commitish如何将 git 工作树重置为更新的提交
【发布时间】:2019-07-29 02:32:41
【问题描述】:

我需要使用应该适用于 Linux 和 MacOS 的 Bash 脚本来扩展给定工具。该脚本有 2 个参数:

  1. 存储库位置(文件系统、ssh、http(s)、...)
  2. commitish,例如分支、标签、提交哈希

我对参数没有影响

脚本运行的结果应该是这样的

  • 存储库被克隆到固定目标(一个存储库始终相同)
  • 存储库的工作树应对应于提交的最新状态(例如,如果它是一个分支,则该分支的尖端)

如果本地(还)不存在存储库,则过程很简单

git clone $REPO_SOURCE $REPO_DIR
cd $REPO_DIR
git checkout $REPO_REF

我的问题:考虑一个存储库已经克隆到/repos/foo。在 obvios git fetch 之后,如何将该存储库更新为提供的 $REPO_REF

  • 如果$REPO_REF 是一个分支,那么git checkout $REPO_REF && git pull 应该可以工作
  • 如果是提交哈希,则不需要更新(只需 git checkout $REPO_REF?)
  • 如果是标签,那么标签可能已经在原点上移动了,如何处理?
  • 如何处理其他极端情况?

是否有一种简单的reset-repository-to-this-commitsh 方式,使存储库的行为就像它是新克隆的一样?

侧节点:

  • 同一存储库可能与不同的提交一起使用,但只能按顺序使用:保证不会同时调用脚本多次
  • 对存储库的所有外部更改可能总是在不通知的情况下被丢弃
  • 虽然删除和克隆存储库会起作用,但由于它们的大小和它是一个解决方案
  • ,这是不切实际的
  • 不需要 (git) 更改,因此检查分离的头部是可以的

【问题讨论】:

    标签: bash git


    【解决方案1】:

    使用“标准” git clone 你可以这样做:

    # cleanup old cruft
    git reset --hard HEAD
    git clean -fdx
    
    # detach from current branch (if on any)
    git checkout --detach
    # delete all local branches
    git for-each-ref --format="%(refname:strip=2)" refs/heads |xargs -r git branch -D
    # fetch and update all remote refs and tags
    git fetch --force --all --tags --prune --prune-tags
    # checkout
    git checkout "$COMMITISH"
    

    这样你就可以像往常一样依赖git checkout 来完成它的工作,并且你不需要复制它的任何启发式方法、快捷方式等。

    【讨论】:

      【解决方案2】:

      唯一完全万无一失但方便的方法是让 other Git(您可能正在克隆,但可能不会)为您解析名称。那么你就有了一个哈希ID,一个哈希ID是通用的。

      如果名称是分支或标签名称,您可以使用git ls-remote 来实现该步骤。如果它可能是其他一些公式(例如,master~13),那么你在这里就不走运了。因此,如果您需要在本地解析名称:

      • 如果遵守标签规则,标签将永远不会移动。这意味着如果你有一个现有的克隆有标签,它有正确的标签,你在这里没问题,如果你有一个没有标签的现有克隆,你可以添加标签并解决它.

      • 如果不遵守标签规则,您将不得不删除并重新创建标签(糟糕),或者重新发明远程标签:复制它们的refs/tags/* 名称到您的 refs/rtags/<remote>/* 命名空间。见Git - Checkout a remote tag when two remotes have the same tag name

      • 如果您有分支名称或与分支名称相关的名称,请将分支名称转换为您自己的远程跟踪名称(例如,将 master~13 替换为 refs/remotes/origin/master~13)并解决它。

      无论如何,您现在有了一个哈希 ID 并且可以使用分离的 HEAD 模式。

      【讨论】:

      • 我真的很喜欢git ls-remote 方法,谢谢!您是否看到任何机会让它与提交哈希一起工作(即如何检测提供的参数是否是原始的有效 git 哈希以省略 git ls-remote 以支持该 raw 值)?
      • Git 假设,至少现在,任何正好 40 个字符长 全十六进制数字的东西都必须是原始哈希 ID。 (即,即使您创建具有这种形式的分支或标记名称,该字符串也会被视为哈希 ID — 即使它不是有效的 — 至少对于 git rev-parse 而言。)这可能会随着切换到 SHA 而改变-256,但可能不会。所以至少现在你可以运行git ls-remote,收集输出,匹配字符串,除非在(某些)正则表达式中它恰好是^[0-9a-f]{40}$,在这种情况下你只需将它用作是。
      • 感谢您的更新。我应该更准确。现在,用例也取决于缩短的(即前缀)哈​​希。有什么方法可以使用ls-remote 或其他针对遥控器的机制来验证它们吗?
      • @muffel:没有。缩短的哈希是有问题的:face2facedeadbeef 是哈希还是分支名称?
      • 好吧,我想说的是用户有责任提供明确的值,如果它既不是标签也不是分支名称,则将其视为哈希
      猜你喜欢
      • 1970-01-01
      • 2013-07-14
      • 1970-01-01
      • 2021-04-22
      • 1970-01-01
      • 1970-01-01
      • 2021-12-09
      • 2018-07-04
      • 1970-01-01
      相关资源
      最近更新 更多