ĂshtĂ« publikuar lĂ«shimi i projektit mergiraf 0.4, i cili zhvillon njĂ« drejtues pĂ«r Git me implementimin e mundĂ«sisĂ« sĂ« bashkimit trepalĂ«sh. Mergiraf mbĂ«shtet zgjidhjen e llojeve tĂ« ndryshme tĂ« konflikteve gjatĂ« bashkimit dhe mund tĂ« pĂ«rdoret pĂ«r gjuhĂ« programuese dhe formate skedash tĂ« ndryshme. ĂshtĂ« e mundur tĂ« thirret mergiraf si njĂ« thirrje e veçantĂ« pĂ«r tĂ« trajtuar konfliktet qĂ« ndodhin gjatĂ« punĂ«s me Git tĂ« zakonshĂ«m, si dhe tĂ« zĂ«vendĂ«sohet nĂ« Git si njĂ« trajtues i bashkimeve pĂ«r tĂ« zgjeruar aftĂ«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 dukshĂ«m i njĂ« sistemi shumĂ« kompleks. Sistemet komplekse kanĂ« njĂ« pronĂ« tĂ« pĂ«rbashkĂ«t â ato janĂ« TĂ KOMPLEKSISHME â dhe nuk mund tĂ« prisni qĂ« sjellja e nevojshme komplekse tĂ« krijohet vetvetiu, rastĂ«sisht. NĂ« vend tĂ« kĂ«saj, kĂ«to sisteme evoluojnĂ« me kalimin e kohĂ«s, hap pas hapi, dhe çdo mutacion kontrollohet me kujdes nĂ« çdo etapĂ«. PĂ«r tĂ« arritur kĂ«tĂ« nevojiten njĂ« strukturĂ« e mirĂ« e pĂ«rcaktuar dhe mjete pĂ«rkatĂ«se. Evolucioni i çdo sistemi tĂ« komplikuar mund tĂ« vizatohet si njĂ« pemĂ« drejtues, ku rrĂ«nja pĂ«rfaqĂ«son njĂ« grup tĂ« zbrazĂ«t funksionesh, dhe çdo nyje â pĂ«rveç rrĂ«njĂ«s â Ă«shtĂ« rezultati i aplikimit tĂ« njĂ« mutacioni ndaj prindit tĂ« saj.
NĂ« kontekstin e produkteve, çdo nyje quhet "version", qĂ« pĂ«rfaqĂ«son njĂ« grup tĂ« caktuar funksionesh dhe anti-funksionesh. Ădo ndryshim i kĂ«tij grupi konsiderohet si njĂ« mutacion, duke formuar njĂ« skaj nĂ« grafikĂ«n tonĂ« drejtuesit akilik. KĂ«to funksione, nĂ« natyrĂ«n e tyre, janĂ« tĂ« abstraktĂ«; ato nuk pasqyrojnĂ« drejtpĂ«rdrejt mĂ«nyrat se si funksionojnĂ« sistemet fizike, por mĂ« shumĂ« demonstrojnĂ« se si agjentĂ«t racional percepsojnĂ« dobishmĂ«rinĂ« e kĂ«tyre sistemeve. PĂ«r tĂ« pĂ«rkthyer idetĂ« nĂ« realizime ekzistuese nĂ« botĂ«n reale, Ă«shtĂ« e nevojshme tĂ« ngremĂ« mĂ«ngĂ«t dhe tĂ« hedhim njĂ« vĂ«shtrim nĂ« detajet *mjaft* tĂ« ulĂ«ta, nĂ« njĂ« gjuhĂ« nĂ« tĂ« cilĂ«n mund tĂ« shprehim dhe tĂ« shpjegojmĂ« se si funksionon konkretisht gjithçka. NĂ« zhvillimin e softuerit, kĂ«to detaje tĂ« ulĂ«ta pĂ«rfaqĂ«sohen zakonisht nga kodi burimor.
Për të sjellë gradualisht kodin burimor në një gjendje që shfaq sjelljen e kërkuar dhe për të dokumentuar se si ata e arrijnë këtë, programuesit paraqesin punën e tyre në terma snapshot-ësh dhe changest-ash. Snapshot paraqet një gjendje të caktuar të produktit me të gjitha detajet e ulëta, ndërsa changeset tregon kalimin midis snapshot-ëve. Zakonisht snapshot-ët krijohen nga changeset të veçanta tek prindërit e tyre, kështu që këto snapshot-ë zakonisht etiketohen me atë që bëjnë changeset-të që i krijuan ato, prandaj këto terma shpesh përdoren ndërlidhur.
NdonjĂ«herĂ« ekzistojnĂ« snapshot-e qĂ« janĂ« marrĂ« si rezultat i disa kalimeve â bashkimeve tĂ« komiteteve. Ato janĂ« tĂ« vĂ«shtira pĂ«r t'u punuar, prandaj zakonisht shmangen. Sistemet 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Ă« programuesit tĂ« organizojnĂ« snapshot-et nĂ« njĂ« grafikĂ« drejtues akilik, t'i annotojnĂ« me komente dhe, nĂ«se Ă«shtĂ« e nevojshme, tĂ« ndryshojnĂ« rendin e tyre.
Kjo funksionalitet lejon programuesit të shkruajnë një histori semantikisht domethënëse të projektit, që është thelbësore për debimin dhe për t'iu përgjigjur pyetjeve si "Pse u mor kjo detaj e ulët (p.sh., variabli)?", "Sa përqind është kontributi im në këtë projekt?", "Kush e shpërthyu implementimin e backdoor-it dhe kur?", "Cila ndryshim i ulët e prishi këtë funksion (pavarësisht se nuk duhej, ne e kemi verifikuar gjithçka!?)"
Sistemet e kontrollit tĂ« versioneve e plotĂ«sojnĂ« kĂ«tĂ« konceptin e degĂ«ve â njĂ« koncept i ulĂ«t qĂ« do tĂ« thotĂ« thjesht njĂ« fragment tĂ« vazhdueshĂ«m tĂ« historisĂ« sĂ« ulĂ«t tĂ« projektit, semantikisht i rĂ«ndĂ«sishĂ«m pĂ«r programuesin. DegĂ«t zakonisht pĂ«rdoren pĂ«r implementimin e funksioneve specifike, ndonjĂ«herĂ« krijohen disa degĂ« pĂ«r kandidatĂ«t e ndryshĂ«m tĂ« implementimit tĂ« njĂ« funksioni tĂ« njĂ«jtĂ«. Duke pĂ«rdorur procese me degĂ«zim (tĂ« cilat nĂ« fakt janĂ« standardi kryesor dhe i zakonshĂ«m nĂ« zhvillim, pĂ«rdoren kudo), çdo programues individual mund tĂ« menaxhojĂ« me efikasitet shumĂ« degĂ« konflikti tĂ« projektit, secila prej tĂ« cilave diferencohet nga niveli i gatishmĂ«risĂ« ose cilĂ«sisĂ«. Kjo i lejon programuesit tĂ« kombinojnĂ« rezultatet e punĂ«s sĂ« tyre dhe tĂ« tjerĂ«ve pa pasur nevojĂ« tĂ« rishkruajnĂ« gjithçka manualisht çdo herĂ«.
Zakonisht, krijohet një degë kryesore që paraqet produktin "zyrtar", nga e cila degët anësore për secilën veçori e ndahen, të cilat rregullisht (idealisht pas çdo komitimi) sinkronizohen me degën kryesore, duke lejuar zhvilluesit të punojnë me versionin më të ri të produktit dhe njëkohësisht të integrojnë veçori që ata aktualisht po zhvillojnë, duke zbuluar probleme që lindin nga veprimet e zhvilluesve të tjerë sa më herët të jetë e mundur.
Kur përpiqeni të kombinoni veçori nga snapshot-e të ndryshme (çfarë është thjesht gjetja e një paraardhësi të përbashkët dhe aplikimi i sets ndryshimesh që i krijojnë ato, njëri pas tjetrit mbi tjetrin, kjo operacion quhet rebase, ndërsa bashkimi është thuajse si rebase, thjesht strukturohet ndryshe grafi i komiteteve, duke i bërë ata të vështirë për t'u manipuluar, prandaj evitohen bashkimet në favor të rebase-ve) janë probleme. Sistemët moderne të kontrollit të versioneve (VCS) përdorin algoritme të brendshme për të bashkuar ndryshime, të cilat thjesht ndajnë skedarët në rreshta të veçantë, i trajtojnë çdo rresht si simbol, dhe skedarët si sekuenca të tyre, dhe pastaj aplikojnë algoritme për t'i bashkuar ato, që kanë origjinën nga bioinformatika.
Më vjen keq, kjo paraqitje rresht pas rreshti e kodit burimor nuk ka asgjë të përbashkët me përmbajtjen e tij. I vetmi meritë është se është e thjeshtë dhe universale. Mos përputhjet çojnë në konflikte gjatë, duke qenë një burim i vazhdueshëm i dhimbjeve për zhvilluesit. Zgjidhja e konflikteve kërkon që zhvilluesi të studiojë me përpikëri të dy versionet e kodit, jo vetëm seksionet e markuara nga algoritmi rresht pas rreshti si "të ndryshuar" ose "konfliktuese", por ndoshta edhe të gjithë projektin.
Zhvilluesi duhet të kuptojë ndryshimet, të shkruajë manualisht kodin e bashkuar dhe të eliminojë çdo mos përputhje. Problemet shumëfishohen kur mjeti rresht pas rreshti identifikon gabimisht ndryshimet, që ndodh shpesh gjatë ndryshimeve të mëdha, duke përfshirë ato triviale, si reformati i kodit. Nëse ndryshimet e mëvonshme nuk mund të aplikohen në kodin e bashkuar manualisht, situata kthehet në një makth të plotë. Pavarësisht rasteve të frikshme, në shumicën e rasteve, algoritmi rresht pas rreshti funksionon, veçanërisht nëse zhvilluesit përpiqen aktivisht të mos krijojnë probleme. Një nga mënyrat për të minimizuar këto probleme është kërkesë e detyrueshme për përpunimin e burimeve me mjete të kanonizimit, siç është black.
Natyrisht, zgjidhja e duhur për rastet e tmerrshme (dhe përgjithësisht, jo vetëm për to, algoritmi rresht pas rreshti është një heuristikë, ai mund të çojë në kod të pambushur, për shembull një zhvillues e emëron një variabël të re, ndërsa një tjetër shkruan një pjesë të re kodi duke përdorur atë variabël, këtu nuk do të ketë konflikt bashkimi/rebase, por rezultati do të bëhet i pambushur) është përdorimi i një modeli të brendshëm të duhur.
Pavarësisht se studimet në këtë fushë janë duke u zhvilluar për rreth 30 vjet, dhe kanë çuar në krijimin e disa produkteve komerciale pronësore, këto kërkime deri në kohët e fundit nuk ishin shndërruar në produkte praktikisht të aplikueshme me kod të hapur. Shumica e zgjidhjeve të softuerit të lirë kanë filluar të zhvillohen në fillim të viteve 2010, dhe ishin fokusuar kryesisht në gjuhën Java.
Implementimi më i shquar i lirë i asaj periudhe, GumTree, u krijua nga një kërkues me një sfond akademik, shkruar në Java, ka një përfaqësim të brendshëm abstrakt, që i paraprin treesitter, ka backend-e si ato të baza në treesitter dhe ato të tjera për analizimin e kodit burimor në përfaqësime abstrakte. Ky sistem di vetëm të krijojë (në formën e një logu tekstual të ngjarjeve, gjithashtu ka një API, që mund të thirret lehtësisht nga çdo Gjuhë Programimi me lidhje me Java) dhe të vizualizojë ndryshimet. Megjithatë, për bashkimin e ndryshimeve, si dhe për shkarkimin e skedarëve të ndryshimeve të gjeneruara prej saj, nuk është përdorimi nga dola (megjithatë, ndoshta mund të implementohet shkarkimi i ndryshimeve përmes API).
Një implementim më i ri dhe më praktik i aplikueshëm i difftastic është shkruar në Rust, është i bazuar në treesitter, i fokusuar në gjenerimin e ndryshimeve të ndriçuara në konsolë. Ky sistem gjithashtu është i orientuar për të vizualizuar ndryshimet dhe nuk e ka qëllim bashkimin e ndryshimeve ose aplikimin e patch-eve.
Disa kohĂ« mĂ« parĂ«, projekti mergiraf doli dhe po zhvillohet aktivisht. Ky mjet i shkruar nĂ« Rust (zĂ« 21 MiB!) gjithashtu bazohet nĂ« treesitter, i cili Ă«shtĂ« bĂ«rĂ« njĂ« standard pĂ«r parserat e gramatikave kontekstualisht tĂ« lirĂ« nĂ« mjetet e zhvillimit, ashtu siç Ă«shtĂ« LLVM pĂ«r optimizimin e pĂ«rfaqĂ«simeve tĂ« ulĂ«ta tĂ« instruktimeve. Ndryshe nga konkurrentĂ«t, mergiraf ofron funksione jo pĂ«r gjenerimin e differencave, por pĂ«r zgjidhjen automatike tĂ« konflikteve tĂ« bashkimit. NĂ«n kapak, mergiraf pĂ«rdor pĂ«r gjenerimin e patch-ave 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.
Serilizimi i patch-ave në skedarë, të cilat mund të aplikohen më vonë, fatkeqësisht nuk është realizuar (por është krejtësisht e mundur që të realizohet përmes analizimit të regjistrave të ngjarjeve të gjeneruara nga GumTree). Një metodë tjetër premtuese për aplikimin e dallimeve mund të jetë përdorimi i ndryshimeve jo përmes patch-ave, por përmes funksionalitetit të ristrukturimit të LSP-serverëve, çka mund të ndihmojë në zbardhjen e konflikteve në nivelin e tërë projektit. Vizualizimi mbështetet vetëm për konfliktet.
Shembulli i funksionimit: stema e pĂ«rbashkĂ«t âbase.pyâ (indentim me tab, njĂ« varg i tepĂ«rt nĂ« fillim) foo = 1 def main(): print(foo + 2 + 3) âa.pyâ (indentim me tab, 2 vargje tĂ« tepĂ«rta nĂ« fillim nĂ« vend tĂ« njĂ«, pĂ«r printimin e ndihmĂ«s Ă«shtĂ« pĂ«rdorur biblioteka icecream, shtuar klasa âbazâ: from icecream import ic foo = 1 def main(): ic(foo + 2 + 3) class baz: def __init__(self): âââbazâââ âb.pyâ (variabli âfooâ Ă«shtĂ« rinomuar nĂ« âbarâ, i pĂ«rpunuar me âblackâ pas ndryshimeve, duke rezultuar nĂ« qĂ« indetimet janĂ« me hapĂ«sira dhe vargjet e tepĂ«rta 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 printimin e ndihmĂ«s Ă«shtĂ« pĂ«rdorur biblioteka âicecreamâ, variabli âfooâ Ă«shtĂ« rinomuar nĂ« âbarâ, i pĂ«rpunuar me âblackâ pas ndryshimeve, duke rezultuar nĂ« qĂ« indetimet janĂ« me hapĂ«sira dhe vargjet e tepĂ«rta janĂ« hequr, pĂ«rzierje tabesh dhe hapĂ«sirash pĂ«r indetim, por dukja e lejuar).
KĂ«tu e shohim njĂ« mangĂ«si tĂ« mjetit. Stili i dokumentit zakonisht konfigurohet nĂ« skedarĂ«t '.editorconfig', dhe ndryshimet globale tĂ« stilit, si ndryshimi i tabeve nĂ« hapĂ«sira dhe pranimi i stilit tĂ« black-it, siç Ă«shtĂ« bĂ«rĂ« nĂ« âb.pyâ, zakonisht shoqĂ«rohen me ndryshime nĂ« â.editorconfigâ. Prandaj, pĂ«r njĂ« aplikim mĂ« tĂ« saktĂ« tĂ« ndryshimeve tĂ« tilla, mjeti duhet tĂ« ketĂ« njĂ« koncept pĂ«r stilin global 'nĂ« default', dhe tĂ« dijĂ« si tĂ« tĂ«rheqĂ« cilĂ«simet nga â.editorconfigâ.
Burimi: opennet.ru
