Czy istnieje sposób na uzyskanie katalogu głównego git za pomocą jednego polecenia?

669

Mercurial ma sposób drukowania katalogu głównego (zawierającego .hg) poprzez

hg root

Czy jest coś równoważnego w git, aby uzyskać katalog zawierający katalog .git?

wojo
źródło
Dobry skrypt Emil. Udostępniam skrypt w trybie online i umożliwiłem dodanie pliku / katalogu jako argumentu. github.com/Dieterbe/git-scripts/commit/…
Dieter_be
Również dla każdego, kto był ciekawy lub poszukiwany, bzr rootczęsto korzystano z Bazaru
Kristopher Ives
Proszę zwrócić uwagę na „gcd”: Git-Aware „cd” w odniesieniu do katalogu głównego repozytorium z autouzupełnianiem na jeetworks.org/node/52 .
Micha Wiedenmann
1
@MichaWiedenmann: link nie działa.
d33tah

Odpowiedzi:

1111

Tak:

git rev-parse --show-toplevel

Jeśli chcesz replikować polecenie Git bardziej bezpośrednio, możesz utworzyć alias :

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

i teraz git rootbędzie działać tak samo hg root.


Uwaga : W submodule wyświetli się katalog główny submodułu, a nie repozytorium nadrzędne. Jeśli używasz Git> = 2.13 lub nowszej, istnieje sposób, że podmoduły mogą wyświetlać katalog główny superprojektu. Jeśli twój git jest starszy, zobacz inną odpowiedź.

baudtack
źródło
148
Zawsze definiuję, git config --global alias.exec '!exec 'więc mogę robić takie rzeczy git exec make. Działa to, ponieważ aliasy powłoki są zawsze wykonywane w katalogu najwyższego poziomu.
Daniel Brockman,
8
To właśnie hg rootrobi. Drukuje katalog najwyższego poziomu z pobranego repozytorium. Nie przełącza cię na to (i nie mógł tego zrobić ze względu na interakcję całej koncepcji bieżącego katalogu i powłoki).
Wszechobecny
14
Smal zastrzeżenie z tym rozwiązaniem - będzie śledzić wszelkie dowiązania symboliczne. Tak więc, jeśli jesteś w sieci ~/my.proj/foo/bari ~/my.projjest do niej dowiązanie ~/src/my.proj, powyższe polecenie przeniesie Cię do ~/src/my.proj. Może to stanowić problem, jeśli cokolwiek zechcesz zrobić później, nie jest agnostyczne dla drzewa.
Franci Penov
3
Jak mogę tego użyć z poziomu git hooka? W szczególności wykonuję hak po scaleniu i muszę uzyskać rzeczywisty katalog główny lokalnego repozytorium git.
Derek
12
To rozwiązanie (i wiele innych na tej stronie, które próbowałem) nie działa w haczyku git. Mówiąc ściślej, nie działa, gdy jesteś w katalogu projektu .git.
Dennis,
97

manAktualizacja git-config(pod Alias ) mówi:

Jeśli rozszerzenie aliasu jest poprzedzone wykrzyknikiem, będzie traktowane jak polecenie powłoki. [...] Należy pamiętać, że polecenia powłoki będą wykonywane z katalogu najwyższego poziomu repozytorium, który niekoniecznie musi być bieżącym katalogiem.

W systemie UNIX możesz wykonać:

git config --global --add alias.root '!pwd'
Scott Lindsay
źródło
2
Więc jeśli masz polecenie „git root”, jak możesz umieścić to w aliasie? Jeśli wstawię to do siebie .zshrci zdefiniuję `alias cg =" cd $ (git root) ", część $ () zostanie oceniona w czasie źródłowym i zawsze wskazuje na ~ / dotfiles, ponieważ tam jest mój zshrc .
zelk
2
@cormacrelf Nie umieszczasz go w aliasie powłoki. Możesz umieścić go w funkcji powłoki lub skrypcie.
Conrad Meyer,
4
@cormacrelf Umieść go w pojedynczych cudzysłowach zamiast w podwójnych cudzysłowach, wtedy nie zostanie rozwinięty w czasie definicji, ale w czasie wykonywania.
clacke
3
@Mechanicalsnail Really? Czego więc oczekujesz, że zrobi to poza repozytorium?
Alois Mahdal
1
@AloisMahdal faktycznie dla mnie nie zawiedzie poza repozytorium, po prostu zgłasza cwd.
justinpitts
90

Został --show-topleveldopiero niedawno został dodany do git rev-parselub dlaczego nikt go wymienić?

Ze strony podręcznika git rev-parse:

   --show-toplevel
       Show the absolute path of the top-level directory.
marc.guenther
źródło
1
Dzięki za zwrócenie na to uwagi; bez twojej pomocy trudno byłoby mi zgadnąć git-rev-parse- bo jego nazwa sugeruje, że chodzi o przetwarzanie specyfikacji wersji. BTW, z przyjemnością zobaczę git --work-treepracę podobną do git --exec-path[=<path>]: „Jeśli nie podano ścieżki, git wydrukuje bieżące ustawienie”; przynajmniej IMO byłoby logicznym miejscem, aby poszukać takiej funkcji.
imz - Ivan Zakharyaschev,
4
W szczególności możesz root = rev-parse --show-toplevelużywać aliasu w swoim gitconfig.
Ślimak mechaniczny
2
innymi słowy, możesz to zrobić, git config --global alias.root "rev-parse --show-toplevel"a wtedy git rootbędziesz w stanie wykonać pracę
nonpolarity
@RyanTheLeach git rev-parse --show-topleveldziała, gdy próbowałem go w submodule. Wyświetla katalog główny submodułu git. Co to dla ciebie drukuje?
wisbucky,
2
Byłem zdezorientowany, dlaczego ta odpowiedź powiela odpowiedź najwyższą. Okazuje się, że najlepsza odpowiedź została edytowana od --show-cdupdo --show-top-levelw lutym 2011 r. (Po przesłaniu tej odpowiedzi).
wisbucky,
54

Co powiesz na „ git rev-parse --git-dir”?

F:\prog\git\test\copyMerge\dirWithConflicts>git rev-parse --git-dir
F:/prog/git/test/copyMerge/.git

The --git-dir opcja wydaje się działać.

Na stronie podręcznika git rev-parse :

--git-dir

    Show $GIT_DIR if defined else show the path to the .git directory.

Możesz zobaczyć to w akcji w tym git setup-shskrypcie .

Jeśli jesteś w folderze submodułowym, z Git> = 2.13 , użyj :

git rev-parse --show-superproject-working-tree

Jeśli używasz git rev-parse --show-toplevel, upewnij się, że używasz Git 2.25+ (Q1 2020) .

VonC
źródło
3
Och, czekaj, to było blisko, ale dostaje rzeczywisty katalog .git, a nie podstawę repozytorium git. Ponadto katalog .git może być gdzie indziej, więc nie tego dokładnie szukałem.
wojo
2
Racja, widzę teraz to, czego tak naprawdę szukałeś. --show-cdup jest wtedy bardziej odpowiednie. Zostawiam swoją odpowiedź za zilustrowanie różnicy między tymi dwiema opcjami.
VCC
2
Wydaje się również, że to polecenie podaje ścieżkę względną, .gitjeśli jesteś już w katalogu głównym. (Przynajmniej działa na msysgit.)
Blair Holloway
2
+1, to jedyna odpowiedź, która odpowiada na pierwotne pytanie „uzyskać katalog zawierający katalog .git?”, Zabawne, że OP wspomina „katalog .git może być gdzie indziej”.
FabienAndre
1
Jest to jedyne rozwiązanie, które działa w systemie Windows AND daje wynik analizowalny podczas korzystania z submodułów git (np. C: \ repositories \ myrepo \ .git \ modules \ mysubmodule). To sprawia, że ​​jest to najbardziej niezawodne rozwiązanie, zwłaszcza w skrypcie wielokrotnego użytku.
chriskelly,
36

Aby napisać prostą odpowiedź tutaj, abyśmy mogli skorzystać

git root

aby wykonać zadanie, po prostu skonfiguruj swojego gita za pomocą

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

a następnie możesz dodać następujące elementy do ~/.bashrc:

alias cdroot='cd $(git root)'

dzięki czemu możesz po prostu cdrootprzejść na sam szczyt repozytorium.

niepolarność
źródło
Bardzo dobrze! Ostatecznie wygodne!
scravy
Świetna odpowiedź, dziękuję!
AVarf
26

Jeśli jesteś już na najwyższym poziomie lub nie jesteś w repozytorium git cd $(git rev-parse --show-cdup), zabierze Cię do domu (tylko cd). cd ./$(git rev-parse --show-cdup)jest jednym ze sposobów naprawienia tego.

Karl
źródło
7
Inną opcją jest go zacytować: cd "$(git rev-parse --show-cdup)". To działa, ponieważ cd ""zabiera cię nigdzie, a nie z powrotem $HOME. A i tak najlepszą praktyką jest cytowanie wywołań $ (), na wypadek, gdyby wypisały coś ze spacjami (ale nie w tym przypadku to polecenie).
ctrueden
Ta odpowiedź działa dobrze, nawet jeśli zmieniłeś katalog na repozytorium git za pomocą dowiązania symbolicznego . Niektóre inne przykłady nie działają zgodnie z oczekiwaniami, gdy repozytorium git znajduje się pod dowiązaniem symbolicznym, ponieważ nie rozwiązują katalogu głównego git względem bash $PWD. Ten przykład będzie git rozwiązać w stosunku do głównego $PWDzamiast realpath $PWD.
Damien Ó Ceallaigh,
16

Aby obliczyć bezwzględną ścieżkę bieżącego katalogu głównego git, powiedzmy do użycia w skrypcie powłoki, użyj tej kombinacji readlink i git rev-pars:

gitroot=$(readlink -f ./$(git rev-parse --show-cdup))

git-rev-parse --show-cdupdaje odpowiednią liczbę „..”, aby dostać się do katalogu głównego z cwd lub pusty ciąg znaków, jeśli jesteś w katalogu głównym. Następnie dodaj „./”, aby zająć się pustą wielkością ciągu, i użyj readlink -fdo przetłumaczenia na pełną ścieżkę.

Możesz również utworzyć git-rootpolecenie w PATH jako skrypt powłoki, aby zastosować tę technikę:

cat > ~/bin/git-root << EOF
#!/bin/sh -e
cdup=$(git rev-parse --show-cdup)
exec readlink -f ./$cdup
EOF
chmod 755 ~/bin/git-root

(Powyższe można wkleić do terminala, aby utworzyć git-root i ustawić bity wykonania; rzeczywisty skrypt znajduje się w wierszach 2, 3 i 4).

I wtedy będziesz w stanie biec git root aby uzyskać katalog główny bieżącego drzewa. Zauważ, że w skrypcie powłoki użyj „-e”, aby spowodować zamknięcie powłoki, jeśli rev-pars nie powiedzie się, abyś mógł poprawnie uzyskać status wyjścia i komunikat o błędzie, jeśli nie jesteś w katalogu git.

Emil Sit
źródło
2
Twoje przykłady się zepsują, jeśli ścieżka katalogu głównego „git” zawiera spacje. Zawsze używaj "$(git rev-parse ...)"zamiast hacków takich jak ./$(git rev-parse ...).
Mikko Rantalainen
readlink -fnie działa tak samo na BSD. Zobacz to SO dla obejść. Python odpowiedź prawdopodobnie będzie działać bez instalowania czegokolwiek: python -c 'import os, sys; print(os.path.realpath(sys.argv[1]))' "$(git rev-parse --show-cdup)".
Bluu
16

Jak zauważyli inni, sednem rozwiązania jest użycie git rev-parse --show-cdup. Istnieje jednak kilka skrajnych przypadków do rozwiązania:

  1. Gdy cwd jest już korzeniem działającego drzewa, polecenie zwraca pusty ciąg.
    W rzeczywistości tworzy pustą linię, ale podstawienie polecenia usuwa przerwanie linii końcowej. Ostatecznym wynikiem jest pusty ciąg.

    Większość odpowiedzi sugeruje wcześniejsze przygotowanie wyjścia ./tak, aby puste wyjście stało się "./"nim cd.

  2. Gdy GIT_WORK_TREE jest ustawiony na lokalizację, która nie jest rodzicem cwd, wyjściem może być bezwzględna nazwa ścieżki.

    Poprzedzenie ./jest źle w tej sytuacji. Jeśli a ./jest poprzedzone ścieżką bezwzględną, staje się ścieżką względną (i odnoszą się tylko do tej samej lokalizacji, jeśli cwd jest katalogiem głównym systemu).

  3. Dane wyjściowe mogą zawierać białe znaki.

    To naprawdę ma zastosowanie tylko w drugim przypadku, ale ma łatwą poprawkę: użyj podwójnych cudzysłowów wokół podstawiania poleceń (i wszelkich późniejszych zastosowań wartości).

Jak zauważyły ​​inne odpowiedzi, możemy to zrobić cd "./$(git rev-parse --show-cdup)", ale łamie się to w przypadku drugiej krawędzi (i przypadku trzeciej krawędzi, jeśli pominiemy podwójne cudzysłowy).

Wiele powłok traktuje się cd ""jako brak cd "$(git rev-parse --show-cdup)"operacji , więc w przypadku tych powłok możemy to zrobić (podwójne cudzysłowy chronią pusty ciąg znaków jako argument w przypadku pierwszej krawędzi i zachowują białe znaki w przypadku trzeciej krawędzi). POSIX twierdzi, że wynik cd ""jest nieokreślony, więc najlepiej jest unikać tego założenia.

Rozwiązanie, które działa we wszystkich powyższych przypadkach, wymaga pewnego rodzaju testu. Sporządzono jawnie, może to wyglądać następująco:

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

W cdprzypadku pierwszej krawędzi nie jest wykonywane żadne działanie.

Jeśli dopuszczalne jest uruchamianie cd .dla pierwszego przypadku krawędzi, wówczas warunek można wykonać w rozszerzeniu parametru:

cdup="$(git rev-parse --show-cdup)" && cd "${cdup:-.}"
Chris Johnsen
źródło
Dlaczego nie użyjesz po prostu „git config --global --add alias.root '! Pwd'” i aliasu powłoki gitroot = 'cd git root', którego używa powyższa odpowiedź?
Jason Axelson
1
Użycie aliasu może nie być możliwe, np. Jeśli chcesz go napisać w skrypcie i nie możesz polegać na niestandardowym aliasie.
niebieskawy
1
Moduły podrzędne to kolejny przypadek narożny.
Ryan The Leach
14

Na wszelki wypadek, jeśli podajesz tę ścieżkę do samego Gita, użyj :/

# 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)
Nick Volynkin
źródło
12

Krótkie rozwiązania, które działają z podmodułami, hakami i wewnątrz .gitkatalogu

Oto krótka odpowiedź, której większość będzie chciała:

r=$(git rev-parse --git-dir) && r=$(cd "$r" && pwd)/ && echo "${r%%/.git/*}"

Będzie to działać w dowolnym miejscu drzewa roboczego git (w tym w .gitkatalogu), ale zakłada, że ​​katalog (y) repozytorium są nazywane.git (co jest domyślne). W przypadku podmodułów nastąpi przejście do katalogu głównego najbardziej zewnętrznego repozytorium.

Jeśli chcesz dostać się do katalogu głównego bieżącego submodułu użyj:

echo $(r=$(git rev-parse --show-toplevel) && ([[ -n $r ]] && echo "$r" || (cd $(git rev-parse --git-dir)/.. && pwd) ))

Aby łatwo wykonać polecenie w katalogu głównym podmodułu, [alias]w swoim .gitconfig, dodaj:

sh = "!f() { root=$(pwd)/ && cd ${root%%/.git/*} && git rev-parse && exec \"$@\"; }; f"

To pozwala łatwo robić takie rzeczy jak git sh ag <string>

Solidne rozwiązanie, które obsługuje różne nazwy lub zewnętrzne .gitlub$GIT_DIR katalogi .

Zauważ, że $GIT_DIRmoże wskazywać gdzieś na zewnątrz (i nie można go nazwać.git ), stąd potrzeba dalszego sprawdzania.

Umieść to w .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 1  # git_root will print any errors
  cd "$root"
}

Wykonać go przez pisanie git_root(po ponownym uruchomieniu powłoki: exec bash)

Tom Hale
źródło
Ten kod jest sprawdzany pod kątem funkcji Solid bash, aby znaleźć katalog główny repozytorium git . Szukaj tam aktualizacji.
Tom Hale,
Miły. Bardziej skomplikowane niż to, co zaproponowałem 7 lat temu ( stackoverflow.com/a/958125/6309 ), ale nadal +1
VonC
1
Krótsze rozwiązanie według tych zasad jest następujące: (root=$(git rev-parse --git-dir)/ && cd ${root%%/.git/*} && git rev-parse && pwd)ale nie obejmuje to zewnętrznych $GIT_DIRnazw, które są inne niż.git
Tom Hale
Zastanawiam się, czy to bierze pod uwagę wiele drzew roboczych, które są teraz możliwe w git 2.5+ ( stackoverflow.com/a/30185564/6309 )
VonC
Twój link do komentarza do „Solidnej funkcji bash, aby znaleźć root” ... daje teraz 404.
ErikE
8

Aby nieco zmienić „git config”, odpowiedz:

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

i wyczyść ścieżkę. Bardzo dobrze.

Bruce K.
źródło
7

Jeśli szukasz dobrego aliasu, aby to zrobić, a także nie wysadzić w powietrze, cdjeśli nie jesteś w gitarze, reż:

alias ..g='git rev-parse && cd "$(git rev-parse --show-cdup)"'
Dan Heberden
źródło
6

Ten alias powłoki działa niezależnie od tego, czy znajdujesz się w podkatalogu git, czy na najwyższym poziomie:

alias gr='[ ! -z `git rev-parse --show-toplevel` ] && cd `git rev-parse --show-toplevel || pwd`'

zaktualizowano, aby używało nowoczesnej składni zamiast backticks:

alias gr='[ ! -z $(git rev-parse --show-toplevel) ] && cd $(git rev-parse --show-toplevel || pwd)'
MERM
źródło
5
alias git-root='cd \`git rev-parse --git-dir\`; cd ..'

Wszystko inne zawodzi w pewnym momencie albo idzie do katalogu domowego, albo po prostu zawodzi. To najszybszy i najkrótszy sposób powrotu do GIT_DIR.

tocororo
źródło
Wygląda na to, że „git rev-parse - git-dir” jest najczystszym rozwiązaniem.
Stabledog
3
To się nie udaje, gdy $GIT_DIRzostanie odłączony od .gitdrzewa roboczego za pomocą opcji -Files i gitdir: SOMEPATH. W konsekwencji nie powiedzie się to również w przypadku podmodułów, w których $GIT_DIRzawiera .git/modules/SUBMODULEPATH.
Tino
5

Oto skrypt, który napisałem, który obsługuje oba przypadki: 1) repozytorium z obszarem roboczym, 2) samo repozytorium.

https://gist.github.com/jdsumsion/6282953

git-root (plik wykonywalny na twojej ścieżce):

#!/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
)

Mam nadzieję, że jest to pomocne.

jdsumsion
źródło
1
Keith, dziękuję za sugestię, załączyłem scenariusz.
jdsumsion
Właściwie poparłem najlepszą odpowiedź, ponieważ zdałem sobie sprawę, że git execpomysł jest bardziej pomocny w repozytoriach innych niż nagie. Jednak ten skrypt w mojej odpowiedzi poprawnie obsługuje przypadek nagi i nie nagi, co może być przydatne dla kogoś, więc zostawiam tę odpowiedź tutaj.
jdsumsion
1
Jednak to zawiedzie w ciągu git submodules, gdzie $GIT_DIRzawiera coś takiego /.git/modules/SUBMODULE. .gitZakładasz również, że katalog jest częścią drzewa roboczego w przypadku, w którym nie jest nagi.
Tino
4
$ git config alias.root '!pwd'
# then you have:
$ git root
FractalSpace
źródło
Ten alias zawiedzie jako globalny. Zamiast tego użyj tego (w ~ / .gitconfig): [alias] findroot = "!f () { [[ -d ".git" ]] && echo "Found git in [pwd ]" && exit 0; cd .. && echo "IN pwd" && f;}; f"
FractalSpace
dlaczego głosować? Zamiast tego zaznacz błąd lub zasugeruj ulepszenie.
FractalSpace
1
Dla mnie git config --global alias.root '!pwd'działa. Nie byłem w stanie zauważyć żadnego przypadku, w którym działałby inaczej niż wariant nieglobalny. (Unix, git 1.7.10.4) BTW: Twój findrootwymaga /.git, aby uniknąć nieskończonej rekurencji.
Tino
4

Od wersji 2.13.0 Git obsługuje nową opcję wyświetlania ścieżki projektu głównego, która działa nawet wtedy, gdy jest używana z wnętrza submodułu:

git rev-parse --show-superproject-working-tree
Jordi Vilalta Prat
źródło
git-scm.com/docs/… . Ciekawy. Musiałem tego przegapić. +1
VonC
3
Ostrzeżenie jednak: „Nic nie wyświetla, jeśli bieżące repozytorium nie jest używane jako podmoduł w żadnym projekcie.”
VCC
Dziękuję za komentarz! Nie zauważyłem tego.
Jordi Vilalta Prat
2

Wstępnie skonfigurowane aliasy powłoki w środowisku szkieletowym

Jeśli używasz szkieletu powłoki, może być już dostępny alias powłoki:

  • $ grtw oh-my-zsh (68k) ( cd $(git rev-parse --show-toplevel || echo "."))
  • $ git-rootin prezto (8.8k) (wyświetla ścieżkę do działającego katalogu głównego drzewa)
  • $ g.. zimfw (1k) (zmienia bieżący katalog na najwyższy poziom działającego drzewa).
Hotschke
źródło
1

Chciałem rozwinąć doskonały komentarz Daniela Brockmana.

Definiowanie git config --global alias.exec '!exec 'pozwala robić takie rzeczy, git exec makeponieważ, jak man git-configstwierdza:

Jeśli rozszerzenie aliasu jest poprzedzone wykrzyknikiem, będzie traktowane jak polecenie powłoki. [...] Należy pamiętać, że polecenia powłoki będą wykonywane z katalogu najwyższego poziomu repozytorium, który niekoniecznie musi być bieżącym katalogiem.

Warto również wiedzieć, że $GIT_PREFIXbędzie to ścieżka do bieżącego katalogu względem katalogu najwyższego poziomu repozytorium. Ale wiedząc, że to tylko połowa sukcesu ™. Zmienna ekspansja powłoki sprawia, że ​​jest raczej trudny w użyciu. Sugeruję bash -cwięc użycie w ten sposób:

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

inne polecenia obejmują:

git exec pwd
git exec make
Bruno Bronosky
źródło
1

W przypadku, gdy ktoś potrzebuje tego sposobu zgodnego z POSIX, bez potrzeby gitwykonywania pliku wykonywalnego:

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

Jeśli chcesz tylko funkcjonalność jako część skryptu, usuń shebang i zastąp ostatni git_root_recurse_parentwiersz:

git_root() {
    (git_root_recurse_parent)
}
swalog
źródło
Uwaga: jeśli NIE zostanie to wywołane w repozytorium git, rekursja w ogóle się nie kończy.
AH
@AH Druga ifinstrukcja miała sprawdzić, czy zmieniłeś katalog w rekursji. Jeśli pozostaje w tym samym katalogu, zakłada, że ​​utknąłeś gdzieś (np. /) I hamuje rekurencję. Błąd został naprawiony i powinien działać zgodnie z oczekiwaniami. Dzięki za zwrócenie na to uwagi.
swalog
0

Sam musiałem to dziś rozwiązać. Rozwiązałem go w języku C #, ponieważ potrzebowałem go do programu, ale myślę, że można go w zasadzie przepisać. Rozważ tę domenę publiczną.

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;

}
Hylke Bons
źródło