Почему git возвращает жалобу на отсутствующую опцию -m?

Итак, я работаю над проектом с другими людьми, и там работают несколько вилок-гитов. Кто-то просто исправит проблему, и я слился с его вилкой, но потом понял, что могу найти лучшее решение. Я хочу отменить сделанный мной коммит. Я попытался сделать это с помощью git revert HEAD, но он дал мне эту ошибку:

fatal: Commit <SHA1> is a merge but no -m option was given.

Что это значит? Когда я слился и сделал это, я использовал параметр -m, чтобы сказать "Слияние с < имя пользователя > ".

Что я здесь делаю неправильно?

Ответ 1

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

Если вы хотите отменить фиксацию слияния, вы должны указать, какой родительский элемент слияния вы хотите рассматривать как основную соединительную линию, то есть то, к чему вы хотите вернуться.

Часто это будет родительский номер один, например, если вы были на master и сделал git merge unwanted, а затем решил вернуть слияние unwanted. Первым родителем будет ваша ветвь pre-merge master, а второй родитель будет концом unwanted.

В этом случае вы можете сделать:

git revert -m 1 HEAD

Ответ 2

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

$ git lola
*   2582152 (HEAD, master) Merge branch 'otherguy'
|\  
| * c7256de (otherguy) bar
* | b7e7176 baz
|/  
* 9968f79 foo

Примечание: git lola - нестандартный, но полезный псевдоним.

Нет кубиков с git revert:

$ git revert HEAD
fatal: Commit 2582152... is a merge but no -m option was given.

Чарльз Бейли дал отличный ответ, как обычно. Используя git revert, как в

$ git revert --no-edit -m 1 HEAD
[master e900aad] Revert "Merge branch 'otherguy'"
 0 files changed, 0 insertions(+), 0 deletions(-)
 delete mode 100644 bar

эффективно удаляет bar и создает историю

$ git lola
* e900aad (HEAD, master) Revert "Merge branch 'otherguy'"
*   2582152 Merge branch 'otherguy'
|\  
| * c7256de (otherguy) bar
* | b7e7176 baz
|/  
* 9968f79 foo

Но я подозреваю, что вы хотите выбросить слияние:

$ git reset --hard HEAD^
HEAD is now at b7e7176 baz

$ git lola
* b7e7176 (HEAD, master) baz
| * c7256de (otherguy) bar
|/  
* 9968f79 foo

Как описано в git rev-parse manual

<rev>^, например. HEAD ^, v1.5.1^0
Суффикс ^ к параметру ревизии означает первый родитель этого объекта commit. ^<n> означает, что n-й родительский элемент (т.е. <rev>^ эквивалентен <rev>^1). В качестве специального правила <rev>^0 означает сам commit и используется, когда <rev> - это имя объекта тега, относящегося к объекту фиксации.

поэтому перед вызовом git reset, HEAD^ (или HEAD^1) был b7e7176, а HEAD^2 был c7256de, то есть соответственно первый и второй родители слияния.

Будьте осторожны с git reset --hard, потому что это может разрушить работу.

Ответ 3

У меня была эта проблема, решение заключалось в том, чтобы посмотреть на график фиксации (используя gitk) и увидеть, что у меня было следующее:

*   commit I want to cherry-pick (x)
|\  
| * branch I want to cherry-pick to (y)
* | 
|/  
* common parent (x)

Теперь я понимаю, что хочу сделать

git cherry-pick -m 2 mycommitsha

Это связано с тем, что -m 1 будет сливаться на основе общего родителя, где в качестве -m 2 объединяется на основе ветки y, то есть той, которую я хочу, чтобы выбрать cherry-pick.