Отмена «git push»


592

Вот что я сделал на своей предполагаемой стабильной ветке ...

% git rebase master
First, rewinding head to replay your work on top of it...
Fast-forwarded alpha-0.3.0 to master.
% git status
# On branch alpha-0.3.0
# Your branch is ahead of 'origin/alpha-0.3.0' by 53 commits.
#
nothing to commit (working directory clean)
% git push
Fetching remote heads...
  refs/
  refs/heads/
  refs/tags/
  refs/remotes/
'refs/heads/master': up-to-date
updating 'refs/heads/alpha-0.3.0'
  from cc4b63bebb6e6dd04407f8788938244b78c50285
  to   83c9191dea88d146400853af5eb7555f252001b0
    done
'refs/heads/unstable': up-to-date
Updating remote server info

Все это было ошибкой, как я позже понял. Я хотел бы отменить весь этот процесс и вернуть ветку alpha-0.3.0 обратно в прежнее состояние.

Что мне делать?


возможно, этот стековый пост? stackoverflow.com/questions/134882/undoing-a-git-rebase
Стин

4
Это не совсем та же ситуация, отмена rebase - это сценарий локального репозитория, отмена git push требует удаленного репозитория и может быть более сложной в зависимости от вашего доступа.
CB Bailey

Стин - ты прав - наверное, мне следовало бы. Я подумал, что благословенный репозиторий, из которого все извлекаются, - это скорее задача администратора, и поэтому он принадлежит здесь, где общий git на стороне клиента - это вопрос переполнения стека.
Кира,

Быстрое пояснение - я предполагаю, что если вы ссылаетесь на коммит git с частичным значением хеша, git будет предполагать, что вы говорите о коммите, чей хеш начинается с этой строки?
Гершом

Ответы:


944

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

Затем вам нужно «принудительно» нажать старую ссылку.

git push -f origin last_known_good_commit:branch_name

или в вашем случае

git push -f origin cc4b63bebb6:alpha-0.3.0

Возможно, вы receive.denyNonFastForwardsустановили удаленный репозиторий. Если это так, то вы получите ошибку, которая включает фразу [remote rejected].

В этом случае вам придется удалить и воссоздать ветку.

git push origin :alpha-0.3.0
git push origin cc4b63bebb6:refs/heads/alpha-0.3.0

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

git update-ref refs/heads/alpha-0.3.0 cc4b63bebb6 83c9191dea8

16
Идеальный и хорошо объясненный ответ - большое спасибо. Для всех, кто сталкивается с этим, по академическим причинам я попробовал оба первых двух подхода, и оба сработали - очевидно, если первый работает, это самый чистый подход. Если бы я провожал тебя 10 раз, Чарльз, я бы. :)
Сайрус

139
Для git push -f origin last_known_good_commit:branch_name
краткости

5
git push -f origin cc4b63bebb6: alpha-0.3.0 => это помогло мне, обратите внимание, alpha-0.3.0 - это имя ветви, а cc4b63bebb6 - это идентификатор коммита, к которому мы хотим вернуться. Итак, после выполнения этой команды мы будем в cc4b63bebb6 commit id.
Кумар

22
Это решение очень опасно, если вы работаете в общем репо. Рекомендуется, чтобы все коммиты, переданные в удаленное репо с общим доступом, считались «неизменяемыми». Используйте 'мерзавец Возвратить' вместо: kernel.org/pub/software/scm/git/docs/...
Saboosh

1
jww - по сравнению со всем остальным, git - самый многофункциональный и эффективный из доступных инструментов управления исходным кодом. Каждая команда использует это по-своему. Стоит провести выходные, играя с новым репозиторием и изучая все распространенные сценарии. После того, как вы потратили некоторое время на работу с ним, разработка стала намного менее стрессовой.
user1491819

165

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

git checkout alpha-0.3.0
git reset --hard cc4b63bebb6
git push origin +alpha-0.3.0

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


9
Это сработало и для меня, но стоит отметить, что это «переписает» историю на пульте. Это может быть то, что вы хотите, но это не так!
Том

3
+1 за этот ответ, который действительно помог мне. Я также хотел добавить (и прояснить), что идентификатор фиксации (который следует после параметра " --hard") должен быть идентификатором любого коммита, в который вы хотите сбросить свою ветку.
Майкл Даутерманн

1
Хорошо переписал историю ... любой, кто мог вытащить изменения, я просто позаботился о том, чтобы они сделали, git reset --hard [commit_id]чтобы мы не связывались с пространственно-временным континуумом.
Чужая форма жизни

9
Что означает «+» в «git push origin + alpha-0.3.0»?
jpierson

1
@jpierson +заставляет произойти толчок, аналогично -f(но немного другому: stackoverflow.com/a/25937833/1757149 ). Без него, если вы пытаетесь git push origin alpha-0.3.0толкающий потерпит неудачу: Updates were rejected because the tip of your current branch is behind.
A__

106

git revert менее опасен, чем некоторые из предложенных здесь подходов:

prompt> git revert 35f6af6f77f116ef922e3d75bc80a4a466f92650
[master 71738a9] Revert "Issue #482 - Fixed bug."
 4 files changed, 30 insertions(+), 42 deletions(-)
prompt> git status
# On branch master
# Your branch is ahead of 'origin/master' by 1 commit.
#
nothing to commit (working directory clean)
prompt>

Замените 35f6af6f77f116ef922e3d75bc80a4a466f92650 своим собственным коммитом.


2
Как мне получить 35f6af6f77f116ef922e3d75bc80a4a466f92650 ID? Этот ответ был бы лучше, если бы вы могли это объяснить.
Volomike

2
@Volomike (и гугл-разработчики будущего), этот вопрос описывает множество способов его получения: контроль версий и вопрос о хеше на SO
Jaime

Это правильный ответ, потому что с помощью «git reset» вы не сможете нажимать (обновления были отклонены, потому что конец вашей текущей ветви находится за своим удаленным аналогом), или вам нужно форсировать извлечение, которое не совсем чистое.
Томас Деко

Это работало на меня. Тем не менее, будьте осторожны, так как возврат отменит все изменения в ваших локальных файлах.
user1941537

Я выбирал этот подход несколько раз, но я также использую git rebase -i <id-before-last-good-commit> для интерактивного перебазирования и очистки истории, как это предлагается здесь, stackoverflow.com/questions/5189560/… .
Эрнесто Алли

35

Принятое решение (от @charles bailey) очень опасно, если вы работаете в общем репо.

Рекомендуется, чтобы все коммиты, переданные в удаленное репо с общим доступом, считались «неизменяемыми». Вместо этого используйте «git revert»: http://www.kernel.org/pub/software/scm/git/docs/user-manual.html#fixing-mistakes

https://git-scm.com/book/be/v2/Git-Basics-Undoing-Things


Какие именно инструкции вы предписываете? У вас только старые ссылки.
jww

32

Способ сделать это без потери изменений, которые вы хотели:

git reset cc4b63b 
git stash
git push -f origin alpha-0.3.0
git stash pop

Затем вы можете выбрать файлы, которые вы хотели нажать


19

Еще один способ сделать это:

  1. создать другую ветку
  2. оформить предыдущий коммит в этой ветке, используя "git checkout"
  3. нажмите новую ветку.
  4. удалить старую ветку и нажать удалить (использовать git push origin --delete <branch_name>)
  5. переименовать новую ветку в старую ветку
  6. нажмите снова

2
Это похоже на реальное решение, когда у вас уже есть неправильные коммиты в репо
Илларион Ковальчук


11

Отмена множественных коммитов git reset --hard 0ad5a7a6 (просто предоставьте хеш SHA1 коммитов)

Отменить последний коммит

git reset --hard HEAD ~ 1 (изменения в последнем коммите будут удалены) git reset --soft HEAD ~ 1 (изменения в последнем коммите будут доступны в виде незафиксированных локальных изменений)


9

Сценарий 1 : Если вы хотите отменить последний коммит, скажем, 8123b7e04b3, ниже приведена команда (это работает для меня):

git push origin +8123b7e04b3^:<branch_name>

Вывод выглядит так:

Total 0 (delta 0), reused 0 (delta 0)
To https://testlocation/code.git
 + 8123b7e...92bc500 8123b7e04b3^ -> master (forced update)

Дополнительная информация: Сценарий 2 : В некоторых ситуациях вы можете вернуть обратно то, что вы только что отменили (в основном, отменить отмену) с помощью предыдущей команды, а затем использовать следующую команду:

git reset --hard 8123b7e04b3

Вывод:

HEAD is now at cc6206c Comment_that_was_entered_for_commit

Более подробная информация здесь: https://github.com/blog/2019-how-to-undo-almost-anything-with-git


Сценарий 1 должен быть принят ответ, поскольку в вопросе не указано, какой коммит удалить. Принятый ответ удаляет только последний коммит. Этот ответ удаляет любой коммит.
Доминик Черизано,

0

Существующие ответы являются хорошими и правильными, однако что, если вам нужно отменить, pushно:

  1. Вы хотите сохранить коммиты локально или оставить незафиксированные изменения
  2. Вы не знаете, сколько коммитов вы только что нажали

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

git push -f origin refs/remotes/origin/<branch>@{1}:<branch>

-2

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

git push origin +HEAD^:branch

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

git revert <SHA-1>
git push origin branch

1
да! это работало как шарм при работе с github. Спасибо.
cukabeka

Речь идет о «пуш», тогда это касается удаленной ветки. Нет, чтобы переместить ГОЛОВУ на один коммит, что означает игнорирование последнего переданного коммита, просто сделайте это: git push origin + HEAD ^: your_branch
mkebri
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.