Existe uma maneira de obter o diretório raiz do git em um comando?
a Mercurial tem uma forma de imprimir o directório raiz (que contém .HG) via
hg root
Existe algo equivalente no git para obter o diretório que contém o .directório git?
21 answers
Sim:
git rev-parse --show-toplevel
A página man
Para git-config
(Sob Também conhecido por ) diz:
Se a expansão da alcunha for precedida de um ponto de exclamação, será tratada como uma concha comando. Por exemplo, definir "alias".new = !gitk -- all -- not ORIG_HEAD", a invocação "git new "é equivalente a executar o comando shell "gitk -- all --not ORIG_HEAD". Note que a consola os comandos serão executados a partir do directório de topo de um repositório, o qual poderá não ser necessariamente a corrente Directorio.
Então, no UNIX você pode fazer:
git config --global --add alias.root '!pwd'
Só recentemente foi adicionado a git rev-parse
ou porque é que ninguém o menciona?
Da página do homem:
--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
A opção --git-dir
parece funcionar.
From git rev-parse manual page:
--git-dir
Show $GIT_DIR if defined else show the path to the .git directory.
Você pode vê-lo em ação neste git setup-sh
script .
Se já estiver no nível superior ou não num repositório git {[[0]} irá levá-lo para casa (apenas cd). cd ./$(git rev-parse --show-cdup)
é uma maneira de resolver isso.
Para escrever uma resposta simples aqui, para que possamos usar
git root
Para fazer o trabalho, basta configurar o seu git usando
git config --global alias.root "rev-parse --show-toplevel"
E então você pode querer adicionar o seguinte ao seu ~/.bashrc
:
alias cdroot='cd $(git root)'
De modo que você pode apenas usar cdroot
para ir para o topo do seu repo.
Para calcular a localização absoluta da pasta de raiz do git actual, por exemplo, para usar num programa de consola, use esta combinação de readlink e git rev-parse:
gitroot=$(readlink -f ./$(git rev-parse --show-cdup))
git-rev-parse --show-cdup
dá-lhe o número certo de".."s para obter
para a raiz de seu cwd, ou a cadeia vazia se você estiver na raiz.
Então prepara "./ "para lidar com a caixa de texto vazia e usar
readlink -f
traduzir para um caminho completo.
Você também pode criar um comando git-root
no seu caminho como um script de shell para aplicar isto técnica:
cat > ~/bin/git-root << EOF
#!/bin/sh -e
cdup=$(git rev-parse --show-cdup)
exec readlink -f ./$cdup
EOF
chmod 755 ~/bin/git-root
(o texto acima pode ser colado num terminal para criar git-root e definir bits de execução; o programa actual está nas linhas 2, 3 e 4.)
E depois serias capaz de correr para obter a raiz da tua árvore actual. Note que no script shell, use "-e" para fazer com que a shell saia se o rev-parse falhar de modo que você possa obter corretamente o estado de saída e mensagem de erro se você não estiver em um diretório git.Como outros observaram, o núcleo da solução é usar git rev-parse --show-cdup
. No entanto, existem alguns casos extremos para resolver:
-
Quando o cwd já é a raiz da árvore de trabalho, o comando produz uma cadeia vazia.
na verdade, produz uma linha vazia, mas a substituição de comandos sai da quebra da linha de fuga. O resultado final é um texto vazio.A maioria das respostas sugere que se prepare o resultado com
./
para que um resultado vazio se torne"./"
antes de ser alimentado acd
. -
Quando o GIT_WORK_TREE está definido para um local que não é o pai da cwd, o resultado pode ser um nome de caminho absoluto.
A pré-venda
./
está errada nesta situação. Se um./
é pré-adicionado a um caminho absoluto, ele se torna um caminho relativo (e eles só se referem ao mesmo local se o cwd é o diretório raiz do sistema). -
A saída pode conter espaços em branco.
Isto só se aplica em o segundo caso, mas tem uma correção fácil: use aspas duplas em torno da substituição de comandos (e quaisquer usos subsequentes do valor).
Como outras respostas observaram, podemos fazer {[[8]}, mas isto quebra no segundo caso edge (e o terceiro caso edge se deixarmos as aspas duplas).
Muitas conchas tratam cd ""
como um no-op, de modo que para essas conchas nós poderíamos fazer cd "$(git rev-parse --show-cdup)"
(as aspas duplas protegem o texto vazio como um argumento no primeiro caso edge, e preservam espaços em branco in the third edge case). POSIX diz que o resultado de cd ""
é indeterminado, então pode ser melhor evitar fazer esta suposição.
Uma solução que funcione em todos os casos acima requer um teste de algum tipo. Feito explicitamente, pode parecer assim:
cdup="$(git rev-parse --show-cdup)" && test -n "$cdup" && cd "$cdup"
Não cd
está pronto para a primeira caixa.
Se for aceitável executar cd .
para o primeiro caso de aresta, então o condicional pode ser feito na expansão do parâmetro:
cdup="$(git rev-parse --show-cdup)" && cd "${cdup:-.}"
Soluções curtas que funcionam com submódulos, ganchos e dentro da pasta .git
r=$(git rev-parse --git-dir) && r=$(cd "$r" && pwd)/ && echo "${r%%/.git/*}"
Isto irá funcionar em qualquer parte de uma árvore de trabalho git( incluindo dentro do directório .git
), mas assume que o(s) directório (s) do repositório (s) são chamados .git
(que é o padrão). Com submódulos, isso vai para a raiz do repositório externo contendo.
Se queres chegar à raiz da corrente utilização do submódulo:
echo $(r=$(git rev-parse --show-toplevel) && ([[ -n $r ]] && echo "$r" || (cd $(git rev-parse --git-dir)/.. && pwd) ))
Para executar facilmente um comando na sua raiz submódula, em [alias]
no seu .gitconfig
, adicionar:
sh = "!f() { root=$(pwd)/ && cd ${root%%/.git/*} && git rev-parse && exec \"$@\"; }; f"
Isto permite-lhe fazer coisas como:git sh ag <string>
Solução robusta que suporta pastas com nomes diferentes ou externas .git
ou $GIT_DIR
.
Note que $GIT_DIR
pode apontar para algum lugar externo( e não ser chamado .git
), daí a necessidade de mais verificações.
.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"
}
Execute-o por dactilografia git_root
(após reiniciar a sua casca: exec bash
)
Só para o caso de estares a dar este caminho ao próprio Git, usa :/
# 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)
Para alterar a resposta" git config " apenas um pouco:
git config --global --add alias.root '!pwd -P'
E limpa o caminho. Bom.
Se está à procura de um bom pseudónimo para fazer isto e não explodir cd
Se não está num git dir:
alias ..g='git rev-parse && cd "$(git rev-parse --show-cdup)"'
Esta alcunha da shell funciona quer esteja numa sub-pasta git, quer no nível superior:
alias gr='[ ! -z `git rev-parse --show-toplevel` ] && cd `git rev-parse --show-toplevel || pwd`'
Actualizado para usar a sintaxe moderna em vez de retoques:
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 ..'
{[[2]} tudo o resto falha em algum momento, seja indo para o diretório home ou simplesmente falhando miseravelmente. Este é o caminho mais rápido e mais curto para voltar ao GIT_DIR.
Aqui está um script que eu escrevi que lida com ambos os casos: 1) repositório com um espaço de trabalho, 2) repositório bare.
Https://gist.github.com/jdsumsion/6282953
git-root
(ficheiro executável na sua localização):
#!/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
)
Espero que isto seja útil.
git-extras
Adiciona $ git root
ver 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
Disponibilidade de git-extras
- homebrew (osx)/linuxbrew (linux)
$ brew install git-extras
- Repos debian / ubuntu (https://packages.debian.org/sid/git-extras)
$ apt-get install git-extras
$ git config alias.root '!pwd'
# then you have:
$ git root
Desde O Git 2. 13. 0 , suporta uma nova opção para mostrar a localização do projecto root, que funciona mesmo quando é usado dentro de um submódulo:
git rev-parse --show-superproject-working-tree
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;
}
Alcunhas de consola pré-configuradas em Frameworks
Se utilizar um shell framework, poderá já existir um shell alias disponível:
-
$ grt
in oh-my-zsh (68k) (cd $(git rev-parse --show-toplevel || echo ".")
) -
$ git-root
in prezto (8, 8 k) (mostra o caminho para a raiz da árvore de trabalho) -
$ g..
zimfw (1k) (muda a pasta actual para o nível superior da árvore de trabalho.)
No caso de alguém precisar de uma forma compatível com POSIX de fazer isto, sem precisar de git
executável:
#!/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