git stash -> объединить сохраненные изменения с текущими изменениями


187

Я внес некоторые изменения в свою ветку и понял, что забыл, что я спрятал некоторые другие необходимые изменения в этой ветке. То, что я хочу, - это способ объединить мои скрытые изменения с текущими изменениями.

Есть ли способ сделать это?

Это больше для удобства, в конце концов я сдался и зафиксировал сначала свои текущие изменения, а затем свои скрытые изменения, но я бы предпочел ввести их одним махом.


Вероятно, дубликат stackoverflow.com/q/1360712/72178
ks1322

Ответ Иисуса Навина должен быть принятым ответом. Это сообщение от stackoverflow - первая ссылка Google на этот вопрос, дайте правильный ответ в Интернете!
Жером

Ответы:


272

Я только что обнаружил, что если ваши незафиксированные изменения будут добавлены в индекс (т. Е. «Поэтапно», используя 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или что-то.
Мэтт Кантор

13
На самом деле, это не хак - это улучшение по сравнению с тем, что вы хотите, так как вы можете легко вернуться к изменениям в индексе.
Hoffmanc

2
Ничего себе, действительно ли это поведение предназначено Git?
edi9999

9
Я не думаю, что есть что-то «предназначенное» 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
Я получил это сообщение - изменения не конфликтуют, а делятся одними и теми же файлами, есть ли какие-нибудь случаи использования stashes / apply?
Бемис,

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создает разницу между сохраненным содержимым и фиксацией назад, когда запись в хранилище была создана впервые . Так что это перезапишет изменения рабочего файла, сделанные OP.
Пол Ф. Вуд

Зачем перезаписывать? Созданный с помощью diff git stash show -pбудет объединен git apply, если это возможно без конфликтов.
ks1322

1

То, как я это делаю, git addэто сначала к этому git stash apply <stash code>. Это самый простой способ.


4
Как это не является точной копией принятого ответа?
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 stash. К сожалению, у git, похоже, нет возможности легко объединить два тайника. Таким образом, один из вариантов - создать два файла .diff и применить их оба - чтобы это не было дополнительной фиксацией и не требовало десятиэтапного процесса: |

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


Это превращает проблему применения одного различий в проблему применения двух различий. Кроме того, принятое решение не включает коммит, просто этап, и это только одна команда (git add). (Я не downvoter.)
Айке

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