Mercurial可以通过以下方式打印根目录(包含.hg)
hg root
git中是否有等效的东西来获取包含.git目录的目录?
bzr root
集市中好奇或搜寻的人也非常有用
Mercurial可以通过以下方式打印根目录(包含.hg)
hg root
git中是否有等效的东西来获取包含.git目录的目录?
bzr root
集市中好奇或搜寻的人也非常有用
Answers:
是:
git rev-parse --show-toplevel
如果您想直接复制Git命令,可以创建一个别名:
git config --global alias.root 'rev-parse --show-toplevel'
现在git root
将像一样运行hg root
。
注:在一个子模块,这将显示的根目录下的子模块,并没有父库。如果您使用的是Git> = 2.13或更高版本,则子模块可以通过一种方式显示超级项目的根目录。如果您的git早于该版本,请参阅其他答案。
git config --global alias.exec '!exec '
以便我可以做类似的事情git exec make
。之所以可行,是因为外壳别名始终在顶级目录中执行。
hg root
。它打印出已检出存储库的顶级目录。它不会将您切换到它(事实上,由于当前目录的整个概念和您的shell会如何交互,所以它无法这样做)。
~/my.proj/foo/bar
并~/my.proj
与之链接~/src/my.proj
,则上述命令会将您移至~/src/my.proj
。如果之后要执行的操作与树无关,则可能会出现问题。
.git
目录中时,它不起作用。
(在Alias下)的man
页面显示:git-config
如果别名扩展名带有感叹号作为前缀,它将被视为shell命令。[...]注意,shell命令将从存储库的顶级目录执行,该目录不一定是当前目录。
因此,在UNIX上,您可以执行以下操作:
git config --global --add alias.root '!pwd'
.zshrc
,并且定义了“ alias cg =“ cd $(git root)”,则$()部分将在源代码时进行评估,并始终指向〜/ dotfiles,因为这是我的zshrc所在的位置。
有--show-toplevel
最近才加入git rev-parse
或为什么没人提呢?
从git rev-parse
手册页:
--show-toplevel
Show the absolute path of the top-level directory.
git-rev-parse
-因为它的名字表明它与处理修订规范有关。顺便说一句,我很高兴看到git --work-tree
类似的工作git --exec-path[=<path>]
:“如果没有给出路径,git将显示当前设置”;至少,IMO,寻找这样的功能将是一个合乎逻辑的地方。
root = rev-parse --show-toplevel
在gitconfig中使用别名。
git config --global alias.root "rev-parse --show-toplevel"
,然后git root
将能够完成工作
git rev-parse --show-toplevel
在子模块中尝试时起作用。它输出git子模块的根目录。它为您打印什么?
--show-cdup
是--show-top-level
2011年2月至(在提交此答案之后)。
怎么样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-dir
Show $GIT_DIR if defined else show the path to the .git directory.
您可以在此git setup-sh
脚本中看到它的运行。
如果您位于子模块文件夹中,且Git> = 2.13,请使用:
git rev-parse --show-superproject-working-tree
如果您正在使用git rev-parse --show-toplevel
,请确保它与Git 2.25+(Q1 2020)一起使用。
.git
如果您已经在根目录中,该命令似乎也会提供一个相对路径。(至少它对msysgit有用。)
如果您已经在顶层或不在git存储库中,cd $(git rev-parse --show-cdup)
则会带您回家(仅使用cd)。 cd ./$(git rev-parse --show-cdup)
是解决该问题的一种方法。
cd "$(git rev-parse --show-cdup)"
。之所以有效,是因为cd ""
它使您无所事事,而不是返回$HOME
。最好还是引用$()调用,以防它们输出带有空格的东西(不过,在这种情况下,此命令不会)。
$PWD
。这个例子混帐的根相将解析为$PWD
代替realpath $PWD
。
要计算当前git根目录的绝对路径(例如要在shell脚本中使用),请使用readlink和git rev-parse的这种组合:
gitroot=$(readlink -f ./$(git rev-parse --show-cdup))
git-rev-parse --show-cdup
给您正确的数字“ ..”以从您的cwd到达根,如果您位于根,则为空字符串。然后在前缀“ ./”之前处理空字符串,并用于
readlink -f
转换为完整路径。
您还可以git-root
在PATH中创建一个命令作为外壳程序脚本来应用此技术:
cat > ~/bin/git-root << EOF
#!/bin/sh -e
cdup=$(git rev-parse --show-cdup)
exec readlink -f ./$cdup
EOF
chmod 755 ~/bin/git-root
(以上内容可以粘贴到终端中以创建git-root并设置执行位;实际的脚本在第2、3和4行中。)
然后,您将能够运行git root
以获取当前树的根。请注意,在shell脚本中,如果rev-parse失败,请使用“ -e”导致shell退出,这样,如果您不在git目录中,则可以正确获取退出状态和错误消息。
"$(git rev-parse ...)"
代替hack之类的东西./$(git rev-parse ...)
。
正如其他人指出的那样,该解决方案的核心是使用git rev-parse --show-cdup
。但是,有一些边缘情况需要解决:
当cwd已经是工作树的根时,该命令将产生一个空字符串。
实际上,它会产生一个空行,但命令替换会删除尾随的换行符。最终结果是一个空字符串。
大多数的答案建议前面加上输出,./
使空的输出成为"./"
它被送到之前cd
。
当GIT_WORK_TREE设置为不是cwd父级的位置时,输出可能是绝对路径名。
./
在这种情况下,前置是错误的。如果将a ./
放在绝对路径之前,则它将成为相对路径(如果cwd是系统的根目录,则它们仅引用相同的位置)。
输出可能包含空格。
这实际上仅适用于第二种情况,但是它有一个简单的解决方法:在命令替换(以及该值的任何后续用法)周围使用双引号。
正如其他答案所指出的,我们可以这样做cd "./$(git rev-parse --show-cdup)"
,但是这会在第二种情况(如果我们不使用双引号的情况下在第三种情况)中中断。
许多shell都将其cd ""
视为无操作对象,因此我们可以做到cd "$(git rev-parse --show-cdup)"
(双引号在第一个边缘情况下将空字符串作为参数保护,在第三个边缘情况下保留空白)。POSIX表示的结果cd ""
不确定,因此最好避免做出此假设。
在以上所有情况下均有效的解决方案需要某种测试。明确完成后,可能看起来像这样:
cdup="$(git rev-parse --show-cdup)" && test -n "$cdup" && cd "$cdup"
没有cd
针对第一边缘的情况下完成的。
如果可以cd .
在第一个边缘情况下运行,则可以在参数的扩展中完成条件:
cdup="$(git rev-parse --show-cdup)" && cd "${cdup:-.}"
git root
'?
与子模块,挂钩和.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) ))
要在子模块根目录中轻松执行命令,请在[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"
}
通过键入执行它git_root
(重新启动后壳:exec bash
)
(root=$(git rev-parse --git-dir)/ && cd ${root%%/.git/*} && git rev-parse && pwd)
但这不包括外部名称$GIT_DIR
,这些名称不是.git
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
$ brew install git-extras
$ apt-get install git-extras
alias git-root='cd \`git rev-parse --git-dir\`; cd ..'
其他所有操作都在某个时候失败,要么进入主目录,要么不幸失败。这是回到GIT_DIR的最快和最短的方法。
$GIT_DIR
使用-Files .git
和从工作树中分离时,此操作将失败gitdir: SOMEPATH
。因此,这对于$GIT_DIR
包含的子模块也失败.git/modules/SUBMODULEPATH
。
这是我编写的可处理这两种情况的脚本:1)具有工作区的存储库,2)裸存储库。
https://gist.github.com/jdsumsion/6282953
git-root
(您路径中的可执行文件):
#!/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 exec
想法在非裸仓库中更有用。但是,我的答案中的此脚本可以正确处理裸机与非裸机情况,这可能对某人有用,因此我将其留在此处。
git submodule
的失败。您还假设,在非裸露的情况下,该目录是工作树的一部分。$GIT_DIR
/.git/modules/SUBMODULE
.git
$ git config alias.root '!pwd'
# then you have:
$ git root
[alias] findroot = "!f () { [[ -d ".git" ]] && echo "Found git in [
pwd ]" && exit 0; cd .. && echo "IN
pwd" && f;}; f"
git config --global alias.root '!pwd'
。我无法发现任何情况都与非全局变量有所不同。(Unix,git 1.7.10.4)BTW:您findroot
需要a /.git
来避免无限递归。
从Git 2.13.0开始,它支持一个新选项来显示根项目的路径,即使从子模块内部使用它也可以正常工作:
git rev-parse --show-superproject-working-tree
如果使用外壳程序框架,则可能已经有可用的外壳程序别名:
$ grt
在oh-my-zsh(68k)(cd $(git rev-parse --show-toplevel || echo ".")
)$ git-root
在prezto(8.8k)中(显示到工作树根的路径)$ g..
zimfw(1k)(将当前目录更改为工作树的顶层。)我想补充一下丹尼尔·布罗克曼的出色评论。
定义git config --global alias.exec '!exec '
允许您执行以下操作:git exec make
因为man git-config
状态如下:
如果别名扩展名带有感叹号作为前缀,它将被视为shell命令。[...]注意,shell命令将从存储库的顶级目录执行,该目录不一定是当前目录。
知道$GIT_PREFIX
相对于存储库顶级目录的当前目录的路径也很方便。但是,知道这只是成功的一半。Shell变量扩展使其很难使用。所以我建议这样使用bash -c
:
git exec bash -c 'ls -l $GIT_PREFIX'
其他命令包括:
git exec pwd
git exec make
如果任何人都需要执行POSIX兼容方式而不需要git
可执行文件:
#$1: Path to child directory
git_root_recurse_parent() {
# Check if cwd is a git root directory
if [ -d .git/objects -a -d .git/refs -a -f .git/HEAD ] ; then
pwd
return 0
fi
# Check if recursion should end (typically if cwd is /)
if [ "${1}" = "$(pwd)" ] ; then
return 1
fi
# Check parent directory in the same way
local cwd=$(pwd)
cd ..
git_root_recurse_parent "${cwd}"
}
git_root_recurse_parent
如果只希望将功能作为脚本的一部分,请删除shebang,然后将最后git_root_recurse_parent
一行替换为:
git_root() {
(git_root_recurse_parent)
}
if
语句应该检查您是否在递归中更改了目录。如果它位于同一目录中,则假定您被卡在某个位置(例如/
),并阻止递归。该错误已修复,现在应该可以按预期运行。感谢您指出。
今天不得不自己解决这个问题。我在程序中需要时用C#解决了它,但是我想它可以轻松地重写。考虑这个公共领域。
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;
}