Jak napisać własne polecenie w gicie
Dzisiaj napiszemy własnie polecenie do GITa 🙂 Nie będę pokazywał jak napisać własne polecenie, aby tylko nauczyć się czegoś nowego. Nasze polecenie będzie bardzo praktyczne. Będzie służyło do dodania na końcu wiadomości commita dodatkowego tekstu. W czym to Nam może pomóc?
Problem do rozwiązania
We wpisie Git: Jak dodać numer zadania z VSTS do ostatnich 5 commit message pokazałem możliwości polecenia --filter-branch
. Dzięki niemu możemy w szybki i nie taki trudny sposób edytować wiadomość ostatnich commitów. Minusem tego rozwiązania jest to, że trzeba to polecenie znać na pamięć albo mieć gdzieś zapisane. Ja mam je zapisane zapisane w OneNote. Za każdym razem jak chcę go użyć to muszę uruchomić aplikację, znaleźć odpowiednią stronę, skopiować polecenie do konsoli i zmienić numer zadania oraz liczbę commitów wstecz, które polecenie ma objąć. Dzięki własnemu poleceniu wpiszemy dużo prostsze polecenie do konsoli z odpowiednimi parametrami. Wywołanie polecenia z przytoczonego wpisu wygląda tak:
git filter-branch --msg-filter 'sed "s/\(.*\)/\1 #321/g"' HEAD~5..HEAD
A wywołanie naszego własnego polecenie będzie wyglądało tak:
git append "#321" 5
Dużo prostsze i czytelniejsze. Pierwszy parametr to tekst, które zostanie dodany na końcu wiadomości commita. Drugi parametr to liczba ostatnich commitów, dla których wiadomość zostanie zmieniona. Tylko tyle 🙂
UWAGA!!!
To polecenie przepisuje historię, czyli wszystkie zmienione commity będą miały inne SHA-1. Nie wykonujemy tego polecenia na commitach już wypchniętych na serwer, tyko na lokalnych zmianach.
Dawno temu we wpisie Git hooks + Vsts: automatyczne łączenie zadania z commitem pisałem jak automatycznie dodawać numer taska podczas tworzenia commita. Po co teraz robić taki skrypt? Z tego powodu, że tamto rozwiązanie przy moich charakterze pracy ma jeden minus. Podczas pracy nad jakimś zadaniem robię dużo commitów, które potem scalam z innymi lub poprawiam informacje w nim zawarte. Jeśli zadanie jest większe to na koniec dnia pracy wypycham na serwer mój feature branch. Wtedy już następuje automatyczne połączenie commitów z zadaniem w Azure DevOps (dawne Visual Studio Team Services). Następnego dnia niektóre z tych połączonych commitów mogą już nie istnieć, bo je scalę z innymi przy pomocy interactive rebase. Nie chcę mi się później ręcznie tego odkręcać.
Własne polecenie – podstawy
Własne polecenie to po prostu skrypt napisany np. w języku Bash (lub innym języku skryptowym). Plik ze skryptem trzeba umieścić w katalogu gdzie mamy zainstalowanego Gita. Ja pracuję na Windowsie i u mnie to będzie katalog: C:\Program Files\Git\mingw64\libexec\git-core
. UWAGA! Trzeba mieć uprawnienia administratora, aby móc zapisywać w tym katalogu. Aby dowiedzieć się gdzie mamy zainstalowanego Gita wpisujemy w konsoli:
git --exec-path
Żeby nasze polecenie można było wywołać wpisując git append
, trzeba plik nazwać git-append. Plik musi być bez rozszerzenia. Jak widać w katalogu znajduje się dużo aplikacji, ale również takich plików bez rozszerzenia. Można podejrzeć jak niektóre polecenia zostały napisane. Na przykład polecenie git rebase
jest po prostu skryptem i do tego napisanym również w Bashu. Chociaż ten skrypt jest trochę większy od naszego 🙂
Własne polecenie – skrypt
Na wstępie chcę powiedzieć, że nie jestem specjalistą od Basha 🙂 Uczę się go na bieżąco pisząc ten i inne skrypty.
Na początku zaznaczamy w jakim języku skryptowym piszemy:
#!
/bin/bash
Następnie wywołujemy nasze główne polecenie:
git filter-branch -f --msg-filter 'sed "s/\(.*\)/\1 '$1'/g"' HEAD~$2..HEAD
I już 🙂 Koniec.
Na tym moglibyśmy zakończyć nasz skrypt, ale takie polecenie jest bardzo niebezpieczne. Wpiszemy złe parametry i do wielu commitów możemy dokleić tekst, którego nie chcemy. Oczywiście można to później odkręcić korzystając z polecenia git reflog
, ale po co? Dodamy zabezpieczenie w postaci pytania, na które trzeba odpowiedzieć wpisując y lub n i naciskając ENTER.
Na początku, po deklaracji języka dodajemy:
echo "You want to append text: \"$2\" to last $1 commits."
while true; do
read -p "Do you want to continue [y/n]? " yn
case $yn in
[Yy]* ) git filter-branch -f --msg-filter 'sed "s/\(.*\)/\1 '$2'/g"' HEAD~$1..HEAD; break;;
[Nn]* ) exit;;
* ) echo "Please answer yes [y] or no [n].";;
esac
done
Jeśli użytkownik naciśnie y, wykona się polecenie. Jeśli wciśnie n, to się nie wykona. Natomiast jeśli wciśnie jeszcze coś innego pokaże się mu informacja: Please answer yes [y] or no [n]. Dodatkowo przed pytaniem wyświetlimy jeszcze informację co chcemy zrobić.
Parametry przekazywane do skryptu można odczytać za pomocą kolejnych liczb ze znakiem dolara przed nią np. $1 to pierwszy parametr, $2 to drugi itd.
OK. Wygląda już to lepiej. Ale co się stanie jak użytkownik wpisze złe parametry? Jeśli jako drugi parametr wpisze tekst zamiast liczby? Zróbmy jeszcze walidację parametrów.
if [ x = x${1} ] && [ x = x${2} ]; then
echo ">>> Both parameters are empty."
exit 1
fi
if [ x = x${2} ]; then
echo ">>> Second parameter is empty."
exit 1
fi
# Check if is integer
# https://unix.stackexchange.com/questions/151654/checking-if-an-input-number-is-an-integer
if ! [ "$2" -eq "$2" ] 2> /dev/null
then
echo ">>> Second parameter must be an integer!"
exit 1
fi
Najpierw sprawdzamy czy przekazano parametry. Drugie sprawdzenie dotyczy czy przekazano drugi parametr. Ostatni IF waliduje czy drugi parametr to int. Za każdym razem wyświetlam stosowny komunikat.
No i fajnie 🙂 Już wygląda to całkiem profesjonalnie. Przeglądając inne skrypty zauważyłem, że dużo z nich pokazuje jak tego skryptu użyć, taka pomocnicza informacja. Zróbmy i to. Przyda się to jak dacie swój skrypt kolegom z zespołu. Nie będzie trzeba każdemu wyjaśniać o co chodzi, będą mogli przeczytać pomoc.
W kilku skryptach, które przeglądałem znajduje się zmienna USAGE
lub LONG_USAGE
z informacjami jak wywołać polecenia i jakie parametry przyjmuje. Dodamy to na początku skryptu:
#!/bin/bash
USAGE="USAGE: git append TEXT_TO_APPEND NUMBER_OF_COMMITS\nExample: git append \"#3301\" 5"
Dodatkowo zrobimy sobie funkcję do tego:
show_usage () {
echo -e "\n$USAGE"
}
Musimy jeszcze wstawić wywołanie tej funkcji na końcu każdego IF. Dodatkowo dodamy sekcję, aby pokazać pomoc jak ktoś przekaże jeden z argumentów: help
, -h
lub /?
.
case $1 in
help | -h | "/?")
show_usage
exit 1
esac
Podsumowanie
I to już koniec. Naprawdę. Cały skrypt wygląda tak (jest dostępny również u mnie na GitHubie):
W ten sposób napisaliśmy własny skrypt, którym szybko możemy dodać numer zadania do ostatnich commitów. Na dobrą sprawę można dodać każdy tekst 🙂 , ale mi chodzi tylko o numery zadań z Azure DevOps.
Źródła:
https://git-scm.com/docs/git
https://coderwall.com/p/bt93ia/extend-git-with-custom-commands
2 Komentarze
dotnetomaniak.pl · 10 listopada 2018 o 6 h 20 min
Jak napisać własne polecenie w gicie – Tomasz Prasołek
Dziękujemy za dodanie artykułu – Trackback z dotnetomaniak.pl
git filter-repo - co to jest + praktyczny przykład - Poznaj Gita · 23 marca 2020 o 6 h 23 min
[…] taki skrypt “zainstalować” u siebie na komputerze opisał w tym wpisie: […]