Командный интерпретатор bash позволяет задавать произвольные алиасы для разных команд и выражений. Алиасы не являются командами сами по себе, но им, как и командам, можно передавать аргументы. Алиасы позволяют сделать вызов громоздких команд очень простым, с легко запоминающимися названиями.

Использовать Git я привык исключительно из консоли, но на ввод длинных команд с разными аргументами тратится значительное количество времени. Поэтому я ввёл практику использования алиасов. Для безопасных команд я использовал короткие алиасы, которые по сути стали горячими клавишами, а для функциональных — простые короткие слова из состава команд Git. Если команда опасная, то можно сделать её в два слова, написанных через дефис, для исключения случайного ввода. На самом деле, использование алиасов для работы с Git широко практикуется, я решил лишь преподнести отдельный вариант подборки алиасов, которые для меня оказались очень удобными.

Формат задания алиаса имеет следующий вид:

alias name="<выполняемый код>"

Основной проблемой алиасов является то, что они не подхватываются автоматически механизмом автодополнения кода. Их написание отличается от тех команд, которые зарегистрированы в системе автодополнения, поэтому приходится дополнительно регистрировать алиасы, назначая им соответствующие спецификации автодополнения (compspec) через встроенную в bash команду complete. В случае с Git над complete существует обёртка __git_complete, в которую необходимо передавать предопределённые функции-обёртки, начинающиеся с префикса _git_ и оканчивающиеся названием подкоманды git. В Ubuntu весь связанный с этим код можно посмотреть в файле /usr/share/bash-completion/completions/git.

Алиас

Действие

f

Получить изменения с сервера

s

Просмотреть текущее состояние локального репозитория

ss

Просмотреть текущее состояние локального репозитория и количество изменённых строк

d

Просмотреть изменения, сделанные в файлах и ожидающие подтверждения, в стандартном diff-формате

dd

Просмотреть изменения, сделанные в файлах и ожидающие подтверждения, с выделением одним только цветом

l

Список последних коммитов в кратком формате.

ll

Список последних коммитов с развёрнутой информацией о них.

go или gg

Переход на другую ветку или коммит, создание новой ветки с опцией -b.

pull

Получить изменения с сервера и влить их в текущую ветку.

commit

Сделать коммит (зафиксировать изменения).

add

Добавить файлы или изменения в будущий коммит.

reset

Отменить добавление изменений в будущий коммит.

push

Отправить новые коммиты на сервер.

push-fix

Отправить коммиты на сервер с перезаписью их истории, если другие люди не успели отправить туда свои коммиты.

merge

Влить заданную ветку в текущую.

amend

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

rebase

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

branch

Переименовывание или удаление локальной ветки

pick

Применить в текущей ветке отдельные существующие коммиты.

stash

Сохранить свои текущие изменения во временное хранилище.

apply

Применить свои текущие изменения из временного хранилища, но не удалять и оттуда.

pop

Забрать свои изменения из временного хранилища и применить их.

Ниже приведено примерное содержимое файла ~/.bash_aliases с основными алиасами Git и кодом их автоматической регистрации в механизме автодополнения командой строки.

#!/bin/bash

alias f="git fetch --tags"
alias s="git status"
alias ss="git status && git diff --shortstat"
alias d="git diff"
alias dd="git diff --word-diff=color"
alias l="git log -n 20 --graph --pretty=format:'%Cred%h%Creset %an: %s / %Cgreen%cr%Creset %Creset %C(yellow)%d%Creset' --abbrev-commit --date=relative"
alias ll="git log"
alias go="git checkout"
#или alias gg="git checkout"
alias pull="git pull"
alias commit="git commit"
alias add="git add"
alias reset="git reset"
alias push="git push"
alias push-fix="git push --force-with-lease"
alias merge="git merge"
alias amend="git commit --amend"
alias rebase="git rebase"
alias branch="git branch"
alias pick="git cherry-pick"
alias stash="git stash"
alias apply="git stash apply"
alias pop="git stash pop"

# Регистрируем алиасы в системе автодополнения
git_completions="/usr/share/bash-completion/completions/git"
if [ -f "${git_completions}" ]; then
    source "${git_completions}"

    # Получаем массивы алиасов и соответствующих им команд git
    cmds=( $(alias | grep -v ss | grep -Po '(?<=git )[\w-]+' | sed -r 's/[ -]+/_/g') )
    aliases=( $(alias | grep -v ss | grep git | grep -Po '(?<=alias )\w+') )

    # Регистрируем каждый алиас
    for (( i = 0; i < ${#aliases[@]}; i++ )); do
        a="${aliases[$i]}"
        cmd="${cmds[$i]}"
        __git_complete "${a}" _git_"${cmd}"
    done
fi

Для того, чтобы файл с алиасами применялся при входе в систему, необходимо добавить его подключение в файл ~/.bashrc с помощью команды source (или .). Файл ~/.bashrc запускается на исполнение всегда при старте командного интерпретатора bash, поэтому если файл редактировался из консоли, потребуется её заново открыть или запустить вложенный командный интерпретатор bash.

if [ -f ~/.bash_aliases ]; then
  . ~/.bash_aliases
fi

Алиасы s, d и l простые, дают необходимый минимум информации. Задумка двухбуквенных в том, чтобы дать слегка больше информации, если это требуется. С помощью f можно получить последние изменения в репозитории и влить их в текущую ветку с помощью pull или pull -r. Через l можно посмотреть, что за новые коммиты прилетели в ветку, или что было последним из изменений, а через ll — подробно изучить коммиты. Переключиться на другую ветку можно через go, создать новую ветку можно через go -b. При создании коммита, в общем случае, сначала вводится s, проверяется на какой мы ветке, какие файлы требуется добавить, затем d, чтобы проверить свои изменения. Через add добавляются файлы (или add -i для выбора отдельных изменений в файлах), через commit -m создаётся новый коммит. Если вдруг в тексте сообщения коммита оказалась опечатка, можно быстро всё поправить через amend. Если в main-ветку успели прилететь новые коммиты, можно сделать rebase main. И потом сделать push. Если ветка своя собственная, то можно делать rebase -i с исправлениям прошлых коммитов и отправить модифицированные коммиты через push-fix.

Если шла работа, но срочно понадобилось переключиться на другую ветку, можно временно убрать свои изменения через stash, переключиться на другую ветку через go. Потом можно вернуть изменения с помощью apply или pop. Отдельные коммиты из других веток можно применять с помощью pick, также это может быть полезным, если случайно сделать изменения в отделённом HEAD (например, в подмодуле).

Алиасы могут совпадать с существующими командами. Если такие команды обычно не используются, то это проблемой не является. Если же команды понадобятся, то в случае исполняемых файлов всегда можно указать полный путь к файлу. Не будет проблем и с командами, которые запускаются от имени суперпользователя, поскольку алиасы прописаны лишь для непривилегированного пользователя. Если используется язык Go, то с использованием алиаса go могут возникнуть проблемы. В качестве решения можно изменить алиас на gg или gc, либо же сделать алиас golang для команды go. Здесь кому как удобнее.

В Ubuntu 21.10 при использовании алиаса над git checkout выводятся сообщения об ошибках. Происходит это из-за того, что одна из переменных в целочисленных сравнениях оказывается пустой. Вариантом подавления вывода ошибок является замена в файле /usr/share/bash-completion/completions/git сравнения через квадратные скобки на арифметическое сравнение через двойные скобки, например, (( var1 < var2 )), в которых можно использовать названия переменных без предшествующего знака $. Такое исправление работает и в zsh, на который автодополнение тоже рассчитано.

Патч, решающий проблему
--- /usr/share/bash-completion/completions/git  2021-08-09 15:29:27.000000000 +0300
+++ ./git       2022-04-08 23:32:38.501198226 +0300
@@ -1011,7 +1011,7 @@
        if [ "$cmd" = "remote" ]; then
                ((c++))
        fi
-       while [ $c -lt $cword ]; do
+       while (( c < cword )); do
                i="${words[c]}"
                case "$i" in
                --mirror) [ "$cmd" = "push" ] && no_complete_refspec=1 ;;
@@ -1187,7 +1187,7 @@
        done
        local wordlist="$1"
 
-       while [ $c -lt $cword ]; do
+       while (( c < cword )); do
                for word in $wordlist; do
                        if [ "$word" = "${words[c]}" ]; then
                                if [ -n "${show_idx-}" ]; then
@@ -1221,7 +1221,7 @@
        done
        local wordlist="$1"
 
-       while [ $c -gt "$__git_cmd_idx" ]; do
+       while (( c > __git_cmd_idx )); do
                ((c--))
                for word in $wordlist; do
                        if [ "$word" = "${words[c]}" ]; then
@@ -1283,7 +1283,7 @@
 __git_has_doubledash ()
 {
        local c=1
-       while [ $c -lt $cword ]; do
+       while (( c < cword )); do
                if [ "--" = "${words[c]}" ]; then
                        return 0
                fi
@@ -1449,7 +1449,7 @@
 {
        local i c="$__git_cmd_idx" only_local_ref="n" has_r="n"
 
-       while [ $c -lt $cword ]; do
+       while (( c < cword )); do
                i="${words[c]}"
                case "$i" in
                -d|-D|--delete|-m|-M|--move|-c|-C|--copy)
@@ -2479,7 +2479,7 @@
 __git_config_get_set_variables ()
 {
        local prevword word config_file= c=$cword
-       while [ $c -gt "$__git_cmd_idx" ]; do
+       while (( c > __git_cmd_idx )); do
                word="${words[c]}"
                case "$word" in
                --system|--global|--local|--file=*)
@@ -3213,7 +3213,7 @@
 _git_tag ()
 {
        local i c="$__git_cmd_idx" f=0
-       while [ $c -lt $cword ]; do
+       while (( c < cword )); do
                i="${words[c]}"
                case "$i" in
                -d|--delete|-v|--verify)
@@ -3388,7 +3388,7 @@
        local __git_C_args C_args_count=0
        local __git_cmd_idx
 
-       while [ $c -lt $cword ]; do
+       while (( c < cword )); do
                i="${words[c]}"
                case "$i" in
                --git-dir=*)

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

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


  1. sergio_nsk
    13.04.2022 10:31
    +16

    Не надо так делать. dd - это программа, go - это компилятор, ll - часто ls -l, reset - это команда шелла. Неужели сложно написать git в начале?

    Примерно так

    git() {
        if [[ $@ == "f" ]]; then
            command git fetch --tags
        elif [[ $@ == "s" ]]; then
            command git status
        else
            command git "$@"
        fi
    }

    Bash documentation:

    For almost every purpose, shell functions are preferred over aliases.


    1. E_STRICT
      13.04.2022 10:52
      +7

      Зачем вообще использовать Баш вместо Гит алиасов?


      1. 13werwolf13
        13.04.2022 11:44
        +1

        возможно потому что bashrc/zshrc/etc с собой таскать проще чем bashrc+gitconf+ещёпачкувсего


        1. E_STRICT
          13.04.2022 11:49
          +2

          Про какую пачку речь? Все алиасы хранятся в одном .gitconfig файле.


          1. 13werwolf13
            13.04.2022 11:49

            но кроме гита используется ещё 100500 софтин и утилит на постоянной основе


            1. storoj
              13.04.2022 22:00

              можно сделать git init в домашней директории и синхронизировать все свои настройки на всех компьютерах


              1. 13werwolf13
                14.04.2022 06:25

                увы но нет

                прийдётся писать огромный .gitignore файлик в котором заигнорено будет больше чем попадёт в репу потому что есть некотоорые софтины к примеру гуглохром запуск двух экземпляров которых одновременно на разных тачках приведут к проблемам, а есть софтины дотфайлы которых нет смысла таскать с собой везде (те кто пишет на ноде, го или расте сейчас дружно закивали головой). к тому же git не автоматизирует синхронизацию а лишь уменьшает кол-во действий для неё

                я использую resilio (да мне просто лень переехать на synthing) синхроню отдельную директорию из которой часть конфигов отправляю в хомяк симлинками а часть через mount bind, и это тоже костылизм потому что некоторые софтины не могут работать с конфигом через симлинк (примеры rclone и cherrytree). приходится постоянно руками (ну не совсем руками, через ansible но всё равно не автоматически) поддерживать все нужные связи между папкой синхрона и хомяком на разных тачках (у меня это два pc и два ноута).

                давно есть идея создать для этого инструмент который бы заранее знал каким конфигам можно симлинк а каким маунтбинд и при появлении определённого конфига на одной тачке делал всё необходимое на второй. но пока это идея в зачаточной стадии


                1. storoj
                  14.04.2022 14:36

                  Есть настройка ignore untracked: пока явно не начнёшь трекать какой-нибудь конфиг, git status будет пуст.


                  1. 13werwolf13
                    14.04.2022 14:44

                    не знал о таком сыпасиба.


                    1. storoj
                      14.04.2022 14:47

                      git config --local status.showUntrackedFiles no


  1. PlatinumThinker
    13.04.2022 10:33
    +1

    Есть уже подобный проект bash-it. Только там постарались избежать конфликтов с программами и существующими алиасами.
    Есть аналогичные алиасы в oh-my-zsh. Хотя конечно считаю что это то еще зло, т.к. легко можно ошибиться.


  1. brownfox
    13.04.2022 13:54

    Большая часть алиасов выполнена по схеме alias n='git n'

    Идея настолько очевидная, что ценность статьи не очень понятна :)


    1. andrey0700 Автор
      13.04.2022 19:33

      Поделиться существующей практикой и идеями. Я уже достаточно давно использую алиасы, они оказались намного удобнее, чем вводить команды целиком, причём именно в таком виде, легко запоминаются, нет никакой путаницы, действия доводятся до автоматизма. Собственно, основной моей деятельностью в консоли является работа с git.

      Ну и в интернете список алиасов всегда под рукой. :)


  1. randomsimplenumber
    13.04.2022 13:54

    dd и reset - существующие утилиты, к git никак не относятся.


    1. andrey0700 Автор
      13.04.2022 19:15
      -3

      dd используется или через sudo, или от имени суперпользователя. В обоих случаях алиасы работать перестают, поскольку прописаны у непривилегированного пользователя. На моей практике у меня не возникало проблем с существующими командами.

      Если алиасы совпадают с командами, которые в норме не используются, то проблем нет. Именно поэтому я лишь про команду go упомянул.

      Отразил данную информацию в статье.


      1. randomsimplenumber
        13.04.2022 23:44
        +2

        dd используется или через sudo, или от имени суперпользователя

        dd используется по разному. Git, кстати, тоже. А делать алиасы, совпадающие с существующими программами, это вредительство.


        1. andrey0700 Автор
          14.04.2022 07:40

          Чем же это может вредить? С таким же успехом навредить может кастомизация горячих клавиш. Мне не нравится F2 для переименовывания файлов, я её на другое действие переназначаю. Алиасы предназначены для катомизации терминала под себя, как будет удобно именно отдельному человеку. Из людей, с кем я работал, один взял мой вариант, а другой сделал себе свои, совсем другие, алиасы.

          Что касается пересечений с названиями команд, то писать /bin/dd будет даже более хорошей практикой в скриптах, поскольку исключает пересечение с алиасами. Если часто требуется выполнять эту команду из консоли, то можно не прописывать автоматическое подключение алиасов в bashrc, а инициализировать их раз в день в рабочей консоли отдельной командой. Либо же подобрать другое название, например, dc (diff, color).

          И если уж называете вредительсвом, то давайте расшифровку того, что имеете в виду, какие именно случаи, и какой вред в этих случаях алиасы могут нанести.


          1. wibotwi
            14.04.2022 08:55

            В скриптах алиасы не работают. Вы можете в скриптах продолжать писать dd.


            1. andrey0700 Автор
              14.04.2022 19:42

              Большое спасибо за пояснение! Действительно. Этого момента не знал.


          1. E_STRICT
            14.04.2022 10:51

            писать /bin/dd будет даже более хорошей практикой в скриптах, поскольку исключает пересечение с алиасами

            Такой скрипт не будет портабельным, потому абсолютный путь может отличаться на разных системах. Чтобы игнорировать алиас или шел функцию достаточно поместить название команды в кавычки либо запускать через command.


          1. randomsimplenumber
            14.04.2022 14:34

            Чем же это может вредить?

            Ну, можно представить кулхацкера, который на своей любимой системе виндовз сделал глубокий апгрейд: поменял картинки и подписи на всех ярлыках, потому что ему удобно, когда вместо иконки 'мой компьютер' - мусорная корзина. Вредит он только себе - с такими нестандартными привычками за любым другим компьютером ему будет неудобно.


  1. bullkasizumom
    13.04.2022 18:48
    +2

    почему бы не использовать .gitconfig для алиасов и не плодить конфликты в bash командах? или это очередная статья из разряда придумал не знаю для чего, но могу вот так...


  1. souls_arch
    14.04.2022 07:18
    +3

    И сколько секунд экономит нам pull вместо git pull? Сейчас угадаю - 0. При скорости печати 200-300зн/м вслепую и редкости операции.

    Там и так все сокращено, куда еще? Вы еще команды линуха/макОС уже до букв аббревиатур сокращенные посокращайте

    В громоздких запросах бд - псевдонимы необходимость. А в гите то на кой?

    Это мое мнение, можно пинать.


  1. saipr
    14.04.2022 08:26
    +1

    Если не предвзято взглянуть на первую часть статьи, то, в принципе, имеем неплохую подсказку по командам git для начинающего пользователя.


  1. wibotwi
    14.04.2022 08:58

    А зачем вам алиас на git pull? Я ума не приложу зачем эта команда может понадобиться. Я в 100% случаев зову git pull --rebase.


    1. Zuy
      14.04.2022 10:07

      А что не так с git pull? Ну вот лежит у меня master, хочу я с сервера свежие комитты подтянуть в него, так и использую git pull. Или я чего-то не понимаю?


      1. mayorovp
        14.04.2022 11:24
        +1

        Проблема в том, что эти свежие комитты будут вмержены в вашу текущую ветку, причём ваша ветка будет считаться основной. Это не проблема если вы работаете в отдельной ветке, которую потом будете мержить обратно, но если результат git pull запушить — большинство инструментов построения списков изменений поломаются.


        Ну а если вы и вовсе PR готовите, то там комиты слияния выглядят попросту некрасиво.


        1. storoj
          14.04.2022 15:13

          git config --global pull.rebase true


          1. wibotwi
            14.04.2022 16:43

            да, но автор мне кажется не любит .gitconfig, иначе бы не клал git алиасы в .bashrc


        1. Zuy
          14.04.2022 17:14

          Ах, вот вы про что. Тут все верно, git pull делается только на ветках в которых работа не идёт и обратно они не отправляются.


          1. wibotwi
            14.04.2022 17:51
            +1

            в таких ветках и git pull --rebase будет работать. А тогда зачем платить дважды? Я за то чтобы git pull не использовалась никогда.


  1. arelive
    14.04.2022 11:27

    А теперь ищем в поиске гитхаба 'dotfiles', открываем любой репозиторий, заходим в .bashrc / .zshrc и видим, что вешать алиасы на все частые команды, не только git - повсеместная практика. Заодно понимаем, что алиасы 'll', 'gs' и тем более 'go' - очень и очень плохие.


  1. cool_burn
    15.04.2022 10:02
    -1

    Зачем это нужно, если есть powerlevel10k?)


  1. rionnagel
    15.04.2022 15:47

    tudoy/sudoy/getoverhere/nunafig

    Вообще я иногда испльзую аллиасы только при хронических ошибках и сильном постоянстве (ls/sl, чтоб паровозик не вызывал, ip ч тоб всегда был с -c и т.д.).

    Как бы не звучало, но имхо по аллиасам мана достаточно.