Как я могу переместить ГОЛОВУ назад в предыдущее место? (Отдельная голова) & Отменить фиксацию

179

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

git reset origin/master

Но мне нужно выйти из этого. Как я могу переместить ГОЛОВУ назад в предыдущее место?

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

timpone
источник
12
HEAD - это просто указатель на ваше текущее местоположение (или, если быть точным, ревизия). git checkout 23b6772стоит сделать.
Ярослав Админ
Возможный дубликат Revert Git repo для предыдущего коммита
Эндрю С
1
@YaroslavAdmin Нет , это должно не . Извлечение коммита напрямую - причина, по которой произошло отключенное состояние HEAD (поскольку ветви удаленного отслеживания не могут быть извлечены сами и автоматически переносятся на коммит, на который они указывают, когда вы пытаетесь сделать это, как это делал OP) Также, извините за некромантику комментарий :-) Я вроде надеюсь, что первоначальная проблема уже решена ...
RomainValeri

Ответы:

398

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

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

CodeWizard
источник
Если вы не используете последний коммит - это означает, что HEAD указывает на предыдущий коммит в истории, он называется отсоединенным HEAD, если только этот предыдущий коммит в истории не является вершиной другой ветви. По моему опыту, вы можете сказать, что вы отстранены, если HEAD не указывает на коммит, на который также указывает какая-либо ветка. Это не относится к тегам.
Тим
Вы можете находиться в отдельном HEAD и в то же время иметь ветку с тем же коммитом, что и в HEAD этой ветки. Я не понимаю ваш комментарий
CodeWizard
3
У меня проблемы с использованием встроенной разметки кода для заголовков :)
jub0bs
Не смог найти лучшего способа подчеркнуть это. не стесняйтесь редактировать. Вы более чем рады
CodeWizard
22

Делать

git reset 23b6772

Чтобы увидеть, если вы находитесь в правильном положении:

git status

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

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

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

git push --force-with-lease // a useful command @oktober mentions in comments
amuliar
источник
1
Будьте ВНИМАТЕЛЬНО ОСТОРОЖНЫ с git push --force. Во многих ситуациях это сделает вас на некоторое время наименее популярным человеком в команде ...
Kay V
Чтобы добавить к вышеупомянутой заметке, я только что натолкнулся на эту цитату на about.gitlab.com/blog/2014/11/26/keeping-your-code-protected и должен был добавить ее: «Одна команда git push --force может легко испортить день для многих людей: у репозиториев [186 Jenkins] главы ветвей переписаны, чтобы указывать на более старые коммиты, и фактически более новые коммиты были неуместны после плохого git-push ». - очень непопулярный разработчик ....
Кей V
2
@KayV взглянуть git push --force-with-lease(Thoughtbot статьи: thoughtbot.com/blog/git-push-force-with-lease )
Oktober
1
Полезный флаг, @ октобер, и хорошая статья. Спасибо, что добавили это здесь и обменивались мнениями об этом.
Кей V
1
Спасибо! это помогло мне избежать неудачного слияния. так как слияния не реагируют так же, revertкак коммиты, я оказался в невероятно сложной ситуации. force-with-leaseдал мне уверенность, чтобы переписать историю мерзавцев ветви, не затрагивая работу других людей. Браво!
anon58192932
11

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

использование git checkout -

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


Краткое объяснение: эта команда вернет ГОЛОВУ обратно в последнюю позицию. См. Примечание о результатах в конце этого ответа.


Мнемоника: этот подход очень похож на использование 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 был отсоединен.

Кей V
источник
Это не работает , потому что если я ( в предположении , что 8acc968 является ГОЛОВА ~ 2) , git checkout 8acc968то git branch -vесть MyBranchв списке ниже ... но затем git checkout MyBranchудаляет мои комментарии.
amuliar
Привет @amuliar - git checkout 8acc968проверю коммит, а не ветку. Если MyBranchесть коммиты, которые вы хотите, попробуйте git checkout MyBranch. Если он не содержит изменений в коммите 8acc968, вам необходимо объединить эти изменения после проверки ветви.
Кей V
Спасибо за ответ! Я сделал, git checkoutчтобы увидеть предыдущий коммит и хотел вернуться к последнему коммиту. Но без последнего коммита я был в значительной степени потерян. Это решение идеально подходит для моей ситуации!
ZYY
4

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

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

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

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

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

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

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

antak
источник
0

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

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

  1. git pull origin branch_name (скажи мастер)
  2. git checkout branch_name
  3. git pull origin branch_name

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

Дипак Кумар
источник
0

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

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

затем

git checkout <My-remote-branch>

затем

git pull

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

Зайд Мирза
источник
0

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

Давайте предположим , что ваше имя ветви в качестве филиала-ххх .

Шаги для решения:

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

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

Сатиш Кумар
источник