Blog

Git-aliaset 10 tasolla: edistyneestä eteenpäin

JUN 17, 2024

Kaksiosaisen blogikirjoitukseni ensimmäisessä osassa lähdimme liikkeelle aivan perusteista: esittelin Gitin aliakset, näytin, miten niillä voi korvata pitkiä ja monimutkaisia komentoja, sekä käsittelin muutamia useimmille käyttäjille tuntemattomia konsepteja, kuten Gitille itselleen parametreja välittäviä aliaksia ja edistynyttä lokien muotoilua mukautetuilla pretty-formaateilla.

Jan Krag

Jan has been with us since 2014 as a Continuous Improvement Agent. He is an accredited trainer for Docker and Github and is also a certified life coach. Jan has a truly diverse range of interests. He breeds oriental cats, builds and flies his own kites, collects Rubik’s cubes, and enjoys snowboarding. Wow!

Ennen kuin jatkat pidemmälle, suosittelen vahvasti lukemaan ensin ensimmäisen osan.

Toisessa osassa esittelen entistä edistyneempiä konsepteja ja tutkin Git-aliasten todella ”villejä” käyttötapoja, mukaan lukien suorastaan hulluja esimerkkejä. Lopuksi esittelen myös muutamia vaihtoehtoja samoihin tarpeisiin.

Sukelletaan siis asiaan.

Taso 6: ! Muut kuin Git-komennot

Enemmän vastinetta rahalle.

Git-aliaset laajentavat niiden asioiden valikoimaa, joita voimme tehdä Git-kontekstissa. Tässä ja useimmissa seuraavissa osioissa tarkastellaan, mihin pystymme, kun astumme Git-alikomentojen rajojen ulkopuolelle.

”Bang”-ominaisuus muuttaa perusteellisesti Git-aliasten mahdollisuuksia, sillä sen avulla voimme kutsua shelliä ja suorittaa mitä tahansa järjestelmämme shell-komentoa. Tämä onnistuu yksinkertaisesti lisäämällä aliaslaajennuksen alkuun huutomerkki eli Unix-/shell-maailmassa ”bang”.

Aloitetaan hyvin yksinkertaisesta esimerkistä, joka havainnollistaa konseptin selkeästi ja on myös hyödyllinen.

Joillakin alustoilla Git toimitetaan valmiiksi asennettuna kahden hyödyllisen GUI-työkalun kanssa: "Git gui" stagingia ja committamista varten sekä "Gitk" historian tarkasteluun. Mutta miksi git gui on Git-alikomento ja gitk ei ole? Hämmentävää, mutta helposti korjattavissa aliasella:

Ja kun kerran olemme aiheessa, minulla on ollut samankaltainen ongelma. Kun aivoni ovat syvällä ”Git”-tilassa, sormeni kirjoittavat usein ”Git” jo ennen kuin olen päättänyt, mitä komentoa käytän. Sitten päätänkin yhtäkkiä listata kansion tiedostot ja kirjoitan nopeasti ll <enter> (päivittäin käyttämäni shell-alias komennolle ls -al), jolloin saan yhtäkkiä:

Nyt ”kirjoitusvirhe” git ll vain toimii, mutta paljastaa samalla bang-ominaisuuden erittäin tärkeän varoituksen: se voi olla sekä siunaus että kirous, kuten esimerkki osoittaa.

Vaikka git ll -aliakseni näyttää toimivan, se näyttää aina repohakemiston juuren sisällön, vaikka olisin alikansiossa.

Shell-komento pwd tulostaa nykyisen työhakemiston; tämä alias tarjoaa nopean tavan tulostaa polku, jossa repositorioni sijaitsee.

Tosin tämä yksittäinen ongelma olisi parempi ratkaista tavallisella Git-aliasella, jolloin uuden shell-istunnon luomista ei tarvita (siitä, kumpi toimii nopeammin, ei tosin ole vielä yksimielisyyttä).

Minulla on kuitenkin ainakin yksi todella hyvä käyttökohde tälle sivuvaikutukselle. Joskus, kun olet muista syistä cd:llä siirtynyt syvälle alikansioon, Git-statuksen tulostetta on todella ärsyttävää lukea, koska kaikki muut polut tulostetaan suhteessa nykyiseen kansioosi. Näet siis muutokset esimerkiksi näin:

Hyödynnetään siis ”juurikansio”-sivuvaikutusta ja lisätään vaihtoehtoja tavalliselle st-aliaselle:

Ne näyttävät statuksen aina suhteessa repon juureen.

Git-1

(-s tarkoittaa vain vähemmän monisanaista ”short”-muotoista tulostetta.)

Huomaa, että vastaava vaikutus voidaan saavuttaa config-muuttujalla status.relativePaths ja tämän blogikirjoituksen ensimmäisen osan ”tasolla 5” käsitellyllä -c-ominaisuudella.

Lopetetaan tämä osio pienellä hauskalla kokeilulla. Jos kirjoitan tiedostamattani Git ennen ll:ää, voin joskus kirjoittaa Gitin myös ennen kuin päätän käyttää esimerkiksi Git statusta, mikä johtaa ikävään tilanteeseen:

$ git git statusgit: 'git' is not a git command.Joten aivoni keksivät luoda:

Kyllä, tämä saa komennon git git status toimimaan, ja aliasten rekursiivisen luonteen ansiosta jopa git git git git git status toimii nyt… ainakin teoriassa.

Todellisuudessa tämä on enemmän hyvä vitsi kuin hyvä idea, sillä siihen liittyy kaksi merkittävää seurausta. Ensimmäinen ongelma on, kuten yllä näkyy, että komento suoritetaan nyt repon juurikansiosta, mikä voi aiheuttaa sekaannusta. Toinen ongelma on, että se rikkoo varsin tärkeän mahdollisuuden suorittaa git help git, jolla saa varsinaisen Git-komennon ohjesivun. Sen sijaan tulostuisi nyt paljon vähemmän hyödyllinen:

Taso 7: Git-aliasten uudelleenkäyttö

Rakenna aiemmin tehdyn varaan … Käytä sitä, mikä tuli ennen

Gitin vanhemmissa, ennen versiota 2.20 julkaistuissa versioissa Git-alias ei voinut viitata toiseen Git-aliakseen. Tämä johti usein useisiin samankaltaisiin aliaksiin config-tiedostossa, kuten mukautettuja Git log -komentoja käsitellessämme näimme.

Ainoa käytettävissä ollut kiertotapa oli hyödyntää bang-ominaisuutta, sillä kävi ilmi, että seuraava toimii täysin hyvin:

Tämä ei kutsu olemassa olevaa aliasta rekursiivisesti, vaan käynnistää uuden shell-istunnon, joka sattuu käyttämään Gitiä aliaksen kanssa.

Onneksi Git 2.20:stä (2018) alkaen rekursiiviset aliakset on sallittu, ja versiosta 2.30 (Q1 2021) alkaen myös bash-completion (tab-täydennys) ymmärtää ja kääntää ne.

Nyt Git-konfiguraationi voi siis olla huomattavasti selkeämpi:

Taso 8: Toimintojen putkittaminen

Unix-komentojen ketjuttaminen lisää hallintaa (tai hulluutta)

Mainitsin aiemmin, että bang-ominaisuus muutti pelin, mutta raapaisimme vasta pintaa. Seuraava askel tulee, kun huomaat, että shellin kutsuminen mahdollistaa useiden komentojen ketjuttamisen.

Yksinkertaisin käyttötapa ovat aliakset, jotka tekevät shellin ja &&-operaattorin avulla useita erillisiä asioita peräkkäin.

Huomautus: Yllä oleva alias on rivitetty luettavuuden vuoksi. Config-tiedostossa sen on oltava yhdellä rivillä. Palaamme tähän myöhemmin.

Voimme jopa käyttää olemassa olevia ympäristömuuttujia tai määrittää uusia muuttujia suoraan aliaksessa.

In case of fire

Tulostin kopion omaan toimistoomme, mikä synnytti Slackissa pitkän ja humoristisen keskustelun siitä, miksi tämä ei toimisi ja miten sitä pitäisi parantaa.

Lopputuloksena syntyi seuraava aliashelmi, joka havainnollisti hienosti muuttujien käyttöä:

Todellinen voima tulee kuitenkin esiin, kun viemme tämän vielä askeleen pidemmälle ja alamme käyttää Unix-putkia yhden komennon tulosteen välittämiseen toiselle.

Määritän ensin nopean remoteurl-aliaksen, jotta Git-remoten URL-osoitteen hakeminen olisi helpompaa. Mutta entä jos kloonasin repon ssh:llä ja URL on muotoa "git@", kun haluan käyttää sitä repon verkkosivuston löytämiseen?

Välitetään ensimmäisen komennon tuloste sedille, joka hakee ja korvaa sekä vaihtaa git@:n  https://:ksi.

Viimeistellään tämä lisäämällä alias, joka ohjaa tulosteen suoraan leikepöydälleni Macin pbcopy-komennolla. (Windowsissa voisimme tehdä saman clip-komennolla.)

Vastaavasti voimme käyttää muita shellin ominaisuuksia, kuten tulosteen ohjaamista tiedostoihin. Haluan toisinaan luoda repoihini .mailmap-tiedoston. Sen avulla voit esimerkiksi "yhdistää" joidenkin osallistujien vanhan sähköpostiosoitteen uuteen tai varmistaa, että käyttäjän eri kirjoitusasut yhdistetään.

Jotta mailmapille olisi hyvä lähtökohta, tarvitsen luettelon tekijöistä sekä heidän nimistään ja sähköpostiosoitteistaan vakiomuodossa "Jan Krag <jan.krag@example.com>", joka muistuttaa hieman komennon git shortlog -sne tulostetta, mutta ilman ensimmäistä numerosaraketta.

Tätä varten keksin seuraavat aliakset:

[alias]mm   = "!git log  --format='%aN ' | sort -u"mmm  = "!git mm >> .mailmap"mmme = "!git mmm && code .mailmap"

Log tulostaa jokaisen commitin tekijän ja sähköpostiosoitteen, minkä jälkeen shellin sort-komennon "unique"-valitsin poistaa kaksoiskappaleet ja lajittelee tulosteen. Ensimmäinen alias tulostaa tiedot konsoliin, kun taas toinen ohjaa tulosteen ja luo .mailmap-tiedoston tai lisää sen olemassa olevaan tiedostoon.

Kolmas on kiireisiin tilanteisiin tarkoitettu kätevä versio, joka avaa uuden .mailmap-tiedoston heti VSCode-editorissani. Tässä siis yhdistämme putkia, uudelleenohjauksia ja &&-ominaisuuden yhteen aliakseen.

Taso 9: Funktiot

Bash-funktiot ovat ylivoimaisia!

Nostetaan jälleen tasoa siinä, mitä voimme tehdä. Nyt kun käytössämme on tämä shell-konteksti, voimme hyödyntää myös funktioiden määrittelyä. Miksi haluaisin tehdä niin, saatat kysyä? Se tekee monimutkaisista aliaksista jonkin verran selkeämpiä, mutta tärkeintä on mahdollisuus lukea komentoriviargumentteja ja käyttää niitä hallitummin.

Tavallisissa aliaksissa voit lisätä aliaksen perään haluamasi valitsimet ja argumentit, jotka lisätään laajennuksen jälkeen. Esimerkiksi palatakseni edellisen kirjoituksen Git slog -aliakseeni, sitä voi aivan hyvin käyttää näin: git slog -3 tai git slog --all. Mutta entä jos haluan luoda aliaksen, jossa tarvitsen saman argumentin useassa kohdassa?

Hyvin yksinkertainen esimerkki tästä on aliakseni, jolla poistan haaran sekä paikallisesti että remotesta:

Huomaa syntaksi. Shell-kontekstissani aloitan määrittelemällä funktion f(), joka suorittaa aloitusmerkin { ja päättävän merkin }; väliset lauseet.

Lopuksi kutsun tätä funktiota sen nimellä f. Hienoa on, että voimme nyt välittää funktiolle argumentteja, jotka ovat funktion kontekstissa käytettävissä "sijaintiparametreina" yhdestä alkaen numeroituina. ${1} viittaa siis yksinkertaisesti ensimmäiseen argumenttiin, jonka käyttäjä antaa funktiota kutsuessaan. Kuten esimerkistä näet, voimme käyttää parametria niin monta kertaa kuin haluamme.

Katsotaan toista yksinkertaista esimerkkiä:

[alias] # Lisää GitHub-repo helposti uudeksi remoteksi ghremote= "!f(){ git remote add $1 https://github.com/$2.git; }; f"

Tässä esimerkissä käytän funktiota en argumentin uudelleenkäyttöön, vaan siksi, että haluan ottaa vastaan useita argumentteja ja käyttää niitä aliaksessa tietyissä kohdissa.

Saatat huomata, että tässä esimerkissä sijaintiparametreja käytetään ilman aaltosulkeita. Tällä haluan vain havainnollistaa, että bashin sääntöjen mukaan sulkeita tarvitaan vain yhdeksää suuremmille sijaintiparametreille, joten valinta on sinun.

Kokeillaan tätä ghremote-aliasta:

Taso 10: Yliampuminen

Monirivisen muotoilun esittely.

Olemme aiemmin nähneet muutamia esimerkkejä aliaksista, jotka päätyvät asetustiedostossasi hyvin pitkiksi riveiksi ja ovat siksi lähes ”lukukelvottomia”. On kuitenkin mahdollista tehdä oikeita monirivisiä aliaksia. Lisää vain kenoviiva rivin loppuun, sillä se suojaa rivinvaihdon.

Tämä ei kuitenkaan varsinaisesti vastaa kysymykseen: "pitäisikö minun?"

Jossain vaiheessa tulevat vastaan rajat sille, mitä aliaksilla on järkevää tehdä, ja kannattaa harkita joitakin vaihtoehtoja, jotka esittelen "tasolla 11". Tämä on kuitenkin blogikirjoitus aliaksista, joten venytetään rajoja hieman ja tee oma arviosi.

Aloitetaan tämä osio melko monimutkaisella mutta toisinaan hyödyllisellä esimerkillä, jota en aio selittää yksityiskohtaisesti.

swm-aliaksen symbolic-ref-kikan yhdistäminen tähän oletushaaran löytämiseksi jää harjoitustehtäväksi sinulle, hyvä lukija.

Selitettävää ei juuri enää ole, joten katsotaan vain muutamia esimerkkejä, jotka voivat innostaa sinua kirjoittamaan omia aliaksia.

"Haluan vain avata tämän repon verkkosivun."

Mutta mitä tehdä, jos Git-remote käyttää SSH:ta?

Katsotaan, miten sitä käytetään:

git-1

Mitkä tiedostot saavat eniten huomiota?

Löysin tämän alun perin Michael Walesin .gitconfig-blogikirjoituksesta ja muokkasin sitä hieman omaan käyttööni sopivaksi.

[alias]churn = !git -p log --all -M -C --name-only\      --format='format:' $@ \        | sort \        | grep -v '^$' \        | uniq -c \        | sort -r \        | awk 'BEGIN {print count,file} {print $1 , $2}'

Ja käytössä git-katas-repositoriossa:

$ git churn42 README.md24 basic-commits/README.md21 basic-branching/README.md19 ignore/README.md19 basic-staging/README.md17 submodules/README.md17 3-way-merge/README.md16 configure-git/README.md15 Overview.md14 ff-merge/README.md

Miksi minun täytyy tietää, miten jatkaa?

Pidän usein Git-koulutuksia, ja aina kun puhumme merge-/rebase-konfliktien ratkaisemisesta, minulla on kyseenalainen ilo esitellä:

git merge --continuegit rebase --continuegit cherry-pick --continuegit revert --continue

Jossain vaiheessa aloin pohtia: ”Miksi ihmeessä minun käyttäjänä pitää määrittää, ’mitä’ jatkan, kun Git tietää selvästi olevansa merge-tilassa, rebase-tilassa ja niin edelleen? Miksei olisi vain continue-komentoa, joka ’tekee oikean asian’?”

Muistaakseni tein niin kuin ennen ChatGPT:tä tehtiin: etsin netistä ja löysin bash-skriptin, joka tekee tämän. Se on luultavasti myös järkevin ratkaisu, kuten seuraavassa luvussa todetaan, mutta fanina tein sen, mikä piti tehdä, ja sain sen toimimaan puhtaana aliaksena. Voin siis esitellä tämän hirvityksen, joka todella kiteyttää ylitseampumisen hengen:

Git-aliasten jakaminen

Päätän tämän osion jakamalla kanssasi ”pyhän graalini” -aliaksen, jonka kehitin noin 10 vuotta sitten kovalla työllä ja päättäväisyydellä.

Halusin ratkaista aliasten jakamisen esimerkiksi työkavereiden kanssa Slackissa. Jos haluan antaa nopean aliaksen vähemmän kokeneelle Git-käyttäjälle, on tarpeettoman monimutkaista selittää joka kerta, miten globaali asetustiedosto löydetään ja muokataan, mihin aliaskoodi tiedostossa lisätään ja niin edelleen.

Olisi paljon selkeämpää lähettää sopiva git config –global alias.foo "do this Git thing" -komento, jonka vastaanottaja voi suorittaa suoraan. Yksinkertaiset aliakset kirjoitan ulkomuistista, mutta jo hieman monimutkaisemmissa aliaksissa, joissa on lainausmerkkejä ja ehkä muuttujia, komennon kirjoittaminen oikein ei ole aivan suoraviivaista. Siksi keksin kirjoittaa exportalias-aliaksen. En arvannutkaan, miten vaikeaa tämän saaminen oikein toimivaksi olisi. Yksi onnistumiskriteereistä oli matkan varrella, että sen pitäisi pystyä viemään myös itsensä. En ole testannut sitä perusteellisesti kaikilla todella hulluilla monirivisillä aliaksilla, mutta niissä tapauksissa jakaisin joka tapauksessa .gitconfig-katkelman.

Jätin tämän tarkoituksella ilman rivinvaihtoja varmistaakseni, että se on vietävässä muodossa.

Kokeillaan sitä aiemmin tässä kirjoituksessa esiintyneellä hieman monimutkaisemmalla aliaksella – sellaisella, joka sisältää erikoismerkkien lisäksi myös escapetut lainausmerkit.

Taso 11: Bonuskierros

Onko hulluudella rajaa?

Tässä viimeisessä bonusosiossa esittelen muutamia vaihtoehtoisia tapoja laajentaa Gitin toiminnallisuutta – vaihtoehtoja, jotka voivat osoittautua järkevämmiksi kuin koko sivun mittaiset moniriviset aliakset.

Mukautetut suoritettavat tiedostot

Ensimmäinen oivallus on, että Git on viisaasti rakennettu siten, että mikä tahansa polustasi löytyvä suoritettava tiedosto nimeltä git-something muuttuu git something -komennoksi.

Tämä tarkoittaa, että jotkin pidemmistä aliaksistamme voisi toteuttaa sen sijaan yksinkertaisena bash-skriptinä. Miksi tällä on väliä, saatat kysyä? Osittain siksi, että vältyt monilta .gitconfig-tiedoston rajoissa pysymiseen liittyviltä muotoiluvaivoilta, kuten rivinvaihtojen escapetukselta ja tarpeettomalta lainausmerkkien kanssa säätämiseltä.

Toinen etu on, että voimme kirjoittaa paremmin ”oikeita” skriptejä, joissa on asianmukainen argumenttien käsittely, virheenkäsittely, käyttöohjeteksti ja niin edelleen.

Git ei itse asiassa edes edellytä Bashin käyttöä. Voit kirjoittaa uudet Git-komentosi millä tahansa kielellä, vaikka kannattaakin ehkä pitäytyä kielessä, jolle on saatavilla hyvä Git-kirjasto, kuten Python, Java tai Go.

Git-laajennuspaketit

Jos voimme kirjoittaa mukautettuja Git-komentoja polussamme olevina binaareina, voimme myös kirjoittaa ja jakaa kokonaisia niiden kokoelmia. On jopa avoimen lähdekoodin projekteja, jotka tarjoavat tällaisia ”Git-laajennuksia” joko tiettyihin tarkoituksiin tai yleisiksi ”hyödyllisten” komentojen kokoelmiksi.

Yksi suurimmista näistä yleiskokoelmista on https://github.com/tj/git-extras, joka lisää asennettuna komentoarsenaaliisi yli 70 uutta komentoa, mukaan lukien itseään palvelevan git extras -komennon, joka listaa ne kaikki. Sen voi asentaa useimmilla yleisillä paketinhallintaohjelmilla tai kloonata manuaalisesti, jos se ei ole mahdollista, esimerkiksi:$sudo apt-get install git-extras

tai

En luettele kaikkia 70 komentoa, mutta tässä muutamia poimintoja:

  • git-abort: Keskeytä მიმდინარე Git-toiminto.

  • git-alias: Määritä, hae ja näytä aliaset.

  • git-magic: Automatisoi add/commit/push-rutiinit.

  • git-repl: Gitin read-eval-print-loop.

  • git-standup: Palauta mieleen, mitä teit edellisenä työpäivänä.

Toinen tutustumisen arvoinen laajennuspaketti on Git Pastiche. Se sisältää huomattavasti pienemmän valikoiman komentoja, jotka ovat ehkä hieman matalamman tason komentoja, mutta pidän erityisesti komennoista git stats ja git activity, joista on toisinaan paljon hyötyä.

Tässä yhteydessä on ehkä myös hyvä mainita, että Gitin "ydinlaajennuksena" pitämämme Git LFS, eli Git Large File Storage, on niin ikään toteutettu laajennuksena tämän mallin mukaisesti ja kirjoitettu Go-kielellä. Git LFS:n ydinkomento on vain git-lfs-suoritustiedosto, joka puolestaan ohjaa kaikki lfs-alikomennot muille Go-ohjelmille.

Ohje

Lopuksi käsittelen ohjeita lyhyesti. Jos haluat panostaa omiin Git-komentoihisi yhtä paljon kuin esimerkiksi "git extras" ja muut, voit tarjota omia ohjesivuja.

Kun kirjoitat git help mycustom, Git tarkistaa, löytyykö järjestelmästäsi mycustomille man-sivu. Man-sivujen luominen ei kuulu tämän blogikirjoituksen aihepiiriin, mutta aiheesta löytyy helposti hyviä ohjeita.

Git-aliasten kohdalla olet ehkä huomannut, että esimerkiksi git help st tulostaa vain:

Tästä voi olla hyötyä tai sitten ei, tarpeistasi riippuen.

Tällaisten perusaliasten kohdalla, eli niiden, jotka eivät kutsu bashia, voit käyttää myös muotoa git st --help. Se avaa aliaksen varsinaisen komennon normaalin ohjesivun, tässä tapauksessa komennon git status.

Kiitokset ja vastuuvapauslausekkeet

Tämän kirjoituksen esimerkit ovat peräisin yli vuosikymmenen ajalta kertyneestä henkilökohtaisesta Git-kokoelmastani. Osaa niistä on muokattu sen mukaan, mitä pyrin kussakin osiossa havainnollistamaan.

Näiden aliasten alkuperästä: osan kirjoitin itse omiin tarpeisiini, osan olen saanut työkavereilta, Git-kurssieni osallistujilta ja ystäviltä. Osan löysin vuosien varrella verkosta ja joko kopioin sellaisenaan tai muokkasin omaan käyttööni. Yleisesti näitä jaetaan yhteisöllisessä hengessä, joten toivon tämän kuuluvan "fair use" -periaatteen piiriin.

Viime aikoina olen alkanut lisätä hyvin monimutkaisten aliasten kohdalle konfiguraatiooni kommentin siitä, mistä olen ne löytänyt. Siitä huolimatta näiden koodiesimerkkien alkuperää on vaikea jäljittää, sillä muut tekevät samoin kuin minä: lainaavat jostain ja muokkaavat tarpeen mukaan.

Jos löysit tästä blogikirjoituksesta aliaksen, jonka alkuperäiseksi tekijäksi katsot itsesi, kerro siitä minulle. Mainitsen sinut lähteenä tai poistan aliaksen pyynnöstäsi.

Muista tutustua myös tämän blogikirjoituksen ensimmäiseen osaan, jos et ole vielä tehnyt niin!

  • Ohjelmistokehitys
  • DevOps
  • CI/CD

Subscribe to our newsletter