Comments 18
Но вообще статья про разработку commit hooks на C# познавательна, спасибо.
Это не решает проблему, т.к. timestamp миграции 2го комита может раньше timespamp'а миграции 1го, а миграции должны выполняться последовательно, иначе будет undefined behavior :)
У меня другой совет Сэмам и Бобам: раз уж сидите на дотнете, используйте EF-миграции.
Перед комитом с миграцией, заливайте в свой фиче-бран последние изменения и если там есть новая миграция, просто перегенерируйте свою. Это делается несложным скриптом:
1 Update-Database -TargetMigration "before"
2 удаляем свою миграцию
3 Add-Migration "myNewMigration"
Тогда не надо будет договариваться, менять числа на сервере, ставить хуки, вы не будете блокировать друг друга и если миграции затрагивают одни и те же таблицы, у вас будет возможность решить конфликты.
P.S. доки по теме: https://docs.microsoft.com/ru-ru/ef/ef6/modeling/code-first/migrations/teams
P.P.S.
Еще можно "огородить" работу с БД отдельным интерфейсом/сервисом и делегировать это специально выделенному человеку. Остальные будут работать с ней только через интерфейс/RPC используя временные "затычки".
Или банально делать более мелкие комиты. Проблема останется, но разруливать мелкие конфлиты гораздо проще и экономнее для нервной системы :)
Это не решает проблему, т.к. timestamp миграции 2го комита может раньше timespamp'а миграции 1го, а миграции должны выполняться последовательно, иначе будет undefined behavior :)
Можно сортировать не по timestamp, а по имени файла без %login%
EF-миграции создают сущий кошмар в ситуации, когда параллельно разрабатывается несколько фич и в develop
они сливаются в одном порядке, а в master
— в другом.
Имхо, если вы так делаете, то тут и с EF и без будет кошмар.
Обычно разработка ведется в фиче бранче, потом заливается в develop, а develop вливают в master fast-forward'ом и проблем быть не должно
Фичи вливаются в develop
когда их сделал разработчик, а в master
— когда они полностью протестированы и готовы к релизу. Поэтому мержить develop
в master
(по крайней мере у нас) строго-настрого запрещено: иначе в релиз может проскочить сломанная фича.
Проблема именно в том, что EF нужен полный "слепок" текущего состояния БД для миграций. Поэтому если просто использовать EF без миграций, заменяя их SQL-скриптами и сторонними утилитами типа FluentMigrator, проблема не возникает.
Я вас понял. У нас есть отведенное для тестирования время и в конце спринта всё вливается в master, либо спринт проливается. Если нужна доработка создается отдельная фикс-миграция. Проблем с EF не наблюдаем.
Раз у вас принятно вливать по отдельности, наверное, EF не самый удачный выбор.
Но он делает так не потому что он "плохой", а потому что такой подход дает гарантию не сломать БД при мерже.
А как вы решаете такую проблему?
Фича в девелопе готова к мержу в мастер, но в develop'е уже есть другие миграции, которые пока не готовы и связанны с вашей?
В проектах поменьше решаем административно — задачи ставятся так, чтобы параллельных миграций не было, и релизятся в той же последовательности.
В проектах побольше пишем миграции руками в виде SQL-скриптов. При этом для доступа к данным все равно используем EF, но без миграций. Оба варианта уже несколько лет исправно работают.
А тестируются они где? У вас разворачивается полная копия окружения под каждую фичу? И как вы потом тестируете, что они не конфликтуют между собой после мержа?
stepNNN.sql -> stepYYYY-MM-DD-HHMM-%login%.sql.
Почему не назвать файл более понятным именем, например, feature-XXX.sql
или fix-YYY.sql
, а с порядком применения миграций разбираться в отдельном оркестрационном скрипте, в явно описанном виде, а не через магические числа с потенциальными конфликтами?
Мне кажется, что получить конфликт c feature-XXX.sql
примерно так же маловероятно, как получить конфликт с имеем бранча в репозитории. Имён всяких много, на крайняк XXX может быть/включать номер task-а или issue для пущей уникальности и простоты навигации по коду. Но если что можно и переименовать, на порядок это никак не влияет. А вот последний незадействованный номер — это hot spot, конфликт просто напрашивается.
На всякий случай уточню, что xxx
— это не число, а имя фичи или проблемы, например feature-user-logon-reporting.sql
. Чтобы тут возник конфликт, нужно чтобы два человека вдруг случайно выбрали совершенно одно и то же длинное имя в пересекающиеся интервалы времени.
Возможно я чего-то не понимаю, но не могли бы Вы пояснить, почему Вы использовали такую конструкцию, а не механизм await:
.ConfigureAwait(false)
.GetAwaiter()
.GetResult();
Вы совершенно правы, использование await было бы более удобным. Я писал об этом в пункте 5 раздела "Направления дальнейшего развития". Лучше определить интерфейсы hook'ов через Task:
public interface IPreCommitHook
{
Task<bool> Process(IList<string> args);
}
Тогда в их реализации можно свободно использовать async/await.
Тем не менее, насколько мне известно, сами hook'и не подерживают асинхронные операции, поэтому где-то всё равно придётся дожидаться окончания работы задач.
Резервирование констант и Git hooks на C#