Mercurial имеет способ распечатать корневой каталог (содержащий .hg) через
hg root
Есть ли что-то эквивалентное в git для получения каталога, содержащего каталог .git?
Mercurial имеет способ распечатать корневой каталог (содержащий .hg) через
hg root
Есть ли что-то эквивалентное в git для получения каталога, содержащего каталог .git?
Да:
git rev-parse --show-toplevel
Примечание: в субмодуле будет отображаться корневой каталог субмодуля, а не родительский репозиторий. Если вы используете Git> = 2.13 или выше, вот способ, которым подмодули могут показать корневой каталог суперпроекта. Если ваш git старше этого, см. этот другой ответ.
Страница man
для git-config
(под псевдонимом) гласит:
Если расширение псевдонима начинается с восклицательного знака, оно будет рассматриваться как оболочка команда. [...] Обратите внимание, что оболочка команды будут выполняться из каталога верхнего уровня репозитория, который может не обязательно быть текущим каталогом.
Итак, в UNIX вы можете сделать:
git config --global --add alias.root '!pwd'
Добавлен ли --show-toplevel
только недавно в git rev-parse
или почему его никто не упоминает?
На странице git rev-parse
man:
--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> = 2.13, используйте:
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). cd ./$(git rev-parse --show-cdup)
является одним из способов его фиксации.
Как отмечали другие, суть решения заключается в использовании git rev-parse --show-cdup
. Тем не менее, есть несколько крайних случаев для адреса:
Когда cwd уже является корнем рабочего дерева, команда дает пустую строку.
На самом деле он создает пустую строку, но команда замещает полосу отрывной линии. Конечным результатом является пустая строка.
В большинстве ответов предлагается добавить вывод с помощью ./
, чтобы пустой результат становился "./"
, прежде чем он будет отправлен на cd
.
Когда GIT_WORK_TREE установлен в местоположение, которое не является родительским элементом cwd, вывод может быть абсолютным именем пути.
Превращение ./
неверно в этой ситуации. Если a ./
добавляется к абсолютному пути, он становится относительным путем (и они относятся только к одному и тому же адресу, если cwd является корневым каталогом системы).
Вывод может содержать пробелы.
Это действительно применимо только во втором случае, но у него есть легкое исправление: используйте двойные кавычки вокруг подстановки команды (и любых последующих применений значения).
Как отмечали другие ответы, мы можем сделать cd "./$(git rev-parse --show-cdup)"
, но это ломается во втором краевом случае (и в случае третьего края, если мы опустим двойные кавычки).
Многие оболочки рассматривают cd ""
как no-op, поэтому для этих оболочек мы можем сделать 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, скажем, для использования в оболочке script, используйте эту комбинацию readlink и git rev-parse:
gitroot=$(readlink -f ./$(git rev-parse --show-cdup))
git-rev-parse --show-cdup
дает вам правильное количество "..", чтобы получить
к корню из вашего cwd, или пустую строку, если вы находитесь в корне.
Затем добавьте "./", чтобы иметь дело с пустой строкой и использовать
readlink -f
, чтобы перевести на полный путь.
Вы также можете создать команду git-root
в PATH в качестве оболочки script, чтобы применить эту технику:
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 и установки битов выполнения, фактический script находится в строках 2, 3 и 4.)
И тогда вы сможете запустить git root
, чтобы получить корень вашего текущего дерева.
Обратите внимание, что в оболочке script используйте "-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
Вот краткий ответ, который больше всего захочется:
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 \"[email protected]\"; }; f"
Это позволяет вам легко делать такие вещи, как git sh ag <string>
Надежное решение, которое поддерживает каталоги .git
или $GIT_DIR
с разными именами.
Обратите внимание, что $GIT_DIR
может указывать на что-то внешнее (и не называться .git
), поэтому необходима дополнительная проверка.
Поместите это в свой .bashrc
:
# Print the name of the git working tree 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 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 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
)
Чтобы внести изменения в "git config", ответьте немного:
git config --global --add alias.root '!pwd -P'
и очистите путь. Очень приятно.
Если вы ищете хороший псевдоним, чтобы сделать это, а не взорвать cd
, если вы не находитесь в директории git:
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
$ brew install 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)'
alias git-root='cd \`git rev-parse --git-dir\`; cd ..'
Все остальное не удается в какой-то момент либо перейти в домашний каталог, либо просто провалиться. Это самый быстрый и самый короткий способ вернуться к GIT_DIR.
Вот скрипт, который я написал, который обрабатывает оба случая: 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 config alias.root '!pwd'
# then you have:
$ git root
Начиная с Git 2.13.0, он поддерживает новую опцию показа пути корневого проекта, которая работает даже при использовании изнутри подмодуля:
git rev-parse --show-superproject-working-tree
Если вы используете оболочку оболочки, возможно, уже существует псевдоним оболочки:
$ grt
в о-о-о (68k) (cd $(git rev-parse --show-toplevel || echo ".")
)$ git-root
в prezto (8.8k) (отображает путь к корню рабочего дерева)$ g..
zimfw (1k) (изменяет текущий каталог на верхний уровень рабочего дерева.)На случай, если кому-то понадобится 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)
}
Я хотел бы остановиться на превосходном комментарии Дэниела Брокмана.
Определение 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
Надо было решить это сам сегодня. Решил его на С#, поскольку мне это нужно для программы, но я думаю, что это можно переписать. Рассмотрим этот общедоступный домен.
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;
}