Git і GitHub: різниця для власників VPS
Git працює на вашому комп’ютері або сервері, а GitHub зберігає репозиторії онлайн. Дізнайтеся, що це означає для налаштування та розгортання на VPS.
Що таке GitHub?
GitHub — це хостингова служба, яка зберігає Git-репозиторії та створює для них вебсайт. Git — це система керування версіями, яка працює на вашому комп’ютері або сервері. GitHub — це продукт однієї компанії поверх Git. З 2018 року він належить Microsoft. Ви можете щодня використовувати Git і ніколи не відкривати GitHub. Неможливо використовувати GitHub без Git.
Це важливо одразу після того, як ви отримуєте VPS (virtual private server). Git записує історію ваших конфігураційних файлів і скриптів розгортання. GitHub зберігає копію цієї історії, коли на сервері її немає, а також надає засоби для запуску збірок і перевірки змін. У цьому посібнику розглянуто один приклад: від порожньої папки до розгортання на сервері. Кожне нове слово пояснюється під час першої згадки.
Що Git робить самостійно
Git — це система керування версіями. Вона записує стан каталогу з часом, щоб можна було побачити, що, коли і чому змінилося. Git створили у 2005 році для роботи над ядром Linux. Це розподілена система, тобто кожна копія репозиторію містить повну історію. У її конструкції немає центрального сервера. Ноутбук колеги є такою самою повною копією, як і будь-який сервер.
Установіть Git і задайте дані своєї ідентичності. Git відмовляється записувати коміт без імені та адреси електронної пошти, оскільки обидва значення записуються безпосередньо в коміт.
sudo apt update && sudo apt install -y git
git --version
git config --global user.name "Your Name"
git config --global user.email "you@example.com"В Ubuntu 24.04 команда git --version виводить git version 2.43.0. Будь-який випуск за останні кілька років поводиться так само в усіх наведених нижче випадках.
Приклад: репозиторій для файлів розгортання VPS
Репозиторій, зазвичай скорочено «repo», — це каталог, за яким стежить Git. Він стає репозиторієм після виконання git init, яка створює в ньому прихований каталог .git. Цей каталог і є репозиторієм. Видаліть .git — і залишиться звичайний каталог без історії.
mkdir vps-deploy && cd vps-deploy
git init -b main
printf '.env\n*.key\n' > .gitignore-b main задає назву першої гілки як main. Якщо не вказати цей параметр, Git виведе розгорнуту підказку щодо назви гілки за замовчуванням. .gitignore містить шляхи, які Git не повинен відстежувати. Додайте до нього файл із секретами в перший день, оскільки файл, який хоча б раз було зафіксовано, залишається в історії навіть після видалення. Щоб видалити його належним чином, потрібно переписати кожен наступний коміт.
Коміти: одиниця історії
Тепер додайте скрипт і зафіксуйте його.
printf '#!/bin/sh\nsudo systemctl restart caddy\n' > restart.sh
git add restart.sh .gitignore
git commit -m "Add restart script and gitignore"
git log --onelinegit add переміщує зміну до області підготовки, тобто до списку того, що потрапить у наступний коміт. git commit записує цей список в історію як один запис. Коміт містить знімок кожного відстежуваного файлу, повідомлення, автора, часову мітку та вказівник на попередній коміт. git log --oneline виводить по одному рядку для кожного коміту; кожен рядок починається з короткого хешу, наприклад a1b2c3d. Цей хеш є назвою коміту, і майже кожна команда Git приймає його.
Пропустіть крок git add, і git commit відповість no changes added to commit (use "git add" and/or "git commit -a"). Нічого не зламано. Git повідомляє, що область підготовки порожня, тому немає нічого для створення знімка. git status — це команда, яку слід запускати щоразу, коли ви не знаєте, що робити: вона показує поточну гілку, підготовлені зміни та файли, які Git бачить, але не відстежує.
Гілки: друга лінія історії
Гілка — це змінний вказівник на коміт. main — це гілка, і в Git вона нічим не відрізняється від інших гілок. Її створення не потребує ресурсів, оскільки Git записує новий вказівник, а не копіює файли.
git switch -c add-backup
printf '#!/bin/sh\nrestic backup /srv\n' > backup.sh
git add backup.sh
git commit -m "Add nightly backup"
git switch main
lsПісля git switch main backup.sh немає у списку. Нічого не було видалено. Файл існує в гілці add-backup, а в main його ніколи не було, тому Git видалив його з робочого каталогу, коли ви перейшли на іншу гілку. Одного разу це дивує кожного. git switch add-backup повертає файл.
Віддалені репозиторії: де нарешті з’являється GitHub
Усе дотепер виконувалося на одному комп’ютері, без мережі. Віддалений репозиторій — це URL-адреса з назвою для іншої копії того самого репозиторію. GitHub розміщує одну з таких копій для вас. Стандартна назва основного remote — origin.
Створіть порожній репозиторій через вебсайт GitHub, а потім підключіть його. У цьому випадку краще використовувати SSH замість HTTPS: SSH key — це файл під вашим контролем, і він не втрачає чинність так, як personal access token.
ssh-keygen -t ed25519 -C "vps-deploy"
cat ~/.ssh/id_ed25519.pub
ssh -T git@github.comВставте надрукований public key на сторінці SSH keys у своєму обліковому записі GitHub, а потім повторно виконайте перевірку. Робочий ключ відповідає Hi yourname! You've successfully authenticated, but GitHub does not provide shell access.. GitHub не надає вам shell, тому така відмова означає успішну перевірку. git@github.com: Permission denied (publickey). означає, що ваш ключ не було передано або його не прийнято. Перевірте, що вставили файл .pub, а не private key поруч із ним.
git remote add origin git@github.com:yourname/vps-deploy.git
git push -u origin maingit push надсилає ваші коміти до remote. -u записує, що локальний main відстежує віддалений main, тому надалі достатньо виконати git push без додаткових параметрів. git clone <url> — зворотна операція на новому комп’ютері: вона копіює весь репозиторій разом з історією та налаштовує origin. HTTPS remote також працює. Він використовує той самий протокол, що й будь-яка вебсторінка, тому підходить для мереж, які блокують вихідний порт 22. Якщо це потребує пояснення, у матеріалі з чого насправді складається HTTP-запит описано принцип роботи.
Pull requests, issues і forks: складові GitHub, а не Git
Усе описане вище належить до Git і працює з будь-яким сервером. Три наведені нижче поняття є функціями GitHub. Інші хостинги їх копіюють, а сам Git про них нічого не знає.
Pull request (PR) — це запит на злиття однієї гілки з іншою, оформлений на сторінці для обговорення. Ви надсилаєте add-backup, відкриваєте PR до main, і сайт показує відмінності commit за commit. Користувачі коментують окремі рядки. Автоматизовані перевірки повідомляють, чи пройшла перевірка гілки. Після натискання кнопки merge GitHub виконує злиття у власній копії, а потім оновлює main. Назва походить від початкового процесу, у якому ви просили супроводжувача pull вашу гілку до своєї.
Issue — це пронумерований ланцюжок повідомлень про помилку або завдання. Він зберігається в базі даних GitHub, а не у вашому репозиторії. Це важливо врахувати перед вибором хостингу: після клонування репозиторію ви маєте всі commit, але не маєте жодного issue. Щоб отримати issue, потрібно викликати API.
Fork — це власна серверна копія чужого репозиторію. Ви маєте доступ на запис до цієї копії, надсилаєте до неї гілку і відкриваєте pull request зі своєї копії до оригіналу. Так ви можете робити внесок у проєкт, супроводжувачі якого раніше про вас не чули. Fork — це clone, який зберігається на GitHub і пам’ятає своє джерело.
Програмне забезпечення працює з усіма трьома об’єктами через той самий API, який використовує користувач. Агент перевірки pull request, якого ви запускаєте на власному сервері, стежить за новими PR, читає diff і публікує коментарі до рядків. Такі правила, як файл AGENTS.md у корені репозиторію, існують тому, що тепер репозиторій читають не лише люди, а й інструменти.
Що GitHub насправді робить для власника VPS
Почніть зі зберігання за межами сервера. Скрипти розгортання та playbook-файли мають зберігатися не на сервері, який вони налаштовують. Створіть VPS із нового образу, клонувати репозиторій і запустіть розгортання. Зробіть цей репозиторій приватним і надайте серверу deploy key: SSH-ключ, зареєстрований для одного репозиторію, а не для всього облікового запису, з правами лише на читання. Витік ключа лише для читання розкриває один репозиторій. Витік ключа облікового запису розкриває все, до чого ви маєте право на запис.
sudo git clone git@github.com:yourname/vps-deploy.git /srv/vps-deploy
cd /srv/vps-deploy
git pull --ff-only--ff-only відмовляється створювати merge commit. На сервері, який лише отримує зміни, merge завжди є помилкою, тому цей прапорець перетворює незрозумілу історію на однозначну помилку fatal: Not possible to fast-forward, aborting.. На сервері змінилося щось, чого там не повинно бути. Знайдіть причину, перш ніж знову виконувати pull.
Клонування від імені root із подальшим запуском Git від імені іншого користувача призводить до fatal: detected dubious ownership in repository at '/srv/vps-deploy'. Git відмовляється читати репозиторій, власником якого є інший користувач, оскільки шкідливий .git/config може змусити Git виконати команди. Виправте власника за допомогою chown, а не додавайте виняток safe.directory, оскільки виняток вимикає перевірку, але не усуває причину.
GitHub Actions: конвеєри збирання та розгортання
Actions — це система CI/CD GitHub (безперервна інтеграція та безперервна доставка). Додайте YAML-файл у .github/workflows/, і GitHub запустить його, коли відбудеться вказана вами подія.
name: check
on:
push:
branches: [main]
jobs:
shellcheck:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- run: sudo apt-get update && sudo apt-get install -y shellcheck
- run: shellcheck *.shФайл є workflow. Job виконується на одній машині. Step — це одна команда або одна опублікована action. uses: підключає action з іншого репозиторію, а @v7 фіксує її основну версію (v7 є поточною для actions/checkout станом на August 2026). Завжди фіксуйте версію, оскільки невказана версія action означає, що запускається код, якого ви не перевіряли, з доступом до ваших секретів.
runs-on: ubuntu-latest запитує для GitHub нову віртуальну машину, яку видаляють після завершення job. Стандартні runner безкоштовні в публічних репозиторіях, а безкоштовний план станом на August 2026 включає 2,000 хвилин на місяць для приватних репозиторіїв. Перш ніж планувати бюджет на основі цієї цифри, перевірте актуальну сторінку з цінами.
Секрети зберігаються в налаштуваннях репозиторію та читаються як ${{ secrets.DEPLOY_KEY }}. Workflow, запущений pull request із fork, отримує токен лише для читання і не має доступу до цих секретів, оскільки інакше стороння особа могла б відкрити PR, єдиним завданням якого було б вивести їх.
Запуск Actions runner на власному VPS
runs-on: self-hosted передає завдання на машину, якою ви керуєте, замість GitHub-hosted runner. На сторінці налаштувань runner репозиторію відображаються рядок завантаження, веб-адреса репозиторію та реєстраційний токен, дійсний протягом однієї години. Вставте останні два значення в REPO_URL і RUNNER_TOKEN, після чого налаштування зводиться до трьох команд.
./config.sh --url "$REPO_URL" --token "$RUNNER_TOKEN"
sudo ./svc.sh install
sudo ./svc.sh start
./svc.sh statussvc.sh status має показати, що сервіс активний, а також останні рядки журналу. Runner відкриває вихідне HTTPS-з’єднання з GitHub і запитує завдання, тому відкривати для нього вхідний порт не потрібно. svc.sh install створює unit systemd. Саме цей крок часто пропускають: без нього runner завершує роботу разом із SSH-сеансом, а кожне наступне завдання залишається в черзі без пояснення. У матеріалі повне налаштування self-hosted runner на VPS описано hardening і очищення, необхідні для runner, який працює тривалий час.
Перевага в тому, що для розгортання більше не потрібен вхідний SSH-ключ, доступний з інтернету, оскільки завдання вже виконується на цьому сервері. Кеш збірки також зберігається між запусками, а лічильник хвилин не використовується.
Одне застереження є обов’язковим. Власна документація GitHub рекомендує використовувати self-hosted runners лише для приватних репозиторіїв, оскільки fork публічного репозиторію може виконати небезпечний код на вашому runner, відкривши pull request. Runner виконує все, що вказано у workflow-файлі цієї гілки. У приватному репозиторії, де ви контролюєте, хто може виконувати push, ризик невеликий. У публічному репозиторії вважайте будь-який self-hosted runner машиною, на якій сторонні особи можуть виконувати код.
Чи потрібен вам GitHub узагалі?
Ні. Git — стандарт, а GitHub — зручний сервіс. Forgejo і Gitea — self-hosted forge-системи; forge — це Git-хост із прикріпленими issues і pull requests. Обидві постачаються як один Go-бінарний файл і працюють на невеликому VPS. Forgejo — це fork Gitea від 2022 року, який тепер забезпечує роботу Codeberg. Перенесення репозиторію виконується однією командою, оскільки wire protocol ідентичний.
git remote -v
git remote set-url origin git@git.example.com:you/vps-deploy.git
git push origin mainПереноситься кожен commit, оскільки кожен clone вже містить повну історію. Не переноситься рівень, який GitHub додав поверх Git: issues і обговорення в pull requests. CI також не переноситься. Forgejo має власну реалізацію Actions, яка читає подібний YAML із .forgejo/workflows/. У документації прямо зазначено обмеження: GitHub Actions і Forgejo Actions — не одне й те саме, тому деякі компоненти можуть не запрацювати одразу. Forgejo також потребує власного runner. Плануйте цей крок як port, а не як копіювання.
Чесна причина, через яку більшість проєктів залишаються на GitHub, — це contributors. Публічний код має розміщуватися там, де користувачі вже мають обліковий запис. Ваші приватні deploy-скрипти — ні. Це два окремі рішення, і ви можете відповісти на них по-різному.
Що ламається першим і що означає помилка
Відхилено push. Ви бачите таке:
! [rejected] main -> main (fetch first)
error: failed to push some refs to 'github.com:yourname/vps-deploy.git'
hint: Updates were rejected because the remote contains work that you do
hint: not have locally.Після вашого останнього pull було виконано push, часто — змін, які ви внесли у вебредакторі. Виконайте git pull --rebase, щоб відтворити ваші коміти поверх їхніх, а потім повторіть push. Не використовуйте git push --force у спільній гілці, оскільки ця команда вилучає інші коміти з цієї гілки на сервері.
fatal: refusing to merge unrelated histories. Ви локально виконали git init і водночас дозволили GitHub створити репозиторій із README. Історії не мають спільного коміту, тому Git не може визначити потрібну дію автоматично. Найпростіше рішення — клонувати копію з GitHub у нову папку та перемістити в неї свої файли.
error: src refspec main does not match any. Гілки, яку ви вказали, тут не існує. Зазвичай репозиторій ще не має комітів або ваша гілка називається master. Команда git branch --show-current допоможе визначити причину.
Секрет потрапив до коміту. Негайно відкличте або замініть облікові дані. Вважайте їх загальнодоступними від моменту push, оскільки форки, дзеркала й кешовані копії містять дані, які ви не можете видалити.
FAQ
Чи є GitHub тим самим, що й Git?
Ні. Git — це програма керування версіями, яку встановлюють на машині. Вона працює без мережі та облікового запису. GitHub — це комерційний hosted-сервіс, який зберігає Git-репозиторії та додає до них вебінтерфейс, issues, pull requests і CI. Git випустили у 2005 році, а GitHub запустили у 2008 році на його основі. Git можна використовувати необмежено довго без GitHub. Кожна функція GitHub працює поверх Git.
Чи потрібен обліковий запис GitHub, щоб використовувати Git на моєму VPS?
Ні. git init, git commit і git log працюють на сервері навіть без налаштованого remote. Цього вже достатньо, щоб відстежувати зміни у файлах /etc або в скриптах розгортання. Обліковий запис стає корисним, коли потрібна копія історії, яка збережеться після відмови сервера, або друга машина, з якої можна виконати clone. Self-hosted forge, як-от Forgejo і Gitea, забезпечують таку саму можливість на обладнанні, яким ви володієте. Також можна використовувати звичайний SSH remote, що вказує на bare-репозиторій на іншій машині, без будь-якого forge-програмного забезпечення.
Що таке pull request?
Pull request — це запит на злиття однієї гілки з іншою, до якого додається сторінка обговорення. Ви передаєте гілку на remote, відкриваєте PR для main, а хост показує зміни commit за commit. Рецензенти можуть залишати коментарі до окремих рядків, а автоматизовані перевірки повідомляють про успішне або неуспішне виконання. Це функція GitHub, а не Git, тому в самому Git немає команди для її створення. Інші хости реалізують ту саму ідею, іноді називаючи її merge request.
Чи варто запускати runner GitHub Actions на власному VPS?
Для приватного репозиторію часто так. Задача виконується на обладнанні, за яке ви вже платите. Хвилини виконання не тарифікуються. Кеш збірки залишається прогрітим. Розгортанню більше не потрібен вхідний SSH-ключ, відкритий для інтернету, оскільки runner сам встановлює вихідне з’єднання з GitHub і запитує роботу. Для публічного репозиторію GitHub не рекомендує такий підхід. Будь-хто може зробити fork вашого репозиторію й відкрити pull request, workflow якого запустить код на вашій машині.
Чи можна пізніше перенести репозиторії з GitHub?
Код — так, без проблем. Кожен clone містить повну історію, тому git remote set-url origin <new url>, а потім push переносить усе, що містить commit. Залишається лише рівень, яким керує GitHub: issues, обговорення pull request і історія Actions зберігаються в його базі даних, а не у вашій папці .git. Інструменти міграції можуть копіювати issues через API, а файли workflow зазвичай потрібно відредагувати для CI нового хоста. Це варто враховувати й зберігати справжню документацію в репозиторії, а не в обговореннях issues.