如何将git工作树重置为更新的提交

时间:2019-03-07 09:05:06

标签: bash git

我需要使用Bash脚本扩展给定的工具,该脚本应该可以在Linux和MacOS上使用。该脚本获取2个参数:

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

我对参数没有影响

脚本运行的结果应该是

  • 该存储库被克隆到一个固定的目标位置(一个存储库总是相同)
  • 存储库的工作树应对应于社区的最新状态(例如,如果该分支是该分支的尖端)

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

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

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

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

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

侧节点:

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

2 个答案:

答案 0 :(得分:2)

唯一完全安全且方便的方法是让 other Git(您可能正在克隆的Git,但可能不会克隆)为您解析名称。然后,您有了一个哈希ID,并且哈希ID是通用的。

如果名称是分支名称或标记名称,则可以使用git ls-remote完成该步骤。如果可能是其他措辞(例如master~13),那么您就不走运了。因此,如果您需要在本地解析名称:

  • 如果遵守标签规定,则任何标签都不会移动。这意味着,如果您有一个具有标签的现有克隆,它具有正确的标签,并且您在这里还可以,并且如果您有一个没有标签的现有克隆,则可以添加该标签并对其进行解析

  • 如果不遵守标签规定,则必须删除并重新创建标签(讨厌),否则重新发明远程标签:复制其{{1} }命名为您的refs/tags/*命名空间。参见Git - Checkout a remote tag when two remotes have the same tag name

  • 如果您有分支名称或与分支名称相关的名称,请将分支名称转换为您自己的远程跟踪名称(例如,将refs/rtags/<remote>/*替换为master~13)并进行解析

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

答案 1 :(得分:1)

使用“标准” git克隆,您可以这样做:

# 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来完成其工作,而无需复制其任何试探法,快捷方式等。