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

StackOverflow https://stackoverflow.com/questions/253055

  •  05-07-2019
  •  | 
  •  

Вопрос

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

> 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/'

Что мне следует делать?(Я могу получить доступ к удаленному репозиторию.)

Это было полезно?

Решение

Я на самом деле однажды запустил репозиторий --force и .git, и меня отчитал Линус БОЛЬШОЕ ВРЕМЯ . В целом это создаст много проблем для других людей. Простой ответ: & Quot; не делайте этого & Quot;.

Я вижу, что другие так или иначе дали рецепт для этого, поэтому я не буду повторять их здесь. Но вот совет для восстановления ситуации после того, как вы выдвинули исправленный коммит с помощью --force (или + master).

<Ол>
  • Используйте git reflog, чтобы найти старый коммит, который вы изменили (назовите его old, и мы назовем новый коммит, который вы создали, изменив new).
  • Создайте слияние между git checkout new && git merge -s ours old и git merge master, записав дерево git push . HEAD:master, например <=>.
  • Объедините это с вашим мастером с помощью <=>
  • Обновите ваш мастер с помощью результата с помощью <=>
  • Выдвиньте результат.
  • Тогда люди, которые были достаточно неудачны, чтобы основывать свою работу на коммите, который вы стерли, исправив и форсировав толчок, увидят, что в результате слияния вы увидите, что вы поддерживаете <=>, а не <=>. Их более поздние слияния не приведут к конфликтам между <=> и <=>, которые возникли в результате ваших изменений, поэтому им не придется страдать.

    Другие советы

    Вы видите функцию безопасности 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 в этой ситуации - сокращение от <=>.

    Быстрая тирада:Тот факт, что никто не опубликовал здесь простой ответ, демонстрирует отчаянную враждебность пользователей, проявляемую Git CLI.

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

    Как только вы разрешите все конфликты, вы можете нажать еще раз.

    Итак:

    git pull
    

    Если вы получаете ошибки при извлечении, возможно, что-то не так в конфигурации вашего локального репозитория (у меня была неправильная ссылка в разделе ветки .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, я думал, что это было завершено ФУБАР.

    Решение:Примерно так, как предложил @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
    

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

    Если вы знаете, что никто не снял ваш коммит без изменений, используйте параметр --force-with-lease git push.

    В TortoiseGit вы можете сделать то же самое в " Push ... " параметры " Force: может отменить " и проверка " известные изменения ".

      

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

    Вот очень простой и понятный способ протолкнуть свои изменения после того, как вы уже внесли git add "your files" и git commit --amend:

    git push origin master -f
    

    или:

    git push origin master --force
    

    Вы получаете эту ошибку, потому что Git Remote уже имеет эти файлы коммитов. Вы должны принудительно нажать на ветку, чтобы это работало:

    git push -f origin branch_name
    

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

    git pull origin branch_name
    

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

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

    Я просто продолжал делать то, что мне сказал Мерзавец.Итак:

    • Не могу нажать из-за измененной фиксации.
    • Я делаю рывок, как было предложено.
    • Сбой слияния.поэтому я исправляю это вручную.
    • Создайте новый коммит (с пометкой "объединить") и нажмите на него.
    • Кажется, это работает!

    Примечание:Измененный коммит был последним.

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

    <Ол>
  • Пока сохраняйте свою работу.
  • Храни свои изменения на время, если они сделаны: git stash Теперь твоя рабочая копия чиста в состоянии твоего последнего коммита.
  • Внесите исправления и исправления.
  • Подтвердите изменения в режиме " изменить " : git commit --all --amend
  • Ваш редактор появится с запросом на сообщение журнала (по умолчанию старое сообщение журнала). Сохраните и выйдите из редактора, когда вы довольны им.

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

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

  • Лицензировано под: CC-BY-SA с атрибуция
    Не связан с StackOverflow
    scroll top