Jak pisać czytelne komunikaty commitów w Git: wielkość liter i format

Czytelny komunikat commita w Git ma krótki wiersz tematu (celuj w 50 znaków), napisany w trybie rozkazującym, jak w angielskim „Add”, a nie „Added”, i bez kropki na końcu. Potem pusty wiersz, a po nim treść zawinięta na 72 znakach, która wyjaśnia, dlaczego wprowadzono zmianę. Jeśli chodzi o wielkość liter, wybierz jedną konwencję i trzymaj się jej: z prefiksem takim jak feat: lub docs: wyraz po nim zwykle pisze się małą literą, a bez prefiksu klasyczna rada mówi, żeby pierwszy wyraz zaczynać wielką.
Samo Git niczego z tego nie wymusza, dlatego historie z czasem się rozjeżdżają. Poniżej znajdziesz reguły, skąd pochodzi każda z nich i jak sprawić, żeby narzędzia sprawdzały je za Ciebie, bez konieczności pamiętania o wszystkim.
Anatomia dobrego komunikatu commita
fix(editor): keep cursor position after paste
Pasting into an empty textarea moved the cursor to the start, because
the change handler replaced the value before restoring the selection.
Restore the selection after updating the value instead.
Fixes #142Trzy części: temat, który mówi, co robi commit, treść, która mówi, dlaczego, oraz opcjonalne stopki z odnośnikami i metadanymi. Dokumentacja samego Git zaleca, by zaczynać od „a single short (no more than 50 characters) line summarizing the change, followed by a blank line and then a more thorough description” (jednego krótkiego wiersza, nie dłuższego niż 50 znaków, który podsumowuje zmianę, po nim pustego wiersza, a potem dokładniejszego opisu). Wszystko do pierwszego pustego wiersza jest traktowane jako tytuł commita, a to właśnie pokazują git log --oneline, git shortlog i git format-patch.
Wiersz tematu: krótki, w trybie rozkazującym, bez kropki
Pięćdziesiąt znaków to limit miękki. Własny przewodnik SubmittingPatches projektu Git nazywa go właśnie tak i prosi autorów, by „skip the full stop” (pominęli kropkę na końcu). Jeśli nie udaje się zejść poniżej 50, to często znak, że commit robi dwie rzeczy.
Ten sam przewodnik prosi, by „describe your changes in imperative mood” (opisywać zmiany w trybie rozkazującym), jakby wydawać polecenia bazie kodu: „make xyzzy do frotz”, a nie „makes xyzzy do frotz” ani „changed xyzzy to do frotz”. Przydatny test z siedmiu zasad komunikatów commitów Chrisa Beamsa: dobry temat uzupełnia zdanie „If applied, this commit will …” (Po zastosowaniu ten commit …).
- „If applied, this commit will add CSV export” działa.
- „If applied, this commit will added CSV export” nie działa.
- „If applied, this commit will bug fixes” też nie działa i niczego nie mówi czytelnikowi.
Tryb rozkazujący pasuje też do komunikatów, które Git pisze za Ciebie, takich jak Merge branch 'main' i Revert "…", więc Twoje commity wyglądają w logu tak samo.
Wielkość liter w temacie: dwa obozy
Tu rady naprawdę się różnią, a właściwa odpowiedź zależy od tego, czy Twoje tematy zaczynają się od prefiksu.
| Konwencja | Przykład | Kto ją zaleca |
|---|---|---|
| Bez prefiksu, wielką literą | Add CSV export | Notatka Tima Pope'a o komunikatach commitów z 2008 roku; siedem zasad Chrisa Beamsa |
| Prefiks obszaru, po nim mała litera | doc: clarify sign-off rules | SubmittingPatches projektu Git |
| Prefiks typu, opis małą literą | feat: add CSV export | Wytyczne commitów Angulara; konfiguracja conventional w commitlint |
Wersja projektu Git ma szczegół wart skopiowania. Tylko pierwszy wyraz po prefiksie traci wielką literę i tylko dlatego, że jest pierwszy: wyrazy, które zawsze pisze się wielką literą, ją zachowują. Jego własny przykład to refs: HEAD is also treated as a ref, ponieważ HEAD zawsze zapisuje się wielkimi literami. Ta sama logika daje fix: handle iOS paste i docs: update README badges.
Nasza opinia: w angielskim komunikacie z prefiksem pierwszy wyraz zaczynaj małą literą, chyba że to nazwa albo skrótowiec. Bez prefiksu zaczynaj go wielką. Mieszanie obu stylów to jedyny prawdziwy błąd, bo git log --oneline zamienia Twoje tematy w listę, a lista, na której wielkość liter zmienia się co kilka wierszy, wygląda niedbale. To samo rozumowanie zastosowane do dokumentacji znajdziesz w naszym przewodniku o pisaniu spójnej dokumentacji.
Co naprawdę mówi specyfikacja Conventional Commits
Specyfikacja Conventional Commits 1.0.0 definiuje taką strukturę:
<type>[optional scope]: <description>
[optional body]
[optional footer(s)]Najważniejsze reguły w skrócie:
feat(nowa funkcja) ifix(poprawka błędu) to dwa typy zdefiniowane w specyfikacji. Odpowiadają wydaniom MINOR i PATCH w Semantic Versioning, a zmiany łamiące zgodność odpowiadają wydaniu MAJOR. Inne typy są dozwolone; specyfikacja wspomina obuild,chore,ci,docs,style,refactor,perfitest, tak jak zaleca konfiguracja conventional w commitlint, oparta na konwencji Angulara.- Zmianę łamiącą zgodność oznacza się znakiem
!przed dwukropkiem (feat!: drop Node 16 support) albo stopkąBREAKING CHANGE:, która musi być zapisana wielkimi literami. - Narzędzia czytające ten format nie mogą traktować go jako rozróżniającego wielkość liter, z wyjątkiem
BREAKING CHANGE. Na pytanie, czy typy mają być pisane małymi, czy wielkimi literami, FAQ specyfikacji odpowiada, że można użyć dowolnej wielkości liter, „but it's best to be consistent” (ale najlepiej być konsekwentnym).
Specyfikacja nie ustala długości tematu ani nie wymaga trybu rozkazującego. To pochodzi z konwencji Git.
Gdzie commitlint jest surowszy niż specyfikacja
@commitlint/config-conventional z commitlint to zwykły sposób egzekwowania tego formatu, a jego domyślne ustawienia idą dalej niż specyfikacja. Przepuściliśmy przykładowe tematy przez wersję 21:
| Temat | Wynik |
|---|---|
feat: add CSV export | Przechodzi |
feat: Add CSV export | Nie przechodzi: temat nie może być w sentence case |
Feat: add CSV export | Nie przechodzi: typ musi być pisany małymi literami |
fix: handle empty textarea. | Nie przechodzi: kropka jest niedozwolona |
fix: README typo | Nie przechodzi: to też liczy się jako sentence case |
fix: typo in README | Przechodzi |
Na wiersz z README trzeba uważać. Temat zaczynający się od skrótowca albo nazwy klasy, taki jak fix: README typo czy feat: URLSearchParams support, zostaje odrzucony, choć projekt Git zaakceptowałby odpowiednik. Przeredaguj temat tak, żeby skrótowiec nie stał na początku, albo złagodź regułę subject-case w konfiguracji. Domyślny limit nagłówka to 100 znaków, więc commitlint nie będzie też pilnował 50.
Treść: zawijaj na 72 i wyjaśniaj dlaczego
Git nigdy nie zawija Twojego komunikatu na nowo. Wyjaśnienie Tima Pope'a z 2008 roku nadal obowiązuje: git log wcina komunikaty o cztery spacje, więc na 80-kolumnowym terminalu, po odjęciu jeszcze czterech dla symetrii z prawej strony, zostaje 72 kolumny, a zawinięty tekst pozostaje czytelny także wtedy, gdy commity wysyła się mailem przez git format-patch. Nasze narzędzie Zawijaj tekst na N znakach zawinie akapit na 72 znakach na granicach wyrazów, jeśli Twój edytor tego nie robi.
W treści opisz to, czego diff nie pokaże: problem, powód wyboru takiej poprawki i wszystko, co próbowano, a nie zadziałało. W wierszu poleceń każde -m staje się osobnym akapitem, więc git commit -m "fix: keep cursor after paste" -m "Pasting into…" daje temat, pusty wiersz i treść.
Niech sprawdzają narzędzia
- VS Code: ustaw
"git.inputValidation": true. Pole commita ostrzega wtedy, gdy temat przekroczy 50 znaków (git.inputValidationSubjectLength) albo inny wiersz przekroczy 72 (git.inputValidationLength). - Vim: jego dołączone ustawienia dla komunikatów commitów zawijają treść na 72 (
textwidth=72) i przestają podświetlać temat po 50 znakach. - Szablon commita:
git config commit.template ~/.gitmessageotwiera każdy commit w edytorze z Twoimi przypomnieniami. - Hook commit-msg do sprawdzania bez zależności. Zapisz go jako
.git/hooks/commit-msgi nadaj mu prawo wykonywania:
#!/bin/sh
# Checks the subject line of every commit message.
subject=$(head -n 1 "$1")
length=${#subject} # counts bytes in some shells; fine for ASCII subjects
if [ "$length" -gt 72 ]; then
echo "commit-msg: subject is $length characters (limit 72, aim for 50)" >&2
exit 1
fi
if [ "$length" -gt 50 ]; then
echo "commit-msg: note, subject is $length characters (aim for 50)" >&2
fi
case "$subject" in
*.) echo "commit-msg: drop the full stop at the end of the subject" >&2
exit 1 ;;
esac
if [ -n "$(sed -n 2p "$1")" ]; then
echo "commit-msg: leave line 2 blank, between subject and body" >&2
exit 1
fiOstrzega powyżej 50 znaków, odrzuca tematy dłuższe niż 72, końcową kropkę i brak pustego wiersza, a git commit --no-verify go pomija, gdy naprawdę trzeba. Do szybkiego policzenia znaków przed commitem wklej temat do naszego Licznika znaków.
Lista kontrolna wygląda więc tak: temat w trybie rozkazującym, około 50 znaków, bez kropki, jedna reguła wielkości liter dla całego repozytorium, pusty wiersz, treść zawinięta na 72 znakach, która wyjaśnia, dlaczego, oraz hook albo linter, żeby reguły przetrwały pracowity tydzień.


