mergiraf — AST-põhine tööriist Git'i kolme külje ühendamiseks

On välja antud mergiraf projekti versioon 0.4, mis arendab Git'i draiverit, võimaldades kolme külje ühendamist. Mergiraf toetab erinevate konfliktitüüpide lahendamist ühendamisel ning võib olla kasutusel erinevate programmeerimiskeelte ja failivormingute jaoks. On võimalik, et mergiraf kutsub eraldi esile konfliktide töötlemiseks, mis tekivad tavalise Git'iga töötades, samuti asendab Git'i ühendamise käitlejat, et laiendada selliste käsu nagu merge, revert, rebase ja cherry-pick võimalusi. Kood on saadaval GPLv3 litsentsi alusel. Uues versioonis on lisatud tugi keelte Python, TOML, Scala ja TypeScript jaoks ning viidatud on jõudluse optimeerimisele.

Allpool on toodud üksikasjalik kirjeldus probleemidest, mida mergiraf aitab lahendada:

Tarkvara on selge näide ülimalt keerulisest süsteemist. Keerulistel süsteemidel on üks ühine omadus — nad on KEERULISED — ja sa ei saa oodata, et vajalik keeruline käitumine tekib iseenesest, juhuslikult. Selle asemel arenevad need süsteemid ajaga, samm-sammult, ja iga mutatsioon on hoolikalt igas etapis kontrollitud. Selle saavutamiseks on vajalik hästi määratletud struktuur ja vastavad tööriistad. Iga keerulise süsteemi evolutsiooni saab visualiseerida suunatud puuna, kus juur esindab tühja funktsioonide kogumit ning iga sõlm — välja arvatud juur — on mutatsiooni rakendamise tulemuseks oma vanemale.

Toodete kontekstis nimetatakse iga sõlme "versiooniks", mis esindab kindlat funktsioonide ja antifunktsioonide kogumit. Igasugune muudatus selles kogumis loetakse mutatsiooniks, mis loob serva meie suunatud suunamata graafikus. Need funktsioonid on olemuslikult abstraktsed; need ei kajasta otseselt füüsiliste süsteemide toimimise viise, vaid näitavad pigem, kuidas arukad agendid joogavad nende süsteemide kasulikkust. Idee ellu viimiseks olemasolevates reaalses maailmas rakendustes on oluline käised üles käärida ja sukelduda *piisavalt* madalatele üksikasjadele, mille keeles saab väljendada ja selgitada, kuidas kõik täpselt töötab. Tarkvaraarenduses on need madalamad tasemed tavaliselt esindatud lähtekoodiga.

Ettepanekute järkjärgulise parandamise saavutamiseks ja selle dokumenteerimiseks, kuidas nad sinna jõudsid, esitavad programmeerijad oma tööd snapshot'ide ja changeset'ide terminoloogias. Snapshot esindab toote kindlat olekut koos kõigi madalatelt tasemetelt detailidega, samas kui changeset tähistab üleminekut snapshot'ide vahel. Tüüpiliselt tekivad snapshot'id üksikute changeset'ide kaudu nende vanematele, seetõttu on need snapshot'id enamasti tähistatud muutustega, mis need lõid, mistõttu kasutatakse neid termineid tihti vaheldumisi.

Mõnikord eksisteerivad snapshot'id, mis on saadud mitmete üleminekute tulemusena — commit'ide liitmisest. Nendega on keeruline töötada, seetõttu tavaliselt neid vältida. Kaasaegsed avatud lähtekoodiga versioonihaldussüsteemid, nagu Git, pakuvad üsna põhjalikke võimalusi arendustootmise töövoogude haldamiseks. Need võimaldavad arendajatel korraldada snapshot'e suunatud suletud graafidena, lisada neile kommentaare ja vajadusel muuta nende järjekorda.

See funktsionaalsus võimaldab arendajatel kirjutada semantiliselt tähenduslikku projekti ajalugu, mis on hädavajalik vigade eemaldamiseks ja küsimustele vastamiseks, näiteks «Miks see madalatasemeline detail (nt, muutuja) sisse viidi?», «Kui suur on minu panus sellesse projekti?», «Keda tabasid tagasiviikmisega seotud probleemid ja millal?», «Milline madalatasemeline muudatus rikkus selle funktsiooni (kuigi see ei pidanud, me kõik kontrollisime!?)»

Versioonihaldussüsteemid täiendavad kontseptsiooni harudest - madala taseme mõisted, mis tähendavad lihtsalt pidevat fragmenti projekti madalama taseme ajaloost, millel on arendaja jaoks semantiliselt oluline tähendus. Harusid kasutatakse tavaliselt konkreetsete funktsioonide rakendamiseks, mõnikord luuakse mitmeid harusid erinevate rakenduste kandidaatide jaoks sama funktsiooni jaoks. Harude haldamise töövoogude kasutamine (mis on tegelikult peavool ja arenduse standard, mida kasutatakse igal pool ja igal pool) võimaldab igal eraldi arendajal tõhusalt hallata mitmeid projekti konflikti harusid, millest igaühel on erinev valmiduse või kvaliteedi tase. See võimaldab arendajatel kombineerida oma ja teiste tööde tulemusi, ilma et peaks iga kord kogu käsitsi uuesti kirjutama.

Tavaliselt luuakse peamine haru, mis esindab "ametlikku" toodet, millest hargnevad külgharud iga funktsiooni jaoks, mis regulaarselt (ideaalis pärast iga commit'i) sünkroonitakse peaharuga, võimaldades arendajatel töötada kõige värskema toote versiooniga ja samal ajal rakendada funktsioone, mida nad parasjagu arendavad, tuvastades probleeme, mis tulenevad teiste arendajate tegevusest, võimalikult varakult.

Erinevate snapshot-ide funktsioonide kombineerimise katsetamisel (mis on lihtsalt ühisema esivanema leidmine ja nende muutuste järkjärguline rakendamine teise kohal, seda operatsiooni nimetatakse rebase'iks; liitmine on peaaegu nagu rebase, lihtsalt struktuuri kommit graaf erinevalt, mis muudab nende manipuleerimise ebamugavaks, seega püütakse liitmist vältida rebase'i kasuks) tekivad probleemid. Kaasaegsed versioonihaldussüsteemid (VCS) kasutavad muutuste ühendamise jaoks sisemisi algoritme, mis jagavad failid eraldi ridadeks, käsitledes iga rida kui sümbolit ja faile kui nende järjekordi, ning seejärel rakendavad neid ühendamiseks algoritme, mis on pärit bioinformaatikast.

Kahjuks ei anna lineaarne esitusviis lähtekoodi sisust midagi mõistetavat. Selle ainus voorus on, et see on lihtne ja universaalne. Erinevused saavad konfliktide põhjuseks, olles pidev peavalu arendajatele. Konfliktide lahendamine nõuab arendajalt, et ta uuriks hoolikalt mõlemat koodiversiooni, mitte ainult neid osi, mida lineaarne võrdlusalgoritm näitab kui "muudetud" või "konflikti tekitavad", vaid võib-olla kogu projekti.

Arendaja peab lahendama muudatused, kirjutama käsitsi ühise koodi ja kõrvaldamise mis tahes erinevused. Probleemide arv suureneb, kui ridade tööriist tuvastab muudatused valesti, mis juhtub sageli suurte muudatuste korral, sealhulgas triviaalsete, nagu koodi ümbervormistamine. Kui hilisemaid muudatusi ei õnnestu rakendada käsitsi liidetud koodile, muutub olukord täielikuks õudusunenäoks. Hoolimata hirmutavatest juhtumitest töötab enamikul juhtudel lineaarne algoritm, eriti kui arendajad püüavad aktiivselt mitte tekitada talle probleeme. Üheks viisiks selliste probleemide minimeerimiseks on kohustatud nõue töödelda lähtefaile kanoniseerimise tööriistadega, nagu black.

Muidugi on hirmutavate juhtumite (ja üldiselt, mitte ainult nende jaoks, lineaarne algoritm on heuristika, mis võib triviaalsetel viisidel põhjustada mittetöötavat koodi; näiteks kui üks arendaja nimetab muutuja ümber ja teine kirjutab samal ajal uue koodilõigu, mis kasutab seda muutujat, ei ole sulandumise/ülekanne konflikt, kuid tulemus ei tööta) lahenduseks õige sisemine mudel.

Hoolimata asjaolust, et selle valdkonna uurimistööd on tehtud juba ligi 30 aastat ja need on viinud mitmete patenteeritud kaubanduslike toodete loomise, ei ole neid uuringute tulemusi viimase ajani muundatud praktiliseks rakenduseks avatud lähtekoodiga toodetes. Enamus avatud lähtekoodiga lahendusi hakkasid arenema 2010. aastate alguses ja keskendusid peamiselt Java keelele.

Selle perioodi kõige silmapaistvam avatud rakendus, GumTree, on loodud akadeemilise taustaga teadlase poolt, kirjutatud Java keeles, omab oma abstraktset sisemist representatsiooni, mis eelneb treesitter'ile, ning tal on nii treesitter'ile kui ka teistele tööriistadele põhinevad tagaplaanid, mis teisendavad allika koodi abstraktseteks representatsioonideks. See süsteem suudab ainult genereerida (sündmustest tekstilise logina, samuti on olemas API, mida saab lihtsalt kutsuda mis tahes programmeerimiskeelest, mis omab Java binde) ja visualiseerida muudatusi. Siiski ei sobi see süsteem muudatuste ühinemiseks ega genereeritud diff-failide vaatamiseks, kuigi tõenäoliselt saab diff'e API kaudu üles laadida.

Noorem ja praktiliselt rakendatav versioon difftastic on kirjutatud Rust keeles, põhineb treesitter'il ja keskendub värviliste diff'ide genereerimisele konsoolis. See süsteem on samuti suunatud diff'ide visualiseerimisele ja ei püüdle muudatuste integreerimise või patch'ide rakendamise poole.

Hiljuti tekkis ja aktiivselt areneb projekti mergiraf. See Rust keeles kirjutatud tööriist (oma maht on 21 MiB!) põhineb samuti treesitter'il, mis on saanud sama standardi kontekstitundlike grammatikate parside jaoks arengutööriistades, nagu LLVM madala taseme käskude optimeerimiseks. Erinevalt konkurentidest pakub mergiraf mitte diff'ide genereerimise funktsioone, vaid automaatse konflikti lahendamise funktsioone. Mergiraf kasutab patch'ide genereerimiseks GumTree algoritmi rakendust ja rakendamiseks spork'i algoritmi, mis on kohandatud treesitter'i struktuuride jaoks.

Kahjuks ei ole patch'ide serialiseerimine failidesse, mida saaks hiljem rakendada, teostatud (kuid on tõenäoline, et seda võiks teostada GumTree genereeritud sündmuslogide analüüsi kaudu). Teine perspektiivikas viis erinevuste rakendamiseks võiks olla nende rakendamine mitte patch'ide kaudu, vaid LSP-serverite refaktoreerimisfunktsionaalsuse kaudu, mis võiks aidata konflikte tuvastada kogu projekti tasandil. Visualiseerimine toetatakse ainult konfliktide korral.

Töö näide: ühisvanem «base.py» (tabidega indentatsioon, üleliigne rida alguses) foo = 1 def main(): print(foo + 2 + 3) «a.py» (indentatsioon tabidega endiselt, 2 üleliigset rida alguses, debug-prindiks on kasutusel teek icecream, lisatud klass «baz»: from icecream import ic foo = 1 def main(): ic(foo + 2 + 3) class baz: def __init__(self): «»»baz»»» «b.py» (muutujat «foo» nimetati ümber «bar»iks, töödeldud teekiga «black» pärast muudatusi, tulemuseks on indentatsioon tühikutega ja üleliigsed read eemaldatud): bar = 1 def main(): print(bar + 2 + 3) Käsk .\/mergiraf merge .\/base.py .\/a.py .\/b.py -x a.py -y b.py -s base.py -o .\/res.py toob järgmise tulemuse from icecream import ic bar = 1 def main(): ic(bar + 2 + 3) class baz: def __init__(self): «»»baz»»» (debug-prindiks on kasutusel teek «icecream», muutuja «foo» nimetati ümber «bar»iks, töödeldud teekiga «black» pärast muudatusi, tulemuseks on indentatsioon tühikutega ja üleliigsed read eemaldatud, tabide ja tühikute segu, kuid lubatud vorm).

Siin on kohe nähtav tööriista puudus. Dokumendi stiil konfigureeritakse tavaliselt failides «.editorconfig», ning globaalsed stiili muudatused, nagu tabide asendamine tühikutega ja black stiili kasutuselevõtt, nagu «b.py» puhul, kaasnevad tavaliselt muudatustega failis «.editorconfig». Seetõttu peab tööriist olema parema kohanemise jaoks selliste muudatuste jaoks omama kontseptsiooni globaalsest stiilist «vaikimisi» ja suutma tõmmata seadistusi failist «.editorconfig».

Allikas: opennet.ru

Osta usaldusväärne hostimine veebilehtede jaoks DDoS-i kaitsega, VPS VDS serverid 🔥 Osta usaldusväärne hostimine veebilehtede jaoks DDoS-i kaitsega, VPS VDS serverid | ProHoster