Я использую поддерево Git с парой проектов, над которыми я работаю, чтобы разделить между ними некоторый базовый код. Базовый код часто обновляется, и обновления могут происходить в любом из проектов, и в конечном итоге все они будут обновлены.
Я столкнулся с проблемой, когда git сообщает, что мое поддерево обновлено, но нажатие отклоняется. Например:
#! git subtree pull --prefix=public/shared project-shared master
From github.com:****
* branch master -> FETCH_HEAD
Already up-to-date.
Если я нажму, я должен получить сообщение, что толкать нечего ... Верно? ВЕРНО? :(
#! git subtree push --prefix=public/shared project-shared master
git push using: project-shared master
To git@github.com:***
! [rejected] 72a6157733c4e0bf22f72b443e4ad3be0bc555ce -> master (non-fast-forward)
error: failed to push some refs to 'git@github.com:***'
hint: Updates were rejected because the tip of your current branch is behind
hint: its remote counterpart. Merge the remote changes (e.g. 'git pull')
hint: before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.
Что могло быть причиной этого? Почему толкать не удается?
git
git-subtree
Матеуш
источник
источник
--rejoin
для ускорения выталкивания поддерева. Когда я вручную выполняю push-запускsubtree split --rejoin
поддерева, ветвь разделенного поддерева имеет историю только до последнего повторного присоединения, когда обычно она содержит всю историю поддерева. Для меня это непосредственная причина ошибки, связанной с перемоткой вперед. Я все еще не уверен, почему разделение поддерева создает усеченную историю.Ответы:
Я нашел ответ в этом комментарии блога https://coderwall.com/p/ssxp5q
источник
error: unknown option 'prefix'
heroku
иpythonapp
есть в ответе. Перевод этого с языка, специфичного для Heroku:git push <your subtree's origin> `git subtree split --prefix=Path/to/subtree master`:master --force
В Windows вложенная команда не работает:
Вы можете сначала запустить вложенный бит:
Это (после большого количества чисел) вернет токен, например
Используйте это в содержащей команду, например:
источник
git subtree
что раньше это не команда. После использования вашего решения я смог развернуть папку на heroku вместо всего моего репоИспользуйте
--onto
флаг:[РЕДАКТИРОВАТЬ: к сожалению
subtree push
, не пересылается--onto
на нижележащийsplit
, поэтому операция должна выполняться двумя командами! После этого я вижу, что мои команды идентичны командам в одном из других ответов, но объяснение другое, поэтому я все равно оставлю его здесь.]Или, если вы не используете bash:
Я часами просматривал исходный код git-subtree, чтобы понять это, так что надеюсь, вы это оцените;)
subtree push
начинается с запускаsubtree split
, который переписывает вашу историю коммитов в формат, который должен быть готов к отправке. Таким образом, он удаляетpublic/shared/
переднюю часть любого пути, в котором он есть, и удаляет любую информацию о файлах, у которых его нет. Это означает, что даже если вы вытащите без сжатия, все коммиты суб-репозитория в восходящем направлении игнорируются, поскольку они называют файлы своими пустыми путями. (Коммиты, которые не касаются файлов вpublic/shared/
, или коммиты слияния, которые идентичны родительским, также сворачиваются. [РЕДАКТИРОВАТЬ: Кроме того, с тех пор я обнаружил некоторое обнаружение сквоша, поэтому теперь я думаю, что это только в том случае, если вы вытащили несжатый, а затем упрощенное свертывание фиксации слияния, описанное в еще одном ответе, позволяет выбрать несжатый путь и отбросьте сжатый путь.]) В результате материал, который он пытается отправить, в конечном итоге содержит любую работу, которую кто-то привязал к текущему репозиторию хоста, из которого вы нажимаете, но не рабочие люди, привязанные непосредственно к суб-репозиторию или через другой хост репозиторий.Однако, если вы используете
--onto
, то все восходящие коммиты записываются как ОК для использования дословно, поэтому, когда процесс перезаписи сталкивается с ними как с одним из родителей слияния, он хочет переписать, он сохранит их, а не пытается их переписать. обычным способом.источник
git remote -v
.--onto
опция помогает git идентифицировать коммиты, которые уже находятся во вспомогательном репозитории.Для приложения типа «GitHub pages», где вы развертываете поддерево «dist» в ветке gh-pages, решение может выглядеть примерно так
Я упоминаю об этом, поскольку он немного отличается от приведенных выше примеров heroku. Вы можете видеть, что моя папка "dist" существует в главной ветке моего репо, а затем я нажимаю ее как поддерево в ветку gh-pages, которая также находится в источнике.
источник
Я уже сталкивался с этой проблемой раньше, и вот как я ее решил.
Я обнаружил, что у меня есть ветка, которая не была прикреплена к локальной основной ветке. Эта ветка существует и просто висит в пустоте. В вашем случае это, вероятно, называется
project-shared
. Предполагая, что это так, и когда вы делаете это,git branch
вы видите локальнуюproject-shared
ветку, тогда вы можете « добавлять » новые коммиты в свою существующуюproject-shared
ветку, выполнив:git subtree split --prefix=public/shared --onto public-shared --branch public-shared
Как я понял, я
git subtree
начну создавать новую ветку--onto
, в данном случае это локальнаяpublic-shared
ветка. Затем ветвь означает создание ветки, которая просто заменяет старуюpublic-shared
ветку.Это сохранит весь предыдущий SHA
public-shared
ветки. Наконец, вы можете сделатьgit push project-shared project-shared:master
Предполагая, что у вас есть
project-shared
пульт; это подтолкнет локальное зависание вproject-shared
ветке void кmaster
ветке удаленногоproject-shared
.источник
Это из-за ограничений исходного алгоритма. При обработке коммитов слияния исходный алгоритм использует упрощенные критерии для отсечения неродственных родителей. В частности, он проверяет, есть ли родитель, у которого такое же дерево. Если такой родитель найден, он свернет фиксацию слияния и вместо нее будет использовать родительскую фиксацию, предполагая, что у других родителей есть изменения, не связанные с поддеревом. В некоторых случаях это может привести к удалению частей истории, в которых есть фактические изменения в поддереве. В частности, он отбрасывает последовательности коммитов, которые касаются поддерева, но приводят к тому же значению поддерева.
Давайте посмотрим на пример (который вы можете легко воспроизвести), чтобы лучше понять, как это работает. Рассмотрим следующую историю (формат строки: коммит [дерево] тема):
В этом примере мы разделяем
dir
. КоммитыD
иE
имеют то же деревоz
, потому что у нас есть фиксацияC
, которая отменила фиксациюB
, поэтомуB-C
последовательность ничего не делает дляdir
даже если в ней есть изменения.Теперь займемся разделением. Сначала мы разбиваем на коммит
C
.Затем мы разбиваем на коммит
E
.Да, мы потеряли две фиксации. Это приводит к ошибке при попытке подтолкнуть второе разбиение, поскольку у него нет тех двух коммитов, которые уже попали в источник.
Обычно вы можете допустить эту ошибку, используя
push --force
, поскольку отброшенные коммиты обычно не содержат в себе важной информации. В долгосрочной перспективе ошибку необходимо исправить, чтобы в истории разделения действительно были все коммиты, которые касаютсяdir
, как и ожидалось. Я ожидаю, что исправление будет включать более глубокий анализ родительских коммитов на предмет скрытых зависимостей.Для справки, вот часть исходного кода, отвечающая за поведение.
copy_or_skip() ... for parent in $newparents; do ptree=$(toptree_for_commit $parent) || exit $? [ -z "$ptree" ] && continue if [ "$ptree" = "$tree" ]; then # an identical parent could be used in place of this rev. identical="$parent" else nonidentical="$parent" fi ... if [ -n "$identical" ]; then echo $identical else copy_commit $rev $tree "$p" || exit $? fi
источник
Ответ Эрика Вудраффа мне не помог, но помогло следующее:
Обычно я использую команду git subtree pull с параметром --squash. Похоже, это действительно усложнило согласование, поэтому мне нужно было выполнить извлечение поддерева без сжатия на этот раз, разрешить некоторые конфликты и затем нажать.
Надо добавить, что раздавленная тяга не выявила конфликтов, все в порядке.
источник
Другое [более простое] решение - продвинуть головку пульта ДУ, сделав еще одну фиксацию, если можете. После того, как вы поместите эту расширенную голову в локальное поддерево, вы снова сможете вытолкнуть ее из нее.
источник
Вы можете принудительно отправить локальные изменения в удаленное репозиторий поддерева
источник
Быстрый PowerShell для пользователей Windows на основе решения Криса Джордана
источник
Вот что я написал на основе того, что сказал @entheh.
источник
Была и эта проблема. Вот что я сделал, основываясь на самых популярных ответах:
Дано:
Введите это:
Обратите внимание, что токен, который выводится командой «git subtree push», используется в «git push».
источник