Как правильно заставить 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 привел хороший пример толчка для комментариев: конфиденциальные данные . Вы ошибочно просочились данные, которые не должны быть отправлены. Если вы достаточно быстры, вы можете «починить»* его, нажав сверху.

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

cregox
источник
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в основной репо? То, что вы сейчас делаете (если я хорошо это понял) - это форсирование, а затем потеря ваших изменений в «основном» репо. Сначала вы должны объединить изменения локально.

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

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

git push --force origin B:C
IcedDante
источник
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 на другой компьютер? "

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

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

VonC
источник
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и создать пиар

Mihai
источник
3

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

git checkout <hash>
git push -f HEAD:master
Брайан М.
источник