Как мне отменить последние локальные коммиты в Git? - PullRequest
19725 голосов
/ 29 мая 2009

Я случайно отправил неправильные файлы на Git , но я еще не отправил коммит на сервер.

Как мне отменить эти коммиты из локального репозитория?

Ответы [ 78 ]

21323 голосов
/ 29 мая 2009

Отменить коммит и повторить

$ git commit -m "Something terribly misguided"             # (1)
$ git reset HEAD~                                          # (2)
<< edit files as necessary >>                              # (3)
$ git add ...                                              # (4)
$ git commit -c ORIG_HEAD                                  # (5)
  1. Это то, что вы хотите отменить.
  2. Это оставляет ваше рабочее дерево (состояние ваших файлов на диске) без изменений, но отменяет фиксацию и оставляет внесенные вами изменения неизмененными (поэтому они будут отображаться как «Изменения не подготовлены для фиксации» в git status, так что вы Надо будет добавить их еще раз до совершения). Если вы только хотите добавить больше изменений к предыдущему коммиту или изменить сообщение о коммите 1 , вы можете вместо этого использовать git reset --soft HEAD~, что похоже на git reset HEAD~ (где HEAD~ совпадает с HEAD~1), но оставляет существующие изменения поэтапно.
  3. Внести исправления в рабочие файлы дерева.
  4. git add все, что вы хотите включить в свой новый коммит.
  5. Подтвердить изменения, повторно используя старое сообщение фиксации. reset скопировал старую голову в .git/ORIG_HEAD; commit с -c ORIG_HEAD откроет редактор, который изначально содержит сообщение журнала от старого коммита и позволяет вам редактировать его. Если вам не нужно редактировать сообщение, вы можете использовать опцию -C.

Однако помните, что если вы добавили какие-либо новые изменения в индекс, то с помощью commit --amend они будут добавлены в ваш предыдущий коммит.

Если код уже передан на ваш сервер и у вас есть права на перезапись истории (rebase), тогда:

git push origin master --force

Вы также можете посмотреть на этот ответ:

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

Приведенный выше ответ покажет вам git reflog, который используется, чтобы узнать, что такое SHA-1, к которому вы хотите вернуться. Как только вы нашли точку, к которой вы хотите отменить, использовать последовательность команд, как описано выше.


1 Обратите внимание, однако, что вам не нужно возвращаться к более ранней фиксации, если вы только что допустили ошибку в своем сообщении фиксации . Более простой вариант - git reset (чтобы отменить внесение изменений, которые вы сделали с тех пор), а затем git commit --amend, который откроет ваш редактор сообщений по умолчанию, предварительно заполненный последним сообщением.

10286 голосов
/ 29 июля 2011

Отмена коммита немного страшна, если вы не знаете, как он работает. Но на самом деле это удивительно легко, если вы понимаете.

Допустим, у вас это есть, где C - это ГОЛОВА, а (F) - это состояние ваших файлов.

   (F)
A-B-C
    ↑
  master

Вы хотите обнулить коммит C и больше никогда его не видеть . Вы делаете это:

git reset --hard HEAD~1

Результат:

 (F)
A-B
  ↑
master

Теперь Б - ГОЛОВА. Поскольку вы использовали --hard, ваши файлы возвращаются в свое состояние при коммите B.

Ах, но предположим, что commit C был не катастрофой, а всего лишь ошибкой. Вы хотите отменить фиксацию, но сохраните свои изменения , чтобы немного отредактировать их, прежде чем выполнять более качественную фиксацию. Начиная снова здесь, с C в качестве вашей головы:

   (F)
A-B-C
    ↑
  master

Вы можете сделать это, исключив --hard:

git reset HEAD~1

В этом случае результат:

   (F)
A-B-C
  ↑
master

В обоих случаях HEAD - это просто указатель на последний коммит. Когда вы делаете git reset HEAD~1, вы говорите Git переместить указатель HEAD на один коммит. Но (если вы не используете --hard) вы оставляете свои файлы такими, какими они были. Так что теперь git status показывает изменения, которые вы зарегистрировали в C. Вы ничего не потеряли!

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

git reset --soft HEAD~1

Это не только оставляет ваши файлы в покое, оно даже оставляет ваш index в покое. Когда вы выполните git status, вы увидите, что в индексе есть те же файлы, что и раньше. Фактически, сразу после этой команды вы могли бы выполнить git commit и повторить тот же коммит, который вы только что сделали.

Еще одна вещь: Предположим, вы уничтожили коммит , как в первом примере, , но потом обнаружили, что он вам все-таки нужен ? Не повезло, правда?

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

git checkout -b someNewBranchName shaYouDestroyed

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

1964 голосов
/ 16 июня 2011

Мне понадобилось время, чтобы понять, так что, может быть, это кому-нибудь поможет ...

Существует два способа «отменить» ваш последний коммит, в зависимости от того, сделали ли вы коммит открытым или нет (передан в удаленный репозиторий):

Как отменить локальный коммит

Допустим, я зафиксировал локально, но теперь хочу удалить этот коммит.

git log
    commit 101: bad commit    # latest commit, this would be called 'HEAD'
    commit 100: good commit   # second to last commit, this is the one we want

Чтобы восстановить все, как было до последнего коммита, нам нужно reset до коммита до HEAD:

git reset --soft HEAD^     # use --soft if you want to keep your changes
git reset --hard HEAD^     # use --hard if you don't care about keeping the changes you made

Теперь git log покажет, что наш последний коммит был удален.

Как отменить публичный коммит

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

git revert HEAD

Ваши изменения теперь будут отменены и готовы к фиксации:

git commit -m 'restoring the file I removed by accident'
git log
    commit 102: restoring the file I removed by accident
    commit 101: removing a file we don't need
    commit 100: adding a file that we need

Для получения дополнительной информации, проверьте Основы Git - Undoing Things

1684 голосов
/ 29 мая 2009

Добавить / удалить файлы, чтобы получить вещи, как вы хотите:

git rm classdir
git add sourcedir

Затем измените коммит:

git commit --amend

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

Обратите внимание, что вы должны делать это, только если вы еще не нажали. Если вы нажали, то вам просто нужно зафиксировать исправление в обычном режиме.

952 голосов
/ 29 мая 2009
git rm yourfiles/*.class
git commit -a -m "deleted all class files in folder 'yourfiles'"

или

git reset --hard HEAD~1

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

От hard reset до HEAD-1 установит вашу рабочую копию в состояние фиксации до вашей неверной фиксации.

724 голосов
/ 31 июля 2010

Чтобы изменить последний коммит

Заменить файлы в индексе:

git rm --cached *.class
git add *.java

Тогда, если это частная ветка, изменить коммит:

git commit --amend

Или, если это общая ветка, сделайте новый коммит:

git commit -m 'Replace .class files with .java files'


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


ProTip ™: добавьте *.class к gitignore , чтобы остановить это снова.


Чтобы отменить коммит

Изменение коммита является идеальным решением, если вам нужно изменить последний коммит, но более общее решение - reset.

Вы можете сбросить git на любой коммит с помощью:

git reset @~N

Где N - количество коммитов до HEAD, а @~ сбрасывает до предыдущего коммита.

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

git reset @~
git add *.java
git commit -m "Add .java files"

Ознакомьтесь с git help reset, в частности с разделами --soft --mixed и --hard, чтобы лучше понять, что это делает.

Reflog

Если вы запутались, вы всегда можете использовать reflog, чтобы найти упавшие коммиты:

$ git reset @~
$ git reflog
c4f708b HEAD@{0}: reset: moving to @~
2c52489 HEAD@{1}: commit: added some .class files
$ git reset 2c52489
... and you're back where you started


612 голосов
/ 25 мая 2012

Использование git revert <commit-id>

Чтобы получить идентификатор фиксации, просто используйте git log

493 голосов
/ 31 января 2013

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

git reset --hard HEAD^1

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

git reset --soft HEAD^1

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

git reset HEAD

Теперь переданные файлы поступают из подготовленной области в неподготовленную область. Теперь файлы готовы к редактированию, поэтому, что бы вы ни изменили, вы захотите перейти к редактированию, добавить его и сделать новый / новый коммит.

Подробнее

466 голосов
/ 13 декабря 2011

Если у вас установлено Git Extras , вы можете запустить git undo, чтобы отменить последний коммит. git undo 3 отменит последние 3 коммита.

433 голосов
/ 06 апреля 2012

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

prompt> git reset --hard 5a7404742c85
HEAD is now at 5a74047 Added one more page to catalogue
prompt> git push origin master --force
Total 0 (delta 0), reused 0 (delta 0)
remote: bb/acl: neoneye is allowed. accepted payload.
To git@bitbucket.org:thecompany/prometheus.git
 + 09a6480...5a74047 master -> master (forced update)
prompt>
...