Käes on Mergiraf 0.4 projekti uus versioon, mis arendab Git'i draiverit, võimaldades kolmeosalist sulandumist. Mergiraf toetab erinevate konfliktide lahendamist sulandumisel ja seda saab kasutada erinevate programmeerimiskeelte ja failivormingute jaoks. Mergiraf'i saab kasutada iseseisva töötlusena konfliktide lahendamiseks tavalise Giti töö käigus või asendada Git'i sulandumise töötlejaga, et laiendada selliste käskude nagu merge, revert, rebase ja cherry-pick võimalusi. Kood on litsentseeritud GPLv3 alusel. Uues versioonis on lisatud tugi Python, TOML, Scala ja Typescript keelte jaoks, samuti on täiustatud jõudlust.
Allpool on toodud üksikasjalik ülevaade probleemidest, mida mergiraf aitab lahendada:
Tarkvara on suurepärane näide äärmiselt keerulisest süsteemist. Keerulistel süsteemidel on üks ühine omadus — nad on KEERULISED — ja te ei saa ootavad, et vajalik keeruline käitumine toimub juhuslikult. Selle asemel arenevad need süsteemid ajas, samm-sammult, ning iga mutation kontrollitakse hoolikalt igas etapis. Selleks on vajalik hästi määratletud struktuur ja sobivad tööriistad. Igat keerulist süsteemi võib visualiseerida suunatud puuna, kus juur esindab tühja funktsioonide kogumit ja iga sõlm — välja arvatud juur — on mutatsiooni tulemus oma vanemast.
Toote kontekstis kutsutakse iga sõlme "versiooniks", mis kujutab endast määratud funktsioonide ja vastandfunktsioonide kogumit. Iga muudatus selles kogumis loetakse mutatsiooniks, mis moodustab serva meie suunatud suletud graafikus. Need funktsioonid on oma olemuselt abstraktsed; nad ei kajasta otseselt, kuidas füüsilised süsteemid toimivad, vaid näitavad pigem, kuidas ratsionaalsed agentid tajuvad nende süsteemide kasulikkust. Ideede viimiseks reaalse maailma rakendusteni tuleb üles käärida varrukad ja süveneda *piisavalt* madalate detailide juurde, mille keeles saab väljendada ja selgitada, kuidas kõik tegelikult töötab. Tarkvaraarenduses esindavad need madalamad tasemed tavaliselt lähtekoodi.
Koodi järkjärguline viimine nõutud käitumise seisu ja selle dokumenteerimine, kuidas nad sinna jõudsid, esitatakse programmeerijate poolt snapshot'ide ja changest'ide kaudu. Snapshot on toote kindel seisund koos kõikide madalamate detailidega, samas kui changeset tähistab üleminekut snapshot'ide vahel. Tavaliselt genereeritakse snapshot'id nende vanemate juurde kuuluvate üksikute changeset'ide kaudu, seega need snapshot'id tähistatakse tavaliselt selle, mida need changeset'id teevad, mistõttu neid termineid kasutatakse sageli vahetatult.
Mõnikord on olemas snapshot'e, mis on saadud mitme ülemineku — commit'ide sulandumise — tulemusena. Nendega on keeruline töötada, seetõttu neid tavaliselt välditakse. Kaasaegsed avatud lähtekoodiga versioonihaldussüsteemid, nagu Git, pakuvad üsna põhjalikke võimalusi arendusprotsesside juhtimiseks. Need võimaldavad arendajatel korraldada snapshot'e suunatud suletud graafikutena, annotatsiooni kommentaaridega ja vajadusel muuta nende järjekorda.
See funktsionaalsus võimaldab arendajatel kirjutada semantiliselt tähendusrikka projekti ajaloo, mis on kriitilise tähtsusega veaparanduse ja küsimustele vastamiseks, nagu 'Miks see madalamate detailide (nt muutujate) sisestamine toimus?' 'Kui suur on minu panus sellesse projekti?' 'Keda tabas tagasilöök ja millal?' 'Milline madalamate tasemete muudatus rikkus selle funktsiooni (kuigi ei pidanud, me kontrollisime seda!?)'
Versioonihaldussüsteemid täiendavad seda kontseptsiooniga haru — madalamate tasemete mõiste, mis tähendab lihtsalt katkematut madalamate tasemete ajalugu projekti, mis on arendajale semantiliselt tähendusrikas. Harusid kasutatakse tavaliselt konkreetsete funktsioonide elluviimiseks, mõnikord luuakse mitu haru ühe ja sama funktsiooni erinevate kandidaatide jaoks. Kasutades harudega töötamise töövooge (mis on tegelikult peavool ja standard arenduses, kasutatakse igal pool), saab iga arendaja tõhusalt hallata mitmeid konfliktseid projekti haru, millest igaühel on erinev valmisolek või kvaliteet. See võimaldab arendajatel kombineerida oma ja teiste töö tulemusi ilma et peaks iga kord kõike käsitsi ümber kirjutama.
Tavaliselt luuakse peamine haru, mis esindab "ametlikku" toodet, millelt hargnevad külharud iga funktsiooni jaoks, mis sünkroniseeritakse regulaarsete intervallidega (ideaalis pärast igat commitit) peamise haruga, võimaldades arendajatel töötada kõige värskema toote versiooniga ja samal ajal rakendada funktsioone, mida nad parajasti arendavad, tuvastades probleemid, mis tulenevad teiste arendajate tegevustest, võimalikult vara.
Kuna püüda kombineerida eri snapshotide funktsioone (mis tähendab, et leida ühine eelkäija ja rakendada nende muutuste kogumeid järjestikku üle teise, nimetatakse seda operatsiooni rebase'iks; ühendamine on aga peaaegu nagu rebase, lihtsalt korraldab commit-graafi teisiti, mistõttu on sellega keerulisem manipuleerida ja seetõttu püütakse ühendamisest loobuda rebase-de kasuks), esinevad probleeme. Kaasaegsed versioonihaldussüsteemid (VCS) kasutavad sisemise muudatuste ühendamise algoritme, mis lihtsalt jagavad failid eraldi ridadeks, käsitledes iga rida kui sümbolit, ja faile – kui nende järjestusi, rakendades siis nende ühendamiseks algoritme, mis pärinevad bioinformaatikast.
Kahjuks ei oma selline ridade kaupa esitlemine allikakoodist midagi pistmist selle sisuga. Selle ainus eelis on see, et see on lihtne ja universaalne. Erinevused toovad kaasa konflikte, olles pidev peavalude allikas arendajatele. Konfliktide lahendamine nõuab arendajalt kahe koodiversiooni hoolikat uurimist, mitte ainult nende osade osas, mida ridade võrdlemise algoritm on tähistanud kui "muudetud" või "konflikti tekitavad", vaid võib-olla ka kogu projekti kohta.
Arendaja peab mõistma muudatusi, kirjutama käsitsi ühendatud koodi ja kõrvaldanud kõik erinevused. Probleeme lisandub siis, kui ridade tööriist tuvastab muudatusi valesti, mis juhtub sageli suuremate muudatuste, sealhulgas triviaalsete, näiteks koodi vormindamise puhul. Kui järgnevaid muudatusi ei suudeta rakendada käsitsi ühendatud koodi, muutub olukord täielikuks õuduseks. Hoolimata kohutavatest juhtudest töötab enamikul juhtudel ridade algoritm, eriti kui arendajad püüavad aktiivselt mitte tekitada selle jaoks probleeme. Üks viis selliste probleemide minimeerimiseks on allika töötlemise kohustuslike nõuete seadmine kanoniseerimise tööriistade kaudu, nagu black.
Muidugi on õige lahendus õudsetele juhtumitele (ja mitte ainult neile; ridade algoritm on heuristika, mis võib triviaalsetel viisidel viia mitte töötava koodini; näiteks kui üks arendaja nimetab muutuja ümber ja teine kirjutab samal ajal uue koodilõigu, mis kasutab seda muutujat, siis konflikti ühendamise/rebase'i osas ei teki, aga tulemus on mittetöötav) – kasutada õiget sisemist mudelit.
Hoolimata sellest, et selles valdkonnas on uurimistööd tehtud juba umbes 30 aastat ja see on viinud mitmete patenteeritud kommertstootete loomise juurde, ei ole need uurimistööd hiljuti praktilisteks rakendusteks avatud allikaga toodeteks muutunud. Enamik avatud lähtekoodiga lahendusi hakkas arenema 2010. aastate alguses ja keskendus peamiselt Java keelele.
Selle perioodi silmapaistvaim avatud lahendus, GumTree, on loodud akadeemilise taustaga uurija poolt, kirjutatud Java keeles, omab oma abstraktset sisemist representatsiooni, mis eelnes treesitter'ile, ja omab nii treesitter'iga kui ka muude tööriistadega põhinevaid tagaplane, et parsimise lähtekood muutuks abstraktseteks representatsioonideks. See süsteem suudab ainult genereerida (sündmuste tekstilögana, samuti on API, mida saab lihtsalt kutsuda mistahes programmeerimiskeelest, millel on Java sidemed) ja visualiseerida muudatusi. Siiski, muudatuste ühendamiseks ega genereeritud diff-failide vaatamiseks, ei sobi see kohe (kuigi on tõenäoline, et diff-ide laadimise saab rakendada API kaudu).
Noorem ja praktikas rakendatav difftastic lahendus, kirjutatud Rust'is, põhineb treesitter'il ja keskendub eristatud diff-ide genereerimisele konsoolis. See süsteem on samuti suunatud diff-ide visualiseerimisele ja ei sea oma eesmärkideks muudatuste ühendamist ega patchide rakendamist.
Hiljuti ilmus ja aktiivselt areneb projekt mergiraf. See Rustis kirjutatud tööriist (moodustab 21 MiB!) põhineb samuti treesitteril, mis on muutunud sama standardiks kontekstivabade grammatika parserite seas nagu LLVM madala taseme käsute esituste optimeerimise jaoks. Erinevalt konkurentidest pakub mergiraf mitte diff'ide genereerimise funktsioone, vaid automaatse konfliktide lahendamise võimalusi. Mergiraf kasutab patšide genereerimisel GumTree algoritmi rakendust ja nende rakendamisel spork algoritmi rakendust, mis on kohandatud treesitteri struktuuride jaoks.
Patšide serialiseerimist failidesse, mida saaks hiljem rakendada, kahjuks ei ole rakendatud (aga on täiesti võimalik, et see võiks olla teostatav GumTree genereeritud sündmuste logide parsimise kaudu). Teine perspektiivikas võimalus erinevuste rakendamiseks võiks olla erinevuste rakendamine mitte patšide kaudu, vaid LSP-serverite refaktoreerimisfunktsionaalsuse kaudu, mis võiks aidata avastada konflikte kogu projekti tasemel. Visualiseerimine toetab ainult konfliktilahendust.
Töö näide: ühine esiis «base.py» (tabulatsioonidega taanded, üks tühi rida alguses) foo = 1 def main(): print(foo + 2 + 3) «a.py» (tabulatsioonide säilitamine, 2 üleminekut tühja rida alguses, silumiskirjatud «icecream» raamatukogu kasutades, 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» nimetatakse ümber «bar», muudetud «black» abil, tulemuseks on taandena tühjad read eemaldatud): bar = 1 def main(): print(bar + 2 + 3) Kutsumine ./mergiraf merge ./base.py ./a.py ./b.py -x a.py -y b.py -s base.py -o ./res.py annab järgmise tulemuse from icecream import ic bar = 1 def main(): ic(bar + 2 + 3) class baz: def __init__(self): «»»baz»»» (silumiskirjatu «icecream» raamatukogu kasutades, muutujat «foo» nimetatakse ümber «bar», muudetud «black» abil, tulemuseks on taandena tühjad read eemaldatud, tabulatsioonide ja ruutude segu, kuid lubatud vormi saavutamine).
Siin on nähtav tööriista puudus. Dokumentide stiil konfigureeritakse tavaliselt failides «.editorconfig», ning globaalsete stiilimuudatuste, nagu tabulatsioonide muutmine ruutudeks ning black stiili vastuvõtmine, nagu seda tehti «b.py», käivad tavaliselt koos muudatustega failis «.editorconfig». Seetõttu peaks tööriist sarnaste muudatuste korrektsemaks rakendamiseks omama mõistet globaalsetest vaikimisi stiilidest ja suutma seadistusi «.editorconfig» failist laadida.
Allikas: opennet.ru
