Как мне отправить исправленный коммит в удаленный репозиторий 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).

  1. использование git reflog найти старый коммит, который вы исправили (назовите его old и мы назовем новый коммит, который вы создали, исправив new).
  2. Создать слияние между old а также new, записывая дерево new, лайк git checkout new && git merge -s ours old,
  3. Слейте это своему хозяину с git merge master
  4. Обновите ваш мастер с результатом с git push . HEAD:master
  5. Выдвиньте результат.

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

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

Вы можете сделать это простым и безопасным способом, выполнив следующие действия:

  1. Измените свой последний коммит с помощью git commit --amendи любые опции, которые вам нужно добавить
  2. git pullдля синхронизации вашего локального репо с вашим удаленным репо.
  3. После вытягивания у вас будут конфликты между локальным и удаленным. Вам просто нужно решить их, приняв текущие изменения и снова зафиксировав их.
  4. 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.

Что бы я сделал?

  1. Если в той же ветке работает больше людей или кто-то просматривает ваш код, я быgit commit --amend, затемgit push -f ...и пусть люди знают, что им нужноgit pull --rebaseчтобы иметь возможность видеть ваши изменения.
  2. Если что-то подобное происходит при просмотре 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^

затем нажмите измененную фиксацию без конфликта.

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

Вот, как я исправил редактирование в предыдущем коммите:

  1. Сохранить свою работу до сих пор.
  2. Сохраните ваши изменения на время, если они сделаны: git stash Теперь ваша рабочая копия чиста в состоянии вашего последнего коммита.
  3. Сделайте правки и исправления.
  4. Зафиксируйте изменения в режиме "Изменить": git commit --all --amend
  5. Ваш редактор подойдет с запросом сообщения журнала (по умолчанию старое сообщение журнала). Сохраните и выйдите из редактора, когда вы довольны им.

    Новые изменения добавляются в старый коммит. Смотрите сами с git log а также git diff HEAD^

  6. Повторно примените ваши скрытые изменения, если они сделаны: git stash apply

Просто удалите удаленную ветку

      git push --delete origin <your-branch>

а затем нажмите исправленную ветку.

Другие вопросы по тегам