git push --force-with-аренды против --force

183

Я пытаюсь понять разницу между

git push --force

и

git push --force-with-lease

Я предполагаю, что последний только отправляет на удаленный, если удаленный не имеет коммитов, которых нет в локальной ветви ?

Александр Миллс
источник
"локальная удаленная ветка отслеживания ". В основном это означает, что пульт должен выглядеть так, как ожидает ваш клиент. git help pushесть сценарии использования, объясняющие его назначение (в основном, чтобы вы не потеряли изменения, которые кто-то только что подтолкнул). Что мне немного неясно, так это то, как работает ветка удаленного отслеживания. Но, по-видимому, обычно нужно будет выглядеть именно так, как он выглядел в прошлый раз, когда вы делали коммиты fetchили pullбез них.
zzxyz
4
@zzxyz: фактическая реализация --force-with-leaseаналогична инструкциям сравнения и замены на современных процессорах: тот, кто хочет, чтобы произошел обмен, предоставляет ожидаемое значение и новое значение. Система, выполняющая обмен, сравнивает ожидаемое значение с истинным текущим значением и выполняет обмен, если и только если оба значения равны. С git pushожидаемым значением будет то, что находится в имени удаленного отслеживания, например, git push --force-with-lease origin Xотправляет ваше собственное origin/Xвместе с новым желаемым значением; originGit говорит вам, если он сделал обмен или нет.
Торек
1
Если Git at originсделал обмен, вы сделали. Если нет, вы можете запустить, git fetch originчтобы подобрать новое текущее значение, переработать ваши изменения, если необходимо, и выполнить еще одно принудительное сравнение и обмен, чтобы повторить попытку.
Торек

Ответы:

173

force перезаписывает удаленную ветку вашей локальной веткой.

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

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

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

Я уверен, что вы посмотрели на документы, но здесь может быть более многословное объяснение:

https://git-scm.com/docs/git-push

chevybow
источник
39

Ищите ответный рисунок из достоверных и / или официальных источников.

«Сравнение и обмен», упомянутые Тореком в комментариях и в его другом ответе , далее проиллюстрированы источниками самого Git .

последний только подталкивает к удаленному, если у удаленного нет коммитов, которых нет у локальной ветви?

Эта функция была введена в этом коммите (декабрь 2013, Git v1.8.5-rc0)

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

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

Итак, «аренда» означает:

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

В источниках до сих пор упоминается «cas»:

  • Эта опция первоначально называлась « cas» (для «сравнивать и менять»), название, которое никому не понравилось, потому что оно было слишком техническим.
  • Вторая попытка назвала его «lockref» (потому что это концептуально похоже на нажатие после взятия блокировки), но слово «блокировка» было ненавистным, потому что оно подразумевало, что оно может отклонить push другими, что не работает так, как эта опция.
  • Этот раунд называет это «силой с арендой».
    Вы предполагаете, что взяли в аренду аренду рефери, когда выбирали, чтобы решить, какой должна быть перебазированная история, и вы можете отменить ее, только если аренда не была нарушена.

Итак: « git push --force-with-leaseпротив --force»

Как я упоминал в « push --force-with-leaseпо умолчанию », как упоминается в Git 2.13 (Q2 2017), эту опцию --force-with-leaseможно игнорировать, если выполняется фоновый процесс (например, тот, который вы найдете в IDE с плагином Git) git fetch origin.
В этом случае --forceпреобладает.

VonC
источник
29

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

Например. У нас есть проект с веткой функций, над которой будут работать Алиса и Боб. Они оба клонируют этот репозиторий и начинают работу. Алиса вначале завершает свою часть функции и переносит ее в главный репозиторий. Это все хорошо. Боб также заканчивает свою работу, но, прежде чем поднять ее, он замечает, что некоторые изменения были объединены с мастером. Желая сохранить чистое дерево, он выполняет ребаз против ветки master. Конечно, когда он пойдет, чтобы подтолкнуть эту перебазированную ветвь, она будет отклонена. Однако, не понимая, что Алиса уже подтолкнула ее работу, он выполняет push -force. К сожалению, это удалит все записи об изменениях Алисы в центральном хранилище.

То, что делает --force-with-lease - отказывается обновлять ветку, если мы не ожидаем того состояния; т.е. никто не обновил ветку вверх по течению. На практике это работает путем проверки того, что ссылка на исходный код - это то, что мы ожидаем, потому что ссылки являются хешами и неявно кодируют цепочку родителей в их значение.

Вот хороший пост о git push --force и git push --force-with-lease.

Шакил
источник
2
чего я не понимаю - если ты сделаешь ребаз с мастером, то у тебя получится пушить без --force-with-lease ? Зачем --force-with-leaseнужно после ребазинга с мастером?
Александр Миллс
3
@AlexanderMills там могут быть некоторые возможности, которые вызывают проблемы. Если вы последний человек, который подтолкнул это к мастеру, то проблем нет, но есть другой человек, который работает с другой задачей, тогда это может вызвать серьезные проблемы. Скажем, сначала A - B - C был в мастере, сначала Алиса сделала это A - B - C - D - E, и в то же время Боб сделал это A - B - C - F - G. Если Алиса - последний толчок человека в мастер после сброса A - B - C - D - E - F - G не вызовет никаких проблем, но другой человек Том попытается нажать A - B - C - D - E - R в то же время в мастерской катастрофе произойдет !! !
Шакил
3
--forceне теряет коммитов, он просто отрывает их. Они могут быть воскрешены с помощью своих хэшей, например, в предположении git checkout <SHA>или git reset --hard <SHA>, при условии, что сопровождающий удаленного репо не выполняет никаких операций GC или отсечения.
Кит Рассел
1
«push -force для git настоятельно не рекомендуется, так как он может уничтожить другие коммиты, уже переданные в общий репозиторий». Это утверждение основано на мнениях. Выполнение принудительного нажатия является частью обычного рабочего процесса проверки кода git rebase. Также, как уже упоминалось, вы можете получить коммиты даже после этого.
Этьен
9

Предполагая, что любые перехваты предварительного получения на сервере принимают push, это всегда будет успешным:

git push --force

Принимая во внимание, что это выполняет определенную проверку на стороне клиента перед продолжением:

git push --force-with-lease

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

  1. Выясните свою текущую ветку.

  2. Беги git for-each-ref refs/remotes. Обратите внимание на идентификатор фиксации, который, по мнению вашего git-клиента, соответствует исходному состоянию вашей текущей ветки.

Например, если вы находитесь на ветке "foo", обратите внимание на идентификатор фиксации, связанный с "refs / remotes / origin / foo".

  1. Определите фактический идентификатор фиксации удаленной ветви на вышестоящем git-сервере прямо сейчас.

  2. Разрешить «git push» можно только в том случае, если идентификаторы коммитов, извлеченные вами из шагов 2 и 3, согласуются. Другими словами, продолжайте, только если представление вашего местного git-клона о upstream согласуется с фактическим upstream.

Здесь есть печальное следствие: поскольку git fetchвсе ссылки в разделе «refs / remotes / origin / *» обновляются до последних версий, эта комбинация команд практически идентична git push --force:

git fetch

# The command below behaves identically to "git push --force"
# if a "git fetch" just happened!

git push --force-with-lease

Чтобы обойти эту врожденную слабость, git push --force-with-leaseя стараюсь никогда не бежать git fetch. Вместо этого я всегда запускаю git pull --rebaseвсякий раз, когда мне нужно синхронизировать с апстримом, так как git pullобновляет только одну ссылку под refs / remotes, сохраняя «аренду» --force-with-leaseполезной.

Г. Сильви Дэвис
источник
1
если проверка на стороне клиента, есть ли возможность для состояния гонки? т.е. кто-то еще толкает изменения после проверки, но до принудительного толчка?
Craq
2

Сила с арендой не обязательно безопасна. Это просто работает, как сказала Сильви. Одно замечание: в git ветка - это просто указатель на коммит. И коммиты указывают на ноль или более родительских коммитов. Даже если вы полностью изменили ветку с помощью жесткого git-сброса и принудительного пуша или пуша с принудительной арендой без необходимости, это не обязательно является большой проблемой. Вы можете использовать свой локальный git reflog, чтобы увидеть, как ваш локальный совет по веткам (Где был HEAD в то время?) Изменился, сбросить и снова нажать на ветку. Тогда вы потеряете только новые коммиты в удаленной ветке, но даже они могут быть восстановлены членами команды.

Рыбы
источник