Персональна освітня сорінка
by Pavlo Shcherbukha
Зацікавило питання як на своєму комп’ютері налаштувати локальний і віддалений репозиторії (типу резервний зробити). Ну, не завжди хочеться засмічувати GitHub якимись тестами своїми. З іншого боку, хочеться використати звичні інструменти для архівування та відгалужування коду.
Налаштування віддаленого репозиторія на локальній машині
1.1. Створення bare repository:
Створення нової папку, наприклад, my_project.git, і перейти у неї в терміналі.
$ mkdir /path/to/my_project.git
$ cd /path/to/my_project.git
$ git init --bare
Bare repository відрізняється від звичайного тим, що він не має робочої директорії з файлами проєкту. Він містить лише внутрішні дані Git, такі як історія коммітів, гілки та теги (тобто, лише вміст папки .git). Такий репозиторій ідеально підходить для використання як “центральне сховище”, з якого розробники будуть завантажувати й надсилати зміни. Зазвичай такі репозиторії називають з суфіксом .git, щоб підкреслити їхню “бездротову” природу.
1.2. Створення локального репозиторію:
Створіть робочу папку для вашого проєкту. Якщо у вас вже є проєкт, просто перейдіть у його директорію.
$ mkdir /path/to/my_project
$ cd /path/to/my_project
$ git init
1.3. Прив’язка локального репозиторію до bare:
Тепер, коли у вас є локальний репозиторій, додайте ваш bare repository як віддалений. Зазвичай йому дають назву origin за замовчуванням.
$ git remote add origin /path/to/my_project.git
1.4. Перший push:
Додайте файли у свій локальний репозиторій, зробіть перший комміт, а потім надішліть (push) його у віддалений (bare) репозиторій.
$ touch README.md
$ git add README.md
$ git commit -m "Initial commit"
$ git push -u origin master
Тепер можна працювати з локальним репозиторієм, робити комміти та періодично синхронізувати його з вашим “бекапом” за допомогою команд git push та git pull. Це дозволить мати повну історію версій і локальний “бекап” без використання сторонніх сервісів.
А якщо bear репозиторій розмістити на іншій машині. Як між ними організувати спілкування?
Для того, щоб це працювало, потрібно налаштувати доступ по SSH між вашим комп’ютером (client) і машиною, де буде розміщено bare repository (server).
2.1. На машині-сервері (server):
Створити користувача Git (наприклад, git), який буде керувати репозиторіями. У домашній директорії цього користувача створити папку з вашим bare repository:
$ mkdir my_project.git
$ cd my_project.git
$ git init --bare
2.2. На машині-клієнті (client):
Створити пару SSH-ключів. Публічний ключ (id_rsa.pub) потрібно скопіювати на сервер в файл ~/.ssh/authorized_keys користувача git. Додати віддалений репозиторій до локального проекту, використовуючи SSH-адресу:
$ git remote add origin ssh://git@<IP_адреса_сервера>/path/to/my_project.git
2.3. Тепер можна надіслати (push) зміни на сервер:
$ git push origin master
Як для мене, то прийнятне рішення для особистих проектів, що потребують локального бекапу та синхронізації між кількома пристроями.
## 3. Деякі команди git, що використовую
### 3.1. Отримати красивий лог змін
git log --pretty=format:"%h - %an, %ar : %s" --since=2.weeks
f4a2b1c - Jane Doe, 3 days ago : Fix critical bug in user authentication
a9b8c7d - John Smith, 5 days ago : Add feature for data export
e6f5g4h - Jane Doe, 1 week ago : Refactor payment processing module
%h: Відображає короткий commit hash.
%an: Відображає ім’я автора.
%ar: Відображає відносний час від поточної дати ( “2 days ago”, “5 hours ago”).
%s: Відображає перший рядок commit message.
–since=2.weeks: Вказує на проміжок часу (останні 2 тажні) за який відрображати лог.
Відносні проміжки часу
Можна використовувати різні одиниці виміру часу.
Секунди, хвилини, години, дні:
--since=30.minutes (за останні 30 хвилин)
--since=12.hours (за останні 12 годин)
--since=10.days (за останні 10 днів)
Місяці та роки:
--since=3.months (за останні 3 місяці)
--since=1.year (за останній рік)
Комбіновані вирази: Ви можете поєднувати різні одиниці.
--since="1.month 2.days ago" (місяць і два дні тому)
Звісно! Git надає багато гнучких способів для фільтрації комітів за часом. Ось основні альтернативи та доповнення до –since=2.weeks.
Відносні проміжки часу
Ви можете використовувати різні одиниці виміру часу.
Секунди, хвилини, години, дні:
--since=30.minutes (за останні 30 хвилин)
--since=12.hours (за останні 12 годин)
--since=10.days (за останні 10 днів)
Місяці та роки:
--since=3.months (за останні 3 місяці)
--since=1.year (за останній рік)
Комбіновані вирази: Ви можете поєднувати різні одиниці.
--since="1.month 2.days ago" (місяць і два дні тому)
Конкретні дати та час
Можна вказувати точні дати у різних форматах.
Формат YYYY-MM-DD:
--since=2025-09-15 (з 15 вересня 2025 року)
"Людський" формат:
--since="Sep 15 2025"
--since="yesterday" (за вчора і сьогодні)
--since="10:00" (від сьогоднішнього ранку о 10:00)
--since="2025-09-20 10:00:00" (точна дата і час)
git log -- ./iib_app_srvc/post_storedocument_ProcessInput.esql
git log -- ./iib_app_srvc/
commit d80c6a82e28693fb46c09664a453d0c8ded3a3ee Author: pasha pasha@mail.com Date: Mon Nov 25 18:14:02 2024 +0200
Future 1
commit 89d350b3214aaf1883dfe9a0f31286111fb9f4a4 Author: pasha pasha@mail.com Date: Mon Nov 25 07:19:42 2024 +0200
Fix 22 added new field check
### <a name="p3.3">3.3. Які зміни в файли внесені у вказаному комміті</a>
```bash
git show b0f8d8f83a1bfc7f2dbfb9560e0423e13e6c243b
git show b0f8d8f83a1bfc7f2dbfb9560e0423e13e6c243b
commit b0f8d8f83a1bfc7f2dbfb9560e0423e13e6c243b
Author: pasha <pasha@mail.com>
Date: Sat Sep 20 20:39:42 2025 +0300
az-29
diff --git a/function_app.py b/function_app.py
index a73266f..f57a20f 100644
--- a/function_app.py
+++ b/function_app.py
@@ -40,7 +40,7 @@ async def hello_orchestration_starter(req: func.HttpRequest, client: df.DurableO
# Start the orchestration and return a status response
try:
- logging.info(f" Starting orchestration with blob name = {blob_name}")
+ #logging.info(f" Starting orchestration with blob name = {blob_name}")
#, client_input={"name": blob_name}
instance_id = await client.start_new(function_name)
response = client.create_check_status_response(req, instance_id)
@@ -77,7 +77,7 @@ def hello_orchestration_orchestrator(context: df.DurableOrchestrationContext):
result1 = yield context.call_activity("hello_orchestration_activity", "Seattle")
result2 = yield context.call_activity("hello_orchestration_activity", "Tokyo")
result3 = yield context.call_activity("hello_orchestration_activity", "London")
- result4 = yield context.call_activity("video_orchestration_activity", 'blob_name')
+ result4 = yield context.call_activity("video_orchestration_activity", "blob_name")
logging.info(f"Orchestration completed with results: {[result1, result2, result3, result4]}")
Перед виконанням треба закоммітити останні зміни, або зробити git stash. Пілся виконання закоммічені зміни відправити в віддалений репозиторій використовуючи git push.
git fetch origin
git rabase
git fetch + git rebase
Це двокроковий процес, який дає більше контролю і створює чистішу історію.
git fetch: завантажує зміни з віддаленого репозиторію, не торкаючись робочої гілки. Ви можете переглянути зміни (git log origin/main), перш ніж їх застосовувати.
git rebase: Ця команда бере унікальні локальні коміти (ті, що зробили, але ще не відправили на сервер), "відкладає" їх убік, оновлює локальну гілку до останньої версії з сервера, а потім застосовує локальні коміти один за одним поверх цих оновлень.
Результат: Історія комітів залишається лінійною, без зайвих коммітів злиття. Виглядає так, ніби ви почали свою роботу вже після того, як ваш колега вніс свої зміни. Це “переписує” історію ваших локальних комітів (вони отримують нові хеші).
Аналогія: Ви написали свою частину документа. Потім побачили, що колега вже вніс зміни в основний документ. Ви берете свої правки, “вирізаєте” їх, оновлюєте основний документ до версії колеги, а потім “вставляєте” свої правки вже в оновлену версію.
Команда git pull –rebase є скороченням для послідовності git fetch + git rebase.
git pull
або, якщо ви в гілці tz01 то
git fetch
git merge origin/tz01
Уявимо собі ситуацію, коли ви парцюєте віддалено (з різних причин), але вам необхідно передавати свої зміни в ізольовану мережу клієнта, де в нього стоїть якийсь локальний gitlab чи навіть не локальний, але ви прямого доступу до нього не маєте і можете принести флешку і потім щось з нею робити. А увіть, що ви працюєете постійно над проектом і вам це треба робити реугярно.
Використання патчів — це чудовий спосіб переносити зміни між ізольованими середовищами («air-gapped» чи просто різними мережами), де немає прямого зв’язку між репозиторіями.
В git є два основних підходи: git format-patch (створює текстові файли змін) та git bundle (створює один бінарний файл, який Git сприймає як повноцінний віддалений репозиторій). На постійній основі, bundle набагато зручніший. Потрібно створити один файл, який для Git виглядає як “remote”. Це надійніше, ніж патчі, бо передається вся історія та об’єкти.
Працює це таким чином.
Створити файл, що містить стан вашої гілки (наприклад, develop або main):
1.1. Переше оновлення
git bundle create transport.bundle main
Наступного разу ви зможете створювати інкрементальні бандли (тільки нові коміти), але для початку краще брати всю гілку.
1.2. Наступні оновлення (Інкрементальні)
Щоб не тягати щоразу всю історію (коли проект розростеться), ви зможете створювати бандл лише з новими змінами. Наприклад, від останнього переданого тегу або коміту:
# Створити бандл тільки з новими комітами після версії v1.0
git bundle create incremental.bundle v1.0..main
В обох випадках створиться файл: transport.bundle
Переносити можемо через флешку, поштою, по ssh. Тобто, сам метод доставки не важливий. Важливо, щоб цей файл з’явився на машині в клієнтському перименті.
3.1. Простий процес
Перевірит файл:
git bundle verify transport.bundle
Підтягти зміни прямо з файлу:
git pull transport.bundle main
Коли ви робите git pull з бандлу на клієнтській машині, Git сприймає файл як тимчасове джерело. Якщо ви хочете, щоб клієнтський репозиторій “знав” про ваш локальний як про постійний remote, можна прописати шлях до файлу в конфігурації.
Коли на клієнтській машині ще взагалі немає цього проекту, можна зробити clone прямо з файлу:
git clone transport.bundle my-project
В результаті Git створить папку my-project, розпакує туди всі коміти та налаштує гілку.
3.2. Складний але більш надійний і процесний підхід.
Нагадаю Коли ви робите git pull з бандлу на клієнтській машині, Git сприймає файл як тимчасове джерело. Якщо ви хочете, щоб клієнтський репозиторій “знав” про ваш локальний як про постійний remote, можна прописати шлях до файлу в конфігурації.
3.2.1. Готуємо конфігурацію, для постійного remote, куди будемо класти файли transport.bundle.
git remote add dev-machine /шлях/до/transport.bundle
git fetch dev-machine
Тут треба розуміти, що коли налаштовуємо:
git remote add dev-machine /шлях/до/transport.bundle
Це не видалить уже існуючий origin до GitLab. Просто з’явиться ще одне джерело (alias). Можна побачити обидва, виконавши git remote -v:
origin — буде вказувати на GitLab.
dev-machine — буде вказувати на ваш файл-бандл.
3.2.2. Оновлення bandle
Коли ви приносите новий файл transport.bundle на клієнтську машину і кладете його за тим самим шляхом, вам не потрібно знову додавати remote. Просто отримуємо зміни:
git fetch dev-machine
Git прочитає файл і оновить локальну копію гілки (наприклад, dev-machine/main).
3.2.3. Злиття (Merge) зміни в робочу гілку:
git merge dev-machine/main
3.2.4. Відправка в GitLab
git push origin main
Ідея з “remote як каталог” дуже зручна, тому, що перетворює файл бандлу на повноцінне джерело даних. Git сам відстежує, які коміти є в бандлі, а яких ще немає у вашому проекті. Якщо ви будете постійно переносити зміни, зручно зберігати бандл в одній і тій самій папці з одним і тим самим ім’ям. Тоді команда git fetch dev-machine завжди буде працювати автоматично, як тільки ви заміните старий файл новим.
Використання Python для автоматизації цього процесу — логічний крок, що дозволить уникнути помилок у написанні хешів або тегів вручну.
Ось концепт скрипта, який використовувати як внутрішній інструмент. Цей скрипт автоматично визначає останній створений бандл (або тег) і генерує новий інкрементальний файл.
import subprocess
import datetime
def create_git_bundle(branch="main", last_tag=None):
# Генеруємо ім'я файлу з поточною датою
date_str = datetime.datetime.now().strftime("%Y-%m-%d")
filename = f"transport_{date_str}.bundle"
if last_tag:
# Інкрементальний бандл: від тегу до вершини гілки
command = ["git", "bundle", "create", filename, f"{last_tag}..{branch}"]
else:
# Повний бандл
command = ["git", "bundle", "create", filename, branch]
try:
result = subprocess.run(command, check=True, capture_output=True, text=True)
print(f"✅ Бандл створено: {filename}")
return filename
except subprocess.CalledProcessError as e:
print(f"❌ Помилка: {e.stderr}")
return None
# Використання
# create_git_bundle("main", "v1.0.2")
Мінімізація помилок: Скрипт може сам перевіряти git describe –tags –abbrev=0, щоб знайти останній тег і автоматично підставити його в команду бандлу.
Гнучкість: Ви можете розширити його, щоб він автоматично копіював створений файл на мережевий диск або флешку, щойно вона буде підключена.
Простота: Це перетворює “складну операцію в консолі” на запуск однієї команди python make_bundle.py.
Скрипт робить дві речі: перевіряє цілісність самого файлу (git bundle verify) та звіряє контрольні суми (SHA-256), щоб гарантувати, що антивірус не “відкусив” шматок файлу під час копіювання. Сам скрипт слугує “приймальним шлюзом” для всіх ваших майбутніх бандлів.
import hashlib
import subprocess
import os
def verify_and_fetch(bundle_path, remote_name="dev-machine"):
# 1. Перевірка наявності файлу
if not os.path.exists(bundle_path):
print(f"❌ Файл {bundle_path} не знайдено!")
return
# 2. Перевірка через Git (внутрішня цілісність об'єктів)
print(f"🔍 Перевірка Git-структури {bundle_path}...")
check = subprocess.run(["git", "bundle", "verify", bundle_path],
capture_output=True, text=True)
if check.returncode != 0:
print(f"❌ Git-бандл пошкоджено або не сумісний!\n{check.stderr}")
return
# 3. Оновлення репозиторію
print(f"🚀 Оновлення з {bundle_path}...")
try:
# Оновлюємо remote, який вказує на цей файл
subprocess.run(["git", "fetch", remote_name], check=True)
print("✅ Успішно! Тепер можна виконувати 'git merge dev-machine/main'")
except subprocess.CalledProcessError:
print("❌ Помилка під час git fetch. Перевірте шлях у git remote.")
# Використання
# verify_and_fetch("transport.bundle")
Чому цей скрипт важливий:
Захист від “битих” файлів: Якщо флешка збоїть або антивірус змінить вміст бандлу, скрипт зупинить процес до того, як ви спробуєте влити зміни в основний код.
Завершене архітектурне рішення: Це виглядає як завершене архітектурне рішення від розробки до безпечного постачання (Delivery).
Клієнту не потрібно знати команди Git: Це дає йому скрипт, який каже “Все ОК” або “Файл пошкоджено”.
Це фактично реалізація CI/CD для ізольованих мереж:
Це фактично реалізація CI/CD для ізольованих мереж. На Python, такі скрипти стануть органічним продовженням екосистеми інструментів в парі з аналізом логів в Jupyter notebook.
Для критичних систем рекомендується генерувати окремий файл .sha256 разом із бандлом для зовнішньої перевірки цілісності перед відкриттям у Git
3.7. Як створити повністю автономний архів git репозиторіїв
На випадок активних бойових дій чи проблем з електропостачанням чи інтернетом використання git bundle — це один із найідеальніших і найнадійніших способів створити повністю автономний резервний архів Git-репозиторію. Поряд іде створення замкнутого локального середовища розробки, що відірване від корпоративного, але це більш широка тема. А опреації з git репозиторіями це є один з важливих кроків.
На відміну від звичайного git clone чи розархівованого робочого каталогу, .bundle файл має кілька критичних переваг саме для сценаріїв кризового резервування:
Повна автономність (Single File): Уся історія коммітів, усі гілки (branches), теги (tags) та refs пакуються в один бінарний файл. Його зручно шифрувати, копіювати на флешку чи зберігати в хмарі.
Збереження структури Git: Це не просто ZIP-архів із сирцевим кодом (без історії), а повноцінний Git-архів. З нього можна відновлювати репозиторій звичайною командою git clone repo.bundle.
Відсутність залежності від мережі та сервера: Для розпакування чи роботи з історією вам не потрібен доступ до корпоративного GitLab чи VPN.
Практичні команди для створення бекапу
Щоб бекап був максимально повним (з усіма віддаленими гілками та тегами), рекомендується виконувати пакування з прапором –all.
Перед створенням бандлу обов’язково викачайте всі останні зміни та гілки з сервера:
# Fetch усіх гілок та тегів з віддаленого сервера
git fetch --all --prune
# Створення єдиного bundle-файлу з усією історією та гілками
git bundle create my-project-backup.bundle --all
Після створення обов’язково перевірте, чи файл не пошкоджений і чи читається він інструментами Git:
git bundle verify my-project-backup.bundle
Відновити проект з бандлу можна так само легко, як і з віддаленого URL:
git clone my-project-backup.bundle my-restored-project
GitLab Merge Requests та Issues: git bundle зберігає тільки Git-дані (код, гілки, комміти, теги). Він не зберігає:
Опис Merge Requests та коментарі до них.
GitLab Issues, Wiki (якщо вона не викачана як окремий git-репозиторій).
Налаштування CI/CD pipelines та змінні оточення (CI/CD Variables).
Якщо ця інформація критична, завантажте додатково Wiki (вона є окремим Git-репозиторієм в GitLab) або скористайтеся GitLab API / експортом проекту через Web UI (Settings -> General -> Advanced -> Export project).
Безпека: Корпоративний код — це конфідеційна інформація. Зберігайте підготовлені .bundle файли у зашифрованому вигляді (наприклад, за допомогою GPG, 7-Zip із шифруванням AES-256 або у сховищі VeraCrypt).
$giturl = "http://gitlab-host.corporate.ua/DEV_PROJECTS"
$gitproject = "flask-web_app"
New-Item -ItemType Directory -Path ".\$gitproject" -Force
Set-Location ".\$gitproject"
git clone "$giturl/$gitproject.git" .
# Fetch усіх гілок та тегів з віддаленого сервера
git fetch --all --prune
# Створення єдиного bundle-файлу з усією історією та гілками
git bundle create "$gitproject-backup.bundle" --all
# Перевірка цілісноті bandle файлу
git bundle verify "$gitproject-backup.bundle"
Set-Location ..
projects.txt
Node-Red-APP1
Node-Red-APP2
$giturl = "http://gitlab-host.corporate.ua/NODE-RED_PROJECTS"
$projectsFile = ".\projects.txt"
if (Test-Path $projectsFile) {
Get-Content $projectsFile | Where-Object { $_.Trim() -ne "" } | ForEach-Object {
$gitproject = $_.Trim()
Write-Host "`n=== Processing project: $gitproject ===" -ForegroundColor Cyan
# Створюємо папку та переходимо в неї
New-Item -ItemType Directory -Path ".\$gitproject" -Force | Out-Null
Set-Location ".\$gitproject"
# Клонуємо, підтягуємо гілки та робимо бандл
git clone "$giturl/$gitproject.git" .
git fetch --all --prune
$bundleFile = "$gitproject-backup.bundle"
git bundle create $bundleFile --all
git bundle verify $bundleFile
# Повертаємося у вихідну директорію
Set-Location ..
}
} else {
Write-Error "Файл $projectsFile не знайдено!"
}
Якщо не хочеться створювати окремий файл, можна задати перелік проектів прямо в змінній-масиві $projects:
$giturl = "http://gitlab-host.corporate.ua/NODE-RED_PROJECTS"
$projects = @(
"NODE-RED-APP1",
"NODE-RED-APP2",
"NODE-RED-APP3"
)
foreach ($gitproject in $projects) {
Write-Host "`n=== Processing project: $gitproject ===" -ForegroundColor Cyan
New-Item -ItemType Directory -Path ".\$gitproject" -Force | Out-Null
Set-Location ".\$gitproject"
git clone "$giturl/$gitproject.git" .
git fetch --all --prune
$bundleFile = "$gitproject-backup.bundle"
git bundle create $bundleFile --all
git bundle verify $bundleFile
Set-Location ..
}
Якщо у вас на робочій машині в одній директорії лежить декілька робочих репозиторіїв, їх можна забандлити всі разом за допомогою одного PowerShell-однорядка.
Цей скрипт пройдеться по всіх підпапках, перевірить наявність .git, оновлює дані та збереже готові .bundle файли на рівень вище.
Get-ChildItem -Directory | Where-Object { Test-Path "$($_.FullName)\.git" } | ForEach-Object {
Set-Location $_.FullName
Write-Host "Backing up $($_.Name)..." -ForegroundColor Green
git fetch --all --prune
$bundlePath = "..\$($_.Name)-$(Get-Date -Format 'yyyy-MM-dd').bundle"
git bundle create $bundlePath --all
git bundle verify $bundlePath
}
# Створення зашифрованого AES-256 ZIP-архіву через 7-Zip (якщо встановлено 7-Zip CLI)
7z a -tzip -p"ВашНадійнийПароль" -mem=AES256 "git-backups-$date.zip" *.bundle
Оскільки ви завантажили репозиторії через .bundle, пам’ятайте, що ви так само можете робити комміти локально, а потім пакувати ваші нові робочі гілки назад у bundle для переносу на корпоративну машину:
# Створити бандл тільки з вашою новою фіча-гілкою
git bundle create my-feature.bundle feature/my-new-code
Після чого на робочій машині робиться звичайний git pull my-feature.bundle feature/my-new-code.
Автономні залежності:
Якщо ви використовуєте локальні контейнери (Docker / K3s / Podman), намагайтеся експортувати та зберігати локально базові Docker-образи (docker save -o image.tar image:tag), а також локальні кеші пакетів (PyPI wheels, npm cache тощо), щоб при відсутності інтернету не впиратися у відсутність якоїсь бібліотеки.
Безпека локального контуру: Оскільки вимоги щодо безпеки діють і тут, головне — тримати локальний диск або бакапи зашифрованими (BitLocker / VeraCrypt) та випадково не закоммітити в зовнішній чи особистий Git якісь корпоративні проди/секрети/сертифікати.
Автономність і можливість безперервно працювати в умовах нестабільного живлення та зв’язку зараз цінується значно більше, ніж суворе слідування бюрократичним регламентам, які писалися для мирного часу і стабільного офісу.
Як на мій погляд є суттєва проблема: .gitignore чудово захищає від витоку секретів у загальний репозиторій, але під час кризового перенесення робить локальні конфіги найвразливішими. При зміні машини чи відновленні середовища з нуля саме пошук втрачених .env-файлів, docker-compose.override.yml та сертифікатів забирає найбільше часу.
Щоб не порушувати гигієну розробки (не коммітити .env у Git) і водночас не втрачати локальне оточення, є кілька практик.
Зберігайте в Git не самі секрети, а повну структуру конфігів з безпечними значеннями за замовчуванням:
Коммітьте цей файл у Git. У ньому мають бути всі змінні оточення, які потрібні сервісам, але із заповненими заглушками або локальними дефолтами:
# App Settings
PORT=8080
LOG_LEVEL=debug
# Database Connection
DB_HOST=postgres-db
DB_PORT=5432
DB_NAME=dev_db
DB_USER=dev_user
DB_PASSWORD=change_me_locally
При переносi на нову машину достатньо виконати cp .env.example .env — і каркас готовий.
Якщо для локального запуску потрібні специфічні прокидання портів чи томи (volumes), створюйте шаблонний override-файл. Сам файл docker-compose.override.yml внесіть у .gitignore, а його шаблон .example коммітьте в репозиторій.
Оскільки самі .bundle файли містять лише те, що є в Git, зробіть окремий процес бекапу для не-Git файлів (все, що ігнорується):
Зберігайте всі ваші локальні .env, docker-compose.override.yml та дев-сертифікати в окремому каталозі або збирайте їх скриптом.
Пакуйте їх у один зашифрований архів (наприклад, за допомогою 7-Zip з паролем чи VeraCrypt контейнером) і переносьте разом із .bundle файлами.
PowerShell-скрипт для швидкого збору всіх .env та override.yml:
Цей скрипт знаходить усі локальні конфіги в папках проектів (ігноруючи node_modules, venv тощо) та пакує їх в один ZIP-архів:
# Збираємо всі локальні .env та docker-compose файли
$backupDir = ".\local-configs-backup"
New-Item -ItemType Directory -Path $backupDir -Force | Out-Null
Get-ChildItem -Recurse -Include ".env", ".env.local", "docker-compose.override.yml" |
Where-Object { $_.FullName -notmatch "node_modules|venv|\.git" } |
ForEach-Object {
# Зберігаємо відносний шлях, щоб знати, з якого проекту файл
$relPath = Resolve-Path -Relative $_.FullName
$safeName = $relPath -replace "^\.\\", "" -replace "\\", "_"
Copy-Item $_.FullName -Destination "$backupDir\$safeName"
}
# Пакуємо в зашифрований ZIP (якщо є 7-Zip) або звичайний Archive
Compress-Archive -Path "$backupDir\*" -DestinationPath ".\local_configs_$(Get-Date -Format 'yyyy-MM-dd').zip" -Force
Remove-Item $backupDir -Recurse -Force
Write-Host "Локальні конфіги успішно зібрані в ZIP!" -ForegroundColor Green
У docker-compose.yml можна прописати дефолтні значення для локальної розробки безпосередньо в синтаксисі файлу. Якщо змінна .env не задана, Compose візьме значення після :-:
version: '3.8'
services:
app:
build: .
ports:
- "${APP_PORT:-8080}:8080"
environment:
- DB_HOST=${DB_HOST:-postgres}
- DB_USER=${DB_USER:-postgres}
- DB_PASSWORD=${DB_PASSWORD:-postgres_dev_pass}
При такому підході файл docker-compose.yml залишається абсолютно безпечним для Git, але проект піднімається командую docker compose up навіть без наявного .env файлу.
Якщо конфігів багато і вони складні:
sops (Secrets OPerationS від Mozilla): Дозволяє зашифрувати .env файл за допомогою ключа (GPG/age) та коммітити його в Git. Ви коммітите файл .env.enc, а на будь-якій локальній машині розшифровуєте його однією командою, маючи лише один приватний ключ.
KeePass / Bitwarden / BW CLI: Зберігати локальні dev-змінні як замітки в зашифрованому менеджері паролів.
Поєднання повної структури в .env.example та окремого зашифрованого архіву з .env файлами повністю вирішує проблему втрати локального оточення під час екстреного переміщення.
tags: