有一种方法可以在一个命令中获得git根目录吗?
Mercurial有一种打印根目录(包含.hg)的方法
hg root
在git中是否有相当于获取包含.git目录的目录?
是:
git rev-parse --show-toplevel
git-config
的man
页(在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
。 但是,有一些边缘案例需要解决:
-
当cwd已经是工作树的根时,该命令产生一个空string。
实际上它会产生一个空行,但是命令replace会剥离掉尾随的行。 最终的结果是一个空string。大多数的答案build议预先输出
./
以便在input到cd
之前,空输出变成"./"
。 -
当GIT_WORK_TREE设置为不是cwd的父级的位置时,输出可能是绝对path名。
在这种情况下,预先考虑
./
是错误的。 如果一个./
被预置在一个绝对path上,它将成为一个相对path(如果cwd是系统的根目录,它们只能指向相同的位置)。 -
输出可能包含空格。
这真的只适用于第二种情况,但它有一个简单的解决方法:围绕命令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的可用性
- 自制软件(osx)/ linuxbrew(linux)
$ brew install git-extras
- debian / ubuntu的回购( https://packages.debian.org/sid/git-extras)$
$ apt-get install git-extras
今天必须自己解决这个问题。 解决它在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; }