Есть ли способ получить корневой каталог git одной командой? - PullRequest
575 голосов
/ 06 июня 2009

Mercurial имеет способ печати корневого каталога (который содержит .hg) через

hg root

Есть ли что-то эквивалентное в git для получения каталога, содержащего каталог .git?

Ответы [ 22 ]

947 голосов
/ 06 июня 2009

Да

git rev-parse --show-toplevel

Примечание : в субмодуле будет отображаться корневой каталог субмодуля, а не родительский репозиторий. Если вы используете Git> = 2.13 или выше, вот способ, которым подмодули могут показать корневой каталог суперпроекта. Если ваш git старше этого, посмотрите этот другой ответ. 1011 *

91 голосов
/ 11 декабря 2009

Страница man для git-config (под Псевдоним ) гласит:

Если расширение псевдонима начинается с восклицательного знака, оно будет рассматриваться как оболочка команда. [...] Обратите внимание, что оболочка команды будут выполняться из каталога верхнего уровня репозитория, который может не обязательно быть текущим каталогом.

Итак, в UNIX вы можете сделать:

git config --global --add alias.root '!pwd'
85 голосов
/ 10 сентября 2010

Был ли --show-toplevel только недавно добавлен в git rev-parse или почему никто не упоминает об этом?

со страницы руководства git rev-parse:

   --show-toplevel
       Show the absolute path of the top-level directory.
44 голосов
/ 06 июня 2009

Как насчет "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
30 голосов
/ 03 мая 2014

Чтобы написать простой ответ, чтобы мы могли использовать

git root

чтобы выполнить эту работу, просто настройте свой git с помощью

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

и затем вы можете добавить следующее к вашему ~/.bashrc:

alias cdroot='cd $(git root)'

так что вы можете просто использовать cdroot, чтобы перейти к началу репо.

25 голосов
/ 15 июня 2009

Если вы уже на верхнем уровне или не в репозитории git, cd $(git rev-parse --show-cdup) доставит вас домой (просто cd). cd ./$(git rev-parse --show-cdup) - это один из способов исправить это.

17 голосов
/ 05 июля 2010

Как уже отмечалось, ядром решения является использование git rev-parse --show-cdup. Однако есть несколько крайних случаев для рассмотрения:

  1. Когда cwd уже является корнем рабочего дерева, команда выдает пустую строку.
    На самом деле он выдает пустую строку, но подстановка команды удаляет разрыв задней строки. Окончательный результат - пустая строка.

    В большинстве ответов предлагается добавить к выводу ./, чтобы пустой вывод стал "./" до того, как он будет передан cd.

  2. Когда для GIT_WORK_TREE задано местоположение, которое не является родительским для cwd, выходные данные могут быть абсолютным путем.

    Предположим, ./ неверно в этой ситуации. Если к абсолютному пути добавляется ./, он становится относительным путем (и они ссылаются на одно и то же местоположение, только если cwd является корневым каталогом системы).

  3. Вывод может содержать пробелы.

    Это действительно применимо только во втором случае, но его легко исправить: используйте двойные кавычки вокруг подстановки команд (и любые последующие использования значения).

Как уже отмечалось в других ответах, мы можем сделать 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:-.}"
16 голосов
/ 09 июня 2010

Чтобы вычислить абсолютный путь к текущему корневому каталогу 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.

11 голосов
/ 29 июля 2015

На всякий случай, если вы направляете этот путь к самому 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)
10 голосов
/ 09 августа 2016

Короткие решения, которые работают с подмодулями, в хуках и внутри каталога .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)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...