Vim по полной: Работа с Git

    Оглавление


    1. Введение (vim_lib)
    2. Менеджер плагинов без фатальных недостатков (vim_lib, vim_plugmanager)
    3. Уровень проекта и файловая система (vim_prj, nerdtree)
    4. Snippets и шаблоны файлов (UltiSnips, vim_template)
    5. Компиляция и выполнение чего угодно (vim-quickrun)
    6. Работа с Git (vim_git)
    7. Деплой (vim_deploy)
    8. Тестирование с помощью xUnit (vim_unittest)
    9. Библиотека, на которой все держится (vim_lib)
    10. Другие полезные плагины

    Часто ли вам приходится использовать Git? В смысле, вы коммитите изменения каждый час или каждые несколько минут? Я делаю это очень часто и не слежу за чистотой репозитория, так как считаю его не более чем журналом изменений, а не произведением искусства. Такой подход требует от редактора хорошей интеграцией с Git, позволяющей в пару нажатий клавиш создать новый коммит, вернуться в прежнее состояние, перейти на другую ветку и так далее. Если вы используете современную среду разработки, в которой реализована интеграция с Git, вам очень повезло, но что делать пользователям редактора Vim? Есть ли плагин, который не просто реализует Vim-команды по тиму GitCommit, GitCheckout и GitBranch, а предоставляет удобный интерфейс в лучших традициях редактора?

    GUI в CLI


    Когда я впервые задумался об интеграции Vim с Git, я, конечно же, попробовал готовые плагины и решения, но почему они все лишь реализуют команды редактора, а не предоставляют чего то большего? Я активно пользуюсь Git как с помощью CLI, так и посредством различных программ с GUI. У того и у другого есть свои плюсы и минусы, но в работе часто решаются следующие задачи:
    • Индексация и добавление коммитов
    • Просмотр изменений
    • Переход между ветками и слияние
    • Просмотр истории, ее фильтрация и переход в прежние состояния

    У Git есть еще много полезного, но, как показала моя практика, чаще всего используются эти четыре действия. Важно отметить, что все они отнюдь не тривиальны. На пример, для добавления нескольких файлов в коммит нужно выполнить две команды и перечислить адреса этих файлов, что довольно долго (при использовании CLI). С другой стороны, постоянно переключаться между редактором и используемой программой с GUI для работы с Git тоже довольно накладно, так как, лично мне, тяжело переключаться между контекстом (читать — интерфейсом) используемого редактора (Vim) и GUI (мышь). Заметив это, я решил написать собственный плагин для Vim, который будет удобен пользователям этого редактора и при этом достаточно прост, даже для любителей GUI. Кстати, именно с этого плагина началась библиотека vim_lib, о которой вы уже слышали в прошлых моих статьях.

    В чем же изюм этого плагина? С помощью горячих клавиш можно легко индексировать файлы, коммитить индекс и т.д. В свою очередь окна редактора используются плагином так, что получается GUI с привычным для пользователя Vim управлением. На пример, чтобы удалить ветку, достаточно открыть окно веток, навести курсор на нужную ветку и использовать dd, «как дома»!

    Основные возможности


    Плагин, о котором я хочу рассказать называется vim_git. Плагин довольно сложный, так как я постарался учесть все потребности пользователя Git, от чего в нем реализовано множество возможностей, но в этой статье я постараюсь максимально просто и понятно об этом всем рассказать.

    Об окнах


    Для начала запомните: плагин активно использует окна (window) редактора как элементы графического интерфейса.
    Пример


    Окна реализованы так, что используются они с помощью стандартных команд редактора Vim. То есть для выбора некоторого элемента, на пример ветки, нужно навести указатель (текстовый) на имя этой ветки, чтобы удалить ее используется команда dd, а для добавления команда a, и так везде. Все окна сопровождаются встроенной документацией, о которой сообщает подсказка вида «Branch list (Press? for help)». Нажав ?, подсказка будет развернута в том же окне.
    Пример


    Достаточно просто?

    Об API плагина


    Так же вам стоит знать: все создаваемые мной плагины реализуют API в виде Vim функций. Так, все API данного плагина присутствует в виде функций vim_git#..., на пример vim_git#status, vim_git#tagList, vim_git#branchList и т.д. Большинство плагинов при этом реализуют как пункты меню Vim, которые используют API плагина, так и команды. Лично мне удобнее биндить клавиши, это быстрее любых меню и команд редактора, но я не настаиваю.

    Вот пример того, как я забиндил клавиш для плагина vim_git:
    Plugin 'vim_git', {
          \  'map': {
          \    'status':      '<Leader>gs', " Окно статуса
          \    'log':         '<Leader>gl', " Окно истории коммитов
          \    'branchList':  '<Leader>gb', " Окно веток
          \    'tagList':     '<Leader>gt', " Окно тегов
          \    'addCurrent':  '<Leader>ga', " Добавить текущий файл в индекс
          \    'addAll':      '<Leader>gA', " Добавить все изменения в индекс
          \    'commit':      '<Leader>gc', " Коммит индекса
          \    'commitAll':   '<Leader>gC', " Добавить все изменения в индекс и их коммит
          \    'pushCurrent': '<Leader>go', " Push
          \    'pullCurrent': '<Leader>gi', " Pull
          \    'remoteList':  '<Leader>gr', " Окно удаленных репозиториев
          \  }
          \}
    

    О стеке окон


    Многие окна vim_git (как и всех моих плагинов) реализованы в виде стека. Это означает, что если в окне вы выполняете команду, которая приводит к открытию другого окна (на пример пытаетесь посмотреть различия между двумя коммитами), это новое окно будет открыто в текущем окне. Если вы закроете новое окно (на пример с помощью :q), то откроется первое окно. Таким образом вы используете стек окон.
    Если эти моменты вам понятны, то переходим к делу.

    Индекс


    Для просмотра состояния индекса Git используется vim_git#status (или сочетание gs). Это окно содержит подробную информацию о состоянии репозитория и индекса в виде ответа самого Git. То есть никакой обработки плагин не выполняет, все стандартно.
    Окно статуса


    В данном окне реализованы следующие команды (сочетания клавишь):
    • a — добавить файл под курсором в индекс. При этом окно будет автоматически перерисовано и вы увидите что файл действительно добавлен в индекс. Чтобы не повторяться, все окна плагина перерисовываются автоматически по мере надобности
    • dd — удалить файл под курсором из индекса
    • da — удалить все файлы из индекса
    • u — восстановить файл под курсором в состояние последнего коммита
    • U — восстановить все файлы в состояние последнего коммита
    • d — показать изменения в файле в режиме
      Git-diff

    • D — показать изменения в файле в режиме
      Vim-diff


    Коммит


    При коммите плагин откроет новое окно, в котором вам будет необходимо написать комментарий. После сохранения и закрытия этого окна (на пример с помощью ZZ), коммит будет создан. Чтобы отменить создание коммита, достаточно закрыть окно без сохранения (:q!). Естественно в коммит попадут только те изменения, которые были добавлены в индекс на момент выполнения коммита.
    Окно коммита


    История коммитов


    Для просмотра истории коммитов используется vim_git#log (или сочетание gl). Это окно выводит историю коммитов в двух режимах:
    • Классический — коммиты перечислены в виде блоков
      Пример


    • Граф — коммиты представлены в виде дерева
      Пример



    В данном окне реализованы следующие команды (сочетания клавиш):
    • Enter — перейти на указанный коммит
    • u — отменить изменения
    • d — показать разницу между текущим состоянием репозитория и указанным коммитом в режиме Git-diff
    • v — переключиться между режимами вывода истории (классический и граф)

    Отдельно следует упомянуть о фильтре и состоянии коммита.

    Фильтр истории


    Команда (сочетание клавиш) f открывает диалог, в котором вы можете добавить различные фильтры для истории, будь то имя интересующего вас автора или дата создания коммита.
    Диалог фильтра


    Состояние коммита


    Если навести указатель на хэш интересующего нас коммита и нажать s, то откроется окно состояния коммита, в котором будут перечислены все измененные данным коммитом файлы.
    Окно состояния коммита


    В этом окне реализованы следующие команды (сочетания клавишь):
    • d — изменения (в режиме Git-diff) в файле под курсором, внесенные коммитом
    • D — изменения (в режиме Git-vim) в файле под курсором, внесенные коммитом

    Ветки


    Для просмотра доступных веток (локальных и удаленных) используется vim_git#branchList (или сочетание gb).
    Окно веток


    В данном окне реализованы следующие команды (сочетания клавишь):
    • Enter — перейти на ветку под курсором
    • a — добавить новую ветку
    • r — переименовать ветку под курсором
    • dd — удалить ветку
    • m — слить текущую ветку с веткой под курсором
    • o — push ветки (только для локальных веток)
    • d — показать разницу между текущей веткой и веткой под курсором (в режиме Git-diff)
    • s — показать состояне ветки (аналогично состоянию коммита)
    • i — слить изменения из удаленной ветки в текущую

    Удаленные репозитории


    Для просмотра зарегистрированных удаленных репозиториев используется vim_git#remoteList (или сочетание gr).
    Окно удаленных репозиториев


    В данном окне реализованы следующие команды (сочетания клавиш):
    • a — добавить новый псевдоним удаленного репозитория
    • dd — удалить псевдоним под курсором
    • r — переименовать псевдоним под курсором
    • f — получить изменения из репозитория под курсором
    • i — получить и слить изменения из удаленного репозитория под курсором в текущую ветку
    • o — отправить все изменения текущей ветки в удаленный репозиторий под курсором

    Теги


    Для просмотра тегов используется vim_git#tagList (или сочетание gt).
    Окно тегов


    В данном окне реализованы следующие команды (сочетания клавиш):
    • Enter — перейти на коммит, на который указывает тег под курсором
    • a — добавить новый тег для текущего коммита
    • A — добавить аннотирующий тег для текущего коммита
    • dd — удалить тег под курсором
    • s — показать информацию о теге

    Пока все


    Сила плагина в удобном API и GUI, что позволяет мне активно пользоваться Git не выходя из редактора. Конечно я не осветил все функции vim_git, так как статья уже довольно длинна и не хочется утомлять читателя, потому вы найдете еще много интересного в этом плагине (на пример с помощью go легко push'ить, а с помощью gi pull'ить изменения).
    Share post

    Similar posts

    AdBlock has stolen the banner, but banners are not teeth — they will be back

    More
    Ads

    Comments 45

      +1
      А как добавить в git индекс все измененные, новые и переименованные файлы?
        +1
        vim_git#addAll или gA, либо в окне статуса добавить файлы руками.
        +2
        Спасибо за статью и продвижение vim. Я как пользователь vim(4 года уже) не представляю работу без него.
        Самая крутая идея vim — это режимы редактирования и навигация, после освоения vim не как редактора, а как идеи для редактирования текста, жизнь становится ярче и повсюду радуги и единороги)
        Сейчас у меня vim навигация в браузере, даже этот текст я пишу в vim(https://chrome.google.com/webstore/detail/wasavi/dgogifpkoilgiofhhhodbodcfgomelhe?hl=en-US), vim-like навигация в консоли, vim-mode в RubyMine, даже в клиенте твитерра под МакОс есть что-то на подобии такой навигации.

        В общем, кто ценит свое время — изучайте vim. Удачи.
          +1
          А чем так уж удобно разделение на режимы навигации и редактирования? Разве это наоборот не замедляет набор, особенно при написании кода, в котором не получится просто писать длинную партянку текста без постоянной навигации по тексту, как на печатной машинке.
            +1
            vi-like навигация удобнее тем что не надо постоянно перепрыгивать на мышку и обратно.
              +1
              Ну, мне скорей интересно, чем vim-like навигация лучше, в сравнении с навигацией в emacs, когда вся навигация висит на хоткеях… просто многие себе в томже emacs настраивают vim-like навигацию и утверждают, что так удобней, а я вот что-то пока не проникся этой темой…
                +1
                Удобство в доступном для слепого метода печати сочитании клавишь.
                  +1
                  ну постараюсь привести пример. есть код, мы в режиме «нормал». курсор в начале.
                  задача — заменить слово тест на «hello»

                  |some_method(«test»)

                  что нужно нажать в вим: f«ci»hello

                  как это сделать в простом редакторе?
                    0
                    «в простом редакторе» — умойтесь, все emacs-хейтеры, так emacs еще никто не опускал :)
                      0
                      я не доказываю что emacs-like навигация хуже, или любая другая, я говорю конкретно о себе. сейчас мой сетап это emacs + evil-mode.
                      0
                      Ну… пишем в init.el примерно такой код:

                      (defun goto-forward-quote ()
                      (interactive)
                      (search-forward-regexp "'+\\|\\\"+" nil t))

                      (global-set-key (kbd «C-») 'goto-forward-quote)

                      Он позволяет при помощи хоткея ходить по скобкам вперед.
                      Соответственно находясь в начале строки, можно нажать Ctrl+End, курсор перейдет в начало слова «test» а там с insert'ом заменяемяем «test» на «hello».

                      Но на пратике лично мне удобней пользоваться переходами по словам/символам и в конец строки/начало строки.
                        0
                        Клавиша End на моей клавиатуре расположена крайней справа (над Num-блоком). Как думаете, удобно будет в слепую искать ее там?
                          0
                          Ну так забиндить можно на любую удобную комбинацию)
                            0
                            Ctrl у меня тоже не совсем под пальцем ) Это не придирки, мне реально не удобно пользоваться комбинациями, отличными от чисто буквенных при слепом методе.
                  0
                  Во-первых это позволяет иметь очень мощный и удобный режим навигации. В емаксе хоткеи очень сложные. В vim-е все «хоткеи» в основном однобуквенные. Плюс числовые модификаторы, буферы — это всё делает навигацию по документу быстрой и удобной, когда вы освоитесь с редактором.

                  Во-вторых это позволяет очень быстро писать макросы для сравнительно сложной обработки текста. Аналогом можно считать поиск и замену по регулярным выражениям, а также множественные курсоры, но в разных ситуациях разные инструменты показывают разную эффективность. Простое регулярное выражение, конечно, проще выполнить без всяких макросов. Множественные курсоры удобны, когда число изменяемых строк в пределах нескольких десятков. А вот когда надо обработать какой-нибудь файл логов в несколько тысяч строк и трансформация на регулярные выражения ложится не очень хорошо, то макросы очень сильно пригождаются.

                  Конечно можно объединить режим навигации и редактирования в один, как делают большинство редакторов. Нажатие обычных клавиш должно вводить текст, поэтому все команды навигации (к ним я причисляю команды вставки из буфера обмена и прочие) должны будут висеть на горячих клавишах с модификаторами. В итоге когда вам нужно ввести несколько команд навигации, вы будете нажимать кучу модификаторов на каждую команду. Это достаточно долго и не очень удобно. Куда удобней переключиться в другой режим и вводить команды без модификаторов.
                +1
                есть плагин для работы с Git и давольно популярный — Fugitive. Умеет много чего, например частичные коммиты (т.е. в коммит попадают только часть изменений текущего файла), советую.
                  +1
                  Слышал. Он умеет GUI интерфейс и Vim-diff сравнение изменений?
                    +1
                    diff умеет, на счёт веток не уверен.
                      +1
                      Ну как я сказал в статье, diff бывает разный. О каком именно diff вы говорите? Или умеет оба?
                        +1
                        vim-diff. Второй же можно просто получить командой git diff и отправить в буффер, но я не знаю зачем он нужен.
                          +1
                          Второй же можно просто получить командой git diff и отправить в буффер

                          Так мы же не устанавливаем плагин для Vim, чтобы команды git diff запускать и отправлять выхлоп в буфер )

                          я не знаю зачем он нужен

                          Если вам нужно посмотреть различия сразу нескольких файлов, на пример.
                            +1
                            Это ж одна команда, можно забиндить на кнопку.
                              0
                              Вы предлагаете написать плагин и в документации добавить: а вот эти команды слишком простые, просто добавьте себе в vimrc:
                              nnoremap ga…
                              nnoremap gb…
                              nnoremap gc…
                              ?
                            +1
                            Можно открыть буфер с выводом git status и затем на нужном файле нажать D, чтобы посмотреть git diff:

                            :Gstatus
                            D
                            


                            Но обычно редактируемые файлы и так открыты в буферах и нужно только на нужных :Gdiff делать. Зачем полный вывод git diff (все файлы сразу) смотреть — не знаю.
                              0
                              Когда вы принимаете чужие изменения, гораздо проще смотреть полный Git-diff, чем открывать каждый файл в редакторе (предварительно записав куда то список измененных файлов) и читать их Git-diff.
                                0
                                Да, об этом я не подумал. Никогда не работал мэнтэйнером, для них действительно полезно.
                                  0
                                  В планах интегрировать vim_git с github или bitbucker так, чтобы можно было комментировать строки кода прямо из Vim. Не знаю, это фишка Git или конкретно этих веб-сервисов, но очень удобная.
                                    0
                                    Git тут абсолютно не при чём. Встроенная возможность что‐то комментировать есть только в fossil, но, насколько я знаю, там только встроенные в репозиторий wiki и issue tracker. Довольно долгое время bitbucket не давал возможность комментировать строки изменений.

                                    Кстати, насколько я знаю, ни один из сервисов такой возможности не имеет: я знаю комментарии к строкам в различиях изменения, к самому изменению и к строкам в аггрегированных различиях PR, но не к строкам кода.

                                    Кстати, а как вы будете делать такую возможность: system('curl') или +python/+ruby/…? Без просмотра имеющихся комментариев возможность не такая полезная.
                                      0
                                      Кстати, а как вы будете делать такую возможность: system('curl') или +python/+ruby/…?

                                      Пока не знаю. Предпочтения я отдаю кроссплатформенным, легковесным и нативным решениям.
                                    0
                                    Ещё git diff полезен для самопроверки перед созданием изменения. Я даже в моём aurum автоматически открываю буфер с diff при фиксировании изменения. Разве вам никогда не хотелось окинуть взглядом все изменения, чтобы посмотреть (или поискать), не забыли ли вы где‐то отладочный print? Или (в случае с частичной фиксацией (пример: git add -p + git commit, но я использую другой интерфейс)) — проверить, что вы ничего не забыли из того, что хотели и забыли всё, что не хотели зафиксировать.
                                      0
                                      С этим я не спорю — полезный и часто используемый кейс. Я к тому, что в редакторе вывод diff всех файлов будет неудобен, на мой взгляд. Вызываю обычно из соседнего терминала в tmux/byobu.

                                      Посмотрел — fugitive умеет и такой вывод (как в терминале). Он предоставляет обёртку над командами, которые напрямую не визуализирует. В данном случае :Git diff. Неудобно, что он как бы сворачивает vim и показывает это на весь терминал. Создать новый split и показать в нём было бы полезнее.
                                        0
                                        О том и речь, fugitive просто реализует Vim команды, которые выполняют git в терминале. Не вижу удобство такого плагина, когда есть :!git…
                                        0
                                        Мой aurum находит самое большое окно по соседству с окном (это не единственный вариант: можно и split, а можно и отключить), в котором предполагается писать пояснения к изменению и открывает diff там. При отмене и фиксации изменения diff пропадает, предыдущий буфер возвращается на место (на случай если Delphinum будет делать такое в своём дополнении, напомню про &bufhidden: буфер нужно скрывать; и я читал людей, которые не используют set hidden).

                                        Если вы посмотрите diff в командной строке, то он что‐то безвозвратно заменит. Иногда настолько безвозвратно, что и scrollback buffer не поможет. И ещё там нет свёрток (aurum имеет также в своём составе ftplugin, добавляющий свёртки к diff’ам: bitbucket.org/ZyX_I/aurum/src/ee5d7e8121f3e7380eb5abedf42895346294cccc/ftplugin/diff.vim, можно использовать без aurum и его зависимостей, что даже удивительно (обычно я пишу всё с зависимостью, как минимум, от frawor)).

                                        Git diff, насколько я понимаю, практически напрямую вызывает :!git diff. Бесполезная возможность по мне.
                                          0
                                          И ещё там нет свёрток

                                          Vim из коробки умеет свертки diff.

                                          Git diff, насколько я понимаю, практически напрямую вызывает :!git diff. Бесполезная возможность по мне.

                                          Если выбрасывать его в Vim, то гораздо удобнее, чем читать в терминале, ибо подсветка, сверки, vim-like управление и т.д.
                                            0
                                            Вообще‐то я говорил про терминал. Но Vim всё равно не умеет свёртки из коробки: code.google.com/p/vim/source/browse/runtime/ftplugin/diff.vim?r=bfc3682510d68e594ef3a81ffaaf16468c8276e2. Где здесь свёртки:
                                            " Vim filetype plugin file
                                            " Language: Diff
                                            " Maintainer:   Bram Moolenaar <Bram@vim.org>
                                            " Last Change:  2005 Jul 27
                                            
                                            " Only do this when not done yet for this buffer
                                            if exists("b:did_ftplugin")
                                              finish
                                            endif
                                            let b:did_ftplugin = 1
                                            
                                            let b:undo_ftplugin = "setl modeline<"
                                            
                                            " Don't use modelines in a diff, they apply to the diffed file
                                            setlocal nomodeline
                                            
                                            ?
                                            Если выбрасывать его в Vim, то гораздо удобнее, чем читать в терминале, ибо подсветка, сверки, vim-like управление и т.д.
                                            Именно об этом я и говорю.
                                              0
                                              Где здесь свёртки?

                                              Я об этом:
                                              Vim-diff

                                                0
                                                Я я о свёртках diff’ах. Не в vimdiff, он тут совсем не при чём, а в буферах с патчем и filetype=diff.
                                                  0
                                                  Есть простые решения, но зачем, если git diff сам обрезает файл, оставляя только строки с изменениями.
                                                    0
                                                    Вообще‐то в этой ветке обсуждался полный diff. И вы сами говорили, зачем такое нужно: habrahabr.ru/post/261783/#comment_8488049. И я говорил, что полный diff у меня для review. Свёртки пригождаются при просмотре больших diff’ов.
                                                      0
                                                      Так я и говорю — зачем свертки, если git diff сам отрезает строки, которые расположены слишком далеко от измененных строк.
                                                      0
                                                      И вы явно не поняли, что сворачивается. А сворачиваются во‐первых, каждый файл отдельно (первый уровень). Во‐вторых, каждый кусок (hunk) — то, что имеет строку вида @@ -3491,3 +3491,4 @@ в качестве заголовка (последняя свёртка полезна в основном только если вы использовали --show-c-function или аналог при создании diff’а) — второй уровень.
                                                        0
                                                        Вот так, конечно, намного понятнее )
                        0
                        Кстати, есть одна возможность в aurum, которую я, на момент его разработки, нигде не видел и использую часто: AuHyperlink, копирующая в буфер обмена различные URL: обычно ссылки на HTML или RAW версии файла, первые — часто с конкретными указаниями на строку, ещё есть clone и push URL (не использовались почти никогда, т.к. URL’ы от GH и BB я могу и по памяти написать), ссылки на просмотр изменения в веб‐интерфейсе (использовались редко), ссылка на лог (использовалась практически только для тестов). Fugitive имеет вместо этого :Gbrowse, но я совершенно не понимаю, зачем (зато есть :Gbrowse!, использующий clipboard; AuHyperlink имеет бесконечно больше двух вариантов использования, но только один легко доступен по‐умолчанию). (Ещё fugitive имеет :Gbrowse {rev}@{remote}, а у меня @{remote} нет, что нехорошо.)
                          –2
                          интересно

                          Only users with full accounts can post comments. Log in, please.