GIT 结帐明确参考
GIT checkout unambiguous ref
我有一个分支和一个标签都命名为 test
。
如果我有像 heads/test
或 refs/heads/test
这样明确的引用,我如何才能在不进入分离状态的情况下结帐?
git checkout heads/test
我想保存当前的 HEAD 状态,然后 return 保存到它:
# Exit if dirty
# Save HEAD
ref=$(git symbolic-ref -q --short HEAD)
if [ -z "$ref" ] ; then # Detached
ref=$(git rev-parse HEAD)
fi
echo $ref
# Do Stuff that changes HEAD
git checkout master
# Restore HEAD
git checkout $ref
::为清晰起见进行了编辑::
来自文档:
Branch to checkout; if it refers to a branch (i.e., a name that, when prepended with "refs/heads/", is a valid ref), then that branch is checked out. Otherwise, if it refers to a valid commit, your HEAD becomes "detached" and you are no longer on any branch (see below for details).
因此:如果同时存在名称为 test
的分支和标签,则 git checkout test
将在不分离的情况下检出分支。 git确实给出了警告,但它仍然会一直这样。
但另一方面,如果您给它除以外的任何内容,如上定义的“分支名称”-包括明确限定分支,如heads/test
- 然后它分离。
所以看起来如果你有 heads/test
并且想在不分离的情况下结帐,(瓷器)程序是将 heads/
剥掉并且只是 checkout test
.
如果您真的不想那样做...好吧,我不知道有什么更好的“安全”选择。
你可以使用 git symbolic-ref
git symbolic-ref -m "Checkout test" HEAD refs/heads/test
git reset HEAD -- .
git checkout -- .
但请注意,在这种情况下,您必须 完全 限定 ref - 所以您仍然不能只使用 heads/test
。此外,如果您不在 -m
参数中手动提供“原因”,您将搞砸 reflog。然后您必须更新索引和工作树。我猜你可以写一个脚本或别名来做这一切。
或者您可以直接操作 .git/HEAD
文件,但如果您弄乱了它,git 将无法识别该存储库,直到您修复它。
另外,你说:
Checking out tags/test works fine.
不确定这意味着什么,因为 (a) 您的问题是如何在不输入分离头的情况下检出 heads/test
,但是 (b) 检出标签 always 进入分离的头部。并且:
I am getting the ref from:
git symbolic-ref -q --short HEAD
什么情况下会这样returntags/test
?也许我误解了,因为你把它放在了你谈论签出标签的同一行......你的意思是 git symbolic-ref -q --short HEAD
是 returning heads/test
,并且你正在存储然后尝试检查它?
在那种情况下,见上文;但在那种情况下,您也可以省去 --short
,至少这将使 symbolic-ref
方法发挥作用更近了一步...
编辑: git symbolic-ref --short -q HEAD
在这种 ambiguous-reference 情况下行为不当。例如:
$ mkdir t
$ cd t
$ git init
Initialized empty Git repository in ...
$ echo test symref > README
$ git add README
$ git commit -m initial
[master (root-commit) ee3448a] initial
1 file changed, 1 insertion(+)
create mode 100644 README
$ git branch test
$ git tag test
$ git checkout test
warning: refname 'test' is ambiguous.
Switched to branch 'test'
$ git symbolic-ref -q --short HEAD
heads/test
所以我下面的原回答有一个重要的错误。我会在 OP 的替代方案上使用一个轻微的变体:
if headRef=$(git symbolic-ref -q HEAD); then
headRef=${headRef#refs/heads/}
else
headRef=$(git rev-parse HEAD)
fi
注意:
git symbolic-ref
错误(returns 失败状态,以及不打印符号引用)当 HEAD
不是符号引用时:
if ! ref=$(git symbolic-ref -q --short HEAD); then
... HEAD is detached ...
(换句话说,您不需要单独的 zero-length 字符串测试。)
HEAD
只能 是分支名称的符号引用,而不是标记名称。
大多数 Git 命令的行为如 the gitrevisions documentation 中所述,因为裸名 test
将通过 [= 解析为提交 pointed-to 18=] 而不是 refs/heads/test
。但是,git checkout
命令的行为有所不同:git checkout test
将首选分支。
因此,如果 git symbolic-ref
成功,您的短引用适合传递给 git checkout
。如果失败了,你确实需要运行git rev-parse HEAD
获取hash ID传递给后面的git checkout
.
我希望有一个管道检查命令可以处理来自合格 ref 的分支检查,但我想出了这个解决方法:
# Save Checkout
refBranch=$(git symbolic-ref -q HEAD)
refDetach=$(git rev-parse HEAD)
echo "refBranch [$refBranch]"
echo "refDetach [$refDetach]"
# Do Stuff
git checkout master --quiet
echo "Now on [$(git symbolic-ref -q --short HEAD)]"
# Restore Checkout
if [[ ${refBranch:0:11} == "refs/heads/" ]] ; then
echo "Checkout Branch [${refBranch:11}]"
git checkout ${refBranch:11} --quiet
else # Detached
echo "Checkout Detach [$refDetach]"
git checkout $refDetach --quiet
fi
或者如果我们保证总是得到 refs/heads/
前缀:
# Save Checkout
if headRef=$(git symbolic-ref -q HEAD); then
headRef=${headRef:11}
else
headRef=$(git rev-parse HEAD)
fi
echo "headRef [${headRef}]"
# Do Stuff
git checkout master --quiet
echo "Now on [$(git symbolic-ref -q --short HEAD)]"
# Restore Checkout
git checkout $headRef --quiet
我有一个分支和一个标签都命名为 test
。
如果我有像 heads/test
或 refs/heads/test
这样明确的引用,我如何才能在不进入分离状态的情况下结帐?
git checkout heads/test
我想保存当前的 HEAD 状态,然后 return 保存到它:
# Exit if dirty
# Save HEAD
ref=$(git symbolic-ref -q --short HEAD)
if [ -z "$ref" ] ; then # Detached
ref=$(git rev-parse HEAD)
fi
echo $ref
# Do Stuff that changes HEAD
git checkout master
# Restore HEAD
git checkout $ref
::为清晰起见进行了编辑::
来自文档:
Branch to checkout; if it refers to a branch (i.e., a name that, when prepended with "refs/heads/", is a valid ref), then that branch is checked out. Otherwise, if it refers to a valid commit, your HEAD becomes "detached" and you are no longer on any branch (see below for details).
因此:如果同时存在名称为 test
的分支和标签,则 git checkout test
将在不分离的情况下检出分支。 git确实给出了警告,但它仍然会一直这样。
但另一方面,如果您给它除以外的任何内容,如上定义的“分支名称”-包括明确限定分支,如heads/test
- 然后它分离。
所以看起来如果你有 heads/test
并且想在不分离的情况下结帐,(瓷器)程序是将 heads/
剥掉并且只是 checkout test
.
如果您真的不想那样做...好吧,我不知道有什么更好的“安全”选择。
你可以使用 git symbolic-ref
git symbolic-ref -m "Checkout test" HEAD refs/heads/test
git reset HEAD -- .
git checkout -- .
但请注意,在这种情况下,您必须 完全 限定 ref - 所以您仍然不能只使用 heads/test
。此外,如果您不在 -m
参数中手动提供“原因”,您将搞砸 reflog。然后您必须更新索引和工作树。我猜你可以写一个脚本或别名来做这一切。
或者您可以直接操作 .git/HEAD
文件,但如果您弄乱了它,git 将无法识别该存储库,直到您修复它。
另外,你说:
Checking out tags/test works fine.
不确定这意味着什么,因为 (a) 您的问题是如何在不输入分离头的情况下检出 heads/test
,但是 (b) 检出标签 always 进入分离的头部。并且:
I am getting the ref from:
git symbolic-ref -q --short HEAD
什么情况下会这样returntags/test
?也许我误解了,因为你把它放在了你谈论签出标签的同一行......你的意思是 git symbolic-ref -q --short HEAD
是 returning heads/test
,并且你正在存储然后尝试检查它?
在那种情况下,见上文;但在那种情况下,您也可以省去 --short
,至少这将使 symbolic-ref
方法发挥作用更近了一步...
编辑: git symbolic-ref --short -q HEAD
在这种 ambiguous-reference 情况下行为不当。例如:
$ mkdir t
$ cd t
$ git init
Initialized empty Git repository in ...
$ echo test symref > README
$ git add README
$ git commit -m initial
[master (root-commit) ee3448a] initial
1 file changed, 1 insertion(+)
create mode 100644 README
$ git branch test
$ git tag test
$ git checkout test
warning: refname 'test' is ambiguous.
Switched to branch 'test'
$ git symbolic-ref -q --short HEAD
heads/test
所以我下面的原回答有一个重要的错误。我会在 OP 的替代方案上使用一个轻微的变体:
if headRef=$(git symbolic-ref -q HEAD); then
headRef=${headRef#refs/heads/}
else
headRef=$(git rev-parse HEAD)
fi
注意:
git symbolic-ref
错误(returns 失败状态,以及不打印符号引用)当HEAD
不是符号引用时:if ! ref=$(git symbolic-ref -q --short HEAD); then ... HEAD is detached ...
(换句话说,您不需要单独的 zero-length 字符串测试。)
HEAD
只能 是分支名称的符号引用,而不是标记名称。大多数 Git 命令的行为如 the gitrevisions documentation 中所述,因为裸名
test
将通过 [= 解析为提交 pointed-to 18=] 而不是refs/heads/test
。但是,git checkout
命令的行为有所不同:git checkout test
将首选分支。
因此,如果 git symbolic-ref
成功,您的短引用适合传递给 git checkout
。如果失败了,你确实需要运行git rev-parse HEAD
获取hash ID传递给后面的git checkout
.
我希望有一个管道检查命令可以处理来自合格 ref 的分支检查,但我想出了这个解决方法:
# Save Checkout
refBranch=$(git symbolic-ref -q HEAD)
refDetach=$(git rev-parse HEAD)
echo "refBranch [$refBranch]"
echo "refDetach [$refDetach]"
# Do Stuff
git checkout master --quiet
echo "Now on [$(git symbolic-ref -q --short HEAD)]"
# Restore Checkout
if [[ ${refBranch:0:11} == "refs/heads/" ]] ; then
echo "Checkout Branch [${refBranch:11}]"
git checkout ${refBranch:11} --quiet
else # Detached
echo "Checkout Detach [$refDetach]"
git checkout $refDetach --quiet
fi
或者如果我们保证总是得到 refs/heads/
前缀:
# Save Checkout
if headRef=$(git symbolic-ref -q HEAD); then
headRef=${headRef:11}
else
headRef=$(git rev-parse HEAD)
fi
echo "headRef [${headRef}]"
# Do Stuff
git checkout master --quiet
echo "Now on [$(git symbolic-ref -q --short HEAD)]"
# Restore Checkout
git checkout $headRef --quiet