Даведнік па Git

Карысныя спасылкі

Усталёўшчык Git і інструкцыі ўсталяваньня можна атрымаць тут: http://git-scm.com/download

Афіцыйны навучальны дапаможнік (пачаткоўцам): http://www.kernel.org/pub/software/scm/git/docs/gittutorial.html

Афіцыйны даведнік (адмыслоўцам): http://www.kernel.org/pub/software/scm/git/docs/user-manual.html

Даведнік па камандах: http://git-scm.com/docs

Шпаргалка па асноўных камандах (у PDF): https://na1.salesforce.com/help/doc/en/salesforce_git_developer_cheatsheet.pdf

Інтэрактыўная шпаргалка на OverAPI: http://overapi.com/git/

Вольная электронная кніга «Pro Git»: http://git-scm.com/book/ru

Шэраг навучальных дапаможнікаў ад Atlassian: https://www.atlassian.com/git/

Інтэрактыўныя курсы ад CodeSchool: Try Git, Git Real, Git Real 2

Уводзіны

Пра кантроль вэрсіяў

Сыстэма кантролю вэрсіяў (СКВ) – гэта сыстэма, якая рэгіструе зьмены ў адным ці некалькіх файлах з тым, каб у далейшым можна было вярнуцца да былых вэрсіяў (калі пэўныя зьмены прывялі праект у непрацоўны выгляд і выправіць іх прынамсі хутка не ўяўляецца магчымым; ці калі стала зразумелым, што пэўныя зьмены былі непатрэбныя) альбо проста праглядзець гісторыю зьменаў (напрыклад, высьветліць хто і чаму ўнёс пэўную зьмену ў праграму). Дадзены даведнік будзе разглядаць ужываньне СКВ для коду праграмы, але ў самым агульным выпадку СКВ можна ўжываць для захаваньня зьменаў файлаў любых тыпаў – дакумэнтаў, выяваў і інш.

Усе існыя СКВ дзеляцца на наступныя тыпы:

Лякальныя сыстэмы

Калі зьмены робяцца на адным кампутары і, адпаведна, няма неабходнасьці сынхранізаваць зьмены паміж некалькімі ўдзельнікамі, тады вэрсіі можна захоўваць праз простае капіяваньне тэчак на лякальным кампутары. Звычайна да асноўнага імені тэчкі дадаецца дата і час кожнай зьмены, каб падзяляць іх. Але такі падыход хаця і вырашае асноўную задачу (дазваляе захоўваць гісторыю зьменаў), але робіць гэта не эфэктыўна і не прадухіляе карыстальніка ад элемэнтарных памылак (памылкова ўнесьці зьмены ў файл, які знаходзіцца ня ў той тэчцы; не туды скапіяваць тэчку і перазапісаць пэўную вэрсію, назаўжды згубіўшы яе).

Таму нават у выпадку лякальнага захаваньня зьменаў варта карыстацца адпаведнымі сродкамі. Напрыклад, стандартная пастаўка Mac OS X утрымлівае прыладу rcs, якая апэрыруе патчамі паміж вэрсіямі файла (патч – гэта розьніца паміж вэрсіямі). Патчы захоўваюцца ў адмысловым фармаце на дыску і дазваляюць аднавіць любую вэрсію файлу зь яго гісторыі зьменаў, пасьлядоўна накладаючы патчы.

Схема лякальнай СКВ
Схема лякальнай СКВ

Цэнтралізаваныя сыстэмы

Але ж часьцей за ўсё існуе неабходнасьць сынхранізаваць зьмены паміж некалькімі ўдзельнікамі і захаваньне зьменаў на лякальным кампутары зусім не падыходзіць для гэтых мэтаў. Таму наступным крокам на шляху разьвіцьця СКВ стала стварэньне цэнтралізаваных сыстэмаў, пры якіх гісторыя зьменаў захоўваецца на цэнтральным сэрвэры. Адміністратары такіх сыстэмаў маюць магчымасьць наладзіць хто да якой часткі праекту мае доступ. Кіраўнікі праектаў маюць разуменьне хто чым займаецца на праекце.

Схема цэнтралізаванай СКВ
Схема цэнтралізаванай СКВ

Аднак, пры такім падыходзе ёсьць сур'ёзны недахоп (які прысутнічае і ў лякальных сыстэмах) – гісторыя зьменаў захоўваецца ў адным месцы. Калі ўдзельнік праекту губляе сувязь з гэтым цэнтральным сэрвэрам ці, яшчэ горш, сэрвэр выключаецца (напрыклад на тэхнічнае абслугоўваньне), тады, па-першае ўдзельнік на гэты пэрыяд часу губляе доступ на гісторыі зьменаў, а па-другое, ня можа ўнесьці (захаваць) ў гісторыю свае зьмены. І зусім кепска, калі дыску гэтага сэрвэру, на якім захоўвалася гісторыя зьменаў, здарыцца зламацца. Тады ўся гісторыя зьменаў будзе незваротна згублена, апроч хіба што некалькіх вэрсіяў, якія былі ў якасьці працоўных выцягнутыя ўдзельнікамі на свае лякальныя кампутары.

Разьмеркаваныя сыстэмы

У гэтай сытуацыі ў гульню ўступаюць разьмеркаваныя СКВ. У такіх сыстэмах як Git, Mercurial, Bazaar альбо Darcs кліенты ня проста выцягваюць апошнія вэрсіі файлаў, але цалкам капіююць сабе ўвесь рэпазыторый. Таму ў выпадку, калі «памірае» сэрвэр, празь які ішла праца, любы кліенцкі рэпазыторый можа быць скапіяваны назад на сэрвэр, каб аднавіць базу даных.

Схема разьмеркаванай СКВ
Схема разьмеркаванай СКВ

Наладкі

Наладкі зьмяняюцца пры выкананьні каманды git config і захоўваюцца ў наступных файлах:

  • <ТЭЧКА_РЭПАЗЫТОРЫЮ>/<ТЭЧКА_GIT>/config (звычайна .git/config у корне рэпазыторыю) — наладкі, спэцыфічныя для гэтага рэпазыторыю;
  • <ХАТНЯЯ_ТЭЧКА_КАРЫСТАЛЬНІКА>/.gitconfig (зьмяняюцца пры выкарыстаньні опцыі --global) — наладкі, спэцыфічныя для карыстальніка;
  • /etc/gitconfig (зьмяняюцца пры выкарыстаньні опцыі --system) — наладкі, характэрныя для ўсёй сыстэмы;

Асабістыя даныя карыстальніка

Перш за ўсё пазначце свае ідэнтыфікацыйныя даныя:

Прылада параўнаньня (merge tool)

Акрамя гэтага можна пазначыць сваю ўлюбёную прыладу параўнаньня файлаў:

Яшчэ наладкі

Пры каміце зьмяняе ўсе CR/LF (Windows-стыль для пераводу радка), якія патрапіліся ў кодзе, на адзіночны LF (Linux-стыль для пераводу радка):

Пры чэкаўце зьмяняе ўсе LF на CR/LF, а пры каміце робіць наадварот:

Наладжвае Git такім чынам, каб ён фарбаваў лог:

Прагляд наладкаў

Праглядзець усе цяперашнія наладкі можна камандай:

Пры гэтым вынік папярэдняй каманды будзе выглядаць неяк так:

А цяперашняе значэньне пэўнага атрыбуту наступным чынам (напрыклад, імя карыстальніка):

Стварэньне рэпазыторыяў

Існуюць дзьве галоўныя магчымасьці, каб стварыць рэпазыторый. Першая — стварыць новы рэпазыторый ў лякальнай тэчцы (ў пустой, ці з ужо існуючым праектам). Другая — кланаваць існуючы «аддалены» рэпазыторый.

Стварэньне лякальнага рэпазыторыю

Для таго, каб стварыць новы лякальны рэпазыторый, трэба ў тэчцы праекту (ці ў пустой тэчцы, у якой плянуецца стварыць праект) запусьціць каманду:

У выніку будзе створана схаваная тэчка рэпазыторыю .git

Кланаваньне аддаленага рэпазыторыю

Аддалены ў дадзеным выпадку дастаткова адноснае разуменьне, таму што такім рэпазыторыем можа быць і існуючы ў лякальнай файлавай сыстэме (хаця гэта і ня вельмі верагодны выпадак). Але галоўнае для гэтага мэтаду — што «эталонны» рэпазыторый ужо павінен недзе існаваць:

Напрыклад, у выпадку каманды:

у цяперашняй тэчцы будзе створана тэчка mygrit, у якую будзе кланаваны рэпазыторый, які знаходзіцца па адрасе github.com/schacon/grit.git з выкарыстаньнем пратаколу git://. Магчымы таксама пратакол http(s):// ці ўвогуле без пратаколу ў выпадку лякальнага зьмяшчэньня «аддаленага» рэпазыторыю. Калі імя ствараемага рэпазыторыю (апошні парамэтар) не пазначана, будзе ўжытае імя аддаленага рэпазыторыю.

Акрамя сьцягваньня аддаленага рэпазыторыю ў лякальнае месцазнаходжаньне гэтая каманда створыць спасылку на аддалены рэпазыторый пад імем «origin», а таксама пераключыцца на першапачатковую галіну аддаленага рэпазыторыю (верагодней за ўсё «master»).

Жыцьцёвы цыкл стану файлаў

Такім чынам, вы стварылі новы рэпазыторый і гатовыя ўносіць зьмены, каб стварыць яшчэ адзін карысны праект. У гэты момант важна разабрацца са станамі, у якіх могуць знаходзіцца файлы вашага праекту, з пункту гледжаньня Git. Два асноўных стана — гэта адсочваемы і неадсочваемы. Назвы гавораць самі за сябе, за зьменамі ў адсочваемых файлах Git сочыць, а за зьменамі ў неадсочваемых, адпаведна, не. Адразу варта адзначыць, што ў выпадку, калі рэпазыторый ствараецца як клон аддаленага (ужо існуючага) рэпазыторыю, усе файлы ў тэчцы створанага рэпазыторыю аўтаматычна пераходзяць у стан сачэньня. Калі ж вы ствараеце абсалютна новы рэпазыторый (каманда git init), усе раней існуючыя файлы ў тэчцы рэпазыторыю застаюцца ў неадсочваемым стане і якія б зьмены вы ў іх ня ўнесьлі, Git аб іх ня будзе ведаць датуль, пакуль вы не перавядзеце іх яўна ў адсочваемы стан.

Адсочваемы стан у сваю чаргу падзяляецца на нязьменены (першапачатковы альбо зафіксаваны стан), зьменены (у файл унесьлі зьмены, але пакуль яшчэ ня далі ніякіх інструкцыяў, што з гэтымі зьменамі рабіць), праіндэксаваны (карыстальнік праінструктаваў Git, што зьбіраецца зафіксаваць зьмены ў файле). Калі зьмены ў праіндэксаваным файле фіксуюцца, файл пераходзіць ізноў у нязьменены стан. Акрамя гэтага зьмены ў зьмененым альбо праіндэксаваным файле могуць быць адмененыя, тады файл таксама пераходзіць у нязьменены стан.

Усё вышэйсказанае пра станы файлаў адлюстравана ў наступнай схеме:

Жыцьцёвы цыкл стану файлаў
Жыцьцёвы цыкл стану файлаў

Праверка статусу

Атрымаць справаздачу аб тым, у якім статусе знаходзяцца файлы праекту, можна камандай git status. Калі вы выканаеце гэтую каманду адразу пасьля стварэньня новага рэпазыторыю ў пустой тэчцы, вы пабачыце прыкладна наступнае:

У вывадзе пазначана ў якой галіне мы знаходзімся (па змоўчваньні гэта заўсёды «master»), а таксама што Git не знайшоў ніякіх зьменаў, якія можна было б праіндэксаваць альбо зафіксаваць (nothing to commit).

Цяпер створым новы файл README.txt у корані праекту і запусьцім тую ж самую каманду:

Гэтым разам Git заўважыў, што зьявіўся новы файл, за якім не было каманды сачыць (Untracked files), і вывеў назву гэтага файлу.

Далучэньне новых файлаў да рэпазыторыю

Прыйшоў час далучыць файл да рэпазыторыю, іншымі словамі перавесьці яго з неадсочваемага стану ў адсочваемы. Для гэтага выкарыстоўваецца каманда git add. Забяжым наперад і адзначым, што гэтая каманда ў Git шматфункцыянальная і выкарыстоўваецца ў тым ліку для таго, каб праіндэксаваць зьмены ў файле. Гэта можа бянтэжыць, таму паспрабуйце адразу гэта прыняць як факт, хоць і дзіўны. Такім чынам:

Цяпер, калі вывесьці справаздачу аб статусе праекту, атрымаем наступнае:

Пры гэтым такі файл апынаецца ў праіндэксаваным стане і наступным крокам яго цяперашні зьмест можа быць зафіксаваны ў рэпазыторыі. Каманда git add можа прымаць і сьпіс файлаў, і маскі файлаў:

Індэксацыя зьмененых файлаў

Хаця апэрацыі далучэньня новых і індэксацыі зьмененых файлаў па сутнасьці сваёй адрозьніваюцца адна ад другой, у Git для іх ажыцьцяўленьня ўжываецца адна і тая ж каманда git add. Уявім, што ў нашым рэпазыторыі ўжо ёсьць адсочваемы і нязьменены файл TODO.txt. Унясем у яго пэўныя зьмены і запытаем у Git пра статус рэпазыторыю:

У выніку Git нам кажа (радкі 8 і 12), што файл TODO.txt зьменены (modified), але зьмены яшчэ не праіндэксаваныя (Changes not staged), каб мець магчымасьць іх зафіксаваць. Таму праіндэксуем іх:

Гэтым разам запыт на статус нам выдасьць наступны вынік:

Які кажа нам пра тое, што ў рэпазыторыі існуюць адзін новы і адзін зьменены файлы, якія былі праіндэксаваныя і гатовыя да фіксацыі.

Але цяпер уявім, што вы забыліся ўнесьці пэўныя зьмены ў файл TODO.txt і не жадаеце фіксаваць яго бяз гэтых зьменаў. Унясем зьмены і ізноў запытаемся пра статус рэпазыторыю:

Што-што? Ці не падводзіць нас зрок? Файл TODO.txt пазначаны двойчы і як праіндэксаваны, чые зьмены могуць быць зафіксаванымі, і як зьменены, але не праіндэксаваны. На самай справе ніякай памылкі тут няма. Калі мы цяпер зробім фіксацыю гэтага файлу, у рэпазыторый трапіць не цяперашні яго стан, але праіндэксаваны на папярэднім кроку. Акрамя гэтых праіндэксаваных зьменаў, існуюць яшчэ і не праіндэксаваныя, пра гэта нам Git і кажа. Каб гэтыя апошнія, непраіндэксаваныя зьмены таксама трапілі ў рэпазыторый, трэба ізноў выканаць каманду індэксацыі git add TODO.txt.

Прагляд зьменаў

Часам абагульняючай справаздачы пра статус праекту, якая выводзіцца камандай git status, недастаткова і нам патрэбна зразумець што менавіта зьмянілася ў зьмененых файлах. На дапамогу прыходзіць каманда git diff. Каб пабачыць, якія зьмены мы зрабілі але яшчэ не праіндэксавалі, трэба выканаць каманду git diff без аргумэнтаў:

У восьмым радку нам гавораць, што ў файл TODO.txt дадаўся радок «2. Зрабіць нешта яшчэ» (прэфікс «+» кажа пра тое, што дадалося, а прэфікс «-» — што зьнікла).

Каб пабачыць, чым праіндэксаваныя зьмены адрозьніваюцца ад апошняга зафіксаванага стану, трэба дадаць парамэтар --cached (пачынаючы з вэрсіі 1.6.1 у Git існуе раўназначны парамэтар --staged):

У трэцім радку нам гавораць, што быў праіндэксаваны новы файл README.txt, а ў дзесятым радку кажуць пра тое, што ў файл TODO.txt дадалі радок «1. Зрабіць пэўную рэч», і таксама праіндэксавалі гэтую зьмену.

Фіксацыя зьменаў

Такім чынам, мы дакладна ведаем што ў якіх файлах было зьменена, і застаўся апошні крок у жыцьцёвым цыкле стану файлаў Git-рэпазыторыю — канчаткова зафіксаваць гэтыя зьмены. Для фіксацыі зьменаў існуе каманда git commit. Калі выканаць гэтую каманду без парамэтраў, Git адчыніць тэкставы рэдактар (які пазначаны ў парамэтры наладак core.editor) з прапановай увесьці камэнтар для каміту (фіксацыі):

Уводзім нейкі камэнтар і зачыняем акно рэдактару, захоўваючы зьмены. Git выдасьць наступны вынік:

Тое ж самае можна зрабіць такім чынам, каб Git не адчыняў акно рэдактару, праз дадатковы парамэтар:

Яшчэ варыяцыі каманды фіксацыі, якія могуць стацца карыснымі...

Адначасова праіндэксаваць і зафіксаваць усе зьмены ўва ўсіх адсочваемых файлах у адной камандзе можна наступным чынам (але дадзеная каманда не дадае новыя файлы да рэпазыторыю):

Калі мы забылі нешта зрабіць у межах ужо зробленай апошняй фіксацыі, дадатковыя зьмены (ужо праіндэксаваныя) ў гэтую фіксацыю можна дадаць такім чынам:

То бок у дадзеным выпадку будзе зроблена не новая фіксацыя, але дапоўнена апошняя. Калі пазначыць камэнтар у гэтай камандзе, тады камэнтар апошняй фіксацыі будзе ім перакрыты.

Адмена зьменаў

Да гэтага часу мы з вамі разглядзелі поўны цыкл станаў, якія могуць прымаць файлы з пункту гледжаньня Git, але гэта толькі адна з магчымых, аптымістычная пасьлядоўнасьць, калі ўсё ідзе гладка. Але існуе яшчэ адна, пэсымістычная пасьлядоўнасьць, калі зьмены трэба не праіндэксаваць, альбо зафіксаваць, але адмяніць.

Адмена працоўных зьменаў

Спачатку самы просты выпадак — у нас быў файл у зафіксаваным стане і мы ўнесьлі ў яго зьмены, якія яшчэ не праіндэксавалі:

Стан рэпазыторыю пасьля зьменаў у файле

Адмяніць гэтыя зьмены і, адпаведна, перавесьці файл у папярэдні зафіксаваны стан можна наступным чынам:

У выніку атрымаецца:

Стан рэпазыторыю пасьля адмены зьменаў у файле

Адмена праіндэксаваных зьменаў

Цяпер уявім, што мы не адмянілі працоўныя зьмены ў папярэднім кроку, але ўжо пасьпелі праіндэксаваць іх:

Стан рэпазыторыю пасьля індэксацыі зьменаў у файле

Адмяніць гэтую індэксацыю можна наступным чынам:

Пры гэтым зьмены ў файле застануцца, але застануцца толькі ў працоўнай вэрсіі, індэкс больш не будзе іх утрымліваць:

Стан рэпазыторыю пасьля адмены індэксацыі

Таксама варта дадаць, што парамэтар --mixed, а таксама імя апошняй фіксацыі HEAD зьяўляюцца змоўчнымі і тую ж самую каманду можна было б выканаць наступным чынам:

Адмена праіндэксаваных і працоўных зьменаў

Ізноў вернемся да стану, калі ў нас ёсьць праіндэксаваныя зьмены:

Стан рэпазыторыю пасьля індэксацыі зьменаў у файле

Адначасова адмяніць і працоўныя, і праіндэксаваныя зьмены можна камандай:

У выніку атрымаецца:

Стан рэпазыторыю пасьля адмены зьменаў у файле

Зьмяшчэньне ў індэкс стану пэўнай фіксацыі

Дый увогуле каманда git reset мае больш агульны сэнс і можна яе ўяўляць як перамяшчэньне індэксу, напрыклад каманда:

Прывядзе да таго, што індэкс будзе ўтрымліваць стан папярэдняй (тыльда ў канцы HEAD) фіксацыі:

Перамяшчэньне індэксу да стану папярэдняй фіксацыі

І, як пабочны эфэкт гэтага, выкананьне каміту ў наступны момант прывядзе да таго, што папярэдняя фіксацыя будзе яшчэ раз зафіксавана і перакрые цяперашнюю (стан камітаў [fe287f0...] і [bfb2e2b...] будзе поўнасьцю ідэнтычным):

Каміт пасьля перамяшчэньня індэксу да стану папярэдняй фіксацыі

Зьмяшчэньне ў індэкс і ў працоўную галіну стану пэўнай фіксацыі

Амаль тое ж самае, што апісвалася ў папярэднім разьдзеле, можна выканаць іншай камандай:

Адрозьненьнем будзе тое, што ня толькі індэкс, але і працоўная галіна будзе ўтрымліваць стан пазначанай фіксацыі (папярэдняй ў дадзеным прыкладзе — HEAD~). І яшчэ адным немалаважным адрозьненьнем будзе тое, што гэтую каманду немагчыма ўжыць без пазначэньня імён файлаў, для якіх мы жадаем яе выканаць, дакладней магчыма, але сэнс яе будзе зусім іншы.

Калі ў якасьці парамэтру пазначыць апошнюю фіксацыю:

тады вынік каманды будзе дакладна такім жа, як і вынік каманды (глядзі разьдзел):

То бок зьмены ў індэксе і ў працоўнай галіне будуць згубленыя, у выніку індэкс і працоўная галіна будуць зьмяшчаць стан апошняй фіксацыі.

Адмена лякальных фіксацыяў

Дагэтуль мы разглядалі магчымасьці адмены пэўных зьменаў, не зьмяняючы папярэдняй гісторыі камітаў. Але Git дазваляе адмяняць каміты, якія былі зробленыя раней і ўжо зафіксаваныя ў гісторыі. Прычым ёсьць 2 шляхі, як гэта можна рабіць. Адзін, для лякальных фіксацыяў — тых, што маюцца пакуль што толькі ў лякальнай гісторыі, мы разгледзім у дадзеным разьдзеле. Іншы, для фіксацыяў, якія ўжо былі зьмешчаныя ў аддалены, альбо публічны рэпазыторый — у наступным разьдзеле.

Улічваючы, што адмена лякальных фіксацыяў фізычна выдаляе іх з гісторыі камітаў, яе ня варта ўжываць для «цэнтральнага» рэпазыторыю, таму што гэта можа значна ўскладніць сумесную працу ў камандзе, калі нехта ўжо сьцягнуў сабе такую фіксацыю і разьлічвае, што яна там ёсьць і будзе заставацца далей. Памятаем, што тэхнічна ў Git няма цэнтральнага рэпазыторыю, пад такім разумеецца той рэпазыторый, які каманда распрацоўкі дамовілася лічыць цэнтральным, і які для кожнага з каманды зьяўляецца аддаленым.

«Адмяні мяне далікатна»

Адмена лякальных фіксацыяў ў сваю чаргу таксама дзеліцца на 2 варыянты. Спачатку разгледзім «далікатны». Уявім сябе наступны стан рэпазыторыю і яго гісторыю:

Стан рэпазыторыю перад адменай

Калі выканаць наступную каманду:

Апошняя фіксацыя будзе фізычна выдаленая з гісторыі камітаў, а яе стан застанецца ў індэксе і ў працоўнай галіне:

Далікатная адмена апошняй фіксацыі

У якасьці парамэтру можна пазначыць ня толькі перадапошні, але і любы іншы каміт з гісторыі камітаў. Тады індэкс і працоўная галіна будзе ўтрымліваць зьмены ня толькі апошняга, але сукупна ўсіх адмененых камітаў. Такім чынам, асноўнае прызначэньне гэтай каманды — перарабіць адзін ці некалькі камітаў альбо аб'яднаць некалькі апошніх камітаў у адзін.

Яшчэ раз зьвяртаю ўвагу, што каманда, якую мы толькі што разглядзелі, фізычна зьмяняе гісторыю камітаў, і хаця яна робіць гэта далікатна, захоўваючы адмененыя зьмены ў індэксе і ў працоўнай вобласьці, ужываць яе трэба ўважліва, асабліва памятаючы пра недапушчальнасьць адмяняць каміты, якія раней ужо былі заліты ў аддалены рэпазыторый.

«Адмяні мяне брутальна»

Але ў Git ёсьць яшчэ і каманда брутальнай адмены фіксацыяў. Ізноў вернемся да зыходнай сытуацыі:

Стан рэпазыторыю перад адменай

Калі замест парамэтра --soft, як у папярэднім прыкладзе, ужыць парамэтар --hard:

Фіксацыі ня толькі будуць адмененыя, але і ўсе зьмены, якія былі імі зробленыя, будуць назаўжды згубленыя:

Брутальная адмена апошняй фіксацыі

Нечага і казаць, што калі ўжо далікатную адмену трэба рабіць уважліва, дык перад тым, як рабіць брутальную, варта не адзін раз усё ўзважыць.

Таксама зьвярніце ўвагу, што ў адрозьненьні ад папярэдняга прыкладу ў якасьці ілюстрацыі мы зрабілі адмену не аднаго, але двух апошніх камітаў: ~2 пасьля HEAD. І ўвогуле, можна карыстацца не адноснымі імёнамі (столькі і столькі камітаў назад ад апошняга), а скарочанымі хэшамі камітаў для пазначэньня таго, да якога каміту зрабіць адкат. У наступным прыкладзе эфэкт быў бы дакладна такім жа, як і ў папярэднім:

Адмена аддаленых фіксацыяў

У папярэднім разьдзеле мы зьвярталі асаблівую ўвагу на недапушчальнасьць выдаляць фіксацыі, які былі ўжо зьмешчаныя ў аддалены рэпазыторый. Але ўсё ж існуе «правільны» спосаб адмяніць такія фіксацыі, калі раптам зьявілася патрэба. Уявім наступны стан рэпазыторыю, прычым гэта стан аддаленага ці публічнага рэпазыторыю, зафіксаваную гісторыю якога мы «не маем права» зьмяняць:

Стан рэпазыторыю перад адменай

І, напрыклад, мы заўважылі, што фіксацыя fe287f0... увяла ў код сур'ёзную праблему і варта яе выдаліць, ці ў дадзеным выпадку лепш сказаць выключыць. Тады можна выканаць наступную каманду:

У гэтым выпадку Git сам прааналізуе, якія зьмены былі зроблены фіксацыяй fe287f0..., зьменіць код такім чынам, каб гэтыя зьмены выключыць, і зробіць новы каміт, які зафіксуе выключэньне памылковых зьменаў:

Стан рэпазыторыю перад адменай

Зьвярніце ўвагу, што як каміт fe287f0..., які мы плянавалі «адмяніць», гэтак і наступны пасьля яго каміт fdb2291... засталіся ў гісторыі камітаў. Стан жа рэпазыторыю пасьля гэтага адкату будзе дакладна такім жа, як калі б каміту fe287f0... увогуле не было. Варта дадаць, што Git здолее зрабіць адкат аўтаматычна толькі ў выпадку, калі ён відавочны. Калі ж існуюць канфлікты (нейкія файлы зьмяняліся як у каміце fe287f0..., гэтак і ў пазьнейшых камітах), Git праінфармуе пра іх і прапануе выправіць.

Ізаляваны стан

Існуе яшчэ адзін стан, у якім можа знаходзіцца рэпазыторый (менавіта ўвесь рэпазыторый, а не асобны(-я) файл(-ы)) — гэта так званы ізаляваны стан (detached HEAD state), у які рэпазыторый можна перавесьці пры дапамозе наступнай каманды:

У гэтым выпадку рэпазыторый прыме стан фіксацыі, хэш якой быў пазначаны ў камандзе, але гэта ізаляваны (ад гісторыі камітаў) стан. Усе зьмены, якія будуць цяпер уносіцца ў рэпазыторый, застануцца ў небыцьці, іх немагчыма будзе зафіксаваць. Ізаляваны стан ужываецца, напрыклад, для таго, каб мець магчымасьць пратэставаць як праект вёў сябе ў пэўны момант сваёй гісторыі, але каб пры гэтым не нашкодзіць працоўнай галіне.

Вярнуць рэпазыторый ізноў у працоўны стан (да апошняй працоўнай фіксацыі) можна наступнай камандай:

Выдаленьне файлаў

Калі па нейкай прычыне праект больш ня мае патрэбы ў нейкім файле, выдаліць яго з праекту можна наступным чынам:

Гэтая каманда выдаляе файл лякальна і перастае сачыць за ім, застанецца толькі закаміціць гэтую зьмену.

Ігнараваньне файлаў

Пры распрацоўцы праектаў акрамя файлаў, якія трэба захоўваць у рэпазыторыі, існуе шэраг файлаў, якія наадварот ня варта там захоўваць. Да такіх файлаў могуць адносіцца логі выкананьня праграмы, часовыя файлы, файлы наладак праекту (калі ўдзельнікі праекту вольныя выкарыстоўваць розныя сродкі распрацоўкі) і г.д. Зразумела, можна не дадаваць такія файлы да рэпазыторыю, але яны заўсёды будуць выводзіцца Git'ам ў справаздачы аб статусе, і чым большы праект, тым больш нязручна альбо нават немагчыма будзе весьці далейшую распрацоўку. Git мае сродак, каб цалкам ігнараваць пэўныя файлы, быццам іх не існуе. Гэта файл .gitignore у корані праекту, які ўтрымлівае маскі файлаў для ігнараваньня. Вось прыклад зьмесьціва гэтага файлу:

Часам бывае такое, што мы спачатку дадалі пэўны файл да рэпазыторыю, але пазьней вырашылі, што ня варта захоўваць яго ў рэпазыторыі, хаця лякальна ён павінен застацца. Тады можна выканаць наступную каманду:

якая выдаліць файл development.log з рэпазыторыю, прычым Git ня толькі перастане сачыць за ім, але і фізычна выдаліць ўсю інфармацыю з рэпазыторыю, якая тычыцца гэтага файлу. Пасьля гэтага застанецца толькі дадаць адпаведнае правіла у .gitignore.

Аддаленыя рэпазыторыі

Аддаленыя рэпазыторыі, гэта нішто іншае як лякальныя імя і спасылка да фізычна аддаленага рэпазыторыю. Напрыклад, калі мы клануем аддалены рэпазыторый, Git аўтаматычна стварае лякальную спасылку origin да рэпазыторыю, URL якога быў пазначаны пры кланаваньні.

Прагляд

Каб праглядзець сьпіс існуючых лякальна спасылак на аддаленыя рэпазыторыі, трэба выканаць каманду:

Якая выдасьць, што у дадзены момант існуе адзіная спасылка — origin.

Да гэтай каманды можна дадаць парамэтар -v:

Тады акрамя імені Git выдасьць яшчэ і адпаведную спасылку.

Стварэньне

Стварыць новую спасылку на аддалены рэпазыторый можна наступным чынам:

Напрыклад:

створыць спасылку zagorski на рэпазыторый, які месьціцца па спасылцы https://github.com/zagorski/git-test.git.

Перайменаваньне

Перайменаваць аддалены рэпазыторый можна наступным чынам:

Выдаленьне

Выдаліць лякальную спасылку на аддалены рэпазыторый можна наступным чынам:

Атрыманьне чужых зьменаў

Атрымаць ўсе зафіксаваныя зьмены (пачынаючы з папярэдняга pull) з аддаленага рэпазыторыю «origin» у лякальную галіну «master» можна наступнай камандай:

На самай справе гэта не атамарная апэрацыя, яна складаецца зь некалькіх іншых апэрацыяў. Па-першае, пры дапамозе каманды git fetch зьмены з аддаленага рэпазыторыю сьцягваюцца на лякальную машыну (у галіну «origin/master»), а затым адбываецца спроба аўтаматычнага зьліцьця гэтай лякальнай копіі аддаленага рэпазыторыю са зьменамі лякальнай актыўнай галіны пры дапамозе каманды git merge origin/master.

Публікацыя ўласных зьменаў

Наадварот перамясьціць ўсе зафіксаваныя зьмены (пачынаючы з папярэдняга push) зь лякальнай галіны «master» у аддалены рэпазыторый «origin» можна пры дапамозе каманды:

Галінаваньне

Галіна ў Git уяўляе зь сябе асобную лінію распрацоўцы. Новы функцыянал альбо выпраўленьне памылкі, незалежна ад таго, наколькі дробнымі ці буйнымі будуць адпаведныя зьмены, варта рабіць у асобных галінах. І толькі калі праца над імі цалкам скончана, зьліваць гэтыя часовыя галіны ў асноўную. У такім разе вы гарантуеце, што сырыя, нестабільныя зьмены не трапяць у асноўную галіну.

Прыклад галінаваньня
У вышэйпрыведзеным малюнку паказаны рэпазыторый з дзьвюма (акрамя асноўнай) ізаляванымі галінамі распрацоўцы — адна для выпраўленьня нязначнай памылкі («small_bug»), іншая для рэалізацыі новага функцыяналу («big_feature»).

Прагляд

Наступная каманда выводзіць сьпіс галінаў цяперашняга лякальнага рэпазыторыю і пазначае якая зь іх на дадзены момант актыўная (сымбаль зорачкі перад імем галіны):

Стварэньне

Стварыць новую галіну (пад імем «cat»), адгалінаванай ад актыўнай галіны, можна пры дапамозе наступнай каманды:

Пры гэтым рэпазыторый не будзе пераключаны на гэтую толькі што створаную галіну, але застанецца ў цяперашняй актыўнай.

Пераключэньне

Пераключыцца з актыўнай галіны ў галіну пад імем «cat» (якая пасьля выкананьня гэтай апэрацыі стане актыўнай) можна наступнай камандай:

Наступная каманда выканае адначасова дзьве папярэднія апэрацыі — створыць новую галіну пад імем «dog» і пераключыцца з актыўнай галіны ў толькі што створаную:

Калі цяпер вывесьці сьпіс галінаў, атрымаем наступны вынік:

Выдаленьне

Пасьля зьліцьця пэўнай галіны з «master» яна можа быць выдалена (цалкам зьнішчана з гісторыі):

Калі ў галіне «cat» раптам засталіся незафіксаваныя зьмены, Git не дазволіць выканаць гэтую апэрацыю, але існуе спосаб настаяць на выдаленьні ў такім выпадку, пазначыўшы опцыю -D замест -d:

Аддаленыя галіны

Пры працы з галінамі ў аддаленым рэпазыторыі існуюць пэўныя асаблівасьці. Па-першае, наступным чынам можна вывесьці асноўную інфармацыю пра аддалены рэпазыторый («origin» у дадзеным выпадку), якая будзе ўлучаць у сябе інфармацыю пра яго галіны (разьдзел «Remote branches»), інфармацыю аб тым, за якімі зь іх вы сочыце («tracked»), а таксама інфармацыю аб тым, якія лякальныя галіны зьвязаны зь якімі аддаленымі галінамі (разьдзелы «Local branch...» і «Local refs...»):

Прагляд

Вывесьці сьпіс усіх лякальных спасылак на аддаленыя галіны (усіх аддаленых рэпазыторыяў) можна наступнай камандай:

Стварэньне

Пры неабходнасьці стварыць аддаленую галіну і пачаць сачыць за ёй можна скарыстацца наступнымі камандамі. Спачатку створым новую лякальную галіну:

А пасьля створым аднайменную аддаленую галіну і зьвяжам лякальную зь ёю:

Калі іншы ўдзельнік каманды захоча працаваць са створанай вамі аддаленай галіной, яму дастаткова скарыстацца камандай пераключэньня ў аднайменную лякальную галіну — Git аўтаматычна зьвяжа яе з адпаведнай аддаленай:

Выдаленьне

Выдаліць аддаленую галіну «shopping_cart» з аддаленага рэпазыторыю «origin» можна наступным чынам:

А выдаліць лякальныя спасылкі на ўжо выдаленыя аддаленыя галіны аддаленага рэпазыторыю «origin» можна такім чынам:

Зьліцьцё і перамяшчэньне галінаў

Зьліцьцё

Каманда зьліцьця выглядае наступным чынам:

Пры зьліцьці зьмены з пазначанай у камандзе галіны («some_branch») заўсёды заліваюцца ў цяперашнюю галіну, але якім чынам адбываецца зьліцьцё падзяляецца на 2 спосабы.

Прасоўваньне наперад

Уявім сабе, што мы адгалінаваліся ад асноўнай галіны, зрабілі ў новай галіне пэўныя зьмены, а асноўная за гэты час не зьмянілася:

Асноўная галіна не зьмянілася за час рэдагаваньня дадатковай

Мы праверылі, што новы функцыянал працуе правільна і жадаем яго зьмясьціць у асноўную галіну. Для гэтага пераключаемся ў асноўную галіну:

Пераключэньне ў асноўную галіну

і выконваем каманду зьліцьця:

У гэты момант ніякага зьліцьця на самай справе не адбываецца. Давайце разьбяромся, для гэтага паглядзіце на папярэдні малюнак, пры гэтым трэба памятаць, што галіны ў нашых схемах «рухаюцца» зьнізу ўверх. Пры гэтым, як відаць з малюнка, з галавы (паказальнік HEAD) асноўнай галіны можна трапіць у галаву галіны «feature», якую мы зьліваем, заўсёды рухаючыся наперад. Таму Git у такім выпадку ня робіць зьліцьцё, а проста перамяшчае галаву асноўнай галіны ў галаву той, што зьліваецца:

Прасоўваньне наперад
То бок прасоўвае паказальнік наперад (fast forwarding у ангельскай тэрміналёгіі).

Паўнавартаснае

Калі ж за час працы над галіной «feature», у асноўную галіну былі ўнесеныя зьмены:

Асноўная галіна зьмянілася за час рэдагаваньня дадатковай

Тады простае прасоўваньне наперад немагчымае: нельга трапіць з галавы «master» у галаву «feature», рухаючыся выключна наперад. У гэтым выпадку пры выкананьні зьліцьця Git спрабуе сабраць усе зьмены, якія былі зробленыя ў галіне «feature» з моманту адгалінаваньня ад «master», накласьці іх на цяперашні стан «master» і зафіксаваць гэтыя зьмены пры дапамозе новага каміту:

Паўнавартаснае зьліцьцё

Канфлікты і іх вырашэньне

Пры паўнавартасным зьліцьці магчымыя канфлікты — гэта калі адзін і той жа кавалак коду ў пэўным файле быў зьменены ў абедзьвюх галінах пасьля іх адгалінаваньня. У выпадку ўзьнікненьня канфлікту Git спыніцца і прапануе выправіць канфлікт:

Калі ў гэты момант выканаць каманду git status:

Можна ўбачыць, што Git не зрабіў каміт, але спыніўся як раз перад ім. Цяпер трэба ўручную ўнесьці неабходныя зьмены ў канфліктны файл (README.txt). Трэба заўважыць, што ён зараз утрымлівае вэрсіі зьменаў з абедзьвюх галінаў, абгорнутых у адмысловы сынтаксіс Git:

Усё, што стаіць паміж радкамі <<<<<<< HEAD і ======= — гэта зьмены, якія былі зробленыя ў галіне «master», а тое, што стаіць паміж ======= і >>>>>>> feature — гэта зьмены, якія былі зробленыя ў галіне «feature». Якім чынам канфлікт павінен быць выпраўлены, залежыць ад сытуацыі. Уявім, што фінальная вэрсія нашага файлу README.txt павінна ўтрымліваць зьмены з абедзьвюх галінаў, тады пакінем у файле такі зьмест:

Цяпер зробім адзнаку для Git, што канфлікт вырашаны, дадаўшы зьмены да індэксу праз каманду git add README.txt, і напрыканцы выканаем каміт: git commit -m "Merge commit". Канфлікт вырашаны, зьмены з галіны «feature» зьлітыя ў асноўную галіну:

Выбарачнае зьліцьцё

Існуе яшчэ каманда выбарачнага зьліцьця асобных камітаў адной галіны ў іншую:

git cherry-pick 53212e5 — зьлівае каміт, хэш якога пазначаны апошнім у камандзе, зь іншай галіны ў цяперашнюю.

git cherry-pick --edit 53212e5 — тое ж самае, што і папярэдняя каманда, але ў дадатак адкрыецца акно для зьмены камэнтара каміту, які мы зьліваем.

git cherry-pick --no-commit 53212e5 55ae374 — адначасова зьлівае зьмены з двух камітаў іншай галіны ў цяперашнюю, пры гэтым зьлітыя зьмены не каміцяцца, але толькі індэксуюцца, каб пазьней закаміціць іх асобнай камандай.

git cherry-pick -x 53212e5 — пры зьліцьці каміту, дадае адпаведны камэнтар з пазначэньнем поўнага хэшу гэтага каміту (мае сэнс толькі калі аддалены каміт зьліваецца ў лякальную галіну, інакш лякальны хэш ня будзе мець ніякага сэнсу для іншых удзельнікаў каманды).

git cherry-pick --signoff 53212e5 — пры зьліцьці каміту, дадае інфармацыю пра аўтара зыходнага каміту і пра аўтара зьліцьця.

Перамяшчэньне

Для перамяшчэньня характэрна тое, што месца адгалінаваньня пэўнай галіны перамяшчаецца з аднаго каміту ў іншы. Гэты спосаб эквівалентны зьліцьцю, у сэнсе таго, што ў выніку будзем мець той жа самы стан актыўнай галіны. Адрозьненьнем жа зьяўляецца тое, што гісторыя камітаў будзе выглядаць не разгалінаванай, але лінейнай:

Ілюстрацыя перамяшчэньня галінаў

Каб зрабіць перамяшчэньне цяперашняй працоўнай галіны «feature» у асноўную «master», трэба выканаць наступную каманду (актыўнай галіной у гэты момант павінна быць «feature» — git checkout feature):

Калі паглыбіцца ў дэталі, то пры гэтым адбываецца наступнае: зьмены цяперашняй галіны, якія былі зроблены ў ёй пасьля адгалінаваньня ад «master», перамяшчаюцца ў часовае сховішча; пасьля гэтага паказальнік цяперашняй галіны перамяшчаецца ў HEAD галіны «master», а потым наноў ужываюцца зьмены з часовага сховішча.

Калі ў часе зьліцьця Git сутыкнуўся з канфліктам, ён спыніцца і запытае выправіць канфлікт. Пасьля выпраўленьня (напрыклад у файле README.txt) трэба праіндэксаваць зьмены (зьвярніце ўвагу, што на дадзеным этапе мы знаходзімся ня ў пэўнай галіне, а пасярод перамяшчэньня, так бы мовіць у працоўным асяродку Git'а):

а пасьля гэтага даць каманду скончыць працэс зьліцьця:

Інтэрактыўная перабудова

Хаця для выкананьня перабудовы камітаў выкарыстоўваецца тая ж каманда rebase, я вынес апісаньне ў асобны разьдзел, таму што сутнасьць перабудовы зусім іншая ў параўнаньні з перамяшчэньнем. Наступная каманда прапануе інтэрактыўную перабудову двух апошніх камітаў цяперашняй галіны.

У выніку ў новым тэкставым акне будзе выведзена наступная інфармацыя для магчымай праўкі:

Калі ўсё пакінуць як ёсьць (каманду pick), тады 2 апошніх каміта будуць ізноў ужыты па новай. Але ёсьць і іншыя магчымасьці (чытай ніжэй).

Перастаноўка і выключэньне

Самае простае, што можна зрабіць — гэта зьмяніць парадак камітаў ці ўвогуле выключыць які(-я)-небудзь зь іх. Для гэтага зьменім першыя тры радкі ў зьявіўшымся акне на наступнае:

У гэтым выпадку, калі захаваць зьмены ў акне і закрыць яго, каміты 310154e і f7f3f6d будуць памененыя месцамі, а каміт a5f4a0d увогуле будзе выключаны і не ўжыты.

Замена камэнтароў да камітаў

Наступнае, што можна зрабіць — гэта зьмяніць камэнтар да камітаў. Для гэтага ужывем каманду reword для таго каміту, камэнтар якога жадаем зьмяніць:

У гэтым выпадку, калі захаваць зьмены ў акне і закрыць яго, для каміта f7f3f6d будзе запытаны новы камэнтар.

Злучэньне камітаў

Таксама можна злучыць некалькі камітаў у адзін. Для гэтага ужывем каманду squash:

У гэтым выпадку, калі захаваць зьмены ў акне і закрыць яго, зьмены камітаў 310154e і a5f4a0d будуць злучаны са зьменамі каміту f7f3f6d і ўсе яны будуць ужыты як адзін каміт.

Рэдагаваньне камітаў

Пры дапамозе каманды edit асобныя каміты могуць быць разьбітыя на некалькі камітаў ці ўвогуле быць зьмененыя цалкам (больш падрабязна глядзі адпаведны разьдзел кнігі ProGit)

Прагляд гісторыі зьменаў

git log --pretty=oneline — выводзіць кожны запіс логу у адзін радок.

git log --oneline --graph — выводзіць кожны запіс логу у адзін радок пры гэтым паказвае гісторыю камітаў у выглядзе графу.

Пры вывадзе логу можна задаваць якім прамежкам часу трэба абмежавацца:

git log --until=1.minute.ago — усе логі ад пачатку і да кропкі часу, якая была 1 хвіліну назад.

git log --since=1.day.ago — усе логі за апошнія суткі.

git log --since=1.month.ago --until=2.weeks.ago — усе логі пачынаючы ад кропкі часу 1 месяц назад і да кропкі часу 2 тыдні назад.

git log --since=2000-01-01 --until=2012-12-21 — усе логі пачынаючы ад даты 01.01.2010 і да даты 21.12.2012.

---

Пры запыце паказаць зьмены можна карыстацца наступнымі магчымасьцямі:

git diff HEAD^ — паказаць чым адрозьніваецца цяперашні стан ад перадапошняга каміту.

git diff HEAD^^ — паказаць чым адрозьніваецца цяперашні стан ад стану ў 3 каміты назад.

git diff HEAD~5 — паказаць чым адрозьніваецца цяперашні стан ад стану ў 5 камітаў назад.

git diff HEAD^..HEAD — паказаць чым адрозьніваецца перадапошні каміт ад апошняга.

git diff 4fb063f..f5a6ff9 — паказаць чым адрозьніваюцца 2 каміта па скаротам іх хэшаў.

git diff master temp — таксама можна параўнаць дзьве галіны.

---

git blame index.html --date short — паказвае падрабязную інфармацыю па ўсёй гісторыі зьменаў ў пэўным файле.


Ачыстка гісторыі (purging history). Часьцей за ўсё яна абгрунтавана датычна лякальнага рэпазыторыю, альбо цэнтральнага калі напрыклад выдаляецца вялікі файл, каб гісторыя не захоўвала яго, ці выдаляецца файл, які парушае аўтарскія правы - таксама, каб гісторыя не захоўвала яго. У астатніх выпадках зьмена гісторыі цэнтральнага рэпазыторыю непажадана.

git filter-branch --tree-filter 'rm -f passwords.txt' — Git будзе вымаць з рэпазыторыю ў працоўную тэчку кожны з камітаў, запускаць пазначаную каманду (выдаленьне файлу passwords.txt з кораня праекта) і затым наноў рабіць гэты каміт. Опцыя -f патрэбная на выпадак, калі нейкі каміт не ўтрымлівае файлу passwords.txt, каб выкананьне ачысткі гісторыі не «зламалася» з-за гэтага.

git filter-branch --tree-filter 'rm -f passwords.txt' -- --all — тое ж, што і папярэдняя каманда, але выдаленьне файлу будзе адбывацца ня толькі ўва ўсіх камітах актыўнай галіны, але ўвогуле ўсіх галінаў праекта. Замест --all можна пазначыць любую галіну, у якой мы жадаем пачысьціць гісторыю.

Каб Git не вымаў кожны з камітаў і не каміціў яго наноў, а зрабіў чыстку наўпрост у рэпазыторыі каманду можна зьмяніць наступным чынам:

git filter-branch --index-filter 'git rm --cached --ignore-unmatch passwords.txt' — прызначэньне опцыі --ignore-unmatch аналягічна прызначэньню опцыі -f у камандах, прыведзеных вышэй.

Калі робіцца чыстка гісторыі, Git стварае рэзэрвовую копію дрэва гісторыі. Пры спробе запусьціць яшчэ адну чыстку, ён выдасьць паведамленьне, што не можа стварыць яшчэ адзін бэкап. Каб пазьбегнуць гэтага можна дадаць опцыю -f у саму каманду filter-branch:

git filter-branch -f --tree-filter 'rm -f passwords.txt'

У выніку чысткі гісторыі некаторыя каміты могуць стаць пустымі. Напрыклад, нейкі каміт утрымліваў толькі выдаленьне нейкага аднаго файлу, а мы потым гэты файл выдалілі з гісторыі. Каб увогуле сьцерці такія пустыя каміты з гісторыі, можна скарыстацца наступнай камандай:

git filter-branch -f --prune-empty -- --all

git reflog — тое ж, што і звычайны лог, але выводзіць абсалютна ўсю гісторыю зьмены HEAD, улічваючы нават выдаленыя каміты.

git log --walk-reflogs — тое ж, што reflog, праз каманду звычайнага логу.

Тэгі

У Git тэгамі завуцца спасылкі на пэўныя каміты, звычайна для адсечкі рэлізаў.

git tag — выводзіць сьпіс тэгаў.

git tag -a v0.0.3 -m "version 0.0.3" — стварае тэг «v0.0.3» з пазнакай адпаведнага камэнтару.

git push --tags — пераносіць новыя тэгі на аддалены рэпазыторый.

git tag -d release01 — выдаляе тэг «release01» з лякальнага рэпазыторыю.

git push origin :refs/tags/release01 — выдаляе той жа тэг «release01» толькі з аддаленага рэпазыторыю.

Часовае сховішча

git stash save — захоўвае ў часовым сховішчы яшчэ ня скончаныя і, адпаведна, не зафіксаваныя зьмены ў адной з галінаў, перад тым як пераключыцца ў іншую (напрыклад, узьнікла такая неадкладная патрэба). Гэты пачак захаваных зьменаў атрымлівае імя выгляду stash@{0} і такіх пачкаў раней захаваных зьменаў можа быць некалькі (мяняюцца нумары ў дужках у імені).

git stash list — выводзіць сьпіс усіх зьменаў, якія былі раней зьмешчаны ў часовае сховішча.

git stash apply — бярэ зьмены з часовага сховішча пад імем stash@{0} і вяртае іх ў актыўную галіну (АЛЕ ў часовым сховішчы гэтыя зьмены працягваюць заставацца). Калі трэба выняць зьмены пад іншым імем, гэтае імя дадаецца ў каманду апошнім аргумэнтам.

git stash drop — выдаленьне зьменаў пад імем stash@{0} з часовага сховішча. Калі трэба выдаліць зьмены пад іншым імем, гэтае імя дадаецца ў каманду апошнім аргумэнтам.

git stash pop — аб'ядноўвае дзьве папярэднія каманды ў адну (спачатку выконвае git stash apply, а затым git stash drop).

git stash save --keep-index — захоўвае ў часовым сховішчы зьмены, за выключэньнем ужо праіндэксаваных, якія пакідаюцца ў актыўнай галіне для магчымага каміту.

git stash save --include-untracked — захоўвае ў часовым сховішчы зьмены, за якімі Git ужо сочыць, і ў дадатак новыя файлы, якія яшчэ не былі дададзеныя ў рэпазыторый.

git stash save "Some comment" — пры захоўваньні зьменаў у часовым сховішчы, да іх можна дадаць камэнтар.

git stash list --stat — акрамя самога сьпісу зьменаў выводзіць яшчэ дадатковую інфармацыю пра іх.

git stash show — выводзіць дадатковую інфармацыю пра зьмену, захаваную ў часовым сховішчы.

git stash clear — выдаляе ўсе зьмены з часовага сховішча.

Падмодулі

Падмодулі (submodules) — гэта асобныя рэпазыторыі, якія прызначаны для захоўваньня даных, якія выкарыстоўваюцца некалькімі праектамі. Можна іх яшчэ назваць бібліятэкамі. Ствараюцца падмодулі гэтак жа сама, як і звычайныя рэпазыторыі, а спаслацца на іх зь іншага праекту (рэпазыторыю) можна наступным чынам:

git submodule add [email protected]:css.git — дадзеная каманда створыць асобную тэчку css у корані цяперашняга рэпазыторыю і спампуе туды зьмест падмодуля. Пасьля выкананьня гэтай каманды трэба закаміціць зьмены і запушыць іх на аддалены рэпазыторый.

Зьвязваньне цяперашняга рэпазыторыю з падмодулем стварае толькі загатоўку паўнавартаснай працы, што трэба зрабіць далей:

cd css — уваходзім у створаную тэчку.

git checkout master — ...і ствараем асноўную галіну. Пасьля гэтага мы можам рабіць неабходныя зьмены ў падмодулі і каміціць іх звычайным чынам:

git commit -am "Update menu font" — ... а пасьля пушыць зьмены ў падмодулі на сэрвэр: git push".

Але гэта ня ўсё, пасьля гэтага трэба вярнуцца ў бацькоўскі рэпазыторый: cd .., праіндэксаваць зьмены ў гэтым бацькоўскім рэпазыторыі (зьмяніўся зьмест падмодулю): git commit -m "Update menu fonr in css" і запушыць іх на сэрвэр: git push.

Калі нехта клянуе сабе аддалены рэпазыторый, які ўтрымлівае падмодулі, перад пачаткам лякальнай працы з праектам неабходна запусьціць гэтую каманду: git submodule init, каб Git зрабіў усе неабходныя наладкі, а пасьля гэтую каманду: git submodule update, каб Git сьцягнуў зьмест гэтых падмодуляў.

Падобна, калі 2 удзельніка каманды працуюць над рэпазыторыям, які ўлучае ў сябе падмодуль, і адзін зь іх робіць зьмену ў падмодулі, тады іншаму недастаткова проста сьцягнуць зьмены як звычайна: git pull, але трэба яшчэ дадаткова зрабіць лякальнае аднаўленьне падмодулю: git submodule update.

У выпадку падмодуляў вельмі важна памятаць, што пушыць трэба 2 разы — адзін раз сам падмодуль, іншы раз бацькоўскі рэпазыторый. Праблема ў тым, што Git дазволіць запушыць бацькоўскі рэпазыторый без папярэдняга пушаньня падмодулю, і ў гэтым выпадку далейшая праца ўсёй каманды будзе спынена, пакуль памылка не будзе выпраўлена. Каб не зрабіць такой памылкі, можна заўсёды пушыць бацькоўскі рэпазыторый з наступнай опцыяй, якая не дазволіць гэта зрабіць, пакуль не запушаны падмодуль: git push --recurse-submodules=check.

Але ёсьць яшчэ больш зручны спосаб не зрабіць памылкі: git push --recurse-submodules=on-demand. Гэтая каманда аўтаматычна запушыць усе падмодулі пры неабходнасьці.

Для доўгіх камандаў, як у папярэдніх выпадках, можна рабіць скароты: git config alias.pushall "push --recurse-submodules=on-demand". Наступным разам дастаткова будзе набраць: git pushall, каб Git запушыў падмодулі і бацькоўскі рэпазыторый за адну каманду.


Даведнікі пераехалі на GitHub Pages. Актуальная вэрсія даступная па адрасе: https://yurtsevich.github.io/refs/git/