Частково збирання вишні з Git


501

Я працюю над двома різними галузями: випуск та розвиток .

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

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

git cherry-pick bc66559

не робить трюку.

Коли я роблю а

git show bc66559

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

Відповіді:


792

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

Щоб використовувати його в поєднанні з вишневим набором:

git cherry-pick -n <commit> # get your patch, but don't commit (-n = --no-commit)
git reset                   # unstage the changes from the cherry-picked commit
git add -p                  # make all your choices (add the changes you do want)
git commit                  # make the commit!

(Дякую Тіму Хенігану за те, що він нагадав мені, що у git-cherry-pick є варіант - no-commit, і дякую Феліксу Рейб за те, що він зазначив, що потрібно скинути! Якщо ви хочете лише залишити кілька речей поза комітетом , ви можете використовувати git reset <path>...для видалення лише цих файлів.)

Ви, звичайно, можете надати конкретні шляхи до add -pнеобхідності. Якщо ви починаєте з патчем ви могли б замінити cherry-pickз apply.


Якщо ви дійсно хочете git cherry-pick -p <commit>(цей варіант не існує), ви можете використовувати його

git checkout -p <commit>

Це відрізнятиме поточне зобов’язання від вказаного вами зобов’язання, а також дозволяє застосовувати описи від цього, що відрізняється окремо. Цей варіант може бути більш корисним, якщо комісія, яку ви виконуєте, має конфлікти злиття в частині комітету, який вас не цікавить. (Однак зауважте, що checkoutвідрізняється від cherry-pick: checkoutнамагається повністю застосувати <commit>вміст, cherry-pickзастосовує diff зазначений фіксатор від його батька. Це означає, що ви checkoutможете застосувати більше, ніж просто те, що може бути більше, ніж ви хочете.)


Насправді, якщо я дотримуюсь порад з git 1.7.5.4, "git add -p" говорить "Без змін", оскільки все це вже в індексі. Мені потрібно зробити "git reset HEAD" перед "git add" - будь-яким способом уникнути цього скидання за допомогою якоїсь опції?
Фелікс Рабе

@FelixRabe: Я насправді здивований, що в якийсь момент, cherry-pick -nочевидно , не залишив поетапних змін - конвенція, безумовно, що --no-commitваріанти зупиняються безпосередньо перед фіксацією, тобто, коли всі зміни відбулися. Я додам скидання у відповідь.
Каскабель

1
@Blixt Тобто, якщо комітети, які є на іншій гілці, але не вашій поточній гілці, є ABCDEF, git checkout -p <F>це не просто отримує вам зміни від F, це дає вам ABCDEF все пюре разом і дозволяє вам розібрати, яку частину ви хочете . Розділення цього лише на деякі зміни від F - це біль. З іншого боку, git cherry-pick -n <F>ви отримуєте лише зміни від F - і якщо деякі з цих змін суперечать, це корисно повідомляє вам, щоб ви могли зрозуміти, як правильно злитися.
Каскабель

У мене були проблеми з цим, коли зміна була доповненням до файлу. The git resetвидалить поетапні файли і add -pпросто скаже «нічого додати».
Ян Грінґер


36

Припускаючи, що потрібні зміни перебувають на чолі відділення, від якого потрібно зміни, скористайтеся git checkout

для одного файлу:

git checkout branch_that_has_the_changes_you_want path/to/file.rb

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

git checkout branch_that_has_the_changes_you_want path/to/file.rb path/to/other_file.rb

5
Це копіює весь файл: не тільки зміни.
Список Джеремі

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

15

Спираючись на відповідь Майка Монкевича, ви також можете вказати один або кілька файлів для оформлення замовлення з наданого ша1 / відділення.

git checkout -p bc66559 -- path/to/file.java 

Це дозволить вам інтерактивно вибирати зміни, які ви хочете застосувати до вашої поточної версії файлу.


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

1

Якщо ви хочете вказати список файлів у командному рядку та виконати все в одній атомній команді, спробуйте:

git apply --3way <(git show -- list-of-files)

--3way: Якщо патч не застосовується чисто, Git створить конфлікт злиття, щоб ви могли запустити git mergetool. Якщо --3wayвідмовитися, Git відмовиться від патчів, які не застосовуються чисто.


0

Якщо "частково збирання вишні" означає "всередині файлів, вибираючи деякі зміни, але відкидаючи інші", це можна зробити, ввівши git stash:

  1. Зробіть повну вишню вибору.
  2. git reset HEAD^ щоб перетворити всю вишневу комісію в нестандартні робочі зміни.
  3. Тепер git stash save --patch: інтерактивно виберіть небажаний матеріал для зберігання.
  4. Git повертає сховані зміни з вашої робочої копії.
  5. git commit
  6. Викиньте притон небажаних змін: git stash drop.

Порада: якщо ви дасте ім’я небажаних змін імені: git stash save --patch junkтоді, якщо ви забудете зробити це (6) зараз, пізніше ви розпізнаєте приховування того, що воно є.


Якщо ви просто збираєте вишню, то скиньте ... ви нічого не будете зберігати. Як було сказано вище, вам потрібно або зробити вишню з --no-фіксацією, або скинути --hard HEAD ~. Зауважте, що ви ведете негативно (вибираючи те, що не хочете). Наведене вище рішення дозволяє або позитивний, або негативний підхід.
П'єр-Олів'є Варес

0

Використовуйте git format-patchдля того, щоб вирізати частину зобов'язань, які вас цікавлять, і git amзастосувати її до іншої гілки

git format-patch <sha> -- path/to/file
git checkout other-branch
git am *.patch
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.