Хувилбар хяналтын систем (Git)
Хувилбарын хяналтын системүүд (Version Control Systems буюу VCS) нь эх кодын (эсвэл бусад файл, хавтасны цуглуулгын) өөрчлөлтийг хянахад ашиглагддаг хэрэгслүүд юм. Нэрнээс нь харахад эдгээр хэрэгсэл нь өөрчлөлтийн түүхийг хадгалахад туслахаас гадна хамтын ажиллагааг хөнгөвчилж өгдөг. Логик хувьд VCS нь хавтас болон түүний агуулгын өөрчлөлтийг цуврал снапшотууд (snapshots) хэлбэрээр хянах бөгөөд снапшот бүр нь хамгийн дээд түвшний директор доторх файл/хавтасны тухайн үеийн төлөвийг бүрэн агуулдаг. Мөн VCS нь снапшот бүрийг хэн үүсгэсэн, ямар тайлбар мэдээлэл дагалдсан зэрэг мета-өгөгдлийг (metadata) хадгалдаг.
Хувилбарын хяналт яагаад хэрэгтэй вэ? Ганцаараа ажиллаж байхдаа ч энэ нь төслийн хуучин снапшотуудыг харах, тодорхой өөрчлөлтүүд яагаад хийгдсэн тухай лог хөтлөх, хөгжүүлэлтийн зэрэгцээ салаалан (branches) ажиллах зэрэг олон боломжийг олгодог. Бусадтай хамтран ажиллах үед бусад хүмүүс юу өөрчилснийг харах, зэрэгцээ хөгжүүлэлтийн зөрчлүүдийг (conflicts) шийдвэрлэхэд маш чухал хэрэгсэл болдог.
Орчин үеийн VCS-үүд нь дараах асуултуудад хялбархан (мөн ихэвчлэн автоматаар) хариулахад тусалдаг:
- Энэ модулийг хэн бичсэн бэ?
- Энэ файлын энэ тодорхой мөр хэзээ, хэнээр, ямар шалтгаанаар засварлагдсан бэ?
- Сүүлийн 1000 өөрчлөлтийн явцад, тодорхой нэгж тест (unit test) хэзээ, яагаад ажиллахаа больсон бэ?
Бусад VCS байдаг ч Git нь хувилбарын хяналтын де-факто стандарт хэрэгсэл юм. Энэхүү XKCD комик Git-ийн нэр хүндийг маш сайн илэрхийлдэг:

Git-ийн интерфейс нь кодын дотоод хэрэгжилтийг ил гаргадаг leaky abstraction тул түүхийг дээрээс нь доош нь (интерфейс буюу командын мөрнөөс нь эхэлж) сурах нь маш их төөрөгдөл үүсгэдэг. Хэдхэн тушаалыг цээжлээд шидэт шившлэг шиг ашиглаж, ямар нэгэн зүйл буруу болох үед дээрх комик шиг бүгдийг устгаад дахин татдаг хүмүүс олон байдаг.
Git нь ашиглахад тийм ч таатай биш интерфейстэй байж болох ч түүний суурь дизайн, санаанууд нь үнэхээр гайхалтай юм. Муухай интерфейсийг цээжлэх шаардлагатай байдаг бол үзэсгэлэнтэй дизайныг ойлгон ухамсарлаж болдог. Энэ шалтгаанаар бид Git-ийг доороос нь дээш буюу өгөгдлийн загвараас (data model) нь эхлэн тайлбарлаж, дараа нь командын мөрийн интерфейсийг нь авч үзэх болно. Өгөгдлийн загварыг ойлгосны дараа командуудыг тэдгээр нь суурь өгөгдлийг хэрхэн өөрчилж байгаагоор нь илүү сайн ойлгож чадна.
Git-ийн өгөгдлийн загвар
Git-ийн давуу тал нь түүний түүхийг хадгалах, салаалах хөгжүүлэлтийг дэмжих, мөн хамтын ажиллагааг хангах зэрэг хувилбарын хяналтын бүх шилдэг боломжуудыг олгодог өгөгдлийн загварт оршдог.
Снапшотууд (Snapshots)
Git нь хамгийн дээд түвшний хавтас доторх файл болон хавтаснуудын түүхийг цуврал снапшот хэлбэрээр загварчилдаг. Git-ийн нэршлээр бол файлыг “blob” гэх бөгөөд энэ нь ердөө л багц байтууд юм. Хавтасыг “tree” (мод) гэх бөгөөд энэ нь нэрсийг blob эсвэл өөр tree-тэй холбодог (ингэснээр хавтас дотор өөр хавтас байж болно). Снапшот нь хянагдаж буй хамгийн дээд түвшний tree (мод) юм. Жишээлбэл, бид дараах бүтэцтэй tree-тэй байж болно:
<root> (tree)
|
+- foo (tree)
| |
| + bar.txt (blob, contents = "hello world")
|
+- baz.txt (blob, contents = "git is wonderful")
Энэхүү хамгийн дээд түвшний tree нь “foo” нэртэй tree (дотроо “bar.txt” нэртэй blob агуулсан) болон “baz.txt” нэртэй blob гэсэн хоёр элементийг агуулж байна.
Түүхийг загварчлах нь: снапшотуудын хамаарал
Хувилбар хяналтын систем нь снапшотуудыг хэрхэн холбох ёстой вэ? Хамгийн энгийн загвар бол шугаман түүх байх болно. Түүх нь цаг хугацааны дараалал бүхий снапшотуудын жагсаалт байна. Гэвч Git нь олон шалтгааны улмаас ийм энгийн загвар ашигладаггүй.
Git-д түүх нь снапшотуудын directed acyclic graph (DAG) буюу чиглэлт ацикл график юм. Энэ нь математикийн нарийн үг мэт сонсогдож болох ч бүү сандраарай. Энэ нь ердөө л Git дэх снапшот бүр өөрийн өмнөх снапшотууд болох “эцэг (parents)” снапшотууд руу чиглэсэн холбоосыг заадаг гэсэн үг юм. Энэ нь шугаман түүх шиг ганц эцэг биш, харин багц эцэг байна. Учир нь зэрэгцээ салаалсан (branches) хөгжүүлэлтүүдийг нэгтгэх (merging) үед нэг снапшот олон эцгээс үүсэж болно.
Git эдгээр снапшотуудыг “commit” (коммит) гэж нэрлэдэг. Коммитуудын түүхийг дараах байдлаар дүрсэлж болно:
o <-- o <-- o <-- o
^
\
--- o <-- o
Дээрх зураглалд o тэмдэгтүүд нь тусдаа коммитуудыг (снапшот) илэрхийлнэ.
Сумнууд нь коммит бүрийн эцэг рүү чиглэж байна (энэ нь “дараагийнх нь өмнөх
рүүгээ чиглэх” хамаарал юм). Гурав дахь коммитын дараа түүх хоёр тусдаа салаа
(branches) болон хуваагдаж байна. Энэ нь, жишээлбэл, хоёр өөр боломжийг бие даан,
зэрэгцээ хөгжүүлж байгааг илэрхийлж болно. Ирээдүйд эдгээр салааг нэгтгэж,
хоёр боломжийг хоёуланг нь агуулсан шинэ снапшот үүсгэж болох бөгөөд үр дүнд нь
түүх дараах байдалтай харагдах ба шинээр үүссэн нэгтгэлийн (merge) коммитыг
тодоор харуулав:
o <-- o <-- o <-- o <---- o
^ /
\ v
--- o <-- o
Git-ийн коммитууд нь өөрчлөгдөшгүй (immutable) байдаг. Энэ нь алдааг засаж болохгүй гэсэн үг биш; харин түүхийг “засварлах” үед үнэндээ цоо шинэ коммитууд үүсдэг бөгөөд reference-үүд (доороос үзнэ үү) шинэ коммитууд руу чиглэхээр шинэчлэгддэг.
Өгөгдлийн загвар, псевдо кодоор
Git-ийн өгөгдлийн загварыг псевдо кодоор бичсэнийг үзэх нь илүү ойлгомжтой байж болох юм:
// файл нь багц байтууд байна
type blob = array<byte>
// хавтас нь нэр бүхий файл, хавтаснуудыг агуулна
type tree = map<string, tree | blob>
// коммит нь эцэг, мета-өгөгдөл болон дээд түвшний tree-ийг агуулна
type commit = struct {
parents: array<commit>
author: string
message: string
snapshot: tree
}
Энэ бол түүхийг хадгалах маш цэвэрхэн, энгийн загвар юм.
Объектууд болон агуулгаар хаяглах нь
“Объект” гэдэг нь blob, tree, эсвэл commit-ийн аль нэг нь юм:
type object = blob | tree | commit
Git-ийн өгөгдлийн санд бүх объектууд өөрсдийн SHA-1 хэшээр агуулгаар хаяглагддаг (content-addressed).
objects = map<string, object>
def store(object):
id = sha1(object)
objects[id] = object
def load(id):
return objects[id]
Blob, tree, коммит зэрэг нь бүгд объектууд бөгөөд ингэж нэгддэг. Тэд бусад объектуудыг заахдаа диск дээр өөртөө шууд агуулдаггүй, харин тэдгээрийн хэшээр холбоосыг хадгалдаг.
Жишээлбэл, дээрх хавтасны бүтцийг харуулсан tree (git cat-file -p
698281bc680d1995c5f4caaf3359721a5a58d48d тушаалаар харвал) дараах байдалтай
байна:
100644 blob 4448adbf7ecd394f42ae135bbeed9676e894af85 baz.txt
040000 tree c68d233a33c5c06e0340e4c224f0afca87c8ce87 foo
Энэхүү tree нь өөрийн агуулга болох baz.txt (blob) болон foo (tree) рүү
чиглэсэн заагчийг агуулж байна. Хэрэв бид baz.txt-ийн хэшээр хаяглагдсан агуулгыг
git cat-file -p 4448adbf7ecd394f42ae135bbeed9676e894af85 ажиллуулж харвал
дараах үр дүнг авна:
git is wonderful
Reference-үүд (References)
Одоо бүх снапшотуудыг өөрсдийн SHA-1 хэшээр нь тодорхойлж болно. Гэвч энэ нь тохиромжгүй юм, учир нь хүмүүс 40 тэмдэгтээс бүрдсэн арван зургаатын тоог цээжлэхдээ муу байдаг.
Git-ийн шийдэл бол SHA-1 хэшүүдэд хүнд уншихад хялбар нэр өгөх явдал бөгөөд
үүнийг “reference” гэнэ. Reference-үүд нь коммитууд руу чиглэсэн заагч юм.
Өөрчлөгдөшгүй объектуудаас ялгаатай нь reference-үүд нь өөрчлөгдөх боломжтой
(өөр коммит руу чиглүүлэн шинэчилж болно). Жишээлбэл, master reference нь
хөгжүүлэлтийн үндсэн салааны (main branch) хамгийн сүүлийн коммит руу чиглэж
байдаг.
references = map<string, string>
def update_reference(name, id):
references[name] = id
def read_reference(name):
return references[name]
def load_reference(name_or_id):
if name_or_id in references:
return load(references[name_or_id])
else:
return load(name_or_id)
Үүний тусламжтайгаар Git урт хэш тооны оронд “master” гэх мэт хүнд ойлгомжтой нэрийг ашиглан түүхэн дэх тодорхой снапшотыг зааж чаддаг.
Нэг зүйлийг анхаарахад бидэнд түүхэн дэх “одоо хаана байна вэ” гэсэн ойлголт
хэрэгтэй байдаг бөгөөд ингэшээр шинэ снапшот үүсгэхэд түүнийг ямар коммитоос
эхлэхийг (коммитын parents талбарыг хэрхэн оноохыг) мэддэг. Git-д энэхүү
одоогийн байршлыг “HEAD” гэж нэрлэдэг тусгай reference заадаг.
Репозиториуд (Repositories)
Эцэст нь бид Git-ийн repository (репозитори) гэж юу болохыг тодорхойлж болно:
энэ нь ердөө л objects болон references гэсэн өгөгдөл юм.
Диск дээр Git-ийн хадгалдаг зүйл бол ердөө л объектууд болон reference-үүд
юм: Git-ийн өгөгдлийн загварт өөр зүйл байхгүй. Бүх git тушаалууд нь
өгөгдлийн граф бүтцэд шинэ объект нэмэх, reference-үүдийг нэмэх/шинэчлэх замаар
коммитын DAG-ийг өөрчлөх үйлдэл рүү хөрвөдөг.
Ямар нэгэн тушаал ажиллуулах болгондоо уг тушаал цаанаа өгөгдлийн граф бүтцэд
ямар өөрчлөлт оруулж байгааг бодож байгаарай. Жишээлбэл, хэрэв та граф бүтцэд
“хийгдээгүй байгаа өөрчлөлтүүдийг хаяад ‘master’ reference-ийг 5d83f9e коммит
руу чиглүүлэх” өөрчлөлт хийхийг хүсвэл үүнийг хийх тушаал байгаа (энэ тохиолдолд
git checkout master; git reset --hard 5d83f9e байна).
Staging area
Энэ бол өгөгдлийн загвараас тусдаа боловч коммит үүсгэх интерфейсийн нэг хэсэг болох чухал ойлголт юм.
Снапшот үүсгэхийг ажлын хавтасны одоогийн төлөв дээр суурилан шууд үүсгэдэг гэж төсөөлж болох юм. Зарим хувилбар хяналтын хэрэгслүүд ингэж ажилладаг боловч Git тэгдэггүй. Бид цэвэрхэн снапшотуудыг үүсгэхийг хүсдэг бөгөөд одоогийн байгаа бүх өөрчлөлтийг шууд снапшот болгох нь үргэлж тохиромжтой байдаггүй. Жишээлбэл, та хоёр өөр боломжийг хөгжүүлсэн бөгөөд тэдгээрийг хоёр тусдаа коммит болгохыг хүсэж байна гэж бодъё. Эсвэл кодонд дебаг хийх явцдаа олон газар print тушаалуудыг бичсэн бөгөөд тэдгээрийг оруулахгүйгээр зөвхөн алдаа зассан хэсгээ коммит болгохыг хүсэж болно.
Git нь дараагийн снапшотдоо аль өөрчлөлтүүдийг оруулахыг зааж өгөх боломжийг staging area (бэлтгэл талбар) гэх механизмаар дамжуулан олгодог.
Git-ийн командын мөрийн интерфейс
Мэдээллийг давтахгүй байх үүднээс бид лекцийн тэмдэглэлд командуудыг нэг бүрчлэн тайлбарлахгүй. Дэлгэрэнгүй мэдээллийг Pro Git номоос үзэх эсвэл лекцийн бичлэгийг үзнэ үү.
Үндсэн тушаалууд (Basics)
git help <command>: Git тушаалын тусламжийг харахgit init: шинэ Git repository үүсгэх бөгөөд өгөгдөл нь.gitхавтаст хадгалагданаgit status: одоогийн төлөвийг харахgit add <filename>: файлуудыг staging area-д нэмэхgit commit: шинэ коммит үүсгэх- Сайн коммитын тайлбар бичиж байгаарай!
- Сайн коммит тайлбар бичих бусад шалтгаанууд!
git log: түүхийн жагсаалтыг хавтгайруулан харуулахgit log --all --graph --decorate: түүхийг граф (DAG) хэлбэрээр харуулахgit diff <filename>: staging area-тай харьцуулахад хийсэн өөрчлөлтүүдийг харахgit diff <revision> <filename>: файлын хоёр өөр снапшот хоорондын ялгааг харахgit checkout <revision>: HEAD-ийг өөрчлөх (салааг сонговол одоогийн салааг солино)
Салаалалт ба Нэгтгэлт (Branching and merging)
git branch: салаануудыг (branches) харахgit branch <name>: шинэ салаа үүсгэхgit switch <name>: өөр салаа руу шилжихgit checkout -b <name>: шинэ салаа үүсгээд шууд шилжихgit branch <name>; git switch <name>тушаалтай ижил
git merge <revision>: одоогийн салаа руу заасан салааг нэгтгэх (merge)git mergetool: merge conflicts (нэгтгэлийн зөрчил) шийдвэрлэхэд туслах тусгай хэрэгслийг ажиллуулахgit rebase: коммитуудын дарааллыг шинэ суурь коммит руу шилжүүлэх (rebase хийх)
Алсын серверүүд (Remotes)
git remote: холбогдсон алсын (remote) repositories-ийг харахgit remote add <name> <url>: шинэ алсын repository нэмэхgit push <remote> <local branch>:<remote branch>: объектуудыг алсын сервер рүү илгээж, алсын reference-ийг шинэчлэхgit branch --set-upstream-to=<remote>/<remote branch>: локал болон алсын салааны хамаарлыг тохируулахgit fetch: алсын серверээс объект/reference-үүдийг татаж авахgit pull:git fetch; git mergeхийхтэй адилgit clone: алсын repository-г диск рүүгээ бүрэн хуулж авах
Буцаах (Undo)
git commit --amend: коммитын агуулга эсвэл тайлбар мэдээллийг засахgit reset <file>: файлыг staging area-аас гаргах (unstage)git restore: хийсэн өөрчлөлтийг устгаж хуучин төлөвт нь оруулах
Гүнзгийрүүлсэн Git
git config: Git нь маш өндөр хэмжээнд тохируулагддагgit clone --depth=1: түүхийг бүтнээр нь биш зөвхөн сүүлийн хэсгийг хуулж авах (shallow clone)git add -p: өөрчлөлтийн хэсгүүдийг сонгож интерактив байдлаар staging-д нэмэх (interactive staging)git rebase -i: коммитуудыг интерактив байдлаар нэгтгэх, устгах, өөрчлөх (interactive rebasing)git blame: мөр бүрийг хамгийн сүүлд хэн өөрчилснийг харахgit stash: ажлын хавтас дахь өөрчлөлтүүдийг түр зуур хадгалж цэвэрлэх (stash)git bisect: алдааг олохын тулд түүхэн дунд хоёртын хайлт хийх (binary search)git revert: өмнөх коммитын өөрчлөлтийг эсрэгээр нь хийх шинэ коммит үүсгэхgit worktree: нэгэн зэрэг олон салааг өөр өөр хавтсанд нээж ажиллах.gitignore: Git-ээр хянахгүй үл тоомсорлох файлуудыг заах
Бусад сэдвүүд
- GUI програмууд: Git-д зориулсан олон график хэрэглэгчийн интерфейстэй програмууд байдаг. Бид тэдгээрийг ашигладаггүй бөгөөд командын мөрийг илүүд үздэг.
- Бүрхүүлийн холболт (Shell integration): Өөрийн бүрхүүлийн prompt дээр Git-ийн төлөвийг (одоогийн салаа гэх мэт) харуулах нь маш тохиромжтой байдаг (zsh, bash). Энэ нь ихэвчлэн Oh My Zsh зэрэг фрэймворкуудад багтсан байдаг.
- Засварлагчийн холболт: Үүнтэй адил олон код засварлагчид Git-ийн холболттой ирдэг. Vim-д зориулсан стандарт хэрэгсэл бол fugitive.vim юм.
- Ажлын урсгалууд (Workflows): Бид танд өгөгдлийн загвар болон үндсэн командуудыг заасан боловч том төслүүд дээр ажиллах явцад ямар дүрмүүдийг баримтлах талаар яриагүй (олон өөр аргууд байдаг).
- GitHub: Git бол GitHub биш. GitHub нь бусдын төсөлд хувь нэмэр оруулах татах хүсэлт (pull requests) гэх мэт өөрийн гэсэн аргуудыг санал болгодог.
- Бусад Git үйлчилгээнүүд: GitHub нь цорын ганц биш юм: GitLab болон BitBucket зэрэг олон repository hosting үйлчилгээнүүд байдаг.
Эх сурвалжууд
- Pro Git номыг уншихыг маш их зөвлөж байна. 1–5-р бүлгийг уншиход та Git-ийг өндөр түвшинд ашиглах бараг бүх мэдлэгийг олж авах болно. Дараагийн бүлгүүдэд илүү нарийн, гүнзгий сэдвүүд байгаа.
- Oh Shit, Git!?! бол Git дээр гаргадаг түгээмэл алдаануудыг хэрхэн засах тухай богино заавар юм.
- Git for Computer Scientists нь Git-ийн өгөгдлийн загварыг цөөн псевдо код, олон тооны зургаар тайлбарласан богино тайлбар юм.
- Git from the Bottom Up нь зөвхөн өгөгдлийн загвараас гадна Git-ийн хэрэгжүүлэлтийн нарийн ширийн зүйлийг сонирхсон хүмүүст зориулсан дэлгэрэнгүй тайлбар юм.
- How to explain git in simple words
- Learn Git Branching бол вэб хөтөч дээр Git сурах боломжтой тоглоом юм.
Дасгал ажил
- Хэрэв та Git-ийн талаар туршлагагүй бол Pro Git номын эхний хэдэн бүлгийг унших эсвэл Learn Git Branching тоглоомыг тоглож үзээрэй. Ажиллах явцдаа Git-ийн командуудыг өгөгдлийн загвартай хэрхэн холбогдож байгааг бодож үзээрэй.
- Энэхүү хичээлийн вэбсайтын репозитор-ыг
локал руугаа clone хийнэ үү.
- Түүхийг граф хэлбэрээр харж судлаарай.
README.mdфайлыг хамгийн сүүлд хэн өөрчилсөн бэ? (Сэжүүр:git logкомандыг аргументтай ашиглана)._config.ymlфайлынcollections:мөрний хамгийн сүүлийн өөрчлөлтийн коммитын тайлбар мэдээлэл юу байсан бэ? (Сэжүүр:git blameболонgit showашиглана).
- Git-ийг сурч байх явцад гаргадаг нийтлэг алдаа бол Git-ээр удирдах шаардлагагүй том файлуудыг эсвэл нууц мэдээллийг коммит болгож нэмэх явдал юм. Репозиторт файл нэмээд, хэдэн коммит хийсний дараа тэр файлыг түүхээс (зөвхөн сүүлийн коммитоос биш) бүрэн устгаж туршина уу. Та үүнийг үзэж болно.
- GitHub-аас аль нэг репозиторыг хуулж аваад, түүний бэлэн байгаа файлыг
өөрчилнө үү. Таныг
git stashажиллуулахад юу болох вэ?git log --all --onelineажиллуулахад юу харагдаж байна вэ?git stash popажиллуулан stashed хийсэн өөрчлөлтөө буцаан авна уу. Энэ нь ямар нөхцөлд хэрэгтэй байж болох вэ? - Бусад командын мөрийн хэрэгслүүдтэй адил Git нь
~/.gitconfigнэртэй тохиргооны файлтай байдаг.~/.gitconfigдотор алиас үүсгэснээр таныгgit graphажиллуулахадgit log --all --graph --decorate --onelineкомандын гаралт гардаг болгоорой. Үүний тулд~/.gitconfigфайлыг шууд засварлаж эсвэлgit configтушаалыг ашиглаж болно. Git алиасны талаарх мэдээллийг эндээс үзнэ үү. - Та
git config --global core.excludesfile ~/.gitignore_globalажиллуулсны дараа~/.gitignore_globalфайлд глобал үл тоомсорлох загваруудыг тодорхойлж болно. Энэ нь глобал үл тоомсорлох файлын байршлыг зааж өгдөг боловч та тухайн зам дээр файлыг гараар үүсгэх хэрэгтэй. Өөрийн глобал gitignore файлд үйлдлийн систем эсвэл код засварлагчийн түр зуурын файлуудыг (жишээ нь,.DS_Store) үл тоомсорлохоор тохируулна уу. - Энэхүү хичээлийн вэбсайтын репозитор-ыг fork хийж аваад, үсгийн алдаа эсвэл бусад сайжруулах зүйлийг олж засаад GitHub дээр татах хүсэлт илгээнэ үү (та үүнийг үзэж болно). Зөвхөн хэрэгтэй сайжруулалтыг (спам хийхгүй байхыг хүсье!) илгээгээрэй. Хэрэв засах зүйл олдохгүй бол энэ дасгалыг алгасаж болно.
- Хамтын ажиллагааны нөхцөлийг дуурайлган нэгтгэлийн зөрчлийг (merge conflicts)
шийдвэрлэх дасгал хийгээрэй:
git initажиллуулж шинэ репозитор үүсгээд, дотор нь хэдэн мөр бүхийrecipe.txtнэртэй файл үүсгэнэ үү.- Үүнийг коммит болгоод, хоёр салаа үүсгэнэ үү:
git branch saltyболонgit branch sweet. saltyсалаанд нэг мөрийг өөрчлөөд (жишээ нь, “1 cup sugar”-ыг “1 cup salt” болгож) коммит хийнэ үү.sweetсалаанд мөн ижил мөрийг өөрөөр өөрчлөөд (жишээ нь, “1 cup sugar”-ыг “2 cups sugar” болгож) коммит хийнэ үү.- Одоо
masterсалаа руу шилжиж, эхлээдgit merge saltyхийж, дараа ньgit merge sweetхийхийг оролдоно уу. Юу болох вэ?recipe.txtфайлын агуулгыг шалгана уу - энд байгаа<<<<<<<,=======, болон>>>>>>>тэмдэглэгээнүүд ямар утгатай вэ? - Файлыг засварлан хүссэн агуулгаа үлдээж, зөрчлийн тэмдэглэгээнүүдийг
устгаад,
git addболонgit commit(эсвэлgit merge --continue) ажиллуулан зөрчлийг шийдвэрлэнэ үү. Эсвэлgit mergetoolажиллуулж терминал эсвэл график интерфейс бүхий хэрэгслээр зөрчлийг шийдвэрлэхийг оролдоно уу. - Шинээр үүсгэсэн нэгтгэлийн түүхийг харахын тулд
git log --graph --onelineажиллуулна уу.
Лиценз: CC BY-NC-SA.