Принудительно «git push» перезаписывать удаленные файлы

769

Я хочу отправить свои локальные файлы и разместить их на удаленном репо, не сталкиваясь с конфликтами слияния. Я просто хочу, чтобы моя локальная версия имела приоритет над удаленной.

Как я могу сделать это с Git?

opensas
источник
106
Не git push origin --forceработал у вас?
Неясно, хотите ли вы переопределить только файлы .git или связанную с ними рабочую копию. Если это git-репозиторий, то git push - это ответ. Если вы хотите обновить удаленную рабочую копию, вы должны использовать ловушку после получения
Pierre-Olivier Vares
@ Майк, который почему-то работает на меня ... интересно, что
Вероятная причина, принудительное принудительное нажатие не работает, состоит в том, что он мог быть явно отключен в удаленном репо (чтобы гарантировать, что ничего не будет потеряно из-за идиотских и / или злостных участников): используйте, config receive.denyNonFastforwardsчтобы узнать.
Фрэнк

Ответы:

1089

Вы должны иметь возможность принудительно установить локальную ревизию в удаленном репо, используя

git push -f <remote> <branch>

(например git push -f origin master). Уход <remote>и <branch>заставит толкнуть все локальные ветви, которые установили --set-upstream.

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

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

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

Скажем, я клонировал ваш репо и добавил несколько коммитов так:

            D ---- E тема
           /
A ---- B ---- C разработка

Но позже в developmentветке появляется буква a rebase, которая заставляет меня получать сообщение об ошибке, например, при запуске git pull:

Распаковка предметов: 100% (3/3), готово.
Из <репо-местоположения>
 * развитие филиала -> FETCH_HEAD
Авто-слияние <файлы>
КОНФЛИКТ (контент): конфликт слияния в <местоположениях>
Автоматическое объединение не выполнено; исправить конфликты, а затем зафиксировать результат.

Здесь я мог бы исправить конфликты и commit, но это оставило бы меня с действительно ужасной историей коммитов:

       C ---- D ---- E ---- F тема
      / /
A ---- B -------------- C 'разработка

Это может показаться заманчивым в использовании, git pull --forceно будьте осторожны, потому что это оставит вас с мельчайшими коммитами:

            D ---- E тема

A ---- B ---- C 'разработка

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

            D '--- E' тема
           /
A ---- B ---- C 'разработка

Обновление 3: Вы также можете использовать эту --force-with-leaseопцию в качестве «более безопасного» принудительного толчка, как упомянул Кексейк в своем ответе :

Принудительное нажатие с помощью «аренды» позволяет принудительно выполнить принудительное нажатие, если на удаленном компьютере появятся новые коммиты, которых вы не ожидали (технически, если вы еще не загрузили их в ветку удаленного отслеживания), что полезно, если Вы не хотите случайно перезаписывать чужие коммиты, о которых вы даже не знали, и просто хотите переписать свои собственные:

git push <remote> <branch> --force-with-lease

Вы можете узнать больше о том, как использовать --force-with-lease, прочитав любое из следующего:

Тревор Норрис
источник
5
Поскольку это выбранный ответ, я буду комментировать здесь. Использование силы не является проблемой при работе самостоятельно. Например, мой облачный хост начинается с собственного git. Если я работаю локально и создаю проект и хочу разместить его на своем облачном хосте (OpenShift), у меня есть два отдельных проекта git. Мой местный и мой OpenShift один. Я получаю свой локальный файл так, как мне нравится, но теперь хочу просмотреть его на моем OpenShift. Затем вы впервые нажимаете на OpenShift, используя -fфлаг. По сути, положить ваш локальный мерзавец на OpenShift.
Уэйд
128

Вы хотите, чтобы заставить толкать

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

Если вы хотите более подробное объяснение каждой из следующих команд, то смотрите мой раздел подробностей ниже. У вас есть 4 различных варианта принудительного нажатия с помощью Git:

git push <remote> <branch> -f
git push origin master -f # Example

git push <remote> -f
git push origin -f # Example

git push -f

git push <remote> <branch> --force-with-lease

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

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

Сила толкания детали

Указание пульта и ветки

Вы можете полностью указать конкретные ветки и пульт. -fФлаг короткая версия--force

git push <remote> <branch> --force
git push <remote> <branch> -f

Опуская ветку

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

git push <remote> --force

в то время как до версии 2.0 новые репозитории будут иметь настройки по умолчанию для продвижения нескольких локальных веток. Настройки в вопросе являются remote.<remote>.pushи push.defaultнастройки (см . Ниже)

Опуская пульт и филиал

Когда и удаленный, и ветвь опущены, поведение just git push --forceопределяется push.defaultнастройками Git config:

git push --force
  • Начиная с Git 2.0, настройка по умолчанию, в simpleосновном будет просто выдвигать вашу текущую ветвь к ее восходящему удаленному аналогу. Пульт дистанционного управления определяется branch.<remote>.remoteнастройками филиала , и в противном случае по умолчанию используется исходное хранилище.

  • До Git версии 2.0, настройка по умолчанию matching, в основном, просто выталкивает все ваши локальные ветки в ветки с одинаковым именем на пульте (по умолчанию это источник).

Вы можете прочитать больше push.defaultнастроек, прочитав git help configили онлайн версию страницы руководства git-config (1) .

Сила толкать более безопасно с --force-with-lease

Принудительное нажатие с помощью «аренды» позволяет принудительно выполнить принудительное нажатие, если на удаленном компьютере появятся новые коммиты, которых вы не ожидали (технически, если вы еще не загрузили их в ветку удаленного отслеживания), что полезно, если Вы не хотите случайно перезаписывать чужие коммиты, о которых вы даже не знали, и просто хотите переписать свои собственные:

git push <remote> <branch> --force-with-lease

Вы можете узнать больше о том, как использовать --force-with-lease, прочитав любое из следующего:

Сообщество
источник
Вы правы, но это действительно должно использоваться только в исключительных ситуациях.
Скотт Берревоэтс
1
@ScottBerrevoets « Я бы предпочел, чтобы выдвинуть то, что у меня есть, и позволить ему перезаписывать удаленно, а не интегрировать. » Я дал ОП именно то, что он просил.
Я знаю, но ОП может не знать о последствиях этого. Вы технически ответили на вопрос, но я думаю, что предупреждение не делать этого не является неуместным.
Скотт Берревоэтс
1
@ScottBerrevoets Я пытаюсь, чтобы модератор включил мой ответ в канонический, потому что я упоминаю новую --force-with-leaseопцию;)
1
К вашему сведению: объединено со stackoverflow.com/questions/24768330/…
Shog9
32

Другой вариант (чтобы избежать принудительного толчка, который может быть проблематичным для других участников):

  • разместите ваши новые коммиты в отдельной ветке
  • сбросить masterнаorigin/master
  • объединить вашу выделенную ветку с masterпостоянным сохранением коммитов из выделенной ветви (то есть создать новые ревизии, поверх masterкоторых будет отражаться ваша выделенная ветка).
    Смотрите " git command для создания одной ветви как другой ", чтобы узнать стратегии для имитации a git merge --strategy=theirs.

Таким образом, вы можете выдвинуть мастер на дистанцию ​​без необходимости что-либо форсировать.

VonC
источник
Чем результат отличается от «push -force»?
alexkovelsky
6
@alexkovelsky Любой принудительный толчок переписывает историю, вынуждая других пользователей репо сбрасывать свои собственные локальные репо, чтобы соответствовать вновь выдвинутым коммитам. Этот подход только создает новые коммиты и не требует принудительного толчка.
VonC
1
Я предлагаю добавить в свой ответ заголовок: «Вы не хотите насильно толкать» :)
alexkovelsky
@alexkovelsky Хороший вопрос. Я отредактировал ответ соответственно.
VonC
4

git push -f немного деструктивен, потому что он сбрасывает все удаленные изменения, которые были сделаны кем-то еще в команде. Более безопасный вариант: {git push --force-with-lease}.

То, что делает {--force-with-lease}, - отказывается обновлять ветку, если мы не ожидаем того состояния; т.е. никто не обновил ветку вверх по течению. На практике это работает, проверяя, что ссылка на исходный код - это то, что мы ожидаем, потому что ссылки - это хэши, и неявно кодируют цепочку родителей в их значение. Вы можете сказать {--force-with-lease}, что именно нужно проверять, но по умолчанию проверит текущую удаленную ссылку. На практике это означает, что, когда Алиса обновляет свою ветвь и передает ее в удаленный репозиторий, указательная головка ветки будет обновлена. Теперь, если Боб не извлекает данные из пульта, его локальная ссылка на пульт будет устаревшей. Когда он отправляет push, используя {--force-with-lease}, git проверяет локальный ref на новом пульте и отказывается форсировать push. Фактически {--force-with-lease} позволяет принудительно нажимать, только если в это время никто другой не выдвигал изменения на удаленное устройство. Это {--force} с пристегнутым ремнем безопасности.

Ландо Ке
источник
3

Работает для меня:

git push --set-upstream origin master -f
Джитиш ПН
источник
0

Простые шаги с помощью черепахи

GIT дает локальные файлы коммит и помещает их в репозиторий git.

Шаги:

1) тайник меняет имя тайника

2) тянуть

3) тайник поп

4) зафиксируйте 1 или более файлов и дайте изменения фиксации, описание задайте автора и дату

5) толкать

Нагнат Мунгаде
источник