2008-10-31 5 views
494

Когда я немного поработал с моим исходным кодом, я сделал свою обычную вещь, а затем я нажал на удаленный репозиторий. Но потом я заметил, что забыл организовать импорт в исходный код. Поэтому я команду изменить, чтобы заменить предыдущий коммит:Как я могу направить исправленную фиксацию в удаленный репозиторий 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/' 

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

+0

Что делать, если мой -amend должен был только изменить сообщение фиксации? Любой способ редактировать последнее сообщение фиксации, если оно уже было нажато на удаленный? Я сделал это на Github и получил то же сообщение о не быстрой перемотке вперед. Затем я применил решение ниже, но слияние просто добавило больше сообщений фиксации сверху .. – 2010-03-06 23:17:26

+7

@faB: Я думаю, что это FAQ. Сообщение фиксации хешируется вместе с фиксацией, поэтому chaning _it_ изменяет revid (hash). Если это не ясно: нет, вы не можете. IIRC может хранить внеполосную информацию в заметках (поэтому вы можете аннотировать существующие коммиты, не изменяя их). Чтобы наметить определенные коммиты, используйте теги – sehe 2011-03-21 22:06:14

+1

Вы скоро (git1.8.5, Q4 2013) сможете [делать «git push -force» более тщательно] (http://stackoverflow.com/a/18505634/6309). – VonC 2013-09-10 08:42:54

ответ

390

Я на самом деле когда-то толкнул с --force и .git хранилище и получил ругал Linus BIG TIME. В общем, это создаст массу проблем для других людей. Простой ответ: «Не делай этого».

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

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

Тогда люди, которые были достаточно неудачны основывали свою работу на коммит вы стерт изменения и заставляя толчок (который вы быть очень очень плохой мальчик) будет видеть в результате слияния будет видеть что вы пользуетесь new над old. Их последующие слияния не будут видеть конфликты между old и new, которые возникли в результате внесения изменений, поэтому им не нужно страдать.

1

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

+0

Не совсем. Возможно, проблема заключается в том, что вы не обновили свою локальную копию с удаленного репо. Git не будет нажимать на него, потому что вам, возможно, придется иметь дело с слияниями вручную. В моем другом ответе у меня есть команда (и объяснение), которая заставит нажать - но будьте осторожны, что может удалить изменения в пульте дистанционного управления. – mipadi 2008-10-31 18:14:00

88

Короткий ответ: не нажимайте исправленные обязательства на публичное репо.

Длинный ответ: несколько команд Git, таких как git commit --amend и git rebase, фактически перепишите диаграмму истории. Это прекрасно, пока вы не опубликовали свои изменения, но как только вы это сделаете, вы действительно не должны обманывать историю, потому что, если кто-то уже получил ваши изменения, тогда, когда они попытаются снова вытащить, , Вместо того, чтобы вносить изменения в коммит, вы должны просто сделать новую фиксацию с изменениями.

Однако, если вы действительно, действительно хотите, чтобы толкать исправленный совершить, вы можете сделать это так:

$ git push origin +master:master 

Ведущий + знак заставит толчок произойти, даже если это не приводит к в «быстрой перемотке» фиксации. (Быстрая перемотка вперед происходит, когда изменения, которые вы нажимаете, это прямой потомок изменений уже внесено в публичное репо.)

+3

Как это отличается (лучше или хуже), чем git push -f? Благодаря! – bentford 2012-02-27 15:36:05

+7

@bentford: Это в основном то же самое, что и `git push -f`. – mipadi 2012-02-27 15:46:13

226

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

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

Если вы знаете, что вы единственный человек, нажавший, и вы хотите надавить измененную фиксацию или нажать фиксацию, которая ветрует ветвь, вы можете «заставить» Git обновить удаленную ветку с помощью переключателя -f.

git push -f origin master 

Даже это не может работать, как Git позволяет удаленным хранилищам отказаться от не-FastForward выталкивает на дальнем конце с помощью переменной конфигурации 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 имеет значение null local_ref, что означает наведение нулевой ветви на удаленную сторону master, т. Е. Удаление удаленной ветви. Имя филиала без : означает, что локальная ветвь с указанным именем выдает на удаленную ветку с тем же именем. master в этой ситуации не хватает для master:master.

+1

это не работало с github, оно дало мне следующее сообщение: [remote reject] master (удаление текущей ветви запрещено) – vedang 2010-11-12 13:12:05

+0

Я не хотел форсировать push (что я знал, решил бы проблему), но теперь я думаю У меня нет выбора. – vedang 2010-11-12 13:14:19

+1

Это единственное решение, которое работало на моем репо с ассемблемой. – Failpunk 2011-02-04 00:56:22

188

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

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

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

Итак:

git pull 

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

И после того, как

git push 

Может быть, вы получите дополнительные фиксации с предметом, говоря о «Trivial слияния».

16

Я решил его, отбрасывая мой местный Измененная фиксации и добавления новых изменений в верхней части:

# 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 
7

У меня была такая же проблема.

  • Accidentally поправками последней фиксации, что уже толкнул
  • Совершено много изменений на местном уровне, допускали пять раз
  • попытался оттолкнуть, получил сообщение об ошибке, запаниковал, сливались удаленный, есть много не -my-files, push, failed и т. д.

Как 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), но спасенным дневной работы.

2

Если вы не нажали код на удаленную ветку (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 

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

27

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

git reset --soft HEAD^ 
git stash 
git push -f origin master 
git stash pop 
git commit -a 
git push origin master 

, который выполняет следующие действия:

  • Сброс ветви головки к родителю фиксации.
  • Закрепить этот последний фиксатор.
  • Force push to remote. Теперь у пульта нет последнего фиксации.
  • Поп ваш трюк.
  • Зафиксируйте чисто.
  • Push to remote.

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

2

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

git push origin master -f 

или:

git push origin master --force 
1

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

git push -f origin branch_name 

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

git pull origin branch_name 

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

3

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

В TortoiseGit вы можете сделать то же самое под опциями «Push ...» «Force: May discard» и проверить «известные изменения».

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

1

Я просто продолжал делать то, что Гит сказал мне сделать. Таким образом:

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

Примечание: исправленная фиксация была последней.

Смежные вопросы