我想要一个简单的 git 命令来进入存储库的“根”。
我从一个脚本开始,但发现我无法更改 shell 的活动目录,我必须执行一个函数。不幸的是,例如,我无法直接使用非破折号形式“git root”来调用它。
function git-root() {
if [ -d .git ]; then
return 0
fi
A=..
while ! [ -d $A/.git ]; do
A="$A/.."
done
cd $A
}
您有更好的解决方案吗? (功能很快就写好了,欢迎提出建议)
更简单的是,窃取 有没有办法在一个命令中获取 git 根目录? ,并从
创建一个别名(按照 Peter 的建议)cd "$(git rev-parse --show-toplevel)"
无论您是否位于根目录中,这都有效。
这个问题之前已经被问过,有没有一种方法可以通过一个命令获取 git 根目录?复制 @docgnome 的答案,他写道
cd $(git rev-parse --show-cdup)
如果愿意,可以创建别名:
alias git-root='cd $(git rev-parse --show-cdup)'
如果您位于 git 根目录的子目录中,Peter 的上述答案非常有效。如果您已经在 git root 中,它会将您带回 $HOME。为了防止这种情况,我们可以使用一些 bash 条件。
if [ "`git rev-parse --show-cdup`" != "" ]; then cd `git rev-parse --show-cdup`; fi
因此别名变为:
alias git-root='if [ "`git rev-parse --show-cdup`" != "" ]; then cd `git rev-parse --show-cdup`; fi'
$ git config alias.root '!pwd'
$ git root
使用子模块、挂钩和
.git
目录中的简短解决方案
这是大多数人想要的简短答案:
r=$(git rev-parse --git-dir) && r=$(cd "$r" && pwd)/ && cd "${r%%/.git/*}"
这将在 git 工作树中的任何位置(包括在
.git
目录内)工作,但假设存储库目录称为 .git
(这是默认值)。对于子模块,这将转到最外层包含存储库的根目录。
如果你想到达当前子模块的根目录,请使用:
cd ''$(r=$(git rev-parse --show-toplevel) && [[ -n $r ]] && echo "$r" || (cd $(git rev-parse --git-dir)/.. && pwd) )
要轻松地在子模块根目录中执行命令,请在
[alias]
中的 .gitconfig
下添加:
sh = "!f() { root=$(pwd)/ && cd ${root%%/.git/*} && git rev-parse && exec \"$@\"; }; f"
这可以让您轻松执行诸如
git sh ag <string>
之类的事情
强大的解决方案,支持不同名称或外部
.git
或 $GIT_DIR
目录。
请注意,
$GIT_DIR
可能指向外部某个地方(而不是称为.git
),因此需要进一步检查。
将其放入您的
.bashrc
:
# Print the name of the git working tree's root directory
function git_root() {
local root first_commit
# git displays its own error if not in a repository
root=$(git rev-parse --show-toplevel) || return
if [[ -n $root ]]; then
echo $root
return
elif [[ $(git rev-parse --is-inside-git-dir) = true ]]; then
# We're inside the .git directory
# Store the commit id of the first commit to compare later
# It's possible that $GIT_DIR points somewhere not inside the repo
first_commit=$(git rev-list --parents HEAD | tail -1) ||
echo "$0: Can't get initial commit" 2>&1 && false && return
root=$(git rev-parse --git-dir)/.. &&
# subshell so we don't change the user's working directory
( cd "$root" &&
if [[ $(git rev-list --parents HEAD | tail -1) = $first_commit ]]; then
pwd
else
echo "$FUNCNAME: git directory is not inside its repository" 2>&1
false
fi
)
else
echo "$FUNCNAME: Can't determine repository root" 2>&1
false
fi
}
# Change working directory to git repository root
function cd_git_root() {
local root
root=$(git_root) || return 1 # git_root will print any errors
cd "$root"
}
通过输入
cd_git_root
执行它(重新启动 shell 后:exec bash
)
不幸的是,更改当前目录只能由 shell 完成,而不能由任何子进程完成。当 git 开始解析你的命令时,已经太晚了——git 已经在一个单独的进程中生成了。
这是一个非常粗糙的、未经测试的 shell 函数,它可能会做你想要的事情:
function git() {
if [ "$1" == "root" ]; then
git-root
else
git "$@"
fi
}
在 bash 和 zsh 中工作的更好的别名是:
alias git-root='cd "$(git rev-parse --show-cdup)"'
如果您使用 oh-my-zsh 并且您在
中添加了
git
插件
plugins+=(git)
.zshrc
配置文件,以下命令(别名)有效:
grt
此别名的定义方式如下:
grt='cd "$(git rev-parse --show-toplevel \|\| echo .)"'
alias cdg='_t=$(git rev-parse --show-toplevel) && cd "$_t" && pwd'
简短的别名,但当你不在 git repo 或其他地方时可以处理情况。它还会在 cd'ing 后打印当前工作目录 (
pwd
),但如果需要,您可以将其删除。