Comments 62
Да.
Не совсем понятно, почему не сделать для каждой выделенной библиотеки отдельный репозиторий, а не таскать изменения туда-сюда между ветками?
да,git это позволяет, буквально сегодня делал
Т.е. он и примет 8, и заблокирует 9 правки на схеме?
он спросит что делать если не сможет очевидным образом разрешить коллизию через diff3
Понятно, значит он разрешит оба мержа, жаль, конечно, мог бы и догадаться, что на левой ветке 5 правка уже есть.
нет, он не сможет наложить повторно одну и ту же правку, diff так не работает
строго говоря он начнёт вас спрашивать ещё на этапе 3-8
строго говоря он начнёт вас спрашивать ещё на этапе 3-8
И про 8 тоже спросит? А чего там спрашивать?
ну если я правильно понял схему то 3 патчит 4,4 меняется на 6, 6 патчит 7 и 7 меняется на 8, а значит патч 3 уже в комплекте
если же на однои из этапов патч 3->4 полностью откатывается то спрашивать не будет, если не полностью то будет попытка решить это самостоятельно, и если не выйдет будет вопрос
если же на однои из этапов патч 3->4 полностью откатывается то спрашивать не будет, если не полностью то будет попытка решить это самостоятельно, и если не выйдет будет вопрос
Не совсем так, на схеме изображены три ветки одного и того же проекта, время идет снизу вверх. Стрелки — это merge, т.е. перенос какой-то правки или их группы с одной ветки на другую. Вот история этой схемы:
1. От ствола ответвляются правая и левая ветки.
2. На стволе производятся изменения.
3. На правой ветке производятся изменения.
4. Изменения 3 переносятся на ствол.
5. На правой ветке еще производятся изменения.
6. Изменения 5 переносятся на ствол.
7. Изменения правок 2 и 6 переносятся на левую ветку.
8. Изменения 3 с правой ветки переносятся на левую.
9. Изменения 5 с правой ветки переносятся на левую.
1. От ствола ответвляются правая и левая ветки.
2. На стволе производятся изменения.
3. На правой ветке производятся изменения.
4. Изменения 3 переносятся на ствол.
5. На правой ветке еще производятся изменения.
6. Изменения 5 переносятся на ствол.
7. Изменения правок 2 и 6 переносятся на левую ветку.
8. Изменения 3 с правой ветки переносятся на левую.
9. Изменения 5 с правой ветки переносятся на левую.
если 5-я правка уже есть, он ее пропустит если при наложении патча ничего не меняется
лишнего коммита не будет
лишнего коммита не будет
вообще в git совершенно другая схема работы с ветками, там ветки делаются в больших количествах и есть удобные инструменты для сведения веток
вы не мержили переименование файлов с изменением. вот это весело
Работаю с Mercurial и суть такова:
Попытка сделать 3 -> 8
Попытка сделать 3 -> 8
Работаю с Mercurial и суть такова:
Попытка слить 2 и 6 в 7 одновременно лишена смысла, т.к. изменение 2 уже содержится внутри 6.
Аналогично с 3 -> 8, и 5 -> 9: Mercurial не даст сделать такое слияние. Я сделал небольшой тестовый репозиторий для Вас и вот что получается:
Попытка слить 2 и 6 в 7 одновременно лишена смысла, т.к. изменение 2 уже содержится внутри 6.
Аналогично с 3 -> 8, и 5 -> 9: Mercurial не даст сделать такое слияние. Я сделал небольшой тестовый репозиторий для Вас и вот что получается:
>hg merge -r3 -r8
abort: can't merge with ancestor
>hg merge -r5 -r9
abort: can't merge with ancestor
abort: can't merge with ancestor
>hg merge -r5 -r9
abort: can't merge with ancestor
> Попытка слить 2 и 6 в 7 одновременно лишена смысла, т.к. изменение 2 уже содержится внутри 6.
Как это? Изменения 2 и 6 — это два совершенно разных изменения, в одном мы делаем что-то одно, а в другом — что-то другое.
Смотрите, допустим этот проект вначале состоит из одного файла содержащего три строки, все это на всех трех ветках:
Как это? Изменения 2 и 6 — это два совершенно разных изменения, в одном мы делаем что-то одно, а в другом — что-то другое.
Смотрите, допустим этот проект вначале состоит из одного файла содержащего три строки, все это на всех трех ветках:
А А А Б Б Б В В В 2. На стволе добавляется строка А А А Б Б Б В В В Г 3. На правой ветке строка 1 изменена А А АА Б Б Б В В В Г 4. Переносим изменение 3 на ствол А АА АА Б Б Б В В В Г 5. Строка 2 на правой ветке изменена А АА АА Б Б ББ В В В Г 6. Переносим изменение 5 на ствол А АА АА Б ББ ББ В В В Г 7. Переносим изменения 2 и 6 на левую ветку А АА АА ББ ББ ББ В В В Г Г 8. Переносим изменение 3 с правой ветки на левую АА АА АА ББ ББ ББ В В В Г Г 9. Пытаемся перенести изменение 5 (ББ) с правой ветки на левую - получаем конфликт
Видите в чем суть, на шаге 7 в моей схеме все три ветки разные, в вашей схеме вы каждым мержем переносите все возможние изменения с одной ветки на другую, я же говорю о выборочном переносе только некоторых изменений.
выборочно переносить изменения — это ад, в котором потом нельзя разобраться
Если есть программная платформа, на основе которой строятся все проекты, то изменения уже делятся на два класса — нужные только в конкретном проекте и полезные для платформы в целом. Вы ответвляете проект, вносите ив него и первые, и вторые изменения, а потом только вторые переносите обратно на ветку платформы. Разве это не типичный сценарий использования?
Пока писал длинные ответ, Вы в целом описали свою проблематику.
Могу дать такой совет, как это должно было бы быть сделано в распределённой системе (Mercurial в частности).
Первый класс изменений ведётся в ветке 1.
Второй класс изменений (под проект Х) ведётся в ветке 2.
Если появляется проект Y, то под него заводится ветка 3.
Все слияния (переносы изменений) делать в направлении 1 -> 2 и 1 -> 3.
Никаких потребностей в выборочных переносах при этом появиться не должно.
Ревизия при слиянии в другую ветку (merge) тянет за собой всех предков — и именно это предотвратит конфликт на шаге 9 в изначальном примере.
Могу дать такой совет, как это должно было бы быть сделано в распределённой системе (Mercurial в частности).
Первый класс изменений ведётся в ветке 1.
Второй класс изменений (под проект Х) ведётся в ветке 2.
Если появляется проект Y, то под него заводится ветка 3.
Все слияния (переносы изменений) делать в направлении 1 -> 2 и 1 -> 3.
Никаких потребностей в выборочных переносах при этом появиться не должно.
Ревизия при слиянии в другую ветку (merge) тянет за собой всех предков — и именно это предотвратит конфликт на шаге 9 в изначальном примере.
Да, вы правы, теперь мы так и делаем, попытка «множественного наследования» оказалась неудачной, думаю она в принципе не реализуема на современных системах, т.к. в ней нет потребности.
Предвижу следующий вопрос с Вашей стороны:
«А что если в проекте Y будут сделаны изменения (добавлена одна функция), которая может потом пригодится в проекте X — для этого ведь понадобится передать частичное изменение (без всех предков) из Y -> X».
Отвечаю: поскольку, частичная передача изменений без ревизий-предков противоречит всей коцепции веток и слияний, делать следует так:
Для всех общих функций в проектах X и Y заводится четвёртая ветка под названием «4(XY) — общее для проектов X и Y» и слияния просиходят по следующей схеме:
1(Платформа) -> 4(XY) -> 2(X)
и
1(Платформа) -> 4(XY) -> 3(Y).
Ещё вопрос: «А что если полезная функция была УЖЕ внесена в 3(Y) и теперь мы хотим перенести её в ветку для проекта X?»
Да, можно отщепить эту функцию старым дедовским способом, взяв отдельный diff из ветки 3(Y) и наложив его на ветку 2(X). Но это плохое решение. А если эту функцию потом надо будет немного усовершенствовать причём для двух проектов сразу? Придётся возиться в обоих ветках, либо опять гонять diff вручную.
Именно для из этих соображений, я предлагаю Вам ветку 4(XY). Выносить всё общее для двух проектов нужно туда (по аналогии с глобально-общей-для всех проектов веткой 1).
Итак, я всё ещё не ответил на вопрос: как средствами Mercurial правильно перенести функцию УЖЕ написанную в ветке 3(Y) куда-то в более подходящее ей место (4XY или 1), если она потребовалась в нескольких проектах одновременно? И не отвечу, ибо не знаю прямо сейчас :) Обычно я заранее планирую что и где должно лежать и пользуюсь строгой последовательностью слияний от общего к частному.
У меня пока одна идея: использовать функциональность распределённых систем под названием Rebase. Подробности опускаю, т.к. не сам не пробовал, только читал в доках.
«А что если в проекте Y будут сделаны изменения (добавлена одна функция), которая может потом пригодится в проекте X — для этого ведь понадобится передать частичное изменение (без всех предков) из Y -> X».
Отвечаю: поскольку, частичная передача изменений без ревизий-предков противоречит всей коцепции веток и слияний, делать следует так:
Для всех общих функций в проектах X и Y заводится четвёртая ветка под названием «4(XY) — общее для проектов X и Y» и слияния просиходят по следующей схеме:
1(Платформа) -> 4(XY) -> 2(X)
и
1(Платформа) -> 4(XY) -> 3(Y).
Ещё вопрос: «А что если полезная функция была УЖЕ внесена в 3(Y) и теперь мы хотим перенести её в ветку для проекта X?»
Да, можно отщепить эту функцию старым дедовским способом, взяв отдельный diff из ветки 3(Y) и наложив его на ветку 2(X). Но это плохое решение. А если эту функцию потом надо будет немного усовершенствовать причём для двух проектов сразу? Придётся возиться в обоих ветках, либо опять гонять diff вручную.
Именно для из этих соображений, я предлагаю Вам ветку 4(XY). Выносить всё общее для двух проектов нужно туда (по аналогии с глобально-общей-для всех проектов веткой 1).
Итак, я всё ещё не ответил на вопрос: как средствами Mercurial правильно перенести функцию УЖЕ написанную в ветке 3(Y) куда-то в более подходящее ей место (4XY или 1), если она потребовалась в нескольких проектах одновременно? И не отвечу, ибо не знаю прямо сейчас :) Обычно я заранее планирую что и где должно лежать и пользуюсь строгой последовательностью слияний от общего к частному.
У меня пока одна идея: использовать функциональность распределённых систем под названием Rebase. Подробности опускаю, т.к. не сам не пробовал, только читал в доках.
Да, понятно, но мы с вами по-моему несколько все усложнили)
Я могу перефразировать вопрос так: отслеживает ли система откуда и какие именно атомарные изменения пришли. если они прошли через несколько разных веток?
Я так понимаю по нашей дискуссии, что и для mercurial, ответ все-таки нет.
Я могу перефразировать вопрос так: отслеживает ли система откуда и какие именно атомарные изменения пришли. если они прошли через несколько разных веток?
Я так понимаю по нашей дискуссии, что и для mercurial, ответ все-таки нет.
Выборочный перенос изменений в git'е называется cherry-pick, реализован очень просто и без проблем взаимодествует с полными мерджами. То есть вы можете черри-пикать отдельные коммиты из ветки в ствол, а потом слить всю ветку целиком без всяких конфликтов.
Наверняка в mercurial есть аналогичный инструмент.
Наверняка в mercurial есть аналогичный инструмент.
нет
типичный сценарий — это появились изменения полезные для платформы — сделали их в транке и смержили в ветки
типичный сценарий — это появились изменения полезные для платформы — сделали их в транке и смержили в ветки
Можно, но неудобно, отлаживать на ветке а потом руками переносить на ствол. откатывать на ветке, и снова мержить со ствола.
Внимательно прочитал Ваш пример и вы абсолютно правы: я переношу ВСЕ возможные изменения с одной ветки на другую, а Вы выборочно.
Ваш вопрос: можно ли в Mercurial переносить изменения по вашей схеме и не получить конфликт на шаге 9?
Я никогда не пробовал переносить изменения выборочно, как это описали Вы.
В частности, меня удивил пункт «7. Переносим изменения 2 и 6 на левую ветку», в результате которого на левой ветке в первой строке осталась одна буква «А». Чтобы добавить вторую букву A вы делаете дополнительный перенос изменения 3.
Вопрос концептуальный: зачем вам понадобился такой контроль версий? Возможно, это из-за специфики работы с SVN…
Если всё-таки необходимо переносить изменения вот так атомарно, то первое что приходит на ум: чтобы сделать выборочный перенос, нужно брать diff от версии N и N-1 (то самое выборочное изменение), сохранять его в файл и накладывать на другую ветку (patch) — но контроль версий тут уже не причём, с этим справится любая diff/patch программа и, естественно, в итоге на пункте 9 будет конфликт.
Второе что приходит на ум: в Mercurial есть расширение под названием MQ — реализует очередь патчей и позволяет проводить всякие хитрые манипуляции. Возможно, даже, удастся реализовать эту схему без конфликтов. Я не спец по mq, в бою не пробовал.
Но повторюсь ещё раз, скорее всего, Вам надо задуматься о самом подходе к веткам — почему Вы хотите копировать изменения выборочно?
Вернусь к Вашему примеру:
7. Переносим изменения 2 и 6 на левую ветку
В левой ветке в первой строке одна буква A.
В левой ветке во второй строке две буквы ББ, которые (если проследить цепочку) пришли из изменения «5. Строка 2 на правой ветке изменена»:
Изменение 5 в свою очередь было сделано поверх изменения «3. На правой ветке строка 1 изменена»:
Для меня, как для разработчика, возникает подозрение: если изменение 5 было сделано поверх 3 — скорее всего 5 зависит от 3? ББ во второй строке не скомпилируется без АА в первой?
А если так, то переносить ББ отдельно от АА — в чём смысл этих атомарных переносов?
Если же ББ никак не зависит от АА и в будущем есть потребность переносить ББ, не перенося AA — их следует сделать в двух разных ветках! Эту будут ревизии без связи предок-потомок и их можно будет атомарно как угодно переносить между ветками, не получив в итоге на шаге 9 никаких конфликтов (ибо память у Mercurial основана на ревизиях, которые однако переносятся между ветками вместе со всеми своими предками). Могу сделать пример и показать.
Таким образом, Ваша схема с атомарными переносами могла бы быть реализована бОльшим числом веток (каждое атомарное изменение производится в своей ветке, а потом комбинируй их как хочешь!) — но концептуально, это лишнее.
Боюсь я немного запутанно описал свои мысли.
Попробуйте прочитать вот эти две более стройные статьи с картинками про ветки и различные use case'ы:
stevelosh.com/blog/2009/08/a-guide-to-branching-in-mercurial/
nvie.com/posts/a-successful-git-branching-model/
Ваш вопрос: можно ли в Mercurial переносить изменения по вашей схеме и не получить конфликт на шаге 9?
Я никогда не пробовал переносить изменения выборочно, как это описали Вы.
В частности, меня удивил пункт «7. Переносим изменения 2 и 6 на левую ветку», в результате которого на левой ветке в первой строке осталась одна буква «А». Чтобы добавить вторую букву A вы делаете дополнительный перенос изменения 3.
Вопрос концептуальный: зачем вам понадобился такой контроль версий? Возможно, это из-за специфики работы с SVN…
Если всё-таки необходимо переносить изменения вот так атомарно, то первое что приходит на ум: чтобы сделать выборочный перенос, нужно брать diff от версии N и N-1 (то самое выборочное изменение), сохранять его в файл и накладывать на другую ветку (patch) — но контроль версий тут уже не причём, с этим справится любая diff/patch программа и, естественно, в итоге на пункте 9 будет конфликт.
Второе что приходит на ум: в Mercurial есть расширение под названием MQ — реализует очередь патчей и позволяет проводить всякие хитрые манипуляции. Возможно, даже, удастся реализовать эту схему без конфликтов. Я не спец по mq, в бою не пробовал.
Но повторюсь ещё раз, скорее всего, Вам надо задуматься о самом подходе к веткам — почему Вы хотите копировать изменения выборочно?
Вернусь к Вашему примеру:
7. Переносим изменения 2 и 6 на левую ветку
А АА АА ББ ББ ББ В В В Г Г
В левой ветке в первой строке одна буква A.
В левой ветке во второй строке две буквы ББ, которые (если проследить цепочку) пришли из изменения «5. Строка 2 на правой ветке изменена»:
А АА АА Б Б ББ
Изменение 5 в свою очередь было сделано поверх изменения «3. На правой ветке строка 1 изменена»:
А А АА
Для меня, как для разработчика, возникает подозрение: если изменение 5 было сделано поверх 3 — скорее всего 5 зависит от 3? ББ во второй строке не скомпилируется без АА в первой?
А если так, то переносить ББ отдельно от АА — в чём смысл этих атомарных переносов?
Если же ББ никак не зависит от АА и в будущем есть потребность переносить ББ, не перенося AA — их следует сделать в двух разных ветках! Эту будут ревизии без связи предок-потомок и их можно будет атомарно как угодно переносить между ветками, не получив в итоге на шаге 9 никаких конфликтов (ибо память у Mercurial основана на ревизиях, которые однако переносятся между ветками вместе со всеми своими предками). Могу сделать пример и показать.
Таким образом, Ваша схема с атомарными переносами могла бы быть реализована бОльшим числом веток (каждое атомарное изменение производится в своей ветке, а потом комбинируй их как хочешь!) — но концептуально, это лишнее.
Боюсь я немного запутанно описал свои мысли.
Попробуйте прочитать вот эти две более стройные статьи с картинками про ветки и различные use case'ы:
stevelosh.com/blog/2009/08/a-guide-to-branching-in-mercurial/
nvie.com/posts/a-successful-git-branching-model/
Спасибо за подробный ответ.
Попробую объяснить зачем мы используем атомарные мержи)
Мы разрабатываем веб-проекты на основе собственного платформы, которая представляет собой некий минимальный сайт с базовыми возможностями. При создании нового проекта мы ответвляем его от ветки платформы и добавляем нужную в данном конкретном случае функциональность. И конечно же в процессе этого мы исправляем и дополняем общий функционал, причем изменения, специфичные для проекта произвольно чередуются с изменениями в общей платформе, и их мы потом и переносим выборочно на исходную ветку платформы.
По-моему, это самый очевидный и прямой путь, как по-другому это можно организовать?
Попробую объяснить зачем мы используем атомарные мержи)
Мы разрабатываем веб-проекты на основе собственного платформы, которая представляет собой некий минимальный сайт с базовыми возможностями. При создании нового проекта мы ответвляем его от ветки платформы и добавляем нужную в данном конкретном случае функциональность. И конечно же в процессе этого мы исправляем и дополняем общий функционал, причем изменения, специфичные для проекта произвольно чередуются с изменениями в общей платформе, и их мы потом и переносим выборочно на исходную ветку платформы.
По-моему, это самый очевидный и прямой путь, как по-другому это можно организовать?
вот и переносите изменения из ветки в ствол и из ствола в другие ветки. а гонять изменения между всеми ветками — вы быстро запутаетесь. а в случае неатомарных коммитов, которые неизбежны, как бы вы всё не перепроверяли, придётся ещё и следить чтобы перемёрживались правильные их группы.
Вы ошиблись, merge tracking в Subversion появился начиная с версии 1.5.0.
Я так понимаю, эти проблемы происходят из того, что при мерже веток в свне остаются обе ветки (и ствол, и бранч). Хотя на самом деле необходимо в этом месте «закрыть» одну из веток (слияние же!). При последующих расхождениях будет создана новая ветвь, которую тоже можно смержить. Т.е. в свн все выглядит так:
| |
|\
| |
| |
А по идее должно быть так:
|
|\
| |
| |
DVCS (например, меркуриал) предлагают более подходящую модель. Ветки могут появляться где угодно и когда угодно, но при слиянии их результатом будет 1 ветка, а не 2. Естественно, влить заново изменения из уже смерженной ветки не выйдет, поскольку они УЖЕ включены в результирующую ветку и являются частью ее истории. Это все равно что просить систему сделать один и тот же коммит 2 раза подряд.
| |
|\
| |
| |
А по идее должно быть так:
|
|\
| |
| |
DVCS (например, меркуриал) предлагают более подходящую модель. Ветки могут появляться где угодно и когда угодно, но при слиянии их результатом будет 1 ветка, а не 2. Естественно, влить заново изменения из уже смерженной ветки не выйдет, поскольку они УЖЕ включены в результирующую ветку и являются частью ее истории. Это все равно что просить систему сделать один и тот же коммит 2 раза подряд.
Простите, не понял — почему все-таки не svn externals?
А как оно тут поможет?
Выносим ядро и библиотеки в отдельные репозитарии. Начиная новый проект, подключаем ядро и нужные модули externals'ами. В процессе работы, если в модуль вносятся общеполезные правки, они коммитятся, оказываясь в соответствующем репозитарии и становясь доступными всем проектам.
Ну, а специфичные для проекта правки делаем в тех файлах, которые специфичны для проекта.
Ну, а специфичные для проекта правки делаем в тех файлах, которые специфичны для проекта.
Да, это решение, правда повторно используемый код должен быть локализован в отдельной папке, а так не вижу в нем никаких недостатков.
если ядро и библиотеки по отдельным репам распихать, то апы будут ооочень небыстрыми.
Не без этого:( У любого решения есть цена.
а мне вот больше интересно как сделать так, чтобы можно было в своей ветке организовывать свою структуру директорий да так, чтобы можно было без проблем мержиться из ствола и заливать обратно.
сейчас я поместил каждый модуль в отдельную репу и копирую её в проект целиком, не прописывая как сабмодуль. это позволяет получать обновления из ствола модуля, но коммитить их и локальные правки в проект. всё бы хорошо, да вот развёртывать такую структуру с нуля вручную гемор, ибо при клонировании репы для модулей не клонируются. а елси прописывать их как субмодули, то они не будут комититься в проект
сейчас я поместил каждый модуль в отдельную репу и копирую её в проект целиком, не прописывая как сабмодуль. это позволяет получать обновления из ствола модуля, но коммитить их и локальные правки в проект. всё бы хорошо, да вот развёртывать такую структуру с нуля вручную гемор, ибо при клонировании репы для модулей не клонируются. а елси прописывать их как субмодули, то они не будут комититься в проект
Это не про SVN?
Как выходите из положения? Пишете скрипт развертывания/деплоя?
это в гите, конечно, в свн-е так нельзя, ибо разбрасывает свои директории по всем папкам %-)
пока никак ^^' я экспериментирую… но видимо придётся сделать скрипт, который будет собирать файлик .gitrepos и использовать его для инициализации репозиториев при апдейте
пока никак ^^' я экспериментирую… но видимо придётся сделать скрипт, который будет собирать файлик .gitrepos и использовать его для инициализации репозиториев при апдейте
Интересно было бы прочесть об этом, когда эксперименты будут завершены.
в общем, я выкрутился так: github.com/sairi-na-tenshi/wc/blob/master/init.cmd — кроссплатформенный скрипт, который инициализирует субрепозиторий.
на всякий случай напомню: SVN с 1.7 в рабочей копии служебную папку .svn держит только в корне
Да, решение с экстерналами накладывает некое ограничение на файловую структуру.
Я прекрасно ветвлюсь и мержусь в Git, вообще без проблем.
Вплоть до того, что могу внести в свой репозиторий чужой с дико другой историей в виде отдельной ветки, аккуратно смержить и отослать автору )
Вплоть до того, что могу внести в свой репозиторий чужой с дико другой историей в виде отдельной ветки, аккуратно смержить и отослать автору )
По поводу cherry-pick вы я думаю всё-таки не правы. В случае если вы сделаете cherry-pick 5-ой правки как девятой, git просто обнаружит идентичную уже объединённую ревизию и ничего не сделает. Мне часто кажется, что там внутри какая-то чистая незамутнённая магия, так что просто попробуйте и скорее всего будете счастливы :)
Sign up to leave a comment.
Чего не может SVN