Git вишневий вибір проти rebase


120

Нещодавно я почав працювати з Git.

Перейшовши через книгу Git в Інтернеті, у розділі "Git Rebase" я виявив таке:

За допомогою команди rebase ви можете прийняти всі зміни, які були здійснені на одній гілці, і відтворити їх на іншій.

(Цитується з: http://git-scm.com/book/en/Git-Branching-Rebasing )

Я подумав, що це точне визначення git cherry-pick (повторно застосувати команду або набір об'єктів фіксування на поточно перевіреній гілці).

Яка різниця між ними?

Відповіді:


166

З часу, коли git cherry-pickнавчився застосовувати декілька комітетів, розмежування справді стало суперечливим, але це можна назвати конвергентною еволюцією ;-)

Справжня відмінність полягає в оригінальному намірі створити обидва інструменти:

  • git rebaseЙого завдання полягає в тому, щоб переадресувати низку змін, які розробник має у своєму приватному сховищі, створеному проти версії X якоїсь гілки вище за течією, до версії Y цієї ж гілки (Y> X). Це ефективно змінює базу цієї серії зобов'язань, отже, "звільнення".

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

  • git cherry-pick- це переведення цікавого завдання з однієї лінії розвитку в іншу. Класичний приклад - це підтримка виправлень безпеки, зроблених на нестабільній гілці розвитку, до стабільної (обслуговуючої) гілки, де mergeнемає сенсу, оскільки це може принести чимало небажаних змін.

    З моменту своєї першої появи git cherry-pickвін зміг вибрати декілька комітетів одночасно.

Отже, можливо, найяскравіша різниця між цими двома командами полягає в тому, як вони поводяться з гілкою, над якою вони працюють: git cherry-pickзазвичай приносить команду з іншого місця та застосовує її поверх вашої поточної гілки, записуючи нову фіксацію, при цьому git rebaseбере вашу поточну гілку та переписує серія власних підказок вчиняється так чи інакше. Так, це сильно натягнутий опис того, що git rebaseможна зробити, але навмисно намагатися зробити загальну ідею зануреною.

Оновлення для подальшого пояснення прикладу використання git rebaseобговорюваного.

Враховуючи цю ситуацію,
стан репо перед звільненням
Книга зазначає:

Однак є й інший спосіб: ви можете взяти виправлення зміни, яка була введена в C3, і повторно застосувати її поверх C4. У Git це називається перезаписом. За допомогою команди rebase ви можете прийняти всі зміни, які були зроблені на одній гілці, і застосувати їх до іншої.

У цьому прикладі ви виконаєте наступне:

$ git checkout experiment
$ git rebase master
First, rewinding head to replay your work on top of it...
Applying: added staged command

"Улов" тут полягає в тому, що в цьому прикладі гілка "експерименту" (предмет для повторного звільнення) спочатку була відхилена від "ведучої" гілки, і, отже, вона ділиться здійснює C0 через C2 з нею - ефективно, "експеримент" є " master "до C2, включаючи C2 плюс виконувати C3 поверх нього. (Це найпростіший можливий випадок; звичайно, "експеримент" може містити кілька десятків комітів поверх своєї первісної бази.)

Тепер git rebaseсказано перезавантажити "експеримент" на поточну підказку "майстра", і git rebaseйде так:

  1. Запускається, git merge-baseщоб побачити, яке останнє зобов’язання ділиться як "експериментом", так і "майстром" (який сенс відхилення, іншими словами). Це С2.
  2. Економить усі зобов’язання, зроблені з моменту відхилення; у нашому прикладі іграшок це просто C3.
  3. Перемотайте HEAD (що вказує на наконечник "експерименту" перед запуском операції), щоб вказати на підказку "master" - ми переходимо на нього.
  4. Намагається застосувати кожну із збережених комісій (як би з git apply) у порядку. У нашому прикладі іграшок це лише одна фіксація, C3. Скажімо, його додаток призведе до створення C3 '.
  5. Якщо все пішло добре, посилання "експеримент" оновлюється, щоб вказувати на фіксацію, отриману в результаті застосування останнього збереженого комітету (C3 'в нашому випадку).

Тепер повернемось до вашого питання. Як бачите, тут технічно git rebase справді пересаджується серія комітетів від "експерименту" до кінця "майстра", тож ви з правом можете сказати, чи справді є "інша галузь" у процесі. Але суть у тому, що наконечник від "експерименту" в кінцевому підсумку став новим наконечником в "експерименті", він просто змінив свою базу:
стан після злиття

Знову ж таки, технічно ви можете сказати, що git rebaseтут включені певні комітети від "майстра", і це абсолютно правильно.


2
Дякую. Я все ще не повністю зрозумів, що ви тут маєте на увазі. У книзі наводиться приклад того, що для повторної бази застосовується серія підказок, що виконуються з іншої гілки, тоді як ви говорите, що це з "тієї ж гілки". А може, є кілька випадків, як це працює?
лізергічно-кислотна

1
Намагався пояснити питання, оновивши мою відповідь.
kostix

98

За допомогою вишеньки вишні створюються оригінальні палички / гілки навколо та створюються нові комірки. За допомогою бази даних вся гілка переміщується з гілкою, що вказує на повторювані коміти.

Скажімо, ви почали з:

      A---B---C topic
     /
D---E---F---G master

База даних:

$ git rebase master topic

Ви отримуєте:

              A'--B'--C' topic
             /
D---E---F---G master

Вишня:

$ git checkout master -b topic_new
$ git cherry-pick A^..C

Ви отримуєте:

      A---B---C topic
     /
D---E---F---G master
             \
              A'--B'--C' topic_new

для отримання додаткової інформації про git ця книга має більшість із них (http://git-scm.com/book)


3
Добре відповів. Також загальноприйнято, що ви, можливо, захочете скористатись вишкою лише A і B, але залишити C висить у тих випадках, коли ви можете зберегти гілку і просто вибрати вишні, які можуть знадобитися колегам. Git створений для роботи з людьми, тому якщо ви не бачите переваг чогось, працюючи наодинці, він часто частіше використовується при роботі в більших групах.
Пабло Джомер

Якщо б замість цього було зроблено інтерактивну базу даних, яка залишає один чи кілька комісій, які гілки ви мали б в кінці? якби він був topicнакладений лише на вершині master, він не містить лівих комісій, до якої гілки вони будуть входити?
Антоній

Ще одне, що я хочу додати: якщо ви git checkout topicі потім git reset --hard C'після збирання вишні, то у вас такий самий результат, як і після звільнення. Я врятував себе від безлічі конфліктів злиття, використовуючи вишню, яка перебирала звільнення, тому що загальний предок був назад.
sorrymissjackson

@anthony - stackoverflow.com/questions/11835948 / ... : наскільки я розумію , вони губляться. Я не - gitгуру, але це rebase/ cherry-pickє у всіх деталях, з gitякими я зрозумів проблему.
thoni56

1
Ваші графіки приносять більше шкоди, ніж користі, оскільки вони функціонально однакові. Єдина відмінність - створена компанією галузь git checkout -b, яка не має нічого спільного git cherry-pick. Кращий спосіб пояснити те, що ви намагаєтесь сказати: «ти біжиш git rebaseна topicгілку і передаєш її master; ти біжиш git cherry-pickпо masterгілці і передаєш її (береться від) topic. "
Rory O'Kane

14

Виробництво вишень для окремих комітетів .

Коли ви робите звільнення, він застосовує всі комісії в історії до ГОЛОВИ гілки, які там відсутні.


Дякую. Чи знаєте ви, якщо вони працюють однаково під кришками? (зберігати їх проміжні виходи у "виправлення" файлів тощо).
лізергічно-кислотна

Афаїк так. Він застосовує всі патчі по одному. Ось чому вам іноді доводиться вирішувати конфлікти злиття посеред бази даних, перш ніж продовжувати.
iltempo

6
@iltempo, він працював для окремих комітетів лише у старих версіях Git; в даний час ви можете зробити щось на кшталт git cherry-pick foo~3..fooі отримати вершину дерев, що виконуються з "foo", вибраного один за одним.
kostix

1
git-rebase використовує ті ж api, що і вишня в кодовій базі, iirc
альтернатива

Я не думаю, що вони насправді працюють так само під прикриттями. Я спробував випустити тисячі комісій, і я думаю, що git створює величезний файл поштової скриньки, а потім працює git amна ньому. В той час, як вишня вибору застосовується фіксувати шляхом комісії (можливо, створивши поштову скриньку з одним повідомленням для кожного виправлення). Моя база не вдалася, оскільки у створеному файлу поштової скриньки не вистачало місця на диску, але вишня вибору з тим самим діапазоном редагування вдалася (і, здається, працює швидше).
onlynone

11

Коротка відповідь:

  • git cherry-pick є більш "низьким рівнем"
  • Таким чином, він може імітувати git rebase

Відповіді, наведені вище, хороші, я просто хотів навести приклад у спробі продемонструвати їх взаємозв'язок.

Не рекомендується замінювати "git rebase" цією послідовністю дій, це просто "доказ концепції", який, я сподіваюся, допомагає зрозуміти, як все працює.

З огляду на таке сховище іграшок:

$ git log --graph --decorate --all --oneline
* 558be99 (test_branch_1) Test commit #7
* 21883bb Test commit #6
| * 7254931 (HEAD -> master) Test commit #5
| * 79fd6cb Test commit #4
| * 48c9b78 Test commit #3
| * da8a50f Test commit #2
|/
* f2fa606 Test commit #1

Скажімо, у нас є деякі дуже важливі зміни (вчиняє №2 по №5) в майстрі, які ми хочемо включити в наш test_branch_1. Зазвичай ми просто переходимо до гілки і робимо "git rebase master". Але оскільки ми робимо вигляд, що у нас є лише "git cherry-pick", ми робимо:

$ git checkout 7254931                # Switch to master (7254931 <-- master <-- HEAD)
$ git cherry-pick 21883bb^..558be99   # Apply a range of commits (first commit is included, hence "^")    

Після всіх цих операцій наш графік фіксації виглядатиме так:

* dd0d3b4 (HEAD) Test commit #7
* 8ccc132 Test commit #6
* 7254931 (master) Test commit #5
* 79fd6cb Test commit #4
* 48c9b78 Test commit #3
* da8a50f Test commit #2
| * 558be99 (test_branch_1) Test commit #7
| * 21883bb Test commit #6
|/
* f2fa606 Test commit #1

Як ми бачимо, комісії №6 та №7 були застосовані проти 7254931 (підказка майстра). HEAD був переміщений і вказує на фіксацію, яка, по суті, є кінчиком перекинутої гілки. Тепер все, що нам потрібно зробити, - це видалити старий вказівник гілки та створити новий:

$ git branch -D test_branch_1
$ git checkout -b test_branch_1 dd0d3b4

Тепер тест_branch_1 вкорінюється з останньої позиції майстра. Готово!


Але також база даних може імітувати вишеньку?
Число945

Оскільки cherry-pickможна застосувати цілий ряд комісій, я думаю, що так. Хоча це дещо дивний спосіб виконання справ, ніщо не заважає вам вибирати всі зобов’язання у вашій гілці функцій зверху master, а потім видалити гілку функції та створити її знову таким чином, щоб вона вказувала на кінчик master. Ви можете думати git rebaseяк послідовність git cherry-pick feature_branch, git branch -d feature_branchі git branch feature_branch master.
raiks

7

Вони обидві команди для перезапису комітетів однієї гілки поверх іншої: різниця полягає в тому, в якій гілці - "ваша" (поточно перевірена HEAD) або "їхня" (гілка передана як аргумент команді) - це база для цього переписування.

git rebaseприймає стартовий фіксатор і відтворює ваші зобов’язання як наступні після їх (стартові фіксації).

git cherry-pickприймає набір комісій і відтворює їхні зобов’язання як наступні після ваших (ваших)HEAD ).

Іншими словами, дві команди за своєю основною поведінкою (ігнорування їх розбіжних характеристик продуктивності, умовні виклики та параметри вдосконалення) симетричні : перевірка гілки barта запуску git rebase fooвстановлює barгілку в ту саму історію, що і встановлення перевірки гілки fooта запуску git cherry-pick ..barбуде встановлено fooдо (зміни від foo, а потім зміни відbar ).

Різниця між двома командами може бути запам'ятована тим, що кожна описує те, що вона робить для поточної гілки: rebaseробить іншу голову новою базою для ваших змін, тоді як cherry-pickвибирає зміни з іншої гілки та ставить їх на вершину вашіHEAD (як вишні поверх пісочниці).


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

4

Обидва роблять дуже схожі речі; Основна концептуальна відмінність полягає (спрощено):

  • rebase переміщує коміти з поточної гілки в іншу гілку .

  • Вибір вишень вибору виконує з іншої гілки до поточної гілки .

Використання діаграм, подібних до відповіді @Kenny Ho :

Враховуючи цей початковий стан:

A---B---C---D master
     \
      E---F---G topic

... і припускаючи, що ви хочете, щоб коміти з topicгілки були відтворені вгорі поточної masterгілки, у вас є два варіанти:

  1. Використання перебазуватися: Ви б спочатку піти topicроблячи git checkout topic, а потім перемістити гілку, запустивши git rebase master, виробництво:

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

    Результат: ваша поточна філія topicбула перезавантажена (переміщена) на master. Філія був оновлений, в той час як галузь залишилася на місці.
    topicmaster

  2. Використання вишні вибір : ви б спочатку піти masterроблячи git checkout master, а потім скопіювати гілку, запустивши git cherry-pick topic~3..topic(або, що те ж саме, git cherry-pick B..G), виробництво:

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

    Результат: комісії з файлів topicбули скопійовані в master. Філія був оновлений, в той час як галузь залишилася на місці.
    mastertopic


Звичайно, тут вам довелося чітко сказати вишневому вибору, щоб вибрати послідовність комірок , використовуючи позначення діапазону foo..bar . Якби ви просто передали ім'я гілки, як у git cherry-pick topic, вона взяла б лише коміти на кінчику гілки, в результаті чого:

A---B---C---D---G' master
     \
      E---F---G topic
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.