有一种方法可以在一个命令中获得git根目录吗?

Mercurial有一种打印根目录(包含.hg)的方法

hg root 

在git中是否有相当于获取包含.git目录的目录?

是:

 git rev-parse --show-toplevel 

git-configman页(在Alias下)说:

如果别名扩展以感叹号为前缀,则将被视为shell命令。 例如,定义“alias.new =!gitk – all – not ORIG_HEAD”,调用“git new”相当于运行shell命令“gitk – all – not ORIG_HEAD”。 请注意,shell命令将从存储库的顶级目录(可能不一定是当前目录)执行。

所以,在UNIX上你可以这样做:

 git config --global --add alias.root '!pwd' 

--show-toplevel最近才被添加到git rev-parse或者为什么没有人提到它?

git rev-parse手册页:

  --show-toplevel Show the absolute path of the top-level directory. 

怎么样“ git rev-parse --git-dir ”?

 F:\prog\git\test\copyMerge\dirWithConflicts>git rev-parse --git-dir F:/prog/git/test/copyMerge/.git 

--git-dir选项似乎可行。

从git rev-parse手册页 :

 --git-dir Show $GIT_DIR if defined else show the path to the .git directory. 

你可以在这个git setup-sh脚本中看到它的作用。

如果你已经在顶层或不在git仓库cd $(git rev-parse --show-cdup)会带你回家(只是cd)。 cd ./$(git rev-parse --show-cdup)是解决这个问题的一种方法。

在这里写一个简单的答案,以便我们可以使用

 git root 

做这个工作,只需使用configuration你的git

 git config --global alias.root "rev-parse --show-toplevel" 

然后你可能想把下面的内容添加到你的~/.bashrc

 alias cdroot='cd $(git root)' 

所以你可以使用cdroot去你的回购顶部。

要计算当前git根目录的绝对path,比如在shell脚本中使用,请使用readlink和git rev-parse的组合:

 gitroot=$(readlink -f ./$(git rev-parse --show-cdup)) 

git-rev-parse --show-cdup为你提供了正确数量的“..”来从你的cwd得到根,或者如果你在根目录的话,它是空的string。 然后前置“./”处理空string的情况,并使用readlink -f转换为完整path。

你也可以在你的PATH中创build一个git-root命令作为shell脚本来应用这个技巧:

 cat > ~/bin/git-root << EOF #!/bin/sh -e cdup=$(git rev-parse --show-cdup) exec readlink -f ./$cdup EOF chmod 755 ~/bin/git-root 

(可以将上面的代码粘贴到terminal中,创buildgit-root并设置执行位;实际的脚本位于第2,3,4行)

然后你可以运行git root来获取当前树的根目录。 请注意,在shell脚本中,如果rev-parse失败,请使用“-e”使shell退出,以便在不在git目录中时正确地获取退出状态和错误消息。

正如其他人所指出的,解决scheme的核心是使用git rev-parse --show-cdup 。 但是,有一些边缘案例需要解决:

  1. 当cwd已经是工作树的根时,该命令产生一个空string。
    实际上它会产生一个空行,但是命令replace会剥离掉尾随的行。 最终的结果是一个空string。

    大多数的答案build议预先输出./以便在input到cd之前,空输出变成"./"

  2. 当GIT_WORK_TREE设置为不是cwd的父级的位置时,输出可能是绝对path名。

    在这种情况下,预先考虑./是错误的。 如果一个./被预置在一个绝对path上,它将成为一个相对path(如果cwd是系统的根目录,它们只能指向相同的位置)。

  3. 输出可能包含空格。

    这真的只适用于第二种情况,但它有一个简单的解决方法:围绕命令replace使用双引号(以及任何后续使用的值)。

正如其他答案已经注意到,我们可以做cd "./$(git rev-parse --show-cdup)" ,但是这在第二个边缘情况下(和第三个边缘情况,如果我们离开双引号)。

许多shell将cd ""视为no-op,因此对于这些shell,我们可以执行cd "$(git rev-parse --show-cdup)" (双引号保护空string作为第一个边框的参数,并在第三个边框中保留空格)。 POSIX表示cd ""的结果是未指定的,所以最好避免做这个假设。

一个解决scheme在所有上述情况下都需要进行某种testing。 明确地做,它可能看起来像这样:

 cdup="$(git rev-parse --show-cdup)" && test -n "$cdup" && cd "$cdup" 

没有cd完成第一个边缘情况。

如果可以运行cd . 对于第一个边缘情况,则可以在扩展参数的情况下完成条件:

 cdup="$(git rev-parse --show-cdup)" && cd "${cdup:-.}" 

修改“git config”的答案只是一点:

 git config --global --add alias.root '!pwd -P' 

并清理path。 非常好。

以防万一,如果您将这条path提供给Git本身,请使用:/

 # this adds the whole working tree from any directory in the repo git add :/ # and is equal to git add $(git rev-parse --show-toplevel) 

如果你正在寻找一个好的别名做这个加上不炸毁cd如果你不是在一个混帐目录:

 alias ..g='git rev-parse && cd "$(git rev-parse --show-cdup)"' 

这个shell别名可以用在你的git子目录中,也可以在顶层:

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

更新为使用现代语法而不是反引号:

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

简短的解决scheme,与子模块,钩子和.git目录内的工作

以下是大多数人想要的简短答案:

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

这将在git工作树(包括.git目录内)的任何地方工作,但是假定版本库目录被称为.git (这是默认的)。 使用子模块时,这将转到最外面的包含存储库的根目录。

如果要获取当前子模块的根目录,请使用:

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

要轻松地在您的子模块根目录下执行命令,请在.gitconfig [alias]下添加:

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

这可以让你轻松地做一些事情,比如git sh ag <string>

强大的解决scheme,支持不同名称或外部.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 # git_root will print any errors cd "$root" } 

通过键入git_root执行它(在重新启动你的shell之后: exec bash

 alias git-root='cd \`git rev-parse --git-dir\`; cd ..' 

一切都失败了,无论是去主目录或只是失败。 这是返回到GIT_DIR的最快和最短的方法。

以下是我编写的脚本,可以处理两种情况:1)具有工作区的存储库; 2)裸存储库。

https://gist.github.com/jdsumsion/6282953

git-root (你的path中的可执行文件):

 #!/bin/bash GIT_DIR=`git rev-parse --git-dir` && ( if [ `basename $GIT_DIR` = ".git" ]; then # handle normal git repos (with a .git dir) cd $GIT_DIR/.. else # handle bare git repos (the repo IS a xxx.git dir) cd $GIT_DIR fi pwd ) 

希望这是有帮助的。

 $ git config alias.root '!pwd' # then you have: $ git root 

git-extras

添加$ git root
请参阅https://github.com/tj/git-extras/blob/master/Commands.md#git-root

 $ pwd .../very-deep-from-root-directory $ cd `git root` $ git add . && git commit 

git-extas的可用性

今天必须自己解决这个问题。 解决它在C#中,因为我需要一个程序,但我想它可以esily重写。 考虑这个公共领域。

 public static string GetGitRoot (string file_path) { file_path = System.IO.Path.GetDirectoryName (file_path); while (file_path != null) { if (Directory.Exists (System.IO.Path.Combine (file_path, ".git"))) return file_path; file_path = Directory.GetParent (file_path).FullName; } return null; }