Como cd automaticamente após o git clone?

37

Eu quero automaticamente cdno diretório criado pelo clonecomando depois que eu git clonefizer alguma coisa.

Importante: não quero alterar a sintaxe do comando (por exemplo, usar um alias / função) porque isso quebraria as conclusões zsh que eu recebo automaticamente do Pretzoprojeto.

EDITAR : A razão pela qual eu não escolhi nenhuma resposta como correta, é porque nenhuma resposta foi dada que atendeu às condições acima.

Eu uso o ZSH, mas uma resposta em qualquer outro shell também é aceitável.

Daniel K.
fonte
Eu gosto da resposta unix.stackexchange.com/questions/97920/…, mas é preciso mencionar para escrever essa função no ~/.bashrcarquivo (por exemplo) e para mim, pelo menos, não funcionou, eu precisava corrigi-la com a substituição do linha:/usr/bin/git "$@" 2>&1 | tee $tmp
lcestari

Respostas:

19

Crie uma função:

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

(Funciona para links com e sem ".git")

Frederik Deweerdt
fonte
2
Eu gostaria de continuar usando git clonepor causa de todas as ferramentas que eu precisaria alterar se não estivesse usando git. Hub é alias como git, oh-meu-zsh fornece auto-completar, etc ...
Daniel K.
3
O @Wildeyes gitnão pode alterar o diretório de trabalho do seu shell; portanto, de qualquer forma, você terá que envolvê-lo em um alias / função que faça o que você deseja e o segue com o builtin cd. Se você deseja chamar em hubvez de git, faça-o na função Se você deseja que ele afete apenas o clonecomando, verifique a ação na função. etc
frostschutz 28/10
Percebi que isso basename [email protected]:pckujawa/pattern-rec.gitresulta em pattern-rec.git - você apenas interrompe a extensão .git ao clonar?
Pat
8
O @Pat basenametambém usa um argumento de sufixo, para que você possa fazer: #git clone $1 && cd $(basename $1 .git)
Henrik N
17

git cloneusa um argumento adicional: o diretório a ser usado. Você pode cloná-lo no diretório de trabalho atual com git clone URL . Então, não há necessidade de alterar o diretório de trabalho; voce ja esta la

Se você realmente deseja que o gitcomando realmente altere o diretório de trabalho, você pode alterá-lo para uma função que chama o real gitquando necessário:

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
fonte
Era exatamente o que eu estava procurando. Depois eu percebi que não há ganchos internos ou algo assim, eu escrevi uma função quase exata :)
Daniel K.
2
@ Wililde Sim: tem um /tmpvolume que está na RAM, como qualquer Linux moderno faz via tmpfs. De qualquer forma, por que você se preocupa com a escrita para o disco, quando você acabou de fazer um clone git, que cria diretórios e escreve talvez centenas de arquivos para o disco ...
Kaz
11
Você provavelmente está certo sobre toda a coisa "nvm se ela grava no disco", eu estava apenas procurando salvar operações extras. Muito obrigado Kaz.
Daniel K.
3
Seja cuidadoso. é git [flags] command [arguments]assim que pedir cegamente cloneem determinada posição falhará.
21416 vonbrand
11
Adicionar o caminho "real" ajudaria? Como: git_real_home = which git git () {... $ git_real_home "$ @" | tee $ tmp
aakoch 5/17/17
7

Se você fornecer o nome local do repo, é muito fácil usar $ _ :

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

Mas se você não deseja digitar novamente nomes longos, é um pouco feio, mas possível com o sed:

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

EDIT: Bem, eu estava indo para agradecer Manav (comentário abaixo) para o conciso

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

mas não funciona no zsh (algo sobre como o zsh faz expansões faz com que ele não trate o primeiro comando como entrada para !$). Eu tive que procurar o que !$:tfez ( Avançando no Bash Shell | $ {me: -whatever} ). !$agarra a última parte do comando anterior e :t"Remova todos os principais componentes de nome de arquivo, deixando a cauda". Boas informações, mas gostaria de poder fazê-lo funcionar com o zsh (tentei noglobsem sucesso).

EDIT: Em vez de usar sedou !$:t(o que não funciona em zsh, pelo menos para mim), eu encontrei duas outras opções (uma adaptação https://unix.stackexchange.com/users/5685/frederik-deweerdt resposta 's com https : //unix.stackexchange.com/users/129926/henrik-n's comment):

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

ou

git clone git@github.com:npm/npm.git && cd ${${_%%.git*}##*/}
Pat
fonte
git clone foo/bar && cd !$:t
Manav
Se o seu repo url terminar, .gitvocê poderá usar !$:t:rpara obter o nome da pasta.
Michael Stramel
2

Uma solução simples para qualquer shell POSIX é especificar o diretório a ser clonado explicitamente (qualquer caminho do sistema de arquivos) e reutilizá-lo:

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

e

cd -

quando você acabar.

Sander
fonte
2

Você poderia fazer algo como:

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)

É bastante simplista. É um precmdgancho (executado antes de cada prompt), que verifica se a última linha de comando se parece git clone .../somethingou git clone .../something dir, adivinhe o diretório a partir dele e faça o cd nele.

Não funciona se você inseriu git clone foo; whateverou whatever; git clone fooou git clone --option repo...

Stéphane Chazelas
fonte
+1 Muito obrigado pelo código; Estou usando há alguns dias. Acabei de notar um problema; se você fechar o terminal logo após a clonagem de algum projeto, na próxima vez em que abrir um terminal, o zsh receberá duas mensagens de erro: CDing into <project>e clone_check:cd:17: no such file or directory: <project>. O erro desaparece assim que o último comando que você executou antes de fechar o terminal for diferente $ git clone.
User938271 19/06
2

Aqui está uma adaptação da resposta acima para OSX

  • mktemp requer parâmetro adicional
  • git cloneescreve STDERRpor padrão (veja isso )

Função:

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
fonte
11
Existem 7 respostas que exibem "acima" a sua. Mas isso pode mudar com o tempo. Tais referências não fazem sentido no SE, edite sua resposta e inclua um link para a resposta a que você estava se referindo.
techraf
0

Eu não recomendaria, mas você pode usar esta frase:

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

christianbundy
fonte
0

Inclua isso no seu shell:

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

Isso funciona ao coletar clandestinamente o alvo de clonagem do erro padrão do git e cd entrando no alvo se (e somente se) a clonagem foi um sucesso.

Ele aceita todos os argumentos e opções que o regular git cloneaceita.

Você pode usar o wrapper git e não precisa se preocupar com suas conclusões, ou pode se livrar do wrapper git e reconectá git clone-lo git-clone.

PSkocik
fonte