Комментарии 114
https://learngitbranching.js.org/?locale=ru_RU не игра, но достаточно интересно и увлекательно
Мне одному кажется, что Git - это адище, построенное максимально неочевидным образом?
Мне так не кажется o_O
В свое время, после нескольких лет с SVN, переход на GIT зашел на ура, все клево и логично. И легкие (по сравнению с svn) бранчи, и удаленные репозитории, когда ты можешь легко подключить дополнительный удаленный репозиторий, например, коллеги ушедшего в отпуск и прям в нем доделать недоделаную фичу и довести ее до пул-реквеста.
Хотя я все не копал, пользуюсь основными фичами, когда-то имел дело с какой-то репой, где некоторые папки были не в этом-же самом репозитории, а какие-то подключенные другие репозитории, вот с этой хренью чет пришлось помучится, так толком и не разобрался, благо не долго с ней дело имел.
Ты про сабмолули? Не особо сложно с ними работать. У меня проблемы только с удалением были
Я легко управлялся с CVS, потом легко переехал на SVN. Но когда появился Git - это было и остается каким-то кошмаром. Не помогают ни книги, ни документация, ни ублюдочные объяснения в стиле "машина времени Git" (кто это вообще придумал, совершенно не соответсвует парадигме Git).
Даже зная, что Git - это граф коммитов, а ветки - это указатели на коммиты, легче не становится. Мне потребовались годы, чтобы сформулировать следующую мысль:
Веткой в Git называется указатель на коммит, и этому указателю задано определенное имя. Если такой указатель указывает на последний коммит в цепочке, то в момент добавления нового коммита (у которого текущий является родителем) этот именованный указатель автоматически "переместится": то есть он начнет указывать на новый коммит. А имя указателя останется прежним. Таким образом, создается иллюзия, что программист работает в именованной ветке, и при добавлении коммитов ветка прирастает новыми коммитами. Хотя, на деле, система Git оперирует не ветками, а именно указателями на коммиты, не более того.
Нужно запомнить: никаких веток, в естественном человеческом понимании, в Git нет.
При этом во всех конторах я всегда был одним из немногих, кто разгребал сложные ситуации коллективной работы, другие просто вообще не въезжают что происходит, умеют только коммитить и выбирать ветки для работы. И каждую команду ввожу с боязнью что результат будет не тот который предполагал, а станет только еще сложнее распутывать весь клубок.
Да, и ветки и тэги - это просто "указатели" на коммиты.
И при коммите "в ветку" указатель этой ветки всегда сместится на новый коммит, без вот этого "если такой указатель указывает на последний коммит в цепочке", так как ветка всегда указывает на последний коммит.
Да, могут существовать другие коммиты, которые уже были созданы из того на который указывает ветка, но текущая ветка про них ничего не знает и потому всегда смещается на новый коммит, а информация о тех "других" коммитах может быть и вовсе потеряна если для них (или их потомком) нет указателя.
Собственно git commit --ament
так и работает: смещает указатель на один коммит назад, создаёт новый коммит, смещает указатель на него.
Старый коммит всё ещё лежит в локальном репозитории и будет доступен для checkout
и прочих манипуляций, пока не будет выполнен gc
, который в том числе убивает вот такие потерянные коммиты.
Таким образом, создается иллюзия, что программист работает в именованной ветке, и при добавлении коммитов ветка прирастает новыми коммитами. Хотя, на деле, система Git оперирует не ветками, а именно указателями на коммиты, не более того.
А в чем разница между именованной веткой и именованным указателем на коммит? При добавлении коммита в ветку она не должна смещаться что ли?
Овладевание рефлогом и ресетом сохранит ваши нервные клетки. Запороть локальный репозитории это нужно ну очень постараться, придется вручную git gc ещё вызвать.
Овладевание рефлогом и ресетом сохранит ваши нервные клетки
Очень сомневаюсь. Я много лет назад писал статьи:
Git: как переключиться на нужный коммит и вернуться обратно? Понимание, что такое ветка
Не бойся хардресета! Он твой друг и помощник. (Как пользоваться git reset)
Но этого все равно недостаточно для безопасной работы с Git. Плюсуйте сюда разгребание логических нестыковок при слиянии кода, часто чужого, и вы поймете что в реальной жизни ситуации могут быть такими, что сам черт ногу сломит. Особенно когда программисты и руководитель проекта не понимают что короткие коммиты на одно изменение - это правильно. Тебе захреначат кучу изменений в одном коммите, а потом окажется что из этих изменений нужны только некоторые. И вот попробуй их разгреби если они в одном коммите лежат. А тебе будут говорить - зато история проекта короткая.
Книгу попробуй Version Control By Example
Меня тоже после SVN таращило, все былое извращённо и противоестественно
VCBE как раз разбито на главы (не обязательно понимать сразу всё) и построено по принципу: вот базовая проблема, вот её решение в логике CVS/SVN, вот неразрешимые проблемы с этим подходом, вот как из этого тупика вышли "системы 3-го поколения"
Постепенно всё бессмысленное и противоестественное обретает смысл
Официальная документация так не помогает....
Ах, нет, там всё написано (https://git-scm.com/book/ru/v2/Ветвление-в-Git-О-ветвлении-в-двух-словах):
Ветка в Git — это простой перемещаемый указатель на один из таких коммитов.
И соответственно глава "3.1 Ветвление в Git - О ветвлении в двух словах" (ИМХО: наглядно с картинками объясняет работу веток)
https://git-scm.com/book/ru/v2/Ветвление-в-Git-О-ветвлении-в-двух-словах
Можете показать место, где вы не поняли официальную доку? (Лично мне +- понятно как гит работает)
Можете показать место, где вы не поняли официальную доку?
Да пожалуйста: где там написано, что в Git сплошь и рядом идут ветвления без веток? Что в пределах одной ветки могут быть ветвления и это нормально? Новичек вообще не въежжает как такое может быть, хотя сталкивается с таким поведением сразу же как только над проектом начинают работать два человека или он сам один, но из разных рабочих мест. Нигде не найдешь внятного концептуального объяснения, что весь гит построен не на ветках, а на цепочках коммитов, и эти цепочки могут произвольно ветвиться и даже не иметь имен. Пользователь читает в доке одно, а по факту видит другое. И у него в голове не укладывается, что он делает неправильно, и что он недопонимает.
Я переходил с SVN, помучился с недельку, потом просветлел, и уж лет 5 как одно удовольствие. Правда, я командной строкой пользуюсь в исключительных случаях, в-основном - TortoiseGit и клиентом в VS. Ну и, конешно, ограничиваюсь только нужной мне функциональностью, чтоб голову лишним не забивать.
У меня лично просветление произошло, когда стал смотреть на репозиторий просто как на граф коммитов с метками - тэгами и ветками, которыми можно более-менее свободно манипулировать - создавать, удалять, двигать, не меняя при этом самого графа. И наоборот, двигать ветки графа по меткам или схлопывать их к меткам.
Да он и закодирован тяп-ляп, на отвяжись.
Например, оказавшись в местах с нестабильным Интернетом, я с удивлением обнаружил, что данная говнософтина оказывается не поддерживает докачку. Соединение прервалось - качайте полностью заново. До этих пор был уверен, что программа, сделанная не кем-то, а линуксоидами, да ещё в те мохнатые годы, когда хороший Интернет был разве только в городах-миллионниках, конечно же умеет обрабатывать обрывы соединения и подобные же неприятности.
это вы еще SVN не пользовались ;) до сих пор помню как я чекаутился и переключался на бранч по пол часа, и тут не было воркэраундов. просто такой вот у заказчика был vpn (13 лет назад) и он так работал вечером.
Да, это суровый и очень странный недочет. Работаю с гигантским проектом, сотни гигабайт через лфс, в некоторые дни пулл может занимать час. Не дай бог рабочий впн моргнет, или связь пропадет на секунду.
До этих пор был уверен, что программа, сделанная не кем-то, а линуксоидами, да ещё в те мохнатые годы, когда хороший Интернет был разве только в городах-миллионниках, конечно же умеет обрабатывать обрывы соединения и подобные же неприятности.
Линуксоиды просто скопируют репозитарий чем-нибудь, что делать докачку умеет. Это всякие сложные системы хостинга репозитариев на шелл его возможности немного хмурятся . А так можно разными git archive, git bundle, git format-patch все просто в файлик(и) упаковать и дальше слать как угодно, включая почту (чем, говорят, разработчики, которые все это для себя придумывали, и занимаются), после чего применить к репозитарию на удаленной системе.
Лучше SVN, хуже чем Fossil. Одно то, сколько приходится делать git push --force
говорит, что в основе задумки что-то кривое.
Когда вы делаете заявления как у вас в комментарии, вас не понимают, потому что кроме SVN и Git люди ничего не знают, и считают что вы призываете вернуться к SVN.
возможно ли что использование --force вызвано тем что вы используете git не как задумывалось?
Конечно не так. Задумывалось по коммиту на каждый чих. Обнаружил опечатку в комментарии - делай коммит, а потом ещё мерж этого коммита в develop делай.
Конечно не так. Задумывалось по коммиту на каждый чих. Обнаружил опечатку в комментарии - делай коммит
нет, лучше сразу 100 несвязанных исправлений в одном комите и сразу в мастер, чтобы тут же на прод заливалось. Ну и комментарий поставить типа - "Fix bug(s)", чтобы коллегам было потом проще дебажить
А mercurial хуже или лучше?
Понятнее.
он умер. Прошёл вместе с компанией и сотней реп путь snv -> mercurial -> git, на гите всё проще, и новые сотрудники знают что это такое и тулов больше и интеграции всякие проще. Тулинг вокруг системы контроля версий рулит. Да, некоторые вещи в hg проще, но тоже не всё супер гладко, но тулиг слабый.
Как по мне — он был во всем лучше и логичнее. Так как делался вроде в том числе на опыте ошибок и проблем гита.
Но увы, конкурентную борьбу он проиграл и де‑факто умер. Когда битбакет, который исторически изначально был именно меркуриал‑хостингом, его окончательно отключил, я понял, что пора переходить на гит. Увы и ах.
Видимо я делаю что-то не так, но ни разу не доводилось использовать push --force.
А зачем вам нужно часто делать push --force
?
Fossil, насколько я понял по описанию, делает force push вообще всегда. Значит он более кривой, чем git?
"Fossil is designed to keep all historical content forever" - я вот не вижу ни одной причины, зачем надо хранить forever все опечатки каждого разработчика. Кто и зачем будет их читать? А если так не делать, то приходим к push force.
Ну вот смотрите. Я от develop сделал бранч, написал фичу, и запушил. Через неделю приходит ревью от начальника: всё норм, только вот в лог пишешь слово с опечаткой. Поправь и принимаем.
Я теперь могу сделать amend, но не смогу его запушить без --force, потому что develop ушёл вперёд.
И это я не говорю про более сложные случаи, когда мой бранч успели смержить или develop так изменился, что нужен rebase.
В git нету концепции мелкой незначительной правки, из-за этого у команды, любящей мелкие одноразовые фичеветки, история коммитов загаживается сотнями "merge", "fix typo", "add comment" ЛИБО это всё делается через amend и push --force
Я от develop сделал бранч
Я теперь могу сделать amend, но не смогу его запушить без --force, потому что develop ушёл вперёд.
Эм, нет, если вы еще не мержили, то состояние develop не играет никакой роли.
Вы не можете запушить без force потому что на сервере другие коммиты в этой ветке, и он не знает, действительно ли вы хотите перезаписать историю ветки или просто что-то перепутали. Это просто защита от нежелательных изменений. Так же как операционная система вас спрашивает, если при копировании в папке уже есть файл с таким именем.
когда мой бранч успели смержить
Если ваш бранч уже смержили, то force push измененного коммита в ту же ветку вообще не имеет смысла. Как его мержить потом с исходным коммитом?
Вообще мерж ветки, в которой еще идет работа, выглядит как недостаток организации процесса разработки. Закончили работу, сделали ревью и тестирование, потом можно мержить. А если уж смержили, то новые изменения только новыми коммитами, а не правкой предыдущих. При этом продолжать работу можно в той же ветке.
или develop так изменился, что нужен rebase
Ну так если вы настолько изменили историю своей ветки, то что удивительного, если сервер просит вас подтвердить, что это действительно то, что вы хотите? Это нельзя назвать более сложным случаем, тут нужен тот же push с подтверждением.
В git нету концепции мелкой незначительной правки
Ну как это нету, amend это она и есть. И от Fossil она, насколько я вижу, отличается только тем, что он не требует подтверждения перезаписи.
из-за этого у команды, любящей мелкие одноразовые фичеветки, история коммитов загаживается сотнями "merge", "fix typo", "add comment"
ЛИБО это всё делается через amend и push --force
Ну и в Fossil это делается через amend и push --force, просто там флаг --force не надо указывать.
Это вообще не соответствует действительности. Мелкие фичеветки и ненужные коммиты никак не связаны. Ничего не мешает разработчику исправить опечатку до мержа, а не после. Если мержит без исправлений, значит или нет нормального код-ревью, или просто всем пофиг, Git тут ни при чем.
Обычно нормальный процесс разработки выглядит так. Все "amend", "fix typo" и "add comment" находятся только на локальной машине разработчика. Потом он делает интерактивный rebase и объединяет историю в 1-2 законченных коммита, иногда больше. Только потом он делает push (без force). Правки на код-ревью делаются новыми коммитами БЕЗ amend для удобства ревьюера (поэтому тут force тоже не нужен). После ревью и тестирования разработчик еще раз объединяет коммиты и делает push --force. Потом можно мержить. Но обычно по задаче нужен только один коммит, поэтому в настройках проекта в GitLab часто ставят галочку, которая при мерже объединяет всё в один коммит автоматически, так что и здесь force push не нужен.
Иногда бывает так, что лень запускать юнит-тесты локально, а после push и до ревью запускается пайплайн, и тесты не проходят. Тут правки к тестам можно залить через amend и force push, чтобы не путать ревьюера и самому не путаться. Но можно и отдельным коммитом, GitLab все равно показывает общий diff для всех коммитов.
Вообще мерж ветки, в которой еще идет работа, выглядит как недостаток организации процесса разработки.
Да нет. Нормально. Когда репозитариев несколько.
Что-то накодили, смержили, сделали push в репозитарий тестового стенда(откуда никто ничего никогда не тянет). Оно там собралось, протестировалось. Если успешно - коммит с мержем отправляется в публичный репозитарий. Не успешно - локальный мерж (который push-али) убиваем, продолжаем работу.
Идея в том, что тестируются не только изменения по решаемой задаче, а вместе с теми изменениями, которые в основной ветке успели набежать.
А зачем для тестового стенда отдельный репозитарий и мержи? Ветки же дают те же возможности.
Для того, чтобы те изменения, которые делаются (и возможно, даже откатить захочется) - не тащились всеми остальными.
Кроме того, по самой логике: Вот есть у нас несколько веток, где разные люди ISSUE-1, ISSUE-2 чинят. Ну ладно, каждая из них по отдельности - тест прошла. Потом все это вместе смержили в main/master/release-1.2.3 - и все упало. Тестировать надо весь комплект вместе. Вот тот самый коммит, сборка которого на публикацию пойдет. И никому этот комплект не показывать, пока не тесты не покажут, что все работает.
Ветки же дают те же возможности.
Они, если все в одной репой, делают сильно напряжным реализацию "Вот это у нас master следующего релиза, но еще не оттестированный, поэтому пользоваться им еще нельзя". (Извинюсь, что повторяюсь, но меня давно раздражает, что именно эта часть возможностей Distributed version control потерялась, когда все стало централизоваться в одном репозитарии)
Для того, чтобы те изменения, которые делаются - не тащились всеми остальными.
Так в гите они и не тащатся. Остальные должны специально сделать checkout этой ветки.
Тестировать надо весь комплект вместе.
Так это тоже можно сделать с ветками.
Так это тоже можно сделать с ветками.
Как? Вот собрали мы бинарник из коммита xyz. И именно этот бинарник в релиз пойдет и именно этот коммит толжен стать следующим коммитом в main, если тесты пройдут.
А если не пройдут - чтобы все могли считать, что этого всего никогда не было. Или даже не считать, а действительно его никогда не видеть и не учитывать, что он был.
В смысле, я верю что можно - но с двумя репами оно гораздо интуитивнее и меньше голова напрягается.
2 ветки, одна идет параллельно другой. Например, release-test и release. Мержим несколько задач в release-test, тестируем финальный коммит, потом или мержим release-test в release, или исходные ветки в том же порядке. Если тесты не прошли, откатываем release-test, убираем ветку которая не работает, мержим заново остальные и делаем force push. То есть практически то же самое, что и с репозитариями. С 2 репозитариями, мне кажется, нужно больше вспомогательных скриптов и ручной работы.
мержим release-test в release
И получаем новый коммит на release, если были неаккуратны и fast forward не получился.
После приходят хмурые тестировщики и говорят "мы вот релизную ветку посмотрели и оно как-то отличается от того, что мы тестировали и чему мы OK сказали".
Задача ставится - чтобы в release оказался тот самый коммит, который тестировали.
Почему такая задача? А чтобы потом меньше объяснять, почему внутри зарелиженного бинарника(а тестировали и его в том числе) версии 1.2.4 коммит, из которого он собирался, не совпадает с тем коммитом, что в release на верхушке стоит и тег ver-1.2.4 имеет.
Если в release кто-то добавляет коммиты не из ветки, которая тестировалась, то так может быть и с 2 репозитариями.
Если в release кто-то добавляет коммиты не из ветки, которая тестировалась
Был quickfix USSUE-3. Его(и только его - все остальное для следующей версии) оттестировали отдельно и слили в release, получив ver-1.2.3-fix1. Опубликовали.
Его также слили (где-то между USSUE-1 и USSUE-2) в release-test. Который ответвлялся от ver-1.2.3
Если теперь release-test в release слить - fast forward не получится.
Ну да, можно новый release-test создать, сделав rebase всего на ver-1.2.3-fix1. Но это возиться надо.
В общем - слишком много головной боли. Гораздо проще мыслить "вон на том стенде есть release, который будет опубликован 'как есть' для всех, если тесты пройдет". Без лишних манипуляций со слияниями и слежением, чтобы эти слияния прошли как надо.
Я не очень понял, но работа с release-test не должна ничем отличаться от работы с release в другом репозитарии. Всё то же самое, только вместо другого названия репозитария вы указываете другое название ветки. Как вы переносите коммиты из тестового репозитария в release, так же переносите и из release-test.
Его также слили (где-то между USSUE-1 и USSUE-2) в release-test.
Если теперь release-test в release слить - fast forward не получится.
Если вы сделаете то же самое для ветки "test-repo:release", то будет та же проблема. Нет разницы, в каком репозитарии находится ветка. Одинаковые действия с коммитами приведут к одинаковому результату.
Я вообще не имел в виду fast forward, на мой взгляд лучше делать явный мерж release-test в release. Так в истории будет явно видно, что мы перенесли протестированные изменения. В release не должно ничего попадать помимо release-test, тогда можно быть уверенным, что после мержа содержимое файлов такое же, которое тестировалось. Неважно, какие там хеши коммитов.
Ну да, можно новый release-test создать, сделав rebase
Не должно быть rebase для ветки тестирования. В ветку тестирования только мержатся задачи, которые надо протестировать совместно для релиза.
Я вообще не имел в виду fast forward, на мой взгляд лучше делать явный мерж release-test в release.
Уже сказал, почему это нежелательно. Потому что внутри бинарника, собранного с release-test будет в качестве 'откуда собрали' не тот хэш коммита, что на верхушке получившегося release стоит.
В ветку тестирования только мержатся задачи, которые надо протестировать совместно для релиза.
Которая лишняя сущность. Или Легче мыслить 'ветка релиза, но еще не опубликованная, тестируем ее'.
Вот workflow
1) Начало. Имеем три репозитария. Публичный/опубликованный/стабильные версии, репозитарий поддержки, репозитарий разработки

2) Команда разработки начинает что-то делать

3) feature-1 успевают раньше, решают, что оно готово. Поэтому сливают в release (получается ff) и отправляют в таком виде на тестирование (Тестируют dev:release). Тестирование изменения принимает. (Если не принимает - возвращаем верхушку release обратно - как в шаге 2 было)

4) Тут прилетает issue-3, требующая срочного решения. Команда поддержки чинит, сливает с release(снова будет ff), отправляет на тестирование (тестируют support:release).

5) Тестирование проходит, версия с исправлением публикуется(push из support в public), ставится тег версии

6) Разработка подтягивает внесенные изменения(потому что регулярно сама или автоматикой делает fetch upstream-а)

7) Сливает их (тут ff нет - будет нормальный мерж), отправляют на тестирование (снова dev:release)

8) Доделывают feature-2, сливают в release (снова нет ff), отправляют на тестирование (тестируют dev:release)

9) Тестирование говорит OK, новая версия публикуются (push из dev в public), ставится тег версии.

Ну где-то так. И вот на мой взляд - во всем этом вообще особо думать не надо, что откуда тянуть, где что лежить и что куда push-ать. Опубликованные версии лежат на public, релиз следующей версии - на dev, команда поддержки ничего про разработку не знает и знать не хочет. Тестируются - всегда release от тех людей, что попросят. Собранные бинарники собираюся/были собраны в точности из тех коммитов и тегов, что внутри них вписаны. А что красивой линии с последовательным увеличением версий на release нет - ну и пускай, для этого теги есть.
Уже сказал, почему это нежелательно. Потому что внутри бинарника не тот хэш коммита
Ну а я написал, что правильнее ориентироваться на содержимое файлов, а не на хеши. Потому что работа программы зависит не от хешей, а от содержимого файлов. Если нужна именно гарантия, можно один раз сделать скрипт, который сравнивает файлы в этих ветках побайтово, и добавить его в пайплайн. Но обычно достаточно положиться на то, что Git работает правильно, и содержимое файлов после мержа этих веток не меняется, потому что в release приходят коммиты только из release-test.
В ветку тестирования только мержатся задачи, которые надо протестировать совместно
Которая лишняя сущность.
Почему она лишняя, если в вашем подходе она тоже есть? Вы же писали "Тестировать надо весь комплект вместе".
Или Легче мыслить 'ветка релиза, но еще не опубликованная, тестируем ее'
release-test это и есть такая ветка.
Поэтому сливают в release (получается ff)
Я не вижу ценности в том, чтобы обманывать самих себя. Если мы перенесли изменения из другой ветки, мы должны выразить это явно в виде merge, а не притворяться, что мы закоммитили напрямую в финальную ветку. А то получается, что для одних задач у нас ff нескольких коммитов, для других merge, непонятно где что, вот эти 2 коммита это одна задача с ff или 2 разных, и т.д.
Тестируют dev:release
Сочетание "dev" и "release" для меня выглядит как нонсенс. Если еще идет разработка, то это что-то противоположное релизу.
И вот на мой взгляд - во всем этом вообще особо думать не надо, что откуда тянуть, где что лежить и что куда push-ать.
Я не вижу в вашем описании никаких отличий от работы с ветками. Просто вместо названия репозитария используется суффикс в названии ветки.
Ну а я написал, что правильнее ориентироваться на содержимое файлов, а не на хеши. Потому что работа программы зависит не от хешей, а от содержимого файлов.
Правильно. Но содержимое файлов заказчику может и видно, но плохо. А если внутри файла стоит "собрано из хэша abcd", а на release стоит другой хэщ - то возникают вопрос "А это точно тот файл? А если собрать из release - работать будет? Мы же другое тестировали."
Я не вижу ценности в том, чтобы обманывать самих себя. Если мы перенесли изменения из другой ветки, мы должны выразить это явно в виде merge, а не притворяться, что мы закоммитили напрямую в финальную ветку
Это делать так, чтобы была ветка - это обманывать себя. Git все равно забудет, что, например, зелененький коммит для feature-1 был на ветке feaure-1. Кроме того - а какая разница? А так - ну есть и есть. Вот внесенные изменения. То что он по задаче номер... из таск-трекера делался -- это где-то в описании или названии можно вписать.
Я не вижу в вашем описании никаких отличий от работы с ветками. Просто вместо названия репозитария используется суффикс в названии ветки.
Технически и если внимательно посмотреть - да. Но принцип наименьшего сюрприза с моей точки зрения лучше соблюдается, когда это именно отдельные репозитарии.
"public -- живет на публичных серверах, доступен на чтение всем, писать может только главный по выпускам."
"dev - какой-то внутренний сервер компании, мы на нем резвимся и наших странных коммитов никто не видит. А перед публикацией и причесать их можно".
На самом деле я бы спорил, что main/master/release вообще нужен как таковой. Для фиксации результатов "вот в этот момент мы выпустили версию x.y.z - достаточно тегов.
А сливать изменения - ну вот сейчас мы делаем новую версию? Так она не 1.2.4 должна быть, а 1.3.1. Мержим все в ветку 1.3. Как доделаем и оттестируем - тег 1.3.1 появится.
А фиксы - в ветку 1.2. Под тегом 1.2.4 как раз следующий будет.
заказчику
Заказчику можно сказать "Не обращайте внимание на хеши, у нас есть скрипт, который блокирует сборку если содержимое файлов отличается от тестовой ветки". Или писать в файл хеш контента, и выводить его же в логе запуска юнит-тестов, где его может посмотреть заказчик. Или вообще не писать хеш в файл, а только версию из тега.
Git все равно забудет, что, например, зелененький коммит для feature-1 был на ветке feaure-1. Кроме того - а какая разница?
Ну и пусть, главное что в истории будет явное слияние. В визуализации для любой задачи будет история коммитов, параллельная main.
Разница в том, что программистам так будет проще работать с историей. Задача значит мерж, в сообщении мерж-коммита ссылка на мерж-реквест со всем обсуждением.
Если я всё правильно понял, на шаге 9 вы делаете форс-пуш в public:release. И именно в возможности так делать видите преимущество нескольких репозиториев.
Так с ветками тоже можно форс-пушнуть одну ветку в другую, и результат будет ровно тот же самый. Только идея в любом случае очень сомнительная. Как минимум, вы теряете тот коммит, из которого собирался ver-1.2.3-fix1, ушедший в релиз. Как максимум, рискуете и сами изменения случайно потерять.
Если я всё правильно понял, на шаге 9 вы делаете форс-пуш в public:release.
Зачем там force? На public же ничего не трогалось между 5-ым и 9 шагом, push release вполне нормально уйдет, без ругани, требующей force. Просто запишется остаток графа - и все.
ver-1.2.3-fix1
Почему теряю? Синий коммит (в котором фикс сделан) - как был под своим id-ом, так и остается. В том числе в public(оставаясь помеченным тегом)
Я ещё раз внимательно посмотрел на ваши схемы, и понял, что у вас кружочки одинакового цвета это один и тот же коммит, с одним и тем же хэшем (вчера у меня сложилось впечатление, что это черри-пикинг тех же изменений). Тогда действительно никакого форс-пуша не будет, и замечание про потерю коммитов, соответственно, не актуально.
Актуальным остаётся замечание, что с ветками ничего не мешает точно так же процессы построить. Просто вместо support:release и dev:release будут ветки, условно hotfix и release-testing, в которые будут периодически мёржиться изменения из release (что у вас уже делается на шаге 7, только шаг 6 перестанет быть нужен). Использовать merge commit или fast-forward для залива протестированной версии в release уже отдельный, совершенно не связанный вопрос (моё имхо -- fast-forward + tag вполне уместно).
потому что на сервере другие коммиты в этой ветке,
Чужих коммитов в этой ветке нет. Он мой прошлый пуш считает "другими коммитами в этой ветке". Иначе разговора бы не было.
Мелкие фичеветки и ненужные коммиты
Если я в долгоживущей ветке сижу, то незначительную правку внесу со следующим коммитом и всё. Вопрос возникает если коммитить в текущую ветку больше ничего не планировалось
Чужих коммитов в этой ветке нет. Он мой прошлый пуш считает "другими коммитами в этой ветке".
Ну так я и не сказал "чужие". Он их считает другими, потому что они фактически другие, там другие данные в файлах. Почему он должен считать их теми же?
Вопрос возникает если коммитить в текущую ветку больше ничего не планировалось
Не понимаю. Если вам на код-ревью указали на опечатку, почему надо мержить ветку до исправления опечатки? Неважно, большие там изменения или маленькие.
Да не надо мержить. Хочется просто обойтись без отдельного коммита "Исправил одну опечатку"
Я теперь могу сделать amend, но не смогу его запушить без --force, потому что develop ушёл вперёд.
Просто не добавляйте ничего в ветку после ее мержа. Заводите новую от актуального мастера или какого нужно коммита.
Если б мне принесли ветку, которую мержили, форспушили, мержили, форспушили, я бы не поленился и нашел бы домашний адрес этого человека.
Одно то, сколько приходится делать git push --force говорит, что в основе задумки что-то кривое.
а что не так с --force ? Я постоянно использую, а как иначе пушить изменения в свой бранч после squash ?
а что не так с --force ? Я постоянно использую, а как иначе пушить изменения в свой бранч после squash ?
Пушать в другой бранч? А старый и грохнуть можно.
Т.е. работать со всеми мелкими исправлениями в какой-нибудь ISSUE-123-WIP, а после того как squash сделал - уже в ISSUE-123, который и вливать туда, куда хотели.
Обычно при работе в команде влитие идёт через Merge/Pull Request, а он завязан на ветку - новая ветка это новый PR, а значит всё обсуждение из старого "теряется", оставая в старом - это как минимум не удобно.
Да и разницы между force
-пушем в свою существующую ветку и созданием новой ветки с удалением старой практически нет. Кроме того что ветка будет новая что отразится на том что завязано на имя ветки.
А зачем вообще избегать force
-пуша? Это же сервер просто предупреждает о том, что он не сможет плавно переместить указатель ветки на новый коммит - то есть переместить так чтобы не потерять ни один из коммитов входящих в ветку в данный момент, а если локально проводился squash
, amend
или rebase
, то это как раз и приводит к ситуации когда часть коммитов (про которые знает сервер) из ветки выпадают и force
при пуше просто говорит ему "да, клиент знает что делает - терять коммиты можно".
При командной работе force
-пуш в релизные ветки обычно запрещён политиками, изменять что-то в чужих в целом не принято, а с историей коммитов в своих ветках можно делать всё что угодно.
Ты не один такой
Ты не один, тоже мучаюсь, особенно мозг начинает плавиться когда не стандартные ситуации появляются. Git тот ещё ящик пандоры.
Git просто имеет ту же философию, что и C: это отличная система для групп, в которых никто никогда не ошибается.
По моему git прощает все ошибки, хотя может и не все если фигачить какую то совсем уж адскую дичь )
Например какие ситуации?
Git построен максимально очевидным образом. Это примитивнейшая система хранения деревьев объектов. Он простой и понятный внутри, но сложноват со стороны интерфейса, который пытается быть высокоуровневым и "удобным". Познайте внутренности, поймите как он работает на самом деле, разберитесь с git ls-files, git cat-file, git commit-tree, и познаете дзен.
Что мне не нравится в гите так это сабмодули. Они логичные и понятные в рамках выбранной идеи, но создают кучу проблем и сложностей на ровном месте. Стараюсь ими вообще не пользоваться. Уж лучше делать одну монорепу, из которой пушить отдельные папки в внешние сабрепы, чем наоборот.
Поговаривают, что гит прекрасен в своём исполнении, но ужасен в использовании (с последним могу согласиться). Ну типа как haskell - безупречный математически обоснованный язык, а глупым людишкам зачем-то надо на нём print message сделать!
Да, но ничего лучше пока не придумали.
Вам кажется.
Всё устроено предельно логично.
Степень логичности такая, что создали два сайта-бредогенератора, высмеивающих команды git'а.
https://git-man-page-generator.lokaltog.net/#YWRkJCRoaXN0b3J5
https://web.archive.org/web/20140413194418/http://www.antichipotle.com:80/git/
(для них ещё предлагали практическое использование: проверять знание git'а, показывая эти страницы)
Всё устроено предельно логично.
запредельно даже ;)
Как узнать хеш текущего коммита? mercurial: hg id. git: такой команды не завезли, есть штук 50 заклинаний.
Как выгрузить изменения в другой репозиторий? mercurial: ну укажи url репозитория. git: не-не, сначала создай remote (вот мануал с простыней параметров), а потом делай push (другой мануал с простыней параметров)
Субмодули. mercurial: просто работают. (другое дело, если субмодуль сломался, нужно исполнить странный танец). git: ну, есть команда (простыня параметров), не забывай танцевать синхронизировать.
Как узнать хеш текущего коммита? mercurial: hg id. git: такой команды не завезли, есть штук 50 заклинаний.
git log -1?
commit 7ea5bc21d02d1056691979f22ca59f9a6e98e567 (HEAD -> master)
Не угадали. Нужно только хеш.
git rev-parse HEAD
Да. Удачи найти это через git help ;)
Вряд ли найдется хоть 1 человек, который полностью знает о всех возможностях гита. Поэтому я бы всем рекомендовал после того, как научились базовым вещам, пройтись по всем командам гита и почитать описание без глубокого вникания. Так у вас сформируется некоторый mind map, который можно будет детализировать по мере необходимости.
Это проблема документации, но не инструмента.
Первое мое знакомство с гитом закончилось паникой и клонированием репозитория заново. Сейчас я не могу представить свою работу без ребейзов и форспушей. Если мне завтра скажут, что мы теперь меркуриал используем, то я уйду.
UPD: мне разобраться помогла книга Pro Git. Почему-то многие думают, что читать книги по гиту это перебор. Я же считаю, что не знать инструмент, которым пользуешься каждый день, вот это перебор.
Нужно только хеш.
А зачем?
`hg id` тоже не только хэш выдает, если ветка не default, или у текущего коммита есть тэги. Так что `hg id --template "{id}"` (а если есть локальные изменения, то после хэша будет ещё и "плюсик").
В итоге, не сильно-то и проще, чем `git log -1 --format="%H"`.
Не одному.
Гит был сделан какими-то инопланетянами. Для неких других инопланетян.
Нет, наверняка для каких-то неведомых существ с десятью щупальцами с отдельным мозгом в каждом из них это наверняка потрясающая штука! Но вот когда ее занесло к нам на Землю...
Если на любую вполне законную претензию к массово используемуму продукту неизменно слышишь единственную универсальную отмазку "выучите гит" "станьте ежиками" - с этим продуктом совершенно определенно "что-то не так".
да, так кажется пока не попытаешься придумать что-то лучше. идея снепшотов кажется более очевидной, пока не упрёшься в практическую реализацию. гит изоморфен процессам которые мы осуществляем в своей работе, и в этом его большое преимущество. мы не мыслим снепшотами, а мыслим небольшими изменениями, и это именно то как работает гит - он совмещает вместе кусочки кода и запоминает путь этих совмещений. поскольку мы в своей работе движемся вперёд и редко назад то аддитивная модель взаимодействия с репозиторием более адекватно представляет действия которые мы хотим совершить в виде скриптового языка. и про инфраструктуру как код тоже не надо забывать - благодаря тому что по Гиту можно путешествовать мы можем интегрировать его с devops/secops/testing/Cİ/CD практиками.
в целом то что очевидно не всегда работает очевидным образом, а иногда чтобы что-то работало очевидно нужно в корне пересмотреть подход, а также принять во внимание точки перехода количественных изменений в качественные, иногда такие сингулярные точки являются критическими при проектировании систем и меняют подход кардинально
Наоборот, хранение снапшотов вместо дельт позиционируется как основное отличие Git от других систем контроля версий.
Снимки, а не различия [Snapshots, Not Differences]
Основное отличие Git от любой другой системы контроля версий (включая Subversion и её собратьев) — это подход к работе со своими данными.
...
Это очень важное различие между Git и почти любой другой системой контроля версий. Git переосмысливает практически все аспекты контроля версий, которые были скопированы из предыдущего поколения большинством других систем.
Под снапшотами можно иметь в виду много чего, но в смежной сфере (бэкапы) под снапшотами часто понимают[1][2] уход от обычной негибкой цепочки из дельт к, эээ, "хардлинкам на блочном/файловом уровне". Мы можем удалить любой снапшот и физически удалятся только те блоки/файлы, на которые не осталось ссылок.
На самом деле, конечно, Git использует "цепочки из дельт разумной длины" ради сжатия, как и остальные системы контроля версий. И ему, конечно, нельзя удалять старые состояния как в бэкапах - в сфере контроля версий нужна вся история и иммутабельность. О какой тогда принципиальной разнице говорит Git Book? Либо это восторженная реклама, либо у Git на самом деле есть "более сильная абстракция снапшота", но верится с трудом и доказательств путём сравнения с, например, Hg не видно.
Имеет значение - на что слияние смотрит, когда конфликты определяет и решает, куда что вставилось. На дельты или на снапшоты.
В SVN, например, до какой-то версии (потом это как-то починили), если файл привести к одному и тому же состоянию разными способами в разных ветках - оно упорно не хотело сливать, последовательно просматривая изменения и ругаясь про "вот тут и тут эти строчки менялись, давай решай, что делать". А то что прямо сейчас файл и там и там одинаковый - это, видимо, не считается.
В Git Book интересно, что
заявление касается систем нового поколения (т.е. 2005+ и распределённых)
речь идёт в том числе о хранении: "storing data as changes to a base version of each file", "Git doesn’t think of or store its data this way"
есть чёткое противопоставление: наши дельты - это скрытая деталь реализации, их дельты - часть неудачного интерфейса (протекают в интерфейс)
где этот неудачный интерфейс в новых системах? hg repack, fossil repack существуют; с упомянутым в книге bazaar не знаком, но пишут, что он "stores a set of related file versions together, and then does gzip entropy compression across the whole set of them"
стиль этого раздела выглядит очень напористо (словно он должен провозглашать правильность отсутствия отслеживания переименований)
hg repack
Мда, это не то, о чём я думал, это часть расширения для кэширования данных с сервера.
А про хранение документация говорит, что "once an object is in the store, it is in its final place in the store and no further optimization is performed".
Ближе к теме revlog.reuse-external-delta=no
и настройки сжатия (generaldelta
, revlog-compression-zstd
,...).
Ещё к вопросу первичности дельт vs снапшотов в разных системах:
Subversion manages versioned trees as first order objects (the repository is an array of trees), and the changesets are things that are derived (by comparing adjacent trees.) Systems like Arch or Bitkeeper are built the other way around: they're designed to manage changesets as first order objects (the repository is a bag of patches), and trees are derived by composing sets of patches together.
Человек, писавший это, был действительно очень мотивирован, когда покупал за $2.5к домен для пет-проекта по сути
Или для него потратить 2.5к не страшнее покупки лишней чашки кофе.
Люди для пет-проектов 3Д принтеры покупают.
В оригинале написано
And thankfully the domain devlands.com was available for a whopping... $10.46.
Пока слабо представляется полезность, демо версию бы скачал. Автор молодец, так держать (знаю по собственному опыту как подобная похвала мотивирует дальше заниматься своим делом описанным в собственной статье)
На первой картинке сразу возникает непонятность.
Куда направлена ось времени? Вправо или влево?
Что означают стрелки? "Коммит произошел от" или "Указываю на следующий коммит"?
В этой игре визуально можно понять, почему происходит отвал HEAD при элементарной команде "git checkout <хеш_коммита>"?
А игра покажет, почему git находится в разных состояниях при команде "git checkout <имя_ветки>" и "git checkout <хеш_последнего_коммита_в_ветке>?
Основная цель Devlands — сделать Git и кодинг более понятным для обычного пользователя, даже если у него нет или почти нет опыта в кодинге.
Мне кажется, что это большое заблуждение. Человеку, который не использует эту систему на постоянной основе, не нужны эти знания. Тем более они выветрятся без практики очень быстро. А тому, кто понимает зачем ему Git, тому не нужна игра, ему нужна практика.
Человеку, который не использует эту систему на постоянной основе, не нужны эти знания.
Именно про Git можно согласиться. Но вот просто про Version Control и версионирование надо бы знать всем, кто работает с текстами. Т.е. практически вообще всем.
Я столкнулся с проблемой версионирования объектов в 3Д пакете blender. Очень часто бывает, что работаешь над чем-то и хочется сделать чекпоинт, так как есть риск пойти по ложному пути и порушить результат многодневного труда.
Если бэкапить файлы целиком, получается нерациональное расходование места на диске. Бывает так, что работаешь над объектом который занимает в памяти мегабайты, но в том же файле находится неизменный объект в виде 3Д скана на сотни мегабайт. И он дублируется в каждый бэкап.
Я уже голову сломал как быть и пока что пришел к такому методу:
1) В проекте есть группа которая называется "backup" куда я дублирую промежуточные и хорошие обьекты к которым можно вернуться и откатиться, если пошел по ложному пути. Стараюсь им назначать осмысленные имена и иногда дату включаю в имя объекта. Например "face_apply_modificators_10mar".
И я не знаю как иначе этот хаос контролировать. Поделился актуальным, извиняюсь за некоторый оффтоп.
Из опыта не совсем такой, но похожей ситуации: меняющийся компактный код и текстовые настройки плюс огромные статичные файлы, перемешанные в поддиректориях проекта. Соотношение переменного к статичному (по количеству файлов, не по размеру) тоже где-то 100:1. То есть, если делать version control на месте, то ignore list будет в разы длиннее списка включенных файлов.
Решение: скрипт (ant, nant, whatever) копирует только изменяемые файлы (по определенным предсказуемым паттернам, так что не надо гоняться за отдельными файлами) в стороннюю директорию, и уже она идет в version control.
У вас сложнее: динамика-статика внутри одного файла. Но, насколько я помню, в Блендере есть скриптинг. Если скрипт может выбрать объекты по простым признакам (хоть только по именам, но вдруг и вовсе по времени изменения) и выгружать их в другой блендер-файл... Попробуйте копнуть в этом направлении.
О, я вспомнил что в блендере есть замечательная штука — линковка объектов между файлами. Т.е. всю тяжеловесную статику можно сгрузить в один файл и прилинковать оттуда в рабочий :-)
О да - теперь в путь!
Я-то в Блендере провел дай бог 20-30 часов своей жизни, так что и не мог помнить таких деталей... Ну а теперь, когда есть способ разнесения статики-динамики по разным файлам - задача просто сводится к традиционной. Если динамика может лежать где угодно в файловой системе - то прямо там ее можно и "версить". Если они таки перемешаны по необходимости "с чем попало" - игра с игнор-листами. Если игноры становятся unmanageble - селективное (полу)авто-копирование в версионную директорию.
... "жалкого Intel Macbook Pro 2020 года."
Смешно.
Я мучился с Git, поэтому создал про него игру