Отмените Git-слияние, которое еще не было перенесено
В моей основной ветке я сделал git merge some-other-branch
локально, но никогда не отправлял изменения в мастер-источник. Я не хотел сливаться, поэтому я хотел бы отменить это. При выполнении git status
после моего слияния я получил это сообщение:
# On branch master
# Your branch is ahead of 'origin/master' by 4 commits.
На основании некоторых инструкций, которые я нашел, я попытался запустить
git revert HEAD -m 1
но теперь я получаю это сообщение с git status
:
# On branch master
# Your branch is ahead of 'origin/master' by 5 commits.
Я не хочу, чтобы моя ветвь была впереди любого количества коммитов. Как мне вернуться к этому моменту?
36 ответов
С git reflog
проверить, какой коммит предшествует слиянию (git reflog
будет лучшим вариантом, чем git log
). Затем вы можете сбросить его, используя:
git reset --hard commit_sha
Есть и другой способ:
git reset --hard HEAD~1
Это вернет вам 1 коммит.
Имейте в виду, что любые измененные и незафиксированные / неснятые файлы будут сброшены в их неизмененное состояние. Чтобы сохранить их или спрятать изменения или посмотреть --merge
Вариант ниже.
Как @Velmont предложил ниже в своем ответе, в этом прямом случае используется:
git reset --hard ORIG_HEAD
может дать лучшие результаты, так как это должно сохранить ваши изменения. ORIG_HEAD
будет указывать на коммит непосредственно перед тем, как произойдет слияние, так что вам не придется охотиться за ним самостоятельно.
Еще один совет заключается в использовании --merge
переключаться вместо --hard
поскольку он не сбрасывает файлы без необходимости:
git reset --merge ORIG_HEAD
--merge
Сбрасывает индекс и обновляет файлы в рабочем дереве, которые отличаются между
и HEAD, но сохраняет те, которые отличаются между индексом и рабочим деревом (т. Е. С изменениями, которые не были добавлены).
Предполагая, что ваш местный мастер не опередил источника / мастера, вы должны быть в состоянии сделать
git reset --hard origin/master
Тогда ваш местный master
ветвь должна выглядеть идентично origin/master
,
См. Главу 4 в книге Git и оригинальный пост Линуса Торвальдса.
Чтобы отменить слияние, которое уже было передано:
git revert -m 1 commit_hash
Обязательно отмените возврат, если вы снова делаете ветку, как сказал Линус.
Странно, что пропала самая простая команда. Большинство ответов работают, но отмена слияния, которое вы только что сделали, это простой и безопасный способ:
git reset --merge ORIG_HEAD
Ссылка ORIG_HEAD
будет указывать на исходный коммит до слияния.
(The --merge
Опция не имеет ничего общего со слиянием. Это так же, как git reset --hard ORIG_HEAD
, но безопаснее, поскольку не затрагивает незафиксированные изменения.)
В более новых версиях Git, если вы еще не совершили слияние и у вас есть конфликт слияния, вы можете просто сделать:
git merge --abort
От man git merge
:
[Это] можно запустить только после того, как слияние привело к конфликтам.
git merge --abort
прервет процесс слияния и попытается восстановить состояние перед слиянием.
Вы должны сбросить до предыдущего коммита. Это должно работать:
git reset --hard HEAD^
Или даже HEAD^^
чтобы вернуть этот возврат совершить. Вы всегда можете дать полную ссылку на SHA, если не уверены, сколько шагов назад вы должны сделать.
В случае, если у вас возникли проблемы и в вашей основной ветке не было локальных изменений, вы можете сбросить на origin/master
,
В последнее время я использую git reflog
чтобы помочь с этим. Это в основном работает только в том случае, если произошло слияние, и оно было на вашей машине.
git reflog
может вернуть что-то вроде:
fbb0c0f HEAD@{0}: commit (merge): Merge branch 'master' into my-branch
43b6032 HEAD@{1}: checkout: moving from master to my-branch
e3753a7 HEAD@{2}: rebase finished: returning to refs/heads/master
e3753a7 HEAD@{3}: pull --rebase: checkout e3753a71d92b032034dcb299d2df2edc09b5830e
b41ea52 HEAD@{4}: reset: moving to HEAD^
8400a0f HEAD@{5}: rebase: aborting
Первая строка указывает, что произошло слияние. 2-я строка - время до моего слияния. Я просто git reset --hard 43b6032
заставить эту ветвь отследить до слияния и продолжить.
Если вы находитесь в процессе слияния, вы всегда можете прервать егоgit merge --abort
Если ветки срезаны и не задвинуты. Затем команда git reset будет работать, чтобы отменить слияние:git reset --merge ORIG_HEAD
С современным Git вы можете:
git merge --abort
Старый синтаксис:
git reset --merge
Старая школа:
git reset --hard
Но на самом деле стоит отметить, что git merge --abort
только эквивалентно git reset --merge
При условии MERGE_HEAD
настоящее. Это можно прочитать в справке Git для команды слияния.
git merge --abort is equivalent to git reset --merge when MERGE_HEAD is present.
После неудачного слияния, когда нет MERGE_HEAD
неудачное слияние может быть отменено git reset --merge
, но не обязательно с git merge --abort
Таким образом, они не только старый и новый синтаксис для одного и того же.
Лично я нахожу git reset --merge
гораздо более мощный и полезный в повседневной работе, поэтому я всегда использую его.
Хорошо, ответы, которые мне дали другие люди, были близки, но это не сработало. Вот что я сделал.
Делая это...
git reset --hard HEAD^
git status
... дал мне следующий статус.
# On branch master
# Your branch and 'origin/master' have diverged,
# and have 3 and 3 different commit(s) each, respectively.
Затем я должен был ввести то же самое git reset
команда еще несколько раз. Каждый раз, когда я это делал, сообщение менялось на единицу, как вы можете видеть ниже.
> git reset --hard HEAD^
HEAD is now at [...truncated...]
> git status
# On branch master
# Your branch and 'origin/master' have diverged,
# and have 3 and 3 different commit(s) each, respectively.
> git reset --hard HEAD^
HEAD is now at [...truncated...]
> git status
# On branch master
# Your branch and 'origin/master' have diverged,
# and have 2 and 3 different commit(s) each, respectively.
> git reset --hard HEAD^
HEAD is now at [...truncated...]
> git status
# On branch master
# Your branch and 'origin/master' have diverged,
# and have 1 and 3 different commit(s) each, respectively.
> git reset --hard HEAD^
HEAD is now at [...truncated...]
> git status
# On branch master
# Your branch is behind 'origin/master' by 3 commits, and can be fast-forwarded.
В этот момент я увидел, что сообщение о статусе изменилось, поэтому я попытался сделать git pull
и это, похоже, сработало:
> git pull
Updating 2df6af4..12bbd2f
Fast forward
app/views/truncated | 9 ++++++---
app/views/truncated | 13 +++++++++++++
app/views/truncated | 2 +-
3 files changed, 20 insertions(+), 4 deletions(-)
> git status
# On branch master
Короче говоря, мои команды сводились к следующему:
git reset --hard HEAD^
git reset --hard HEAD^
git reset --hard HEAD^
git reset --hard HEAD^
git pull
Вы должны изменить свою ГОЛОВУ, Не свою конечно, но мерзавца ГОЛОВУ....
Поэтому, прежде чем ответить, давайте добавим немного фона, объясняя, что это HEAD
,
First of all what is HEAD?
HEAD
это просто ссылка на текущий коммит (последний) в текущей ветке.
Там может быть только один HEAD
в любой момент времени. (без учета git worktree
)
Содержание HEAD
хранится внутри .git/HEAD
и он содержит 40 байтов SHA-1 текущего коммита.
detached HEAD
Если вы не на последнем коммите - это означает, что HEAD
указывает на предыдущий коммит в истории его называется detached HEAD
,
В командной строке это будет выглядеть так - SHA-1 вместо имени ветви, так как HEAD
не указывает на конец текущей ветви
Несколько вариантов того, как восстановить систему с отключенной HEAD:
git checkout
git checkout <commit_id>
git checkout -b <new branch> <commit_id>
git checkout HEAD~X // x is the number of commits t go back
Это извлечет новую ветку, указывающую на желаемый коммит.
Эта команда вернется к данному коммиту.
На этом этапе вы можете создать ветку и начать работать с этого момента.
# Checkout a given commit.
# Doing so will result in a `detached HEAD` which mean that the `HEAD`
# is not pointing to the latest so you will need to checkout branch
# in order to be able to update the code.
git checkout <commit-id>
# create a new branch forked to the given commit
git checkout -b <branch name>
git reflog
Вы всегда можете использовать reflog
также. git reflog
будет отображать любые изменения, которые обновили HEAD
и проверка желаемой записи reflog установит HEAD
вернуться к этому коммиту.
Каждый раз, когда ГОЛОВКА изменяется, в reflog
git reflog
git checkout HEAD@{...}
Это вернет вас к желаемой фиксации
git reset --hard <commit_id>
"Переместите" ГОЛОВУ назад к желаемому коммиту.
# This will destroy any local modifications.
# Don't do it if you have uncommitted work you want to keep.
git reset --hard 0d1d7fc32
# Alternatively, if there's work to keep:
git stash
git reset --hard 0d1d7fc32
git stash pop
# This saves the modifications, then reapplies that patch after resetting.
# You could get merge conflicts if you've modified things which were
# changed since the commit you reset to.
- Примечание: ( начиная с Git 2.7)
Вы также можете использоватьgit rebase --no-autostash
также.
git revert <sha-1>
"Отменить" данный диапазон фиксации или фиксации.
Команда сброса "отменит" любые изменения, сделанные в данном коммите.
Новый коммит с патчем отмены будет зафиксирован, в то время как оригинальный коммит останется в истории.
# add new commit with the undo of the original one.
# the <sha-1> can be any commit(s) or commit range
git revert <sha-1>
Эта схема иллюстрирует, какая команда что делает.
Как вы можете видеть там reset && checkout
изменить HEAD
,
Это можно сделать несколькими способами.
1) Прервать слияние
Если вы находитесь в промежутке между неудачным слиянием (ошибочно сделанным с неправильной ветвью) и хотите избежать слияния, вернитесь к последней ветке, как показано ниже:
git merge --abort
2) Сбросить ГОЛОВУ в удаленную ветку
Если вы работаете из удаленной ветки разработки, вы можете сбросить HEAD до последнего коммита в удаленной ветке, как показано ниже:
git reset --hard origin/develop
3) Удалить текущую ветку и снова оформить заказ из удаленного хранилища.
Учитывая, что вы работаете над веткой разработки в локальном репо, которая синхронизируется с удаленной веткой / веткой разработки, вы можете сделать следующее:
git checkout master
##to delete one branch, you need to be on another branch, otherwise you will fall with the branch :)
git branch -D develop
git checkout -b develop origin/develop
если нет конфликта и слияние завершено, то:
git reset --hard HEAD~1
если при выполнении слияния возник конфликт, то прерывание удалит вас из последних изменений слияния:
git merge --abort
или если вы хотите вернуться к определенному идентификатору фиксации.
git reset --hard <commit-id>
Вы могли бы использовать git reflog
чтобы найти предыдущий заказ. Иногда это хорошее состояние, в которое вы хотите вернуться.
В частности,
$ git reflog
$ git reset --hard HEAD@{0}
Я смог решить эту проблему с помощью одной команды, которая не включает поиск идентификатора коммита.
git reset --hard remotes/origin/HEAD
Принятый ответ не работал для меня, но эта команда достигла результатов, которые я искал.
Если вы еще не совершили это, вы можете использовать только
$ git checkout -f
Это отменит слияние (и все, что вы сделали).
Добрался до этого вопроса также, пытаясь вернуться к исходному совпадению (т. Е. NO фиксирует перед началом координат). Исследуя дальше, обнаружили, что есть reset
Команда именно для этого:
git reset --hard @{u}
Замечания: @{u}
это сокращение для origin/master
, (И, конечно, вам нужен этот удаленный репозиторий, чтобы это работало.)
Отвечая на вопрос "Отменить слияние Git, которое еще не было отправлено"
Вы можете использовать
git reset --hard HEAD~1
Рассмотрим следующую ситуацию, когда есть 2 ветки master и feature-1:
$ git log --graph --oneline --all
Сделайте слияние Git
$ git merge feature-1
$ git log --graph --oneline --all
Отменить слияние Git
$ git reset --hard HEAD~1
$ git log --graph --oneline --all
Самый простой ответ тот, который дал Одино - Велмонт
Сначала сделай git reset --merge ORIG_HEAD
Для тех, кто хочет выполнить сброс после того, как внесены изменения, сделайте это (потому что это первый пост, увиденный для всех вопросов по git reset слиянию)
git push origin HEAD --force
Это будет сброшено таким образом, что вы не сможете снова получить объединенные изменения после извлечения.
Вы можете использовать только две команды, чтобы отменить слияние или перезапустить с помощью определенного коммита:
git reset --hard commitHash
(вы должны использовать коммит, который хотите перезапустить, например, 44a587491e32eafa1638aca7738)git push origin HEAD --force
(Отправка новой локальной ветки master в origin/master)
Удачи и вперед!
Используйте эту команду, чтобы прервать слияние:
git слияние --abort
Просто чтобы посмотреть на дополнительную опцию, я в основном следовал описанной здесь модели ветвления: http://nvie.com/posts/a-successful-git-branching-model/ и поэтому объединялся с --no-ff
(нет перемотки вперед) обычно.
Я только что прочитал эту страницу, так как я случайно слил ветку тестирования вместо своей ветки релиза с мастером для развертывания (веб-сайт, мастер - это то, что работает). Ветвь тестирования объединена с двумя другими ветвями и насчитывает около шести коммитов.
Таким образом, чтобы вернуть весь коммит, мне просто нужен был один git reset --hard HEAD^
и это отменило все слияние. Так как слияния не были быстро переданы, слияние было блоком, и один шаг назад - "ветвь не слитая".
Если ваше слияние и соответствующие коммиты еще не были перенесены, вы всегда можете переключиться на другую ветку, удалить оригинальную и заново создать ее.
Например, я случайно слил разрабатываемую ветку в master и хотел отменить это. Используя следующие шаги:
git checkout develop
git branch -D master
git branch -t master origin/master
Вуаля! Мастер находится на той же стадии, что и источник, и ваше неправильно объединенное состояние стирается.
Стратегия: создать новую ветку, где все было хорошо.
Обоснование: отменить слияние сложно. Существует слишком много решений, в зависимости от многих факторов, таких как то, совершили ли вы слияние или отменили его, или были ли новые коммиты с момента вашего слияния. Кроме того, вам все еще нужно иметь относительно глубокое понимание git, чтобы адаптировать эти решения к вашему случаю. Если вы слепо следуете некоторым инструкциям, вы можете получить "пустое слияние", при котором ничто не будет объединено, и дальнейшие попытки слияния заставят Git сказать вам "Уже в курсе".
Решение:
Допустим, вы хотите объединить dev
в feature-1
,
Найдите ревизию, которую вы хотите получить слияние:
git log --oneline feature-1 a1b2c3d4 Merge branch 'dev' into 'feature-1' <-- the merge you want to undo e5f6g7h8 Fix NPE in the Zero Point Module <-- the one before the merge, you probably want this one
Проверьте это (вернитесь во времени):
git checkout e5f6g7h8
Создайте новую ветку оттуда и проверьте ее:
git checkout -b feature-1
Теперь вы можете перезапустить слияние:
Объединение:
git merge dev
Исправьте ваши конфликты слияния.
Commit:
git commit
Когда вы будете удовлетворены результатами, удалите старую ветку:
git branch --delete feature-1
Просто создайте новую ветку, а затем выберите нужные коммиты.
Это делает его более простым и безопасным после сброса, описанного во многих ответах выше
Если вам нужно решение для командной строки, я предлагаю просто ответить на вопрос MBO.
Если вы новичок, вам может понравиться графический подход:
- Подать мяч
gitk
(из командной строки или щелкните правой кнопкой мыши в браузере файлов, если у вас есть) - Вы можете легко найти коммит слияния там - первый узел сверху с двумя родителями
- Перейдите по ссылке на первого / левого родителя (та, что в вашей текущей ветке до слияния, обычно красная для меня)
- На выбранном коммите щелкните правой кнопкой мыши "Reset branch to here", выберите там hard reset
Я думаю, что вы можете сделать git rebase -i [hash] [branch_name]
где [hash]
является идентифицирующим хешем для того места, которое вы хотите перемотать назад, плюс один (или сколько коммитов вы хотите вернуться), а затем удалите строки для коммитов в редакторе, которые вам больше не нужны. Сохраните файл. Выход. Молиться. И это должно быть перемотано. Возможно, вам придется сделать git reset --hard
, но это должно быть хорошо на этом этапе. Вы также можете использовать это для извлечения определенных коммитов из стека, если вы не хотите сохранять их в своей истории, но это может оставить ваш репозиторий в состоянии, которое вы, вероятно, не хотите.
Сначала убедитесь, что вы все совершили.
Затем верните ваш репозиторий в предыдущее рабочее состояние:
$ git reset f836e4c1fa51524658b9f026eb5efa24afaf3a36
или используя
--hard
(это удалит все локальные, не зафиксированные изменения!):$ git reset f836e4c1fa51524658b9f026eb5efa24afaf3a36 --hard
Используйте хеш, который был там до вашего ошибочно объединенного коммита.
Проверьте, какие коммиты вы хотите повторно зафиксировать в верхней части предыдущей правильной версии:
$ git log 4c3e23f529b581c3cbe95350e84e66e3cb05704f commit 4c3e23f529b581c3cbe95350e84e66e3cb05704f ... commit 16b373a96b0a353f7454b141f7aa6f548c979d0a ...
Примените свои правые коммиты в верхней части правой версии вашего хранилища:
Используя cherry-pick (изменения, внесенные некоторыми существующими коммитами)
git cherry-pick ec59ab844cf504e462f011c8cc7e5667ebb2e9c7
Или путем выбора диапазона коммитов:
Сначала проверьте правильные изменения, прежде чем объединить их:
git diff 5216b24822ea1c48069f648449997879bb49c070..4c3e23f529b581c3cbe95350e84e66e3cb05704f
Сначала проверьте правильные изменения, прежде чем объединить их:
git cherry-pick 5216b24822ea1c48069f648449997879bb49c070..4c3e23f529b581c3cbe95350e84e66e3cb05704f
где это диапазон правильных коммитов, которые вы совершили (исключая ошибочно совершенное слияние).
Я знаю, что это не прямой ответ на вопрос, но, имея в виду, насколько сложна эта проблема для истории хранилища, я хотел поделиться своим опытом и сообщить всем, что создание новой ветки из последнего коммита до слияния может быть хорошей альтернативой, в основном, когда слияние уже было перенесено.