Add proxy/VPN/telegram launchd and emergency runbooks; reorganize apps docs; document JA3 CrossOver runbook and Wine troubleshooting; add GOG/HoMM game scripts, disk cleanup guides, and gitea push-via-proxy helper. Ignore temp/. Co-authored-by: Cursor <cursoragent@cursor.com>
1805 lines
82 KiB
Markdown
1805 lines
82 KiB
Markdown
# Gitea Complete Guide — local_machine
|
||
|
||
> **Этот гайд** — справочник по использованию Gitea для репозитория **local_machine** (документация и скрипты локальной машины).
|
||
> Сервер: **gitea.hunab.app** (209.38.32.21).
|
||
> **Быстрый старт для local_machine:** [LOCAL_MACHINE_GITEA_SETUP.md](./LOCAL_MACHINE_GITEA_SETUP.md).
|
||
|
||
> Для других репозиториев: **legal** на 206.189.35.205 — [GITEA_LEGAL_206_SERVER_GUIDE.md](./GITEA_LEGAL_206_SERVER_GUIDE.md); **hunabapp** — свои скрипты пуша в том репо.
|
||
|
||
---
|
||
|
||
**Дата:** 2026-01-02
|
||
**Версия Gitea:** 1.25.3
|
||
**Статус:** ✅ Полностью развернут и работает
|
||
**Последнее обновление:** Адаптация под проект local_machine (2026-03-14)
|
||
|
||
---
|
||
|
||
## 📋 Обзор
|
||
|
||
Gitea успешно развернут на production сервере как self-hosted альтернатива GitHub.
|
||
|
||
### Преимущества
|
||
- ✅ Полный контроль данных (код на вашем сервере)
|
||
- ✅ Бесплатно для неограниченного числа репозиториев
|
||
- ✅ Нет лимитов на CI/CD минуты
|
||
- ✅ Низкая задержка (локальная сеть)
|
||
- ✅ Интеграция с существующей инфраструктурой
|
||
|
||
### Текущая конфигурация
|
||
- **Домен:** https://gitea.hunab.app
|
||
- **Сервер:** 209.38.32.21
|
||
- **HTTP порт:** 3000 (внутренний)
|
||
- **SSH порт:** 2223 (внешний)
|
||
- **База данных:** PostgreSQL (hunabgit) - **СТАНДАРТ**
|
||
- **SSL:** Let's Encrypt, TLSv1.2/TLSv1.3
|
||
- **Контейнер:** `gitea`
|
||
- **Сеть:** `hunab-network`
|
||
|
||
**⚠️ ВАЖНО:** PostgreSQL является стандартом для всех развертываний Gitea. MySQL и SQLite не используются.
|
||
|
||
---
|
||
|
||
## 🚀 Развертывание
|
||
|
||
### Быстрый старт для local_machine
|
||
|
||
Репозиторий **local_machine** не разворачивает Gitea — он только пушит в уже работающий сервер. Первая настройка и пуш:
|
||
|
||
```bash
|
||
cd /Users/eternal/code/local_machine
|
||
# 1. Создать репо на https://gitea.hunab.app (New Repository → local_machine)
|
||
# 2. Инициализация и пуш:
|
||
bash scripts/deployment/gitea/setup-and-push.sh
|
||
```
|
||
|
||
Подробно: **[LOCAL_MACHINE_GITEA_SETUP.md](./LOCAL_MACHINE_GITEA_SETUP.md)**.
|
||
|
||
### Развертывание самого Gitea (для админов сервера)
|
||
|
||
Скрипты развертывания Gitea на сервере находятся в других репозиториях (например hunabapp). Пример для справки:
|
||
|
||
```bash
|
||
# Развертывание Gitea (в репо с инфраструктурой)
|
||
bash scripts/deployment/gitea/deploy-gitea.sh
|
||
bash scripts/deployment/gitea/setup-gitea.sh
|
||
bash scripts/deployment/gitea/test-gitea.sh
|
||
```
|
||
|
||
### Docker Compose (для reference)
|
||
|
||
```yaml
|
||
version: "3"
|
||
services:
|
||
gitea:
|
||
image: gitea/gitea:1.25.3
|
||
container_name: gitea
|
||
restart: always
|
||
networks:
|
||
- hunab-network
|
||
ports:
|
||
- "3000:3000"
|
||
- "2223:22"
|
||
volumes:
|
||
- /opt/gitea:/data
|
||
environment:
|
||
- USER_UID=1000
|
||
- USER_GID=1000
|
||
```
|
||
|
||
---
|
||
|
||
## 🗄️ База данных PostgreSQL
|
||
|
||
**⚠️ СТАНДАРТ (ОБЯЗАТЕЛЬНО К СОБЛЮДЕНИЮ):** PostgreSQL является ЕДИНСТВЕННЫМ стандартом для всех развертываний Gitea. MySQL и SQLite ЗАПРЕЩЕНЫ.
|
||
|
||
### ✅ PostgreSQL - ОБЯЗАТЕЛЬНЫЙ СТАНДАРТ
|
||
|
||
- ✅ **Используется на основном сервере** (209.38.32.21)
|
||
- ✅ **Используется на зеркальном сервере** (206.189.35.205)
|
||
- ✅ **ОБЯЗАТЕЛЕН для всех новых развертываний**
|
||
- ✅ **ОБЯЗАТЕЛЕН для всех существующих развертываний** (миграция с MySQL/SQLite)
|
||
- ✅ Лучшая производительность для больших репозиториев
|
||
- ✅ Поддержка транзакций и ACID
|
||
- ✅ Масштабируемость и надежность
|
||
|
||
### ❌ MySQL и SQLite - ЗАПРЕЩЕНЫ
|
||
|
||
- ❌ **ЗАПРЕЩЕНО использовать MySQL** в проекте
|
||
- ❌ **ЗАПРЕЩЕНО использовать SQLite** в production
|
||
- ❌ Ошибка "dial tcp [::1]:3306" означает попытку подключения к MySQL - **НЕДОПУСТИМО**
|
||
|
||
### Стандартная конфигурация
|
||
|
||
**Основной сервер (209.38.32.21):**
|
||
```ini
|
||
[database]
|
||
DB_TYPE = postgres
|
||
HOST = hunab-prod-postgres:5432
|
||
NAME = hunabgit
|
||
USER = hunabgit
|
||
PASSWD = YOUR_PASSWORD
|
||
SSL_MODE = disable
|
||
CHARSET = utf8mb4
|
||
```
|
||
|
||
**Зеркальный сервер (206.189.35.205):**
|
||
```ini
|
||
[database]
|
||
DB_TYPE = postgres
|
||
HOST = gitea-mirror-postgres:5432
|
||
NAME = hunabgit
|
||
USER = utils # ⚠️ На зеркальном сервере используется пользователь utils
|
||
PASSWD = YOUR_PASSWORD
|
||
SSL_MODE = disable
|
||
CHARSET = utf8mb4
|
||
```
|
||
|
||
**⚠️ КРИТИЧЕСКИ ВАЖНО:**
|
||
- ❌ Параметр `PATH` ЗАПРЕЩЕН (используется только для SQLite)
|
||
- ❌ `HOST = localhost:3306` ЗАПРЕЩЕН (это MySQL порт)
|
||
- ✅ Обязательно использовать имя контейнера PostgreSQL в Docker сети
|
||
- ⚠️ **На зеркальном сервере используется пользователь `utils` вместо `hunabgit`**
|
||
|
||
### Создание пользователя utils для зеркального сервера
|
||
|
||
**Проблема:** Если пользователь `utils` не существует или имеет неправильный пароль, Gitea не сможет подключиться к PostgreSQL.
|
||
|
||
**Решение:**
|
||
|
||
#### Автоматический скрипт (рекомендуется)
|
||
|
||
```bash
|
||
# На сервере 206.189.35.205
|
||
bash scripts/deployment/fix-postgres-utils-user.sh
|
||
```
|
||
|
||
#### Ручное создание пользователя
|
||
|
||
```bash
|
||
# Определение суперпользователя PostgreSQL
|
||
POSTGRES_SUPERUSER=$(docker inspect gitea-mirror-postgres | grep -oP '(?<="POSTGRES_USER=")[^"]*' | head -1 || echo "postgres")
|
||
|
||
# Если не найден, пробуем стандартные варианты
|
||
if [ -z "$POSTGRES_SUPERUSER" ] || [ "$POSTGRES_SUPERUSER" = "null" ]; then
|
||
if docker exec gitea-mirror-postgres psql -U postgres -d postgres -c "SELECT 1;" > /dev/null 2>&1; then
|
||
POSTGRES_SUPERUSER="postgres"
|
||
elif docker exec gitea-mirror-postgres psql -U hunabgit -d postgres -c "SELECT 1;" > /dev/null 2>&1; then
|
||
POSTGRES_SUPERUSER="hunabgit"
|
||
else
|
||
POSTGRES_SUPERUSER="postgres"
|
||
fi
|
||
fi
|
||
|
||
# Создание или изменение пароля для utils
|
||
docker exec gitea-mirror-postgres psql -U $POSTGRES_SUPERUSER -d postgres << 'SQL'
|
||
DO $$
|
||
BEGIN
|
||
IF NOT EXISTS (SELECT FROM pg_user WHERE usename = 'utils') THEN
|
||
CREATE USER utils WITH PASSWORD 'YOUR_PASSWORD';
|
||
ELSE
|
||
ALTER USER utils WITH PASSWORD 'YOUR_PASSWORD';
|
||
END IF;
|
||
END
|
||
$$;
|
||
SQL
|
||
|
||
# Предоставление прав
|
||
docker exec gitea-mirror-postgres psql -U $POSTGRES_SUPERUSER -d postgres -c "GRANT ALL PRIVILEGES ON DATABASE hunabgit TO utils;"
|
||
docker exec gitea-mirror-postgres psql -U $POSTGRES_SUPERUSER -d hunabgit -c "GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO utils;"
|
||
docker exec gitea-mirror-postgres psql -U $POSTGRES_SUPERUSER -d hunabgit -c "GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA public TO utils;"
|
||
docker exec gitea-mirror-postgres psql -U $POSTGRES_SUPERUSER -d hunabgit -c "GRANT CREATE ON SCHEMA public TO utils;"
|
||
|
||
# Проверка
|
||
docker exec gitea-mirror-postgres psql -U utils -d hunabgit -c "SELECT version();"
|
||
```
|
||
|
||
**Диагностика проблем:**
|
||
|
||
1. **"role \"utils\" does not exist"** - Пользователь не создан:
|
||
```bash
|
||
docker exec gitea-mirror-postgres psql -U postgres -d postgres -c "CREATE USER utils WITH PASSWORD 'YOUR_PASSWORD';"
|
||
```
|
||
|
||
2. **"password authentication failed"** - Пароль неверный:
|
||
```bash
|
||
docker exec gitea-mirror-postgres psql -U postgres -d postgres -c "ALTER USER utils WITH PASSWORD 'YOUR_PASSWORD';"
|
||
```
|
||
|
||
3. **"permission denied for database"** - Нет прав:
|
||
```bash
|
||
docker exec gitea-mirror-postgres psql -U postgres -d postgres -c "GRANT ALL PRIVILEGES ON DATABASE hunabgit TO utils;"
|
||
```
|
||
|
||
**Проверка после создания:**
|
||
```bash
|
||
docker exec gitea-mirror-postgres psql -U utils -d hunabgit -c "SELECT 1;"
|
||
# Должно вернуть: 1 без ошибок
|
||
```
|
||
|
||
### Настройка через веб-интерфейс
|
||
|
||
При первом запуске http://209.38.32.21:3000:
|
||
|
||
**Database Settings (СТАНДАРТ - PostgreSQL):**
|
||
- **Database Type:** `PostgreSQL` ⚠️ **ОБЯЗАТЕЛЬНО PostgreSQL, НЕ MySQL, НЕ SQLite**
|
||
- **Host:** `hunab-prod-postgres:5432` (для основного сервера) или `gitea-mirror-postgres:5432` (для зеркального)
|
||
- **Database Name:** `hunabgit` ⚠️ **НЕ gitea!**
|
||
- **Username:** `hunabgit` (основной) или `utils` (зеркальный)
|
||
- **Password:** `YOUR_PASSWORD`
|
||
- **SSL Mode:** `disable`
|
||
|
||
**General Settings:**
|
||
- Domain: `gitea.hunab.app`
|
||
- SSH Port: `2223`
|
||
- HTTP Port: `3000`
|
||
- Gitea Base URL: `https://gitea.hunab.app`
|
||
|
||
**Administrator Account:**
|
||
- Username: `hunabgit`
|
||
- Email: `mikhevel@gmail.com`
|
||
- Password: (надежный пароль)
|
||
|
||
---
|
||
|
||
## 🔐 SSL Configuration
|
||
|
||
### Сертификат Let's Encrypt
|
||
|
||
```bash
|
||
# Получение сертификата
|
||
sudo certbot certonly --standalone -d gitea.hunab.app
|
||
|
||
# Копирование в рабочую директорию
|
||
sudo cp /etc/letsencrypt/live/gitea.hunab.app/fullchain.pem /opt/app/ssl/gitea-fullchain.pem
|
||
sudo cp /etc/letsencrypt/live/gitea.hunab.app/privkey.pem /opt/app/ssl/gitea-privkey.pem
|
||
```
|
||
|
||
### Nginx Configuration
|
||
|
||
Конфигурация находится в `docker/nginx/environments/gitea.conf`:
|
||
|
||
```nginx
|
||
# HTTP → HTTPS redirect
|
||
server {
|
||
listen 80;
|
||
server_name gitea.hunab.app;
|
||
return 301 https://$host$request_uri;
|
||
}
|
||
|
||
# HTTPS server
|
||
# CRITICAL: HTTP/2 disabled - git operations require HTTP/1.1
|
||
server {
|
||
listen 443 ssl;
|
||
# http2 on; # DISABLED: git operations don't work well with HTTP/2
|
||
server_name gitea.hunab.app;
|
||
|
||
# SSL configuration
|
||
ssl_certificate /opt/app/ssl/gitea-fullchain.pem;
|
||
ssl_certificate_key /opt/app/ssl/gitea-privkey.pem;
|
||
ssl_protocols TLSv1.2 TLSv1.3;
|
||
ssl_ciphers HIGH:!aNULL:!MD5;
|
||
|
||
# Gitea reverse proxy
|
||
location / {
|
||
proxy_pass http://gitea:3000;
|
||
proxy_set_header Host $host;
|
||
proxy_set_header X-Real-IP $remote_addr;
|
||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||
proxy_set_header X-Forwarded-Proto $scheme;
|
||
proxy_http_version 1.1;
|
||
proxy_set_header Upgrade $http_upgrade;
|
||
proxy_set_header Connection 'upgrade';
|
||
proxy_cache_bypass $http_upgrade;
|
||
|
||
# Timeouts
|
||
proxy_connect_timeout 60s;
|
||
proxy_send_timeout 60s;
|
||
proxy_read_timeout 60s;
|
||
|
||
# Buffer settings
|
||
proxy_buffering off;
|
||
proxy_request_buffering off;
|
||
}
|
||
|
||
# Git operations (git-receive-pack, git-upload-pack) - увеличенные таймауты
|
||
# CRITICAL: HTTP/2 disabled for git operations (git uses HTTP/1.1)
|
||
location ~ ^/.*\.git/(git-receive-pack|git-upload-pack) {
|
||
proxy_http_version 1.1;
|
||
proxy_pass http://gitea:3000;
|
||
proxy_set_header Host $host;
|
||
proxy_set_header X-Real-IP $remote_addr;
|
||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||
proxy_set_header X-Forwarded-Proto $scheme;
|
||
|
||
# CRITICAL: Use keep-alive for stable connection during data transfer
|
||
proxy_set_header Connection "keep-alive";
|
||
|
||
# Extended timeouts for git operations (для больших репозиториев)
|
||
proxy_connect_timeout 300s;
|
||
proxy_send_timeout 600s;
|
||
proxy_read_timeout 600s;
|
||
|
||
# Buffer settings (отключены для больших файлов)
|
||
proxy_buffering off;
|
||
proxy_request_buffering off;
|
||
client_max_body_size 0;
|
||
|
||
# Дополнительные настройки для стабильности
|
||
proxy_redirect off;
|
||
proxy_set_header Accept-Encoding "";
|
||
}
|
||
|
||
# Git info/refs operations - также с увеличенными таймаутами
|
||
location ~ ^/.*\.git/info/refs {
|
||
proxy_http_version 1.1;
|
||
proxy_pass http://gitea:3000;
|
||
proxy_set_header Host $host;
|
||
proxy_set_header X-Real-IP $remote_addr;
|
||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||
proxy_set_header X-Forwarded-Proto $scheme;
|
||
proxy_set_header Connection "";
|
||
|
||
# Extended timeouts
|
||
proxy_connect_timeout 300s;
|
||
proxy_send_timeout 600s;
|
||
proxy_read_timeout 600s;
|
||
|
||
# Buffer settings
|
||
proxy_buffering off;
|
||
proxy_request_buffering off;
|
||
client_max_body_size 0;
|
||
}
|
||
}
|
||
```
|
||
|
||
**Ключевые особенности:**
|
||
- ✅ HTTP/2 отключен для всего server блока (git требует HTTP/1.1)
|
||
- ✅ Правильные SSL сертификаты (gitea-fullchain.pem с SAN для gitea.hunab.app)
|
||
- ✅ Увеличенные таймауты для git операций (300-600s)
|
||
- ✅ Отключена буферизация для больших файлов
|
||
- ✅ Специальные location блоки для git операций
|
||
|
||
### SSL Optimization
|
||
|
||
- ✅ TLSv1.2 и TLSv1.3
|
||
- ✅ Современные cipher suites
|
||
- ✅ HSTS enabled (1 год)
|
||
- ✅ Security headers
|
||
- ✅ Session tickets disabled
|
||
|
||
**Рекомендация:** Добавьте DNS CAA запись:
|
||
```
|
||
Type: CAA
|
||
Name: gitea.hunab.app
|
||
Value: 0 issue "letsencrypt.org"
|
||
```
|
||
|
||
---
|
||
|
||
## 🔄 Push репозиториев (КРИТИЧЕСКИ ВАЖНО)
|
||
|
||
### ✅ Для репозитория local_machine
|
||
|
||
В этом проекте пуш делается из корня **local_machine**:
|
||
|
||
```bash
|
||
cd /Users/eternal/code/local_machine
|
||
git push -u origin main
|
||
```
|
||
|
||
**Если из РФ push по HTTPS зависает** — переключите remote на SSH (порт 2223):
|
||
|
||
```bash
|
||
git remote set-url origin ssh://git@gitea.hunab.app:2223/hunabgit/local_machine.git
|
||
git push -u origin main
|
||
```
|
||
|
||
Если и SSH недоступен — используйте [метод через bundle](#резервный-способ-push-через-bundle) ниже. Полная настройка: **[LOCAL_MACHINE_GITEA_SETUP.md](./LOCAL_MACHINE_GITEA_SETUP.md)**.
|
||
|
||
---
|
||
|
||
### ❌ Проблема: Push через HTTPS зависает
|
||
|
||
При попытке `git push` через HTTPS возникают таймауты:
|
||
```
|
||
fatal: unable to access 'https://gitea.hunab.app/...': Recv failure: Operation timed out
|
||
```
|
||
|
||
**Корневые причины:**
|
||
1. HTTP/2 несовместим с git операциями (git использует HTTP/1.1)
|
||
2. Недостаточные таймауты для больших репозиториев
|
||
3. Проблемы с keepalive соединениями через reverse proxy
|
||
4. Ограничения curl/git на стороне клиента (особенно на macOS)
|
||
|
||
**Диагностика в логах Gitea:**
|
||
```
|
||
Fail to serve RPC(receive-pack): exit status 128
|
||
fatal: the remote end hung up unexpectedly
|
||
```
|
||
|
||
POST запрос доходит до Gitea, но соединение обрывается во время передачи данных.
|
||
|
||
### ✅ Универсальный скрипт пуша (в других репо)
|
||
|
||
В репозиториях с полной инфраструктурой (например hunabapp) используется скрипт, который автоматически выбирает метод (SSH → HTTPS → bundle):
|
||
|
||
```bash
|
||
# Обычный скрипт (для работы не из РФ)
|
||
bash scripts/deployment/gitea/git-push-gitea.sh [branch]
|
||
|
||
# 🇷🇺 ДЛЯ РФ: Скрипт через прокси (ускоряет в 5-10 раз)
|
||
bash scripts/deployment/gitea/git-push-gitea-via-proxy.sh [branch]
|
||
```
|
||
|
||
**Для local_machine** такого скрипта нет — используйте `git push origin main` или SSH (см. выше).
|
||
|
||
**🇷🇺 Из РФ:**
|
||
- Предпочтительно **SSH** (порт 2223) — часто стабильнее HTTPS.
|
||
- Либо метод через bundle (см. раздел ниже).
|
||
|
||
### ✅ Резервный способ: Временный скрипт для коммита и пуша
|
||
|
||
**Когда использовать:**
|
||
- Терминал недоступен из-за проблем с zsh/shell
|
||
- Агент не может выполнить команды напрямую
|
||
- Нужно подготовить все команды заранее
|
||
|
||
**Процесс:**
|
||
1. **Агент создает временный скрипт** в `temp/commit-and-push.sh` с полным коммитом и push командой
|
||
2. **Пользователь выполняет скрипт** вручную в терминале
|
||
3. **Скрипт автоматически** делает `git add`, `git commit` и `git push`
|
||
|
||
**Формат временного скрипта (для local_machine):**
|
||
```bash
|
||
#!/bin/bash
|
||
set -e
|
||
echo "📦 Committing changes..."
|
||
git add -A
|
||
echo "💾 Creating commit..."
|
||
git commit -m "docs: описание изменений"
|
||
echo "🚀 Pushing to Gitea..."
|
||
git push origin main
|
||
echo "✅ Done!"
|
||
```
|
||
|
||
**Требования к скрипту:**
|
||
- ✅ Должен быть исполняемым (`chmod +x`)
|
||
- ✅ Должен содержать полное сообщение коммита с описанием изменений
|
||
- ✅ Для local_machine: `git push origin main` (или SSH remote, см. выше)
|
||
- ✅ Должен быть в папке `temp/` для временных скриптов
|
||
- ✅ Должен иметь понятные echo сообщения для пользователя
|
||
|
||
**Использование:**
|
||
```bash
|
||
# Выполнить скрипт
|
||
bash temp/commit-and-push.sh
|
||
```
|
||
|
||
**Очистка:**
|
||
После успешного выполнения скрипт можно удалить:
|
||
```bash
|
||
rm temp/commit-and-push.sh
|
||
```
|
||
|
||
**⚠️ ВАЖНО:**
|
||
- Скрипт должен быть создан агентом **ПЕРЕД** запросом пользователя на коммит
|
||
- Агент должен **ВСЕГДА** готовить скрипт, если терминал недоступен
|
||
- Скрипт должен содержать **ПОЛНОЕ** описание изменений в коммите
|
||
|
||
### Стандарт: без трейлеров в коммитах
|
||
|
||
В проекте **не используются** git-трейлеры в сообщениях коммитов (строки вида `Key: Value` в конце сообщения). Не добавлять:
|
||
- `Made-with: Cursor` и аналогичные метки инструмента
|
||
- `Co-authored-by:`, `Signed-off-by:` и т.п., если это не требуется явно политикой репозитория
|
||
|
||
Коммиты должны содержать только заголовок и при необходимости тело сообщения в читаемом формате.
|
||
|
||
### Проверки перед коммитом (опционально)
|
||
|
||
Если в проекте есть проверка типов или линтеры — их можно запускать перед коммитом по желанию. Для local_machine (документация и скрипты) обычно достаточно `git add` и `git commit`.
|
||
|
||
(В проекте local_machine нет frontend/backend — при необходимости добавьте свои проверки в скрипты.)
|
||
|
||
*Для других репо:* проверка прав на `.env` после деплоя и typecheck-скрипты — в документации того проекта.
|
||
|
||
### Метод 1: HTTPS с оптимизированными настройками
|
||
|
||
```bash
|
||
# Настройка git для больших push
|
||
git config http.postBuffer 524288000
|
||
git config http.lowSpeedLimit 0
|
||
git config http.lowSpeedTime 0
|
||
git config http.timeout 600
|
||
|
||
# Попытка push (для local_machine — ветка main)
|
||
git push origin main
|
||
```
|
||
|
||
**⚠️ На macOS:** HTTPS push часто не работает из-за отсутствия команды `timeout`. Скрипт автоматически пропускает HTTPS и использует bundle метод.
|
||
|
||
### Метод 2: Bundle метод (надежный fallback) {#резервный-способ-push-через-bundle}
|
||
|
||
Если HTTPS не работает, используется прямой доступ через файловую систему:
|
||
|
||
```bash
|
||
# Создать bundle (для local_machine — ветка main)
|
||
git bundle create /tmp/push.bundle origin/main..main
|
||
|
||
# Скопировать на сервер (hunab-prod — хост с доступом к Docker Gitea)
|
||
scp /tmp/push.bundle hunab-prod:/tmp/
|
||
|
||
# Применить в Gitea (репо local_machine)
|
||
ssh hunab-prod "docker cp /tmp/push.bundle gitea:/tmp/push.bundle && \
|
||
docker exec gitea sh -c 'cd /data/git/repositories/hunabgit/local_machine.git && \
|
||
git bundle unbundle /tmp/push.bundle && \
|
||
git update-ref refs/heads/main \$(git bundle list-heads /tmp/push.bundle | grep main | cut -d\" \" -f1) && \
|
||
rm /tmp/push.bundle' && rm /tmp/push.bundle"
|
||
```
|
||
|
||
**✅ Статус:** Bundle метод всегда работает и обходит все проблемы с таймаутами.
|
||
|
||
### Сравнение методов
|
||
|
||
| Метод | Скорость | Надежность | Сложность | Платформа |
|
||
|-------|----------|------------|-----------|-----------|
|
||
| **SSH** | ⚡⚡⚡ Быстро | ✅✅✅ Высокая | ✅ Просто | Все |
|
||
| **HTTPS (оптимизированный)** | ⚡⚡ Средне | ✅✅ Средняя | ✅ Просто | Linux |
|
||
| **Bundle (прямой доступ)** | ⚡ Медленно | ✅✅✅ Всегда работает | ⚠️ Сложнее | Все |
|
||
|
||
**Рекомендация:** Используйте автоматический скрипт - он выберет лучший метод автоматически.
|
||
|
||
### Миграция репозиториев
|
||
|
||
**Для регулярных push в local_machine:** `git push origin main` или SSH (см. раздел «Для репозитория local_machine» выше). В других репо может быть скрипт `git-push-gitea.sh`.
|
||
|
||
#### Шаг 1: Создание bundle из локального репозитория
|
||
|
||
```bash
|
||
cd /Users/eternal/code/local_machine
|
||
git bundle create /tmp/local_machine-migration.bundle --all
|
||
```
|
||
|
||
#### Шаг 2: Копирование bundle на сервер
|
||
|
||
```bash
|
||
scp /tmp/local_machine-migration.bundle hunab-prod:/tmp/local_machine-migration.bundle
|
||
```
|
||
|
||
#### Шаг 3: Распаковка bundle на сервере
|
||
|
||
```bash
|
||
ssh hunab-prod "cd /tmp && git clone --mirror local_machine-migration.bundle local_machine-mirror.git"
|
||
```
|
||
|
||
#### Шаг 4: Копирование в директорию Gitea
|
||
|
||
```bash
|
||
ssh hunab-prod "
|
||
docker exec gitea mkdir -p /data/git/repositories/hunabgit/
|
||
docker cp /tmp/local_machine-mirror.git gitea:/data/git/repositories/hunabgit/local_machine.git
|
||
docker exec gitea chown -R git:git /data/git/repositories/hunabgit/local_machine.git
|
||
"
|
||
```
|
||
|
||
#### Шаг 5: Распаковка refs из packed-refs
|
||
|
||
**КРИТИЧЕСКИ ВАЖНО:** Gitea не видит ветки в `packed-refs`, нужно распаковать:
|
||
|
||
```bash
|
||
ssh hunab-prod "docker exec gitea sh -c 'cd /data/git/repositories/hunabgit/local_machine.git && cat packed-refs | grep \"refs/heads/\" | while read sha ref; do mkdir -p \$(dirname \$ref) && echo \$sha > \$ref; done'"
|
||
```
|
||
|
||
#### Шаг 6: Обновление базы данных
|
||
|
||
```bash
|
||
ssh hunab-prod "
|
||
docker exec hunab-prod-postgres psql -U hunabgit -d hunabgit -c \"UPDATE repository SET is_empty = false WHERE name = 'local_machine';\"
|
||
docker exec gitea /usr/local/bin/gitea admin regenerate hooks --config /data/gitea/conf/app.ini
|
||
docker restart gitea
|
||
"
|
||
```
|
||
|
||
#### Шаг 7: Проверка
|
||
|
||
```bash
|
||
# Проверка веток через API
|
||
curl -s -H "Authorization: token YOUR_TOKEN" \
|
||
https://gitea.hunab.app/api/v1/repos/hunabgit/local_machine/branches | jq '.[] | .name'
|
||
|
||
# Проверка файлов через API (ветка main)
|
||
curl -s -H "Authorization: token YOUR_TOKEN" \
|
||
https://gitea.hunab.app/api/v1/repos/hunabgit/local_machine/git/trees/main?recursive=0 | jq '.tree[] | .path'
|
||
|
||
# Веб-интерфейс
|
||
# https://gitea.hunab.app/hunabgit/local_machine
|
||
```
|
||
|
||
**✅ Результат:** Репозиторий полностью мигрирован, все файлы доступны через веб-интерфейс и API.
|
||
|
||
### Аутентификация
|
||
|
||
#### Создание токена доступа
|
||
|
||
1. Откройте: https://gitea.hunab.app/user/settings/applications
|
||
2. Generate New Token
|
||
3. Название: `api-access`
|
||
4. Права: `write:repository`, `read:repository`, `read:user`
|
||
5. Скопируйте токен
|
||
|
||
#### Использование токена в git
|
||
|
||
```bash
|
||
# В локальном репозитории local_machine
|
||
cd /Users/eternal/code/local_machine
|
||
git remote set-url origin https://TOKEN@gitea.hunab.app/hunabgit/local_machine.git
|
||
```
|
||
|
||
---
|
||
|
||
## 🏷️ Создание тегов и Release (СТАНДАРТ)
|
||
|
||
### ⚠️ КРИТИЧЕСКИ ВАЖНО: Gitea не обновляет индекс тегов автоматически
|
||
|
||
**Проблема:** Если создать тег напрямую в git репозитории (`git tag -a v1.0.0`), Gitea **НЕ покажет его в веб-интерфейсе** автоматически. Gitea кэширует список тегов и обновляет его только при создании Release через веб-интерфейс или API.
|
||
|
||
### ✅ СТАНДАРТ: Создание тега через базу данных (РЕКОМЕНДУЕТСЯ)
|
||
|
||
**Используйте этот метод для автоматического создания тегов:**
|
||
|
||
```bash
|
||
# 1. Получить ID репозитория
|
||
REPO_ID=$(ssh hunab-prod "docker exec hunab-prod-postgres psql -U hunabgit -d hunabgit -t -c \"SELECT id FROM repository WHERE lower_name = 'local_machine';\" | tr -d ' '")
|
||
|
||
# 2. Создать Release в базе данных
|
||
ssh hunab-prod "docker exec hunab-prod-postgres psql -U hunabgit -d hunabgit -c \"
|
||
INSERT INTO release (
|
||
repo_id,
|
||
publisher_id,
|
||
tag_name,
|
||
lower_tag_name,
|
||
target,
|
||
sha1,
|
||
title,
|
||
note,
|
||
is_draft,
|
||
is_prerelease,
|
||
is_tag,
|
||
created_unix
|
||
) VALUES (
|
||
$REPO_ID,
|
||
1,
|
||
'v1.3.7-CRM',
|
||
'v1.3.7-crm',
|
||
'dev',
|
||
'1542c302c36ad367281f8d9740e4d9f4a817ad23',
|
||
'v1.3.7-CRM: Полная реализация CRM Contacts Page',
|
||
'feat(CRM): Полная реализация CRM Contacts Page v1.3.7',
|
||
false,
|
||
false,
|
||
true,
|
||
EXTRACT(EPOCH FROM NOW())::bigint
|
||
) ON CONFLICT (repo_id, tag_name) DO NOTHING
|
||
RETURNING id, tag_name, title;
|
||
\""
|
||
|
||
# 3. Перезапустить Gitea для обновления индекса
|
||
ssh hunab-prod "docker restart gitea"
|
||
```
|
||
|
||
**Параметры:**
|
||
- `repo_id` - ID репозитория (получить через `SELECT id FROM repository WHERE lower_name = 'local_machine';`)
|
||
- `publisher_id` - ID пользователя (обычно 1 для первого пользователя)
|
||
- `tag_name` - Имя тега (например, `v1.3.7-CRM`)
|
||
- `lower_tag_name` - Имя тега в нижнем регистре (например, `v1.3.7-crm`)
|
||
- `target` - Ветка или commit (например, `dev` или `1542c302c36ad367281f8d9740e4d9f4a817ad23`)
|
||
- `sha1` - SHA коммита (40 символов)
|
||
- `title` - Заголовок Release
|
||
- `note` - Описание Release
|
||
- `is_tag` - `true` для тега, `false` для Release
|
||
|
||
### ✅ Альтернатива: Создание через веб-интерфейс
|
||
|
||
Если нужно создать тег вручную:
|
||
|
||
1. Откройте: https://gitea.hunab.app/hunabgit/local_machine/releases/new
|
||
2. В поле "Tag" введите имя тега (например, `v1.3.7-CRM`)
|
||
3. В поле "Target" выберите commit из списка или введите SHA
|
||
4. Заполните Title и Description
|
||
5. Нажмите "Publish Release"
|
||
|
||
**⚠️ Недостаток:** Требует ручного действия, не автоматизируется.
|
||
|
||
### ✅ Альтернатива: Создание через API (требует токен)
|
||
|
||
```bash
|
||
# 1. Получить токен доступа (один раз)
|
||
TOKEN=$(ssh hunab-prod "docker exec gitea /usr/local/bin/gitea admin user generate-access-token --username hunabgit --scopes 'write:repository' --name 'api-tag-creation' 2>&1 | grep -o '[a-z0-9]\{40\}' | head -1")
|
||
|
||
# 2. Создать Release через API
|
||
curl -X POST "https://gitea.hunab.app/api/v1/repos/hunabgit/local_machine/releases" \
|
||
-H "Authorization: token $TOKEN" \
|
||
-H "Content-Type: application/json" \
|
||
-d '{
|
||
"tag_name": "v1.3.7-CRM",
|
||
"target_commitish": "1542c302c36ad367281f8d9740e4d9f4a817ad23",
|
||
"name": "v1.3.7-CRM: Полная реализация CRM Contacts Page",
|
||
"body": "feat(CRM): Полная реализация CRM Contacts Page v1.3.7",
|
||
"draft": false,
|
||
"prerelease": false
|
||
}'
|
||
```
|
||
|
||
**⚠️ Недостаток:** Требует токен доступа, который нужно создать заранее.
|
||
|
||
### ❌ НЕ РАБОТАЕТ: Создание тега напрямую в git
|
||
|
||
```bash
|
||
# ❌ НЕ РАБОТАЕТ - Gitea не увидит тег в веб-интерфейсе
|
||
git tag -a v1.3.7-CRM -m "Message"
|
||
git push origin v1.3.7-CRM # Даже после push тег не появится в веб-интерфейсе
|
||
```
|
||
|
||
**Почему не работает:**
|
||
- Gitea кэширует список тегов в базе данных
|
||
- Создание тега напрямую в git не обновляет таблицу `release`
|
||
- Gitea не сканирует репозиторий автоматически для поиска новых тегов
|
||
|
||
### 📋 Чеклист создания тега
|
||
|
||
- [ ] Получить ID репозитория из базы данных
|
||
- [ ] Получить SHA коммита для тега
|
||
- [ ] Создать Release в таблице `release` базы данных
|
||
- [ ] Перезапустить Gitea для обновления индекса
|
||
- [ ] Проверить что тег появился в веб-интерфейсе: https://gitea.hunab.app/hunabgit/local_machine/releases
|
||
|
||
### 🔧 Скрипт для автоматического создания тега
|
||
|
||
**Готовый скрипт:** `scripts/deployment/gitea/create-gitea-tag.sh`
|
||
|
||
**🇷🇺 ДЛЯ РФ:** Используйте прокси-версию для ускорения в 5-10 раз:
|
||
- `scripts/deployment/gitea/create-gitea-tag.sh` - обычный скрипт
|
||
- `scripts/deployment/gitea/create-gitea-tag-via-proxy.sh` - **🇷🇺 ДЛЯ РФ** - через прокси
|
||
|
||
**Использование:**
|
||
```bash
|
||
# Обычный скрипт
|
||
bash scripts/deployment/gitea/create-gitea-tag.sh \
|
||
<tag-name> \
|
||
<commit-sha> \
|
||
<title> \
|
||
[description] \
|
||
[branch]
|
||
|
||
# 🇷🇺 ДЛЯ РФ: Через прокси (рекомендуется из РФ)
|
||
bash scripts/deployment/gitea/create-gitea-tag-via-proxy.sh \
|
||
<tag-name> \
|
||
<commit-sha> \
|
||
<title> \
|
||
[description] \
|
||
[branch]
|
||
```
|
||
|
||
**Пример:**
|
||
```bash
|
||
bash scripts/deployment/gitea/create-gitea-tag.sh \
|
||
v1.3.7-CRM \
|
||
1542c302c36ad367281f8d9740e4d9f4a817ad23 \
|
||
"v1.3.7-CRM: Полная реализация CRM Contacts Page" \
|
||
"feat(CRM): Полная реализация CRM Contacts Page v1.3.7" \
|
||
dev
|
||
```
|
||
|
||
**Что делает скрипт:**
|
||
1. ✅ Валидирует параметры (формат тега, SHA коммита)
|
||
2. ✅ Получает ID репозитория из базы данных
|
||
3. ✅ Создает Release в таблице `release`
|
||
4. ✅ Перезапускает Gitea для обновления индекса
|
||
5. ✅ Выводит ссылку для проверки
|
||
|
||
**Особенности:**
|
||
- Автоматически обрабатывает конфликты (обновляет существующий тег)
|
||
- Экранирует специальные символы в SQL
|
||
- Проверяет существование репозитория
|
||
- Выводит понятные сообщения об ошибках
|
||
|
||
---
|
||
|
||
## 📊 Мониторинг
|
||
|
||
### Проверка статуса
|
||
|
||
```bash
|
||
# Контейнер
|
||
ssh hunab-prod "docker ps | grep gitea"
|
||
|
||
# Логи
|
||
ssh hunab-prod "docker logs gitea --tail 50"
|
||
|
||
# Ресурсы
|
||
ssh hunab-prod "docker stats gitea --no-stream"
|
||
|
||
# API
|
||
curl https://gitea.hunab.app/api/v1/version
|
||
|
||
# SSL
|
||
openssl s_client -connect gitea.hunab.app:443 -servername gitea.hunab.app </dev/null 2>&1 | grep -E 'Protocol|Cipher'
|
||
```
|
||
|
||
### Проверка репозитория
|
||
|
||
```bash
|
||
# Ветки
|
||
ssh hunab-prod "docker exec gitea git --git-dir=/data/git/repositories/hunabgit/local_machine.git branch -a | wc -l"
|
||
|
||
# Размер
|
||
ssh hunab-prod "docker exec gitea du -sh /data/git/repositories/hunabgit/local_machine.git"
|
||
|
||
# Последний коммит
|
||
ssh hunab-prod "docker exec gitea git --git-dir=/data/git/repositories/hunabgit/local_machine.git log -1 --pretty=format:'%H %s'"
|
||
```
|
||
|
||
---
|
||
|
||
## 🔧 Troubleshooting
|
||
|
||
Для детальной диагностики проблем см. **[GITEA_TROUBLESHOOTING.md](./GITEA_TROUBLESHOOTING.md)** - Полное руководство по решению проблем.
|
||
|
||
Для диагностики зеркального сервера см. **[GITEA_MIRROR_TROUBLESHOOTING.md](./GITEA_MIRROR_TROUBLESHOOTING.md)**.
|
||
|
||
### Gitea не запускается
|
||
|
||
```bash
|
||
# Проверка логов
|
||
ssh hunab-prod "docker logs gitea --tail 100"
|
||
|
||
# Проверка портов
|
||
ssh hunab-prod "ss -tuln | grep -E '3000|2223'"
|
||
|
||
# Перезапуск
|
||
ssh hunab-prod "docker restart gitea"
|
||
```
|
||
|
||
### Ветки не видны в веб-интерфейсе
|
||
|
||
**Причина:** Refs в `packed-refs`, Gitea их не читает
|
||
|
||
**Решение:** Распаковать refs (см. Шаг 5 миграции)
|
||
|
||
**✅ Статус:** Проблема решена, все ветки видны в веб-интерфейсе
|
||
|
||
### Git hooks кажутся сломанными
|
||
|
||
**Проблема:** Gitea показывает предупреждение "Git hooks of this repository seem to be broken"
|
||
|
||
**Причина:** После прямой миграции репозитория hooks могут быть не синхронизированы с Gitea
|
||
|
||
**Решение:** Регенерировать hooks для всех репозиториев:
|
||
|
||
```bash
|
||
ssh hunab-prod "docker exec gitea /usr/local/bin/gitea admin regenerate hooks --config /data/gitea/conf/app.ini"
|
||
```
|
||
|
||
**Проверка:**
|
||
```bash
|
||
# Проверка прав на hooks
|
||
ssh hunab-prod "docker exec gitea ls -la /data/git/repositories/hunabgit/local_machine.git/hooks/pre-receive"
|
||
|
||
# Проверка содержимого hooks
|
||
ssh hunab-prod "docker exec gitea cat /data/git/repositories/hunabgit/local_machine.git/hooks/pre-receive.d/gitea"
|
||
```
|
||
|
||
**Дополнительно:** Если проблема сохраняется, проверьте:
|
||
1. Файловая система поддерживает выполнение (`chmod +x` работает)
|
||
2. Файловая система не смонтирована с `noexec`
|
||
3. Docker версия >= 20.10.6 (у нас 28.0.1 ✅)
|
||
|
||
**См. документацию Gitea:** https://docs.gitea.com/help/faq#push-hook--webhook--actions-arent-running
|
||
|
||
**✅ Статус:** Решено через `gitea admin regenerate hooks`
|
||
|
||
### Push через HTTPS зависает
|
||
|
||
**Проблема:** Git получает refs (GET запрос успешен), но POST запрос с данными не отправляется или соединение обрывается.
|
||
|
||
**Причина:**
|
||
- Известная проблема с HTTP/2 и большими репозиториями в Gitea
|
||
- Проблемы с keepalive соединениями через reverse proxy
|
||
- Ограничения curl/git на стороне клиента (особенно на macOS)
|
||
|
||
**Решение:**
|
||
1. ✅ **Используйте универсальный скрипт:** `bash scripts/deployment/gitea/git-push-gitea.sh [branch]`
|
||
2. ✅ Скрипт автоматически выбирает лучший метод (SSH > HTTPS > Bundle)
|
||
3. ✅ На macOS автоматически использует bundle метод (обходит проблемы с HTTPS)
|
||
|
||
**✅ Статус:** Систематически решено через универсальный скрипт (2026-01-02)
|
||
|
||
### SSL сертификат не обновляется
|
||
|
||
```bash
|
||
# Проверка автообновления
|
||
ssh hunab-prod "systemctl status certbot.timer"
|
||
|
||
# Ручное обновление
|
||
ssh hunab-prod "sudo certbot renew --dry-run"
|
||
|
||
# Копирование новых сертификатов
|
||
ssh hunab-prod "sudo cp /etc/letsencrypt/live/gitea.hunab.app/*.pem /opt/app/ssl/ && docker restart hunab-prod-nginx"
|
||
```
|
||
|
||
---
|
||
|
||
## 🔒 Безопасность
|
||
|
||
### Рекомендации
|
||
|
||
1. ✅ HTTPS через Let's Encrypt (настроено)
|
||
2. ✅ Modern SSL/TLS protocols (TLSv1.2, TLSv1.3)
|
||
3. ✅ Security headers (HSTS, X-Frame-Options, etc.)
|
||
4. ⚠️ Firewall для ограничения доступа (рекомендуется)
|
||
5. ✅ SSH ключи для git операций
|
||
6. ✅ Регулярные бэкапы данных
|
||
|
||
### Бэкапы
|
||
|
||
```bash
|
||
# Полный бэкап Gitea
|
||
ssh hunab-prod "
|
||
tar -czf /opt/gitea-backup-$(date +%Y%m%d).tar.gz /opt/gitea
|
||
"
|
||
|
||
# Бэкап только репозиториев
|
||
ssh hunab-prod "
|
||
tar -czf /opt/gitea-repos-backup-$(date +%Y%m%d).tar.gz /opt/gitea/git/repositories
|
||
"
|
||
|
||
# Бэкап базы данных
|
||
ssh hunab-prod "
|
||
docker exec hunab-prod-postgres pg_dump -U hunabgit hunabgit > /opt/gitea-db-backup-$(date +%Y%m%d).sql
|
||
"
|
||
```
|
||
|
||
---
|
||
|
||
## 📈 Итоги и выводы
|
||
|
||
### Что было достигнуто
|
||
|
||
1. ✅ **Gitea развернут на production** (209.38.32.21)
|
||
2. ✅ **PostgreSQL настроен** (отдельная БД hunabgit)
|
||
3. ✅ **SSL/TLS настроен** (Let's Encrypt, A rating)
|
||
4. ✅ **Nginx reverse proxy** (с оптимизацией)
|
||
5. ✅ **Репозиторий local_machine** (и при необходимости другие репо) доступен на Gitea
|
||
6. ✅ **DNS настроен** (gitea.hunab.app → 209.38.32.21)
|
||
7. ✅ **Веб-интерфейс работает** (файлы отображаются корректно)
|
||
8. ✅ **API полностью функционален** (все endpoints работают)
|
||
|
||
### Ключевые проблемы и решения
|
||
|
||
#### Проблема 1: MySQL vs PostgreSQL
|
||
- **Проблема:** Gitea пытался подключиться к несуществующему MySQL
|
||
- **Решение:** Настроили PostgreSQL с отдельной БД
|
||
|
||
#### Проблема 2: SSL сертификат для поддомена
|
||
- **Проблема:** Существующий сертификат был для hunab.app, не gitea.hunab.app
|
||
- **Решение:** Получили новый сертификат через certbot --standalone
|
||
|
||
#### Проблема 3: Push через HTTPS зависает
|
||
- **Проблема:** Git получает refs, но POST запрос с данными не отправляется или соединение обрывается
|
||
- **Причина:** Известная проблема с HTTP/2 и большими репозиториями в Gitea, проблемы с keepalive соединениями
|
||
- **Попытки:** Увеличение таймаутов Nginx до 600s, отключение HTTP/2, оптимизация Connection headers
|
||
- **Решение:** Систематическое решение через универсальный скрипт `git-push-gitea.sh` (2026-01-02)
|
||
- Автоматический выбор метода: SSH > HTTPS > Bundle
|
||
- На macOS автоматически использует bundle метод
|
||
- Всегда работает, обходит все проблемы с таймаутами
|
||
|
||
#### Проблема 4: Gitea не видит ветки
|
||
- **Проблема:** Refs в packed-refs, Gitea их не индексирует
|
||
- **Решение:** Распаковали refs в refs/heads/ структуру
|
||
|
||
#### Проблема 5: GitHub требует аутентификацию
|
||
- **Проблема:** git clone --mirror с сервера не работает без токена
|
||
- **Решение:** Использовали bundle, созданный локально
|
||
|
||
### Lessons Learned
|
||
|
||
1. **Прямое копирование эффективнее push** для больших репозиториев
|
||
2. **packed-refs не поддерживается Gitea** — нужна распаковка
|
||
3. **certbot --standalone** проще для новых сертификатов
|
||
4. **Docker network** критичен для PostgreSQL подключения
|
||
5. **Bundle** — универсальный способ переноса репозиториев
|
||
|
||
### Производительность
|
||
|
||
- **Обычный git push через HTTPS:** ❌ Зависает (POST запрос не отправляется или соединение обрывается)
|
||
- **Универсальный скрипт (git-push-gitea.sh):** ✅ Автоматически выбирает лучший метод
|
||
- SSH: ⚡⚡⚡ Быстро (если доступен)
|
||
- HTTPS: ⚡⚡ Средне (только на Linux)
|
||
- Bundle: ⚡ Медленно, но всегда работает (особенно на macOS)
|
||
- **🇷🇺 ДЛЯ РФ: Прокси-версия (git-push-gitea-via-proxy.sh):** ✅ Ускорение в 5-10 раз
|
||
- Работает через российский прокси-сервер (149.154.64.19)
|
||
- Стабильное соединение к Digital Ocean
|
||
- Избежание таймаутов при работе из РФ
|
||
- Bundle метод через прокси: ⚡⚡ Быстро и надежно
|
||
- ✅ **Мгновенная верификация** - обновление tracking ref без сетевых запросов (2026-02-27)
|
||
- **Прямое копирование через bundle:** ✅ ~1-2 минуты для инкрементальных обновлений
|
||
- **Полная миграция:** ✅ ~5-10 минут (включая распаковку refs)
|
||
- **Размер репозитория:** 556.8M (23 ветки, история с 2020 года)
|
||
- **Текущий статус:** ✅ Все файлы доступны, веб-интерфейс работает корректно
|
||
- **Скрипт для push:** ✅ `scripts/deployment/gitea/git-push-gitea.sh` - универсальное решение (2026-01-02)
|
||
|
||
### Следующие шаги (опционально)
|
||
|
||
1. **Настроить CI/CD** в Gitea (Gitea Actions)
|
||
2. **Настроить зеркалирование** GitHub ↔ Gitea (для резервирования)
|
||
3. **Настроить SSH ключи** для бесшовной работы
|
||
4. **Добавить DNS CAA запись** для дополнительной безопасности
|
||
5. **Настроить автоматические бэкапы** (cron job)
|
||
6. **Мигрировать deployment скрипты** на использование Gitea
|
||
|
||
---
|
||
|
||
## 📚 Полезные команды
|
||
|
||
**Для local_machine:**
|
||
```bash
|
||
cd /Users/eternal/code/local_machine
|
||
git push origin main
|
||
# или SSH (если HTTPS таймаутит): git remote set-url origin ssh://git@gitea.hunab.app:2223/hunabgit/local_machine.git
|
||
```
|
||
|
||
**Для админов сервера (Gitea Admin):**
|
||
```bash
|
||
docker exec gitea /usr/local/bin/gitea admin --help
|
||
docker exec gitea /usr/local/bin/gitea admin regenerate hooks
|
||
|
||
# Git операции в Gitea (репо local_machine)
|
||
docker exec gitea git --git-dir=/data/git/repositories/hunabgit/local_machine.git branch -a
|
||
docker exec gitea git --git-dir=/data/git/repositories/hunabgit/local_machine.git log --oneline -10
|
||
|
||
# PostgreSQL операции
|
||
docker exec hunab-prod-postgres psql -U hunabgit -d hunabgit -c "SELECT * FROM repository;"
|
||
|
||
# Проверка конфигурации базы данных
|
||
docker exec gitea cat /data/gitea/conf/app.ini | grep -A 10 '\[database\]'
|
||
# Должно быть: DB_TYPE = postgres, HOST = <postgres-container>:5432
|
||
|
||
# SSL проверка
|
||
openssl s_client -connect gitea.hunab.app:443 -servername gitea.hunab.app
|
||
curl -vI https://gitea.hunab.app 2>&1 | grep -E 'SSL|TLS'
|
||
|
||
# Nginx
|
||
docker exec hunab-prod-nginx nginx -t
|
||
docker logs hunab-prod-nginx --tail 50
|
||
|
||
# Проверка логов Gitea при push
|
||
ssh hunab-prod "docker logs gitea --tail 50 | grep -E '(receive-pack|upload-pack|error)'"
|
||
```
|
||
|
||
---
|
||
|
||
## 🔄 Зеркалирование
|
||
|
||
Для полного руководства по зеркалированию см. **[GITEA_MIRRORING_GUIDE.md](./GITEA_MIRRORING_GUIDE.md)**.
|
||
|
||
### Миграция Gitea на зеркальный сервер
|
||
|
||
**📋 План миграции:** См. **[GITEA_MIGRATION_TO_MIRROR_SERVER.md](./GITEA_MIGRATION_TO_MIRROR_SERVER.md)** - Детальный план миграции Gitea с production сервера (209.38.32.21) на зеркальный сервер (206.189.35.205).
|
||
|
||
**Причины миграции:**
|
||
- Освобождение дискового пространства на production сервере (96% заполнено)
|
||
- Изоляция рисков - проблемы Gitea не влияют на production
|
||
- Улучшение производительности Git операций
|
||
- Масштабируемость
|
||
|
||
### Зеркальный сервер (206.189.35.205)
|
||
|
||
Для резервирования и высокой доступности настроено зеркалирование всех репозиториев на внешний сервер.
|
||
|
||
**Документация:**
|
||
- [Gitea Mirroring Guide](./GITEA_MIRRORING_GUIDE.md) - Полный план зеркалирования
|
||
- [Gitea Migration to Mirror Server](./GITEA_MIGRATION_TO_MIRROR_SERVER.md) - **План миграции Gitea на зеркальный сервер (206.189.35.205)**
|
||
- [Gitea Mirror Troubleshooting](./GITEA_MIRROR_TROUBLESHOOTING.md) - Диагностика зеркального сервера
|
||
- [Gitea Legal — сервер 206.189.35.205](./GITEA_LEGAL_206_SERVER_GUIDE.md) - Стандарт для репозитория legal
|
||
|
||
**Быстрый старт:**
|
||
```bash
|
||
# Развертывание зеркального сервера
|
||
bash scripts/deployment/gitea/deploy-gitea-mirror-server.sh
|
||
|
||
# Миграция всех репозиториев
|
||
bash scripts/deployment/mirror-all-repos-to-external.sh
|
||
```
|
||
|
||
**Архитектура:**
|
||
- **Основной сервер (209.38.32.21):** Primary Gitea, все репозитории
|
||
- **Зеркальный сервер (206.189.35.205):** Mirror Gitea, автоматическая синхронизация
|
||
|
||
---
|
||
|
||
## 🔗 Ссылки
|
||
|
||
- **Веб-интерфейс:** https://gitea.hunab.app
|
||
- **API:** https://gitea.hunab.app/api/v1/
|
||
- **Репозиторий local_machine:** https://gitea.hunab.app/hunabgit/local_machine
|
||
- **Быстрый старт local_machine:** [LOCAL_MACHINE_GITEA_SETUP.md](./LOCAL_MACHINE_GITEA_SETUP.md)
|
||
- **Документация Gitea:** https://docs.gitea.io/
|
||
- **SSL Report:** https://www.ssllabs.com/ssltest/analyze.html?d=gitea.hunab.app
|
||
- **Зеркалирование:** [Gitea Mirroring Guide](./GITEA_MIRRORING_GUIDE.md) (если есть)
|
||
- **Миграция на зеркальный сервер:** [Gitea Migration Plan](./GITEA_MIGRATION_TO_MIRROR_SERVER.md) (если есть)
|
||
|
||
---
|
||
|
||
## ✅ Текущий статус
|
||
|
||
### Репозиторий local_machine
|
||
- **URL:** https://gitea.hunab.app/hunabgit/local_machine
|
||
- **Ветка по умолчанию:** main
|
||
- **Пуш:** `git push origin main` или SSH (порт 2223) — см. [LOCAL_MACHINE_GITEA_SETUP.md](./LOCAL_MACHINE_GITEA_SETUP.md)
|
||
|
||
### Система (сервер Gitea)
|
||
- ✅ Gitea контейнер на 209.38.32.21
|
||
- ✅ PostgreSQL, SSL/TLS, Nginx
|
||
- ✅ DNS: gitea.hunab.app → 209.38.32.21
|
||
|
||
**Последнее обновление:** 2026-03-14
|
||
**Версия документа:** 2.0 (адаптация под проект local_machine)
|
||
**Изменения:**
|
||
- Гайд переориентирован на репозиторий local_machine; примеры и команды приведены к этому проекту
|
||
- Добавлена ссылка на LOCAL_MACHINE_GITEA_SETUP.md для быстрого старта
|
||
|
||
---
|
||
|
||
## 🧹 Очистка истории Git от build-артефактов
|
||
|
||
### 🎯 Когда нужна очистка vs простое удаление
|
||
|
||
**99% случаев:** Файлы уже в `.gitignore`, но Git их отслеживает (закоммичены до добавления в `.gitignore`)
|
||
|
||
**Решение:** ✅ **Простое удаление из tracking** (см. ниже) — БЕЗ переписывания истории!
|
||
|
||
*Пример ниже — для репо с frontend (build-артефакты). В local_machine: убедиться, что путь в .gitignore, затем `git rm --cached -r путь/` и коммит.*
|
||
|
||
**1% случаев:** Нужно удалить файлы из ВСЕЙ истории (например, случайно закоммитили секреты)
|
||
|
||
**Решение:** ⚠️ **Очистка истории** (см. раздел "Когда действительно нужна очистка истории")
|
||
|
||
---
|
||
|
||
## ✅ ПРАВИЛЬНЫЙ ПОДХОД: Простое удаление из tracking
|
||
|
||
**Когда использовать:** Файлы уже в `.gitignore`, но Git их отслеживает.
|
||
|
||
**Пример проблемы:**
|
||
- Файлы в `.gitignore`: `frontend/dist-*`
|
||
- Git все еще отслеживает: 4046 файлов из `dist-*` папок
|
||
- `git status` показывает: `D frontend/dist-cache-busting/404.html` и т.д.
|
||
|
||
### ✅ Решение (ПРАВИЛЬНО):
|
||
|
||
```bash
|
||
# 1. Убедиться что файлы в .gitignore
|
||
cat frontend/.gitignore | grep dist-
|
||
|
||
# 2. Удалить из tracking (файлы останутся в рабочей директории, если есть)
|
||
git rm --cached -r frontend/dist-cache-busting/ \
|
||
frontend/dist-fast-no-image/ \
|
||
frontend/dist-via-proxy/ \
|
||
frontend/dist-zero-downtime/ 2>/dev/null || \
|
||
git add -u -- frontend/dist-*/ # Альтернатива если файлы уже удалены из рабочей директории
|
||
|
||
# 3. Проверить что файлы в staging для удаления
|
||
git status --short | grep "^D " | wc -l
|
||
# Должно показать количество удаляемых файлов
|
||
|
||
# 4. Закоммитить удаление
|
||
git commit -m "chore(frontend): удаление dist-* build-артефактов из Git tracking
|
||
|
||
- Удалены файлы из frontend/dist-cache-busting/, dist-fast-no-image/, dist-via-proxy/, dist-zero-downtime/
|
||
- Файлы были в .gitignore, но отслеживались Git (закоммичены до добавления в .gitignore)
|
||
- Build-артефакты генерируются при деплое и не должны храниться в репозитории"
|
||
|
||
# 5. Push в Gitea (для local_machine: git push origin main или SSH)
|
||
bash scripts/deployment/gitea/git-push-gitea-via-proxy.sh dev # в других репо; для local_machine: git push origin main
|
||
|
||
# 6. Проверка
|
||
git ls-files | grep -E "^frontend/dist-(zero-downtime|fast-no-image|via-proxy|cache-busting)/" | wc -l
|
||
# Должно быть: 0
|
||
```
|
||
|
||
**✅ Результат:**
|
||
- Файлы удалены из tracking (больше не отслеживаются Git)
|
||
- История НЕ переписана (SHA коммитов не изменились)
|
||
- Все коммиты сохранены
|
||
- Работает быстро и безопасно
|
||
|
||
**⚠️ ВАЖНО:** После этого файлы останутся в истории старых коммитов, но новые коммиты их не будут содержать. Это нормально для build-артефактов.
|
||
|
||
---
|
||
|
||
## ❌ КАК НЕ НАДО: git-filter-repo с --invert-paths
|
||
|
||
### ❌ КРИТИЧЕСКАЯ ОШИБКА (НЕ ДЕЛАТЬ ТАК!):
|
||
|
||
```bash
|
||
# ❌ НЕПРАВИЛЬНО - УНИЧТОЖАЕТ ВСЕ КОММИТЫ!
|
||
git filter-repo \
|
||
--path frontend/dist-zero-downtime/ \
|
||
--path frontend/dist-fast-no-image/ \
|
||
--path frontend/dist-via-proxy/ \
|
||
--path frontend/dist-cache-busting/ \
|
||
--invert-paths \
|
||
--force
|
||
```
|
||
|
||
**Что происходит:**
|
||
- ❌ `git-filter-repo` с `--invert-paths` **УНИЧТОЖАЕТ ВСЕ КОММИТЫ**
|
||
- ❌ Все tree objects становятся пустыми (0 файлов в коммитах)
|
||
- ❌ Репозиторий полностью сломан
|
||
- ❌ Нужно восстанавливать из бэкапа
|
||
|
||
**Почему это происходит:**
|
||
- `--invert-paths` означает "сохранить все, кроме указанных путей"
|
||
- Но если указанные пути были в КАЖДОМ коммите, то все коммиты становятся пустыми
|
||
- Git не может создать коммит без файлов
|
||
|
||
**Реальный пример ошибки (2026-02-27):**
|
||
```
|
||
# После git-filter-repo:
|
||
git ls-tree -r HEAD --name-only | wc -l
|
||
# Результат: 0 (ВСЕ КОММИТЫ ПУСТЫЕ!)
|
||
|
||
git log --oneline -5
|
||
# Коммиты есть, но в них НЕТ ФАЙЛОВ
|
||
```
|
||
|
||
**✅ Решение после ошибки:**
|
||
```bash
|
||
# Восстановить из бэкапа
|
||
rm -rf .git
|
||
mv .git.backup-20260227-171445 .git
|
||
|
||
# Использовать ПРАВИЛЬНЫЙ подход (см. выше)
|
||
git rm --cached -r frontend/dist-*/ && git commit -m "..."
|
||
```
|
||
|
||
---
|
||
|
||
## ⚠️ Когда действительно нужна очистка истории
|
||
|
||
**Редкие случаи, когда нужна очистка истории:**
|
||
|
||
1. **Случайно закоммитили секреты** (пароли, API ключи, токены)
|
||
- ⚠️ Критично: секреты в истории = уязвимость безопасности
|
||
- ✅ Нужна полная очистка истории
|
||
|
||
2. **Огромные бинарные файлы** (видео, большие изображения, базы данных)
|
||
- ⚠️ Размер репозитория > 2GB из-за истории
|
||
- ✅ Нужна очистка для уменьшения размера
|
||
|
||
3. **Юридические требования** (удаление файлов по запросу)
|
||
- ⚠️ Требуется полное удаление из истории
|
||
- ✅ Нужна очистка истории
|
||
|
||
**⚠️ ВАЖНО:** Для build-артефактов (`dist/`, `build/`) очистка истории **НЕ НУЖНА** - достаточно простого удаления из tracking!
|
||
|
||
---
|
||
|
||
## 🧹 Очистка истории от файлов с секретами (docs)
|
||
|
||
**Когда применять:** после замены реальных секретов на плейсхолдеры в документации (см. [SECRETS_AND_FILE_PERMISSIONS_POLICY.md](../../security/SECRETS_AND_FILE_PERMISSIONS_POLICY.md)) нужно удалить из истории Git старые версии этих файлов, чтобы секреты нельзя было извлечь из старых коммитов.
|
||
|
||
**Гарантированно безопасный порядок (обязательно):**
|
||
|
||
1. **Бэкап репозитория (ОБЯЗАТЕЛЬНО)** — без бэкапа не приступать.
|
||
2. Запуск скрипта, который делает бэкап сам и выполняет очистку по списку путей.
|
||
3. Проверки целостности (в скрипте).
|
||
4. Применение очищенной версии на Gitea только после бэкапа репо на сервере.
|
||
|
||
### Скрипт очистки (бэкап + filter-repo + проверки)
|
||
|
||
Используется готовый скрипт, который:
|
||
|
||
- Создаёт резервную копию (`git clone --mirror`) в каталог рядом с репо.
|
||
- Клонирует репо в bare, удаляет из истории пути из списка (`git filter-repo --paths-from-file ... --invert-paths`).
|
||
- Проверяет целостность (`git ls-tree -r HEAD | wc -l` > 0, `git fsck`).
|
||
- Восстанавливает в текущем tip почищенные версии файлов (один коммит с плейсхолдерами).
|
||
|
||
**Запуск (из корня репозитория):**
|
||
|
||
```bash
|
||
# Установить git-filter-repo (один раз)
|
||
# macOS:
|
||
brew install git-filter-repo
|
||
# Linux:
|
||
# pip3 install git-filter-repo
|
||
|
||
# Запуск (бэкап создаётся скриптом автоматически)
|
||
bash scripts/maintenance/git-history-cleanup-secrets.sh /path/to/local_machine
|
||
```
|
||
|
||
**Файлы:**
|
||
|
||
- Список путей (файлы, которые удаляются из истории): `scripts/maintenance/git-history-cleanup-secrets-paths.txt` — соответствует таблице в [SECRETS_AND_FILE_PERMISSIONS_POLICY.md](../../security/SECRETS_AND_FILE_PERMISSIONS_POLICY.md) (очистка 2026-03-03).
|
||
- Скрипт: `scripts/maintenance/git-history-cleanup-secrets.sh`.
|
||
|
||
**После скрипта:** выполнить шаги из раздела ниже «Правильная очистка истории»: создание bundle из очищенного bare-репо, загрузка на сервер, **бэкап Gitea-репо на сервере**, замена objects/refs, перезапуск Gitea, обновление локального репо.
|
||
|
||
**Критично:** на production-сервере перед заменой репозитория в Gitea обязательно создать бэкап:
|
||
|
||
```bash
|
||
GITEA_REPO="/data/git/repositories/hunabgit/local_machine.git"
|
||
ssh hunab-prod "docker exec gitea cp -r $GITEA_REPO ${GITEA_REPO}.backup-$(date +%Y%m%d)"
|
||
```
|
||
|
||
---
|
||
|
||
## ✅ Правильная очистка истории (если действительно нужна)
|
||
|
||
**⚠️ КРИТИЧЕСКИ ВАЖНО:** Очистка истории переписывает все коммиты (SHA изменятся), но содержимое сохраняется.
|
||
|
||
### Шаг 1: Резервная копия (ОБЯЗАТЕЛЬНО!)
|
||
|
||
```bash
|
||
# Создать полную резервную копию репозитория
|
||
cd /path/to/repo
|
||
git clone --mirror . ../repo-backup-$(date +%Y%m%d-%H%M%S).git
|
||
|
||
# Проверить размер
|
||
du -sh ../repo-backup-*.git
|
||
```
|
||
|
||
**✅ Результат:** Резервная копия с полной историей (можно восстановить в любой момент)
|
||
|
||
### Шаг 2: Установка git-filter-repo
|
||
|
||
```bash
|
||
# macOS
|
||
brew install git-filter-repo
|
||
|
||
# Linux
|
||
pip3 install git-filter-repo
|
||
|
||
# Проверка
|
||
git filter-repo --version
|
||
```
|
||
|
||
### Шаг 3: Удаление файлов из истории (ПРАВИЛЬНЫЙ СПОСОБ)
|
||
|
||
**⚠️ КРИТИЧЕСКИ ВАЖНО:** Используйте `--path` БЕЗ `--invert-paths` для удаления конкретных файлов!
|
||
|
||
```bash
|
||
# Создать bare clone для безопасной работы
|
||
cd /tmp
|
||
git clone --mirror /path/to/repo repo-clean.git
|
||
|
||
# ✅ ПРАВИЛЬНО: Удалить конкретные файлы/папки
|
||
cd repo-clean.git
|
||
git filter-repo \
|
||
--path frontend/dist-zero-downtime/ \
|
||
--path frontend/dist-fast-no-image/ \
|
||
--path frontend/dist-via-proxy/ \
|
||
--path frontend/dist-cache-busting/ \
|
||
--path-glob '*.secret' \
|
||
--path-glob '*.key' \
|
||
--invert-paths \
|
||
--force
|
||
|
||
# ❌ НЕПРАВИЛЬНО: --invert-paths может уничтожить все коммиты!
|
||
# Используйте ТОЛЬКО если уверены что файлы НЕ в каждом коммите
|
||
|
||
# Очистить reflog и неиспользуемые объекты
|
||
git reflog expire --expire=now --all
|
||
git gc --prune=now --aggressive
|
||
```
|
||
|
||
**⚠️ КРИТИЧЕСКОЕ ПРЕДУПРЕЖДЕНИЕ:**
|
||
- `--invert-paths` **ОПАСЕН** - может уничтожить все коммиты если указанные пути были в каждом коммите
|
||
- **Лучше использовать:** `--path` для удаления конкретных файлов БЕЗ `--invert-paths`
|
||
- **Проверяйте результат:** `git ls-tree -r HEAD --name-only | wc -l` должно быть > 0!
|
||
|
||
### Шаг 4: Проверка целостности (КРИТИЧЕСКИ ВАЖНО!)
|
||
|
||
```bash
|
||
cd repo-clean.git
|
||
|
||
# ✅ КРИТИЧЕСКАЯ ПРОВЕРКА: Файлы в коммитах
|
||
git ls-tree -r HEAD --name-only | wc -l
|
||
# ДОЛЖНО БЫТЬ > 0! Если 0 - репозиторий сломан, восстанавливайте из бэкапа!
|
||
|
||
# Проверить размер
|
||
du -sh .
|
||
# Должно быть меньше оригинала
|
||
|
||
# Проверить количество коммитов
|
||
git log --oneline --all | wc -l
|
||
# Должно быть идентично оригиналу
|
||
|
||
# Проверить что файлы удалены
|
||
git rev-list --all --objects | grep -E "(dist-zero-downtime|dist-fast-no-image)" | wc -l
|
||
# Должно быть: 0
|
||
|
||
# Проверить целостность
|
||
git fsck --full
|
||
# Не должно быть ошибок
|
||
|
||
# Проверить важные ветки
|
||
git branch -a | grep -E "(dev|main|staging)"
|
||
# Все важные ветки должны быть сохранены
|
||
```
|
||
|
||
**✅ Гарантии:**
|
||
- ✅ Все коммиты сохранены (количество идентично)
|
||
- ✅ **Файлы в коммитах > 0** (критично!)
|
||
- ✅ Все сообщения коммитов идентичны
|
||
- ✅ Все авторы и даты сохранены
|
||
- ✅ Все важные ветки сохранены
|
||
- ✅ Все теги сохранены
|
||
- ✅ Файлы удалены из истории
|
||
|
||
**⚠️ КРИТИЧЕСКИ ВАЖНО:** Очистка истории переписывает все коммиты (SHA изменятся), но содержимое сохраняется.
|
||
|
||
#### Шаг 1: Резервная копия (ОБЯЗАТЕЛЬНО!)
|
||
|
||
```bash
|
||
# Создать полную резервную копию репозитория
|
||
cd /path/to/repo
|
||
git clone --mirror . ../repo-backup-$(date +%Y%m%d-%H%M%S).git
|
||
|
||
# Проверить размер
|
||
du -sh ../repo-backup-*.git
|
||
```
|
||
|
||
**✅ Результат:** Резервная копия с полной историей (можно восстановить в любой момент)
|
||
|
||
#### Шаг 2: Установка git-filter-repo
|
||
|
||
```bash
|
||
# macOS
|
||
brew install git-filter-repo
|
||
|
||
# Linux
|
||
pip3 install git-filter-repo
|
||
|
||
# Проверка
|
||
git filter-repo --version
|
||
```
|
||
|
||
#### Шаг 3: Удаление файлов из истории
|
||
|
||
```bash
|
||
# Создать bare clone для безопасной работы
|
||
cd /tmp
|
||
git clone --mirror /path/to/repo repo-clean.git
|
||
|
||
# Удалить папки из истории
|
||
cd repo-clean.git
|
||
git filter-repo \
|
||
--path frontend/dist-zero-downtime/ \
|
||
--path frontend/dist-fast-no-image/ \
|
||
--path frontend/dist-via-proxy/ \
|
||
--path frontend/dist-cache-busting/ \
|
||
--invert-paths \
|
||
--force
|
||
|
||
# Очистить reflog и неиспользуемые объекты
|
||
git reflog expire --expire=now --all
|
||
git gc --prune=now --aggressive
|
||
```
|
||
|
||
**Параметры:**
|
||
- `--path` - путь к папке/файлу для удаления
|
||
- `--path-glob` - glob паттерн для удаления (например, `*.secret`)
|
||
- `--invert-paths` - ⚠️ **ОПАСНО!** Удалить указанные пути (остальное сохранить). Может уничтожить все коммиты!
|
||
- `--force` - принудительное выполнение
|
||
|
||
**✅ Результат:** Очищенный репозиторий без указанных файлов
|
||
|
||
**⚠️ КРИТИЧЕСКОЕ ПРЕДУПРЕЖДЕНИЕ:**
|
||
- `--invert-paths` **ОПАСЕН** - если указанные пути были в КАЖДОМ коммите, все коммиты станут пустыми!
|
||
- **Всегда проверяйте:** `git ls-tree -r HEAD --name-only | wc -l` должно быть > 0 после очистки!
|
||
- **Если результат = 0:** Репозиторий сломан, восстанавливайте из бэкапа!
|
||
|
||
#### Шаг 4: Проверка целостности (ОБЯЗАТЕЛЬНО!)
|
||
|
||
```bash
|
||
cd repo-clean.git
|
||
|
||
# Проверить размер
|
||
du -sh .
|
||
# Должно быть меньше оригинала
|
||
|
||
# Проверить количество коммитов
|
||
git log --oneline --all | wc -l
|
||
# Должно быть идентично оригиналу
|
||
|
||
# Проверить что файлы удалены
|
||
git rev-list --all --objects | grep -E "(dist-zero-downtime|dist-fast-no-image)" | wc -l
|
||
# Должно быть: 0
|
||
|
||
# Проверить целостность
|
||
git fsck --full
|
||
# Не должно быть ошибок
|
||
|
||
# Проверить важные ветки
|
||
git branch -a | grep -E "(dev|main|staging)"
|
||
# Все важные ветки должны быть сохранены
|
||
```
|
||
|
||
**✅ Гарантии:**
|
||
- ✅ Все коммиты сохранены (количество идентично)
|
||
- ✅ Все сообщения коммитов идентичны
|
||
- ✅ Все авторы и даты сохранены
|
||
- ✅ Все важные ветки сохранены
|
||
- ✅ Все теги сохранены
|
||
- ✅ Файлы удалены из истории
|
||
|
||
#### Шаг 5: Применение очищенной версии
|
||
|
||
**⚠️ ПРОБЛЕМА:** Прямой push в Gitea таймаутит из РФ, а скрипт через прокси не работает, потому что после замены `.git` нет remote tracking branches.
|
||
|
||
**✅ РЕШЕНИЕ: Bundle метод + прямое копирование на сервер**
|
||
|
||
```bash
|
||
# 1. Создать bundle из очищенного репозитория
|
||
cd /tmp/repo-clean.git
|
||
git bundle create /tmp/repo-clean.bundle --all
|
||
|
||
# 2. Загрузить bundle на production сервер
|
||
scp -i ~/.ssh/hunab_deploy_key /tmp/repo-clean.bundle hunab@209.38.32.21:/tmp/
|
||
|
||
# 3. Создать временный репозиторий из bundle на сервере
|
||
ssh hunab-prod "cd /tmp && git clone --mirror /tmp/repo-clean.bundle repo-clean.git"
|
||
|
||
# 4. Бэкап текущего Gitea репозитория
|
||
GITEA_REPO="/data/git/repositories/hunabgit/local_machine.git"
|
||
ssh hunab-prod "docker exec gitea cp -r $GITEA_REPO ${GITEA_REPO}.backup-$(date +%Y%m%d)"
|
||
|
||
# 5. Копировать очищенный репозиторий в контейнер
|
||
ssh hunab-prod "docker cp /tmp/repo-clean.git gitea:/tmp/repo-clean.git"
|
||
|
||
# 6. Заменить objects и refs в Gitea репозитории
|
||
ssh hunab-prod "docker exec gitea sh -c '
|
||
cd $GITEA_REPO
|
||
rm -rf objects packed-refs refs/heads refs/tags
|
||
cp -r /tmp/repo-clean.git/objects .
|
||
cp -r /tmp/repo-clean.git/packed-refs . 2>/dev/null || true
|
||
cp -r /tmp/repo-clean.git/refs/heads refs/ 2>/dev/null || true
|
||
cp -r /tmp/repo-clean.git/refs/tags refs/ 2>/dev/null || true
|
||
echo \"ref: refs/heads/main\" > HEAD
|
||
rm -rf refs/original filter-repo
|
||
git reflog expire --expire=now --all 2>/dev/null
|
||
git gc --prune=now 2>&1 | tail -5
|
||
chown -R git:git .
|
||
'"
|
||
|
||
# 7. Перезапустить Gitea для обновления индексов
|
||
ssh hunab-prod "docker restart gitea && sleep 5"
|
||
|
||
# 8. Проверка
|
||
ssh hunab-prod "docker exec gitea sh -c 'cd $GITEA_REPO && \
|
||
echo \"Размер: \$(du -sh .)\" && \
|
||
echo \"Коммитов: \$(git log --oneline --all | wc -l)\" && \
|
||
echo \"Файлов dist в истории: \$(git rev-list --all --objects | grep -cE \"dist-zero-downtime|dist-fast-no-image|dist-via-proxy|dist-cache-busting\" || echo 0)\" && \
|
||
echo \"Веток: \$(git branch | wc -l)\" && \
|
||
echo \"Тегов: \$(git tag | wc -l)\" && \
|
||
git log --oneline -3 main'"
|
||
```
|
||
|
||
**✅ Результат:** Gitea репозиторий обновлен очищенной версией
|
||
|
||
#### Шаг 6: Обновление локального репозитория
|
||
|
||
```bash
|
||
# Заменить .git папку очищенной версией
|
||
cd /path/to/repo
|
||
rm -rf .git
|
||
cp -r /tmp/repo-clean.git .git
|
||
|
||
# Преобразовать bare в обычный репозиторий
|
||
git config core.bare false
|
||
git config core.worktree .
|
||
|
||
# Проверить статус
|
||
git status
|
||
git log --oneline -5
|
||
```
|
||
|
||
**⚠️ ВАЖНО:** После замены `.git` могут появиться артефакты в `git status` (untracked файлы из `.git`). Это не критично - репозиторий работает корректно.
|
||
|
||
### 📊 Результаты: Простое удаление из tracking (ПРАВИЛЬНЫЙ подход)
|
||
|
||
**До удаления:**
|
||
- Файлов отслеживается: 13,281
|
||
- Файлов dist-* в tracking: 4,046
|
||
- Коммитов: 6,218
|
||
|
||
**После удаления:**
|
||
- Файлов отслеживается: 13,281 - 4,046 = 9,235
|
||
- Файлов dist-* в tracking: 0 ✅
|
||
- Коммитов: 6,218 (все сохранены, SHA не изменились) ✅
|
||
- Веток: 27 (все важные сохранены) ✅
|
||
- Тегов: 162 (все сохранены) ✅
|
||
- Время выполнения: ~30 секунд ✅
|
||
- Риск: Минимальный (простой коммит) ✅
|
||
|
||
**⚠️ ВАЖНО:** Файлы останутся в истории старых коммитов, но новые коммиты их не будут содержать. Это нормально для build-артефактов.
|
||
|
||
### 📊 Результаты: Очистка истории (если действительно нужна)
|
||
|
||
**До очистки:**
|
||
- Размер: 968 MB
|
||
- Файлов в истории: 4,046 из `dist-*` папок
|
||
- Коммитов: 6,218
|
||
|
||
**После очистки (если все прошло правильно):**
|
||
- Размер: 391 MB (экономия 577 MB, 60%)
|
||
- Файлов в истории: 0 из `dist-*` папок
|
||
- Коммитов: 6,218 (все сохранены, но SHA изменились)
|
||
- Веток: 27 (все важные сохранены)
|
||
- Тегов: 162 (все сохранены)
|
||
- Время выполнения: ~30-60 минут (с бэкапом и проверками)
|
||
- Риск: Высокий (переписывание истории) ⚠️
|
||
|
||
**❌ Результаты после ОШИБКИ (git-filter-repo с --invert-paths):**
|
||
- Файлов в коммитах: 0 (ВСЕ КОММИТЫ ПУСТЫЕ!) ❌
|
||
- Репозиторий: СЛОМАН ❌
|
||
- Решение: Восстановление из бэкапа ✅
|
||
|
||
### 🛡️ Механизмы защиты
|
||
|
||
**Для простого удаления из tracking:**
|
||
1. ✅ **Проверка .gitignore:** Убедиться что файлы в `.gitignore`
|
||
2. ✅ **Проверка staging:** `git status --short | grep "^D "` показывает удаляемые файлы
|
||
3. ✅ **Проверка после коммита:** `git ls-files | grep dist- | wc -l` = 0
|
||
|
||
**Для очистки истории (если действительно нужна):**
|
||
1. ✅ **Резервная копия:** Полная копия оригинального репозитория (ОБЯЗАТЕЛЬНО!)
|
||
2. ✅ **Бэкап на сервере:** Копия Gitea репозитория перед заменой
|
||
3. ✅ **КРИТИЧЕСКАЯ проверка:** `git ls-tree -r HEAD --name-only | wc -l` > 0 после очистки!
|
||
4. ✅ **Проверка целостности:** `git fsck --full` перед применением
|
||
5. ✅ **Валидация:** Проверка количества коммитов, веток, тегов, файлов в коммитах
|
||
|
||
### ⚠️ Критические ошибки и решения
|
||
|
||
#### ❌ Ошибка 0: git-filter-repo уничтожил все коммиты (КРИТИЧЕСКАЯ!)
|
||
|
||
**Проблема:** После `git-filter-repo --invert-paths` все коммиты стали пустыми (0 файлов).
|
||
|
||
**Симптомы:**
|
||
```bash
|
||
git ls-tree -r HEAD --name-only | wc -l
|
||
# Результат: 0 (ВСЕ КОММИТЫ ПУСТЫЕ!)
|
||
|
||
git log --oneline -5
|
||
# Коммиты есть, но в них НЕТ ФАЙЛОВ
|
||
|
||
git status
|
||
# Показывает ВСЕ файлы как untracked
|
||
```
|
||
|
||
**Причина:** `--invert-paths` удалил указанные пути из ВСЕХ коммитов. Если эти пути были в каждом коммите, все коммиты стали пустыми.
|
||
|
||
**✅ Решение:**
|
||
```bash
|
||
# 1. Восстановить из бэкапа
|
||
rm -rf .git
|
||
mv .git.backup-20260227-171445 .git # Используйте ваш бэкап
|
||
|
||
# 2. Использовать ПРАВИЛЬНЫЙ подход (простое удаление из tracking)
|
||
git rm --cached -r frontend/dist-*/ && git commit -m "..."
|
||
|
||
# 3. НЕ использовать git-filter-repo для build-артефактов!
|
||
```
|
||
|
||
**Профилактика:**
|
||
- ✅ **ВСЕГДА** проверяйте `git ls-tree -r HEAD --name-only | wc -l` после git-filter-repo
|
||
- ✅ **ВСЕГДА** создавайте полный бэкап перед очисткой истории
|
||
- ✅ **НЕ используйте** `--invert-paths` для файлов, которые были в каждом коммите
|
||
- ✅ **Для build-артефактов** используйте простое удаление из tracking (см. "ПРАВИЛЬНЫЙ ПОДХОД" выше)
|
||
|
||
#### Ошибка 1: Прямой push таймаутит
|
||
|
||
**Проблема:** `git push --force` зависает с таймаутом из РФ.
|
||
|
||
**Решение:** Использовать bundle метод + прямое копирование на сервер (см. Шаг 5).
|
||
|
||
#### Ошибка 2: Скрипт через прокси не работает
|
||
|
||
**Проблема:** После замены `.git` нет remote tracking branches (`origin/dev` не существует).
|
||
|
||
**Решение:** Bundle метод обходит эту проблему, так как работает напрямую с файловой системой.
|
||
|
||
#### Ошибка 3: Файлы из `.git` в корне проекта
|
||
|
||
**Проблема:** После замены `.git` git status показывает untracked файлы (COMMIT_EDITMSG, HEAD, config и т.д.).
|
||
|
||
**Решение:** Это артефакты git status - файлы не существуют в корне, можно игнорировать. Репозиторий работает корректно.
|
||
|
||
#### Ошибка 4: Gitea не видит изменения
|
||
|
||
**Проблема:** После замены объектов Gitea не обновляет индекс.
|
||
|
||
**Решение:**
|
||
1. Удалить `refs/original` и `filter-repo` из репозитория
|
||
2. Очистить reflog: `git reflog expire --expire=now --all`
|
||
3. Перезапустить Gitea: `docker restart gitea`
|
||
|
||
### 🔄 Восстановление из резервной копии
|
||
|
||
Если что-то пошло не так:
|
||
|
||
```bash
|
||
# Восстановить локальный репозиторий
|
||
cd /path/to/repo
|
||
rm -rf .git
|
||
git clone --mirror /path/to/backup/repo-backup-*.git .git
|
||
git config core.bare false
|
||
git config core.worktree .
|
||
|
||
# Восстановить Gitea репозиторий на сервере
|
||
ssh hunab-prod "docker exec gitea rm -rf $GITEA_REPO && \
|
||
docker exec gitea cp -r ${GITEA_REPO}.backup-* $GITEA_REPO && \
|
||
docker exec gitea chown -R git:git $GITEA_REPO && \
|
||
docker restart gitea"
|
||
```
|
||
|
||
### 📋 Чеклист: Простое удаление из tracking (99% случаев)
|
||
|
||
**Для build-артефактов (`dist/`, `build/`) - используйте этот чеклист:**
|
||
|
||
- [ ] Проверено что файлы в `.gitignore`
|
||
- [ ] Удалены файлы из tracking: `git rm --cached -r frontend/dist-*/`
|
||
- [ ] Проверено что файлы в staging для удаления: `git status --short | grep "^D "`
|
||
- [ ] Создан коммит с описанием удаления
|
||
- [ ] Push в Gitea (local_machine: `git push origin main` или SSH)
|
||
- [ ] Проверено что файлы больше не отслеживаются: `git ls-files | grep dist- | wc -l` = 0
|
||
- [ ] Обновлен CHANGELOG с описанием операции
|
||
|
||
**✅ Результат:** Файлы удалены из tracking, история НЕ переписана, все работает быстро и безопасно.
|
||
|
||
---
|
||
|
||
### 📋 Чеклист: Очистка истории (1% случаев - только для секретов/юридических требований)
|
||
|
||
**⚠️ ВАЖНО:** Используйте ТОЛЬКО если действительно нужно удалить файлы из ВСЕЙ истории!
|
||
|
||
- [ ] Определено что простая очистка tracking НЕДОСТАТОЧНА (секреты, юридические требования)
|
||
- [ ] Создана резервная копия оригинального репозитория
|
||
- [ ] Установлен `git-filter-repo`
|
||
- [ ] Создан bare clone для безопасной работы
|
||
- [ ] Удалены файлы из истории через `git-filter-repo` (БЕЗ `--invert-paths` если возможно!)
|
||
- [ ] **КРИТИЧЕСКАЯ ПРОВЕРКА:** `git ls-tree -r HEAD --name-only | wc -l` > 0 (если 0 - репозиторий сломан!)
|
||
- [ ] Очищены reflog и неиспользуемые объекты
|
||
- [ ] Проверена целостность (коммиты, ветки, теги, файлы в коммитах > 0)
|
||
- [ ] Создан bundle из очищенного репозитория
|
||
- [ ] Загружен bundle на production сервер (в `/home/hunab/`, НЕ в `/tmp/` - tmpfs только 2GB!)
|
||
- [ ] Создан бэкап Gitea репозитория на сервере
|
||
- [ ] Заменены objects и refs в Gitea репозитории
|
||
- [ ] Удалены `refs/original` и `filter-repo`
|
||
- [ ] Перезапущен Gitea
|
||
- [ ] Проверен результат (размер, коммиты, файлы в коммитах > 0)
|
||
- [ ] Обновлен локальный репозиторий
|
||
- [ ] Обновлен CHANGELOG с описанием операции
|
||
|
||
### 📚 Связанные документы
|
||
|
||
- **[Deployment Changelog](../CHANGELOG.md)** - История изменений deployment (включает очистку истории)
|
||
- **[Git Filter Repo Documentation](https://github.com/newren/git-filter-repo)** - Официальная документация git-filter-repo
|
||
|
||
---
|
||
|
||
**Последнее обновление:** 2026-02-27
|
||
**Версия документа:** 1.6
|
||
**Статус:** ✅ Gitea полностью развернут и работает стабильно
|
||
**Изменения:**
|
||
- Добавлен резервный способ коммитов через временный скрипт (2026-02-16)
|
||
- Добавлен гайд по очистке истории Git от build-артефактов (2026-02-27)
|
||
- **КРИТИЧЕСКОЕ ОБНОВЛЕНИЕ (2026-02-27):** Добавлены четкие предупреждения о том, как НЕ надо делать очистку истории:
|
||
- ❌ `git-filter-repo --invert-paths` УНИЧТОЖАЕТ все коммиты (реальный пример ошибки 2026-02-27)
|
||
- ✅ Правильный подход: простое удаление из tracking (`git rm --cached`) для build-артефактов (99% случаев)
|
||
- ✅ Очистка истории нужна ТОЛЬКО для секретов/юридических требований (1% случаев)
|
||
- ✅ Добавлены критические проверки (`git ls-tree -r HEAD --name-only | wc -l` > 0) и механизмы защиты
|
||
- **ОПТИМИЗАЦИЯ (2026-02-27):** Исправлена медленная верификация push - заменен `git fetch origin` на `git update-ref` для мгновенного обновления tracking ref без сетевых запросов
|
||
|