Есть ли способ получить корневой каталог git в одной команде?
Mercurial имеет способ печати корневого каталога (который содержит.hg) через
hg root
Есть ли что-то эквивалентное в git, чтобы получить каталог, содержащий каталог.git?
24 ответа
Да:
git rev-parse --show-toplevel
Примечание. В подмодуле будет отображаться корневой каталог подмодуля, а не родительский репозиторий.
Имеет --show-toplevel
только недавно был добавлен в git rev-parse
или почему никто не упоминает об этом?
От git rev-parse
справочная страница:
--show-toplevel
Show the absolute path of the top-level directory.
man
страница для git-config
(под псевдонимом) говорит:
Если расширение псевдонима начинается с восклицательного знака, оно будет рассматриваться как команда оболочки. [...] Обратите внимание, что команды оболочки будут выполняться из каталога верхнего уровня репозитория, который необязательно может быть текущим каталогом.
Итак, в UNIX вы можете сделать:
git config --global --add alias.root '!pwd'
Как насчет " 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 2.20, используйте:
git rev-parse --show-superproject-working-tree
Чтобы написать простой ответ здесь, чтобы мы могли использовать
git root
чтобы сделать работу, просто настройте свой git с помощью
git config --global alias.root "rev-parse --show-toplevel"
а затем вы можете добавить следующее к вашему ~/.bashrc
:
alias cdroot='cd $(git root)'
так что вы можете просто использовать cdroot
перейти на вершину вашего репо.
Если вы уже на верхнем уровне или не в репозитории git cd $(git rev-parse --show-cdup)
отвезет вас домой (просто компакт-диск). cd ./$(git rev-parse --show-cdup)
это один из способов исправить это.
Короткие решения, которые работают с подмодулями, в хуках и внутри .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 # git_root will print any errors
cd "$root"
}
Выполните это, набрав git_root
(после перезапуска вашей оболочки: exec bash
)
Как уже отмечали другие, суть решения заключается в использовании git rev-parse --show-cdup
, Тем не менее, есть несколько крайних случаев:
Когда cwd уже является корнем рабочего дерева, команда выдает пустую строку.
На самом деле он выдает пустую строку, но подстановка команды удаляет разрыв задней строки. Конечный результат - пустая строка.Большинство ответов предлагают дополнить вывод
./
так что пустой вывод становится"./"
до того, как его кормятcd
,Когда для GIT_WORK_TREE задано местоположение, которое не является родительским для cwd, выходные данные могут быть абсолютным путем.
Предварение
./
неправильно в этой ситуации. Если./
перед абсолютным путем, он становится относительным путем (и они ссылаются на одно и то же местоположение, только если cwd является корневым каталогом системы).Вывод может содержать пробелы.
Это действительно применимо только во втором случае, но это легко исправить: использовать двойные кавычки вокруг подстановки команд (и любые последующие использования значения).
Как отмечали другие ответы, мы можем сделать cd "./$(git rev-parse --show-cdup)"
, но это нарушается во втором краевом случае (и третьем краевом случае, если мы исключим двойные кавычки).
Многие снаряды лечат 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, скажем, для использования в сценарии оболочки, используйте эту комбинацию 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
чтобы получить корень вашего текущего дерева. Обратите внимание, что в сценарии оболочки используйте "-e", чтобы заставить оболочку завершиться, если rev-parse завершится неудачно, чтобы вы могли правильно получить статус выхода и сообщение об ошибке, если вы не находитесь в каталоге git.
На всякий случай, если вы подаете этот путь к самому 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)
Чтобы немного изменить ответ "git config":
git config --global --add alias.root '!pwd -P'
и очистить путь. Очень хорошо.
Начиная с Git 2.13.0, он поддерживает новую опцию для отображения пути корневого проекта, которая работает даже при использовании изнутри подмодуля:
git rev-parse --show-superproject-working-tree
Если вы ищете хороший псевдоним, чтобы сделать это, а не взорвать cd
если вы не в git dir:
alias ..g='git rev-parse && cd "$(git rev-parse --show-cdup)"'
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-Extras
- доморощенного (OSX)/linuxbrew(Linux)
$ brew install git-extras
- репозитории Debian/ Ubuntu ( https://packages.debian.org/sid/git-extras)
$ apt-get install git-extras
Этот псевдоним оболочки работает независимо от того, находитесь ли вы в подкаталоге 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)'
Вот сценарий, который я написал, который обрабатывает оба случая: 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
)
Надеюсь, это полезно.
alias git-root='cd \`git rev-parse --git-dir\`; cd ..'
Все остальное терпит неудачу в некоторый момент или идет в домашний каталог или просто терпит неудачу. Это самый быстрый и короткий способ вернуться к GIT_DIR.
Предварительно настроенные псевдонимы оболочки в оболочках оболочки
Если вы используете оболочку оболочки, возможно, уже существует псевдоним оболочки:
$ grt
в о-о-о (68k) (cd $(git rev-parse --show-toplevel || echo ".")
)$ git-root
в презто (8.8к) (отображает путь к корню рабочего дерева)$ g..
zimfw (1k) (изменяет текущий каталог на верхний уровень рабочего дерева.)
Я хотел бы расширить превосходный комментарий Дэниела Брокмана.
определяющий git config --global alias.exec '!exec '
позволяет делать такие вещи, как git exec make
потому что, как man git-config
состояния:
Если расширение псевдонима начинается с восклицательного знака, оно будет рассматриваться как команда оболочки. [...] Обратите внимание, что команды оболочки будут выполняться из каталога верхнего уровня репозитория, который необязательно может быть текущим каталогом.
Также полезно знать, что $GIT_PREFIX
будет путь к текущему каталогу относительно каталога верхнего уровня репозитория. Но, зная, что это только полдела ™. Расширение переменной оболочки делает его довольно сложным в использовании. Поэтому я предлагаю использовать bash -c
вот так:
git exec bash -c 'ls -l $GIT_PREFIX'
другие команды включают в себя:
git exec pwd
git exec make
В случае, если кому-то нужен POSIX-совместимый способ сделать это, без необходимости git
исполняемым:
git-root
:
#!/bin/sh
#$1: Path to child directory
recurse_parent() {
if is_cwd_git_root ; then
pwd
return 0
fi
if [ "${1}" = "$(pwd)" ] ; then
return 1
fi
cd ..
recurse_parent "${CWD}"
}
is_cwd_git_root() {
[ -d .git/branches -a -d .git/objects -a -d .git/refs -a -f .git/HEAD ]
}
recurse_parent
В рабочем дереве Git--git-dir
получает путь к метаданным рабочего дерева внутри папки. Чтобы получить путь к фактическому.git
папку, в которую можно установить хуки, используйте--git-common-dir
вместо:
/Projects/mywork$ git rev-parse --git-dir
/Projects/app/.git/worktrees/mywork
/Projects/mywork$ git rev-parse --git-common-dir
/Projects/app/.git
РЕДАКТИРОВАТЬ: Для крючков есть лучшее решение:
/Projects/mywork$ git rev-parse --git-path hooks
/Projects/app/.git/hooks
Пришлось решить это самому сегодня. Решил это в 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;
}
git rev-parse --show-prefix
вернет путь от текущей папки до корневой папки репозитория git.