it-swarm.com.de

Gibt es eine Möglichkeit, das git-Stammverzeichnis in einem Befehl zu erhalten?

Mercurial kann das Stammverzeichnis (das .hg enthält) über drucken

hg root

Gibt es in git etwas Entsprechendes, um das Verzeichnis zu erhalten, das das .git-Verzeichnis enthält?

542
wojo

Ja:

git rev-parse --show-toplevel

Hinweis : In einem Submodul wird das Stammverzeichnis des Submoduls und nicht das übergeordnete Repository angezeigt.

894
baudtack

Die man-Seite für git-config (unter Alias ​​) sagt:

Wenn der Alias-Erweiterung ein Ausrufezeichen vorangestellt ist, wird sie als Shell .__ behandelt. Befehl. [...] Beachten Sie, dass Shell Befehle werden aus dem Verzeichnis der obersten Ebene eines Repositorys ausgeführt. unbedingt das aktuelle Verzeichnis sein.

Unter UNIX können Sie also Folgendes tun:

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

Wurde --show-toplevel erst kürzlich zu git rev-parse hinzugefügt oder warum erwähnt es niemand?

Auf der git rev-parse-Manpage:

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

Wie wäre es mit "git rev-parse --git-dir"?

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

Die --git-dir-Option scheint zu funktionieren.

Von git rev-parse Handbuchseite :

--git-dir

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

Sie können es in Aktion in diesem git setup-sh-Skript sehen.

Wenn Sie sich in einem Submodul-Ordner mit Git 2.20 befinden, verwenden Sie :

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

Schreiben Sie hier eine einfache Antwort, damit wir sie verwenden können

git root

konfigurieren Sie dazu einfach Ihren Git

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

und dann möchten Sie vielleicht Folgendes zu Ihrem ~/.bashrc hinzufügen:

alias cdroot='cd $(git root)'

so können Sie einfach cdroot verwenden, um zur Spitze Ihres Repos zu gelangen.

27

Wenn Sie bereits in der obersten Ebene sind oder sich nicht in einem Git-Repository befinden, führt cd $(git rev-parse --show-cdup) Sie nach Hause (nur cd). cd ./$(git rev-parse --show-cdup) ist eine Möglichkeit, dies zu beheben.

25
Karl

Verwenden Sie diese Kombination aus readlink und git rev-parse, um den absoluten Pfad des aktuellen git-Stammverzeichnisses beispielsweise für die Verwendung in einem Shell-Skript zu berechnen:

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

git-rev-parse --show-cdup gibt Ihnen die richtige Anzahl von ".." s für das Stammverzeichnis von cwd an die Wurzel oder die leere Zeichenfolge, wenn Sie sich in der Wurzel befinden case und verwende readlink -f, um einen vollständigen Pfad zu erstellen.

Sie können auch einen git-root-Befehl in Ihrem PATH als Shell-Skript erstellen, um diese Technik anzuwenden:

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

(Das Obige kann in ein Terminal eingefügt werden, um git-root zu erstellen und Ausführungsbits zu setzen; das eigentliche Skript befindet sich in den Zeilen 2, 3 und 4.)

Und dann könnten Sie git root ausführen, um den Stamm Ihres aktuellen Baums zu erhalten. Beachten Sie, dass im Shell-Skript "-e" verwendet wird, um die Shell zu beenden, wenn die Rev-Analyse fehlschlägt, so dass Sie es können Erhalten Sie den Exit-Status und die Fehlermeldung, wenn Sie sich nicht in einem Git-Verzeichnis befinden.

16
Emil Sit

Wie bereits erwähnt, besteht der Kern der Lösung in der Verwendung von git rev-parse --show-cdup. Es gibt jedoch einige Edge-Fälle, die es zu behandeln gilt:

  1. Wenn cwd bereits die Wurzel des Arbeitsbaums ist, ergibt der Befehl eine leere Zeichenfolge.
    Tatsächlich wird eine leere Zeile erzeugt, aber der Befehlssubstrat entfernt den Zeilenumbruch. Das Endergebnis ist eine leere Zeichenfolge.

    Die meisten Antworten schlagen vor, die Ausgabe mit ./ zu beginnen, sodass eine leere Ausgabe "./" wird, bevor sie an cd übergeben wird.

  2. Wenn GIT_WORK_TREE auf einen Speicherort gesetzt ist, der nicht das übergeordnete Element von cwd ist, kann die Ausgabe ein absoluter Pfadname sein.

    Das Voranstellen von ./ ist in dieser Situation falsch. Wenn ein ./ einem absoluten Pfad vorangestellt wird, wird dieser zu einem relativen Pfad (und sie beziehen sich nur auf denselben Speicherort, wenn cwd das Stammverzeichnis des Systems ist).

  3. Die Ausgabe kann Whitespace enthalten.

    Dies trifft wirklich nur im zweiten Fall zu, hat aber eine einfache Lösung: Verwenden Sie doppelte Anführungszeichen um die Befehlsersetzung (und alle nachfolgenden Verwendungen des Werts).

Wie andere Antworten bereits festgestellt haben, können wir cd "./$(git rev-parse --show-cdup)" tun, aber dies bricht im zweiten Edge-Fall (und im dritten Edge-Fall, wenn wir die Anführungszeichen weglassen).

Viele Shells behandeln cd "" als No-Op. Für diese Shells könnten wir cd "$(git rev-parse --show-cdup)" ausführen (die doppelten Anführungszeichen schützen den leeren String als Argument im ersten Edge-Fall und erhalten Leerzeichen im dritten Edge-Fall). POSIX sagt, dass das Ergebnis von cd "" nicht spezifiziert ist. Es empfiehlt sich daher, diese Annahme zu vermeiden.

Eine Lösung, die in allen oben genannten Fällen funktioniert, erfordert einen gewissen Test. Konkret ausgeführt, könnte es so aussehen:

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

Für den ersten Edge-Fall wird keine cd ausgeführt.

Wenn es zulässig ist, cd . für den ersten Edge-Fall auszuführen, kann die Bedingung in der Erweiterung des Parameters ausgeführt werden:

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

Für den Fall, dass Sie diesen Pfad dem Git selbst hinzufügen, verwenden Sie :/

# 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

Kurze Lösungen, die mit Submodulen, in Hooks und innerhalb des .git-Verzeichnisses funktionieren

Hier ist die kurze Antwort, die die meisten wollen:

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

Dies funktioniert überall in einem Git-Arbeitsbaum (einschließlich innerhalb des .git-Verzeichnisses), es wird jedoch davon ausgegangen, dass Repository-Verzeichnis (e) .git heißen (dies ist der Standard). Bei Submodulen geht dies zur Wurzel des äußersten enthaltenden Repositorys. 

Wenn Sie zum Stamm des aktuellen Submoduls gelangen möchten, verwenden Sie:

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

Um einen Befehl in Ihrem Submodulstamm einfach auszuführen, fügen Sie unter [alias] in Ihrem .gitconfig Folgendes hinzu:

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

So können Sie Dinge wie git sh ag <string>

Robuste Lösung, die unterschiedlich benannte oder externe .git- oder $GIT_DIR-Verzeichnisse unterstützt.

Beachten Sie, dass $GIT_DIR irgendwo auf eine externe Stelle zeigen kann (und nicht .git genannt wird), weshalb weitere Überprüfungen erforderlich sind. 

Fügen Sie dies in Ihren .bashrc ein: 

# 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"
}

Führen Sie es aus, indem Sie git_root eingeben (nach dem Neustart Ihrer Shell: exec bash).

10
Tom Hale

Um die Antwort von "git config" etwas zu ändern:

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

und den Weg bereinigen. Sehr schön.

8
Bruce K

Wenn Sie nach einem guten Alias ​​dafür suchen, cd nicht blasen, wenn Sie sich nicht in einem Git-Verzeichnis befinden:

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

Dieser Shell-Alias ​​funktioniert unabhängig davon, ob Sie sich in einem git-Unterverzeichnis oder auf oberster Ebene befinden:

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

aktualisiert, um moderne Syntax anstelle von Backticks zu verwenden: 

alias gr='[ ! -z $(git rev-parse --show-toplevel) ] && cd $(git rev-parse --show-toplevel || pwd)'
6
MERM

Hier ist ein Skript, das ich geschrieben habe und beide Fälle behandelt: 1) Repository mit einem Arbeitsbereich, 2) einfaches Repository.

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

git-root (ausführbare Datei in Ihrem Pfad):

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

Hoffentlich ist das hilfreich.

5
jdsumsion

git-extras

fügt $ git root hinzu
siehe 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

Verfügbarkeit von Git-Extras

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

Alles andere schlägt irgendwann fehl, entweder in das Home-Verzeichnis zu gehen oder einfach nur zu klagen. Dies ist der schnellste und kürzeste Weg, um zum GIT_DIR zurückzukehren.

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

Seit Git 2.13.0 unterstützt es eine neue Option, um den Pfad des Wurzelprojekts anzuzeigen, der selbst dann funktioniert, wenn er aus einem Submodul heraus verwendet wird:

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

Musste das heute selbst lösen. Ich habe es in C # gelöst, da ich es für ein Programm brauchte, aber ich denke, es kann leicht umgeschrieben werden. Betrachten Sie diese Public Domain.

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

Falls jemand eine POSIX-kompatible Methode benötigt, ohne git ausführbar zu sein:

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

Wenn Sie die Funktionalität nur als Teil eines Skripts verwenden möchten, entfernen Sie Shebang und ersetzen Sie die letzte git_root_recurse_parent-Zeile durch:

git_root() {
    (git_root_recurse_parent)
}
1
swalog

Vorkonfigurierte Shell-Aliase in Shell-Frameworks

Wenn Sie ein Shell-Framework verwenden, ist möglicherweise bereits ein Shell-Alias ​​verfügbar:

  • $ grt in oh-my-zsh (68k) (cd $(git rev-parse --show-toplevel || echo "."))
  • $ git-root in prezto (8.8k) (zeigt den Pfad zur Wurzel des Arbeitsbaums an)
  • $ g..zimfw (1k) (wechselt das aktuelle Verzeichnis auf die oberste Ebene des Arbeitsbaums.)
1
Hotschke

Ich wollte auf Daniel Brockmans hervorragenden Kommentar eingehen.

Durch die Definition von git config --global alias.exec '!exec ' können Sie beispielsweise git exec make ausführen, da man git-config Folgendes festlegt:

Wenn der Alias-Erweiterung ein Ausrufezeichen vorangestellt ist, wird sie als Shell-Befehl behandelt. [...] Beachten Sie, dass Shell-Befehle vom obersten Verzeichnis eines Repositorys ausgeführt werden, das nicht unbedingt das aktuelle Verzeichnis ist.

Es ist auch praktisch zu wissen, dass $GIT_PREFIX der Pfad zum aktuellen Verzeichnis relativ zum Verzeichnis der obersten Ebene eines Repositorys ist. Aber zu wissen, dass es nur die halbe Miete ist. Shell Variable Expansion macht es ziemlich schwierig zu verwenden. Ich schlage also vor, bash -c so zu verwenden:

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

andere Befehle umfassen:

git exec pwd
git exec make
0
Bruno Bronosky