Is there a way to get the git root directory in on

2018-12-31 18:42发布

Mercurial has a way of printing the root directory (that contains .hg) via

hg root

Is there something equivalent in git to get the directory that contains the .git directory?

22条回答
唯独是你
2楼-- · 2018-12-31 19:04

Since Git 2.13.0, it supports a new option to show the path of the root project, which works even when being used from inside a submodule:

git rev-parse --show-superproject-working-tree
查看更多
宁负流年不负卿
3楼-- · 2018-12-31 19:05

Short solutions that work with submodules, in hooks, and inside the .git directory

Here's the short answer that most will want:

r=$(git rev-parse --git-dir) && r=$(cd "$r" && pwd)/ && echo "${r%%/.git/*}"

This will work anywhere in a git working tree (including inside the .git directory), but assumes that repository directory(s) are called .git (which is the default). With submodules, this will go to the root of the outermost containing repository.

If you want to get to the root of the current submodule use:

echo $(r=$(git rev-parse --show-toplevel) && ([[ -n $r ]] && echo "$r" || (cd $(git rev-parse --git-dir)/.. && pwd) ))

To easily execute a command in your submodule root, under [alias] in your .gitconfig, add:

sh = "!f() { root=$(pwd)/ && cd ${root%%/.git/*} && git rev-parse && exec \"$@\"; }; f"

This allows you to easily do things like git sh ag <string>

Robust solution that supports differently named or external .git or $GIT_DIR directories.

Note that $GIT_DIR may point somewhere external (and not be called .git), hence the need for further checking.

Put this in your .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 # git_root will print any errors
  cd "$root"
}

Execute it by typing git_root (after restarting your shell: exec bash)

查看更多
琉璃瓶的回忆
4楼-- · 2018-12-31 19:06

This shell alias works whether you are in a git subdir, or at the top level:

alias gr='[ ! -z `git rev-parse --show-toplevel` ] && cd `git rev-parse --show-toplevel || pwd`'

updated to use modern syntax instead of backticks:

alias gr='[ ! -z $(git rev-parse --show-toplevel) ] && cd $(git rev-parse --show-toplevel || pwd)'
查看更多
时光乱了年华
5楼-- · 2018-12-31 19:09

Has --show-toplevel only recently been added to git rev-parse or why is nobody mentioning it?

From the git rev-parse man page:

   --show-toplevel
       Show the absolute path of the top-level directory.
查看更多
登录 后发表回答