git stash -> злиття прихованих змін із поточними змінами


186

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

Чи є спосіб це зробити?

Більше для зручності, я врешті-решт відмовився і здійснив спочатку свої поточні зміни, потім зміни, але я вважав за краще одним махом.


Можливо дубліката stackoverflow.com/q/1360712/72178
ks1322

Відповідь Джошуа має бути прийнятою відповіддю. Цей пост stackoverflow є першим посиланням google на це питання, дайте правильну відповідь в Інтернеті!
Jérôme

Відповіді:


271

Щойно я виявив, що якщо ваші незапрошені зміни будуть додані до індексу (тобто "поетапно", використовуючи git add ...), то git stash apply(і, імовірно, git stash pop) фактично зробіть належне об'єднання. Якщо конфліктів немає, ти золотий. Якщо ні, вирішіть їх як завжди за допомогою git mergetoolабо вручну за допомогою редактора.

Щоб було зрозуміло, це процес, про який я говорю:

mkdir test-repo && cd test-repo && git init
echo test > test.txt
git add test.txt && git commit -m "Initial version"

# here's the interesting part:

# make a local change and stash it:
echo test2 > test.txt
git stash

# make a different local change:
echo test3 > test.txt

# try to apply the previous changes:
git stash apply
# git complains "Cannot apply to a dirty working tree, please stage your changes"

# add "test3" changes to the index, then re-try the stash:
git add test.txt
git stash apply
# git says: "Auto-merging test.txt"
# git says: "CONFLICT (content): Merge conflict in test.txt"

... що, мабуть, те, що ви шукаєте.


тл; д-р

Виконати git addпершим.


8
Такий хакер, але ей, він працює і, здається, це єдиний спосіб зробити це. Мені б хотілося, що було git stash apply --forceчи що.
Метт Кантор

12
Насправді це не хак - це покращення над тим, що ви хочете, оскільки ви можете легко повернутися до змін в індексі.
hoffmanc

2
Вау, чи справді така поведінка призначена git?
edi9999

9
Я не думаю, що git git колись «задумав». Моя думка на сьогоднішній день, що все, що git, робить це випадково.
Profpatsch

5
Це ідеальне рішення. Я щойно зробив це git add ., щоб git stash applyпотім git resetзастосувати скрипт до моїх робочих змін і об'єднатись без необхідності робити зобов’язання.
Стівен Сміт

70

Біг git stash popабо git stash applyпо суті є злиття. Вам не повинно було вносити ваші поточні зміни, якщо файли, змінені в скрині, також не будуть змінені в робочій копії, і в цьому випадку ви побачили б це повідомлення про помилку:

error: Your local changes to the following files would be overwritten by merge:
       file.txt
Please, commit your changes or stash them before you can merge.
Aborting

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


1
Я отримав таке повідомлення - зміни не конфліктують, але мають спільні файли, будь-які з використанням скриптів / застосувань?
Беміс

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

3
Я б не вважав це відповіддю у всіх випадках. Можливо, ви заховали лише частину набору змін у певному файлі, оскільки хотіли щось перевірити під час розробки. І ви, можливо, не захочете вводити поточний вміст файлу в цей час (або зовсім не так), як це WIP. Це справжня проблема з git, що приховані зміни не можуть бути об'єднані у вашу нинішню гілку
Thomas Watson

21
Відповідь Джошуа Уорнера повинна бути такою, яку позначають як правильну. Щоб об'єднати скриньку, сформулюйте зміни, застосуйте приховування, вирішіть будь-які конфлікти, а потім (за бажанням) зніміть свої зміни.
Vroo

4
"Ви можете здійснити зміни, застосувати скриньку, зробити знову і скоштувати ці два комірки за допомогою git rebase, якщо ви дійсно не хочете двох комітів, але це може бути більше проблем, ніж це варто." Замість цього ви можете зробити: Внесіть зміни, застосуйте приховування та потім git commit --amend.
Габе

27

Те, що я хочу, - це спосіб злити мої приховані зміни з поточними змінами

Ось ще один варіант зробити це:

git stash show -p|git apply
git stash drop

git stash show -pпокаже виправлення останнього збереженого сховища. git applyзастосовуватиме його. Після завершення об'єднання об'єднаний скрипт можна скинути git stash drop.


1
Дякую за це - я не знаю, чому git stash popце не робиться просто у випадках, коли злиття чисто застосовується ...
Iguananaut

Розширена версія: git stash show -p --no-color | git apply --3way( --3way= падіння на тристоронній злиття, якщо патч не виходить).
Дмитро Сандалов

Але git stash show -pстворює різницю між прихованим вмістом та фіксацією назад, коли вперше створено запис сховища . Таким чином, це замінить робочий файл змінами, зробленими ОП.
Пол Ф. Вуд

Навіщо перезаписувати? Різниця, створена з, git stash show -pбуде об'єднана git apply, якщо можливо обійтися без конфліктів.
ks1322

1

Тоді, як я це роблю, git addце спочатку до цього git stash apply <stash code>. Це найпростіший спосіб.


3
Як це не точна копія tl; dr прийнятої відповіді?
RomainValeri

0

Як запропонував @Brandan, ось що мені потрібно було зробити, щоб обійти

error: Your local changes to the following files would be overwritten by merge:
       file.txt
Please, commit your changes or stash them before you can merge.
Aborting

Дотримуйтесь цього процесу:

git status  # local changes to `file`
git stash list  # further changes to `file` we want to merge
git commit -m "WIP" file
git stash pop
git commit -m "WIP2" file
git rebase -i HEAD^^  # I always use interactive rebase -- I'm sure you could do this in a single command with the simplicity of this process -- basically squash HEAD into HEAD^
# mark the second commit to squash into the first using your EDITOR
git reset HEAD^

І вам залишиться повністю об'єднати локальні зміни file, готові до подальшої роботи / очищення або зробити єдиний хороший вчинок. Або, якщо ви знаєте, що об'єднаний вміст fileбуде правильним, ви можете написати відповідне повідомлення і пропустити git reset HEAD^.


0

Можливо, це не найгірша ідея злиття (через difftool) з ... так ... гілка!

> current_branch=$(git status | head -n1 | cut -d' ' -f3)
> stash_branch="$current_branch-stash-$(date +%yy%mm%dd-%Hh%M)"
> git stash branch $stash_branch
> git checkout $current_branch
> git difftool $stash_branch

0

можна легко

  1. Зробіть свої поточні зміни
  2. Видаліть сховище та вирішіть конфлікти
  3. Внести зміни зі скришника
  4. Повторне скидання для здійснення, з якого ви збираєтесь (остання правильна фіксація)

-1

Інший варіант - зробити ще один "git stash" з локальних невмілих змін, а потім об'єднати два git stas. На жаль, схоже, що у git немає способу легко поєднати дві сташі. Отже, один варіант - створити два .diff-файли та застосувати їх обидва - принаймні, це не зайвий фіксатор і не передбачає десятиступенкового процесу: |

як: https://stackoverflow.com/a/9658688/32453


Перетворюється проблема застосування однієї різниці в проблему застосування двох розрізнів. Крім того, прийняте рішення не передбачає фіксації, а лише етап, а це лише одна команда (git add). (Я не прихильник.)
Ейке

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