Git push відхилено після відновлення функції гілки


916

Гаразд, я думав, що це простий сценарій git, що мені не вистачає?

У мене є masterфілія та featureфілія. Я займаюся деякою роботою над master, дехто над feature, а потім ще деякою master. Я закінчую щось подібне (лексикографічний порядок передбачає порядок комітетів):

A--B--C------F--G  (master)
       \    
        D--E  (feature)

У мене немає ніяких проблем , щоб git push origin masterтримати пульт masterоновлюється, ні з git push origin feature(якщо на feature) для підтримки віддаленого резервного копіювання для моєї featureроботи. До цих пір нам добре.

Але тепер я хочу , щоб перебазувати featureна вершині F--Gфіксацій на господаря, так що я git checkout featureі git rebase master. Ще добре. Тепер ми маємо:

A--B--C------F--G  (master)
                 \
                  D'--E'  (feature)

Проблема: в момент, коли я хочу створити резервну копію нового featureрозгалуженого розгалуженого шару git push origin feature, поштовх відхиляється, оскільки дерево змінилося через перезавантаження. Це можна вирішити лише за допомогою git push --force origin feature.

Я ненавиджу використання, --forceне будучи впевненим, що мені це потрібно. Отже, мені це потрібно? Чи має перебазування обов'язково означає , що наступний pushповинен бути --forceFUL?

Ця галузь функції не поділяється ні з якими іншими розробниками, тому у мене фактично не виникає проблем із силовим натисканням, я не збираюсь втрачати будь-які дані, питання більш концептуальне.

Відповіді:


681

Проблема полягає в тому, що git pushпередбачається, що віддалену гілку можна переадресувати до вашої локальної гілки, тобто вся різниця між локальною та віддаленою гілками полягає в локальному, який має в кінці нові нові коміти:

Z--X--R         <- origin/some-branch (can be fast-forwarded to Y commit)
       \        
        T--Y    <- some-branch

При виконанні git rebaseкомісій D і E застосовуються до нової бази та створюються нові коміти. Це означає, що після повторної бази даних у вас є щось подібне:

A--B--C------F--G--D'--E'   <- feature-branch
       \  
        D--E                <- origin/feature-branch

У цій ситуації віддалену гілку не можна переадресувати до локальної. Хоча теоретично локальна гілка може бути об'єднана у віддалену (очевидно, вона вам не потрібна в такому випадку), але як git pushвиконує лише швидкі злиття вперед, вона кидає і помиляє.

І що можна зробити --force, це просто ігнорувати стан віддаленої гілки та встановити її на зобов’язання, яке ти наштовхуєш на неї. Тож git push --force origin feature-branchпросто перекриває origin/feature-branchмісцевий feature-branch.

На мою думку, повернення функціональних гілок masterта примусовий переведення їх до віддаленого сховища добре, якщо ви єдиний, хто працює на цій гілці.


67
Якщо чесно, витягнення та об'єднання оригінальної версії функціональної гілки у перезавантаженій ніби виключає всю ідею повторного використання.
KL-7,

24
Можливо, я вас правильно не зрозумів, але якщо ви потягнете гілку функції, переставте її на свіжу головну гілку, ви не можете її відсунути без сили, тому що віддалену версію функції функції не можна швидко переслати на нову (перебазована) версія гілки функцій. Саме це описав ОП у своєму питанні. Якщо після повторного використання, але перед тим, як натиснути, ви зробите git pull feature-branchце, це потяг призведе до нового злиття (об'єднанням віддалених та локальних версій гілки функцій). Тож ви отримуєте непотрібне злиття після перезавантаження, або натискаєте на --force.
KL-7,

6
Ах, я думаю, я це зрозумів. Ви описуєте той самий підхід, що і у відповіді Марка Лонгайра. Але це породжує комісію злиття. Це може бути корисно в деяких випадках, але я використовую rebase в основному в своїх власних галузях функцій (отже, push --forceце не проблема), щоб тримати історію комісій лінійною без жодних комісій злиття.
KL-7,

11
Проблема з «примусовим натисканням» полягає в тому, що ви дійсно можете «розвантажувати речі» (попередні зобов'язання), те, що зазвичай НІКОЛИ не може бути можливим у будь-якій системі управління версіями. налаштування не приймати силових натискань , щоб обмежити потенційні пошкодження. (Назвіть будь-що з наступного: бурхливі / звільнені працівники, власний ідіотизм, втомлені та перевантажені «рішеннями» ...).
Френк Нокк

13
--force-with-leaseЯк запропонував @hardev, це чудовий варіант
серпня

464

Замість використання -f або --force повинні використовувати розробники

--force-with-lease

Чому? Тому що він перевіряє віддалену гілку на наявність змін, що є абсолютно хорошою ідеєю. Давайте уявимо, що Джеймс і Ліза працюють над однією і тією ж галуззю, і Ліза підняла на себе зобов'язання. Зараз Джеймс відмовляється від своєї місцевої гілки і відхиляється при спробі натиснути. Звичайно, Джеймс вважає, що це пов'язано з перезавантаженням і використовує --force і переписав би всі зміни Лізи. Якби Джеймс застосував - примусово з орендою, він отримав би попередження про те, що існують зобов'язання, зроблені кимось іншим. Я не бачу, чому хтось використовуватиме --force замість --force-with-lease під час натискання після перезавантаження.


33
Чудове пояснення. git push --force-with-leaseврятувало мене купу.
ckib16

5
Це корисний коментар, але насправді не є відповіддю на питання.
Даллін

4
Це відповідь, відмова від освоєння / розробки створює проблему, саме тому - примусово з орендою існує.
Тамір Даніелі

3
Це має бути прийнятою відповіддю. Вирішує саме описану проблему - примушуйте натискати, не змушуючи, якщо хтось ще вчинив тим часом.
Лузян

3
Я думаю, що і прийнята відповідь, і ця вирішує питання. Прийнята відповідь пояснює, чому потрібно змусити. І це пояснює, чому --force-with-leaseвирішує проблему використання--force
Jeff Appareti

47

Я б замість цього використовував "checkout -b", і це легше зрозуміти.

git checkout myFeature
git rebase master
git push origin --delete myFeature
git push origin myFeature

коли ви видаляєте, ви не дозволяєте вставляти гілку, що виходить, що містить інший ідентифікатор SHA. У цьому випадку я видаляю лише віддалену гілку.


6
Це чудово працює, особливо якщо у вашій команді є гак-git, який відкидає всі команди git push --force.
Райан Темза

1
спасибі за те, що він добре працював Ось докладніше про те, що я прочитав, щоб краще зрозуміти. Це дуже корисно, коли ви не хочете чи не можете робити натиск. Видалення віддалених гілок та звільнення
RajKon

5
Це має той самий результат push --force, що і тому є лише способом обійти gpo repo --force. Як такий, я не думаю, що це ніколи не є доброю ідеєю - або репо дозволяє push --force, або з поважної причини відключає це. Відповідь Nabi є більш доцільною, якщо --forceїї вимкнено на віддаленому репо, оскільки це не має ризику втратити комісії від інших розробників або іншим чином викликати проблеми.
Логан Пікап

19

Одним з рішень цієї проблеми є те , що робити msysGit в перебазування злиття робить сценарій - після перебазування, зливає в старій чолі featureз -s ours. Ви закінчите графік фіксації:

A--B--C------F--G (master)
       \         \
        \         D'--E' (feature)
         \           /
          \       --
           \    /
            D--E (old-feature)

... і ваш поштовх featureбуде швидким вперед.

Іншими словами, ви можете:

git checkout feature
git branch old-feature
git rebase master
git merge -s ours old-feature
git push origin feature

(Не перевірено, але я думаю, що це правильно ...)


26
Я вважаю, що найпоширенішою причиною використання git rebase(замість того, щоб masterзнову об’єднуватися у свою галузь функцій) є створення чистої лінійної історії комісій. З вашим підходом історія стає ще гіршою. Оскільки перезавантаження створює нові коміти без будь-яких посилань на їх попередні версії, я навіть не впевнений, що результат цього об'єднання буде адекватним.
KL-7

6
@ KL-7: Вся суть у тому merge -s ours, що вона штучно додає батьківську посилання на попередню версію. Звичайно, історія не виглядає чистою, але, здається, запитувача особливо турбує те, що потрібно змушувати натискати featureгілку, і це обходить це. Якщо ви хочете зробити повторне базування, це більше або менше одного або іншого. :) Більш загально, я думаю, що цікаво, що проект msysgit робить це ....
Марк Лонгейр

@ KL-7: До речі, я поставив +1 вашій відповіді, яка, очевидно, є правильною - я просто подумав, що це теж може бути цікавим.
Марк Лонгейр

Це, безумовно, цікаво, принаймні для мене. Дякую. oursРаніше я бачив стратегію, але думав, що вона стосується лише конфліктних ситуацій, автоматично вирішуючи їх за допомогою змін у нашій галузі. Виявилося, це працює інакше. І працювати таким чином дуже корисно, якщо вам потрібна перезавантажена версія (наприклад, для технічного обслуговування репо, щоб вона чисто застосувала до неї master), але хочете уникнути силових натискань (якщо багато інших ppl з якихось причин використовують вашу функцію).
KL-7,

15

Це може бути, а може і не бути, що в цій гілці є лише один розробник, який зараз (після ребатування) не відповідає потоку / функції.

Як такий, я б запропонував використовувати наступну послідовність:

git rebase master
git checkout -b feature_branch_2
git push origin feature_branch_2

Так, нова галузь, це має вирішити це без сили, що, на мою думку, є головним недоліком git.


3
Вибачте, але: "Продовжуйте генерувати гілки", щоб уникнути переоформлення існуючих, не допомагає "одиноким розробникам функцій" (які можуть переохоплювати), ані кільком людям, які працюють над функціональною гілкою (потрібно повідомляти цю "гілку" та повідомляти про неї пересуватися, люди). - Це більше схоже на ручну версію (“thesis_00.doc, thesis_01.doc, ...”), в межах системи версій…
Frank Nocke,

2
Крім того, це не допомагає, коли у вас відкрито github PR для однієї назви гілки, вам доведеться створити новий PR для нової назви гілки, яку ви натиснули.
gprasant

1
@frankee Напівправда з мого досвіду. Для самотнього розробника, так, просто натиснути на силу досить просто, але звичка може вас кусати пізніше. + щойно приєднався новий розробник? чи, можливо, якась система CI, яка не використовує - твердий скидання? для колективу, який співпрацює, я думаю, що повідомлення нової назви гілки досить просто, це можна легко прописати також + для команди, я б запропонував переглядати місцеві дані або коли філія готова до злиття, а не протягом дня в день , додатковий фіксатор - це менше клопоту, ніж розв'язання конфліктів на основі відновлення / злиття.
JAR.JAR.beans

@gprasant для PR, знову ж таки, я думаю, що це було б неправильно перезавантажувати, я б насправді хотів би побачити, що одиничні коміти з виправленнями PR. Ребазація (сквош) повинна відбутися лише пізніше, як частина злиття для освоєння, і коли PR все готовий і готовий (тому жодного нового PR не потрібно відкривати).
JAR.JAR.beans

13

Мій спосіб уникнути силового натиску - створити нову гілку та продовжувати роботу над цією новою гілкою та після деякої стабільності видалити стару гілку, яка була перезавантажена:

  • Випуск перевіреної філії на місцевому рівні
  • Відгалуження від відновлюваної гілки до нової гілки
  • Переміщення цієї гілки як нової гілки до віддаленого. та видалення старої гілки на віддаленому

1
Чому немає любові до цього варіанту? Це, безумовно, найчистіший, найпростіший, найбезпечніший.
cdmo

Оскільки у мене близько 200 систем, які відстежують ім'я гілки, і це повинно бути конкретним ім'ям для завдання, і якщо я почне робити перейменування гілок кожен натиск, я втрачу розум.
Тамір Даніелі

@TamirDaniely Я не намагався, але чи видалення старої гілки (з віддаленого) перед натисканням та натисканням нової гілки з тим же старим ім'ям вирішує вашу проблему?
Набі

2
@Nabi Це саме те, що робить --force-with-lease, за винятком того, що він також підтверджує, що немає нових зобов'язань, які не є вашими.
Тамір Даніелі

12

Інші відповіли на ваше запитання. Якщо ви перезавантажите гілку, вам потрібно буде натиснути її.

База даних та спільне сховище зазвичай не уживаються. Це переписування історії. Якщо інші користуються цією гілкою або розгалужуються від цієї гілки, перезавантаження буде дуже неприємним.

Загалом, база даних добре працює для місцевого управління філіями. Віддалене управління філіями найкраще працює з явними злиттями (--no-ff).

Ми також уникаємо об'єднання головного майстра у галузь функції. Замість цього ми перезавантажуємося на master, але з новою назвою гілки (наприклад, додаємо суфікс версії). Це дозволяє уникнути проблеми повторної передачі даних у спільному сховищі.


5
Чи можете ви додати приклад, будь ласка?
Термех

8

Що не так з a git merge masterнаfeature гілці? Це дозволить зберегти роботу, яку ви мали, зберігаючи її окремо від основної галузі.

A--B--C------F--G
       \         \
        D--E------H

Редагувати: Вибачте, я не прочитав вашу заяву проблеми Вам потрібна сила, як ви виконували rebase. Усі команди, що змінюють історію, знадобляться--force аргумент. Це невдача, що не дозволить вам втратити роботу (стара Dі Eбула б втрачена).

Отже, ви виконали те, git rebaseщо зробило дерево схожим (хоча частково приховане як Dі Eбільше не знаходиться в названій гілці):

A--B--C------F--G
       \         \
        D--E      D'--E'

Отже, намагаючись просунути свою нову featureгілку (з D'і E'в ній), ви втратили б Dі E.


3
У цьому немає нічого поганого, і я знаю, що це спрацює. Це просто не те, що мені потрібно. Як я вже говорив, питання є більш концептуальним, ніж практичним.
Юваль Адам

4

Для мене такі легкі кроки працюють:

1. git checkout myFeature
2. git rebase master
3. git push --force-with-lease
4. git branch -f master HEAD
5. git checkout master
6. git pull

Зробивши все вище, ми можемо також видалити гілку myFeature, виконавши наступну команду:

git push origin --delete myFeature

3

Наступні роботи для мене:

git push -f origin branch_name

і він не видаляє жодного з мого коду.

Але, якщо ви хочете цього уникнути, то можете зробити наступне:

git checkout master
git pull --rebase
git checkout -b new_branch_name

тоді ви зможете вибрати всі свої зобов’язання до нової гілки. git cherry-pick COMMIT ID а потім натисніть свою нову гілку.


5
-fПсевдонім для цього --force, чому питання намагається уникати, якщо це можливо.
epochengine

1

Як ОП розуміє проблему, просто шукає кращого рішення ...

Як щодо цього як до практики?

  • Увімкніть фактичну галузь для розвитку функцій (де ви ніколи не перезавантажуєте та не натискаєте, тому ваші колеги-розробники функцій вас не ненавиджу). Тут регулярно з’єднуйте ці зміни з основного. Історія Мессьє , так, але життя легко, і ніхто не переплутається в його роботі.

  • Майте другу гілку для розробки функцій, де один член команди команди регулярно відсуває всі функції, які дійсно перезаряджаються, дійсно вимушеними. Так майже чисто базується на досить недавньому майстер-зобов'язанні. Після завершення функції натисніть на цю гілку зверху головного майстра.

Для цього методу вже може бути назва шаблону.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.