Git: исправление репо с веткой и его удаленного на разных ветках - PullRequest
0 голосов
/ 17 февраля 2020

Понятия не имею, как это произошло, но у меня репо git в состоянии следующего типа:

A--B--C--D  master
    \
     E--F   origin/master

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

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

Какой самый чистый способ это прояснить?

1 Ответ

1 голос
/ 17 февраля 2020

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

В этом случае git push --force origin master будет достаточно. Будьте очень уверены, у вас все в порядке с origin/master в вашем хранилище и master в (отдельном) Git хранилище по origin, так как вы больше не можете найти коммит F.

(Ваш собственный репозиторий будет помнить оба коммита E и F в течение некоторого времени под именем reflog origin/master@{<em>number</em>}, пока вы сохраняете свой собственный репозиторий не поврежден, вы все равно можете получить его обратно, если он окажется устаревшим, но в какой-то момент он действительно будет удален. сервер может вообще не иметь reflogs и его копию коммитов E и F могут go исчезать относительно быстро - например, в секундах, или часах, или всего за несколько дней.)

Как и почему это работает

Каждый * Репозиторий 1222 * имеет свои собственные имена ветвей, которые являются полу-частными для этого конкретного репозитория Git. На компьютере, который вы называете origin, есть хранилище с именем ветви master.

Ваши имена для удаленного отслеживания, 1 например origin/master, это ваш Git метод запоминания того, что некоторые другие Git имеют в качестве ответвлений имен. В этом случае ваша origin/master является вашей Git памятью origin master.

Когда у вас есть Git, вызовите их Git через git fetch или git push, два Gits имеют стартовый разговор. Это немного отличается для fetch и pu sh, но вы можете наблюдать, что git fetch будет сам наблюдателем, используя git ls-remote. Просто запустите git ls-remote origin (или оставьте origin в качестве значения по умолчанию, как правило, origin в любом случае): ваш Git выдаст другие Git ветви, тег и другие имена что это в списке. Это первая часть git fetch: ваши Git звонят по телефону Git и получают этот список.

Когда вы используете git fetch, ваш Git использует этот список для запроса Git для любых коммитов и других внутренних Git объектов, которые у них есть, которых у вас нет, которые ваш Git хотел бы иметь. Например, если у вас еще не было коммита F, и вместо этого ваш origin/master запомнил коммит B или E, и они имеют коммит F в качестве master, ваш Git скажет : Я бы хотел сделать коммит F, пожалуйста , и они добавили бы это в список коммитов для отправки. Затем они предложили бы коммит E - Git должен предложить родителям каждого коммита - и ваш Git либо скажет нет, спасибо, у меня уже есть или да, пожалуйста (в этом случае они предложат B, E родителя и т. Д.).

Затем процесс их получения объединяет все, что необходимо для получения этих коммитов. на ваш Git - это где вы увидите counting objects и compressing objects - и отправит это снова. Ваш Git расширяет те, чтобы у вас был правильный набор коммитов и их данных, а затем создает или обновляет ваш origin/master на основе идентификатора ha sh, хранящегося в их master: сейчас что вы определенно имеете коммит F, ваш Git может заставить ваш origin/master указывать на него.

Следовательно, если вы в любой момент выполните:

git fetch origin

- это форма команды «достань мне все» - ваш Git вызовет их Git и получит предварительный список «все». Два Гита выяснят, что нужно получить вашему Git, и передадут его вашему Git. Затем ваш Git создаст или обновит все ваши имена для удаленного отслеживания на основе всех их имен филиалов.

Когда вы используете git push, то есть настолько близко, насколько Git достигает противоположности fetch - пара push и fetch, а не push и pull из-за исторической ошибки 2 - аналогичный процесс происходит, но есть два ключевых различия:

  • Ваш Git отправляет, а не получает. (Ваш Git по-прежнему выбирает, что отправлять, и "должен предложить родитель, если отправляет коммит" все еще сохраняется, и так далее, но с git fetch, их Git отправлено и ваш Git получено.)

  • В конце, вместо некоторого Git обновления какого-то «имени удаленного слежения», ваш Git просит (вежливо) или командует (принудительно) свои Git до установить некоторые его ветви имен. 3

Если вы попросите или прикажете им установить их master, и они подчиняются, ваш Git теперь знает, что их master установлен на ваш sh ID, который вы указали, поэтому ваш Git теперь обновляет ваше origin/master имя удаленного слежения.

Когда вы используйте осторожный тип аскании git push origin master, ваш Git отправляет коммиты, которые у вас есть, таких как C и D, а затем вежливо спрашивает их: Пожалуйста, если все в порядке, установите master, чтобы указать D? Они скажут Нет! Если я сделаю это, я забуду коммит F! Эта ошибка возвращается как Git жаргонные слова отклоненные и без ускоренной перемотки вперед , но это просто означает, что они сказали нет, так как это потеряло бы commit F и, следовательно, E.

Но это именно то, что вы хотите, чтобы они сделали. Так что вам просто нужно отправить им убедительную команду: Установите свои master! Они могут все еще отказаться - если у вас нет разрешения, например, - но, конечно, у вас есть разрешение, и в этом случае они будут подчиняться и терять коммит F.

Для git push есть два режима силы: git push --force - древняя версия, а git push --force-with-lease - более современная (так как Git 1.9 или около того) вариант. Разница между ними в том, что --force просто говорит установить , но --force-with-lease говорит: Я думаю, что ваш master - это _____. Если это так, установите _____ и дайте мне знать, что вы сделали; если нет, скажите мне, что я был не прав, и не устанавливайте ваш master в конце концов. Первый пробел заполняется вашим значением Git origin/master: ваша память Git их Git х master. Так что это дает вам возможность быть уверенными, что вы заставляете их выбрасывать именно то, что, как вы думаете, они выбросят.

Если вы единственный пользователь из других Git, нет необходимости в уходе, который добавляет --force-with-lease: то, что вы считаете правильным, является правильным по определению. Но если вы обеспокоены тем, что можете забыть о себе (например, если вы используете два разных ноутбука и не можете вспомнить, какой из них был обновлен), вы можете использовать более красивую проверку сначала-потом-принудительно --force-with-lease. Никогда неправильно использовать --force-with-lease, и за исключением того факта, что старый --force является историческим значением по умолчанию, --force-with-lease действительно должен быть значением по умолчанию.


1 Git называет эти имена веток удаленного слежения , но я решил несколько лет go, что слово branch здесь - бесполезный беспорядок, который создает некоторые дополнительные путаница, поэтому я теперь просто называю их имена для удаленного слежения .

2 Часто после получения коммитов вы хотите интегрировать эти коммиты. Вот что делает git pull: он запускает git fetch до get коммитов, затем запускает вторую команду Git для интегрирования этих коммитов. Вначале это выглядело как правильная естественная гранулярность, поэтому git pull была командой для пользователя, противоположной git push.

Оказывается, однако, что часто важно отделить например, извлекать операцию из операции интегрирования, вставляя какую-то операцию inspect между ними, чтобы выбрать правильную форму интеграции. Mercurial понял это правильно и Git понял это неправильно: в Mercurial hg pull означает, что Git означает git fetch, и вам нужно добавить отдельную операцию или дополнительный флаг к hg pull, чтобы сделать это также сделайте шаг интеграции.

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

...