Как мне отправить исправленный коммит в удаленный репозиторий Git?
Когда я немного поработал с исходным кодом, я сделал свою обычную фиксацию, а затем отправил в удаленный репозиторий. Но потом я заметил, что забыл организовать свой импорт в исходном коде. Поэтому я делаю команду исправления, чтобы заменить предыдущий коммит:
> git commit --amend
К сожалению, коммит не может быть перенесен обратно в хранилище. Это отклонено как это:
> git push origin
To //my.remote.repo.com/stuff.git/
! [rejected] master -> master (non-fast forward)
error: failed to push some refs to '//my.remote.repo.com/stuff.git/'
Что я должен делать? (Я могу получить доступ к удаленному хранилищу.)
21 ответ
Я на самом деле когда-то толкнул --force
а также .git
хранилище и получил от Линуса БОЛЬШОЕ ВРЕМЯ. В целом это создаст много проблем для других людей. Простой ответ: "Не делай этого".
Я вижу, что другие дали рецепт для этого в любом случае, поэтому я не буду повторять их здесь. Но вот совет для выхода из ситуации после того, как вы вытолкнули исправленный коммит с помощью --force (или +master).
- использование
git reflog
найти старый коммит, который вы исправили (назовите егоold
и мы назовем новый коммит, который вы создали, исправивnew
). - Создать слияние между
old
а такжеnew
, записывая деревоnew
, лайкgit checkout new && git merge -s ours old
, - Слейте это своему хозяину с
git merge master
- Обновите ваш мастер с результатом с
git push . HEAD:master
- Выдвиньте результат.
Тогда люди, которые были достаточно неудачны, чтобы основывать свою работу на коммите, который вы уничтожили, исправив и форсировав толчок, увидят, что в результате слияния увидят, что вы поддерживаете new
над old
, Их последующие слияния не увидят конфликтов между old
а также new
это произошло в результате ваших изменений, поэтому они не должны страдать.
Вы видите функцию безопасности Git. Git отказывается обновлять удаленную ветвь с вашей веткой, потому что заголовок вашей ветки не является прямым потомком текущего заголовка ветки, на которую вы отправляете ветку.
Если бы это было не так, то два человека, отправляющих файлы в один и тот же репозиторий примерно в одно и то же время, не знали бы, что одновременно поступает новый коммит, и тот, кто нажал последний, потеряет работу предыдущего толкателя без какого-либо из них. они понимают это.
Если вы знаете, что вы единственный, кто нажимает, и вы хотите отправить исправленный коммит или выдать коммит, который свернет ветку, вы можете "заставить" Git обновить удаленную ветку, используя -f
переключатель.
git push -f origin master
Даже это может не сработать, так как Git позволяет удаленным репозиториям отклонять небыстрые запросы на дальнем конце, используя переменную конфигурации receive.denynonfastforwards
, В этом случае причина отказа будет выглядеть следующим образом (обратите внимание на часть "удаленный отказ"):
! [remote rejected] master -> master (non-fast forward)
Чтобы обойти это, вам нужно либо изменить конфигурацию удаленного репозитория, либо в качестве грязного хака вы можете удалить и воссоздать ветку таким образом:
git push origin :master
git push origin master
В общем последний параметр git push
использует формат <local_ref>:<remote_ref>
, где local_ref
это имя филиала в локальном хранилище и remote_ref
это имя ветки в удаленном хранилище. Эта пара команд использует два сокращения. :master
имеет нулевое значение local_ref, что означает перемещение нулевой ветви на удаленную сторону master
удалить удаленную ветку. Название ветки без :
означает отправить локальную ветку с заданным именем в удаленную ветку с тем же именем. master
в этой ситуации мало master:master
,
Быстрый разглагольствование: тот факт, что никто не разместил здесь простой ответ, демонстрирует отчаянную враждебность пользователей, проявляемую Git CLI.
В любом случае, "очевидный" способ сделать это, предполагая, что вы не пытались форсировать толчок, - это тянуть первым. Это тянет за собой изменения, которые вы внесли (и так больше не вносили), чтобы они снова были у вас.
Как только вы разрешили конфликты, вы можете нажать еще раз.
Так:
git pull
Если вы получаете ошибки в pull, возможно, что-то не так в вашей локальной конфигурации репозитория (у меня был неправильный ref в разделе ветки.git / config).
И после
git push
Возможно, вы получите дополнительный коммит с темой, рассказывающей о "тривиальном слиянии".
Краткий ответ: не выдвигайте исправленные коммиты в публичное репо.
Длинный ответ: несколько команд Git, вроде git commit --amend
а также git rebase
переписать график истории. Это нормально до тех пор, пока вы не опубликовали свои изменения, но как только вы это сделаете, вам действительно не стоит копаться в истории, потому что, если кто-то уже получил ваши изменения, тогда, когда они попытаются повторить попытку, это может привести к неудаче, Вместо внесения изменений в коммит, вы должны просто сделать новый коммит с изменениями.
Однако, если вы действительно хотите добавить исправленный коммит, вы можете сделать это следующим образом:
$ git push origin +master:master
Ведущий +
Знак заставит произойти толчок, даже если он не приведет к фиксации "ускоренной перемотки". (Ускоренная фиксация происходит, когда изменения, которые вы отправляете, являются прямым потомком изменений, уже находящихся в публичном репо.)
Вот очень простой и понятный способ перенести ваши изменения после того, как вы уже сделали commit --amend
:
git reset --soft HEAD^
git stash
git push -f origin master
git stash pop
git commit -a
git push origin master
Что делает следующее:
- Сбросить заголовок ветки до родительского коммита.
- Спрятать этот последний коммит.
- Сила толчка к пульту. Удаленный теперь не имеет последнего коммита.
- Поп твой тайник.
- Совершайте чисто.
- Нажмите на пульт.
Не забудьте изменить "origin" и "master", если применяете это к другой ветке или удаленной.
Я решил это, отбросив свой локальный исправленный коммит и добавив новые изменения сверху:
# Rewind to commit before conflicting
git reset --soft HEAD~1
# Pull the remote version
git pull
# Add the new commit on top
git add ...
git commit
git push
Если сообщение, которое нужно изменить, относится к последней фиксации в репозитории, то должны быть выполнены следующие команды:
git commit --amend -m "New message"
git push --force repository-name branch-name
Примечание : использовать --force не рекомендуется, если только вы не уверены, что никто другой не клонировал ваш репозиторий после последнего коммита.
Более безопасной альтернативой является использование:
git push --force-with-lease repository-name branch-name
в отличие
--force
, который уничтожит любые изменения, отправленные кем-то другим в ветку,
--force-with-lease
прервется, если в репозиторий было внесено восходящее изменение.
У меня такая же проблема.
- Случайно исправлен последний коммит, который уже был передан
- Сделано много изменений локально, совершено около пяти раз
- Пытался нажать, получил ошибку, запаниковал, объединил удаленный, получил много не-моих файлов, нажал, потерпел неудачу и т. Д.
Как Git-новичок, я думал, что это был полный FUBAR.
Решение: В некотором роде @bara предложил + создал локальную резервную ветку
# Rewind to commit just before the pushed-and-amended one.
# Replace <hash> with the needed hash.
# --soft means: leave all the changes there, so nothing is lost.
git reset --soft <hash>
# Create new branch, just for a backup, still having all changes in it.
# The branch was feature/1234, new one - feature/1234-gone-bad
git checkout -b feature/1234-gone-bad
# Commit all the changes (all the mess) not to lose it & not to carry around
git commit -a -m "feature/1234 backup"
# Switch back to the original branch
git checkout feature/1234
# Pull the from remote (named 'origin'), thus 'repairing' our main problem
git pull origin/feature/1234
# Now you have a clean-and-non-diverged branch and a backup of the local changes.
# Check the needed files from the backup branch
git checkout feature/1234-gone-bad -- the/path/to/file.php
Возможно, это не быстрое и чистое решение, и я потерял свою историю (1 коммит вместо 5), но это спасло работу за день.
Если вы не отправили код в удаленную ветку (GitHub/Bitbucket), вы можете изменить сообщение коммита в командной строке, как показано ниже.
git commit --amend -m "Your new message"
Если вы работаете над определенной веткой, сделайте это:
git commit --amend -m "BRANCH-NAME: new message"
Если вы уже отправили код с неправильным сообщением, вам следует быть осторожным при изменении сообщения. то есть после того, как вы измените сообщение фиксации и попытаетесь нажать его снова, у вас возникнут проблемы. Чтобы сделать это гладко, выполните следующие действия.
Пожалуйста, прочитайте весь ответ, прежде чем делать это
git commit --amend -m "BRANCH-NAME : your new message"
git push -f origin BRANCH-NAME # Not a best practice. Read below why?
Важное примечание: при непосредственном использовании принудительного нажатия вы можете столкнуться с проблемами кода, которые другие разработчики работают в той же ветке. Поэтому, чтобы избежать этих конфликтов, вам нужно извлечь код из вашей ветки, прежде чем делать принудительное нажатие:
git commit --amend -m "BRANCH-NAME : your new message"
git pull origin BRANCH-NAME
git push -f origin BRANCH-NAME
Это лучший метод при изменении сообщения фиксации, если оно уже было отправлено.
Вы можете сделать это простым и безопасным способом, выполнив следующие действия:
- Измените свой последний коммит с помощью
git commit --amend
и любые опции, которые вам нужно добавить -
git pull
для синхронизации вашего локального репо с вашим удаленным репо. - После вытягивания у вас будут конфликты между локальным и удаленным. Вам просто нужно решить их, приняв текущие изменения и снова зафиксировав их.
-
git push
Теперь ваше локальное и удаленное репо обновляются без необходимости изменять историю репо.
Если вы используете Visual Studio Code, вы можете попробовать это расширение, чтобы упростить задачу.
https://marketplace.visualstudio.com/items?itemName=cimdalli.git-commit-amend-push-force
Как видно из названия, он выполняет команды последовательно.
git commit --amend
git push --force
Вы получаете эту ошибку, потому что Git Remote уже имеет эти файлы коммитов. Вы должны принудительно нажать на ветку, чтобы это сработало:
git push -f origin branch_name
Также убедитесь, что вы извлекаете код из удаленного узла, поскольку кто-то из вашей команды мог отправить его в ту же ветку.
git pull origin branch_name
Это один из случаев, когда мы вынуждены принудительно выдавать коммит на удаленный доступ.
Если вы знаете, что никто не снял ваш неизмененный коммит, используйте --force-with-lease
вариант git push
,
В TortoiseGit вы можете сделать то же самое в "Push..." опциях "Force: May Discard" и проверяя "известные изменения".
Принудительно (может отменить известные изменения) позволяет удаленному репозиторию принимать более безопасную передачу без ускоренной перемотки вперед. Это может привести к потере коммитов удаленным репозиторием; используйте это с осторожностью. Это может предотвратить потерю неизвестных изменений от других людей на пульте. Он проверяет, указывает ли ветвь сервера на тот же коммит, что и на ветку удаленного отслеживания (известные изменения). Если да, будет выполнен принудительный толчок. В противном случае он будет отклонен. Поскольку в git нет тегов удаленного отслеживания, теги нельзя перезаписать с помощью этой опции.
В этом случае вы должны --force.
На основе:
Если это индивидуальный проект, я бы сделал так:git push origin <branch-name> -f
Если вы работаете со своей командой или другие коллеги просматривают и используют ваш код,force
флаг не рекомендуется. В основном потому, что вы всегда хотите иметь чистую историю git.
Что бы я сделал?
- Если в той же ветке работает больше людей или кто-то просматривает ваш код, я бы
git commit --amend
, затемgit push -f ...
и пусть люди знают, что им нужноgit pull --rebase
чтобы иметь возможность видеть ваши изменения. - Если что-то подобное происходит при просмотре PR или MR, добавьте новый чистый коммит и в конце
squash
для очистки истории.
Вот очень простой и понятный способ перенести ваши изменения после того, как вы уже сделали git add "your files"
а также git commit --amend
:
git push origin master -f
или же:
git push origin master --force
Я просто продолжал делать то, что сказал мне Гит. Так:
- Не могу нажать из-за исправленного коммита.
- Я делаю тягу, как предложено.
- Слияние не удается. поэтому я исправляю это вручную.
- Создайте новый коммит (помеченный как "слияние") и нажмите его.
- Кажется, работает!
Примечание: исправленный коммит был последним.
Я должен был решить эту проблему с извлечением из удаленного репо и иметь дело с конфликтами слияния, которые возникли, зафиксировать и затем протолкнуть. Но я чувствую, что есть лучший способ.
При изменении автора и коммиттера фиксации у меня сработало следующее.
git push -f origin master
Git был достаточно умен, чтобы понять, что это были коммиты идентичных дельт, которые различались только в разделе метаинформации.
И локальная, и удаленная главы указали на рассматриваемые коммиты.
Чтобы избежать принудительного нажатия, в удаленном голом репозитории удалите последний коммит (тот, который нужно изменить), используя:
git update-ref HEAD HEAD^
затем нажмите измененную фиксацию без конфликта.
Примечание. Это предполагает, что за это время никто не сделал неверный коммит. Если они есть, им придется аналогичным образом перематывать и снова тянуть, возможно, объединяя свои собственные изменения.
Вот, как я исправил редактирование в предыдущем коммите:
- Сохранить свою работу до сих пор.
- Сохраните ваши изменения на время, если они сделаны:
git stash
Теперь ваша рабочая копия чиста в состоянии вашего последнего коммита. - Сделайте правки и исправления.
- Зафиксируйте изменения в режиме "Изменить":
git commit --all --amend
Ваш редактор подойдет с запросом сообщения журнала (по умолчанию старое сообщение журнала). Сохраните и выйдите из редактора, когда вы довольны им.
Новые изменения добавляются в старый коммит. Смотрите сами с
git log
а такжеgit diff HEAD^
Повторно примените ваши скрытые изменения, если они сделаны:
git stash apply
Просто удалите удаленную ветку
git push --delete origin <your-branch>
а затем нажмите исправленную ветку.