Отмените Git-слияние, которое еще не было перенесено

3252

В моей главной ветке я сделал 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.

Я не хочу, чтобы моя ветка была впереди по количеству попыток. Как мне вернуться к этой точке?

  • 3
    Если вам нужно сохранить историю, другими словами, есть изменение, которое кто-либо когда-либо извлек из вас, или вы куда-то его подтолкнули, используйте решение в ответе Юрия Ушакова ниже!
  • 5
    Пожалуйста, отмените выбор текущего победного ответа, это небезопасно (как отмечали многие), хотя все еще набирает голоса. Для меня «MBO» выглядит лучше, хотя у него гораздо меньше очков.
Показать ещё 5 комментариев
Теги:
git-merge
undo

28 ответов

3406
Лучший ответ

С помощью 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

Сбрасывает индекс и обновляет файлы в рабочем дереве, которые отличаются между <commit> и HEAD, но сохраняет те, которые отличаются между индексом и рабочим деревом (т.е. С изменениями, которые не были добавлены).

  • 113
    Я не думаю, что это будет (всегда?) Работать - «один перед слиянием» будет самым последним коммитом, который был объединен из другой ветки - это не будет самый последний коммит в текущей ветке , Правильно? (Это может быть просто результатом того, что git log выбирает для показа по умолчанию - возможно, есть другой вывод git log или для этого можно использовать git reflog )
  • 5
    Я думаю, это может зависеть от того, слите ли вы сквош
Показать ещё 27 комментариев
1387

Предполагая, что ваш локальный мастер не опережал начало/мастер, вы должны иметь возможность делать

git reset --hard origin/master

Затем ваша локальная ветвь master должна выглядеть идентично origin/master.

  • 62
    @ На самом деле это не самый лучший ответ. Возможно, что origin / master может быть впереди вашего локального master как раз перед слиянием некоторыми коммитами, в этом случае это может не дать желаемых результатов.
  • 12
    @ dhruva-sagar Да, но пока мерзавец не говорит, что ты позади, и ты не получаешь, у тебя все будет хорошо.
Показать ещё 9 комментариев
1047

Смотрите глава 4 в книге Git и исходный пост Линусом Торвальдсом.

Чтобы отменить слияние , которое уже было нажато:

git revert -m 1 commit_hash

Обязательно верните возврат, если вы снова завершаете ветку, как сказал Линус.

  • 94
    ^ - Единственно правильный ответ здесь, как отменить слияние, не нарушая историю. Это важно, если вы работаете с общим репо.
  • 0
    Почему этот ответ не имеет больше голосов?
Показать ещё 16 комментариев
838

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

git reset --merge ORIG_HEAD

Ссылка ref ORIG_HEAD будет указывать на первоначальную фиксацию до слияния.

(Параметр --merge не имеет ничего общего с слиянием. Это просто как git reset --hard ORIG_HEAD, но безопаснее, так как он не касается незафиксированных изменений.)

  • 33
    Да, это самый простой способ. Интересно, почему у него так мало голосов по сравнению с другими ответами.
  • 14
    Если с тех пор вы испортили свое рабочее дерево, git reset --merge ORIG_HEAD сохраняет эти изменения.
Показать ещё 18 комментариев
330

С более новыми версиями Git, если вы еще не завершили слияние, и у вас есть конфликт слияния, вы можете просто сделать:

git merge --abort

От man git merge:

[Это] можно запустить только после того, как слияние привело к конфликтам. git merge --abort прервет процесс слияния и попытается восстановить состояние предварительного слияния.

  • 0
    Его слияние совершено, но не выдвинуто (см. Заголовок), он уже слит, ваша команда работает только тогда, когда он все еще находится в середине слияния
108

Вы должны reset выполнить предыдущую фиксацию. Это должно работать:

git reset --hard HEAD^

Или даже HEAD^^, чтобы вернуться, чтобы вернуть фиксацию. Вы всегда можете дать полную ссылку на SHA, если не уверены, сколько шагов вы должны предпринять.

Если у вас возникли проблемы, и ваша главная ветвь не имела локальных изменений, вы можете reset до origin/master.

  • 5
    Лучший ответ IMHO, включает в себя собственный ОП (при условии, что только один шаг для возврата, что, как кажется, имеет место в Q), а также ярлык randomguy3 (который работает, когда «ваша основная ветвь не имела локальных изменений»). «)
  • 4
    Вы комментаторы, @Inger и @Konstantin, почему? Вы пришли сюда после того, как мой ответ был создан, и это более правильно. Просто подняться на ГОЛОВУ на один шаг часто неправильно, и вам действительно нужно посчитать, как далеко вы должны пройти. Git уже устанавливает ORIG_HEAD для вас, почему бы не использовать его?
Показать ещё 3 комментария
76

В последнее время я использовал 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

Первая строка указывает, что произошло слияние. Вторая строка - это время до моего слияния. Я просто git reset --hard 43b6032, чтобы заставить эту ветвь отслеживать до слияния и переноса.

  • 0
    Отличный ответ, спасибо! Нужно было отменить слияние, но другие ответы только испортили его, используя reflog чтобы получить SHA и передать его в git reset .
49

С помощью современных Git вы можете:

git merge --abort

Более старый синтаксис:

git reset --merge

Старая школа:

git reset --hard

Но на самом деле стоит заметить, что git merge --abort эквивалентен только git reset --merge, если присутствует MERGE_HEAD. Это можно прочитать в справке Git для команды merge.

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 гораздо более мощным и полезным в повседневной работе, так что тот, который я всегда использую.

  • 0
    Отлично сработало для меня. Любой другой пост говорит, что это так сложно, но это именно то, что ожидается. Я полагаю, это сработало только потому, что были конфликты, что не совсем отвечает на первоначальный вопрос.
  • 0
    Этот ответ не фокусируется на ситуации ОП и оставляет важный контекст.
37

Хорошо, ответы, которые дали мне другие люди, были близки, но это не сработало. Вот что я сделал.

Выполнение этого...

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
  • 18
    или вы могли бы использовать HEAD^^^^
  • 16
    может быть, даже сброс на origin/master ;)
21

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

В частности,

$ git reflog
$ git reset --hard HEAD@{0}
  • 1
    Спасибо! Вы сэкономили полдня моей работы. Однако я не мог выйти из режима reflog ни одной командой.
  • 1
    @Katarzyna используйте клавишу «q» для выхода из reflog
13

Если вы еще не сделали этого, вы можете использовать

$ git checkout -f

Отменит слияние (и все, что вы сделали).

  • 0
    Попробовал это, и это фактически увеличило количество коммитов, которые опередил мой местный филиал.
11

Получил этот вопрос, также обратившись к тому, чтобы вернуться к совпадению с началом (т.е. НЕТ берет начало до начала). Изучая далее, нашел там команду reset для этого:

git reset --hard @{u}

Примечание: @{u} является сокращением для origin/master. (И, конечно же, вам нужен этот удаленный репозиторий для этого.)

10

Вы можете использовать только две команды для возврата слияния или перезапуска с помощью определенной фиксации:

  • git reset --hard commitHash (вы должны использовать фиксацию, которую хотите перезапустить, например, 44a587491e32eafa1638aca7738)
  • git push origin HEAD --force (Отправка новой локальной ведущей ветки в начало/мастер)

Удачи и вперед!

10

Просто для дополнительной опции, чтобы посмотреть, я в основном следовал описанной здесь модели ветвления: http://nvie.com/posts/a-successful-git-branching-model/ и, как таковые, слияние с --no-ff (без быстрой перемотки вперед) обычно.

Я просто прочитал эту страницу, поскольку случайно случайно объединил ветку тестирования вместо моей ветки релиза с мастером для развертывания (веб-сайт, мастер - это то, что является живым). У тестирующей ветки есть две другие ветки, объединенные с ней и насчитывающие около шести коммитов.

Итак, чтобы вернуть всю транзакцию, мне просто понадобился один git reset --hard HEAD^, и он вернул все слияние. Поскольку слияния не были быстро перенаправлены, слияние было блоком и одним шагом назад является "ветвь не объединена".

7

Самый простой ответ - тот, который дается odinho - Velmont

Сначала сделайте git reset --merge ORIG_HEAD

Для тех, кто смотрит на reset после того, как изменения нажаты, сделайте это (Потому что это первое сообщение, которое было обнаружено для любых вопросов о слиянии git reset)

git push origin HEAD --force

Это будет reset таким образом, что вы не получите объединенные изменения обратно после нажатия.

6

Я смог решить эту проблему с помощью одной команды, которая не включает поиск идентификатора фиксации.

git reset --hard remotes/origin/HEAD

Принятый ответ не работал для меня, но эта команда достигла результатов, которые я искал.

  • 0
    Именно так! Сбрасывает ваши изменения в ГОЛОВУ ветки! Не делать по одному
5

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

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

git checkout develop
git branch -D master
git branch -t master origin/master

Voila! Мастер находится на той же стадии, что и происхождение, и ваше неправильно объединенное состояние стирается.

  • 1
    Примечание. Это не только отменяет слияние, но и любые локальные коммиты, которые были сделаны с момента последнего нажатия на источник.
4

Стратегия: Создайте новую ветку, откуда все было хорошо.

Обоснование: Возвращение слияния сложно. Слишком много решений, в зависимости от многих факторов, таких как то, что вы совершили или нажали ваше слияние, или были новые коммиты с момента вашего слияния. Также вам необходимо иметь относительно глубокое понимание 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

4

Если вам требуется решение из командной строки, я предлагаю просто пойти с ответом MBO.

Если вы новичок, вам может понравиться графический подход:

  • Отключить gitk (из командной строки или щелкнуть правой кнопкой мыши в браузере файлов, если у вас есть)
  • Вы можете легко определить фиксацию слияния - первый node сверху с двумя родителями
  • Следуйте ссылке на первый/левый родитель (тот, который находится в вашей текущей ветке до слияния, обычно красный для меня)
  • В выбранном коммите щелкните правой кнопкой мыши раздел "Reset", выберите жесткий reset там
2

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

1

Если вы совершили слияние:

git reset HEAD~1
# Make sure what you are reverting is in fact the merge files
git add .
git reset --hard
1
  • Во-первых, убедитесь, что вы все сделали.

  • Затем reset ваш репозиторий в предыдущее рабочее состояние:

    $ git reset f836e4c1fa51524658b9f026eb5efa24afaf3a36
    

    или используя --hard (, это приведет к удалению всех локальных, не зафиксированных изменений!):

    $ git reset f836e4c1fa51524658b9f026eb5efa24afaf3a36 --hard
    

    Используйте хеш, который был там до того, как вы неправильно слили фиксацию.

  • Проверьте, какие коммиты вы хотите перехватить в верхней части предыдущей правильной версии:

    $ git log 4c3e23f529b581c3cbe95350e84e66e3cb05704f
    
    commit 4c3e23f529b581c3cbe95350e84e66e3cb05704f
    
    ...
    
    commit 16b373a96b0a353f7454b141f7aa6f548c979d0a
    
    ...
    
  • Примените свои права на верхнюю часть нужной версии вашего репозитория:

    • Используя вишневый выбор (изменения, внесенные некоторыми существующими коммитами)

          git cherry-pick ec59ab844cf504e462f011c8cc7e5667ebb2e9c7
      
    • Или путем выбора вишней диапазона значений:

      • Сначала проверьте правильные изменения перед их объединением:

        git diff 5216b24822ea1c48069f648449997879bb49c070..4c3e23f529b581c3cbe95350e84e66e3cb05704f
        
      • Сначала проверьте правильные изменения перед их объединением:

        git cherry-pick 5216b24822ea1c48069f648449997879bb49c070..4c3e23f529b581c3cbe95350e84e66e3cb05704f
        

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

1

Я думаю, что вы можете сделать git rebase -i [hash] [branch_name], где [hash] - это идентификационный хеш, если вы еще хотите перемотать назад, плюс один (или сколько бы то ни было коммитов, которые вы хотите отправить), а затем удалите строки для коммитов в редактор, который вам больше не нужен. Сохраните файл. Выход. Молиться. И он должен быть перемотан. Возможно, вам придется сделать git reset --hard, но в этот момент это должно быть хорошо. Вы также можете использовать это, чтобы вытащить определенные коммиты из стека, если вы не хотите сохранять их в своей истории, но это может оставить ваш репозиторий в состоянии, которое вам, вероятно, не нужно.

0

Если вы находитесь в процессе слияния, вы всегда можете прервать его git merge --abort

0

В этом случае вы захотите сбросить свою ветку с помощью git reset --hard <branch_name>. Если вы хотите сохранить свои изменения перед их реестром, обязательно создайте новую ветку и git checkout <branch_name>.

Вы можете сбросить состояние до определенного коммита с помощью git reset --hard <commit_id>.

Если изменения были git revert <branch_name> вы можете использовать git revert <branch_name> вместо git revert <branch_name>. Обязательно ознакомьтесь с тем, как использовать git revert и git checkout в других сценариях.

0

Самый простой из простейших шансов, гораздо проще, чем что-либо, сказанное здесь:

Удалите локальную ветвь (локальную, а не удаленную) и потяните ее снова. Таким образом, вы отмените изменения в своей основной ветке, и на кого-либо повлияет изменение, которое вы не хотите нажимать. Запустите его.

0

Если вы заметили, что вам нужно вернуться сразу после слияния, и после попытки слияния вы ничего не сделали, вы можете просто выполнить эту команду: git reset --hard HEAD@{1}.

По существу, ваше слияние sha будет указывать на HEAD@{0}, если после слияния ничего не было зафиксировано, и поэтому HEAD@{1} будет предыдущей точкой перед слиянием.

-13

Вы можете использовать команду git - reset.

git - reset - Reset текущий HEAD для

указанное состояние. git Reset [--mixed |

- мягкий | --hard | --merge] [-q] [] git Reset [-q] []

[-]... git Reset --patch

[] [-] [...]

GIT-Reset

  • 1
    Я попытался git reset git reset --merge и git reset --hard , но все равно получаю то же сообщение о том, что 5 коммитов впереди origin / master.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню