Как я могу переместить HEAD обратно в предыдущее место? (Отдельная голова) & Отменить коммиты

В Git я пытался сделать squash commit путем слияния в другой ветке, а затем сбросил HEAD на предыдущее место с помощью:

git reset origin/master

Но мне нужно выйти из этого. Как я могу переместить HEAD обратно в предыдущее место?

У меня есть фрагмент SHA-1 (23b6772) коммита, в который мне нужно его переместить. Как я могу вернуться к этой фиксации?


person timpone    schedule 29.12.2015    source источник
comment
HEAD - это просто указатель на ваше текущее местоположение (или, если быть точным, ревизию). git checkout 23b6772 должен делать.   -  person Yaroslav Admin    schedule 30.12.2015
comment
Возможный дубликат Вернуть репозиторий Git к предыдущей фиксации   -  person Andrew C    schedule 30.12.2015
comment
@YaroslavAdmin Нет, не должно не. Проверка фиксации напрямую является причиной того, что произошло отключенное состояние HEAD (поскольку ветки удаленного отслеживания не могут быть извлечены сами по себе и автоматически откладываются до фиксации, на которую они указывают, когда вы пытаетесь сделать это, как это сделал OP ) Также извините за некромантический комментарий :-) Я как бы надеюсь, что первоначальная проблема уже решена ...   -  person RomainValeri    schedule 25.03.2019


Ответы (8)


Прежде чем ответить, давайте добавим немного предыстории, объяснив, что это за 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 to 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, а проверка нужной записи в журнале рефлога вернет 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 a 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.

Введите описание изображения здесь

person CodeWizard    schedule 29.12.2015
comment
Если вы не в последней фиксации - это означает, что HEAD указывает на предыдущую фиксацию в истории, она называется отсоединенной HEAD, если эта предыдущая фиксация в истории не является вершиной другой ветки. По моему опыту, вы можете сказать, что вы отключены, если HEAD не указывает на фиксацию, на которую также указывает какая-либо ветвь. Это не относится к тегам. - person Tim; 19.04.2016
comment
Вы можете находиться в отдельной HEAD и в то же время иметь ветку с той же фиксацией, что и HEAD этой ветки. Я не понимаю ваш комментарий - person CodeWizard; 19.04.2016
comment
У меня проблемы с использованием разметки встроенного кода для заголовков :) - person jub0bs; 22.12.2016
comment
Не мог найти лучшего способа это подчеркнуть. не стесняйтесь редактировать. вы более чем добро пожаловать - person CodeWizard; 22.12.2016

Сначала reset локально:

git reset 23b6772

Чтобы убедиться, что вы на правильной позиции, проверьте:

git status

Вы увидите что-то вроде:

На главном узле ветки Ваша ветка отстает от origin / master на 17 коммитов и может быть быстро перенаправлена.

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

git push --force-with-lease // a useful command @oktober mentions in comments

Вместо этого используйте --force-with-lease из --force вызовет ошибку, если другие тем временем закрепили за собой удаленную ветку, и в этом случае вы должны сначала выполнить выборку. Дополнительная информация в этой статье.

person amuliar    schedule 10.10.2018
comment
БУДЬТЕ ПРЕКРАСНО ОСТОРОЖНЫ с git push --force. Во многих ситуациях это на какое-то время сделает вас наименее популярным человеком в команде ... - person Kay V; 11.02.2020
comment
чтобы добавить к приведенному выше примечанию, я только что наткнулся на эту цитату на about.gitlab.com/blog/2014/11/26/keeping-your-code-protected и пришлось добавить его: одна команда git push --force может легко испортить день на много людей: в репозиториях [186 Jenkins] головы веток перемотаны, чтобы указывать на более старые коммиты, и, по сути, новые коммиты были потеряны после неудачного git-push. - очень непопулярный разработчик .... - person Kay V; 14.02.2020
comment
@KayV взгляните на git push --force-with-lease (статья о Thoughtbot: thinkbot.com/blog/git -пуш-форс-с-арендой) - person oktober; 17.02.2020
comment
Полезный флаг, @oktober и хорошая статья. Спасибо, что добавили его сюда и написали мне об этом. - person Kay V; 18.02.2020
comment
Важно отметить, что ключевая деталь в этом ответе неверна; Я предложил правку. А пока: git push --force влияет на ваш пульт. Затем он не фиксирует HEAD для текущей фиксации. - person Kay V; 18.02.2020
comment
благодарю вас! это помогло мне отменить плохое слияние. поскольку слияния не реагируют на revert так же, как коммиты, я оказался в невероятно сложной ситуации. force-with-lease дал мне уверенность переписать историю ветки git, не затрагивая работу других людей. Браво! - person anon58192932; 14.03.2020

Самое быстрое решение (всего 1 шаг)

Используйте 1_

Вы увидите Switched to branch <branch_name>. Подтвердите, что это нужная ветка.


Краткое объяснение: эта команда вернет HEAD в последнее положение. См. Примечание о результатах в конце этого ответа.


Мнемоника: этот подход очень похож на использование cd - для возврата в ранее посещенный каталог. Синтаксис и применимые случаи довольно хорошо совпадают (например, это полезно, когда вы действительно хотите, чтобы HEAD вернулся туда, где он был).


Более методичное решение (2 шага, но запоминающееся)

Быстрый подход решает вопрос ОП. Но что, если ваша ситуация немного отличается: скажем, вы перезапустили Bash, а затем обнаружили, что HEAD отсоединен. В таком случае, вот 2 простых, легко запоминающихся шага.

1. Выберите нужную вам ветку

Используйте git branch -v

Вы видите список существующих местных филиалов. Выберите название ветки, которое соответствует вашим потребностям.

2. Переместите на него ГОЛОВУ.

Используйте git checkout <branch_name>

Вы увидите Switched to branch <branch_name>. Успех!


Итоги

С помощью любого метода теперь вы можете продолжать добавлять и фиксировать свою работу, как и раньше: ваши следующие изменения будут отслеживаться <branch_name>.

Обратите внимание, что и git checkout -, и git checkout <branch_name> дадут дополнительные инструкции, если вы зафиксировали изменения, когда HEAD был отключен.

person Kay V    schedule 09.08.2016
comment
Это не работает, потому что если я это сделаю (при условии, что 8acc968 - это HEAD ~ 2) git checkout 8acc968, тогда git branch -v будет MyBranch в списке ниже ... но затем git checkout MyBranch удалит мои комментарии. - person amuliar; 10.10.2018
comment
Привет, @amuliar - git checkout 8acc968 проверяет фиксацию, а не ветку. Если у MyBranch есть нужные вам коммиты, попробуйте git checkout MyBranch. Если он не содержит изменений в коммите 8acc968, вам нужно будет объединить эти изменения после проверки ветки. - person Kay V; 10.10.2018
comment
Спасибо за ответ! Я сделал git checkout, чтобы увидеть предыдущую фиксацию, и хотел вернуться к последней фиксации. Но без последнего хеша коммита я сильно заблудился. Это решение идеально подходит для моей ситуации! - person zyy; 10.02.2020

Вопрос можно прочитать так:

Я был в отключенном состоянии с HEAD на 23b6772 и набрал git reset origin/master (потому что хотел раздавить). Теперь я передумал, как мне вернуться к HEAD в 23b6772?

Прямой ответ: git reset 23b6772

Но я задал этот вопрос, потому что мне надоело набирать (копировать и вставлять) хэши коммитов или их аббревиатуры каждый раз, когда я хотел сослаться на предыдущий HEAD и искал в Google, есть ли какие-нибудь сокращения.

Оказывается, есть!

git reset - (или в моем случае git cherry-pick -)

Что, кстати, было тем же самым, что и cd - для возврата в предыдущий текущий каталог в * nix! Итак, ура, я выучил две вещи одним выстрелом.

person antak    schedule 22.07.2017

Когда вы запускаете команду git checkout commit_id, HEAD отсоединяется от 13ca5593d(say commit-id), и ветвь становится доступной дольше.

Вернитесь в предыдущее место, выполните пошаговую команду -

  1. git pull origin branch_name (скажи хозяин)
  2. git checkout branch_name
  3. git pull origin branch_name

Вы вернетесь в предыдущее место с обновленным коммитом из удаленного репозитория.

person Deepak Kumar    schedule 18.01.2019

Сегодня я по ошибке проверил фиксацию и начал работать над ней, сделав несколько коммитов в состоянии отсоединения HEAD. Затем я перешел в удаленную ветку, используя следующую команду:

git push origin HEAD: <My-remote-branch>

потом

git checkout <My-remote-branch>

потом

git pull

Наконец-то я получил все изменения в своей ветке, которые я сделал при отсоединении HEAD.

person Zaid Mirza    schedule 25.06.2019

Возможно, это не техническое решение, но оно работает. (если у кого-то из вашего товарища по команде есть такая же ветка в локальном)

Предположим, что название вашей ветки - branch-xxx.

Шаги к решению:

  • Не обновляйте и не тяните - ничего
  • Просто создайте новую ветку (branch-yyy) из branch-xxx на его компьютере.
  • Вот и все, все ваши существующие изменения будут в этой новой ветке (ветка-ггг). Вы можете продолжить работу с этой веткой.

Примечание. Опять же, это не техническое решение, но оно точно поможет.

person Sathish Kumar    schedule 09.06.2020

Переместить последние не отправленные коммиты в новую ветку

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

  1. git checkout WRONG_BRANCH
  2. git branch RIGHT_BRANCH
  3. git reset —-hard LAST_PUSHED_COMMIT
  4. git checkout RIGHT_BRANCH

На этом этапе, если вы запустите git log HEAD, вы увидите, что все ваши коммиты находятся в RIGHT_BRACH.

Данные

  • WRONG_BRANCH - это то место, где сейчас находятся ваши зафиксированные изменения (еще не опубликованные)
  • RIGHT_BRANCH - это место, где будут зафиксированы внесенные вами изменения (еще не опубликованные).
  • LAST_PUSHED_COMMIT - это место, где вы хотите восстановить WRONG_BRANCH на
person aercolino    schedule 20.05.2021