У Git есть строгие обязательства по обратной совместимости: многие продвинутые возможности скрыты за разнообразными опциями, а не применяются как поведение по умолчанию. К счастью, Git также поддерживает и алиасы, так что вы можете создавать свои собственные команды, которые делают всю характерную для Git магию. Под катом — подборка полезных (или как минимум забавных) алиасов, определённых в моём .gitconfig.

git please


$ git config --global alias.please 'push --force-with-lease'

Каждому разработчику приходилось хотя бы раз общаться со своим тимлидом на тему принудительного пуша (force pushing) в общую ветку (не делайте этого). Ребейз (rebasing), внесение правок и squash — всё это забавно до тех пор, пока вы не перезапишете часть общей истории и не раскидаете дублирующиеся коммиты по всему репозиторию. К счастью, Git не позволит вам невольно перезаписать историю на сервере. Вам придётся явным образом передать в git push опцию --force, чтобы доказать серьёзность своих намерений. Но принудительный пуш — это грубый подход: вы затаптываете локальной версией вышерасположенную ветку, и все изменения, которые вы к тому моменту не подтянули (fetch), будут стёрты из истории.



Git-опция --force-with-lease действует гораздо аккуратнее: она проверяет, чтобы ваша локальная копия ref’а была самой свежей, прежде чем накатить её. Это означает, что вы как минимум подтянули все изменения, которые собираетесь затоптать. Но чтобы не писать каждый раз git push --force-with-lease, я сделал для этой строки алиас: git please

git commend


$ git config --global alias.commend 'commit --amend --no-edit'

Бывало так, что вы закоммитили и тут же сообразили, что забыли проиндексировать (stage) файл? Больше не нужно об этом беспокоиться! Алиас git commend тихо прикрепляет к последнему созданному вами коммиту все проиндексированные файлы, повторно используя уже имеющееся сообщение о коммите.

$ git add Dockerfile
$ git commit -m ‘Update Bitbucket pipeline with new Docker image’
# (facepalm)
$ git add bitbucket-pipelines.yml
$ git commend

git it


$ git config --global alias.it '!git init && git commit -m “root” --allow-empty'

Первому коммиту в репозитории нельзя сделать ребейз, как обычному. Поэтому рекомендуется в качестве корневого создавать пустой коммит. Алиас git it инициализирует ваш репозиторий и за одну операцию создаёт пустой корневой коммит. И когда вы в следующий раз запустите проект, то не надо просто добавлять его в систему управления версиями: выполните git it!

$ cd shiny-new-thing
$ git it
Initialized empty Git repository in /shiny-new-thing/.git/
[master (root-commit) efc9119] root

git staaash


$ git config --global alias.stsh 'stash --keep-index'
$ git config --global alias.staash 'stash --include-untracked'
$ git config --global alias.staaash 'stash --all'

git stash — одна из самых восхитительных и полезных Git-команд. Она регистрирует все изменения, вносимые в отслеживаемый файл в вашем рабочем дереве, и скрывает их для последующего использования, а вам показывает чистое дерево, чтобы вы могли спокойно работать с другой его частью. Но если вы создали новые файлы и ещё не проиндексировали их, то по умолчанию git stash их не тронет, поэтому у вас будет неопрятное рабочее дерево. Соответственно, по умолчанию не скрывается и содержимое неотслеживаемых или игнорируемых файлов.

Я сделал несколько удобных алиасов для разных вариантов git stash, в зависимости от того, какие биты вашего рабочего дерева нужно скрыть:

git stsh      # скрывает только непроиндексированные изменения в отслеживаемых файлах
git stash     # скрывает все изменения в отслеживаемых файлах 
git staash    # скрывает неотслеживаемые и отслеживаемые файлы
git staaash   # скрывает игнорируемые, неотслеживаемые и отслеживаемые файлы

Если сомневаетесь в выборе, то самый длинный алиас (git staaash) всегда сможет восстановить рабочее дерево состояния свежего клона вашего репозитория.

git shorty


$ git config --global alias.shorty 'status --short --branch'

Я запускаю git status чаще любой другой Git-команды. Встроенная помощь в Git за последние годы стала куда удобнее, что очень хорошо для начинающих, но для более опытных пользователей информация слишком многословна. Например, git status объясняет мне в 12 строках, что у меня пара индексированных, неиндексированных и неотслеживаемых изменений:

$ git status
On branch master
Changes to be committed:
  (use “git reset HEAD <file>…” to unstage)
    modified: package.json
Changes not staged for commit:
  (use “git add <file>…” to update what will be committed)
  (use “git checkout -- <file>…” to discard changes)
    modified: package.json
Untracked files:
  (use “git add <file>…” to include in what will be committed)
    index.js

Всё то же самое git shorty говорит мне тремя строками:

$ git shorty
## master
AM test
?? .gitignore

Для краткости я сделал это в виде алиаса git st, не смог остановиться.

git merc


$ git config --global alias.merc 'merge --no-ff'

Если вы используете обычный рабочий процесс ветвления без ребейза, то будет не лучшим решением запускать стандартный git merge для слияния веток с фичами с мастер-веткой. Если не добавить к этой команде опции, то по умолчанию станет использоваться стратегия слияния --ff, при которой новый коммит слияния будет создан только в том случае, если в мастер-ветке нет новых изменений. В противном случае мастер-ветка просто «перемотается» до места последнего коммита в вашей ветке. Лишь иногда, создавая коммит слияния, при просмотре Git-истории бывает непросто сказать, какой код был разработан в какой ветке.



git merc использует стратегию --no-ff, при которой всегда создаётся коммит слияния.



Между прочим, --no-ff всегда используется по умолчанию в ходе слияния pull request’ов в Bitbucket.

git grog


$ git config --global alias.grog 'log --graph --abbrev-commit --decorate --all --format=format:"%C(bold blue)%h%C(reset) - %C(bold cyan)%aD%C(dim white) - %an%C(reset) %C(bold green)(%ar)%C(reset)%C(bold yellow)%d%C(reset)%n %C(white)%s%C(reset)"'

Мой алиас git grog (или graphical log) в последние годы разросся настолько, что я больше не уверен, будто точно знаю, что он делает. Но выглядит красиво:



Для сравнения, вот стандартный git log:



Там доступны все виды удобных форматов, так что форкайте вышеуказанную команду и пользуйтесь на здоровье!

Для поклонников GUI


Если вы поклонник Git GUI и работаете под Mac или Windows, то, возможно, вы используете наш бесплатный Git-клиент Atlassian SourceTree. Если да, то примените описанные в этой статье алиасы, создав новое кастомное действие — можно назначить комбинацию клавиш — в настройках SourceTree:



Это действие запускается с помощью меню (Actions > Custom Actions) или клавиатурной комбинации:



Приятного алиасинга!
Поделиться с друзьями
-->

Комментарии (40)


  1. develop7
    07.01.2017 20:43
    +9

    очередная кучка алиасов
    нет бы в апстрим протащить хотя бы какой-нибудь (хотя бы git it в качестве поведения по умолчанию)


    inb4: я понимаю, что это сложно


    1. wing_pin
      09.01.2017 12:21

      Прошу прощения, но я не вижу никакого смысла протаскивать это в апстрим, если все это можно реализовать в виде алиасов. Не стоит плодить сущности без особой нужды на то.


      1. develop7
        09.01.2017 13:13
        +2

        все это можно реализовать в виде алиасов

        своих собственных алиасов у каждого второго пользователя


  1. eugenebabichenko
    07.01.2017 21:21
    +57

    Название вводит в заблуждение. Это не подборка команд, а подборка алиасов, которые отдельно взятой группе пользователей кажутся удобными.


    1. alexac
      07.01.2017 23:53
      +26

      Действительно, ожидал увидеть мясо про rev-parse, for-each-ref, cat-file, rebase --onto, fetch +, update-ref, show-ref… А тут просто пачка алиасов.


      1. AlexWoodblock
        08.01.2017 08:17
        +1

        Можете порекомендовать статьи, в которых более-менее доступно разжевано это самое «мясо»?


        1. alexac
          08.01.2017 11:15

          К сожалению нет. Небольшая часть этого есть в pro git. Оставшаяся же часть осваивается посредством долгого и вдумчивого ковыряния в git на практике.


    1. Halt
      08.01.2017 07:36
      +7

      Это еще не самое страшное. Хуже, когда такой любитель алиасов начинает их втыкать в продуктовые и CI скрипты, потому что «так удобнее».


      1. develop7
        11.01.2017 18:02
        +3

        К слову, я в скриптах пользуюсь исключительно длинными ключами команд (git commit --message="$ABYRVALG" вместо git commit -m "$ABYRVALG")


        1. Halt
          11.01.2017 18:56
          +2

          Разумеется. Скрипт пишется один раз, а читается несколько, да еще и через пол года-год.


  1. afanasiy_nikitin
    07.01.2017 22:20
    -2

    немного полезных алисасов от проекта oh-my-zsh: https://github.com/robbyrussell/oh-my-zsh/wiki/Cheatsheet


  1. worldmind
    07.01.2017 22:41
    +3

    Самый нужный алиас это «кто первым добавил эту строку», пока что-то всё что попадалось как-то криво работало или не работало


  1. inook
    07.01.2017 22:43
    -14

    Использую git-flow и уже давно забыл о боли.


    1. f0rk
      08.01.2017 21:26

      Хмм… На Хабре не любят git-flow?


      1. ZyXI
        08.01.2017 21:37
        +2

        На хабре не любят бессмысленные, да ещё и не относящиеся к статье комментарии. Вот написал бы inook, какое отношение git?flow имеет к статье и почему он «забыл о боли» — минусов было бы меньше.


        1. f0rk
          09.01.2017 12:22
          +1

          Думаю, потому что мерж там по умолчанию --no-ff и не нужно вспоминать, с какой опцией -d или -D нужно удалять слитые ветки. Ну и в принципе, стандартизированный flow и инструменты для него освобождают мозг для более важных задач.


          1. ZyXI
            09.01.2017 17:52

            staaash, grog, commend, shorty, please? Насколько мне известно, git?flow заменяет только merc и it. Кроме того, совет «используйте git?flow» подходит только для новых проектов или проектов, где он уже используется.


  1. NeoCode
    07.01.2017 23:53
    +2

    А я использую пока лишь TortoiseGit в самом примитивном виде, просто для себя лично, локально. Без веток, только фиксацию изменений, чтобы не потерять историю изменений и чтобы было куда откатиться если чего поломаю. На предыдущей работе был svn, на новой ничего — а без контроля версий как-то уже некомфортно :)


    1. YourChief
      08.01.2017 00:22
      +4

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


      1. Sirikid
        08.01.2017 00:52
        +1

        Плюсую, схема «по ветке для фичи/фикса» работает.


    1. Cozi
      10.01.2017 21:30

      на новой ничего

      Т.е. вы один что-то разрабатываете на новой работе, или все-таки у вас там команда и вы живете без системы контроля версий?


  1. apachik
    08.01.2017 01:19
    +1

    добавлю от себя еще две полезных команды

    показать ветки в которые вошел данный коммит:
    git branch -a --contains $SHA
    (можно добавить в sourceTree customAction и дергать мышкой из гуи)

    показать разницу в коммитах между двумя бранчами
    git log --oneline release/release_1.23 ^release/release_1.22


    1. amaslenn
      08.01.2017 11:42
      +1

      А можно как-то проверить коммиты, которые были перенесены в другую ветку с помощью cherry-pick? sha у них отличаются, конечно. Можно попробовать patch-id, но это несколько затратно перебирать много коммитов.


      1. Halt
        08.01.2017 19:47

        Если в коммитах проставляется герритовский ChangeId, то поиском по коммитам с тем же ChangeId. Это можно сделать например с помощью git grep. Но это если вы знаете копии чего вы хотите искать.

        В общем случае видимо только скриптить перебор.


      1. tatalame
        08.01.2017 20:19
        +1

        Есть команда cherry, который делает обратное — показывает коммиты, которых еще нет в другой ветке, может быть она подойдет? Правда, для определения коммитов используется тот же patch-id, подозреваю, который вы сочли дорогим.


        1. amaslenn
          09.01.2017 09:46

          Эта команда, как минимум, уже готова. Спасибо, попробую.


  1. Badja
    08.01.2017 02:53
    -4

    эх, а я так и не добрался до Git :(


    1. Danik-ik
      08.01.2017 15:35
      +1

      Зря. Я начал использовать vcs ещё когда работал на заводе, где никому ничего не надо было и всякий работал как хотел. Тогда это была cvs. Я даже ветки не использовал, но уже забыл про "ё-моё, что ж я наделал-то", "откуда это здесь" и "что я имел в виду". Теперь однозначно git, ветки, упрощённый git flow — даже при том, что владею кодом единолично. Зато нет проблем разрабатывать несколько функциональных едиц, радикально переделывать код, но при этом не терять возможности выпустить хотфикс менее, чем за полчаса. Это реально стоит времени на обучение.


      1. Badja
        08.01.2017 16:31
        +2

        Да, спасибо за информацию, думаю в скором будущем начну обучение.


        1. VolCh
          08.01.2017 18:32
          +1

          Начните прямо сейчас! А то в ближайшем будущем пожалеете, что тянули время. Буквально пяток команд достаточно изучить для начала работы.


  1. poxu
    08.01.2017 11:11
    +1

    Я очень старался, но так и не понял отрывок про git shorty. В полном выводе git status есть информация про package.json и index.js, а в выводе git shorty только какой-то test и .gitignore. Может кто-нибудь пояснить, что имел в виду автор?


    1. farcaller
      08.01.2017 13:23
      +1

      Автор опечатался, скорее всего, и сделал копипасту с разных репозиториев.


      % git status
      On branch master
      Changes to be committed:
        (use "git reset HEAD <file>..." to unstage)
      
          deleted:    a
      
      Changes not staged for commit:
        (use "git add <file>..." to update what will be committed)
        (use "git checkout -- <file>..." to discard changes in working directory)
      
          modified:   b
      
      Untracked files:
        (use "git add <file>..." to include in what will be committed)
      
          c
      
      % git status --short --branch
      ## master
      D  a
       M b
      ?? c


  1. guai
    08.01.2017 13:57
    +4

    я вижу ересь! вся суть гита в том и состоит, чтобы глумиться над теми, кто не смог пройти по минному полю системы его команд.


  1. Dreyk
    08.01.2017 15:32
    +5

    Первому коммиту в репозитории нельзя сделать ребейз, как обычному.

    git rebase -i --root


  1. seregamorph
    08.01.2017 16:51

    soft reset последнего коммита с выводом статуса


    git config --global alias.rs1 '!git reset --soft HEAD~1 && git status --short --branch'


  1. r9dman
    09.01.2017 00:24

    git status --short --branch
    

    =
    git status -sb
    


    можно спокойно обойтись и без алиаса


    1. aso
      09.01.2017 08:09
      +2

      git status — это длинно.
      git st — наше всё! (тяжкое наследие svn, я понимаю).


  1. NeonXP
    09.01.2017 02:06

    Как же приятно узнавать что-то новое о старом добром, казалось бы, вдоль и поперёк известном инструменте!


  1. faost
    10.01.2017 15:38
    +1

    С алиасов гита перешел на алиасы из oh-my-zsh https://github.com/robbyrussell/oh-my-zsh/blob/master/plugins/git/git.plugin.zsh — очень рекомендую, хорошо продуманы. Заменили мне все комманды гита, которые я постоянно использую в работе, избавив меня от головной боли с продумыванием имен и подбором параметров для команд, когда я пытался сам сделать хорошую систему под себя.


  1. Zverik
    11.01.2017 11:47
    +3

    Сегодня добавил себе ещё алиас git branches:

    git config --global alias.branches "for-each-ref --sort=committerdate refs/heads/ --format='%(HEAD) %(color:yellow)%(refname:short)%(color:reset) - %(color:red)%(objectname:short)%(color:reset) - %(contents:subject) - %(authorname) (%(color:green)%(committerdate:relative)%(color:reset))'"
    


    Выводит список локальных веток, отсортированный по времени, с последними коммитами и их датами.