Jak automatycznie CD po klonowaniu git?

37

Chcę automatycznie cdprzejść do katalogu utworzonego przez clonepolecenie po git cloneczymś.

Ważne: nie chcę zmieniać składni polecenia (np. Użyć aliasu / funkcji), ponieważ spowodowałoby to przerwanie uzupełnień zsh, które otrzymuję automatycznie z Pretzoprojektu.

EDYCJA : Powodem, dla którego nie wybrałem żadnej odpowiedzi jako poprawnej, jest to, że nie podano żadnej odpowiedzi, która byłaby zgodna z powyższym warunkiem.

Używam ZSH, ale odpowiedź w dowolnej innej powłoce jest również do przyjęcia.

Daniel K.
źródło
Podoba mi się odpowiedź unix.stackexchange.com/questions/97920/…, ale muszę wspomnieć, aby zapisać tę funkcję w ~/.bashrcpliku (na przykład) i dla mnie przynajmniej nie działała, musiałem to naprawić, zastępując linia:/usr/bin/git "$@" 2>&1 | tee $tmp
lcestari

Odpowiedzi:

19

Utwórz funkcję:

gclonecd() {
  git clone "$1" && cd "$(basename "$1" .git)"
}

(Działa z linkami zarówno z „.git”, jak i bez niego)

Frederik Deweerdt
źródło
2
Chciałbym nadal używać git cloneze względu na wszystkie narzędzia, które musiałbym zmienić, gdybym nie korzystał git. Hub jest aliasowany jako git, oh-my-zsh zapewnia automatyczne uzupełnianie itp.
Daniel K.,
3
@Wildeyes gitnie może zmienić katalogu roboczego twojej powłoki, więc tak czy inaczej będziesz musiał owinąć go w alias / funkcję, która robi to, co chcesz i śledzi to za pomocą wbudowanego cd. Jeśli chcesz zadzwonić hubzamiast git, zrób to w funkcji. Jeśli chcesz, aby wpływał tylko na clonepolecenie, sprawdź działanie w funkcji. itp.
frostschutz
Zauważyłem, że basename [email protected]:pckujawa/pattern-rec.gitpowoduje to wzorzec-rec.git - czy po prostu zostawiasz rozszerzenie .git podczas klonowania?
Pat
8
@Pat basenamebierze również argument sufiksu, dzięki czemu możesz:git clone $1 && cd $(basename $1 .git)
Henrik N
17

git cloneprzyjmuje dodatkowy argument: katalog do użycia. Możesz go sklonować do bieżącego katalogu roboczego za pomocągit clone URL . Następnie nie ma potrzeby zmiany katalogu roboczego; już tam jesteś

Jeśli naprawdę chcesz, aby gitpolecenie zmieniło katalog roboczy, możesz zmienić go na funkcję, która w gitrazie potrzeby wywołuje rzeczywistą :

git()
{
   local tmp=$(mktemp)
   local repo_name

   if [ "$1" = clone ] ; then
     /usr/bin/git "$@" | tee $tmp
     repo_name=$(awk -F\' '/Cloning into/ {print $2}' $tmp)
     rm $tmp
     printf "changing to directory %s\n" "$repo_name"
     cd "$repo_name"
   else
     /usr/bin/git "$@"
   fi
}
Kaz
źródło
Właśnie tego szukałem. Po tym, jak zdałem sobie sprawę, że nie ma żadnych wewnętrznych zaczepów ani czegoś takiego, napisałem prawie dokładną funkcję :)
Daniel K.,
2
@Wildeyes Tak: ma /tmpwolumin znajdujący się w pamięci RAM, tak jak każdy współczesny Linux robi to przez tmpfs. W każdym razie, dlaczego miałbyś przejmować się pisaniem na dysk, skoro właśnie zrobiłeś klon git, który tworzy katalogi i zapisuje może setki plików na dysk ...
Kaz
1
Prawdopodobnie masz rację co do całej sprawy „nvm, jeśli zapisuje na dysk”, chciałem tylko zapisać dodatkowe operacje. Wielkie dzięki Kaz.
Daniel K.
3
Bądź ostrożny. tak jest git [flags] command [arguments], więc ślepe proszenie o cloneokreślone stanowisko zawiedzie.
vonbrand
1
Czy dodanie „prawdziwej” ścieżki pomogłoby? Jak: git_real_home = which git git () {... $ git_real_home "$ @" | tee $ tmp
aakoch
7

Jeśli podasz lokalną nazwę repozytorium, użycie $ _ jest naprawdę łatwe :

git clone git@github.com:npm/npm.git npm-local-dir && cd $_

Ale jeśli nie chcesz ponownie wpisywać długich nazw, jest to trochę brzydkie, ale wykonalne za pomocą sed:

git clone git@github.com:pckujawa/pattern-rec.git && 
cd `echo $_ | sed -n -e 's/^.*\/\([^.]*\)\(.git\)*/\1/p'`

EDYCJA: Cóż, chciałem podziękować Manavowi (komentarz poniżej) za zwięzłość

git clone foo/bar && cd !$:t

ale to nie działa w zsh (coś o tym, jak zsh robi rozwinięcia powoduje, że nie traktuje pierwszego polecenia jako danych wejściowych !$). Musiałem sprawdzić, co się stało !$:t( Awans w Bash Shell | $ {ja: -wszystko} ). !$pobiera ostatnią część poprzedniego polecenia i :t„Usuwa wszystkie wiodące komponenty nazw plików, pozostawiając ogon”. Dobra informacja, ale szkoda, że ​​nie mogę tego zrobić z zsh (próbowałem noglobbezskutecznie).

EDIT: Zamiast sedlub !$:t(co nie działa w zsh, przynajmniej dla mnie), znalazłem dwie inne opcje (jeden dostosowująca https://unix.stackexchange.com/users/5685/frederik-deweerdt „s odpowiedź z https : //unix.stackexchange.com/users/129926/henrik-n's comment):

git clone git@github.com:npm/npm.git && cd $(basename $_ .git)

lub

git clone git@github.com:npm/npm.git && cd ${${_%%.git*}##*/}
Poklepać
źródło
git clone foo/bar && cd !$:t
Manav
Jeśli Twój adres URL repo kończy się .git, możesz użyć !$:t:rnazwy folderu.
Michael Stramel
2

Prostym rozwiązaniem dla dowolnej powłoki POSIX jest jawne określenie katalogu do klonowania (dowolna ścieżka systemu plików) i ponowne użycie go:

git clone <repository> <directory> &&
cd "$_"

i

cd -

kiedy skończysz.

Szlifierka
źródło
2

Możesz zrobić coś takiego:

clone_check() {
  (($? != 0)) && return
  local cmd=$history[$((HISTCMD-1))]
  cmd=("${(@Q)${(z)cmd}}")
  if [[ $cmd = "git clone "* ]]; then
    local dir
    if (($#cmd == 3)); then
      dir=${cmd[3]:t}
      dir=${dir%.git}
      dir=${dir#*:}
    elif (($#cmd > 3)); then
      dir=$cmd[-1]
    else
      return
    fi
    print -r CDing into $dir > /dev/tty
    cd -- $dir
  fi
}
precmd_functions+=(clone_check)

To jest dość uproszczone. Jest to precmdhaczyk (wykonywany przed każdym monitem), który sprawdza, czy wyglądał ostatni wiersz polecenia git clone .../somethinglub git clone .../something dir, zgadnij z niego katalog i włóż do niego cd.

To nie działa, jeśli wprowadzone git clone foo; whateverlub whatever; git clone fooczy git clone --option repo...

Stéphane Chazelas
źródło
+1 Bardzo dziękuję za kod; Używam go od kilku dni. Właśnie zauważyłem jeden problem; jeśli zamkniesz terminal zaraz po sklonowaniu jakiegoś projektu, przy następnym otwarciu terminalu zsh narzeka na dwa komunikaty o błędach: CDing into <project>i clone_check:cd:17: no such file or directory: <project>. Błąd znika, gdy tylko ostatnie polecenie uruchomione przed zamknięciem terminalu różni się od $ git clone.
user938271
2

Oto adaptacja powyższej odpowiedzi dla OSX

  • mktemp wymaga dodatkowego parametru
  • git cloneSTDERRdomyślnie zapisuje (patrz to )

Funkcjonować:

function git {
   local tmp=$(mktemp -t git)
   local repo_name

   if [ "$1" = clone ] ; then
     command git "$@" --progress 2>&1 | tee $tmp
     repo_name=$(awk -F\' '/Cloning into/ {print $2}' $tmp)
     rm $tmp
     printf "changing to directory %s\n" "$repo_name"
     cd "$repo_name"
   else
     command git "$@"
   fi
}
davidhq
źródło
1
Istnieje 7 odpowiedzi, które wyświetlają „powyżej” twojej. Ale z czasem może się to zmienić. Takie odniesienia nie mają sensu w SE, edytuj swoją odpowiedź i dołącz link do odpowiedzi, o której mówiłeś.
techraf
0

Nie polecam go, ale mógłby użyć tego jednego-liner:

echo 'project' | xargs -I % sh -c 'git clone https://github.com/username/%.git && cd %'

christianbundy
źródło
0

Dodaj to do swojej powłoki:

git(){
  case "$1" in clone) git-clone "${@:2}";; *) command git "$@";; esac
}
git-clone(){ 
   local tgt 
   tgt=$(command git clone "$@" 2> >(tee /dev/stderr |head -n1 | cut -d \' -f2)) ||
      return $?
   cd "$tgt"
}

Działa to poprzez ukryte pozyskiwanie celu klonowania ze standardowego błędu gita i cd trafianie do celu, jeśli (i tylko jeśli) klonowanie zakończyło się sukcesem.

Akceptuje wszystkie argumenty i opcje, które git clonerobi normalny .

Albo możesz użyć otoki git i nie musisz się martwić o swoje ukończenia, albo możesz pozbyć się otoki git i ponownie git clonewykonać okablowanie git-clone.

PSkocik
źródło