LINUX.ORG.RU

git merge не конфликтует

 


0

1

Помогите разобраться с git

Есть ветки master и restructurization. Ветка master содержит боевой код. Ветка restructurization содержит большое количество коммитов и скоро должна попасть в master, но в master время от времени тоже попадают коммиты, которые должны забираться в restructurization. Так вот, уже второй раз возникла проблема с тем, что git merge ломает код, не создавая конфликтов. Пример одного из файлов:

В ветке restructurization:

[r0ck3r@desktop project]$ md5sum preload/01_domaincheck.php
8a1914036fd5f56e5f22c8bd0d524377  preload/01_domaincheck.php

[r0ck3r@desktop project]$ git log --pretty=format:%H-%ad --date=short --max-count=15 restructurization preload/01_domaincheck.php
1552eae206f2669daf9a8dbb575491d500b7349e-2020-04-13
cf6eae873456a73b9fe52961e702c9d2403a8f2b-2020-04-08
ffefd2a1c8e8b3c9f8e718f3ac57d2c996c587be-2020-04-08
0818ba5faac1e80205074c24b1cdca53b482c0cf-2020-03-31
9086bc55641f1ed8f333b28ac108776727769f99-2020-03-19
f7f34c4dcc4d9518205bd511009ab8a2945a7e2a-2020-03-19
c07ef8373e447f968bd746201aee6ca86d51afbb-2020-02-11
30c6a1573cedab5b67401a553fa7a08e6a8e4d8a-2020-01-27
604b03de922a668f409c577a25ab1d227fc1c6ff-2020-01-24
8e8eba66a2c6797cef6bce4746f32aacca50c47b-2020-01-14
7a9e6ba5c4bb9a46aa3dde9ad319d004f2dafa1d-2020-01-14
ef3de1db2f4ccd0c91d49283a8ef21277443ba60-2020-01-13
549b149d2eed7f85822344b012b0509064ada258-2019-12-18
0024d8d399c77fd536e9b13a819e1eeec89cefed-2019-12-17
8df1c91c816c99f919b8ab7652184015d13d726b-2019-12-17
В ветке master:
[r0ck3r@desktop project]$ md5sum preload/01_domaincheck.php 
3d45a473e47c067a7cfd86ca68bb49b6  preload/01_domaincheck.php

[r0ck3r@desktop project]$ git log --pretty=format:%H-%ad --date=short --max-count=15 master preload/01_domaincheck.php
b63da3de8a593cc6fc4294ce0ccc8e198df137ff-2020-05-12
0818ba5faac1e80205074c24b1cdca53b482c0cf-2020-03-31
9086bc55641f1ed8f333b28ac108776727769f99-2020-03-19
f7f34c4dcc4d9518205bd511009ab8a2945a7e2a-2020-03-19
c07ef8373e447f968bd746201aee6ca86d51afbb-2020-02-11
30c6a1573cedab5b67401a553fa7a08e6a8e4d8a-2020-01-27
604b03de922a668f409c577a25ab1d227fc1c6ff-2020-01-24
8e8eba66a2c6797cef6bce4746f32aacca50c47b-2020-01-14
7a9e6ba5c4bb9a46aa3dde9ad319d004f2dafa1d-2020-01-14
ef3de1db2f4ccd0c91d49283a8ef21277443ba60-2020-01-13
549b149d2eed7f85822344b012b0509064ada258-2019-12-18
0024d8d399c77fd536e9b13a819e1eeec89cefed-2019-12-17
8df1c91c816c99f919b8ab7652184015d13d726b-2019-12-17
cfe3980804bf07e361beec204c39dba535171830-2019-10-25
4334bcbff73bf1469bc3a5c66d78f34890c7ec5d-2019-10-24

После git merge:

[r0ck3r@desktop project]$ md5sum preload/01_domaincheck.php 
fa8380c416f0f8a59021d0ce285a63c9  preload/01_domaincheck.php

[r0ck3r@desktop project]$ git log --pretty=format:%H-%ad --date=short --max-count=15 restructurization preload/01_domaincheck.php
2932b510073e1337950bddfdfc406b7905223d08-2020-05-12
b63da3de8a593cc6fc4294ce0ccc8e198df137ff-2020-05-12
1552eae206f2669daf9a8dbb575491d500b7349e-2020-04-13
cf6eae873456a73b9fe52961e702c9d2403a8f2b-2020-04-08
ffefd2a1c8e8b3c9f8e718f3ac57d2c996c587be-2020-04-08
0818ba5faac1e80205074c24b1cdca53b482c0cf-2020-03-31
9086bc55641f1ed8f333b28ac108776727769f99-2020-03-19
f7f34c4dcc4d9518205bd511009ab8a2945a7e2a-2020-03-19
c07ef8373e447f968bd746201aee6ca86d51afbb-2020-02-11
30c6a1573cedab5b67401a553fa7a08e6a8e4d8a-2020-01-27
604b03de922a668f409c577a25ab1d227fc1c6ff-2020-01-24
8e8eba66a2c6797cef6bce4746f32aacca50c47b-2020-01-14
7a9e6ba5c4bb9a46aa3dde9ad319d004f2dafa1d-2020-01-14
ef3de1db2f4ccd0c91d49283a8ef21277443ba60-2020-01-13
549b149d2eed7f85822344b012b0509064ada258-2019-12-18

Как видно из выхлопа md5sum - версия этого файла не соответствует ни одной из веток. Почему-то git просто берет и применяет патч к файлу так, как будто он не менялся в restructurization, вместо того, чтобы сообщить о конфликте слияния. git rebase делает с этим файлом то же самое.

Вопрос: что я делаю не так?

★★★★★

Последнее исправление: r0ck3r (всего исправлений: 1)

Может быть git просто самостоятельно разрешил конфликт-то? Чаще всего ведь меняются разные части одного и того же файла и git коректно объединяет изменения?
В этом случае и md5-сумма будет новой и ручного разрешения конфликат не потребуется.
Тут в посте вроде не приведено доказательств, что git не заметил «конфликт».

PeleWin
()
Ответ на: комментарий от PeleWin

Вот коммиты файла в restructurization

1552eae206f2669daf9a8dbb575491d500b7349e-2020-04-13
cf6eae873456a73b9fe52961e702c9d2403a8f2b-2020-04-08
ffefd2a1c8e8b3c9f8e718f3ac57d2c996c587be-2020-04-08
0818ba5faac1e80205074c24b1cdca53b482c0cf-2020-03-31

Вот в master:

b63da3de8a593cc6fc4294ce0ccc8e198df137ff-2020-05-12
0818ba5faac1e80205074c24b1cdca53b482c0cf-2020-03-31

Коммит 0818ba5faac1e80205074c24b1cdca53b482c0cf - общий, а дальше идут различия, но git merge вливает коммит b63da3de8a593cc6fc4294ce0ccc8e198df137ff из master в ветку restructurization, словно в ней нет коммитов связанных с тем же файлом ffefd2a1c8e8b3c9f8e718f3ac57d2c996c587be, cf6eae873456a73b9fe52961e702c9d2403a8f2b и 1552eae206f2669daf9a8dbb575491d500b7349e

Это нормальное поведение для git? Этот проблемный коммит достаточно простой - он связан с раскомментированием одной строчки вверху файла, но это ломает код в restructurization

r0ck3r ★★★★★
() автор топика
Последнее исправление: r0ck3r (всего исправлений: 1)
Ответ на: комментарий от r0ck3r

Вроде нормальное.
А что он должен был сделать?
При слиянии создаётся новый коммит, в котором будут файлы со всеми изменениями из обеих веток. Если получится - git объединит изменения автоматически. Если не получится автоматически - всё равно создаст итоговый файл, а в нём пометит изменения из разных веток и предложит вручную внести изменения теперь.

PeleWin
()
Ответ на: комментарий от PeleWin

самостоятельно разрешил конфликт-то

есть ли какой-либо ключ, запрещающий ему делать это?

r0ck3r ★★★★★
() автор топика

Что включил, то он и смержил. Чему тут удивляться? Выбрать одну ветку надо было без патчей. Изменения могут вносить все подряд. Для того и создается ветка патчевания имеющегося кода. Если что-то криво работает - создается новый коммит, исправляющий наработки идиотов не осиливших тестирование перед отправкой коммитов. Поди разбери какой пьяный болван или школьник там что наделал. Перед патчами необходимо поддерживать тестируемую версию до отправки в раздел патчей. Как известно практически все, кто мнят себя программистами тестированием не любят заниматься. Это сделано или намеренно или по сути криво реализовано. Общий уровень «программистов» может быть весьма низким. Отсюда и эти проблемы.

anonymous
()
Ответ на: комментарий от PeleWin

Вот тут https://stackoverflow.com/questions/13975956/git-overwrites-files-during-a-me... предлагают делать git merge --no-commit --no-ff your-branch, проверять вручную и коммитить. Наверное так и буду мержить master в devel дальше Спасибо!

r0ck3r ★★★★★
() автор топика
Последнее исправление: r0ck3r (всего исправлений: 1)
Ответ на: комментарий от anonymous

ни хрена не понял, но очень интересно

r0ck3r ★★★★★
() автор топика
Ответ на: комментарий от r0ck3r

вместо того, чтобы сообщить о конфликте слияния

Значит конфликта нет, изменения непротиворечивые.

запрещающий ему делать это?

Запрещающий делать что? Мердж? Ты хочешь странного, но можешь попробовать ключ –no-commit, чтобы посмотреть все изменения и потом закоммитить мердж вручную.

связан с раскомментированием одной строчки вверху файла, но это ломает код в restructurization

А зачем это было закоммичено в мастер? Можно было этот конкретный ханк не коммитить? Если всё-таки нет, то я бы сделал тогда отдельную ветку для бэкпорта изменений из мастера и туда коммитил бы только нужные ханки. И потом уже его мержил куда надо.

no-such-file ★★★★★
()
Ответ на: комментарий от no-such-file

попробовать ключ –no-commit, чтобы посмотреть все изменения

так и сделал сейчас

А зачем это было закоммичено в мастер? Можно было этот конкретный ханк не коммитить?

конкретно это можно было не коммитить. Привел этот случай, так как он произошел только что. Но некоторое время назад в master попало другое изменение, добавляющее метод в некоторый базовый класс, но метод с таким же именем уже имелся в этом базовом классе в ветке restructurization, в результате слияние прошло без конфликтов, а код был сломан, так как он имел два метода с одинаковым именем в одном классе (это PHP)

r0ck3r ★★★★★
() автор топика
Последнее исправление: r0ck3r (всего исправлений: 1)
Ответ на: комментарий от no-such-file

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

можно подробнее? Куда девать такие спорные коммиты?

r0ck3r ★★★★★
() автор топика
Ответ на: комментарий от r0ck3r

Почему бы просто не закомментировать у себя в ветке restructurization «ломающую строку»? Не вижу никаких побочных эффектов от этого.
Рано ведь или поздно ветки всё равно придётся сливать? Вот сейчас после решения проблемы с «ломающей строкой» ветка restructurization готова к бесконфликтному вливанию в master (если master не изменилась).

PeleWin
()
Ответ на: комментарий от PeleWin

ну я так и сделал. Просто мне нужен способ выловить при слиянии все такие строки. Пока вариант git merge --no-ff --no-commit master выглядит наиболее оптимальным

r0ck3r ★★★★★
() автор топика
Ответ на: комментарий от r0ck3r

Куда девать такие спорные коммиты?

Всё должно быть по веткам рассовано. Чтобы потом мержить в restructurization только те ветки, которые его не ломают. Не нужно весь мастер мержить. В любом случае придётся контролировать, но хотя бы мелкие патчи на мастере, не относящиеся к новым фичам, не будут мешаться.

no-such-file ★★★★★
()

Почему-то git просто берет и применяет патч к файлу так, как будто он не менялся в restructurization, вместо того, чтобы сообщить о конфликте слияния

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

slovazap ★★★★★
()
Ответ на: комментарий от r0ck3r

Но некоторое время назад в master попало другое изменение, добавляющее метод в некоторый базовый класс, но метод с таким же именем уже имелся в этом базовом классе в ветке restructurization,

git - это не ИИ, он не может понять, совместимы ли изменения логически (т.е, не вызовет ли слияние ошибку компиляции или неправильную работу программы)
гит смотрит только на то, совместимы ли изменения позиционно
например, тут поменяли начало файла, а там - конец файла, тогда гит подумает, что эти изменения совместимы друг с другом, и «сольёт втихую»
прежде чем мёрджить, нужно понять, что именно ты мёрджишь
если у тебя в репе две несовместимые ветки (программисты первой ветки не имели представления о том, что писали программисты второй ветки), то нахрена их мёрджить?
сначала посмотри каждую ветку (diff относительно общего предка) и пойми, что там за хрень вообще лежит
у меня гит мёрдж вызывает внешнюю прогу сравнения файлов, где открываются три закладки: base-local, base-remote, local-result-remote (т.е, 2-, 2- и 3-панельное сравнение)

Egor_
()
Ответ на: комментарий от PeleWin

со всеми изменениями из обеих веток

Маленькая, но важная поправка. Гит не оперирует «изменениями», он оперирует «состояниями».

beastie ★★★★★
()
Ответ на: комментарий от beastie

Гит не оперирует «изменениями», он оперирует «состояниями».

Это неверно и не важно, потому что начальное состояние + последовательность изменений эквивалентно последовательности состояний. Можно сказать что он хранит состояния на логическом уровне, но на физическом там всё равно используется дельта компрессия. А при слияниях он разумеется никаким состоянием не оперирует - сливать можно только изменения.

slovazap ★★★★★
()
Последнее исправление: slovazap (всего исправлений: 2)
Ответ на: комментарий от slovazap

сливать можно только изменения

В git применяется простое 3-стороннее слияние, которое оперирует конкретными состояниями - файл-предок, файл-1, файл-2, и собирает слитый файл.

anonymous
()
Ответ на: комментарий от r0ck3r

а код был сломан, так как он имел два метода с одинаковым именем в одном классе

Это потому что изменения отслеживаются построчно. А ты поменял форматирование в объявлении метода и гит посчитал это новой строкой и смерджил без конфликтов.

deep-purple ★★★★★
()
Ответ на: комментарий от r0ck3r

два метода с одинаковым именем в одном классе

(ворчливым тоном) Молодой человек! Git (как и другие СКВ) оперирует строчками и их содержимом. До смысла содержимого строк ему нет никакого дела, это уже задача для транслятора. Могу порекомендовать вливать изменения из master в develop без создания коммита (ключик –no-commit насколько я помню) и запускать тесты. И в случаи успешного прохождения тестов фиксировать влитые изменения. Иначе вносить правки.

В вашей ситуации ничего необычного не произошло. Так бывает.

dvetutnev
()

У гита есть стратегии слияния. Больше инфы тут: https://git-scm.com/docs/merge-strategies

Стратегия по-умолчанию - рекурсивная. И если почитать как она работает, становится понятно, почему не возникает конфликта.

This can only resolve two heads using a 3-way merge algorithm. When there is more than one common ancestor that can be used for 3-way merge, it creates a merged tree of the common ancestors and uses that as the reference tree for the 3-way merge. This has been reported to result in fewer merge conflicts without causing mismerges by tests done on actual merge commits taken from Linux 2.6 kernel development history. Additionally this can detect and handle merges involving renames, but currently cannot make use of detected copies. This is the default merge strategy when pulling or merging one branch.

Если лень вникать как каждая отдельная стратегия работает (мне тоже лень вникать, лол, это достаточно редкий юзкейс), то просто перебором попробуй разные и посмотри, что выйдет)

nikolnik ★★★
()
  • конфликты гит - мажорная фича:
    • должны работать стандартные конфликты практически всегда
    • смоделировать поведение в изолированной среде
  • «вода мокрая»
  • все познается в сравнении
anonymous
()
Ответ на: комментарий от aol

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

Lrrr ★★★★★
()
Ответ на: комментарий от aol

О, ворвусь пожалуй.

Посоветуй тогда в чём хранить конфиги, если не в git.

Условия:

- Единый «предок» - общий конфиг для всех потомков;
- Каждый потомок унаследован от предка и вносит свои дополнительные изменения в файлы(или даже удаляет некоторые из них);
- Наглядная история изменений в условиях смены конфигов «предка». Изменения «предка» попадают к каждому потомку.

Сейчас оно в у меня в git на 3 ветках: master(«предок») и по ветке на каждого потомка. При изменениях в предке для каждого потомка приходится делать rebase и push --force, что дико напрягает.

Я понимаю, что выбрал микроскоп для забивания гвоздей, но это в силу того что я не смог обнаружить молотка для этой задачи :-/

Pinkbyte ★★★★★
()
Последнее исправление: Pinkbyte (всего исправлений: 1)
Ответ на: комментарий от Pinkbyte

ну, эцсамое.. классическое разделение

app.cfg (можно и в гит) - sensible defaults, общие для всех

app.prod.cfg, app.staging.cfg, app.devel.cfg - только параметры, отличающиеся значений основного конфига или отсутствующие в app.cfg. Не хранить под гитом, добавить в гитигнор. Доставлять в окружение машинерией, которая развертывает прод/стейджинг. Разраб себе сам состряпает конфиг.

Приложение при старте читает app.cfg + еще один конфиг, мержит их (в уме объединяет, в смысле. это не про гит ;) ), работает.

Да, некоторые вложения в код требуются, но они окупаются.

То есть, отвечая на твой вопрос, секреты хранить в vault/docker secrets или что там в окружении для секретов.

Дополнения конфигов, специфичные для конкретного окружения (app.prod.cfg, app.staging.cfg, app.devel.cfg), хранить в системе, которая настраивает окружение (или даже не хранить, а создавать при настройке окружения).

aol ★★★★★
()
Последнее исправление: aol (всего исправлений: 2)
Ответ на: комментарий от aol

Эм, забыл уточнить важную вещь - «приложение» не моё, доступа к исходникам у меня нет. Конфиг распилить на отдельные нельзя. Ничего секретного(ключей, паролей и т.д.) в конфиге нет(ну, если не считать конечно DNS-адреса серверов из внутренней зоны .local)

Дополнения конфигов, специфичные для конкретного окружения (app.prod.cfg, app.staging.cfg, app.devel.cfg), хранить в системе, которая настраивает окружение (или даже не хранить, а создавать при настройке окружения).

Не подходит - эти конфиги тоже нужно синхронизировать

Итак, резюмируя вышесказанное: ты предлагаешь обмазаться самописными скриптами? Это и так уже есть и от этого хотелось бы по возможности уйти настолько, насколько это возможно. То есть скрипты будут, без них никуда, но они должны быть настолько короткие и простые, насколько это вообще возможно.

Пока что git выглядит более лучшим решением, чем дополнительные самописные костыли.

Pinkbyte ★★★★★
()
Последнее исправление: Pinkbyte (всего исправлений: 1)
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.