Как объединить мои локальные незафиксированные изменения в другую ветку Git?

621

Как я могу сделать следующее в Git?

Моя текущая ветвь - это branch1, и я сделал некоторые локальные изменения. Однако теперь я понимаю, что на самом деле я хотел применить эти изменения к branch2. Есть ли способ применить / объединить эти изменения, чтобы они стали локальными изменениями на branch2, не фиксируя их на branch1?

solsberg
источник
2
Существует большая Гит Учебник прямо здесь на SO. Это своего рода центральный вопрос для всех мерзавцев по переполнению стека.
Децио Лира

Ответы:

898

Поскольку ваши файлы еще не зафиксированы в branch1:

git stash
git checkout branch2
git stash pop

или

git stash
git checkout branch2
git stash list       # to check the various stash made in different branch
git stash apply x    # to select the right one

Как отметила по benjohn (см справочной git stashстранице ):

Чтобы также сохранить текущие неотслеживаемые (недавно добавленные) файлы, добавьте аргумент -uтак:

git stash -u
VonC
источник
2
Добро пожаловать. Больше примеров использования тайника на unethicalblogger.com/posts/2008/11/… .
VonC
2
Если вы ищете решение той же проблемы, но с TFS, эквивалентное решение - отложить ваши изменения, а затем использовать TFS Power Tools, чтобы отменить переход к правильной ветви с помощью переключателя / migrate.
xr280xr
1
Это сработало для меня. Тем не менее, мне также пришлось создать локальную ветку, чтобы 'stash pop' работал. Оформить заказ на stackoverflow.com/questions/1783405/git-checkout-remote-branch, если что-то подобное происходит с вами.
mimoralea
21
Для того, чтобы также копить в настоящее время неотслеживаемые (недавно добавленные файлы) , добавьте аргумент -u, так: git stash -u.
Бенджон
2
@ Benjohn Хороший вопрос. Я включил ваш комментарий в ответ для большей наглядности.
VonC
84

Скопирование, временные коммиты и перебазирование могут быть излишними. Если вы еще не добавили измененные файлы в индекс, то вы можете просто извлечь другую ветку.

git checkout branch2

Это будет работать до тех пор, пока файлы, которые вы редактируете, не различаются между branch1 и branch2. Он оставит вас на branch2 с сохраненными рабочими изменениями. Если они отличаются, вы можете указать, что хотите объединить свои локальные изменения с изменениями, внесенными путем переключения ветвей с -mвозможностью оформления заказа.

git checkout -m branch2

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

git reset
CB Bailey
источник
3
Я думал, что тайник «проще» как-то понять, но ваш подход лучше учитывать рабочую директорию в разных ветках. +1
VonC
6
Простая традиционная проверка казалась более подходящей для рассматриваемой проблемы. Оформить заказ легче, он просто обновляет файлы, которые нужно изменить. Возможно, легче понять подход к хранилищу, или может быть просто не достаточно очевидно, что извлечение является «безопасным» в этом случае использования.
CB Bailey
Если checkout -mв некоторых ситуациях «небезопасно» (возможно, это приведет к конфликту слияния), предоставит ли stash какое-либо преимущество (например, можете ли вы открыть поп-шоп)?
Крейг МакКуин
1
@craigMcQueen Вы не можете открыть всплывающий тайник, но он будет жаловаться на конфликты, когда вы его открываете. Вы можете исправить конфликты, а затем зафиксировать, но в этом случае исходный тайник все еще находится в стеке! :)
Shaun F
В случае конфликта слияния файлы не копируются как .orig?
jocull
13

Более короткая альтернатива ранее упоминавшемуся подходу тайника:

Временно переместите изменения в тайник.

  1. git stash

Создайте и переключитесь на новую ветку, а затем вставьте в нее тайник всего за один шаг.

  1. git stash branch new_branch_name

Тогда как раз addи commitвносятся изменения в эту новую ветку.

rbento
источник
10

ВНИМАНИЕ: Не для мерзавцев-новичков.

Этого достаточно в моем рабочем процессе, и я почти попытался написать для него новую команду git. Обычный git stashпоток - это путь, но он немного неловкий. Обычно я сначала делаю новый коммит, так как, если я смотрю на изменения, вся информация свежа в моих мыслях, и лучше просто начать git commitто, что я нашел (обычно это исправление, принадлежащее мастеру, которое я обнаруживаю, работая над функция ветка) сразу.

Также полезно - если вы часто сталкиваетесь с подобными ситуациями - иметь другой рабочий каталог рядом с вашим текущим, в котором masterветка всегда проверена.

Итак, как я этого добиваюсь, выглядит так:

  1. git commit изменения сразу с хорошим сообщением фиксации.
  2. git reset HEAD~1 отменить коммит из текущей ветки.
  3. (необязательно) продолжить работу над функцией.

Иногда позже (асинхронно) или сразу в другом окне терминала:

  1. cd my-project-master который является другим WD, разделяющим то же самое .git
  2. git reflog чтобы найти исправление, которое я только что сделал.
  3. git cherry-pick SHA1 из коммита.

При желании (все еще асинхронном) вы можете затем перебазировать (или объединить) вашу функциональную ветку, чтобы получить исправление, обычно, когда вы собираетесь отправить PR и уже очистили свою функциональную ветку и WD:

  1. cd my-project который является основным WD, над которым я работаю.
  2. git rebase master чтобы получить исправления.

Таким образом, я могу продолжать работать над функцией непрерывно и не беспокоиться о git stashчем-либо или о необходимости чистить мой WD перед git checkout(и затем снова проверять ветку функции), и все равно иметь все свои исправления ошибок masterвместо спрятан в моей ветке

IMO git stashи git checkoutнастоящая PIA, когда вы находитесь в середине работы над какой-то большой функцией.

chakrit
источник
Интересная и действительная альтернатива моему ответу. +1
VonC
Ты идешь из ртути? my-project-masterРазделяя те же .gitделает звук , как он. Почему бы не git checkout -b bugfixABC; git commit -a; git reset HEAD^ --hard, то позже (асинхронно) , а на master, git cherry-pick <SHA1 of the commit(s) in bugfixABC? (или даже, чтобы избежать необходимости выяснять SHA1, git rebase --onto master feature bugfixABCиз того места, где вы в данный момент находитесь. Это означает, что вы можете сделать это сразу после git resetвышеперечисленного, feature
Gauthier
Тем не менее, OP звучит так, как будто они не готовы принять изменения, в этом случае просто checkout -mлучше.
Готье
2

Если бы речь шла о совершенных изменениях, вы должны взглянуть на git-rebase, но, как указано в комментарии VonC, когда вы говорите о локальных изменениях, git-stash, безусловно, будет хорошим способом сделать это.

CLAF
источник
Я не понимаю этого решения: оно переписало бы историю коммитов branch2 из branch1 ... зачем получать все зафиксированные изменения из branch1 в branch2, когда мы хотим получить только локальные не зафиксированные изменения branch1 в branch2? ...
VonC
@VonC: согласен, в этом случае ребаз получает все зафиксированные изменения с момента последнего слияния ветвей в branch1. Сначала я не получил параметр «не совершено» этого вопроса. ребаз не хороший ответ.
CLAF
@claferri: pfew ... У меня начинала болеть голова;) Я бы отказался от твоего ответа, но, поскольку я сам его опубликовал, возник "явный конфликт интересов". С твоим обновленным постом мне теперь вообще не нужно понижать голос. Спасибо :)
VonC
@VonC: в следующий раз не стесняйтесь голосовать, если мой ответ так же неправильн, как этот;)
claf 17.02.09
1

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

Как перейти на другую ветку в git

У вас есть незафиксированные изменения, my_branchкоторые вы хотите зафиксировать master, не фиксируя все изменения my_branch.

пример

git merge master
git stash -u
git checkout master
git stash apply
git reset
git add example.js
git commit
git checkout .
git clean -f -d
git checkout my_branch
git merge master
git stash pop

объяснение

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

-uВариант (он же --include-untracked) в git stash -uпредотвращает вас от потери неотслеживаемые файлов , когда вы позже сделать git clean -f -dвнутри master.

После git checkout masterтого, как важно, что вы НЕ делаете git stash pop, потому что вам понадобится этот тайник позже. Если вы поп тайник , созданный в my_branchа затем сделать git stashв master, вы будете вызывать ненужные конфликты слияния , когда вы примените этот тайник в my_branch.

git resetunstages все, что в результате git stash apply. Например, файлы, которые были изменены в тайнике, но не существуют в них, masterставятся как конфликты, «удаленные нами».

git checkout .и git clean -f -dотбросить все, что не зафиксировано: все изменения в отслеживаемых файлах и все неотслеживаемые файлы и каталоги. Они уже сохранены в тайнике и, если их оставить master, вызовут ненужные конфликты слияния при переключении обратно на my_branch.

Последний git stash popбудет основан на оригинале my_branch, и поэтому не вызовет конфликтов слияния. Однако, если ваш тайник содержит неотслеживаемые файлы, которые вы посвятили мастеру, git будет жаловаться на то, что он «не может восстановить неотслеживаемые файлы из тайника». Чтобы разрешить этот конфликт, удалить эти файлы с вашего рабочего дерева, а затем git stash pop, git add ., и git reset.

Владимир Корнеа
источник
2
Ваш ответ не был удален, потому что он ссылался на ваш сайт, он был удален, потому что он был идентичен этому другому ответу из другого аккаунта. Я вижу, что другой аккаунт имеет тот же профиль, что и ваш, вы используете два аккаунта? Вы можете объединить обе учетные записи. Кроме того, пометьте мод, чтобы объяснить ситуацию, и вы можете получить свой исходный ответ (с повышенным голосом), который будет удален.
1
Вы не можете держать их отдельно , если они объединены, но которые разрешено иметь несколько учетных записей, до тех пор , пока вы не использовать их для совершения голосования мошенничества (или у них взаимодействуют друг с другом в целом). Объясни свою ситуацию моду. Кроме того, удаление было честной ошибкой. Как вы могли ожидать, что кто-то скажет, что вы используете два разных аккаунта?
3
Вам нужно пометить ваше сообщение и использовать опцию Другое, чтобы привлечь внимание мода, на который вы не будете обращать внимания, когда вы редактируете удаленный ответ. Я уже пометил ваши сообщения для модного внимания, но они довольно заняты, так что наберитесь терпения, они в конечном итоге дойдут до вас.
1
Не публикуйте дублированный контент, особенно из разных аккаунтов. Проголосуйте или отметьте, чтобы закрыть как дубликаты, если два вопроса совпадают.
Билл Ящерица