it-roy-ru.com

Есть ли способ получить корневой каталог git в одной команде?

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

hg root

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

542
wojo

Да:

git rev-parse --show-toplevel

Примечание : В субмодуле будет отображаться корневой каталог субмодуля, а не родительский репозиторий.

894
baudtack

На странице man для git-config (под Alias ​​) написано:

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

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

git config --global --add alias.root '!pwd'
90
Scott Lindsay

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

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

   --show-toplevel
       Show the absolute path of the top-level directory.
86
marc.guenther

Как насчет "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
38
VonC

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

git root

чтобы сделать работу, просто настройте свой мерзавец с помощью

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

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

alias cdroot='cd $(git root)'

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

27
太極者無極而生

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

25
Karl

Чтобы вычислить абсолютный путь к текущему корневому каталогу 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 используйте «-e», чтобы вызвать завершение работы командной консоли в случае сбоя rev-parse, чтобы вы могли правильно получить статус выхода и сообщение об ошибке, если вы не находитесь в каталоге git.

16
Emil Sit

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

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

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

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

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

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

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

Как уже отмечалось в других ответах, мы можем выполнить cd "./$(git rev-parse --show-cdup)", но это нарушается во втором случае Edge (и в третьем случае Edge, если мы исключим двойные кавычки).

Многие оболочки рассматривают cd "" как неиспользуемые, поэтому для этих оболочек мы можем сделать cd "$(git rev-parse --show-cdup)" (двойные кавычки защищают пустую строку в качестве аргумента в первом случае Edge и сохраняют пробелы в третьем случае Edge). POSIX говорит, что результат cd "" не указан, поэтому лучше не делать этого предположения.

Решение, которое работает во всех вышеперечисленных случаях, требует некоторого теста. Сделано явно, это может выглядеть так:

cdup="$(git rev-parse --show-cdup)" && test -n "$cdup" && cd "$cdup"

Нет cd для первого случая Edge.

Если допустимо запускать cd . для первого случая Edge, то условное выражение может быть выполнено в расширении параметра:

cdup="$(git rev-parse --show-cdup)" && cd "${cdup:-.}"
16
Chris Johnsen

На всякий случай, если вы указываете этот путь к самому 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)
11
Nick Volynkin

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

10
Tom Hale

Чтобы немного изменить ответ «git config»:

git config --global --add alias.root '!pwd -P'

и очистить путь. Очень хорошо.

8
Bruce K

Если вы ищете хороший псевдоним для этого, а не взрывайте cd, если вы не в git dir:

alias ..g='git rev-parse && cd "$(git rev-parse --show-cdup)"'
7
Dan Heberden

Этот псевдоним оболочки работает независимо от того, находитесь ли вы в подкаталоге 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)'
6
MERM

Вот сценарий, который я написал, который обрабатывает оба случая: 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
)

Надеюсь, это полезно.

5
jdsumsion

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

5
Hotschke
alias git-root='cd \`git rev-parse --git-dir\`; cd ..'

Все остальное терпит неудачу в некоторый момент или идет в домашний каталог или просто терпит неудачу. Это самый быстрый и короткий способ вернуться к GIT_DIR.

5
tocororo
$ git config alias.root '!pwd'
# then you have:
$ git root
4
FractalSpace

Так как Git 2.13.0 , он поддерживает новую опцию для отображения пути корневого проекта, которая работает даже при использовании изнутри подмодуля:

git rev-parse --show-superproject-working-tree
3
Jordi Vilalta Prat

Пришлось решить это самому сегодня. Решил это в 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;

}
1
Hylke Bons

На случай, если кому-то понадобится POSIX-совместимый способ сделать это без использования исполняемого файла git:

git-root :

#$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)
}
1
swalog

Предварительно настроенные псевдонимы оболочки в оболочках оболочки

Если вы используете оболочку оболочки, возможно, уже существует псевдоним оболочки:

  • $ grt in oh-my-zsh (68k) (cd $(git rev-parse --show-toplevel || echo "."))
  • $ git-root in prezto (8.8k) (отображает путь к корню рабочего дерева)
  • $ g..zimfw (1k) (изменяет текущий каталог на верхний уровень рабочего дерева.)
1
Hotschke

Я хотел бы остановиться на превосходном комментарии Дэниела Брокмана.

Определение git config --global alias.exec '!exec ' позволяет вам делать такие вещи, как git exec make, потому что, как man git-config заявляет:

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

Также удобно знать, что $GIT_PREFIX будет путем к текущему каталогу относительно каталога верхнего уровня хранилища. Но, зная, что это только полдела ™. Расширение переменной оболочки делает его довольно сложным в использовании. Поэтому я предлагаю использовать bash -c примерно так:

git exec bash -c 'ls -l $GIT_PREFIX'

другие команды включают в себя:

git exec pwd
git exec make
0
Bruno Bronosky