可以在 Git 中使用别名作为分支吗?

我正在研究大规模使用 Git。我希望通过调用 master分支 trunk来增加采用率并使事情变得更简单。

这可以给 SVN 用户一些安慰。我知道我可以创建一个名为 trunk的分支,但是这似乎偏离了 Git 的规范,可能会导致一些用户感到困惑。

我知道,我也可以创建和删除标签,我的心脏的内容,但当我检查这些标签,它告诉我,这是一个非本地分支,这对我来说很好,但可能不是我想要做的。

我完全是一个 Git 新手,但是在发布和构建系统方面经验丰富。

我想做的是能够调用主干。我已经看到了别名命令的能力-这也适用于版本化对象的名称吗?

我知道 git-svn和其他工具的存在,但是分层存储库系统的开销让我害怕。

17702 次浏览

在 Git 中,“ master”这个名称并没有什么特别之处,它只是按照惯例(默认情况下)被称为 master。如果你愿意,你当然可以叫它“象鼻”:

git branch -m master trunk

这非常类似于 Subversion,其中“主干”这个名称也只是按照约定来称呼。您可以在 Subversion 中将主分支称为“ master”。

您可以按照 Greg 的建议重命名主分支主干,或者您也可以创建一个对主分支进行符号引用的主干,这样 git 和 svn 用户都可以使用他们习惯使用的“ main”分支。

git symbolic-ref refs/heads/trunk refs/heads/master

请注意,躯干不是头等公民。如果签出 trunk并执行 git status,那么您实际上是在 master上,但是您可以在使用分支名称的所有位置(log、 merge 等)使用 trunk命令。

这是查尔斯 · 贝利的回答中所展示的技术的安全包装。

$ git branch-alias <alias> <long-and-unwieldy-branch-name> # create alias
$ git branch-alias <alias> # create alias for current branch
$ git branch # view branches and branch aliases
$ git log <alias>
$ git checkout <alias>
$ git push origin <alias> # pushes the branch, not the alias/reference
$ git branch-alias -d <alias> # delete an alias safely
$ git branch-alias -h # help / usage details

请注意,git 版本2.7.0-2.8.2(包含)中的一个 bug 导致“ git Branch”为分支别名显示“ alias-> alias”,而不是“ alias-> Branch”。如果您受到这个 bug 的影响,我建议您升级到2.8.3或更高版本。

#!/bin/sh
# git branch-alias
# Author: Phil S.
# Version 1.13.1
version=1.13.1


# Creates branch aliases, so that you can refer to a long branch name
# by a convenient short alias.  This is particularly useful for branch
# names beginning with bug-tracker ID numbers (or similar), where the
# benefits of tab-completion are greatly reduced.


# This is mostly a "do what I mean" wrapper around "git symbolic-ref",
# with numerous safety measures included in order to eliminate the
# (otherwise considerable) risk of trashing a branch if you get your
# arguments wrong.


# Installation:
# Place this script somewhere in your PATH and name it "git-branch-alias"
# and you will be able to invoke it with "git branch-alias" as per the
# following examples.  If you have obtained the script from the git
# mailing list, please see the "Mailing list archives" note below.


# Examples:
# git branch-alias <alias> <long-and-unwieldy-branch-name> # create alias
# git branch-alias <alias> # create alias for current branch
# git branch # view branches and branch aliases
# git log <alias>
# git checkout <alias>
# git push origin <alias> # pushes the branch, not the alias/reference
# git branch-alias -d <alias> # delete an alias safely
# git branch-alias -h # help / usage details


# Caveats:
# Although everything else I've tried works seamlessly, I note that
# git merge <alias> will cause the alias name to be mentioned in the
# commit message, rather than the name of the real branch.  It would
# be nicer if the branch name appeared.


# Compatibility:
# Originally developed with git version 1.7.12.4
# Also tested with git versions 1.9.0, 2.5.4, 2.6.6, 2.8.3
#
# Related git changes between versions 1.7.12.4 and 2.8.3:
# git v1.8.0.1
#  * A symbolic ref refs/heads/SYM was not correctly removed with "git
#    branch -d SYM"; the command removed the ref pointed by SYM
#    instead.
#
# git v1.8.1
#  * "git symbolic-ref" learned the "-d $symref" option to delete the
#    named symbolic ref, which is more intuitive way to spell it than
#    "update-ref -d --no-deref $symref".
#
# git v2.6.5
#  * "git symbolic-ref" forgot to report a failure with its exit status.
#
#  I believe this is commit 3e4068ed90fd3c6f24303560113aae6dbb758699:
#  > symbolic-ref: propagate error code from create_symref()
#  > If create_symref() fails, git-symbolic-ref will still exit with
#  > code 0, and our caller has no idea that the command did nothing.
#  > This appears to have been broken since the beginning of time
#
#  As this affects symref creation only, the sole adverse effect here
#  would be an unintended message to the user if symref creation had
#  actually failed (but not even a misleading one, on account of our
#  reading the reference after its creation, and thus displaying an
#  error if it turned out to be invalid).
#
# git v2.8.3
#  * A change back in version 2.7 to "git branch" broke display of a
#    symbolic ref in a non-standard place in the refs/ hierarchy (we
#    expect symbolic refs to appear in refs/remotes/*/HEAD to point at
#    the primary branch the remote has, and as .git/HEAD to point at the
#    branch we locally checked out).
#
#  This caused "git branch" to display "ref -> ref" instead of "ref -> branch"
#  for branch aliases.  The functionality still works otherwise, but is not
#  nearly so convenient to work with when you cannot trivially see what each
#  alias points to.  This bug affected git versions 2.7.0 - 2.8.2 (inclusive).


# Change log:
# v1.13.1
# Change incorrect uses of git show-ref, introduced by v1.10 (including
# effective regression of v1.08), to use git symbolic-ref instead.
#
# v1.12:
# Fix the option handling for '--', and added it to the help text.
#
# v1.11:
# Minor tidy-ups.  Re-posted to git mailing list:
# https://www.mail-archive.com/git%40vger.kernel.org/msg161274.html
#
# v1.10:
# No longer dependent on refs existing as individual files, as they
# may be packed in .git/packed-refs.
#
# v1.09:
# POSIX-compatible option handling and output.
# Documented an issue with "git branch" in git versions 2.7.0 - 2.8.2.
#
# v1.08:
# Remove test git show-ref --verify --heads --quiet "refs/heads/${symref}"
# for asserting that the specified reference was valid before deleting a
# reference, as we need to permit the deletion of references to branches
# which have /already/ been deleted, and this test prevented that.
# n.b. We already had another validation test to fall back on, using
# git symbolic-ref "refs/heads/${symref}"
#
# v1.07:
# Minor tweaks.  Posted as feature-request to git mailing list:
# https://www.mail-archive.com/git%40vger.kernel.org/msg49171.html


# Mailing list archives:
# If you are reading this via the git mailing list archives at gmane.org
# then this code will probably be broken by an email obfuscation filter
# which automatically converts the symbol '@' to the string ' <at> '.
# Specifically the shell positional parameter expansion "$@" is changed
# to "$ <at> "), so don't try to use the version from gmane.  The copy
# of this message at http://www.mail-archive.com/git%40vger.kernel.org/
# should have the correct code.


command=$(basename $0)
if [ "${command##git-}" != "${command}" ]; then
command="git ${command##git-}"
fi


# Print argument (and newline) to stdout or stderr.
stdout () {
printf %s\\n "$1"
}
stderr () {
printf %s\\n "$1" >&2
}


# Returns the supplied parameters suitably quoted for later evaluation.
quote () {
for param; do
printf %s "${param}Z" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/Z\$/' /"
done
}


# Process option parameters.
parameters=
while [ $# -gt 0 ]; do
case "$1" in
( -- ) {
shift
parameters="${parameters}$(quote "$@")"
break
};;
( -v | --version ) version_help=1; shift;;
( -h | --help    ) help=1; shift;;
( -d | --delete  ) delete=1; shift;;
( -* ) {
stdout "Invalid option: $1"
stdout
shorthelp=1
shift
};;
( * ) { # non-option parameter
parameters="${parameters}$(quote "$1")"
shift
};;
esac
done


# Process non-option parameters.
eval "set -- ${parameters}"
symref=$1
branch=$2


# If too few or too many parameters were supplied, display shorthelp.
if [ -z "${symref}" ] || [ -n "$3" ]; then
shorthelp=1
fi


# If displaying the version, exit immediately.
if [ -n "${version_help}" ]; then
stdout "${command} version ${version}"
exit 0
fi


# Don't let short help override long help.
if [ -n "${help}" ]; then
shorthelp=
fi


# Include the usage summary in both short and long help.
if [ -n "${help}" ] || [ -n "${shorthelp}" ]; then
cat <<EOF
Usage:
${command} [--] <alias> [<branch>]
${command} (-d | --delete) [--] <alias>
${command} (-v | --version)


EOF
fi


# n.b. Calling "git branch-alias --help" causes git to look for
# a man page for "git-branch-alias", so we shouldn't advertise
# the long option (although we support it if the script is called
# by its real name, rather than via git).
if [ -n "${shorthelp}" ]; then
cat <<EOF
For help, use: ${command} -h


EOF
exit 0
fi


# Detailed help.
if [ -n "${help}" ]; then
cat <<EOF
Creates a symbolic reference <alias> referring to <branch>.
<branch> defaults to the current checked-out branch.


This symbolic reference acts as an alias for <branch>, and can be
used in its place.  More specifically, it WILL be dereferenced to
its target in nearly all situations, so for any given command you
should treat every usage of <alias> as if it were actually <branch>.


If either <alias> or <branch> begins with a hyphen, you can use the
'--' option to prevent subsequent arguments being treated as options.


To safely delete a branch alias, always use:
${command} -d <alias>


WARNING: These symbolic references appear in your branch list as:
<alias> -> <branch>
and so you might be tempted to try to delete them like a branch:
git branch -d <alias>


However this can cause problems.  In git versions prior to 1.8.0.1
<alias> will be dereferenced and you will instead delete the
branch it refers to (git will allow this even if you currently
have that branch checked out), and the symbolic reference will
still remain (referencing a branch which is no longer available).


In later versions of git the <alias> will be deleted rather than
the branch; however git will still not check to see whether you
currently have <alias> checked out, and will not prevent you
from deleting it in that situation.  This will leave your HEAD ref
in an invalid state.  Using ${command} -d <alias> resolves
this situation by first switching HEAD to <alias>'s target branch
if HEAD was currently set to <alias>.


EOF
exit 0
fi


# Confirm the CWD is within a git repository.
#cwd=$(git rev-parse --show-toplevel)
git=$(git rev-parse --git-dir)
if [ $? -ne 0 ]; then
exit 1
fi


# Use the current branch by default.
if [ -z "${branch}" ]; then
branch=$(git symbolic-ref -q HEAD)
if [ $? -ne 0 ]; then
stderr "Could not establish current HEAD."
exit 1
fi
fi


# We expect plain branch names, but also accept the fully-qualified
# (refs/heads/NAME) paths needed by git symbolic-ref; so strip that
# refs/heads/ prefix if it is specified.
branch=${branch##refs/heads/}
symref=${symref##refs/heads/}


# Deleting a symref.
if [ -n "${delete}" ]; then
# Verify that it IS a symbolic reference.
if ! git symbolic-ref "refs/heads/${symref}" >/dev/null; then
stderr "Error validating refs/heads/${symref} as symbolic reference."
exit 1
fi


# If we currently have <symref> checked out, deleting it is bad
# (as HEAD would no longer be a valid reference).  I believe we do
# need to inspect the file here, as attempting to read the HEAD
# reference via git dereferences it to its target branch, and thus
# we are unable to distinguish between the branch and the symref.
if grep "^ref: refs/heads/${symref}\$" "${git}/HEAD" >/dev/null 2>&1; then
stdout "Cannot delete the currently checked out symbolic reference."
branch=$(git symbolic-ref -q HEAD)
if [ $? -ne 0 ]; then
stderr "Could not establish current HEAD."
exit 1
fi
stdout "Switching HEAD to target branch ${branch}"
# By using git symbolic-ref HEAD to find the target ref
# and setting HEAD to that target, nothing really changes,
# but we can now delete the reference safely.
if ! git symbolic-ref HEAD "${branch}"; then
stderr "Error updating HEAD from ${symref} to ${branch}"
stderr "Aborting."
exit 1
fi
fi


# Delete the reference.
# git 1.8.1+ provides: git symbolic-ref --delete <symref>
# but older versions do not include that option, so we use
# the backwards-compatible command.
stdout "Deleting symbolic reference refs/heads/${symref}"
git update-ref -d --no-deref "refs/heads/${symref}"
exit $?
fi


# Creating a new symbolic reference.


# Error checking.  git symbolic-ref doesn't really do any, and will
# happily mess up your branches; particularly if you get the arguments
# the wrong way around (treating it like ln -s is a really bad idea).
if ! git show-ref --verify --heads --quiet "refs/heads/${branch}"; then
stderr "Target branch refs/heads/${branch} does not exist."
exit 1
fi
if target=$(git symbolic-ref -q "refs/heads/${symref}"); then
stderr "Symbolic reference refs/heads/${symref} already exists:"
stderr "  ${symref} -> ${target##refs/heads/}"
stderr "To delete it, use: ${command} -d ${symref}"
exit 1
elif git show-ref --verify --heads --quiet "refs/heads/${symref}"; then
stderr "Reference refs/heads/${symref} already exists"
stderr "(and is not a symbolic reference!)"
exit 1
fi


# The parameters are good.
# Generate the reference and display the confirmed result.
if git symbolic-ref "refs/heads/${symref}" "refs/heads/${branch}"; then
target=$(git symbolic-ref "refs/heads/${symref}")
stdout "  ${symref} -> ${target##refs/heads/}"
else
stderr "Failed to create branch alias."
exit 1
fi
# EOF

上游功能要求: Https://www.mail-archive.com/git@vger.kernel.org/msg161274.html

Tes,使用 git symbolic-ref <alias-branch> <targetbranch>:

git symbolic-ref refs/heads/trunk refs/heads/master
git symbolic-ref refs/heads/master refs/heads/main

但是“当前分支”(git branch --show-current)将是“不正确的”(仍然显示目标分支而不是别名分支) :

在 Git 2.39之前(2022年第4季度) ,在检出一个指向另一个分支的符号引用的“分支”之后,“ git symbolic-ref HEAD(< a href = “ https://git-scm.com/docs/git-sign-ref”rel = “ nofollow norefrer”> man )报告的是底层分支,而不是用户给签出的作为参数的符号引用。

该命令学会了“ --no-recurse”选项,在解除对 symbolic-ref的引用仅一次之后停止。

犯罪(2022年10月7日) by 滨野俊男(gitster)
(由 朱尼奥 · C · 哈马诺 gitster提交4a48c7d合并,2022年10月21日)

symbolic-ref : 教授“——[无]递归”选项

假设您正在管理项目中的许多维护轨道,其中一些最近的维护轨道是 maint-2.36maint-2.37
再想象一下,您的项目最近标记了官方的2.38版本,这意味着您需要尽快启动 maint-2.38跟踪,方法是:

$ git checkout -b maint-2.38 v2.38.0^0
$ git branch --list 'maint-2.3[6-9]'
* maint-2.38
maint-2.36
maint-2.37

目前为止,一切顺利。
但是,我们也有理由不必担心哪条维护轨道是最新的,我们可以用一个听起来更通用的“维护”分支来指向它,我们可以这样做:

$ git symbolic-ref refs/heads/maint refs/heads/maint-2.38

你可透过以下方法查阅最新的维修路轨:

$ git checkout maint
$ git branch --show-current
maint-2.38

可以说,我们处于“ maint-2.38”而不是“ maint”状态更好,git merge/pull 将记录到 maint-2.38而不是 maint,所以我认为我们的行为是好的。

然而,有一件事情有点让人恼火,那就是我认为除了“猫”以外,没有其他好的方法。Git/HEAD”)来了解您检出了“ maint”以进入该状态。
正如上面“ git branch --show-current(< a href = “ https://git-scm.com/docs/git-Branch # Document/git-branch.txt--show-current”rel = “ nofollow noReferrer”> man )的输出所示,“ git symbolic-ref(< a href = “ https://git-scm.com/docs/git-sign-ref”rel = “ nofollow norefrer”> man ) HEAD 将报告‘ refs/HEAD/maint-2.38’,绕过 HEAD 指向的中间符号 ref‘ refs/HEAD/maint’。

内部 resolve_ref() API 已经具有在解析单个级别的符号引用之后停止的必要支持,我们可以通过向命令添加一个“——[ no-]递归”选项来公开它。

git symbolic-ref现在在其 手册中包括:

 'git symbolic-ref' [-q] [--short] [--no-recurse] <name>

--recurse

--no-recurse

当将值显示为符号引用时,如果 指另一个符号参照,按照这样的链 符号引用,直到结果不再指向 符号 ref (--recurse,默认值)。 --no-recurse仅在解除一个级别的引用之后停止 象征性的参考。