У 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)
eugenebabichenko
07.01.2017 21:21+57Название вводит в заблуждение. Это не подборка команд, а подборка алиасов, которые отдельно взятой группе пользователей кажутся удобными.
alexac
07.01.2017 23:53+26Действительно, ожидал увидеть мясо про rev-parse, for-each-ref, cat-file, rebase --onto, fetch +, update-ref, show-ref… А тут просто пачка алиасов.
AlexWoodblock
08.01.2017 08:17+1Можете порекомендовать статьи, в которых более-менее доступно разжевано это самое «мясо»?
alexac
08.01.2017 11:15К сожалению нет. Небольшая часть этого есть в pro git. Оставшаяся же часть осваивается посредством долгого и вдумчивого ковыряния в git на практике.
Halt
08.01.2017 07:36+7Это еще не самое страшное. Хуже, когда такой любитель алиасов начинает их втыкать в продуктовые и CI скрипты, потому что «так удобнее».
afanasiy_nikitin
07.01.2017 22:20-2немного полезных алисасов от проекта oh-my-zsh: https://github.com/robbyrussell/oh-my-zsh/wiki/Cheatsheet
worldmind
07.01.2017 22:41+3Самый нужный алиас это «кто первым добавил эту строку», пока что-то всё что попадалось как-то криво работало или не работало
inook
07.01.2017 22:43-14Использую git-flow и уже давно забыл о боли.
f0rk
08.01.2017 21:26Хмм… На Хабре не любят git-flow?
ZyXI
08.01.2017 21:37+2На хабре не любят бессмысленные, да ещё и не относящиеся к статье комментарии. Вот написал бы inook, какое отношение git?flow имеет к статье и почему он «забыл о боли» — минусов было бы меньше.
f0rk
09.01.2017 12:22+1Думаю, потому что мерж там по умолчанию --no-ff и не нужно вспоминать, с какой опцией -d или -D нужно удалять слитые ветки. Ну и в принципе, стандартизированный flow и инструменты для него освобождают мозг для более важных задач.
ZyXI
09.01.2017 17:52staaash, grog, commend, shorty, please? Насколько мне известно, git?flow заменяет только merc и it. Кроме того, совет «используйте git?flow» подходит только для новых проектов или проектов, где он уже используется.
NeoCode
07.01.2017 23:53+2А я использую пока лишь TortoiseGit в самом примитивном виде, просто для себя лично, локально. Без веток, только фиксацию изменений, чтобы не потерять историю изменений и чтобы было куда откатиться если чего поломаю. На предыдущей работе был svn, на новой ничего — а без контроля версий как-то уже некомфортно :)
YourChief
08.01.2017 00:22+4А вы изучите лучше все возможности гита — даже для ведения репозитория одним человеком ветки крайне полезны. Для чего:
чтобы вносить изменения в код на какую-то другую тему в то время как имеются незаконченные изменения, для фиксации в общей истории только значащих изменений, в то время как в рабочей ветке могут быть зафиксированы незавершенные состояния кода, для более простого ревью фич, для откладывания изменений в коде и применении их, когда основа для изменения уже другая.
Cozi
10.01.2017 21:30на новой ничего
Т.е. вы один что-то разрабатываете на новой работе, или все-таки у вас там команда и вы живете без системы контроля версий?
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
amaslenn
08.01.2017 11:42+1А можно как-то проверить коммиты, которые были перенесены в другую ветку с помощью
cherry-pick
? sha у них отличаются, конечно. Можно попробоватьpatch-id
, но это несколько затратно перебирать много коммитов.Halt
08.01.2017 19:47Если в коммитах проставляется герритовский ChangeId, то поиском по коммитам с тем же ChangeId. Это можно сделать например с помощью git grep. Но это если вы знаете копии чего вы хотите искать.
В общем случае видимо только скриптить перебор.
Badja
08.01.2017 02:53-4эх, а я так и не добрался до Git :(
Danik-ik
08.01.2017 15:35+1Зря. Я начал использовать vcs ещё когда работал на заводе, где никому ничего не надо было и всякий работал как хотел. Тогда это была cvs. Я даже ветки не использовал, но уже забыл про "ё-моё, что ж я наделал-то", "откуда это здесь" и "что я имел в виду". Теперь однозначно git, ветки, упрощённый git flow — даже при том, что владею кодом единолично. Зато нет проблем разрабатывать несколько функциональных едиц, радикально переделывать код, но при этом не терять возможности выпустить хотфикс менее, чем за полчаса. Это реально стоит времени на обучение.
poxu
08.01.2017 11:11+1Я очень старался, но так и не понял отрывок про git shorty. В полном выводе git status есть информация про package.json и index.js, а в выводе git shorty только какой-то test и .gitignore. Может кто-нибудь пояснить, что имел в виду автор?
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
guai
08.01.2017 13:57+4я вижу ересь! вся суть гита в том и состоит, чтобы глумиться над теми, кто не смог пройти по минному полю системы его команд.
Dreyk
08.01.2017 15:32+5Первому коммиту в репозитории нельзя сделать ребейз, как обычному.
git rebase -i --root
seregamorph
08.01.2017 16:51soft reset последнего коммита с выводом статуса
git config --global alias.rs1 '!git reset --soft HEAD~1 && git status --short --branch'
NeonXP
09.01.2017 02:06Как же приятно узнавать что-то новое о старом добром, казалось бы, вдоль и поперёк известном инструменте!
faost
10.01.2017 15:38+1С алиасов гита перешел на алиасы из oh-my-zsh https://github.com/robbyrussell/oh-my-zsh/blob/master/plugins/git/git.plugin.zsh — очень рекомендую, хорошо продуманы. Заменили мне все комманды гита, которые я постоянно использую в работе, избавив меня от головной боли с продумыванием имен и подбором параметров для команд, когда я пытался сам сделать хорошую систему под себя.
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))'"
Выводит список локальных веток, отсортированный по времени, с последними коммитами и их датами.
develop7
очередная кучка алиасов
нет бы в апстрим протащить хотя бы какой-нибудь (хотя бы
git it
в качестве поведения по умолчанию)inb4: я понимаю, что это сложно
wing_pin
Прошу прощения, но я не вижу никакого смысла протаскивать это в апстрим, если все это можно реализовать в виде алиасов. Не стоит плодить сущности без особой нужды на то.
develop7
своих собственных алиасов у каждого второго пользователя