LINUX.ORG.RU

Git: помогите освоить rebase

 ,


0

1

Сначала схема (стеклянного шара) к теме:

A=https://github.com/void-linux/void-packages
# master-------------------------------------------------|------>
#                                                        |
B=https://github.com/onlylunix/void-packages (FORK)      |
# master        25277 commits behind                     |>
# firebird3upd  1 commit ahead of, 25277 commits behind  |->

C=localhost
$ git config --get remote.origin.url
git@github.com:onlylunix/void-packages.git
Давным-давно из ветки firebird3upd создал Pull request #46672 И вот сейчас эта ветка конфликтует https://ibb.co/FLS3TdM3

Знаю в каком файле конфликт, но не понимаю как действовать дальше ЧТОБЫ НЕ ЗАКРЫЛСЯ Pull request #46672
Спрашиваю потому, что, на github.com уже ругали, и теперь боюсь те кнопки нажимать в их web-интерфейсе (далее WEB), т.к. всё ломается и PR-ы приходится закрывать и создавать новые.

С опаской предполагаю варианты действий:

Вариант 1:
В WEB кнопкой [Sync fork] обновляю ветку B:firebird3upd до A:master. При этом будет конфликт. В WEB редактирую конфликтный файл (Есть такой функционал?).
На localhost выполняю: git pull, что загрузит изменения Sync-нутые и сделанные в WEB при решении конфликта.

Вариант 2:
В WEB кнопкой [Sync fork] обновляю ветку B:firebird3upd до A:master. При этом будет конфликт. Ничего не редактирую.
На localhost выполняю:
git checkout firebird3upd
git fetch
nano 'конфликтный файл' # редактирую 'конфликтный файл'
git add 'конфликтный файл'
git commit --amend --no-edit
git push --force
Вариант 3:
Все действия на localhost-е:
git checkout firebird3upd
git pull --rebase upstream master
nano 'конфликтный файл' # редактирую 'конфликтный файл'
git add 'конфликтный файл'
git commit
git push --force
Повторю что ВАЖНО ЧТОБЫ НЕ ЗАКРЫЛСЯ PR #46672
Прошу помощи!

Эпилог: Git: помогите освоить rebase (комментарий) ...

★★★★★

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

Используй вариант 3. Но вообще, если возникают такие вопросы, значит в гите ты ещё новичок, и тебе лучше на каждый PR создавать feature-ветку и коммитить в ней, а мастер вообще не трогать. Потом, когда rebase, reflog, действия с ветками станут привычным и понятным инструментом, тогда уже можно начинать «срезать углы»

annulen ★★★★★
()

Пока есть коммиты сверху, PR не закроется. Тут волноваться нечего.

Для ленивых: шоб не пердолиться с ремоте, в твоём форке где-то должна быть кнопка «sync with upstream».

А потом просто ребейзнишь свой бранч на master.

ЗЫ: https://imgur.com/a/UtpEqQJ

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

Стоп, а как в Варианте 3 синхронизируется мой форк-«B» на github.com?
В Варианте 3 же изменения будут слиты с «A» на localhost, а потом с localhost отправлены на форк-«B»
Получается как-то глупо

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

Пока есть коммиты сверху, PR не закроется. Тут волноваться нечего.

Так у меня 1 коммит из-за правил void-linux оформлять PR одним коммитом. И он проблемный. Что-то мне думается что опять сломаю

Для ленивых: шоб не пердолиться с ремоте, в твоём форке где-то должна быть кнопка «sync with upstream».

эта кнопка [Sync fork] из стартпоста думаю

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

Да, т.е. в твоём местере будут уже все новые измения.

А потом просто:

git fetch --all
git checkout yourbranch
git rebase master
// тут правим обики
// git add и т.п.
git rebase --continue
git push --force
beastie ★★★★★
()
Последнее исправление: beastie (всего исправлений: 1)
Ответ на: комментарий от superuser

Стоп, а как в Варианте 3 синхронизируется мой форк-«B» на github.com?

git push –force

В Варианте 3 же изменения будут слиты с «A» на localhost, а потом с localhost отправлены на форк-«B»

А что, в мастере на B есть какие-то изменения, которых нет локально?

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

Так надо синхронизировать «B» с первоисточником-«A», смотри схему стартпоста - получается двойной трафик кажетса

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

В https://github.com/onlylunix/void-packages/commits/firebird3upd/ последнее изменение от 24 июля. Если в локальной ветке firebird3upd что-то другое/не актуальное, то можно сделать (предполагая, что B=origin и A=upstream)

git fetch origin firebird3upd
git reset --hard FETCH_HEAD

Это заменит локальную ветку firebird3upd на ту, которая находится в https://github.com/onlylunix/void-packages/commits/firebird3upd, после чего можно её ребейзить и пушить

Соответственно, команда git pull --rebase upstream master синхронизирует локальную ветку firebird3upd с версией master из A

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

В firebird3upd(B) те-же данные что на localhost(C) и они устарели. И в Варианте 3 получается двойной трафик или я не правильно понимаю?

A>>>>>>>>>>>>>>|
               |C=localhost
B<<<<<<<<<<<<<<|

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

В firebird3upd(B) те-же данные что на localhost(C) и они устарели

Команда git push --force обновит firebird3upd(B)

И в Варианте 3 получается двойной трафик или я не правильно понимаю?

«Двойной трафик» в смысле больше мегабайт закачивать из интернета? Если если есть цель обновить локальную версию firebird3upd(C), то объём скачанных данных не зависит от способа - это будут все изменения из master(A). Если такой цели нет и есть оплата за интернет помегабайтно, то можно попробовать поизвращаться с резолвом конфликтов в веб-интерфейсе, но в этом я не силён.

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

да, я про это

Вариант 3:
               -----------------------------------
A>>>>>>>>>>>>>>|git pull --rebase upstream master|
               |...                              |
               |...      C=localhost             |
               |...                              |
B<<<<<<<<<<<<<<|git push --force                 |
               -----------------------------------

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

Чтобы полноценно работать с локальным репозиторием C, нужно, чтобы он был синхронизирован с A. Иначе в нём нельзя будет сделать какой-то другой патч, так как локальный мастер будет отставать на годы. В этом отличие от svn, где можно выкачать подкаталог и работать только с ним как с отдельным репозиторием. Если остро стоит проблема экономии траффика, то может помочь sparse checkout

https://git-scm.com/docs/git-sparse-checkout

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

Да, я не синхронизировал B и C c первоисточником-A с самого создания, т.к. помню что при синхронизации у меня всё развалилось, но тогда я знал еще меньше чем сейчас

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

То что у тебя push --force уже намекает, что это неправильно. Главное правило гита, которое часто игнорируют — нельзя переписывать публичную историю.

Правильный алгоритм простой:
1. Обновить свой форк кноркой Sync fork (можно и не кнопкой а добавив себе 2 remote).
2. Влить (merge) master (которая теперь одинаковая и в апстриме и в твоём форке) ветку в твою ветку firebird3upd. Команда merge прервётся, попросит тебя порешать конфликты. Порешал, сделал git merge --continue и все.
3. Дальше остаётся лишь git push.

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

нельзя переписывать публичную историю.

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

До тех пор, пока есть уверенность, что никто не забирал ветку себе, можно использовать git push --force сколько угодно раз.

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

Если ты создал ПР то у тебя уже такой уверенности быть не может.

И, главное, твой ПР уже комментировали а теперь ты просто убрал те коммиты, и комментарии пропали вместе с ними. Гитхабу стоило бы запретить force push и не учить людей плохому.

rebase бывает необходим примерно раз в лет 5.

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

Так тут нечего волноваться. Наверное видел картинку.

master --o------o---o---o-----o---
         |       \      \    /
feature  +--o--o--o--o---o--o

Это оно и есть. Ты делаешь работу в своей ветке feature и периодически подливаешь (merge) в нее свежие изменения из master.

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

Если остро стоит проблема экономии траффика, то может помочь sparse checkout

https://git-scm.com/docs/git-sparse-checkout

Не поможет. Она влияет только на объем файлов в working tree. Для экономии трафика можно использовать ключи --depth, --single-branch, --filter у команды clone.
Но лучше не надо, т.к. при уменьшении глубины истории merge перестанет работать, т.к. не найдет общих род. коммитов.

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

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

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

Это ок

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

Картинка такая

master - - - - - - - - - - - -  
              \   <- когда-то давно создал ветку, но мастер убежал вперед
firebird3upd   -   

master - - - - - - - - - - - -  
              \             /  <- создал PR, но в нем конфликты 
firebird3upd   - - - - - - -  

master - - - - - - - - - - - -   
                              \  <- скачал актуальный мастер и отребейзил свой коммит на него
firebird3upd                   - 


master - - - - - - - - - - - - -   
                             \  / <- push обратно, но уже без конфликтов на свежий мастер
firebird3upd                  - 
masa ★★
()
Ответ на: комментарий от MirandaUser2

Не поможет. Она влияет только на объем файлов в working tree.

Не правда, там есть возможность фильтрации блобов. Коммиты, не затрагивающие выбранный каталог, качаться не будут.

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

merge ему не понадобится, но и с --filter будет неудобно работать. Придётся каждый раз клонить с --filter 1 и через git am патч таксать

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

Не правда, там есть возможность фильтрации блобов. Коммиты, не затрагивающие выбранный каталог, качаться не будут.

опция --filter=sparse:path=<path> ?
Но это опция команды clone, а не checkout.

И судя по этому багрепорту (https://gitlab.com/gitlab-org/git/-/issues/3) такая форма фильтра недоступна при настройках по умолчанию.

merge ему не понадобится

В этом коменте (Git: помогите освоить rebase (комментарий)) предлагают merge.

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

Правильный алгоритм простой:
1. Обновить свой форк кноркой Sync fork (можно и не кнопкой а добавив себе 2 remote).
...

Обновил свой форк кноркой Sync fork - результат:
https://github.com/void-linux/void-packages/pull/46672
https://ibb.co/hRtvr182
Да чтож такое то, а! Они сами то пробовали свои кнопки?

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

форки в гитхабе это какой-то откровенный тупняк (разве что ЧСВ чье-то увеличивают), постоянно синхронизировать свой форк с мастером для того чтобы ПР передать не имеет никакого смысла - сам форк нужен исключительно из-за того, что у контрибьютора нет прав создавать свои бранчи в целевом репозитории, в целом так примерно должно быть:

# добавить upstream в свой локальный git, т.е.:
git remote add upstream git@github.com:void-linux/void-packages.git
# засинхронизировать его:
git fetch upstream
# переключиться в свой бранч
git checkout firebird3upd
# перекинуть свои коммиты на upstream:
git rebase --onto upstream/master HEAD~1
# поправить конфликты, закоммитить, сделать push с --force
borisych ★★★★★
()
Ответ на: комментарий от superuser

Теперь тут https://github.com/void-linux/void-packages/pull/48350 2 коммита стало, а по правилам надо 1…

не нужно было merge делать - это от лукавого все, теперь так:

# выписываем свою ветку
git checkout firebird5
# откатываемся до паразитного слияния
git reset --soft e4f4ae0ec8f1c349d208e7ead323e314275cae2e
# коммитим
git commit -m "New package: firebird5"
# вливаем с --force
git push --force
borisych ★★★★★
()
Ответ на: комментарий от urxvt

Главное правило гита, которое часто игнорируют — нельзя переписывать публичную историю.

PR это не публичная история, его можно и нужно редактировать, чтобы в публичной истории не было мусора. В github, в отличие от, скажем, gerrit, pr нельзя обновить без force --push

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

Ещё советую поставить себе git config --global pull.ff only, во избежание неосознанных мёржей. Но это уже не относится к обсуждаемой проблеме.

я вообще слабо себе представляю под какими препаратами нужно было находиться, чтобы в git добавить pull, который работает совершенно не предсказуемо, и его поведение определяется настройками, которые могут жить в 4-х разных местах, особо одаренные (привет JetBrains) его еще по умолчанию предлагают использовать, хотя в большинстве случаев за git pull неизбежно идут git reflog и git reset. Только git fetch, только хардкор!

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

Если ты создал ПР то у тебя уже такой уверенности быть не может.

Теоретически, да. На практике, в команде, очень маловероятно, что кто-то стянет твой ПР до того, как он проревьюен и смержен.

rebase бывает необходим примерно раз в лет 5.

Допустим, я создал PR в master. Пока его ревьюили, master ушёл вперёд.

Можно замёржить master в свой PR, а можно сделать rebase. С rebase история будет выглядеть красивее и понятнее. При этом не случится ничего из перечисленного (правда, я GitHub почти не использую, использую GitLab, в котором точно комменты не пропадают, не знаю, какая магия при этом используется):

И, главное, твой ПР уже комментировали а теперь ты просто убрал те коммиты, и комментарии пропали вместе с ними. Гитхабу стоило бы запретить force push и не учить людей плохому.

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

Можно замёржить master в свой PR, а можно сделать rebase.

у моржей есть три основных идеи:

  • при конфликтах котрибьютор может написать пояснение о том, почему он принял то или иное решение, в случае rebase это писать уже некуда (если не править комментарии к коммитам), правда, полезность этой информации крайне сомнительна, потому что если туда что и напишут, то разве что очевидные идеи: оно не сливалось, поэтому мы что-то поменяли, а идти и смотреть какие конфликты были в точках слияния перед тем как принять ПР - это нужно быть совсем уж отважным или упоротым.
  • если разработчик создает коммиты таким образом, что после каждого коммита ветка не ломается (все компилируется, проходят тесты и пр.), то в случае моржа эта идея все также продолжает иметь место быть, в случае rebase уже нет никаких гарантий на то, что если мы возьмем произвольный коммит, то он будет хотябы собираться. Насколько это важно - зависит уже от мейнтейнера апстрима
  • если за ПР в действительности стоит слияние каких-то больших веток, и в исходный бранч льет не один человек, а целая команда, то переставлять голову и тем самым обламывать другие ПР, ожидающие слияния, может быть уже западлом (мы пробовали переставлять голову у себя несколько раз, в т.ч. для develop делать push --force - ощущения не из приятных на самом деле), с другой стороны я как мейнтейнер апстрима совершенно не хочу чтобы моя история превращалась в откровенную кашу - тут кто кого победит, жаба против гадюки, пока судя по всему апстрим имеет больше преференций
borisych ★★★★★
()
Ответ на: комментарий от borisych

Нет одного решения, которое подходит во всех ситуациях. Как и вообще в жизни.

С тем же Git все команды работают по разному. У всех очень разные workflow. Кто-то работает по «git-flow», но даже там добавляет нюансы. Кто-то использует trunk based подход. Кто-то изобретает свои велосипеды (два раза в жизни встречал, причём в обоих случаях, работать с этими велосипедами было очень неудобно).

Но rebase - это мощный инструмент, который часто бывает полезен, и который важно знать. Если человек не умеет пользоваться rebase - значит, он не умеет пользоваться Git. Я так считаю.

А пользоваться или нет - дело выбора каждой команды и каждого человека.

Но без rebase история будет однозначно «грязнее», с кучей коммитов, которые не несут никакой полезной информацией, а являются, например, косметическими правками кода после прохождения линтеров в CI/CD, и прочее.

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

тебе лучше на каждый PR создавать feature-ветку и коммитить в ней, а мастер вообще не трогать.

ну это как бы и есть нормальный режим работы с гитом под названием trunk based development.

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

Да уже не нужно наверное. Но в нескольких компаниях работал по git-flow, так было заведено. Правда, это был сильно упрощённый git-flow.

Я и говорю: нет единого рецепта, как работать. Все делают это по-разному. Я за последние 10 лет поработал в нескольких компаниях, и везде был свой flow, иногда радикально отличающийся от того, что можно прочитать.

Иногда мне какой-то подход первое время казался идиотизмом, а спустя время начинал думать, что в нем есть рациональное зерно.

Да и проекты у всех очень разные.

Chiffchaff
()