Как мне вернуть репозиторий Git к предыдущему коммиту?

7630

Как мне вернуться из моего текущего состояния к снимку, сделанному при определенной фиксации?

Если я это сделаю git log, то я получу следующий вывод:

$ git log
commit a867b4af366350be2e7c21b8de9cc6504678a61b`
Author: Me <me@me.com>
Date:   Thu Nov 4 18:59:41 2010 -0400

blah blah blah...

commit 25eee4caef46ae64aa08e8ab3f988bc917ee1ce4
Author: Me <me@me.com>
Date:   Thu Nov 4 05:13:39 2010 -0400

more blah blah blah...

commit 0766c053c0ea2035e90f504928f8df3c9363b8bd
Author: Me <me@me.com>
Date:   Thu Nov 4 00:55:06 2010 -0400

And yet more blah blah...

commit 0d1d7fc32e5a947fbd92ee598033d85bfc445a50
Author: Me <me@me.com>
Date:   Wed Nov 3 23:56:08 2010 -0400

Yep, more blah blah.

Как мне вернуться к коммиту с 3 ноября, т.е. коммит 0d1d7fc?

Сумасшедший серб
источник
116
Вот очень четкий и подробный пост об отмене вещей в git, прямо из Github.
Нобита
3
Связанный: Откат к старому коммиту Git в публичном репо . Обратите внимание, что этот вопрос добавляет ограничение, что репо является публичным.
58
Я люблю git, но тот факт, что есть 35 ответов на что-то, что должно быть невероятно простым, обнажает огромную проблему с git. Или это документы?
The Muffin Man
2
Как язык «заманивает в ловушку» в использовании слова « возвратиться» как разговорный, означающий « сбросить», даже не упомянутый здесь ??? 6594 голосов до сих пор и не редактировать таким образом, чтобы подчеркнуть разницу? Не было бы более запутанным ссылаться на «сохранение файла» здесь с выражением «
фиксация

Ответы:

9733

Это во многом зависит от того, что вы подразумеваете под «возвратом».

Временно переключиться на другой коммит

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

# This will detach your HEAD, that is, leave you with no branch checked out:
git checkout 0d1d7fc32

Или, если вы хотите делать коммиты, пока вы там, идите и создайте новую ветку, пока вы там:

git checkout -b old-state 0d1d7fc32

Чтобы вернуться туда, где вы были, просто проверьте ветку, на которой вы были снова. (Если вы внесли изменения, как всегда при переключении веток, вам придется обращаться с ними соответствующим образом. Вы можете сбросить их, чтобы выбросить; вы можете спрятать, оформить заказ, спрятать всплывающее окно, чтобы взять их с собой; вы можете зафиксировать их там на ветку, если там нужна ветка.)

Трудно удалить неопубликованные коммиты

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

# 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 возврат имеет очень специфическое значение: создайте коммит с обратным патчем, чтобы отменить его. Таким образом, вы не переписываете историю.

# This will create three separate revert commits:
git revert a867b4af 25eee4ca 0766c053

# It also takes ranges. This will revert the last two commits:
git revert HEAD~2..HEAD

#Similarly, you can revert a range of commits using commit hashes:
git revert a867b4af..0766c053 

# Reverting a merge commit
git revert -m 1 <merge_commit_sha>

# To get just one, you could use `rebase -i` to squash them afterwards
# Or, you could do it manually (be sure to do this at top level of the repo)
# get your index and work tree into the desired state, without changing HEAD:
git checkout 0d1d7fc32 .

# Then commit. Be sure and write a good message describing what you just did
git commit

На самом деле git-revertman-страница охватывает многое из этого в своем описании. Еще одна полезная ссылка - это раздел git-scm.com, где обсуждается git-revert .

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

Вы также можете найти этот ответ полезным в этом случае:
Как переместить HEAD обратно в предыдущее место? (Отдельная голова)

Cascabel
источник
118
@ Комментарий Рода на git revert HEAD~3как лучший ват , чтобы вернуться 3фиксациями является важным утром условности.
Новая Александрия
20
Не могли бы вы написать весь номер? как:git reset --hard 0d1d7fc32e5a947fbd92ee598033d85bfc445a50
Spoeken
16
@MathiasMadsenStav Да, вы можете, конечно, указать коммиты по полному SHA1. Я использовал сокращенные хэши, чтобы сделать ответ более читабельным, и вы также склонны использовать их, если вы печатаете. Если вы копируете и вставляете, обязательно используйте полный хеш. См. Определение ревизий в man git rev-parse для полного описания того, как вы можете называть коммиты.
Каскабель
59
Вы можете использовать git revert --no-commit hash1 hash2 ...и после этого просто фиксировать каждый git commit -m "Message"
реверт
6
Что означает «публиковать» в этом контексте?
Howiecamp
1852

Здесь много сложных и опасных ответов, но на самом деле это просто:

git revert --no-commit 0766c053..HEAD
git commit

Это вернет все из HEAD обратно в хеш коммита, что означает, что он будет воссоздавать это состояние коммита в рабочем дереве, как если бы каждый коммит с тех пор был возвращен. Затем вы можете зафиксировать текущее дерево, и оно создаст совершенно новый коммит, по существу эквивалентный коммиту, к которому вы «вернулись».

( --no-commitФлаг позволяет git отменять все коммиты одновременно, иначе вам будет предложено сообщение для каждого коммита в диапазоне, засоряя вашу историю ненужными новыми коммитами.)

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

Ярина
источник
23
Если вы действительно хотите иметь отдельные коммиты (вместо того, чтобы возвращать все с помощью одного большого коммита), тогда вы можете перейти --no-editвместо --no-commit, чтобы вам не приходилось редактировать сообщение о коммите для каждой реверсии.
88
Если один из коммитов между 0766c053..HEAD является слиянием, то возникнет ошибка (не указывать -m). Это может помочь тем, кто столкнулся с этим: stackoverflow.com/questions/5970889/…
timhc22
7
Чтобы увидеть различия, прежде чем совершать использование git diff --cached.
Джон Эрк
21
$ git revert --no-commit 53742ae..HEADвозвращаетсяfatal: empty commit set passed
Alex G
10
@AlexG потому что вам нужно ввести хеш перед тем, к которому вы хотите вернуться. В моем случае хэши были похожи на: 81bcc9e HEAD{0}; e475924 HEAD{1}, ...(от git reflog), и я хотел отменить то, что я сделал 81bcc9e, затем я должен был это сделатьgit revert e475924..HEAD
EpicPandaForce
1611

Мошенник кодер?

Работаете самостоятельно и просто хотите, чтобы это работало? Следуйте приведенным ниже инструкциям, они надежно работали для меня и многих других на протяжении многих лет.

Работаете с другими? Git это сложно. Прочитайте комментарии ниже этого ответа, прежде чем делать что-то необдуманное.

Возврат рабочей копии в самый последний коммит

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

git reset --hard HEAD

где HEAD - последний коммит в вашей текущей ветке

Возврат рабочей копии в более старый коммит

Чтобы вернуться к коммиту, который старше самого последнего коммита:

# Resets index to former commit; replace '56e05fced' with your commit code
git reset 56e05fced 

# Moves pointer back to previous HEAD
git reset --soft HEAD@{1}

git commit -m "Revert to 56e05fced"

# Updates working copy to reflect the new commit
git reset --hard

Кредиты переходят к аналогичному вопросу переполнения стека. Вернуть ли к фиксации хэш SHA в Git? ,

boulder_ruby
источник
33
Я сделал это, но потом я не смог зафиксировать и отправить в удаленный репозиторий. Я хочу, чтобы конкретный коммит стал ГОЛОВНЫМ ...
Леннон
7
Это означает, что вы уже выдвинули коммиты, которые хотите вернуть. Это может создать много проблем людям, которые проверили ваш код и работают над ним. Так как они не могут применить ваш коммит плавно к своим. В таком случае лучше сделать git revert. Если вы единственный, кто использует репо. Сделай git push -f (но подумай дважды, прежде чем делать это)
vinothkr
6
Я как раз и хочу отметить, что в качестве альтернативы для мягкого решения сброса, вместо того , чтобы делать смешанный сброс первым и жесткий сброс последним, вы можете сделать жесткий сброс первым, следующим образом : git reset --hard 56e05fc; git reset --soft HEAD@{1}; git commit.
5
@nuton linus, создатель git, критиковал его за то, что он слишком сложен. Он официально заявляет, что он был «в шоке», этот мерзавец стал настолько популярным, учитывая его сложность
boulder_ruby
5
@boulder_ruby Я думаю, вы имели в виду, что Линус Торвальдс был создателем git. Но я думаю, что Линус Полинг, вероятно, согласится, что мерзавец сложен.
Suncat2000
215

Лучший вариант для меня и, вероятно, для других - это опция сброса Git:

git reset --hard <commidId> && git clean -f

Это был лучший вариант для меня! Это просто, быстро и эффективно!


** Примечание: ** Как уже упоминалось в комментариях, не делайте этого, если вы делитесь своей веткой с другими людьми, у которых есть копии старых коммитов.

Также из комментариев, если вы хотите менее «баллистический» метод, вы можете использовать

git clean -i
Pogrindis
источник
37
Обязательное предупреждение: не делайте этого, если вы делитесь своей веткой с другими людьми, у которых есть копии старых коммитов, потому что при таком жестком сбросе им придется заново синхронизировать свою работу с новой веткой сброса. Для решения, которое подробно объясняет, как безопасно вернуть коммиты без потери работы с полным сбросом, см. Этот ответ .
7
Второе предупреждение @ Cupcake ... быть в курсе последствий. Обратите внимание, однако, что если вам действительно нужно, чтобы эти коммиты исчезли из истории навсегда, этот метод reset + clean сделает это, и вам нужно будет принудительно отправить ваши измененные ветви обратно на любой пульт дистанционного управления.
ashnazg
5
мерзавец чистого -f ОПАсНО
Тиши
2
Это устанавливает заголовок моей локальной копии на желаемый коммит. Но тогда я не могу выдвинуть какие-либо изменения, потому что это позади пульта. И если я вытащу из удаленного узла, он снова окажется там, где он был при последнем коммите в удаленной ветви. Как полностью стереть (повсюду) несколько подтверждений в моей локальной копии, которые были отправлены?
Ade
2
@Ade .. Вы можете использовать git push -fфлаг .. Но будьте осторожны, он переопределит удаленный .. Убедитесь, что вы знаете, что вы хотите сделать.
Погриндис
176

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

Эта схема иллюстрирует, какая команда что делает. Как вы можете видеть там, reset && checkoutизмените HEAD.

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

CodeWizard
источник
6
Отличная подсказка git reflog, это именно то, что мне было нужно
smac89
4
Ой! Все это кажется очень сложным ... разве нет простой команды, которая просто делает шаг назад в процессе? Как перейти с версии 1.1 в вашем проекте обратно на версию 1.0? Я ожидаю что-то вроде: git stepback_one_commit или что-то ....
Kokodoko
есть: git reset HEAD^--hard`
CodeWizard
3
@Kokodoko Да, это ужасно сложно ... и прекрасный пример того, как мало внимания уделяют экспертам только начинающим людям. Пожалуйста, обратитесь к моему ответу здесь, а также к книге, которую я рекомендую в ней. Git - это НЕ то, что вы можете подобрать интуитивно. И я могу быть абсолютно уверен, что CodeWizard этого не сделал.
Майк Грызун
145

Если вы хотите «отменить», стереть последнее сообщение о коммите и вернуть измененные файлы в промежуточный режим, вы должны использовать команду:

git reset --soft HEAD~1
  • --softуказывает, что незафиксированные файлы должны быть сохранены как рабочие файлы, в отличие от --hardкоторых они будут отброшены.
  • HEAD~1последний коммит Если вы хотите откатить 3 коммита, вы можете использовать HEAD~3. Если вы хотите выполнить откат до определенного номера ревизии, вы также можете сделать это, используя его хэш SHA.

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

Источник: http://nakkaya.com/2009/09/24/git-delete-last-commit/

Стивен Остермиллер
источник
3
Это мягко и мягко: без риска, если вы не подтолкнули свою работу
nilsM
124

Вы можете сделать это с помощью следующих двух команд:

git reset --hard [previous Commit SHA id here]
git push origin [branch Name] -f

Это удалит ваш предыдущий коммит Git.

Если вы хотите сохранить свои изменения, вы также можете использовать:

git reset --soft [previous Commit SHA id here]

Тогда это сохранит ваши изменения.

Киран Богра
источник
2
Я пытался полдюжины ответов в этом посте, пока не добрался до этого ... все эти другие, мой git config постоянно выдавал ошибку при попытке нажать. Этот ответ сработал. Спасибо!
Джин Бо
Для меня одной деталью было то, что я потерял различия ... которые я хотел сохранить, чтобы увидеть, что я сделал в коммите, который не сработал. Поэтому в следующий раз я просто сохраню эти данные перед выполнением этой команды сброса
Gene Bo
1
Для меня это был единственный способ отменить неудачное слияние, в этом случае возврат не сработал. Спасибо!
Дейв Коул
Лучший ответ. Спасибо
Имран Поллоб
Лучший ответ, спасибо.
user1394
114

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

git add . && git checkout master -f

Краткое описание:

  • Это НЕ будет создавать какие-либо коммиты, как это git revertделает.
  • Это НЕ отсоединит вашу ГОЛОВУ, как git checkout <commithashcode>делает.
  • Он отменит все ваши локальные изменения и УДАЛИТ все добавленные файлы с момента последнего коммита в ветке.
  • Он работает только с именами веток, поэтому таким образом вы можете вернуться только к последнему коммиту в ветке.

Я нашел гораздо более удобный и простой способ для достижения результатов выше:

git add . && git reset --hard HEAD

где HEAD указывает на последний коммит в текущей ветке.

Это тот же код, что и предложенный boulder_ruby, но я добавил git add .ранее, git reset --hard HEADчтобы стереть все новые файлы, созданные со времени последнего коммита, так как большинство людей ожидают, что я вернусь к последнему коммиту.

Роман Миненок
источник
83

Хорошо, вернуться к предыдущему коммиту в Git довольно просто ...

Вернуть обратно без сохранения изменений:

git reset --hard <commit>

Вернитесь назад с сохранением изменений:

git reset --soft <commit>

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

Но, как вы видите, различие заключается в использовании двух флагов --softи --hard, по умолчанию, git resetиспользовании --softфлага, но всегда полезно использовать флаг, я объясняю каждый флаг:


--мягкий

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


--жесткий

Будьте осторожны с этим флагом. Он сбрасывает рабочее дерево и все изменения в отслеживаемых файлах и все пропадет!


Я также создал изображение ниже, которое может случиться в реальной жизни, работая с Git:

Git сбросить на коммит

Алиреза
источник
По умолчанию git resetэто git reset --mixedне так git reset --soft. Пожалуйста, проверьте, в чем разница между git reset --mixed, --soft и --hard? и на простом английском языке, что делает «git reset»?
Фабио говорит восстановить Монику
70

Предполагая, что вы говорите о master и о соответствующей ветке (при этом речь может идти о любой рабочей ветке, которая вас интересует):

# Reset local master branch to November 3rd commit ID
git reset --hard 0d1d7fc32e5a947fbd92ee598033d85bfc445a50

# Reset remote master branch to November 3rd commit ID
git push -f origin 0d1d7fc32e5a947fbd92ee598033d85bfc445a50:master

Я нашел ответ от в сообщении в блоге (теперь больше не существует)

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

Лучше использовать возврат (см. Другие ответы), чем сброс. Если вы команда из одного человека, то это, вероятно, не имеет значения.

markreyes
источник
6
Чем этот ответ отличается от множества других?
Матсмат
Это прискорбно. Я написал блогеру по электронной почте - надеюсь, у него все еще есть!
Markreyes
2
Синтаксис push отсутствует в большинстве других предложений о том, как это исправить. Работал отлично.
jpa57
61

Скажем, у вас есть следующие коммиты в текстовом файле с именем ~/commits-to-revert.txtgit log --pretty=onelineих получал)

fe60adeba6436ed8f4cc5f5c0b20df7ac9d93219
0c27ecfdab3cbb08a448659aa61764ad80533a1b
f85007f35a23a7f29fa14b3b47c8b2ef3803d542
e9ec660ba9c06317888f901e3a5ad833d4963283
6a80768d44ccc2107ce410c4e28c7147b382cd8f
9cf6c21f5adfac3732c76c1194bbe6a330fb83e3
fff2336bf8690fbfb2b4890a96549dc58bf548a5
1f7082f3f52880cb49bc37c40531fc478823b4f5
e9b317d36a9d1db88bd34831a32de327244df36a
f6ea0e7208cf22fba17952fb162a01afb26de806
137a681351037a2204f088a8d8f0db6e1f9179ca

Создайте сценарий оболочки Bash, чтобы вернуть каждый из них:

#!/bin/bash
cd /path/to/working/copy
for i in `cat ~/commits-to-revert.txt`
do
    git revert $i --no-commit
done

Это вернет все обратно к предыдущему состоянию, включая создание файлов и каталогов, а также удаление, зафиксирует его в вашей ветви, и вы сохраните историю, но вы вернетесь к той же файловой структуре. Почему Git не имеет, git revert --to <hash>вне меня.

Ланс Караччиоли
источник
41
Вы можете сделать, git revert HEAD~3чтобы удалить последние 3 коммитов
Rod
25
@ Род - Нет, это не правильно. Эта команда вернет коммит, являющийся третьим прародителем HEAD (не последние три коммита).
Кфлоренция
1
@kflorence Хорошо, спасибо за информацию. Будет git revert -n master~3..master~1работать? (Как видно из kernel.org/pub/software/scm/git/docs/git-revert.html )
Род
3
@Rod - Звучит правильно, конечно, уродливый синтаксис, правда? Я всегда находил проверку коммита, к которому я хочу «вернуться», и затем коммит, который стал более интуитивным.
Кфлоренция
7
Там это гораздо проще способ сделать это сейчас , чем со сценарием , как это, просто использовать git revert --no-commit <start>..<end>, потому что git revertпринимает фиксации диапазона в новом (или все?) Версии Git. Обратите внимание, что начало диапазона не входит в обратный.
58

Дополнительные альтернативы решениям Jefromi

Решения Jefromi, безусловно, самые лучшие, и вам обязательно стоит их использовать. Однако для полноты картины я также хотел показать эти другие альтернативные решения, которые также можно использовать для отмены фиксации (в том смысле, что вы создаете новую фиксацию, которая отменяет изменения в предыдущей фиксации , точно так же, как и то, что git revertпроисходит).

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

Альтернатива 1: жесткий и мягкий сброс

Это очень немного измененная версия решения Чарльза Бейли « Вернуть коммит с помощью хэша SHA в Git»? :

# Reset the index to the desired commit
git reset --hard <commit>

# Move the branch pointer back to the previous HEAD
git reset --soft HEAD@{1}

# Commit the changes
git commit -m "Revert to <commit>"

Это в основном работает с использованием того факта, что программный сброс оставит состояние предыдущего коммитирования в индексной / промежуточной области, которое вы можете затем зафиксировать.

Альтернатива 2: удалить текущее дерево и заменить новым

Это решение взято из решения svick Checkout old commit и делает его новым коммитом :

git rm -r .
git checkout <commit> .
git commit

Подобно альтернативе № 1, он воспроизводит состояние <commit>текущей рабочей копии. Это необходимо сделать git rmсначала, потому git checkoutчто не удалит файлы, которые были добавлены с тех пор <commit>.

оборота user456814
источник
Об альтернативе 1, один быстрый вопрос: тем самым мы не проигрываем между коммитами, верно?
Богак
2
@Bogac - точки указывают путь к файлу, в данном случае текущий каталог, поэтому предполагается, что вы запускаете его из корня рабочей копии.
Том
Предупреждение повторяется в ответе несколько раз, но кто-то может добавить, почему это не лучший способ - по сравнению с чем-то вроде git revert HEAD~2..HEADсвязанного решения @ Cascabel (@ Jefromi's). Я не вижу проблемы.
Джошуа Голдберг
55

Вот гораздо более простой способ вернуться к предыдущему коммиту (и иметь его в незафиксированном состоянии, чтобы делать с ним что угодно):

git reset HEAD~1

Таким образом, нет необходимости в фиксации идентификаторов и так далее :)

Павел Вальчевский
источник
не сработало, git pull после этого приводит к: error: Ваши локальные изменения в следующих файлах будут перезаписаны слиянием:
malhal
1
@malhal Это потому, что у вас были незафиксированные изменения. Спрятать / сбросить их, и тогда это будет работать без этой ошибки.
Павел Вальчевский
39

Существует команда (не входящая в состав ядра Git, но она входит в пакет git-extras ) специально для возврата и постановки старых коммитов:

git back

Для справочной страницы , он также может быть использован как таковой:

# Remove the latest three commits
git back 3
Человек тени
источник
39

Лучший способ это:

git reset --hard <commidId> && git push --force

Это сбросит ветку на конкретный коммит, а затем загрузит на удаленный сервер те же коммиты, что и на локальном (это полностью исключит команды после этого конкретного коммита)

Будьте осторожны, когда --forceфлаг удаляет все последующие коммиты после выбранного коммита без возможности их восстановления.

david.t_92
источник
3
работал как шарм!
Гаурав Гупта
Я отклонил голосование, потому что не вижу, как в вашем ответе содержится какая-либо новая информация, которая еще не была указана, например stackoverflow.com/a/37145089/1723886 , stackoverflow.com/a/27438379/1723886 или stackoverflow.com/a/48756719/1723886 . Фактически большинство коммитов уже упоминают git reset --hard, и многие другие упоминают использование --force или -f для push.
Алекс Телон
Это делает работу только с одной командой, ясной и простой. Вы можете понизить мой ответ, если он вам не нравится.
david.t_92
1
Еще один вариант, который стоит рассмотреть на будущее, - это предложить редактирование более раннего ответа или добавить комментарий, в котором говорится, что «это также можно сделать в одной строке, например, с помощью &&». Таким образом, каждый сможет увидеть улучшенный ответ в одном месте.
Алекс Телон
36

После всех изменений, когда вы нажимаете все эти команды, вам, возможно, придется использовать:

git push -f ...

И не только git push.

SiVi
источник
15
Обязательное предупреждение: не делайте этого, если вы делитесь своей веткой с другими людьми, у которых есть копии старых коммитов, потому что подобное принудительное нажатие заставит их пересинхронизировать свою работу. Для решения, которое подробно объясняет, как безопасно вернуть коммиты без потери работы с принудительным толчком, см. Этот ответ .
3
Иногда это то, что вы хотите. Пример: совершил и передал несколько коммитов в неправильную ветвь (ветвь А). После выбора вишни для ветви B я хочу, чтобы эти коммиты были удалены из ветви A. Я бы не хотел возвращаться, так как обратный процесс позже будет применен, когда ветви A и B будут объединены вместе. Выполнение reset --hard <commitId> в ветви A с последующим принудительным нажатием удаляет эти коммиты из ветви, сохраняя их в ветви B. Я могу обойтись без этого, потому что знаю, что никто не разрабатывает в ветви A.
Дуг R
Спасибо! Я не мог понять, как заставить удаленную ветвь соответствовать моей локальной ветке, просто нужно было принудительно нажать.
Mido
32

Вы можете выполнить все эти начальные шаги самостоятельно и вернуться в репозиторий Git.

  1. Извлеките последнюю версию вашего хранилища из Bitbucket с помощью git pull --allкоманды.

  2. Запустите команду Git log с -n 4вашего терминала. Число после -nопределяет количество подтверждений в журнале, начиная с самого последнего принятия в вашей локальной истории.

    $ git log -n 4
    
  3. Сбросьте заголовок истории вашего репозитория, используя git reset --hard HEAD~Nгде N - количество коммитов, которые вы хотите вернуть назад. В следующем примере заголовок будет возвращен на один коммит до последнего коммита в истории репозитория:

  4. Нажмите изменения в репозитории Git, git push --forceчтобы принудительно нажать изменения.

Если вы хотите, чтобы Git-репозиторий был предыдущим коммитом:

git pull --all
git reset --hard HEAD~1
git push --force
Наньхэ Кумар
источник
30

Возврат к самой последней фиксации и игнорирование всех локальных изменений:

git reset --hard HEAD
Мохаммед Ирфан Тирупаттур
источник
28

Выберите необходимый коммит и проверьте его с помощью

git show HEAD
git show HEAD~1
git show HEAD~2 

пока вы не получите необходимый коммит. Чтобы ГОЛОВА указала на это, сделайте

git reset --hard HEAD~1

или git reset --hard HEAD~2или что угодно.

tonythomas01
источник
7
Обязательное предупреждение: не делайте этого, если вы делитесь своей веткой с другими людьми, у которых есть копии старых коммитов, потому что при таком жестком сбросе им придется заново синхронизировать свою работу с новой веткой сброса. Для решения, которое подробно объясняет, как безопасно вернуть коммиты без потери работы с полным сбросом, см. Этот ответ .
2
Кроме того, чтобы быть ясно, git show HEADэквивалентно просто использовать git log HEAD -1.
25

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


Быстрый и неаккуратный : в зависимости от обстоятельств, быстро и грязно на самом деле может быть очень хорошим. Что мое решение здесь делает, так это НЕ необратимо заменяет файлы, которые у вас есть в вашем рабочем каталоге, на файлы, извлеченные / извлеченные из глубины репозитория git, скрывающиеся под вашим каталогом .git /, используя чертовски умные и дьявольски мощные команды git, из которых есть многие. ВЫ НЕ ДОЛЖНЫ ДЕЛАТЬ ТАКОЕ ГЛУБОКОЕ ДЕЙСТВИЕ, ЧТОБЫ ВОССТАНОВИТЬ то, что может показаться катастрофической ситуацией, и попытка сделать это без достаточного опыта может оказаться фатальной .


  1. Скопируйте весь каталог и назовите его как-нибудь еще, например, «мой проект - копия». Предполагая, что ваши файлы репозитория git ("repo") находятся в каталоге "мой проект" (место по умолчанию для них, в каталоге с именем ".git"), вы теперь скопируете свои рабочие файлы и файлы репо.

  2. Сделайте это в каталоге "мой проект":

    .../my project $ git reset --hard [first-4-letters&numbers-of-commit's-SHA]
    

Это вернет состояние репо в «моем проекте» к тому, что было, когда вы сделали этот коммит («коммит» означает снимок ваших рабочих файлов). Все коммиты с тех пор будут навсегда потеряны в «моем проекте», НО ... они все равно будут присутствовать в репозитории в разделе «мой проект - копия», поскольку вы скопировали все эти файлы, в том числе и те, которые находятся в ... /. Git /.

Затем у вас есть две версии в вашей системе ... вы можете просматривать, копировать или изменять файлы, представляющие интерес, или что-то еще из предыдущего коммита. Вы можете полностью отбросить файлы в разделе «Мой проект - копия», если вы решили, что новая работа, так как восстановленный коммит никуда не денется ...

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

Git - блестящее творение, но абсолютно никто не может просто «поднять его на лету»: также люди, которые слишком часто пытаются объяснить это, предполагают, что они уже знакомы с другими VCS [системами контроля версий] и слишком глубоко вникают слишком рано, и совершать другие преступления, такие как использование взаимозаменяемых терминов для «проверки» - способами, которые иногда кажутся почти рассчитанными, чтобы запутать новичка.

Чтобы избавить себя от стресса, учитесь на моих шрамах. Вы должны в значительной степени прочитать книгу по Git - я бы порекомендовал «Контроль версий с помощью Git» . Сделай это раньше, чем позже. Если вы это сделаете, имейте в виду, что большая часть сложности Git связана с ветвлением, а затем с повторным объединением: вы можете пропустить эти части в любой книге. Из твоего вопроса нет причин, почему люди должны ослеплять тебя наукой .

Особенно, если, например, это отчаянная ситуация, и вы новичок в Git!

PS: Еще одна мысль: (сейчас) на самом деле довольно просто хранить репозиторий Git в каталоге, отличном от каталога с рабочими файлами. Это означает, что вам не нужно будет копировать весь репозиторий Git, используя вышеуказанное быстрое и грязное решение. Смотрите ответ Фрайера, используя --separate-git-dir здесь . Тем не менее, будьте осторожны : если у вас есть репозиторий «отдельный каталог», который вы не копируете, и вы выполняете полный сброс, все версии, следующие за фиксацией сброса, будут потеряны навсегда, если у вас нет, как вы абсолютно должны, регулярно создавайте резервные копии вашего хранилища, желательно в облаке (например, Google Drive ) среди других мест.

В этой теме «резервного копирования в облако» следующим шагом является открытие учетной записи (конечно же, бесплатной) с помощью GitHub или (на мой взгляд, лучше) GitLab . Затем вы можете регулярно выполнять git pushкоманду, чтобы сделать ваше облачное хранилище обновленным «должным образом». Но, опять же, говорить об этом слишком рано.

Майк Грызун
источник
23

Это еще один способ прямого сброса на недавний коммит

git stash
git stash clear

Он напрямую удаляет все изменения, которые вы внесли с момента последнего коммита.

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

Point Networks
источник
ПРИМЕЧАНИЕ. Новые файлы, не добавленные в индекс, не сохраняются. Вы тоже добавили их или удалили вручную.
андрейро
Очистка заначки? Помимо того, что это не решение проблемы, это на самом деле вредно. Чтение самого первого предложения вопроса немедленно делает недействительным решение для тайника (что может быть полезно ТОЛЬКО для сброса в последний коммит).
RomainValeri
22

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

git add -A .
git reset --hard HEAD

Просто git reset --hard HEADизбавится от модификаций, но не избавится от «новых» файлов. В их случае они случайно перетащили важную папку куда-то случайно, и все эти файлы были обработаны Git как новые, так что reset --hardне удалось это исправить. Запустив git add -A .предварительно, он явно отслеживал их всех с помощью git, чтобы сбросить их при перезагрузке.

Крис Москини
источник
21

Чтобы сохранить изменения предыдущего коммита в HEAD и перейти к предыдущему коммиту, выполните:

git reset <SHA>

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

git reset --hard <SHA>
Вишну Атраи
источник
20

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

git reset --hard origin/master

/superuser/273172/how-to-reset-master-to-origin-master

nevster
источник
18

Revert - команда для отката коммитов.

git revert <commit1> <commit2> 

Образец:

git revert 2h3h23233

Он способен принимать дальность от головы, как показано ниже. Здесь 1 говорит «отменить последний коммит».

git revert HEAD~1..HEAD

а затем сделать git push

Сириш Ярлагадда
источник
14

Попробуйте сбросить до желаемого коммита -

git reset <COMMIT_ID>

(чтобы проверить использование COMMIT_ID git log)

Это вернет все измененные файлы в состояние без добавления.

Теперь вы можете checkoutвсе файлы, не добавленные

git checkout .

Проверьте, git logчтобы проверить ваши изменения.

ОБНОВИТЬ

Если у вас есть один-единственный коммит в репо, попробуйте

git update-ref -d HEAD

optimistanoop
источник
13

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

Сначала вам нужно удалить развернутый объект из источника :

git push origin :develop (note the colon)

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

git reset --hard EFGHIJK

Наконец, нажмите развиваться снова:

git push origin develop
Джордж Нинан
источник
13

Внимание! Эта команда может привести к потере истории коммитов, если пользователь ошибочно добавил неверный коммит. Всегда имейте дополнительную резервную копию своего git где-нибудь еще на всякий случай, если вы делаете ошибки, чем вы немного безопаснее. :)

У меня была похожая проблема, и я хотел вернуться к предыдущей фиксации. В моем случае я не был заинтересован в сохранении нового коммита, поэтому я использовал Hard.

Вот как я это сделал:

git reset --hard CommitId && git clean -f

Это вернется в локальный репозиторий, а здесь после использования git push -fобновит удаленный репозиторий.

git push -f
maytham-ɯɐɥʇʎɐɯ
источник
13

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

  1. Щелкните правой кнопкой мыши на коммите, который вы хотите сбросить, выберите: Reset to this commit / Hard :

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

  2. Снова щелкните правой кнопкой мыши на коммите, выберите: Текущее имя ветви / Push :

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

  3. Нажмите на Force Push :

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

Обсервованный : Вы должны быть осторожны, потому что вся история коммитов после аппаратного сброса потеряна, и это действие необратимо. Вы должны быть уверены, что вы делаете.

Анджело Полотто
источник
11

Если вы хотите исправить какую-то ошибку в последнем коммите, хорошей альтернативой будет использование команды git commit --amend . Если последняя фиксация не указана какой-либо ссылкой, это сделает свое дело, так как создаст фиксацию с тем же родителем, что и последняя фиксация. Если нет ссылки на последний коммит, он просто будет отброшен, и этот коммит будет последним коммитом. Это хороший способ исправления коммитов без возврата коммитов. Однако у него есть свои ограничения.

Упул Долувира
источник