Як CD автоматично після клонування Git?


37

Мені потрібно автоматично cdперейти до каталогу, створеного cloneкомандою після того, як я git cloneщось буду робити .

Важливо: я не хочу змінювати синтаксис команди (наприклад, використовувати псевдонім / функцію), оскільки це порушить zsh-доповнення, які я отримую автоматично від Pretzoпроекту.

РЕДАКТУВАННЯ : Причиною того, що я не обрав жодну відповідь як правильну, є те, що не було надано відповіді, яка б відповідала вищевказаній умові.

Я використовую ZSH, але відповідь у будь-якій іншій оболонці також прийнятна.


Мені подобається відповідь unix.stackexchange.com/questions/97920/…, але потрібно згадати, щоб написати цю функцію у ~/.bashrcфайл (наприклад), і для мене, принаймні, це не спрацювало, мені потрібно було виправити її із заміною рядок:/usr/bin/git "$@" 2>&1 | tee $tmp
lcestari

Відповіді:


19

Створіть функцію:

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

(Працює для посилань як із ", так і без.")


2
Я хотів би продовжувати користуватися git cloneчерез всі інструменти, які я мав би змінити, якби не користувався git. Хаб відчужений як git, oh-my-zsh забезпечує автоматичне завершення тощо ...
Даніель К.

3
@Wildeyes gitне може змінити робочий каталог вашої оболонки, тому в будь-якому випадку вам доведеться загортати його в псевдонім / функцію, яка виконує те, що ви хочете, і слідкує за цим вбудованим cd. Якщо ви хочете зателефонувати hubзамість git, зробіть це у функції. Якщо ви хочете, щоб це впливало лише на cloneкоманду, перевірте, чи є дія у функції. пр.
frostschutz

Я помітив, що це basename git@github.com:pckujawa/pattern-rec.gitпризводить до шаблону-rec.git - ви просто залишаєте розширення .git, коли ви клонуєте?
Пат

8
@Pat basenameтакож приймає суфіксний аргумент, тож ви можете:git clone $1 && cd $(basename $1 .git)
Генрік N

17

git cloneбере додатковий аргумент: каталог, який потрібно використовувати. Ви можете змусити його клонуватись у поточний робочий каталог за допомогою git clone URL . Потім, не потрібно змінювати робочий каталог; ти вже там.

Якщо ви дійсно хочете, щоб gitкоманда фактично змінила робочий каталог, ви можете змінити його на функцію, яка викликає справжнє, gitколи це необхідно:

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
}

Саме це я і шукав. Після того як я зрозумів, що немає внутрішніх гачків чи чогось подібного, я написав майже точну функцію :)
Daniel K.

2
@Wildeyes Так: є /tmpоб'єм, який знаходиться в оперативній пам'яті, як і будь-який сучасний Linux через tmpfs. У будь-якому випадку, чому б вам було бажання писати на диск, коли ви тільки що зробили клон git, який створює каталоги та записує, можливо, сотні файлів на диск ...
Kaz

1
Ви, напевно, маєте рацію щодо всього "nvm, якщо він записує на диск", я просто прагнув зберегти зайві операції. Велике спасибі Каз.
Даніель К.

3
Будь обережний. це git [flags] command [arguments]так, тому сліпо просити cloneв певну позицію не вдасться.
фонбранд

1
Чи допоможе додати "реальний" шлях? Як: git_real_home = which git git () {... $ git_real_home "$ @" | tee $ tmp
aakoch

7

Якщо ви вкажете локальну назву репо, це дуже просто використовувати $ _ :

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

Але якщо ви не хочете вводити довгі імена, це трохи некрасиво, але це можливо з sed:

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

EDIT: Ну, я збирався подякувати Манаву (коментар нижче) за короткий час

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

але він не працює в zsh (щось про те, як zsh виконує розширення, змушує його не трактувати першу команду як вхід до !$). Мені довелося шукати, що !$:tзробив ( Просування в шквалу Баша | $ {me:-що завгодно ). !$захоплює останню частину попередньої команди та :t"Видалить усі провідні компоненти імен файлів, залишаючи хвіст." Хороша інформація, але я б хотів, щоб я міг змусити її працювати з zsh (я намагався noglobбез успіху).

EDIT: Замість того , щоб використовувати sedабо !$:t(який не працює в Zsh, для мене у всякому разі), я знайшов два інших варіанти (один адаптують https://unix.stackexchange.com/users/5685/frederik-deweerdt «s відповідь з HTTPS : //unix.stackexchange.com/users/129926/ коментарhenhen-n):

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

або

git clone git@github.com:npm/npm.git && cd ${${_%%.git*}##*/}

git clone foo/bar && cd !$:t
Манав

Якщо ваш репо-URL закінчується, .gitви можете використовувати !$:t:rім'я папки.
Майкл Страмель

2

Просте рішення для будь-якої оболонки POSIX - вказати каталог, який явно клонується (будь-який шлях файлової системи) та повторно використовувати його:

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

і

cd -

коли ти закінчиш.


2

Ви можете зробити щось на кшталт:

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)

Це досить спрощено. Це precmdгачок (виконується перед кожним запитом), який перевіряє, чи виглядав останній командний рядок, git clone .../somethingабо git clone .../something dirвідгадує каталог з цього і входить у нього.

Це не працює , якщо ви ввели git clone foo; whateverабо whatever; git clone fooабо git clone --option repo...


+1 Дуже дякую за код; Я використовую його з кількох днів. Я щойно помітив одне питання; якщо ви закриєте термінал відразу після клонування якогось проекту, наступного разу, коли ви відкриєте термінал, zsh скаржиться на два повідомлення про помилку: CDing into <project>і clone_check:cd:17: no such file or directory: <project>. Помилка зникає, як тільки остання команда, яку ви запустили перед закриттям терміналу, відрізняється від $ git clone.
user938271

2

Ось адаптація вищевказаної відповіді на OSX

  • mktemp вимагає додаткового параметра
  • git cloneпише STDERRза замовчуванням (див. це )

Функція:

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
}

1
Є 7 відповідей, які відображають "вище" вашого. Але це може змінитися з часом. Такі посилання не мають сенсу для SE, будь ласка, відредагуйте свою відповідь та додайте посилання на відповідь, на який ви зверталися.
techraf

0

Я б не рекомендував його, але ви можете скористатися цим одношаровим:

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


0

Включіть це до своєї оболонки:

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

Це спрацьовує, нахабно відбираючи ціль клонування від стандартної помилки git і cd'вводячись у ціль, якщо (і тільки якщо) клонування було успішним.

Він приймає всі аргументи та варіанти, які git cloneробить черговий .

Або ви можете використовувати Git обгортку і не потрібно турбуватися про свої завершення, або ви можете позбутися від git обгортки і перенаправити свої git cloneзавершення на git-clone.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.