Pull to refresh

Comments 28

PinnedPinned comments

Поздравляю, вы изобрели мерж стратегию ours

Только вместо одной команды ввели десять.

А для мимокрокодилов... в чем отличие от ребейза?

Это другой путь. Да, можно отребейзить, но у вас возникнет много конфликтов, которые надо будет решать, и да, это можно сделать дополнительными скриптами. Здесь задача была быстро и просто получить состояние как у ветки и быть уверенным что я точно ничего не проморгал, и явное указание дерева гарантирует мне что я получил точно то, что заказал.

Rebase двух несовместимых веток, это изменения истроии. А значит push --force в мастер.

Изменения истории значит что все кто наследовал ветки от мастера получат ветки с новой историей и надо будет это решать. И зачастую там нужно будет решать конфликты не в своём коде. Я когда попал на такое, просто удалил свои ветки и сделал всё заново. (Из за сломанного CI, ветки были не очень свежие).

Это своего рода эквивалент того, что все файлы из старого мастера заменили файлами из нового во время мержа. Внутри гита отличия будут, потому что это два разных дерева файлов, но с точки зрения пользователя отличий нет. Даже blame будет одинаковым.

Но вариант из поста сильно быстрее, если знаешь, что делаешь - не нужен второй чекаут из которого копировать файлики.

надо попробовать ручками скопировать файлы и посмотреть что будет, я думаю есть шансы получить строго то же самое дерево с тем же хешом, файлы то те-же

git cat-file -p 74092e5acd734a7df459ca4b08f4e88f451096f9
tree 6fac19212aba1d31d2df5ad6498cdb4b111a2022
parent 193cf791417f6fb8a48fd8eb123c1bd53ffac10a
parent 338cb13ada6efdbd9a3610adeab7700fb1ba91d2
author ***** <*****> 1699871047 +0300
committer ***** <*****> 1699871047 +0300

manual force commit newMaster to master with fake merge, because old master is obsolete
git cat-file -p 7476ca3bbeecf04eeb9684b3f4c3960a7cdb3a0b
tree 6fac19212aba1d31d2df5ad6498cdb4b111a2022
parent f719d58b010c0b70e8fdefcff2ecbc3e7fddda54
author ***** <*****> 1699885027 +0300
committer ***** <*****> 1699885027 +0300

test commit

Воспроизвёл, да одно и то же дерево

Вот тот самый комментарий, который лучше статьи. Ведь git нам нужен не как хранилище файлов, а для просмотра истории. И вот без объяснения, как эти ручные перлы будут восприниматься не такими подкованными разработчиками как автор, очень важно. А то потом он уволится, а кому-то придется разбираться, что же тут произошло...

Поздравляю, вы изобрели мерж стратегию ours

Только вместо одной команды ввели десять.

Это опция стратегии ort

Стратегия ours ниже

Признаю, да, она делает ровно то, что я изобразил

ours

This resolves any number of heads, but the resulting tree of the merge is always that of the current branch head, effectively ignoring all changes from all other branches. It is meant to be used to supersede old development history of side branches. Note that this is different from the -Xours option to the recursive merge strategy.

и даже назначение тоже самое. Да. Спасибо, буду знать, пойду расковыряю когда она появилась.

Единственное отличие в том что это мердж в себя, и сделать так как я написал, когда это мердж в master, не получится, это будет другой порядок парентов, но, да, это будет _ровно то же самое_ что я тут написал в кучу кода

Чтобы был нужный порядок парентов можно взять theirs

UPD. Попутал, нет theirs как стратегии.

note that, unlike ours, there is no theirs merge strategy to confuse this merge option with.

Можно было бы, существуй такая стратегия.

А пока есть только опция у ort, которая только конфликты автоматически разрешает в нужном направлении.

Более того, я сейчас подумал и понял ours в том виде как сделано в гите более правильно, когда мы мержим master в newMaster. newMaster и должен быть первым парентом, именно он был основной правильной веткой разработки и должен стоять первым.

Ещё раз спасибо, в пост внесён апдейт.

нужно просто забыть старый мастер

Но вы ничего не забыли, оно по-прежнему живёт в истории.

да, живёт, и пусть там лежит. Удалить запушенное без форса нельзя, да и зачем? Эффектов оно из истории никаких не создаёт.

Откуда я знаю зачем, это вы сформулировали так задачу.

Прикольно, не знал что так можно. Я однажды делал что-то похожее но немного по-тупому - через git merge с конфликтами и потом git rm -rf . && git checkout . -- newMaster && git commit

когда я изобретал это в первый раз, мне нужно было перетереть состояние ветки одним из старых состояний в репе в которой под миллион бинарных файлов, суммарным весом в десятки гигабайт. И чтобы не делать два чекаута и руками не переносить, решил поупражняться таким образом, сработало.

Вы же не мастер меняете а ветку по умолчанию, у кого то она называется master, у кого то main, у кого то develop. Достаточно как в комментарии выше смержить в новую ветку со всей историей, а старую впоследствии можно свободно удалить.

нет, никакого отношения к смене ветки по умолчанию указанная процедура не имеет. Ветка по умолчанию остаётся та же, я делаю так, чтобы эта ветка приобрела контент от другой ветки. Если бы я поменял ветку по умолчанию на сервере, это всё равно не позволило бы мне там её назвать старым именем, и коллеги простым pull не переехали бы на неё

Почему вы считаете, что push --force, упомянутый в заголовке, решает эту задачу? Коллеги не увидят вашего переименования и вам придется попросить их поудалять свои мастеры и распаковать заново вашу новую версию. Причем так потеряется история старого мастера.

Потому что именно в такой формулировке я обычно слышу просьбу от коллег которые хотят заменить мастер. И в посте я упоминаю про проблемы коллегам в этом случае.

Их мастер вы заменить не в стостоянии. Он же на их компьютерах.

Наверное проблема именно в неправильных формулировках. В том числе в том, как сформулирован заголовок вашей статьи. Я несколько раз его перечитал и не понял о чем речь. Лишь далее по тексту немного прояснилась хотелка.

Наверное надо было уточнить, что хочется не ветку заменить, а состояние проекта в этой ветке. Сама ветка остается там же и коллеги легко продолжат в ней работать обновившись через простой fetch/pull

Наверно правильная фокмулировка, чтобы указатель с именем "мастер" у всех участников перехал на правильный коммит. То есть что при git checkout master; git fetch; git merge origin/master; произошёл fast-forward.

Название статьи должно было звучать так:
Как в Git залить контент другой ветки в master, избежав всех конфликтов

оказалось что практически тоже самое можно сделать одной командой

Ваша одна команда меняет только newmaster, а master остаётся сломанным.
Забыли обновить сам master. Полное решение будет чуть длиннее:

git checkout newmaster — находясь в «хорошей» ветке

git merge --strategy=ours master — создать коммит слияния со сломанной веткой, полностью игнорируя содержимое сломанной ветки

git checkout master — перейти в сломанную ветку

git merge -ff newmaster — переместить указатель мастера на созданный коммит слияния

подписывая все хешики команд в блокнотик рядом

Вы знали, что сам Git ничего не удаляет и вообще записывает за вас все хешики в свой журнал reflog?

для того чтобы branch -f master сработал, ибо запрещено менять ветку на который сейчас находишься

Чем вам не понравился reset? Он делает то же самое, но на текущей ветке.

порядок указания предков определяет как графические утилиты будут показывать направление мерджа

Порядок предков в гите абсолютно ни на что не влияет.

А всю вашу длинную инструкцию можно заменить одной командой.
Находясь в master сделать:
git merge --ff $(git commit-tree -p newmaster -m "Override master with newmaster" newmaster^{tree})

Sign up to leave a comment.

Articles