Как автоматически cd после git clone?

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

(Работает для ссылок как с ".git", так и без него)

Фредерик Дьюердт
источник
2
Я хотел бы продолжать использовать git cloneиз-за всех инструментов, которые мне пришлось бы изменить, если бы я не использовал git. Hub имеет псевдоним git, oh-my-zsh обеспечивает автозаполнение и т. Д.
Даниэль К.
3
@Wildeyes gitне может изменить рабочий каталог вашей оболочки, поэтому в любом случае вам придется обернуть его в псевдоним / функцию, которая делает то, что вы хотите, и следует за ней со встроенной функцией cd. Если вы хотите позвонить hubвместо git, сделайте это в функции. Если вы хотите, чтобы это влияло только на cloneкоманду, проверьте действие в функции. и т.д.
frostschutz
Я заметил, что это basename git@github.com:pckujawa/pattern-rec.gitприводит к pattern-rec.git - вы просто отключаете расширение .git при клонировании?
Пэт
8
@Pat basenameтакже принимает аргумент суффикса, так что вы можете сделать:git clone $1 && cd $(basename $1 .git)
Henrik 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
}
Kaz
источник
Это было именно то, что я искал. После того, как я понял, что нет внутренних хуков или чего-то в этом роде, я написал почти точную функцию :)
Даниэль К.
2
@Wildeyes Да: есть /tmpтом, который находится в оперативной памяти, как любой современный Linux через tmpfs. В любом случае, зачем вам записывать на диск, когда вы только что сделали git-клон, который создает каталоги и записывает, возможно, сотни файлов на диск ...
Kaz
1
Вы, наверное, правы насчет всего "nvm, если он пишет на диск", я просто хотел сохранить дополнительные операции. Большое спасибо Каз.
Даниэль К.
3
Быть осторожен. это git [flags] command [arguments]так, слепо просить cloneв определенной позиции не удастся.
vonbrand
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'`

РЕДАКТИРОВАТЬ: Ну, я собирался поблагодарить Манав (комментарий ниже) за краткий

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

но он не работает в zsh (что-то из-за того, как zsh делает расширения, заставляет его не рассматривать первую команду как вход !$). Я должен был посмотреть, что !$:tсделал ( Продвижение в Bash Shell | $ {me: -whither} ). !$берет последнюю часть предыдущей команды и :tудаляет все ведущие компоненты имени файла, оставляя хвост. Хорошая информация, но хотелось бы, чтобы она работала с zsh (я пытался noglobбезуспешно).

РЕДАКТИРОВАТЬ: Вместо использования sedили !$:t(который не работает в zsh, для меня в любом случае), я нашел два других варианта (один адаптирует https://unix.stackexchange.com/users/5685/frederik-deweerdt с https : //unix.stackexchange.com/users/129926/henrik-n 's комментарий):

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
Манав
Если ваш репо заканчивается, .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
}
davidhq
источник
1
Есть 7 ответов, которые отображают «выше» ваш. Но это может измениться со временем. Такие ссылки не имеют смысла для SE, пожалуйста, отредактируйте свой ответ и включите ссылку на ответ, на который вы ссылались.
Techraf
0

Я бы не советовал, но вы могли бы использовать эту строку:

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

christianbundy
источник
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.

PSkocik
источник