Skip to content

Commit

Permalink
Add git-simple-commit-msg
Browse files Browse the repository at this point in the history
  • Loading branch information
Yu-Leo committed Jan 29, 2024
1 parent e76cdaf commit 1a69f31
Showing 1 changed file with 80 additions and 0 deletions.
80 changes: 80 additions & 0 deletions content/posts/git-simple-commit-msg/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
---
title: "Упрощаем написание сообщений коммитов git"
slug: "git-simple-commit-msg"
date: 2024-01-29
tags: ["linux", "git"]
description: "Как автоматизировать процесс написания сообщений для коммитов git"
keywords: ["linux", "git", "коммиты", "автоматизация", "туториал"]
---
В этой заметке я расскажу о том, как автоматизировать процесс написания сообщений для коммитов git.
## Постановка задачи
Во многих командах приняты различные соглашения об именовании веток и написании сообщений коммитов git, позволяющие упростить понимание истории изменений.

В одном из репозиториев, c которым я взаимодействую по долгу службы, используется подход [GitHub Flow](https://habr.com/ru/articles/346066/) и приняты следующие соглашения:

**Именование веток.** Для решения каждой задачи от master-ветки разработчиком создается отдельная feature-ветка. Название такой ветки должно иметь вид: `abc-xxx-component-feature_title`
- `abc-xxx` - индекс задачи в таск-трекере. Состоит из:
- `abc` - сокращенное название проекта
- `xxx` - порядковый номер задачи
- `component` - название компонента, в который вносятся изменения
- `feature_title` - краткое описание задачи

**Сообщения коммитов.** Первая строчка сообщения коммита должна иметь вид: `ABC-xxx: [?] component: some comment`
- `ABC-xxx` - индекс задачи в таск-трекере
- `?` - тип изменения:
- `+` - добавление функциональности
- `-` - удаление функциональности
- `*` - изменение функциональности
- `component` - название компонента, в который вносятся изменения
- `some comment` - описание изменений

Во время работы мне часто приходится переключаться между несколькими feature-ветками и создавать в них коммиты. Написание сообщений занимает много времени: после каждой смены ветки приходится либо писать сообщение коммита с нуля, либо рыскать по истории команд в поисках предыдущего коммита, относящегося к нужно фиче.
### Что хочу
Автоматизировать процесс создания коммита. Не прописывать индекс задачи и название компонента в сообщении вручную, а парсить их из названия текущей ветки.
## Решение
Для работы с git-ом я использую терминальные команды. Подробно о настройках своего терминала уже рассказывал в [этом посте](https://yu-leo.github.io/yu0dev/posts/my-terminal/). Кратко: [zsh](https://www.zsh.org/) + [oh-my-zsh](https://ohmyz.sh/) + плагины (в частности - плагин [git](https://github.com/ohmyzsh/ohmyzsh/tree/master/plugins/git)). Поэтому я решил не изобретать велосипед, а использовать возможности, предоставляемые этим набором.

Реализация задуманного умещается в две функции, которые нужно описать в конфиге zsh-а (`~/.zshrc`). По сути они являются простыми [unix pipeline](https://ru.wikipedia.org/wiki/%D0%9A%D0%BE%D0%BD%D0%B2%D0%B5%D0%B9%D0%B5%D1%80_(Unix))-ами:

```zsh
function task_index() {
current_branch | grep -Po "^[a-zA-Z]*-\d*(?=-)" | tr "[:lower:]" "[:upper:]"
}

function component_name() {
current_branch | grep -Po "(?<=\d-)\w*(?=-)" | head -n 1 | tr "[:upper:]" "[:lower:]"
}
```
### Объяснение
- `current_branch` - функция, возвращающая название текущей git-ветки. Предоставляется плагином [git](https://github.com/ohmyzsh/ohmyzsh/tree/master/plugins/git) для oh-my-zsh
- `grep -Po "^[a-zA-Z]*-\d*(?=-)"` - парсинг индекса задачи
- `tr "[:lower:]" "[:upper:]"` - преобразование строчных символов индекса задачи в заглавные
- `grep -Po "(?<=\d-)\w*(?=-)"` - парсинг название компонента
- `head -n 1` - взятие первой строки результата. Теоретически название ветки может содержать несколько подстрок, удовлетворяющих описанной выше регулярке. Например, из строки "*abc-123-component3-some-feature-2*" `grep` спарсит две подстроки: "*component3*" и "*some*". Нас интересует только первая из них
- `tr "[:upper:]" "[:lower:]"` - преобразование заглавных символов названия компонента в строчные. На случай, если название ветки будет содержать заглавные буквы :)
- [Документация по Perl-like регуляркам](https://perldoc.perl.org/perlre)

❗ Для работы Perl-совместимых регулярных выражений (`-P`) **на MacOS** нужно использовать утилиту `ggrep` (GNU grep), вместо дефолтного `grep`. Поставить её можно командой `brew install grep` ([stackoverflow](https://stackoverflow.com/questions/16658333/grep-p-no-longer-works-how-can-i-rewrite-my-searches))
### Пример использования
```shell
git commit -m "$(task_index): [*] $(component_name): some feature"
```
Типичная последовательность действий при разработке новой фичи. Помимо описанных выше функций используем [алиасы](https://github.com/Yu-Leo/knowledge-base/blob/main/git-tutorials/oh-my-zsh-git.md):
```shell
gcm # Переключается на master-ветку
gpr # Пуллим изменения из удалённого репозитория
gcb abc-1234-super_service-super_feature # Создаём feature-ветку
# Кодим фичу...
gaa # Добавляем изменения в индекс git-а
gc -m "$(task_index): [*] $(component_name): super feature" # Коммитимся
gpsup # Пушим ветку и изменения в удалённый репозиторий
```

В итоге получаем коммит с сообщением "`ABC-1234: [*] super_service: super feature`".
## Альтернатива. git hooks
Для решения этой задачи можно использовать механизм [git-hooks](https://git-scm.com/docs/githooks). Процесс его настройки для этих целей подробно описан в [статье](https://habr.com/ru/companies/dins/articles/584562/).

Однако мне не нравится данный способ из-за следующих **недостатков**:
- Нужно помнить правила работы хуков в различных ситуациях. В противном случае хуки могут поломать ваши сообщения коммитов так, что вы даже не заметите, пока не посмотрите историю коммитов. Конечно, с последовательностью действий "*добавить в индекс -> закоммитить -> запушить*" вопросов не возникает. Однако в более сложных ситуациях - `git rebase`, `git rebase -i`, `git commit --amend` и проч. - хуки могут сработать не очевидным на первый взгляд образом
- Написание сообщений коммитов становятся менее явными. При каждом использовании команды `git commit -m "..."` нужно помнить про, что написанный текст будет отредактирован хуком
- Хуки неудобно использовать для части репозиториев. Как пишет сам автор, есть два способа включить хуки: "*Поместить их в специальную директорию .git/hooks в каждый (!) проект*." и "*более элегантный, если подразумевается, что ваши хуки применимы для всех проектов. Нужно добавить в глобальный конфиг Git параметр core.hooksPath, значение которого содержит путь до глобальной папки с хуками, откуда Git будет все тянуть в первую очередь*."

0 comments on commit 1a69f31

Please sign in to comment.