Основным механизмом хранения Git является фиксация — на самом деле все, что git stash
делает, — это делает пару несколько необычных коммитов, поэтому ответ Ника Волынкина является правильным. Однако, возможно, потребуется немного расширения, и есть более простые (ну, потенциально более простые) методы.
Я не очень большой поклонник git stash
, но если вы привыкли его использовать, вот самый простой из других методов:
git stash save
(он же git stash
). Это записывает две фиксации, одну на основе текущего индекса, а вторую для хранения еще не подготовленных файлов рабочего дерева. (Если вам нужно сохранить неотслеживаемые файлы, вы можете добавить флаг -u
, а затем скрипт stash добавит еще одну третью фиксацию. Обычно вы можете просто оставить эти неотслеживаемые файлы в вашем рабочем дереве неотслеживаемыми, хотя.) Эти коммиты не находятся ни в одной ветке, они находятся только в/в специальном тайнике ref. Между тем, вы все еще находитесь не в той ветке, которую я ниже назову wrongbr
.
git checkout
ветка, в которой вы хотите их разместить. Теперь вы находитесь на правильной ветке.
git stash apply --index
. При этом используются специальные коммиты тайника, сделанные на шаге 1, но при этом они остаются там (apply
) в тайнике. --index
очень важен: он указывает сценарию хранения разделять файлы индекса и неустановленные файлы, т. е. возвращает вам предварительно настроенные и неустановленные файлы.
Если все пойдет хорошо, теперь вы можете git commit
внести изменения в нужную ветку. Предыдущие файлы снова помещаются в промежуточные файлы, а неподготовленные файлы по-прежнему остаются неподготовленными, потому что вы apply
отредактировали тайник с помощью --index
. Коммит зафиксирует проиндексированные файлы, оставив непроиндексированные файлы непроиндексированными.
Теперь вы можете вернуться к другой неправильной ветке (там, где вы изначально создали тайник) и git stash apply
или git stash pop
с --index
или без него. Возможно, вам придется очистить все неустановленные файлы (и это безопасно, они все еще находятся в тайнике): git reset --hard
, затем git checkout wrongbr
, затем git stash pop
. Обратите внимание, что pop
— это просто apply
, за которым следует drop
: мы не хотели удалять тайник на шаге 3 (в тайнике есть единственная копия исходного модифицированного, но- неустановленные файлы), поэтому мы использовали там apply
, но теперь мы (предположительно) действительно хотим удалить тайник, поэтому использование pop
допустимо.
Однако на шаге 3 есть большая потенциальная ловушка: возможно, тайник не будет применяться правильно. Если это так, вы должны использовать какой-либо другой метод. Это одна из причин, по которой мне не очень нравится система stash
: она не работает в сложных случаях и оставляет вам необходимость знать инструменты, которые вы можете использовать, если не используете stash
. В этом случае вы можете просто использовать эти инструменты большую часть времени... а затем использовать stash
как удобный ярлык для случаев, когда вы уверены, что он будет работать.
Предыстория: фиксация берет все, что сейчас есть в индексе — git ls-files --cached
покажет полное содержимое, а git status
обрезает это до интересного и добавляет дополнительную полезную информацию — и делает из них фиксацию со всеми необходимыми объектами дерева и так далее. на. Родительский коммит нового коммита — это то, чем был предыдущий коммит.
Вы хотите, чтобы ваша новая фиксация была сделана в другой ветке. Один из способов сделать это — сделать это сейчас, в текущей ветке; затем скопируйте эту фиксацию в новую, другую фиксацию в другой ветке. Чтобы сделать фиксацию копии для новой, другой фиксации в другой ветке, вы можете использовать git cherry-pick
. Это правда, что вы можете использовать git rebase
: под одеялом он использует сам git cherry-pick
. Но rebase
не совсем подходящий инструмент: он предназначен для массового сбора вишен, и у вас есть только один коммит; и в конце он использует git reset
для перемещения метки ветки, но не совсем так, как вы хотите. Вы можете заставить его работать, но есть несколько более подходящих инструментов.
Однако вернемся к исходной проблеме: вы хотите взять текущий индекс и использовать его для создания новой фиксации, но в другой ветке. Это было бы проще всего, если бы вы могли просто переключиться на другую ветку сейчас, ничего не делая, а затем сделать новую фиксацию.
Скорее всего, вы можете сделать это. Просто git checkout otherbranch
, а затем git commit
. Здесь возможны три случая:
Другой ветки пока не существует. Большой! Используйте git checkout -b newbranch
, чтобы создать его, начиная с того места, где вы сейчас находитесь. Затем git commit
. Все готово, если только вы не хотите перебазировать новую ветку, чтобы она начиналась не с того места, где вы сейчас находитесь. Если это так, используйте git rebase
в новой ветке. Обратите внимание, что вы можете сделать это перебазирование позже, после того, как позаботитесь о неустановленных файлах.
Другая ветвь существует, и — вам повезло — git checkout otherbranch
работает нормально. Сделайте это и зафиксируйте, и все готово. Затем вы можете git checkout
выбрать любую ветку для неустановленных файлов.
Самый неприятный случай: другая ветка существует, но git checkout
говорит вам, что вы перезапишете то, что не зафиксировали.
Случай 3 — это тот, где вам нужно совершить или спрятать.
Что делать здесь, зависит от того, что вам наиболее удобно. Вы можете, например, попробовать четырехшаговый метод stash
, описанный выше, как самую простую альтернативу.
Однако для себя я бы просто зафиксировал сейчас, не в той ветке, а затем снова зафиксировал (или использовал git stash
), чтобы убрать неустановленные файлы. Это дает мне коммит, который я могу git cherry-pick
переместить в правую ветвь. Вот пример последовательности, которая, вероятно, сработает:
git commit
, чтобы сделать фиксацию, но не в той ветке (давайте назовем вашу текущую ветку wrongbr
для справки ниже).
git stash save
, чтобы сохранить неустановленные изменения (или, с -u
, также неотслеживаемые файлы).
git checkout
ветка, в которой вы хотите, чтобы коммит был, например, git checkout rightbr
.
git cherry-pick wrongbr
. Если это удастся, хорошо; если нет, отредактируйте файлы по мере необходимости, чтобы очистить после слияния проблемы, затем git commit
результат.
git checkout wrongbr
: теперь мы исправим это, удалив коммит, скопированный на шаге 4.
git reset --hard HEAD^
: удаляет скопированный нами коммит.
git stash pop
(или git stash apply && git stash drop
, который делает то же самое, вариант apply
просто дает вам возможность проверить результат перед тем, как вы drop
заберете тайник).
Обратите внимание на шаг 4: git cherry-pick
берет именованный коммит (наконечник wrongbr
, который содержит нужный нам коммит, который просто находится не в той ветке), сравнивает его с его родителем, а затем пытается применить полученный diff в текущую ветку. Возможно, потребуется выполнить трехстороннее слияние, если файлы в текущей ветке сильно отличаются от соответствующих им файлов в wrongbr
. Это то же самое место, где возникают сложности в простом случае простого извлечения rightbr
и первоначальной фиксации. То есть мы делаем эту длинную версию, потому что самый неприятный случай произошел, когда мы пытались просто git checkout rightbr
перед фиксацией, поэтому есть хороший шанс, что нам нужно что-то исправить. Это также может вызвать проблемы с исходным 4-шаговым методом stash
.
person
torek
schedule
20.05.2015
test/unit/[....]
выше? - person peter-b   schedule 20.05.2015