Git: ключи и слияние. Python: зависимости
Авторизация на удалённом хранилище
- (повтор) любой репозиторий — хранилище
то же самое, если использовать ssh-доступ напрямую
Проблема публикации в не-bare репозиторий (receive.denyCurrentBranch)
- по https — было по умолчанию на GH, теперь отключили
по протоколу git (есть такой) — в действительности по ssh
Отступление про SSH
- Зачем нужен
- Авторизация по паролю
- Суть асимметричного шифрования и авторизация по ключу
- Свойства публичного и приватного ключей
- Агент
Подробнее про SSH в прошлогодней лекции
Процедура слияния в GIT
- Ветка (branch) возможность иметь несколько путей разработки
Не похожа на настоящую ветку: растёт оттуда, где в данный момент расходятся истории
- ⇒ при изменении истории внезапно начинает отрастать не там!
Ветки можно объединять (git merge)
- Пример:
Применение веток для параллельной разработки
- Совместная разработка
- Схема «devel - testing - production»
- Разработка, временно ухудшающая качество
Слияние:
git merge commit-ish
- Слияние бывает с разными стратегиями
Например, git pull из обновлённого репозитория (при неизменённом локальном) — это fetch + merge, но такое fast-forward
- Если прямого наследования нет, нужен специальный «merge commit»
- Пример
Если «чистое» слияние невозможно (изменения в разных ветках затрагивают один и тот же контекст, и изменения неравны), конфликты следует устранить вручную, закоммитить и проложить слияние. Об этом в следующей лекции
Процедура перебазирования в GIT
Ту же задачу — объединение двух вариантов истории — можно решить путём её переписывания (rebase). Как если бы ту же самую работу выполнили после совсем другого коммита.
- (повторение) переписывание в рамках одной ветки
- Rebase делает из двух веток одну (вторая как бы «переотрастает» на конце первой)
- Пример
Пример, когда в результате rebase ветка начинает ответвляться всё раньше по истории
Сравнение с merge
- - Переписывать историю нехорошо, если она хоть кому-то нужна (что делать людям, которые ведут разработку на основе уже несуществующей истории?)
- - Часто бывает, что при перенакладывании изменений (потому что контекст синтаксически не изменился) не совпадает их семантика.
Например, сделали ветку с исправлением функции, а в основной ветке тем временем запилили вторую с той же ошибкой. rebase прошёл
- + merge-коммиты усложняют историю, могут сделать её нечитаемой
+ изменения, сделанные с помощью merge, «опускаются на дно» истории
Для сравнения, rebase всегда выглядит как «свежие» правки
Пример: неадекватный апстрим и набор фиксов в одной ветке
- + rebase:
фиксы поверх апстрима («самые свежие правки»)
- апстрим «вырывается вперёд»
- фиксы ребейзятся поверх апстрима, далее п. 1
- - merge:
фиксы поверх апстрима
- апстрим «вырывается вперёд»
- ветка разработки мержится с апстримом
- ⇒ фиксы по времени раньше обновлений апстрима, «тонут»
- логически «основная ветка» и «ветка с изменениями» поменялись ролями
- если есть конфликты, они распадаются на исходный коммит и правки в merge-коммите
Зависимости при разработке на Python
Зависимости на python-пакеты vs зависимости на системное окружение (то, чему нельзя сделать pip install: утилиты OS и т. п.)
- По этапу применения:
Эксплуатационные (runtime) — то, чему делается import (без них модуль не заработает)
- Сборочные (development) — то, без чего нельзя сформировать дистрибутив (например, средства форматирования документации)
- Инструментальные (environment) — то, без чего нельзя вести разработку (редактор, git, средства профилирования и отладки и т. п.)
pip freeze, requirements.txt и pip instasll -r
- что делать с версиями?
- отдельный req для сборочных зависимостей?
Какие-то инструменты для выявления зависиммостей?
тысячи их (буквально)
Например, pip-check-reqs (возможно, не лучший)
Замечание про зачаточное состояние и непростую задачу учёта зависимостей в Python
Д/З
Изучить модуль textdistance
Найти в нём метрики, позволяющие вычислить количество «быков» и «коров» в игре Быки и коровы (или количество зелёных и оливковых клеток в игре Wordle)
Написать модуль bullscows, предоставляющий две функции:
bullscows(guess: str, secret: str) -> (int, int) — возвращает количество «быков» и «коров» из guess в secret
«быки» — это одинаковые буквы, которые в словах стоят в одинаковых местах, «коровы» — сколько букв догадки использовано в загадке
Например, bullscows("ропот", "полип") -> (1, 2) («о» — бык, «о» и «п» — коровы)
Подсчёт «быков» и «коров» реализовывать вручную нельзя, только textdistance (однако допустимо вычитать или складывать метрики, если это необходимо)
gameplay(ask: callable, inform: callable, words: list[str]) -> int — функция-приложение, обеспечивающая геймплей:
Задумывает случайное слово из списка слов words: list[str]
Спрашивает у пользователя слово с помощью функции ask("Введите слово: ", words)
Выводит пользователю результат с помощью функции inform("Быки: {}, Коровы: {}", b, c)
- Если слово не отгадано, переходит к п. 1
Если слово отгадано, возвращает количество попыток — вызовов ask()
Свойства функции ask():
ask(prompt: str, valid: list[str] = None) -> str
Если необязательный параметр valid не пуст, допустим только ввод слова из valid, иначе спрашивает повторно
Функция inform:
inform(format_string: str, bulls: int, cows: int) -> None
Вызов python -m bullscows словарь длина должен запускать референс-реализацию игры:
словарь — это имя файла или URL (в этом случае необходимо его скачать, например, с помощью urllib)
- Варианты словарей:
длина — необязательный параметр, указывающий длину используемых слов (по умолчанию 5)
Реализация ask() — обычный input() (если нужно, в цикле с проверкой валидности)
Реализация inform() — обычный print()
- В конце выводится количество попыток
- Замечание: игра не совпадает с Wordle, потому что неизвестны позиции быков и коров, только количество
Создать в каталоге с решениями подкаталог 03_MergeRequirements (совпадающий с URL этой страницы) и положить каталог с решением туда
- Соблюдать дисциплину оформления коммитов (одно изменение — один коммит, описание в commit message и т. п.)