Мета заняття: навчитися зберігати історію змін програмою git, повертати зіпсований файл до робочого стану, вести ризиковану ідею окремо від робочого коду й надсилати всю історію в запасне сховище на сервері. Слова «коміт», «гілка» та «репозиторій» розібрані далі в теорії.
Замість <логін> підставляєш свій
логін виду bohdan.g9: ім’я, крапка, номер групи. Кутові дужки не пишуться.
Кабінет — сторінка, де проти кожного критерію стоїть відмітка, зарахований він чи ні.
У прикладах на цій сторінці скрізь написано bohdan.g9 — читай це як свій логін.
Ти розкладеш усе, що написав на заняттях 01 і 02, на окремі коміти —
так називають збережені стани проєкту — зі зрозумілими повідомленнями й напишеш
.gitignore, список того, що git навмисно не зберігає. Потім навмисно зламаєш
main.py, побачиш, що сервіс перестав відповідати, і повернеш робочу версію
однією командою.
Наприкінці заняття в тебе буде щонайменше п’ять власних комітів, друга
гілка (окрема лінія комітів) для ризикованої ідеї й уся історія, надіслана
у сховище ~/repo.git на сервері. Якщо після цього видалити всю теку
~/app, код можна буде повернути. Кожне з цих слів докладно розібране в теорії
нижче.
Ситуація, яка трапляється з кожним. Сервіс працює. Ти відкриваєш main.py,
міняєш кілька рядків, перезапускаєш службу — програму, яку система запускає
сама й тримає запущеною постійно; твоя зветься club-api, з нею ти працював на
занятті 02, — і сторінка більше не відкривається. Що саме ти змінив десять хвилин тому, вже
не пам’ятаєш: правок було чотири в трьох місцях файлу.
Звичайний спосіб захиститися — копії: main2.py, main_stare.py,
main_finalne.py. Через тиждень з цих копій нічого не зрозуміло. Яка з них
робоча? Чим main2.py відрізняється від main_stare.py? Коли саме
з’явилася помилка? Копії відповіді на ці питання не дають.
Git — програма, яка зберігає історію змін у теці проєкту. Вона запам’ятовує, які саме рядки в яких файлах змінилися, коли це сталося і що ти написав про цю зміну, і вміє повернути будь-який попередній стан.
.git всередині неї — прихованій, бо її назва починається з крапки, і звичайна
команда ls такі назви не показує.main.py, README.md та інші.
Це поточний стан проєкту; історія змін зберігається окремо, у теці .git.Тека ~/app у тебе вже є репозиторієм: git там увімкнули, коли створювали
акаунт, і зробили перший коміт із заготовкою. Сьогодні ти в цьому переконаєшся на першому
кроці практики.
Коміт — записаний стан усіх файлів проєкту на той момент, коли ти виконав
команду. У кожному коміті зберігається: вміст файлів, дата й час, ім’я автора, твоє
повідомлення про те, що змінилося, і хеш — рядок із літер і цифр, який git
обчислює сам. Хеш — це ідентифікатор коміта: за ним коміт знаходять і на нього посилаються.
Повний хеш має 40 символів, наприклад
a3f19c2b6d41e0f8c95a7b23d4e6f1908c7a5b3d, але git майже скрізь друкує тільки
перші сім: a3f19c2. Цього скорочення достатньо, щоб відрізнити один коміт від
іншого — на практиці два різні коміти не отримують однакового хеша.
Кожен коміт зберігає посилання на попередній, тому коміти утворюють послідовність. Завдяки
цьому історію можна прочитати згори вниз командою git log. У прикладі нижче
трапляється слово ендпоінт — так із заняття 02 називають окрему адресу, за
якою твоя програма щось відповідає: /api/ping, /api/about.
git log --oneline7c1a9e4 оновив README описом продукту
b83d0f1 виправив заголовок сторінки
5e2ab77 додав ендпоінт /api/about
a3f19c2 додав .gitignore
9f04c88 Заготовка проєктуПриклад із твого вечора. О 19:40 ти зробив коміт «додав ендпоінт /api/about» — тоді все працювало. О 20:15 сервіс перестав відповідати. Історія показує, що між цими моментами був рівно один коміт, а решта змін ще не збережена. Значить, шукати треба у файлах, змінених після 19:40, і в найгіршому разі можна повернути стан на 19:40 і почати заново — код за цю дату нікуди не подівся.
Дмитро зробив коміт о 18:00, після цього дві години правив main.py
і жодного разу не комітив. О 20:00 сервіс перестав відповідати. Що git може повернути
прямо зараз?
Між зміненим файлом і комітом є проміжний крок, і саме на ньому найчастіше плутаються.
Змінений файл спочатку потрапляє в індекс (англійською staging) — список
змін, підготовлених до наступного коміта. Команда git add кладе зміни в цей
список, команда git commit записує в історію те, що в ньому зібралося.
робоча копія --git add--> індекс --git commit--> історіяПобачити обидва списки одразу можна командою git status: зверху йде те, що
вже в індексі й потрапить у наступний коміт, нижче — те, що змінено, але в індекс не
додано.
Навіщо цей проміжний крок. За вечір ти виправив помилку в main.py й заодно
переписав README.md. Це дві різні справи, і в історії їм краще бути двома
комітами з різними повідомленнями. Індекс дозволяє покласти в коміт лише частину змін:
git add main.py, коміт, потім git add README.md, ще один коміт.
Важлива деталь. У коміт іде та версія файлу, яка була на момент git add.
Якщо після git add ти ще раз відредагував файл, останні правки лишаться поза
комітом, поки ти не виконаєш git add вдруге. git status у такому
разі показує один і той самий файл у двох списках одночасно.
Максим виконав git add main.py, потім помітив друкарську помилку
в тому ж файлі, виправив її та зберіг, і одразу зробив git commit -m "...".
Що потрапило в коміт?
Повідомлення пишеться для людини, яка читатиме історію, — найчастіше для тебе самого через місяць. Самому git усе одно, що там написано. Хороше повідомлення одним рядком відповідає на питання «що змінилося в проєкті».
У таблиці нижче трапляється число 500. Це код відповіді сервера: він
означає, що запит дійшов до програми, але під час обробки програма завершилася з помилкою.
Коди відповідей ти бачив на занятті 02: 200 — усе добре, 404 —
такого шляху немає, 500 — помилка всередині програми.
| Так не пишуть | Чому | Так пишуть |
|---|---|---|
| fix | Не сказано ні що зламалося, ні де | виправив 500 на порожній назві в /api/items |
| зміни | Коміт за визначенням містить зміни | додав розділ «Як запустити» в README |
| 123 | Через тиждень не означатиме нічого | заповнив project.yaml: назва, автор, три функції |
| робота за вівторок | Дата й так є в коміті, а що зроблено — ні | додав ендпоінт /api/about з даними брифу |
Практичні правила: один рядок, приблизно до 70 символів; починати з дієслова («додав», «виправив», «переписав»); писати про зміст зміни — «додав ендпоінт /api/about» замість «змінив main.py». Якщо в повідомленні хочеться написати «і», це майже завжди означає, що змін дві й комітів теж має бути два.
Через три тижні Софія шукає, у якому коміті зник підпис автора зі сторінки.
Вона відкриває git log і бачить сорок рядків. Яке повідомлення допоможе їй
знайти потрібний коміт, не переглядаючи всі сорок?
.gitignore — файл зі списком того, що git навмисно не зберігає. Кожен рядок
у ньому — правило: назва файлу, назва теки або шаблон на кшталт *.db, де
зірочка означає «будь-яка послідовність символів».
Не кладуть у репозиторій три групи файлів.
venv) — окрема тека з бібліотеками для одного проєкту. Створює її команда
python3 -m venv venv; pip потім лише встановлює бібліотеки
всередину. Тека важить сотні мегабайтів і на іншому комп’ютері все одно не запрацює: у ній
записані шляхи конкретної системи. Сюди ж тека __pycache__: перед запуском
Python переводить твій код у проміжний вигляд, зрозуміліший йому самому, і складає
результат у цю теку, щоб наступного разу не робити цього знову. Такі файли Python створює
сам, тому зберігати їх у git не треба.~/data і змінюється щоразу, коли
хтось додає запис. Історія коду й дані користувачів — різні речі, і зберігати їх треба
окремо: для бази на занятті 11 буде окремий бекап..env — це текстовий файл із паролями та
ключами, які програма читає під час запуску. Він з’явиться в тебе на занятті 07. Пароль,
який потрапив у репозиторій, вважається розкритим, навіть якщо його звідти прибрали.Тепер важливе про те, як .gitignore працює. Файл, який хоч раз потрапив у
коміт, називається відстежуваним: git знає про нього і стежить за його
змінами. Правила .gitignore діють тільки на невідстежувані файли. Якщо
ти закомітив .env, а потім дописав його в .gitignore, git
продовжить його зберігати, а стара копія з паролем назавжди залишиться в історії. Саме тому
.gitignore пишуть заздалегідь — до того, як такі файли з’являються.
Андрій випадково закомітив файл .env, у якому лежить пароль до
бази. Помітив це наступного дня, дописав рядок .env у .gitignore
і зробив ще один коміт. Що зараз із паролем?
«Відкотити» означає різні речі залежно від того, що саме сталося. Розберемо чотири випадки й команду до кожного.
Ситуація перша: зіпсував файл і ще не комітив. Команда повертає файл до стану з останнього коміта.
git restore main.pyСитуація друга: не пам’ятаю, що саме змінив. Команда друкує рядки, які відрізняються від останнього коміта: із мінусом — те, що було, із плюсом — те, що стало.
git diffСитуація третя: треба повернути файл до стану з давнього коміта. Береш хеш
із git log --oneline і вказуєш його як джерело.
git restore --source=a3f19c2 main.pyСитуація четверта: коміт уже зроблений, а зміни виявилися невдалими.
Команда git revert створює новий коміт, який скасовує зміни вказаного. Історія
при цьому не стирається: видно і невдалу спробу, і її скасування.
git revert a3f19c2git status і git diff —
чи справді ти хочеш втратити те, що там написано.Марта півгодини правила main.py, не комітила, і тепер служба не
запускається. Вона хоче повернутися до останньої робочої версії й почати заново. Яка
команда це зробить?
Гілка — окрема лінія комітів усередині того самого репозиторію. Основна
гілка в наших проєктах називається master: у ній лежить те, що працює. Коли ти
хочеш спробувати щось ризиковане, ти створюєш другу гілку й комітиш у неї. Коміти, зроблені
в другій гілці, у master не потрапляють.
Приклад. Ти вирішив повністю переробити сторінку сервісу: інша структура, інші кольори,
дві години роботи, і невідомо, чи вийде краще. Створюєш гілку feature/nova-storinka
(feature — прийнята назва для гілок із новими можливостями; коса риска в назві
дозволена), працюєш у ній. Якщо вийшло — переносиш зміни в master. Якщо ні —
просто перемикаєшся назад, і всі файли master стають такими, якими були до
експерименту.
git switch -c feature/nova-storinka # створити гілку й перейти в неї
git switch master # повернутися на основну
git branch # список гілок, зірочка проти поточноїПеремикання гілки змінює файли в теці. Ти виконуєш git switch master — і
www-index.html знову має той вміст, що в master. Це не втрата:
коміти другої гілки лишилися на місці, повернешся в неї — повернеться і її версія файлів.
Олег створив гілку feature/temna-tema, зробив у ній два коміти,
потім виконав git switch master і відкрив www-index.html. Темної
теми у файлі немає. Що сталося?
Remote (вимовляється «рімоут») — адреса іншого репозиторію, з яким твій
обмінюється комітами. Найвідоміший приклад такого репозиторію — GitHub, але remote може бути
й просто текою на тому самому сервері. У тебе він уже є: це ~/repo.git. Коротка
назва для нього — origin: саме її пишуть у командах замість повного шляху.
~/repo.git — bare-репозиторій (вимовляється «бер»), тобто
репозиторій без робочої копії: тільки історія, самих файлів main.py чи
README.md там немає. Туди не заходять редагувати код, туди надсилають коміти
командою git push.
git push origin masterЧитається так: надішли в репозиторій origin коміти гілки
master. Надсилаються тільки ті коміти, яких там ще немає.
Навіщо це потрібно на тому самому сервері. По-перше, історія зберігається окремо від
робочих файлів: якщо ти помилково видалиш або зіпсуєш теку ~/app, коміти
вціліють у ~/repo.git, і проєкт можна відновити. По-друге, на занятті 09 саме
звідти забиратиме код скрипт deploy.sh: викочування нової версії
перетворюється на одну команду.
Ігор зробив git push origin master, а після цього ще два коміти
в ~/app. Наступного дня він випадково видалив теку ~/app цілком.
Що можна відновити з ~/repo.git?
Далі скрізь замість bohdan.g9 підставляй свій логін. Усі команди git
виконуються всередині теки репозиторію, тобто в ~/app.
Команда ssh (від secure shell) відкриває командний рядок сервера у твоєму
вікні терміналу: усе, що ти набираєш далі, виконує сервер 91.219.61.4, а твій
комп’ютер лише показує відповідь. Пароль вводиться наосліп, символи на екрані не
з’являються.
ssh bohdan.g9@91.219.61.4
cd ~/app
pwdКоманда pwd має надрукувати /home/bohdan.g9/app. Якщо шлях
інший, git працюватиме не з тим репозиторієм або взагалі скаже, що репозиторію тут немає.
Git записує в кожен коміт ім’я й пошту автора. Поки ти їх не назвав, git поводиться по-різному: або відмовляється створити коміт і пише «Please tell me who you are», або підписує коміт ім’ям, яке вгадав із назви твого акаунта та імені сервера. Вгадане ім’я тобі не потрібне, тому назви себе сам.
git config --global user.name "Богдан"
git config --global user.email "bohdan.g9@club.local"--global означає «для всіх репозиторіїв цього акаунта», тому команду досить
виконати один раз. Пошту git нікуди не надсилає, вона потрібна лише як підпис; можна
вказати club.local, як у прикладі. Прізвище не пиши: сервер спільний на всю
групу, і твою історію може прочитати кожен, хто має доступ до теки, — викладач і
адміністратор. Перевір, що записалося:
git config --global --listls -a ~/app
git log --oneline
git status
git remote -vПерша команда покаже серед звичайних файлів приховану теку .git — це і є
історія. Друга надрукує один коміт із повідомленням «Заготовка проєкту»: його зробили при
створенні акаунта.
git status покаже два списки: Changes not staged for commit —
файли, які ти змінив на заняттях 01 і 02 (project.yaml, main.py),
та Untracked files — файли, про які git ще не знає взагалі
(BRIEF.md, можливо ANALOGI.md і тека __pycache__).
git remote -v надрукує два рядки з назвою origin і шляхом
/home/bohdan.g9/repo.git: віддалений репозиторій уже підключений, залишиться
тільки надіслати туди коміти.
nano ~/app/.gitignoreНабери такий вміст. Рядки, що починаються з #, — коментарі, git їх не
читає, вони для людини.
# те, що відновлюється однією командою
__pycache__/
*.pyc
venv/
.venv/
# дані, які створює програма
*.db
*.sqlite3
data/
# секрети
.envЗберегти й вийти з nano: Ctrl+O, Enter, потім
Ctrl+X. Тепер подивись, що змінилося:
git statusТека __pycache__ зі списку зникла — git більше не пропонує її додати. Замість
неї з’явився новий невідстежуваний файл .gitignore: сам список правил у
репозиторії зберігають, він частина проєкту.
/opt/club/venv на всіх. Файл бази з’явиться на занятті 04 у
~/data, тобто теж поза репозиторієм. Правила все одно пишемо зараз: вони
знадобляться, коли ти працюватимеш із цим проєктом на своєму комп’ютері, і потрібні для
автоперевірки.git add .gitignore
git statusТепер .gitignore у верхньому списку — Changes to be committed.
Це індекс: те, що потрапить у наступний коміт. Записуємо:
git commit -m "додав .gitignore: git не стежить за кешем, базою і .env"У відповідь git надрукує щось на кшталт [master 4b7c1a9] додав .gitignore… і
рядок 1 file changed, 13 insertions(+): один файл, тринадцять доданих рядків.
master на початку — назва гілки, у яку записано коміт.
Дивимось, що ще не збережено, і додаємо по одному файлу — кожен зі своїм повідомленням.
git status
git add project.yaml
git commit -m "заповнив project.yaml: назва продукту, автор і три функції"
git add BRIEF.md
git commit -m "додав BRIEF.md з описом користувача і задачі"
git add main.py
git commit -m "додав ендпоінт /api/about з даними брифу"Якщо якогось із цих файлів немає у списку змінених — пропусти відповідний коміт, це
нормально. Якщо є зайві файли з домашніх завдань, наприклад ANALOGI.md, додай
їх окремим комітом з таким самим підходом: одна зміна — один коміт.
Після кожного коміта корисно виконати git log --oneline і подивитися, як
росте список.
README.md — головний файл-опис проєкту. Його читає той, хто відкриває твою
теку вперше. У заготовці розділи вже намічені, але текст у них службовий, у курсиві між
символами підкреслення. Твоє завдання — замінити його своїм.
У розділі «Як запустити» тобі знадобляться чотири слова із заняття 02.
Служба — програма, яку система запускає сама й тримає запущеною постійно;
твоя зветься club-api. Службами в Linux керує systemd —
частина системи, яка запускає й зупиняє все, що має працювати постійно; ключ
--user у командах означає «моя власна служба, а не загальносерверна». Опис
твоєї служби systemd тримає у файлі ~/.config/systemd/user/club-api.service.
Журнал — записи, які служба надрукувала під час роботи, разом з усіма
помилками; показує їх команда journalctl. curl — програма, яка
робить запит на адресу прямо з командного рядка й друкує відповідь текстом, без браузера.
Ще знадобиться твій порт — число, за яким система відрізняє твою програму від програм решти групи; ти знаходив його на занятті 02. Воно записане в тому самому файлі опису служби:
grep ExecStart ~/.config/systemd/user/club-api.serviceУ надрукованому рядку після --port стоїть твоє число. Випиши його: за хвилину
ти впишеш його в README своєю рукою. У кожного учня число своє, чуже не спрацює.
nano ~/app/README.mdРозділ «Що це» — один абзац про те, для кого сервіс і яку задачу він вирішує. Розділ «Як запустити» — команди, якими сервіс перевіряють і перезапускають. Нижче зразок із чужого проєкту: він показує, з чого складається кожен розділ. Списувати його не можна — у тебе інший проєкт, інший автор і свій порт. Тому кнопки «копіювати» на цьому блоці немає, набирай своє.
## Що це
Список робіт для художньої школи. Оля, 11 років, записує туди
роботи й дати здачі та бачить, яка робота наступна. Без цього
дати розкидані по трьох зошитах і половина губиться.
## Як запустити
Сервіс працює на сервері як служба club-api: systemd запускає
її сам після перезавантаження сервера.
systemctl --user status club-api # стан служби
systemctl --user restart club-api # перезапуск після зміни коду
journalctl --user -u club-api -n 30 # останні 30 рядків журналу
Перевірити, що відповідає (замість 9536 підстав свій порт):
curl http://127.0.0.1:9536/api/pingЗаголовки лишай точно такими: два знаки решітки, пробіл, текст. Автоперевірка шукає саме
рядки ## Що це і ## Як запустити. Комітимо:
git add README.md
git commit -m "переписав README: розділи «Що це» і «Як запустити» під свій сервіс"Сайт віддає файл ~/www/index.html, і він лежить поза репозиторієм: git його
не бачить і не зберігає. Щоб історія сторінки теж збереглася, поруч із кодом тримають її
копію — файл ~/app/www-index.html. Такого файлу в тебе ще немає, команда
cp створить його з нуля:
cp ~/www/index.html ~/app/www-index.html
git add www-index.html
git commit -m "додав www-index.html: копія сторінки сайту з заголовком і описом"Команда cp копіює файл: перший шлях — звідки, другий — куди. Далі, коли
правитимеш сторінку, роби це в ~/app/www-index.html, а потім копіюй у
~/www/index.html — тоді в історії буде кожна версія сторінки.
git log --onelineУ списку має бути сім рядків: заготовка й шість твоїх — .gitignore,
project.yaml, BRIEF.md, main.py,
README.md, www-index.html. Якщо якогось із цих файлів у тебе не
було й ти пропустив коміт, рядків буде на один менше; для критерію L03.1 достатньо п’яти
власних комітів.
git ls-filesКоманда друкує повний список відстежуваних файлів — саме його читає автоперевірка. У
ньому не має бути нічого схожого на venv, __pycache__,
.env чи файл із розширенням .db.
git check-ignore -v .envЦя команда відповідає на питання «чому цього файлу немає в списку» і друкує правило, яке
його виключає: .gitignore:13:.env .env — назва файлу з
правилами, номер рядка, саме правило. Якщо у відповідь порожньо, значить, правило не
спрацювало: перевір, чи збережений .gitignore і чи немає в рядку зайвих
пробілів.
Тепер вправа на відкат. Ламаємо сервіс навмисно.
nano ~/app/main.pyДопиши найпершим рядком файлу:
import nemaye_takoyi_bibliotekyЗберігай (Ctrl+O, Enter, Ctrl+X) і перезапускай службу:
systemctl --user restart club-api
systemctl --user status club-apiСтан буде failed або activating (auto-restart): Python не
знаходить бібліотеку з такою назвою й завершується з помилкою, systemd за правилом
Restart=always запускає службу знову, і вона знову завершується. Подивись, що
саме сталося, і перевір адресу:
journalctl --user -u club-api -n 15
curl -I http://91.219.61.4/u/$USER/api/ping$USER — змінна оболонки, у яку система сама підставляє твій логін, тому цю
команду можна копіювати як є.
У журналі буде рядок ModuleNotFoundError: No module named
'nemaye_takoyi_biblioteky'. Ключ -I просить curl надрукувати
тільки заголовки відповіді; у першому рядку буде число 502. Це код відповіді
сервера. Запит спершу приходить на nginx — програму, яка приймає всі запити
до сервера й за шляхом в адресі передає їх потрібній програмі (заняття 02). Nginx звернувся
до твоєї служби, відповіді не отримав і повернув 502. Тепер дивимось, що змінилося, і
повертаємо:
cd ~/app
git diff
git restore main.py
git diffПерший git diff покаже доданий рядок зі знаком плюс. Після
git restore другий git diff не покаже нічого: файл знову такий,
як в останньому коміті. Запускаємо службу заново й перевіряємо:
systemctl --user restart club-api
curl http://91.219.61.4/u/$USER/api/pingУ відповідь має прийти JSON — текстовий запис даних, де кожне значення
підписане ключем, виду {"status":"ok","author":"Богдан"} (заняття 02). У ньому
має стояти твоє ім’я. Запам’ятай цю послідовність: подивитися
журнал, подивитися git diff, повернути файл, перезапустити службу. На занятті
11 ти робитимеш те саме на час.
git switch -c feature/nova-storinka
git branchКлюч -c означає «створити». Команда git branch покаже дві
гілки, зірочка стоїть проти поточної. Тепер зроби в гілці якусь помітну зміну — наприклад,
інший заголовок сторінки:
nano ~/app/www-index.html
git add www-index.html
git commit -m "проба: інший заголовок і порядок блоків на сторінці"Повертаємось на основну гілку й дивимось, що сталося з файлом:
git switch master
head -25 www-index.html
git log --onelineЗаголовок у файлі знову старий, а коміта «проба» в списку немає — він лишився у своїй
гілці. Перемкнешся назад командою git switch feature/nova-storinka — і зміни
повернуться.
git branch -d feature/nova-storinka зараз її не видалить: у гілці є коміт,
якого немає в master, тому git відмовиться й підкаже ключ -D. А от
git branch -D feature/nova-storinka видаляє гілку разом з її комітами без
запитань — після цього критерій L03.3 стане червоним.Спершу переконайся, що ти на основній гілці й знаєш її назву:
git branch --show-currentМає бути master. Якщо там інше слово — підставляй у наступні команди його.
Надсилаємо:
git push origin master
git push origin feature/nova-storinkaGit надрукує кілька рядків із кількістю переданих об’єктів. Об’єкти —
це одиниці, з яких git складає історію: окремо сам коміт, окремо збережений вміст кожного
файлу, окремо опис кожної теки. Читати ці числа не треба, важливий останній рядок. Якщо в
~/repo.git ще не було жодного коміта, він виглядатиме так:
* [new branch] master -> masterЯкщо ти надсилаєш уже вдруге — так, із двома скороченими хешами: зліва той коміт, який був
у ~/repo.git до команди, справа той, який став після неї:
9f04c88..b83d0f1 master -> masterПеревіряємо, що коміти справді дійшли:
git -C ~/repo.git log --oneline master
git -C ~/repo.git branchКлюч -C означає «виконати команду в іншій теці, не переходячи туди». Слово
master в кінці обов’язкове: у ~/repo.git немає робочої копії й
поточної гілки, тому без назви гілки git може відповісти
does not have any commits yet. Списки комітів у ~/app і
~/repo.git мають збігатися, а гілок у ~/repo.git має бути дві.
git status
git log --oneline
git ls-files
git branchgit status має сказати nothing to commit, working tree clean —
усе збережено. У git log — рядок заготовки й твої коміти: за кроками 5–8 їх
шість, разом сім рядків. У git ls-files
немає кешу, бази й .env. У git branch — дві гілки.
Шість критеріїв заняття 03. П’ять перевіряє програма, шостий відмічає викладач під час розбору. Перевірка запускається за розкладом, тому відмітка в кабінеті з’являється не в ту саму секунду, коли ти виконав команду.
| Код | Критерій | Що це означає | Не зараховано — що робити |
|---|---|---|---|
| L03.1 | ≥5 комітів з осмисленими повідомленнями | Програма читає історію в ~/app і лічить коміти. Заготовка, зроблена при
створенні акаунта, до твоїх п’яти не входить. Повідомлення коротші за 10 символів, а
також fix, update, 123 і порожні не рахуються. |
Виконай git log --oneline і порахуй рядки. Історію заднім числом не
переписуй: просто зроби наступні коміти змістовними. Повідомлення останнього
коміта можна виправити командою git commit --amend -m "нове повідомлення",
але тільки якщо його ще не відправлено командою git push. |
| L03.2 | venv, база й .env не відстежуються git | Програма виконує git ls-files і дивиться, чи немає в списку
віртуального оточення, файлів .db та .env. Заодно перевіряє,
що файл .gitignore існує й містить ці правила. |
Подивись список сам: git ls-files. Якщо зайвий файл там уже є, зроби
так, щоб git перестав його відстежувати, і залиш його на диску:
git rm --cached <шлях до файлу>, потім коміт. Перевір, чи збережений
.gitignore: cat ~/app/.gitignore. |
| L03.3 | існує друга гілка | Програма виконує git branch і перевіряє, що гілок щонайменше дві:
основна й твоя. |
Створи гілку: git switch -c feature/nova-storinka. Перевір списком
git branch. Якщо ти вже видалив гілку після експерименту — створи знову й
цього разу залиши. |
| L03.4 | ~/repo.git містить ті самі коміти | Програма порівнює останній коміт у ~/app з останнім комітом у
~/repo.git. Вони мають збігатися, тобто все, що ти закомітив, має бути
відправлено. |
Виконай git push origin master. Якщо push відхилено, перевір назву
гілки командою git branch --show-current і підстав саме її. Порівняй
результати git log --oneline -1 і
git -C ~/repo.git log --oneline -1 master: перший рядок має бути
однаковий. |
| L03.5 | README має розділи «Що це» і «Як запустити» | Програма шукає у ~/app/README.md рядки ## Що це і
## Як запустити й перевіряє, що під ними є твій текст, а не службовий текст
заготовки в курсиві. |
Перевір файл командою cat ~/app/README.md. Звір заголовки посимвольно:
два знаки решітки, один пробіл. Прибери рядки заготовки, узяті в символи підкреслення.
Не забудь після правки зробити коміт і git push. |
| L03.6 | якість повідомлень комітів | Відмічає викладач: відкриває твій git log, вибирає навмання один коміт
і просить пояснити, що саме в ньому змінилося. |
Перечитай свій git log --oneline сам. Якщо на якомусь рядку ти не можеш
сказати, що там за зміна, наступні повідомлення пиши конкретніше — за зразком із розділу
теорії. |
Довести README.md до стану, у якому в проєкті розбереться людина, яка бачить
його вперше. Перевірка проста: дай прочитати комусь із рідних і не пояснюй нічого вголос.
Записуй, на якому місці людина зупинилася й що перепитала.
Найчастіші місця, де читач зупиняється й перепитує: незрозуміло, для кого сервіс; незрозуміло, що таке «служба» й де вона працює; у розділі «Як запустити» є команди, але не сказано, куди їх вводити. Виправ саме ті місця, які назвала твоя людина, а не ті, які здаються тобі слабкими.
Кожне виправлення збережи окремим комітом, у повідомленні напиши, що саме змінив:
cd ~/app
git add README.md
git commit -m "пояснив у README, що сервіс працює на сервері, а не на моєму ноутбуці"
git push origin masterНаприкінці git status має показати working tree clean, а
git -C ~/repo.git log --oneline -1 master — той самий коміт, що й
git log --oneline -1 у теці проєкту.
git commit пише «Please tell me who you are»Git не знає, чиїм іменем підписувати коміт. Виконай два рядки з кроку 2 практики:
git config --global user.name "Богдан"
git config --global user.email "bohdan.g9@club.local"Після цього повтори git commit — раніше введена команда не пропала, просто
коміт не був створений. Перевірити, що ім’я записалося, можна командою
git config --global --list.
git status каже «nothing to commit, working tree clean», хоча ти щойно правив файлGit бачить файли на диску, а не те, що на екрані в редакторі. Найчастіша причина — файл
не збережений: у nano треба натиснути Ctrl+O, потім Enter, і
лише потім Ctrl+X. Друга причина — редагували не той файл: перевір дату
зміни командою ls -l ~/app, у потрібного файлу час має бути свіжий. Третя —
ти виконуєш git не в тій теці: pwd має друкувати
/home/bohdan.g9/app.
git status його взагалі немаєШвидше за все, він підпадає під правило з .gitignore. Спитай git прямо:
git check-ignore -v shlyah/do/fayluКоманда надрукує рядок із номером правила, яке його виключає. Якщо правило зайве — прибери
його з .gitignore. Якщо правило потрібне, а конкретний файл усе ж треба зберегти,
його додають примусово: git add -f назва_файлу. Для .env, бази й
кешу так робити не можна — саме їх правила й мають зупиняти.
git push відповідає «src refspec … does not match any» або «Updates were rejected»Перший текст означає, що гілки з такою назвою в тебе немає: ти надсилаєш
main, а гілка називається master. Дивись назву й підставляй її:
git branch --show-current
git push origin masterДругий текст означає, що в ~/repo.git уже є коміти, яких немає в тебе. На
цьому сервері в твій репозиторій пише тільки ти, тому таке трапляється, якщо ти працював у
двох місцях. Забери те, чого в тебе немає, і надішли своє:
git pull --rebase origin master
git push origin masterКлюч --rebase тут обов’язковий. Без нього git 2.27 і новіші зупиняться з
повідомленням fatal: Need to specify how to reconcile divergent branches і не
зроблять нічого: git не вибирає сам, як поєднати дві розбіжні історії. З --rebase
він спершу забирає коміти з ~/repo.git, а потім укладає твої поверх них. Щоб не
писати цей ключ щоразу, виконай один раз:
git config --global pull.rebase trueСлужба тримає в пам’яті ту версію коду, з якою її запустили. Після
git restore її треба перезапустити:
systemctl --user restart club-api
systemctl --user status club-apiЯкщо стан і далі failed, читай останні рядки журналу:
journalctl --user -u club-api -n 30 — там буде назва файлу й номер рядка з
помилкою. Перевір, що робоча копія справді чиста: git status має сказати
working tree clean, а git diff — нічого не надрукувати.
Окремий випадок. HEAD — службова позначка git, яка показує, на якому коміті
ти зараз стоїш; зазвичай вона вказує на гілку, наприклад на master. Стара команда
git checkout уміє перемикатися і на гілку, і просто на хеш коміта; у другому разі
HEAD вказує на коміт без гілки. Такий стан git називає detached HEAD
і пише про нього в терміналі кількома рядками. Це означає, що ти дивишся старий стан історії,
і коміти, зроблені зараз, не потраплять у жодну гілку. Повернися на основну гілку командою
git switch master.