ĂshtĂ« publikuar lĂ«shimi i projektit mergiraf 0.4, qĂ« zhvillon njĂ« driver pĂ«r Git me implementimin e mundĂ«sisĂ« sĂ« bashkĂ«veprimit tĂ« trefishtĂ«. Mergiraf mbĂ«shtet zgjidhjen e llojeve tĂ« ndryshme tĂ« konflikteve gjatĂ« bashkimit dhe mund tĂ« pĂ«rdoret pĂ«r gjuhĂ« programimi tĂ« ndryshme dhe formate skedujsh. ĂshtĂ« e mundur njĂ« thirrje e veçantĂ« mergiraf pĂ«r tĂ« trajtuar konfliktet qĂ« shkaktohen gjatĂ« punĂ«s me Git-in standard, si dhe zĂ«vendĂ«simi nĂ« Git tĂ«ć€ç tĂ« bashkimeve pĂ«r tĂ« zgjeruar mundĂ«sitĂ« e komandave si merge, revert, rebase dhe cherry-pick. Kodi shpĂ«rndahet nĂ«n licencĂ«n GPLv3. NĂ« versionin e ri Ă«shtĂ« shtuar mbĂ«shtetje pĂ«r gjuhĂ«t Python, TOML, Scala dhe Typescript, si dhe Ă«shtĂ« optimizuar performanca.
Më poshtë është një përshkrim i detajuar i problemeve që zgjidhen me anë të mergiraf:
Softueri Ă«shtĂ« njĂ« shembull i shkĂ«lqyer i njĂ« sistemi jashtĂ«zakonisht kompleks. Sistemet e komplikuara kanĂ« njĂ« veçori tĂ« pĂ«rbashkĂ«t â ato janĂ« TĂ KOMPLESIVE â dhe nuk mund tĂ« prisni qĂ« sjellja e komplikuar qĂ« ju nevojitet tĂ« shfaqet rastĂ«sisht. NĂ« vend tĂ« kĂ«saj, kĂ«to sisteme evoluojnĂ« me kalimin e kohĂ«s, hap pas hapi, dhe çdo mutacion verifikohet me kujdes nĂ« çdo hap. PĂ«r tĂ« arritur kĂ«tĂ« Ă«shtĂ« e nevojshme njĂ« strukturĂ« e mirĂ«filltĂ« dhe mjete pĂ«rkatĂ«se. Evolucioni i çdo sistemi tĂ« komplikuar mund tĂ« vizualizohet si njĂ« pemĂ« e orientuar, ku rrĂ«nja pĂ«rfaqĂ«son njĂ« grup tĂ« zbrazĂ«t funksionesh, dhe çdo nyjĂ« â pĂ«rveç rrĂ«njĂ«s â Ă«shtĂ« njĂ« rezultat i aplikimit tĂ« njĂ« mutacioni ndaj prindit tĂ« saj.
NĂ« kontekstin e produkteve, çdo nyjĂ« quhet "version", e cila pĂ«rfaqĂ«son njĂ« grup tĂ« caktuar funksionesh dhe anti-funksionesh. Ădo ndryshim i kĂ«tij grupi konsiderohet si njĂ« mutacion, qĂ« formon njĂ« skaj nĂ« grafikun tonĂ« tĂ« orientuar aciklik. KĂ«to funksione nĂ« thelb janĂ« abstrakte; ato nuk pasqyrojnĂ« drejtpĂ«rdrejt mĂ«nyrat se si funksionojnĂ« sistemet fizike, por mĂ« tepĂ«r tregojnĂ« se si agjentĂ«t racionalĂ« perceptojnĂ« dobishmĂ«rinĂ« e kĂ«tyre sistemeve. PĂ«r tĂ« pĂ«rkthyer idetĂ« nĂ« realizime ekzistuese nĂ« botĂ«n reale, Ă«shtĂ« e nevojshme tĂ« mbledhim mĂ«ngĂ«t dhe tĂ« zhytemi nĂ« detajet *mjaft* tĂ« nivelit tĂ« ulĂ«t, nĂ« njĂ« gjuhĂ« me tĂ« cilin mund tĂ« shprehim dhe shpjegojmĂ« se si funksionon konkretisht gjithçka. NĂ« zhvillimin e softuerit, kĂ«to nivel tĂ« ulĂ«t zakonisht pĂ«rfaqĂ«sohen nga kodi burimor.
Për të sjellë gradualisht kodin burimor në një gjendje që tregon sjelljen e kërkuar dhe për të dokumentuar se si arritën aty, programuesit e paraqesin punën e tyre në terma snapshot-esh dhe changeset-esh. Snapshot-i përfaqëson një gjendje të caktuar të produktit me të gjitha detajet e nivelit të ulët, ndërsa changeset-i shënon kalimin mes snapshot-esh. Në përgjithësi, snapshot-et krijohen nga changeset-et e vetme për prindërit e tyre, prandaj këto snapshot-e zakonisht shënohen me atë që bëjnë changeset-et që i krijuan, kështu që këto terma shpesh përdoren ndërlidhur.
NdonjĂ«herĂ« ekzistojnĂ« kopje qĂ« rezultojnĂ« nga disa kalime â bashkimi i komiteteve. Ato janĂ« tĂ« vĂ«shtira pĂ«r t'u punuar, prandaj zakonisht shmangen. Sistemete moderne tĂ« kontrollit tĂ« versioneve me burim tĂ« hapur, si Git, ofrojnĂ« mundĂ«si shumĂ« themelore pĂ«r menaxhimin e proceseve tĂ« zhvillimit. Ato lejojnĂ« zhvilluesit tĂ« organizojnĂ« kopje nĂ« formĂ«n e grafikĂ«ve tĂ« orientuar aciklik, t'i anotojnĂ« ato me komente dhe, nĂ« rast nevoje, tĂ« ndryshojnĂ« rendin e tyre.
Ky kjo funksionalitet u lejon zhvilluesve të shkruajnë një histori projektit që ka kuptim semantik, e cila është thelbësore për debugging dhe për t'u përgjigjur pyetjeve si "Pse u fut ky detaj i ulët (p.sh., variabla)?", "Sa përqind është kontribuimi im në këtë projekt?", "Kush e komprometoi implementimin e backdoor dhe kur?", "Cila ndryshim i ulët e prishi këtë funksion (ndonëse nuk duhej, ne e kontrolluam gjithçka!?)"
Sistemet e kontrollit të versioneve e plotësojnë këtë koncept me degën - një koncept të ulët që do të thotë thjesht një fragment të vazhdueshëm të historisë ulët të projektit, semantikisht të rëndësishëm për zhvilluesin. Degët zakonisht përdoren për implementimin e veçorive specifike, ndonjëherë krijohen disa degë për kandidatët e ndryshme në implementimin e të njëjtës veçori. Duke përdorur flukset e punës me degëzim (të cilat në fakt janë rrjedha kryesore dhe standardi i zhvillimit, përdoren kudo dhe gjithandej), çdo zhvillues i veçantë mund të menaxhojë në mënyrë efektive shumë degë konflikti të projektit, secila e ndryshme sipas nivelit të gatishmërisë ose cilësisë. Kjo u lejon zhvilluesve të bashkojnë rezultatet e punës së tyre dhe të tjerëve pa e riparë gjithçka manualisht çdo herë.
Zakonisht krijohet një degë kryesore që përfaqëson produktin "zyrtar", nga e cila dege të anësishme ndahen për çdo veçori, të cilat rregullisht (idealisht - pas çdo komitimi) sinkronizohen me degën kryesore, duke u lejuar zhvilluesve të punojnë me versionin më të fundit të produktit dhe njëkohësisht të implementojnë veçoritë që ata po zhvillojnë aktualisht, duke identifikuar problemet që rriten nga veprimet e zhvilluesve të tjerë sa më shpejt të jetë e mundur.
Kur pĂ«rpiqesh tĂ« kombinosh funksionet e snapshot-eve tĂ« ndryshme (çka Ă«shtĂ« thjesht gjetja e paraardhĂ«sit tĂ« pĂ«rbashkĂ«t dhe aplikimi i seteve tĂ« ndryshimeve qĂ« i krijojnĂ« ato, njĂ« pas njĂ«, mbi njĂ« tjetĂ«r, kjo operacion quhet rebase, ndĂ«rsa bashkimi â Ă«shtĂ« pothuajse si rebase, thjesht strukturojnĂ« grafikun e komiteteve ndryshe, si rezultat i tĂ« cilit bĂ«het e vĂ«shtirĂ« tĂ« manipulohet, prandaj nga bashkimet pĂ«rpiqen tĂ« heqin dorĂ« nĂ« favor tĂ« rebase-ve), gjithmonĂ« hasen probleme. Sistemet moderne tĂ« kontrollit tĂ« versioneve (VCS) pĂ«rdorin algorithemb tĂ« brendshme pĂ«r bashkimin e ndryshimeve, qĂ« thjesht ndajnĂ« skedarĂ«t nĂ« rreshta tĂ« veçantĂ«, i konsiderojnĂ« çdo rresht si njĂ« simbol, dhe skedarĂ«t si sekuenca tĂ« tyre, dhe mĂ« pas aplikojnĂ« algorithembet pĂ«r bashkimin e tyre, qĂ« janĂ« nga bioinformatika.
Fatkeqësisht, kjo paraqitje rreshtore e kodit burimor nuk ka asnjë lidhje me përmbajtjen e tij. Cilësia e vetme e saj është se është e thjeshtë dhe universale. Paqartësia çon në konflikte, duke qenë një burim i vazhdueshëm i dhimbjeve të kokës për zhvilluesit. Zgjidhja e konflikteve kërkon nga zhvilluesi një shqyrtim të kujdesshëm të të dy versioneve të kodit, përfshirë jo vetëm seksionet e shënuara nga algoritmi rreshtor si 'të ndryshuara' ose 'në konflikt', por ndoshta edhe të gjithë projetin.
Zhvilluesi duhet të kuptojë ndryshimet, të shkruajë manualisht kodin e bashkuar dhe të eliminojë çdo paqartësi. Problemet shtohen kur instrumenti rreshtor identifikon gabimisht ndryshimet, gjë që ndodh shpesh gjatë ndryshimeve të mëdha, përfshirë ato triviale si ndryshimi i formatit të kodit. Nëse ndryshimet pasuese nuk mund të aplikohen mbi kodin e bashkuar manualisht, situata shndërrohet në një makth të plotë. Pavarësisht rasteve alarmuese, në shumicën e rasteve, algoritmi rreshtor funksionon, veçanërisht nëse zhvilluesit përpiqen aktivisht të mos i krijojnë probleme. Një nga mënyrat për të minimizuar këto probleme është kërkesa e detyrueshme për trajtimin e burimeve nga instrumente kanonizimi, si black.
Natyrisht, zgjidhja e duhur pĂ«r tĂ« gjitha rastet e tmerrshme (dhe nĂ« pĂ«rgjithĂ«si, jo vetĂ«m pĂ«r to, algoritmi rresht-pĂ«r-rresht â Ă«shtĂ« njĂ« heuristikĂ«, ai mund tĂ« çojĂ« nĂ« kod jo funksional nĂ« mĂ«nyrĂ« triviale, pĂ«r shembull, njĂ« zhvillues e emĂ«ron njĂ« variabĂ«l ndryshe, ndĂ«rsa njĂ« tjetĂ«r shkruan njĂ« copĂ« kod tĂ« ri qĂ« pĂ«rdor atĂ« variabĂ«l, nuk do tĂ« ketĂ« njĂ« konflikt fusioni/promovimi kĂ«tu, por rezultati do tĂ« bĂ«het jo funksional) â Ă«shtĂ« pĂ«rdorimi i modelit tĂ« duhur tĂ« brendshĂ«m.
Pavarësisht se kërkimet në këtë fushë janë zhvilluar për rreth 30 vjet, dhe kanë rezultuar në krijimin e disa produkteve komerciale pronësore, këto kërkime deri në kohët e fundit nuk janë shndërruar në produkte praktikisht të aplikueshme me burim të hapur. Masa kryesore e zgjidhjeve të softuerit të lirë filloi të zhvillohej në fillim të viteve 2010 dhe ishte e fokusuar kryesisht në gjuhën Java.
Implementimi më i dukshëm i lirë i atij periudhe, GumTree, u krijua nga një hulumtues me një sfond akademik, është shkruar në Java, ka një përfaqësim të brendshëm abstrakt, që i përkiste para treesitter, ka backend si ato që bazohen në treesitter ashtu edhe ato që bazohen në mjete të tjera për analizimin e kodit burimor në përfaqësime abstrakte. Ky sistem di vetëm të gjenerojë (në formën e një logu të ngjarjeve tekstuale, po ashtu ka një API që mund të thirret lehtësisht nga çdo gjuhë programimi që ka lidhje me Java) dhe të vizualizojë ndryshimet. Megjithatë, për përzierjen e ndryshimeve, po ashtu si për shikimin e skedarëve diff të gjeneruar prej saj, ai është i papërshtatshëm nga kutia (megjithatë, është e mundur që ngarkimi i diffeve mund të realizohet përmes API-së).
Një implementim më i ri dhe më praktik i difftastic, i shkruar në Rust, bazohet në treesitter, është fokusuar në gjenerimin e diffeve të ndriçuara në konsolë. Ky sistem gjithashtu është i orientuar drejt vizualizimit të diffeve dhe në përgjithësi nuk ka si qëllim përzierjen e ndryshimeve ose aplikimin e patch-eve.
SĂ« fundmi ka dalĂ« dhe po zhvillohet aktivisht projekti mergiraf. Ky mjet i shkruar nĂ« Rust (zĂ« 21 MiB!) gjithashtu bazohet nĂ« treesitter, i cili Ă«shtĂ« bĂ«rĂ« standard pĂ«r parserĂ« tĂ« gramatikave kontekstualisht tĂ« lirĂ« nĂ« mjetet e zhvillimit, ashtu siç Ă«shtĂ« bĂ«rĂ« LLVM pĂ«r optimizimin e pĂ«rfaqĂ«simeve tĂ« ulĂ«ta tĂ« instruksioneve. Ndryshe nga konkurrentĂ«t, mergiraf ofron funksione jo pĂ«r tĂ« gjeneruar diffs, por pĂ«r tĂ« zgjidhur automatikisht konfliktet e bashkimeve. NĂ«n kapak, mergiraf pĂ«rdor pĂ«r gjenerimin e patches njĂ« implementim tĂ« algoritmit tĂ« pĂ«rdorur nĂ« GumTree, dhe pĂ«r aplikimin â njĂ« implementim tĂ« algoritmit tĂ« pĂ«rdorur nĂ« spork, tĂ« adaptuar pĂ«r strukturat treesitter.
Serializimi i patch-eve në skedarë, të cilat mund të aplikohen më vonë, për fat të keq, nuk është realizuar (por është e mundur që të realizohet përmes analizimit të logeve të ngjarjeve që gjenerohen nga GumTree). Një mënyrë tjetër e premtuar për aplikimin e ndryshimeve mund të jetë përdorimi i ndryshimeve jo përmes patch-eve, por përmes funksionalitetit të rishikimit të serverëve LSP, që mund të ndihmojë në identifikimin e konflikteve në nivelin e tërë projektit. Vizualizimi mbështetet vetëm për konfliktet.
Shembulli i punĂ«s: pĂ«rmendorja e pĂ«rbashkĂ«t "base.py" (indentaime me tab, rreshti i tepĂ«rt nĂ« fillim) foo = 1 def main(): print(foo + 2 + 3) "a.py" (indentaime akoma me tab, 2 rreshta tĂ« tepĂ«rt nĂ« fillim nĂ« vend tĂ« njĂ«rit, pĂ«r printim pĂ«r debug pĂ«rdoret biblioteka icecream, klasa "baz" Ă«shtĂ« shtuar: from icecream import ic foo = 1 def main(): ic(foo + 2 + 3) class baz: def __init__(self): """baz""" "b.py" (variabla "foo" e riemĂ«ruar nĂ« "bar", e pĂ«rpunuar me "black" pas ndryshimeve, si rezultat indentaimet â janĂ« me hapĂ«sira dhe rreshtat e tepĂ«rt janĂ« hequr): bar = 1 def main(): print(bar + 2 + 3) Thirrja .\/mergiraf merge .\/base.py .\/a.py .\/b.py -x a.py -y b.py -s base.py -o .\/res.py jep rezultatin e mĂ«poshtĂ«m from icecream import ic bar = 1 def main(): ic(bar + 2 + 3) class baz: def __init__(self): """baz""" (pĂ«r printim pĂ«r debug pĂ«rdoret biblioteka "icecream", variabla "foo" e riemĂ«ruar nĂ« "bar", e pĂ«rpunuar me "black" pas ndryshimeve, si rezultat indentaimet â janĂ« me hapĂ«sira dhe rreshtat e tepĂ«rt janĂ« hequr, pĂ«rzierje tab dhe hapĂ«sirash pĂ«r indentaim, por dukuria e lejuar).
Këtu shfaqet një mangësi e mjetit. Stili i dokumentit zakonisht konfigurohet në skedarët "editorconfig", dhe ndryshime globale të stilit, si kalimi nga tabullat në hapësira dhe pranimi i stilit black, siç u bë në "b.py", zakonisht shoqërohen me ndryshime në "editorconfig". Prandaj, për një zbatim më të saktë të ndryshimeve të tilla, mjeti duhet të ketë një koncept për stilin global "për të gjithë", dhe të jetë në gjendje të marrë cilësimet nga "editorconfig".
Burimi: opennet.ru
