2.2 Git и системы контроля версий #
🎯 Зачем нужен Git #
Git — это система контроля версий, которая отслеживает изменения в файлах и позволяет:
- Сохранять историю изменений
- Работать в команде без конфликтов
- Откатываться к предыдущим версиям
- Создавать ветки для экспериментов
Без Git:
project_v1.zip
project_v2.zip
project_v2_final.zip
project_v2_final_REALLY_FINAL.zip
project_v2_final_REALLY_FINAL_fixed.zip
С Git:
git log --oneline
a1b2c3d Add user authentication
d4e5f6g Fix login bug
g7h8i9j Update documentation
j1k2l3m Initial commit
⚙️ Основы Git #
Установка и настройка #
# Установка (Ubuntu/Debian)
sudo apt update && sudo apt install git
# Первоначальная настройка
git config --global user.name "Ваше Имя"
git config --global user.email "your.email@example.com"
git config --global init.defaultBranch main
# Проверка настроек
git config --list
Создание репозитория #
# Новый проект
mkdir my-project && cd my-project
git init
# Клонирование существующего
git clone https://github.com/user/repo.git
cd repo
Основной workflow #
# 1. Проверить статус
git status
# 2. Добавить файлы в staging
git add file.txt # конкретный файл
git add . # все изменения
git add *.py # по маске
# 3. Создать коммит
git commit -m "Add user registration feature"
# 4. Отправить на сервер
git push origin main
🌿 Работа с ветками (Branching) #
Зачем нужны ветки #
main branch: A---B---C---F---G
\ /
feature branch: D---E---/
A,B,C - стабильный код
D,E - новая фича
F - merge фичи в main
G - дальнейшая разработка
Основные команды веток #
# Посмотреть ветки
git branch # локальные ветки
git branch -r # удаленные ветки
git branch -a # все ветки
# Создать и переключиться на ветку
git checkout -b feature/user-auth
# или новым способом
git switch -c feature/user-auth
# Переключиться на существующую ветку
git checkout main
git switch main
# Удалить ветку
git branch -d feature/user-auth # только если смержена
git branch -D feature/user-auth # принудительно
Слияние веток (Merge) #
# Переключиться на main
git checkout main
# Способ 1: Слить ветку feature (создает merge коммит)
git merge feature/user-auth
# Способ 2: Rebase для линейной истории (без merge коммита)
git rebase main feature/user-auth # переносит коммиты на верх main
git checkout main
git merge feature/user-auth # fast-forward merge
# Интерактивный rebase для очистки истории
git rebase -i HEAD~3 # объединить/изменить последние 3 коммита
# Если есть конфликты - решить их и:
git add .
git commit -m "Resolve merge conflicts" # для merge
# или
git rebase --continue # для rebase
🔄 Git Flow стратегии #
1. GitHub Flow (простая) #
main ←------ feature/login
←------ feature/payments
←------ hotfix/security-bug
Процесс:
- Создаем ветку от main
- Разрабатываем фичу
- Создаем Pull Request
- После review мержим в main
- Удаляем ветку
2. Git Flow (сложная) #
main ←------ release/v1.0 ←------ develop
hotfix ↗ ↑
main feature
Ветки:
- main — продакшн код
- develop — разработка
- feature/ — новые фичи
- release/ — подготовка релиза
- hotfix/ — срочные исправления
3. Trunk-based (для CI/CD) #
main: A---B---C---D---E---F---G
\ / \ /
X---Y Z-/
Короткоживущие ветки, частые мержи
📝 Хорошие практики коммитов #
Структура коммита #
тип(область): краткое описание
Более подробное описание того, что и зачем
было сделано. Максимум 72 символа в строке.
- Добавлен валидация email
- Исправлена ошибка с регистрацией
- Обновлена документация API
Fixes #123
Типы коммитов #
feat: новая фича
fix: исправление бага
docs: документация
style: форматирование кода
refactor: рефакторинг
test: добавление тестов
chore: обновление зависимостей
# Примеры
git commit -m "feat(auth): add user registration endpoint"
git commit -m "fix(login): resolve session timeout issue"
git commit -m "docs(api): update authentication guide"
Плохие vs хорошие коммиты #
# ❌ Плохие коммиты
git commit -m "fix"
git commit -m "stuff"
git commit -m "changes"
git commit -m "asdfgh"
# ✅ Хорошие коммиты
git commit -m "fix(auth): resolve JWT token expiration"
git commit -m "feat(user): add profile picture upload"
git commit -m "refactor(db): optimize user queries performance"
🐙 GitHub/GitLab для команд #
Pull Requests / Merge Requests #
Создание PR:
# 1. Пушим ветку
git push origin feature/user-profile
# 2. На GitHub создаем PR через веб-интерфейс
# 3. Добавляем описание, reviewers, labels
Шаблон описания PR:
## Что сделано
- Добавлена страница профиля пользователя
- Реализована загрузка аватара
- Добавлены тесты для новой функциональности
## Как тестировать
1. Зайти на /profile
2. Загрузить картинку
3. Проверить сохранение настроек
## Скриншоты
 - 2.2
## Checklist
- [x] Тесты написаны и проходят
- [x] Документация обновлена
- [x] Нет конфликтов с main
- [x] Проведен code review
Code Review процесс #
Reviewer проверяет:
✅ Логику кода
✅ Безопасность
✅ Производительность
✅ Тесты
✅ Соответствие стандартам команды
Типичные комментарии:
💡 "Можно использовать more efficient алгоритм"
🐛 "Здесь может возникнуть NullPointerException"
📝 "Добавьте комментарий к сложной логике"
✨ "Отличное решение!"
🔧 Git в DevOps workflow #
Pre-commit hooks #
#!/bin/sh
# .git/hooks/pre-commit
echo "Running pre-commit checks..."
# Запуск линтера
npm run lint
if [ $? -ne 0 ]; then
echo "❌ Linting failed. Please fix errors before committing."
exit 1
fi
# Запуск тестов
npm test
if [ $? -ne 0 ]; then
echo "❌ Tests failed. Please fix tests before committing."
exit 1
fi
echo "✅ All checks passed!"
Git + CI/CD интеграция #
# .github/workflows/ci.yml
name: CI/CD Pipeline
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Setup Node.js
uses: actions/setup-node@v2
with:
node-version: '16'
- name: Install dependencies
run: npm ci
- name: Run tests
run: npm test
- name: Run linter
run: npm run lint
deploy:
needs: test
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main'
steps:
- name: Deploy to production
run: |
echo "Deploying to production..."
# Команды деплоя
🔍 Полезные Git команды #
История и логи #
# Красивый лог
git log --oneline --graph --decorate --all
# Поиск в истории
git log --grep="auth" # поиск в сообщениях коммитов
git log -S "function_name" # поиск добавления/удаления кода
git log --author="John Doe" # коммиты автора
# Изменения в файле
git log -p filename.txt # все изменения файла
git blame filename.txt # кто что менял
Отмена изменений #
# Отменить изменения в рабочей директории
git checkout -- file.txt # один файл
git checkout . # все файлы
# Убрать из staging
git reset HEAD file.txt # один файл
git reset HEAD # все файлы
# Отменить последний коммит (но сохранить изменения)
git reset --soft HEAD~1
# Отменить последний коммит (и удалить изменения)
git reset --hard HEAD~1
# Создать коммит, отменяющий предыдущий
git revert HEAD
Stashing (временное сохранение) #
# Сохранить текущие изменения
git stash
git stash push -m "Work in progress on feature X"
# Посмотреть stashes
git stash list
# Применить stash
git stash pop # применить и удалить
git stash apply # применить, но оставить в stash
# Удалить stash
git stash drop stash@{0}
git stash clear # удалить все
🎯 Практические сценарии #
Сценарий 1: Hotfix в продакшене #
# 1. Создать hotfix ветку от main
git checkout main
git pull origin main
git checkout -b hotfix/security-fix
# 2. Исправить проблему
vim security_patch.py
git add security_patch.py
git commit -m "fix(security): patch SQL injection vulnerability"
# 3. Смержить в main
git checkout main
git merge hotfix/security-fix
# 4. Создать тег релиза
git tag -a v1.0.1 -m "Security hotfix"
# 5. Задеплоить и очистить
git push origin main --tags
git branch -d hotfix/security-fix
Сценарий 2: Разрешение конфликтов #
# При merge возник конфликт
git merge feature/payments
# CONFLICT (content): Merge conflict in app.py
# Открыть файл, увидеть:
<<<<<<< HEAD
def calculate_total(items):
return sum(item.price for item in items)
=======
def calculate_total(items):
return sum(item.price * item.quantity for item in items)
>>>>>>> feature/payments
# Разрешить конфликт:
def calculate_total(items):
return sum(item.price * item.quantity for item in items)
# Завершить merge
git add app.py
git commit -m "Resolve merge conflict in calculate_total"
🛡️ Безопасность в Git #
Что НИКОГДА не коммитить #
# ❌ Секреты и пароли
DATABASE_PASSWORD=supersecret123
API_KEY=sk-1234567890abcdef
# ❌ Конфиденциальные файлы
.env
secrets.json
private_key.pem
*.p12
# ❌ Большие бинарные файлы
video.mp4
database.dump
node_modules/
.gitignore файл #
# Dependencies
node_modules/
vendor/
# Environment variables
.env
.env.local
.env.production
# Logs
*.log
logs/
# OS generated files
.DS_Store
Thumbs.db
# IDE files
.vscode/
.idea/
*.swp
# Build outputs
dist/
build/
*.pyc
Git-crypt для чувствительных данных #
# Установка git-crypt
sudo apt install git-crypt
# Инициализация в репозитории
git-crypt init
# Настройка .gitattributes
echo "secrets.json filter=git-crypt diff=git-crypt" >> .gitattributes
# Добавление GPG ключа пользователя
git-crypt add-gpg-user user@example.com
# Теперь secrets.json будет зашифрован в Git
📚 Полезные ресурсы #
Обучающие материалы #
- Pro Git Book - официальная книга
- GitHub Git Handbook
- Atlassian Git Tutorials
Инструменты #
- GitKraken - GUI клиент для Git
- SourceTree - бесплатный GUI от Atlassian
- VS Code - отличная встроенная поддержка Git
- git-flow - расширение для Git Flow workflow
Cheat sheets #
# Полезные алиасы для .gitconfig
[alias]
st = status
co = checkout
br = branch
ci = commit
unstage = reset HEAD --
last = log -1 HEAD
visual = !gitk
lg = log --oneline --graph --decorate --all
amend = commit --amend --no-edit
🎯 Практические задания #
Задание 1: Основы Git (45 минут) #
# 1. Настройка Git (если еще не сделано)
git config --global user.name "Ваше Имя"
git config --global user.email "your.email@example.com"
git config --global init.defaultBranch main
# 2. Создайте новый проект
mkdir ~/git-practice
cd ~/git-practice
git init
# 3. Создайте базовую структуру проекта
cat > README.md << 'EOF'
# Git Practice Project
Проект для изучения основ Git и GitHub.
## Описание
Этот проект создан для практики работы с Git.
## Автор
Ваше имя
EOF
# 4. Создайте файл .gitignore
cat > .gitignore << 'EOF'
# Временные файлы
*.tmp
*.swp
*~
# Логи
*.log
logs/
# Зависимости
node_modules/
.env
EOF
# 5. Сделайте первый коммит
git add README.md .gitignore
git commit -m "Initial commit: add README and .gitignore"
# 6. Создайте файл с кодом
mkdir src
cat > src/app.py << 'EOF'
#!/usr/bin/env python3
"""
Простое приложение для демонстрации Git workflow
"""
def greet(name):
"""Функция приветствия"""
return f"Привет, {name}!"
def main():
"""Главная функция"""
user_name = "DevOps Engineer"
message = greet(user_name)
print(message)
if __name__ == "__main__":
main()
EOF
# 7. Добавьте коммит с кодом
git add src/app.py
git commit -m "Add basic Python application"
# 8. Создайте ветку для новой функции
git checkout -b feature/add-config
# 9. Добавьте конфигурационный файл
mkdir config
cat > config/settings.yaml << 'EOF'
app:
name: "Git Practice App"
version: "1.0.0"
debug: true
logging:
level: "INFO"
format: "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
EOF
# 10. Коммит в feature ветке
git add config/settings.yaml
git commit -m "Add application configuration"
# 11. Переключитесь обратно в main и смержите
git checkout main
git merge feature/add-config
# 12. Проверьте историю
git log --oneline --graph
Проверка: У вас должен быть репозиторий с несколькими коммитами и смерж из feature ветки.
Задание 2: Работа с конфликтами (30 минут) #
# 1. Создайте две ветки для симуляции конфликта
git checkout -b feature/update-readme-v1
git checkout -b feature/update-readme-v2
# 2. В первой ветке измените README
git checkout feature/update-readme-v1
cat > README.md << 'EOF'
# Git Practice Project
Проект для изучения основ Git и GitHub.
## Описание
Этот проект создан для практики работы с Git.
Добавлены новые возможности для управления конфигурацией.
## Возможности
- Базовое приложение на Python
- YAML конфигурация
- Гибкие настройки логирования
## Автор
Ваше имя
EOF
git add README.md
git commit -m "Update README: add features section"
# 3. Во второй ветке тоже измените README (в том же месте)
git checkout feature/update-readme-v2
cat > README.md << 'EOF'
# Git Practice Project
Проект для изучения основ Git и GitHub.
## Описание
Этот проект создан для практики работы с Git.
Включает примеры лучших практик DevOps.
## Технологии
- Python 3
- YAML для конфигурации
- Git для контроля версий
## Автор
Ваше имя
EOF
git add README.md
git commit -m "Update README: add technologies section"
# 4. Смержите первую ветку в main
git checkout main
git merge feature/update-readme-v1
# 5. Попробуйте смержить вторую (получите конфликт)
git merge feature/update-readme-v2
# 6. Разрешите конфликт вручную
# Откройте README.md в редакторе и объедините изменения
cat > README.md << 'EOF'
# Git Practice Project
Проект для изучения основ Git и GitHub.
## Описание
Этот проект создан для практики работы с Git.
Добавлены новые возможности для управления конфигурацией.
Включает примеры лучших практик DevOps.
## Возможности
- Базовое приложение на Python
- YAML конфигурация
- Гибкие настройки логирования
## Технологии
- Python 3
- YAML для конфигурации
- Git для контроля версий
## Автор
Ваше имя
EOF
# 7. Завершите merge
git add README.md
git commit -m "Merge feature/update-readme-v2: resolve conflict"
# 8. Посмотрите на итоговую историю
git log --oneline --graph --all
Проверка: Вы должны успешно разрешить конфликт и увидеть merge commit в истории.
Задание 3: GitHub workflow (40 минут) #
# 1. Создайте репозиторий на GitHub (через веб-интерфейс)
# Название: git-devops-practice
# Публичный репозиторий
# Не создавайте README (у нас уже есть)
# 2. Подключите локальный репозиторий к GitHub
git remote add origin https://github.com/ВАШ-USERNAME/git-devops-practice.git
# 3. Пушните код на GitHub
git push -u origin main
# 4. Создайте новую ветку для фичи
git checkout -b feature/add-tests
# 5. Добавьте файл с тестами
mkdir tests
cat > tests/test_app.py << 'EOF'
#!/usr/bin/env python3
"""
Тесты для приложения
"""
import sys
import os
sys.path.append(os.path.join(os.path.dirname(__file__), '..', 'src'))
from app import greet
def test_greet():
"""Тест функции приветствия"""
result = greet("DevOps")
expected = "Привет, DevOps!"
assert result == expected, f"Expected '{expected}', got '{result}'"
print("✅ test_greet passed")
def test_greet_empty():
"""Тест с пустым именем"""
result = greet("")
expected = "Привет, !"
assert result == expected, f"Expected '{expected}', got '{result}'"
print("✅ test_greet_empty passed")
if __name__ == "__main__":
test_greet()
test_greet_empty()
print("🎉 All tests passed!")
EOF
# 6. Добавьте простой скрипт для запуска тестов
cat > run_tests.sh << 'EOF'
#!/bin/bash
echo "🧪 Running tests..."
python3 tests/test_app.py
echo "🔍 Running code style checks..."
python3 -m py_compile src/app.py tests/test_app.py
echo "✅ All checks passed!"
EOF
chmod +x run_tests.sh
# 7. Коммит изменений
git add tests/ run_tests.sh
git commit -m "Add basic tests and test runner"
# 8. Пушните ветку на GitHub
git push origin feature/add-tests
# 9. Создайте Pull Request через веб-интерфейс GitHub
# - Перейдите на GitHub
# - Нажмите "Compare & pull request"
# - Заполните описание PR
# - Создайте PR
Задание 4: GitHub Actions CI/CD (35 минут) #
# 1. Создайте каталог для GitHub Actions
mkdir -p .github/workflows
# 2. Создайте workflow файл
cat > .github/workflows/ci.yml << 'EOF'
name: CI/CD Pipeline
on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main ]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Python 3.9
uses: actions/setup-python@v3
with:
python-version: 3.9
- name: Install dependencies
run: |
python -m pip install --upgrade pip
# pip install -r requirements.txt # если есть файл зависимостей
- name: Run tests
run: |
python tests/test_app.py
- name: Check code syntax
run: |
python -m py_compile src/app.py
python -m py_compile tests/test_app.py
- name: Run application
run: |
python src/app.py
security-scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Run security scan
run: |
echo "🔍 Running security checks..."
# Проверяем, что нет секретов в коде
if grep -r "password\|secret\|key\|token" --include="*.py" --include="*.yaml" .; then
echo "❌ Potential secrets found in code!"
exit 1
else
echo "✅ No secrets detected"
fi
build:
needs: [test, security-scan]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Build application
run: |
echo "🏗️ Building application..."
mkdir -p dist
cp -r src/ dist/
cp -r config/ dist/
cp README.md dist/
echo "✅ Build completed"
- name: Archive build artifacts
uses: actions/upload-artifact@v3
with:
name: application-build
path: dist/
EOF
# 3. Коммит workflow
git add .github/workflows/ci.yml
git commit -m "Add GitHub Actions CI/CD pipeline"
# 4. Добавьте файл с зависимостями проекта
cat > requirements.txt << 'EOF'
# Производственные зависимости
pyyaml>=6.0
# Зависимости для разработки
pytest>=7.0
flake8>=4.0
EOF
git add requirements.txt
git commit -m "Add project dependencies"
# 5. Обновите workflow для использования requirements.txt
cat > .github/workflows/ci.yml << 'EOF'
name: CI/CD Pipeline
on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main ]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Python 3.9
uses: actions/setup-python@v3
with:
python-version: 3.9
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
- name: Lint with flake8
run: |
# Остановить build если есть синтаксические ошибки
flake8 src/ tests/ --count --select=E9,F63,F7,F82 --show-source --statistics
# Предупреждения для остальных ошибок
flake8 src/ tests/ --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics
- name: Test with pytest
run: |
python tests/test_app.py
- name: Run application smoke test
run: |
timeout 5s python src/app.py || test $? = 124
security-scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Run security scan
run: |
echo "🔍 Running security checks..."
if grep -r "password\|secret\|key\|token" --include="*.py" --include="*.yaml" .; then
echo "❌ Potential secrets found in code!"
exit 1
else
echo "✅ No secrets detected"
fi
build:
needs: [test, security-scan]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Build application package
run: |
echo "🏗️ Building application..."
mkdir -p dist
cp -r src/ dist/
cp -r config/ dist/
cp requirements.txt dist/
cp README.md dist/
# Создание версии
echo "1.0.0-$(git rev-parse --short HEAD)" > dist/VERSION
echo "✅ Build completed"
- name: Archive build artifacts
uses: actions/upload-artifact@v3
with:
name: application-build-${{ github.sha }}
path: dist/
EOF
git add .github/workflows/ci.yml
git commit -m "Update CI pipeline with linting and versioning"
# 6. Пушните все изменения
git push origin feature/add-tests
Проверка: После push на GitHub должен запуститься CI pipeline. Проверьте вкладку “Actions” в репозитории.
Задание 5: Продвинутые Git операции (25 минут) #
# 1. Интерактивный rebase для очистки истории
# Создайте несколько "грязных" коммитов
echo "debug line" >> src/app.py
git add src/app.py
git commit -m "debug"
echo "# TODO: fix this" >> src/app.py
git add src/app.py
git commit -m "wip"
echo "more debug" >> src/app.py
git add src/app.py
git commit -m "temp commit"
# 2. Используйте интерактивный rebase для очистки
git rebase -i HEAD~3
# В редакторе измените pick на squash для объединения коммитов
# pick → s (squash) для объединения в предыдущий коммит
# 3. Создайте signed коммиты (если настроен GPG)
git config --global commit.gpgsign true # если есть GPG ключ
# 4. Создайте и примените патч
git format-patch -1 HEAD --stdout > my-feature.patch
# git apply my-feature.patch # для применения в другом репозитории
# 5. Используйте git stash для временного сохранения
echo "temporary changes" >> README.md
git stash push -m "Temporary README changes"
git stash list
git stash pop
# 6. Работа с submodules (пример)
# git submodule add https://github.com/example/library.git lib/external
# git submodule init
# git submodule update
# 7. Продвинутый поиск в истории
# Найти когда была удалена строка
git log -S "deleted_text" --source --all
# Найти коммиты автора
git log --author="Your Name" --oneline
# Показать изменения в файле за период
git log --since="2 weeks ago" --until="1 week ago" -- src/app.py
# 8. Создайте alias для частых команд
git config --global alias.unstage 'reset HEAD --'
git config --global alias.last 'log -1 HEAD'
git config --global alias.visual '!gitk'
git config --global alias.pushf 'push --force-with-lease'
# 9. Настройте git hooks
cat > .git/hooks/pre-commit << 'EOF'
#!/bin/bash
echo "🔍 Running pre-commit checks..."
# Проверить синтаксис Python файлов
for file in $(git diff --cached --name-only --diff-filter=ACM | grep '\.py$'); do
python -m py_compile "$file"
if [ $? -ne 0 ]; then
echo "❌ Syntax error in $file"
exit 1
fi
done
# Проверить на секреты
if git diff --cached | grep -E "(password|secret|key|token)" >/dev/null; then
echo "❌ Potential secrets found in staged changes!"
echo "Please remove sensitive data before committing."
exit 1
fi
echo "✅ Pre-commit checks passed"
EOF
chmod +x .git/hooks/pre-commit
Проверка: Все Git операции должны выполняться без ошибок, pre-commit hook должен срабатывать при коммитах.
📊 Проверочный тест Git #
- Какая команда показывает различия между рабочей копией и staging area?
- Как отменить последний коммит, сохранив изменения в рабочей копии?
- Какая команда создает новую ветку и сразу переключается на неё?
- Как посмотреть историю коммитов в графическом виде в терминале?
- Как временно сохранить незакоммиченные изменения?
Ответы:
git diff
git reset --soft HEAD~1
git checkout -b branch-name
git log --oneline --graph --all
git stash
🎯 Заключение #
Git — это основа современной разработки. Ключевые принципы:
✅ Коммитьте часто маленькими логическими частями
✅ Пишите понятные сообщения коммитов
✅ Используйте ветки для всех изменений
✅ Делайте code review перед мержем
✅ Никогда не коммитьте секреты
✅ Автоматизируйте проверки через CI/CD
Помните: Git — это не просто инструмент версионирования, это основа для командной работы и DevOps процессов.
Следующий раздел: 2.3 Docker и контейнеризация