git: a quick command to go to root of the working tree

前端 未结 7 1747
悲&欢浪女
悲&欢浪女 2020-12-24 01:21

I wanted a simple git command to go up to the \"root\" of the repository.

I started with a script, but figured that I cannot change active directory of the shell, I

7条回答
  •  -上瘾入骨i
    2020-12-24 01:50

    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)/ && cd "${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:

    cd ''$(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

    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 1  # git_root will print any errors
      cd "$root"
    }
    

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

提交回复
热议问题