Как правильно заставить Git push?


1275

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

Теперь мне пришлось что-то менять в удаленном репо. Затем я изменил что-то в своем локальном репо. Я понял, что смена удаленного репо не нужна. Поэтому я попытался перейти git pushот локального репо к удаленному репо, но я получил ошибку вроде:

Чтобы предотвратить потерю истории, обновления без ускоренной пересылки были отклонены. Объедините удаленные изменения перед повторным нажатием. См. Раздел «Примечание о быстрой перемотке» git push --help.

Я думал, что, вероятно,

git push --force

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

Как я уже упоминал в комментариях к одному из ответов :

[Я] попытался форсировать, но когда возвращаюсь на главный сервер, чтобы сохранить изменения, я получаю устаревшую постановку. Таким образом, когда я фиксирую репозитории, они не совпадают. И когда я пытаюсь использовать git push снова, я получаю ту же ошибку.

Как я могу исправить эту проблему?


4
Вы скоро (git1.8.5, Q4 2013) сможете сделать git push -forceболее осторожно .
— VonC


6
Как я подробно излагаю в своем ответе , git push --forceэто действительно еще один действительный способ принудительного нажатия, и он будет выдвигать ветви так же, как и в git push origin master --forceGit по умолчанию push.default config settings, хотя, какие ветви специально выдвигаются, отличается между версиями Git до 2.0 и после 2.0.

2
git push --forceотлично работает в наши дни, FWIW ...
— rogerdpack

git push --force-with-leaseработает даже лучше :), он откажется обновлять ветку, если это не то состояние, которое вы ожидаете. (см. developer.atlassian.com/blog/2015/04/force-with-lease )
— spoorcc

Ответы:


2310

Просто делать:

git push origin <your_branch_name> --force

или если у вас есть определенный репо:

git push https://git.... --force

Это удалит ваш предыдущий коммит (ы) и подтолкнет ваш текущий.

Это может быть не совсем правильно, но если кто-то наткнется на эту страницу, подумав, что, возможно, они захотят простое решение ...

Короткий флаг

Также обратите внимание, что -fсокращение --force, так

git push origin <your_branch_name> -f

тоже будет работать.


58
Вы можете использовать git push origin +masterвместо этого, что позволит вам выдвинуть несколько refspecs, не заставляя их всех.
— Никгрим

5
Имейте в виду, что, если вы случайно сделаете это просто git push --force, вы можете испортить свою основную ветку (в зависимости от поведения по умолчанию в push-режиме) .. Что может отстойно .. немного ..: D
— Jeewes

9
@Jeewes, начиная с Git версии 2.0, поведение по умолчанию в git push --forceосновном состоит в том, чтобы принудительно выдвигать текущую извлеченную ветвь к ее части удаленного счетчика, так что если у вас есть ветвь master, то она идентична git push origin master --force. Это будет отличаться, если вы используете matchingпараметр для push.default, который используется по умолчанию для версий Git до 2.0. matchingтолкает все локальные ветви к удаленным, которые имеют одинаковые имена, поэтому принудительное нажатие может определенно не соответствовать вашим

@Jeewes Но с Git 2.0 по умолчанию безопаснее, или, по крайней мере, он не более опасен, чем git push origin master --forceесть.

2
push -f хорош, но не рекомендуется для мастера, так как в большинстве корпоративных репозиториев -f отключен для мастера. merge -s oursработал для меня
— Mihai

247

И если push --forceне работает, вы можете сделать push --delete. Посмотрите на 2- ую строку в этом случае:

git reset --hard HEAD~3  # reset current branch to 3 commits ago
git push origin master --delete  # do a very very bad bad thing
git push origin master  # regular push

Но будьте осторожны ...

Никогда не возвращайся к публичной истории!

Другими словами:

  • Никогда не forceвыдвигайте публичный репозиторий.
  • Не делайте этого или чего-либо, что может кого-то сломать pull.
  • Никогда resetили rewriteистории в репо кто-то, возможно, уже потянул.

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

Сделайте возврат вместо этого.

И всегда будьте осторожны с тем, что вы подталкиваете к публичному репо . Откат:

git revert -n HEAD~3..HEAD  # prepare a new commit reverting last 3 commits
git commit -m "sorry - revert last 3 commits because I was not careful"
git push origin master  # regular push

По сути, оба заголовка источника (от возврата и сброса зла ) будут содержать одинаковые файлы.


изменить, чтобы добавить обновленную информацию и больше аргументов вокруг push --force

Подумайте о толчковой силе с арендой, а не о толчке, но все же предпочитайте возврат

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

git push --force-with-leaseпредставленный в git 1.8.5 ( благодаря комментарию @VonC к этому вопросу) пытается решить эту конкретную проблему. По сути, это приведет к ошибке и не будет выдвигаться, если пульт был изменен с момента последней загрузки.

Это хорошо, если вы действительно уверены, что это push --forceнеобходимо, но все же хотите предотвратить больше проблем. Я бы пошел так далеко, чтобы сказать, что это должно быть push --forceповедение по умолчанию . Но это еще далеко не оправдание, чтобы заставить push. У людей, которые загрузились до вашей перебазировки, все равно будет много неприятностей, которых можно было бы легко избежать, если бы вы вернулись .

И так как мы говорим о git --pushслучаях ...

Почему кто-то хочет заставить толкать?

@linquize привел хороший пример толчка для комментариев: конфиденциальные данные . Вы ошибочно просочились данные, которые не должны быть отправлены. Если вы достаточно быстры, вы можете «починить»* его, нажав сверху.

*Данные будут по- прежнему находиться на пульте дистанционного управления , если вы не делаете мусор собирать , или очистить его каким - то образом . Существует также очевидный потенциал для его распространения другими, кто уже получил его, но вы поняли идею.


1
Проблема, @rogerdpack, не в том, если это выполнимо. Это. Но это может привести к большой катастрофе. Чем больше кто-то делает это (принудительное продвижение) и чем реже вы обновляете (извлекаете) из публичного репо, тем больше катастрофы. Он может разрушить мир таким, каким вы его знаете! 111 По крайней мере, мир, состоящий из этого конкретного хранилища.
— cregox

3
Если у вас есть конфиденциальные данные, принудительно нажмите их
— linquize

3
@Cawas: Я думаю, он имеет в виду, что если вы пытаетесь удалить конфиденциальные данные из хранилища, то вы хотите переписать историю. Если вы вернетесь, конфиденциальные данные все еще будут присутствовать в предыдущем коммите. Тем не менее, если кто-то другой уже извлек из хранилища, то переписывание истории не поможет вам предотвратить доступ к конфиденциальным данным - в этот момент уже слишком поздно.
— Стюарт Голодец

3
git push origin master --delete # do a very very bad bad thing git push origin master # regular pushэто фактически решило мою проблему отлично (на репо только со мной и моим другом). может быть, это неправильно для публичных репозиториев, но для частного репозитория это спасение жизни.
— Может Пойразоглу

1
это происходит автоматически с некоторыми менеджерами репозитория, так называемым автоматическим сквошем и т. д. принудительное нажатие после завершения ветви функций для уменьшения коммитов является обычным явлением.
— FlavorScape

18

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

Что касается ошибки, которую вы получаете, пробовали ли вы git pullиз локального репо, а затем git pushв основной репо? То, что вы сейчас делаете (если я хорошо это понял) - это форсирование, а затем потеря ваших изменений в «основном» репо. Сначала вы должны объединить изменения локально.


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

1
В этом случае используйте git push -f, но затем, если вы снова измените свой основной репо, вам придется вернуться к своему локальному репо и git pull, чтобы он синхронизировался с последними изменениями. Тогда вы можете сделать свою работу и нажать еще раз. Если вы будете следовать этому «двухтактному» рабочему процессу, вы не получите ошибку, на которую жаловались.
— Ubik

да, я понимаю, что это была моя вина: / Я попробую это и вернусь через некоторое время, спасибо
— Spyros

1
попытался форсировать, но при возвращении на главный сервер, чтобы сохранить изменения, я получаю устаревшую постановку. Таким образом, когда я фиксирую репозитории, они не совпадают. И когда я пытаюсь использовать git push снова, я получаю ту же ошибку.
— Spyros

17

Если я нахожусь в моей локальной ветви A, и я хочу принудительно отправить локальную ветвь B в исходную ветвь CI, можно использовать следующий синтаксис:

git push --force origin B:C

2
Я узнал, что даже я нахожусь в моем местном отделении B, я все еще должен сделать git push --force origin B:C. В моем случае, кажется, что git push --force origin Cбудет только подтолкнуть от локального мастера к удаленной ветви C, независимо от того, на какой ветви я сейчас работаю. git version 2.3.8 (Apple Git-58)
— Weishi Zeng

12

используйте следующую команду:

git push -f origin master

1
Возможно, дайте больше объяснения о том, почему этот ответ предпочтительнее других, и чем он отличается.
— Адам

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

12
Это так же, как и другие, вы просто изменили положение -fфлага ...
— svelandiag

11

Я действительно рекомендую:

  • толкать только в основной репо

  • убедитесь, что основное репо является чистым репо , чтобы никогда не возникало проблем с рабочим деревом основного репо, которое не синхронизировано с его .gitбазой. Смотрите " Как перенести локальный репозиторий git на другой компьютер? "

  • Если вам нужно внести изменения в основной репозиторий (клон), клонируйте его (на главном сервере), внесите изменения и вернитесь к нему.

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


5

Это было наше решение для замены master в корпоративном хранилище gitHub при сохранении истории.

push -fмастер на корпоративных репозиториях часто отключается, чтобы поддерживать историю ветки. Это решение сработало для нас.

git fetch desiredOrigin
git checkout -b master desiredOrigin/master // get origin master

git checkout currentBranch  // move to target branch
git merge -s ours master  // merge using ours over master
// vim will open for the commit message
git checkout master  // move to master
git merge currentBranch  // merge resolved changes into master

подтолкнуть свою ветку desiredOriginи создать пиар


3

У меня был тот же вопрос, но я наконец понял его. Скорее всего, вам нужно выполнить следующие две команды git (заменив хэш номером редакции git commit):

git checkout <hash>
git push -f HEAD:master
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.