Как решить конфликт с git stash без коммитов?


495

Как было задано в этом вопросе , я также хочу знать, как разрешить конфликт, git stash popне добавляя все изменения в коммит (как это делает «git stash pop» без конфликта).

Мой нынешний подход очень не крутой, потому что я делаю это так:

git stash pop -> CONFLICT
git stash drop
[resolve conflict]
[add conflict files]
git reset HEAD <all files that are in commit-mode>

[Обновление] Способ воспроизвести это:

mkdir foo; cd foo; git init
echo "1" > one
echo "2" > two
git add -A; git commit -m "first"
echo "1.1" > one
echo "2.1" > two
git stash
echo "2.2" > two
git commit -a -m "second"
echo "Only this file would stay in HEAD without the conflict" > third
git add third
git stash pop
git status

2016-06-27: Добавлен новый файл с именем «третий» в пример, чтобы показать, что обходные пути, такие как решение от scy, работают только для пустых HEAD, но не устраняют первоначальную проблему, заключающуюся в том, что HEAD не имеет такой же контент, как для git stash popбез конфликта.


Таким образом, вы git addразрешаете конфликтные файлы, эффективно помещая их в индекс, и хотите, чтобы их не было в нашем индексе?
Ромен

Да все верно. Я просто хочу поведение, которое git stash popпроисходит, когда не возникает конфликта (но с уведомлением, какие файлы должны быть объединены).
Свен

2
Похоже, ответ на этот вопрос здесь: stackoverflow.com/questions/3945826/git-stash-questions . В выбранном ответе на 4-м комментарии Адам объясняет, почему Git делает это.
Патрик

@Patrick Спасибо за эту информацию - так что, похоже, не будет никакого доступного решения, потому что оно «разработано»
Свен

Ответы:


510

Не следуйте другим ответам

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

Чистый раствор

Следующее решение кажется мне намного чище, и оно также предлагается самим Git - попробуйте выполнить git statusв хранилище конфликт:

Unmerged paths:
  (use "git reset HEAD <file>..." to unstage)
  (use "git add <file>..." to mark resolution)

Итак, давайте сделаем то, что предлагает Git (без каких-либо бесполезных коммитов):

  1. Вручную (или с помощью какого-либо инструмента слияния , см. Ниже) разрешите конфликт (ы).
  2. Используйте, git resetчтобы пометить конфликт (ы) как разрешенные и отменить изменения. Вы можете выполнить его без каких-либо параметров, и Git удалит все из индекса. Вы не должны выполнять git addраньше.
  3. Наконец, удалите тайник с помощью git stash drop, потому что Git не делает этого при конфликте.

Переведено в командную строку:

$ git stash pop

# ...resolve conflict(s)

$ git reset

$ git stash drop

Объяснение поведения по умолчанию

Существует два способа пометить разрешенные конфликты: git addи git reset. Хотя git resetпомечает конфликты как разрешенные и удаляет файлы из индекса, git addтакже помечает конфликты как разрешенные, но сохраняет файлы в индексе.

Добавление файлов в индекс после разрешения конфликта происходит специально. Таким образом, вы можете отличить изменения от предыдущего тайника и изменения, сделанные после разрешения конфликта. Если вам это не нравится, вы всегда git resetможете удалить все из индекса.

Инструменты слияния

Я настоятельно рекомендую использовать любой из трехсторонних инструментов слияния для разрешения конфликтов, например, KDiff3 , Meld и т. Д., Вместо того, чтобы делать это вручную. Обычно он сам решает все или большинство конфликтов автоматически. Это огромная экономия времени!


32
@kamalpal, кажется, это необходимо, когда git stash popтерпит неудачу с конфликтами.
Эмиль Бержерон

21
@kamalpal да, Git даже уведомляет вас, что тайник не был сброшен в случае конфликта. И вопрос был о таком случае, поэтому вам действительно нужно выполнить,git stash drop если вы не хотите сохранить этот тайник.
Дэвид Ференци Рогожан

@ DavidFerenczyRogožan Git вообще не уведомил меня о том, что не пропустил тайник. Версия 2.17.1 здесь.
Роберт Симер

298

Предположим, у вас есть этот сценарий, где вы храните свои изменения, чтобы вытащить из источника. Возможно, потому что ваши локальные изменения просто debug: trueв каком-то файле настроек. Теперь вы тянете, и кто-то ввел новую настройку там, создавая конфликт.

git status говорит:

# On branch master
# Unmerged paths:
#   (use "git reset HEAD <file>..." to unstage)
#   (use "git add/rm <file>..." as appropriate to mark resolution)
#
#   both modified:      src/js/globals.tpl.js
no changes added to commit (use "git add" and/or "git commit -a")

Ладно. Я решил пойти с тем, что предложил Git: я решил конфликт и совершил:

vim src/js/globals.tpl.js
# type type type …
git commit -a -m WIP   # (short for "work in progress")

Теперь моя рабочая копия находится в том состоянии, в котором я хочу, но я создал коммит, который мне не нужен. Как мне избавиться от этого коммита без изменения моей рабочей копии? Подождите, есть популярная команда для этого!

git reset HEAD^

Моя рабочая копия не была изменена, но фиксация WIP пропала. Это именно то, что я хотел! (Обратите внимание, что я здесь не использую --soft, потому что, если в вашем тайнике есть автоматически объединенные файлы, они автоматически размещаются, и, таким образом, вы в конечном итоге получите эти файлы снова reset.)

Но осталась еще одна вещь: страница руководстваgit stash pop напоминает нам, что «применение состояния может привести к сбою при конфликтах; в этом случае оно не удаляется из списка хранения. Вам необходимо разрешить конфликты вручную и git stash dropвпоследствии вызвать их вручную». Вот что мы делаем сейчас:

git stash drop

И сделано.


34
Просто унаследовано много уродства, когда нужно сознательно выполнять сброс коммитов HEAD ^ ... для чего-то, что должно влиять только на рабочее дерево.

6
Почему бы просто не разрешить конфликты, а затем git add <resolved conflict files>последовать git reset HEAD?
BoltzmannBrain

Спасибо за предложение, но это не решает первоначальную проблему, что это не то же самое поведение, что и git stash popбез конфликта. Просто добавьте еще один файл в HEAD, прежде чем делать конфликтующие, git stash popа затем вы git commit -a -m WIPдобавите новый файл в коммит. Но без конфликта, только новый файл останется в HEAD, но не git stash popфайлы.
Свен

7
Я не думаю, что необходимо сначала зафиксировать, а затем отменить фиксацию. Просто сбросьте от Давида Ференчи ответ будет так же
vladkras

3
Для пользователей Windows, ^это используется в качестве специального продолжения линии и оставит вас сидеть на Подробнее? подскажите вместо выполнения команды. Вместо того, чтобы использовать: git reset --soft HEAD~1. Видите, как сделать-я-удалить-unpressed-git-commits?
mrfelis

87

Вместо добавления изменений, внесенных вами для разрешения конфликта, вы можете использовать его git reset HEAD fileдля разрешения конфликта без постановки изменений.

Возможно, вам придется выполнить эту команду дважды, однако. Один раз, чтобы пометить конфликт как разрешенный, и один раз, чтобы отменить внесение изменений, которые были поставлены процедурой разрешения конфликтов.

Вполне возможно, что должен быть режим сброса, который выполняет обе эти функции одновременно, хотя сейчас его нет.


2
Режим сброса - тот, который я ищу - другие обходные пути похожи на тот, который я описал, и не подходят для более чем 5 файлов.
Свен

25
И используйте «git stash drop», чтобы закончить «git stash pop».
Дэвид Лю

2
Хотя вопрос не требует этого явно, может быть полезно обновить ответ, включив в него «git stash drop», так как тайник не удаляется автоматически в случае конфликта.
Абхишек Патхак

29
git checkout stash -- .

работал на меня.

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


Это помогло, когда "git pull --autostash" вводит нежелательные коммиты слияния и git checkout stash -. безусловно перезаписывает конфликты из тайника
Алек Истомин

11
git add .
git reset

git add . установит ВСЕ файлы, сообщающие git, что вы разрешили конфликт

git reset будет удалять все поставленные файлы без создания коммита


Это на самом деле не плохой ответ, это очень похоже на git add -uтоgit reset
ebob

4

Кажется, что это может быть ответом, который вы ищете, я лично еще не пробовал, но, похоже, это может сработать. С помощью этой команды GIT попытается применить изменения, как они были раньше, не пытаясь добавить их все для фиксации.

git stash apply --index

вот полное объяснение:

http://git-scm.com/book/en/Git-Tools-Stashing


Спасибо за эту подсказку, но это не поможет, когда я уже это сделал git stash pop- или есть ли способ отменить это и сделать, git stash apply --indexкогда я узнал, что git stash popстолкнется с конфликтом?
Свен

Я добавил пример того, как это сделать - представьте, что вы редактируете более 10 файлов, поэтому вы не знаете, какой из них вы изменили за пределами тайника.
Свен

3
Если вы посмотрите на нижнюю часть этого поста ЗДЕСЬ, там написано, что если вы запустите git stash popи у вас возникнут конфликты, тайник не будет удален ... так что вы можете запустить, git reset --hardчтобы отменить всплывающее окно, а затем попробовать предложенное мной решение.
Марко Понти

Просто попробовал это, и это не работает после того, как у вас есть файл в состоянии конфликта. Даже если вы исправите конфликт вручную.
Sam3k

2

git stash branchwill works, которая создает новую ветку для вас, проверяет коммит, на котором вы были, когда вы спрятали свою работу, повторно применяет свою работу там, а затем удаляет тайник, если он успешно применяется. проверить это


2

Самый быстрый способ, который я нашел, - это разрешить конфликт, затем сделать git add -u, а потом и сделать git reset HEAD, что даже не требует фиксации.


1

Согласно Git Stash вопросы , после устранения конфликта,git add <file> это правильный курс действий.

После прочтения этого комментария я понял, что изменения автоматически добавляются в индекс (по проекту). Вот почему git add <file>завершает процесс разрешения конфликта.


-1

Это не лучший способ сделать это, но это работает:

$ git stash apply
$ >> resolve your conflict <<
$ >> do what you want to do with your code <<
$ git checkout HEAD -- file/path/to/your/file

этот ответ кажется мне совершенно неправильным, так как он отбрасывает все изменения file/path/to/your/file, о которых не спрашивал ОП, AFAIU
oromoiluig
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.