git:转到工作树根的快速命令

问题描述 投票:0回答:9

我想要一个简单的 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 bash scripting
9个回答
64
投票

更简单的是,窃取 有没有办法在一个命令中获取 git 根目录? ,并从

创建一个别名(按照 Peter 的建议)
cd "$(git rev-parse --show-toplevel)"

无论您是否位于根目录中,这都有效。


63
投票

这个问题之前已经被问过,有没有一种方法可以通过一个命令获取 git 根目录?复制 @docgnome 的答案,他写道

cd $(git rev-parse --show-cdup)

如果愿意,可以创建别名:

alias git-root='cd $(git rev-parse --show-cdup)'

15
投票

如果您位于 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'

6
投票
$ git config alias.root '!pwd'
$ git root

3
投票

使用子模块、挂钩和

.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


2
投票

不幸的是,更改当前目录只能由 shell 完成,而不能由任何子进程完成。当 git 开始解析你的命令时,已经太晚了——git 已经在一个单独的进程中生成了。

这是一个非常粗糙的、未经测试的 shell 函数,它可能会做你想要的事情:

function git() {
    if [ "$1" == "root" ]; then
        git-root
    else
        git "$@"
    fi
}

1
投票

在 bash 和 zsh 中工作的更好的别名是:

alias git-root='cd "$(git rev-parse --show-cdup)"'

0
投票

如果您使用 oh-my-zsh 并且您在

中添加了 
git

插件
plugins+=(git)

.zshrc
配置文件,以下命令(别名)有效:

grt

此别名的定义方式如下:

grt='cd "$(git rev-parse --show-toplevel \|\| echo .)"'

0
投票
alias cdg='_t=$(git rev-parse --show-toplevel) && cd "$_t" && pwd'

简短的别名,但当你不在 git repo 或其他地方时可以处理情况。它还会在 cd'ing 后打印当前工作目录 (

pwd
),但如果需要,您可以将其删除。

© www.soinside.com 2019 - 2024. All rights reserved.