Jak napisać własne polecenie w gicie

Opublikowane przez Tomasz Prasołek w dniu

sherman-yang-598251-unsplash

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-coreUWAGA! 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

Kategorie: GitPorady

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: […]

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *