Я хотел бы переместить последние несколько коммитов, которые я совершил, чтобы освоить, в новую ветку и вернуть мастер до того, как эти коммиты были сделаны. К сожалению, мой Git-fu еще недостаточно силен, какая-нибудь помощь?
Т.е. как можно из этого выйти
master A - B - C - D - E
к этому?
newbranch C - D - E
/
master A - B
git
git-branch
branching-and-merging
Марк А. Николози
источник
источник
Ответы:
Переезд в существующую ветку
Если вы хотите переместить ваши коммиты в существующую ветку , это будет выглядеть так:
--keep
Опция сохраняет любые неподтвержденные изменения , которые могут возникнуть в несвязанных файлах, или откатится , если эти изменения должны быть перезаписаны - аналогично тому , чтоgit checkout
делает. Если он прерывается, внеситеgit stash
изменения и повторите попытку или используйте,--hard
чтобы потерять изменения (даже из файлов, которые не изменились между фиксациями!)Переезд в новую ветку
Этот метод работает, создавая новую ветку с первой командой (
git branch newbranch
), но не переключаясь на нее. Затем мы откатываем текущую ветку (master) и переключаемся на новую ветку, чтобы продолжить работу.Но удостоверьтесь, сколько человек вернется. В качестве альтернативы, вместо того
HEAD~3
, чтобы просто указать хеш коммита (или ссылкуorigin/master
), к которой вы хотите вернуться, например:ВНИМАНИЕ: В Git версии 2.0 и более поздних, если вы позже
git rebase
добавите новую ветку к исходной (master
) ветке, вам может понадобиться явная--no-fork-point
опция во время перебазирования, чтобы избежать потери коммитов, перемещенных вами из главной ветки. Имеяbranch.autosetuprebase always
набор делает это более вероятно. См . Ответ Джона Меллора для деталей.источник
Для тех, кто интересуется, почему это работает (как я был сначала):
Вы хотите вернуться к C и переместить D и E в новую ветвь. Вот как это выглядит на первый взгляд:
После
git branch newBranch
:После
git reset --hard HEAD~2
:Поскольку ветвь является просто указателем, мастер указал на последний коммит. Когда вы сделали newBranch , вы просто сделали новый указатель на последний коммит. Затем с помощью
git reset
вы переместили главный указатель назад на две фиксации. Но так как вы не переместили newBranch , он все еще указывает на коммит, который он сделал изначально.источник
git push origin master --force
чтобы изменения отображались в основном репозитории.git rebase
будете молча отбрасывать 3 коммитаnewbranch
. Смотрите мой ответ для деталей и более безопасных альтернатив.origin/master
не отображается на диаграмме выше. Если вы нажмете,origin/master
а затем внесете изменения выше, конечно, все будет смешно. Но это проблема «Доктор, мне больно, когда я делаю это». И это выходит за рамки того, что задал первоначальный вопрос. Я предлагаю вам написать свой вопрос, чтобы изучить свой сценарий, а не угонять этот.git branch -t newbranch
». Вернитесь и прочитайте ответы снова. Никто не предлагал это сделать.newbranch
станет ясно, что они хотят базироваться на существующей локальнойmaster
ветке. После выполнения обслуживаемого ответа, когда пользователь получает вокруг работаетgit rebase
вnewbranch
, мерзавец будет напоминать им , что они забыли установить вверх по течению ветви, так что они будут работать ,git branch --set-upstream-to=master
тоgit rebase
и та же проблема. Они могут также использоватьgit branch -t newbranch
в первую очередь.В основном...
Метод, раскрытый Sykora, является лучшим вариантом в этом случае. Но иногда это не самый простой и не общий метод. Для общего метода используйте git cherry-pick :
Чтобы достичь того, чего хочет OP, это двухэтапный процесс:
Шаг 1 - Обратите внимание, какой коммит от мастера вы хотите на
newbranch
казнить
Обратите внимание на хеши (скажем, 3) коммитов, на которые вы хотите
newbranch
. Здесь я буду использовать:C commit:
9aa1233
D commit:
453ac3d
E commit:
612ecb3
Шаг 2 - Положите их на
newbranch
ИЛИ (на Git 1.7.2+, используйте диапазоны)
git cherry-pick применяет эти три коммита к newbranch.
источник
Еще один способ сделать это, используя всего 2 команды. Также сохраняет ваше текущее рабочее дерево нетронутым.
Старая версия - прежде чем я узнал о
git branch -f
Будучи в состоянии ,
push
чтобы.
это хороший трюк , чтобы знать.источник
git branch -f
здесь отличается ?.
является текущим директором. Git может нажать на удаленные или GIT URL-адреса.path to local directory
поддерживается синтаксис Git URL. Смотрите раздел GIT URLS вgit help clone
.Большинство предыдущих ответов опасно неправильны!
Не делайте этого:
Поскольку в следующий раз, когда вы запустите
git rebase
(илиgit pull --rebase
), эти 3 коммита будут молча отброшеныnewbranch
! (см. объяснение ниже)Вместо этого сделайте это:
--keep
это как--hard
, но безопаснее, так как терпит неудачу, а не выбрасывает незафиксированные изменения).newbranch
.newbranch
. Поскольку на них больше не ссылается ветвь, она делает это с помощью git reflog :HEAD@{2}
коммит, которыйHEAD
использовался для ссылки на 2 операции назад, то есть до того, как мы 1. извлеклиnewbranch
и 2. использовалиgit reset
для отмены 3 коммитов.Предупреждение: reflog включен по умолчанию, но если вы отключили его вручную (например, с помощью «чистого» хранилища git), вы не сможете вернуть 3 коммитов после запуска
git reset --keep HEAD~3
.Альтернатива, которая не зависит от reflog:
(если вы предпочитаете, вы можете написать
@{-1}
- ранее проверенную ветку - вместоoldbranch
).Техническое объяснение
Зачем
git rebase
отказываться от 3 коммитов после первого примера? Это связаноgit rebase
с тем, что без аргументов--fork-point
по умолчанию эта опция включена, которая использует локальный журнал reflog, чтобы попытаться быть устойчивым к принудительной ветке восходящей ветки.Предположим, что вы разветвились от origin / master, когда он содержал коммиты M1, M2, M3, а затем сделали три коммита самостоятельно:
но затем кто-то переписывает историю, принудительно нажимая origin / master, чтобы удалить M2:
Используя ваш локальный reflog,
git rebase
можно увидеть, что вы разветвились из более ранней инкарнации origin / master ветви, и, следовательно, что коммиты M2 и M3 на самом деле не являются частью вашей тематической ветви. Следовательно, это разумно предполагает, что, поскольку M2 был удален из вышестоящей ветки, вы больше не захотите его в своей ветке тем, как только ветвь темы будет перебазирована:Такое поведение имеет смысл, и, как правило, это правильно делать при перебазировании.
Так что причина того, что следующие команды не работают:
потому что они оставляют reflog в неправильном состоянии. Git считает,
newbranch
что он раздвоил ветку upstream в ревизии, которая включает в себя 3 коммита, затемreset --hard
переписывает историю апстрима для удаления коммитов, и поэтому при следующем запускеgit rebase
он отбрасывает их, как и любой другой коммит, который был удален из апстрима.Но в данном конкретном случае мы хотим, чтобы эти 3 коммита рассматривались как часть ветки темы. Чтобы достичь этого, нам нужно отключить апстрим в более ранней ревизии, которая не включает 3 коммита. Это то, что делают мои предложенные решения, поэтому они оба оставляют reflog в правильном состоянии.
Для получения дополнительной информации см. Определения
--fork-point
в документах git rebase и git merge-base .источник
master
. Так что нет, они не опасно ошибаются.-t
вы ссылаетесь,git branch
происходит неявно, если выgit config --global branch.autosetuprebase always
установили. Даже если вы этого не сделаете, я уже объяснил вам, что такая же проблема возникает, если вы настраиваете отслеживание после выполнения этих команд, что, скорее всего, намеревается сделать ОП, учитывая их вопрос.Гораздо проще решение с использованием git stash
Вот гораздо более простое решение для фиксации в неправильной ветви. Начиная с ветки
master
с тремя ошибочными коммитами:Когда использовать это?
master
Что это делает, по номеру строки
master
, но оставляет все рабочие файлы нетронутымиmaster
рабочее дерево точно равным состоянию HEAD ~ 3newbranch
Теперь вы можете использовать
git add
иgit commit
как обычно. Все новые коммиты будут добавлены вnewbranch
.Что это не делает
цели
ОП заявил, что цель состояла в том, чтобы «вернуть мастера до того, как эти коммиты были сделаны», не теряя изменений, и это решение делает это.
Я делаю это, по крайней мере, один раз в неделю, когда я делаю новые коммиты
master
вместоdevelop
. Обычно у меня есть только один коммит для отката, в этом случае использованиеgit reset HEAD^
в строке 1 - более простой способ отката только одного коммита.Не делайте этого, если вы отправили изменения мастера вверх по течению
Кто-то еще, возможно, потянул эти изменения. Если вы переписываете только свой локальный мастер, то это не повлияет на его продвижение вверх по потоку, но передача переписанной истории сотрудникам может вызвать головную боль.
источник
git add
иgit commit
команды, и команды, которые я использовал, поэтому все, что мне нужно было сделать, это нажать стрелку вверх и войти несколько раз, и бум! Все вернулось, но теперь на правильной ветке.Это не «перемещает» их в техническом смысле, но имеет тот же эффект:
источник
rebase
для того же?rebase
ветку в сценарии выше.Чтобы сделать это без переписывания истории (т.е. если вы уже выдвинули коммиты):
Обе ветви могут быть вытолкнуты без усилия!
источник
Была только эта ситуация:
Я выполнил:
Я ожидал этого коммита, я был бы ГОЛОВОМ, но коммит Л это сейчас ...
Чтобы быть в нужном месте в истории, проще работать с хэшем коммита
источник
Как я могу пойти от этого
к этому?
С двумя командами
дающий
а также
дающий
источник
Если вам просто нужно переместить все ваши невыполненные коммиты в новую ветку , то вам просто нужно,
создать в новую ветвь от текущей:
git branch new-branch-name
нажмите вашу новую ветку :
git push origin new-branch-name
верните вашу старую (текущую) ветвь в последнее нажатое / стабильное состояние:
git reset --hard origin/old-branch-name
Некоторые люди также имеют другие,
upstreams
а неorigin
, они должны использовать соответствующиеupstream
источник
1) Создайте новую ветку, которая переместит все ваши изменения в new_branch.
2) Затем вернитесь к старой ветке.
3) сделать git rebase
4) Затем открытый редактор содержит информацию о последних 3 коммитах.
5) Изменить
pick
кdrop
во всех этих 3 фиксаций. Затем сохраните и закройте редактор.6) Теперь последние 3 коммита удалены из текущей ветви (
master
). Теперь принудительно нажмите на ветку со+
знаком перед именем ветви.источник
Вы можете сделать это всего за 3 простых шага, которые я использовал.
1) создать новую ветку, где вы хотите зафиксировать недавнее обновление.
git branch <branch name>
2) Найти недавний коммит-идентификатор для коммита на новой ветке.
git log
3) Скопируйте это примечание id коммита, что Список последних коммитов находится сверху. так что вы можете найти свой коммит. Вы также найдете это через сообщение.
git cherry-pick d34bcef232f6c...
Вы также можете указать некоторый диапазон идентификатора коммита.
git cherry-pick d34bcef...86d2aec
Теперь ваша работа выполнена. Если вы выбрали правильный идентификатор и правильную ветку, то у вас все получится. Поэтому перед этим будьте осторожны. иначе может возникнуть другая проблема.
Теперь вы можете нажать свой код
git push
источник
Еще один способ сделать это:
[1] Переименуйте
master
ветку в своюnewbranch
(если вы находитесь наmaster
ветке):[2] Создайте
master
ветку из коммита, который вы хотите:источник