В чем разница между git-worktree и git-subtree?

Когда я подумал, что Git не может быть более сложным, я обнаружил, что Git Worktree. Либо это синоним поддерева, либо функция, о которой я никогда не знал. Является ли worktree тем же, что и поддерево, или они разные. Если они разные, как они различаются и какую проблему решает worktree?

2 ответа

Решение

Это очень разные. Чтобы понять их правильно, давайте определим рабочее дерево (или "рабочее дерево" или "рабочее дерево" или почти любой вариант этих написаний) относительно индекса и коммитов.

Вы уже знаете, что коммиты сохраняют моментальные снимки, и что каждый коммит имеет уникальный идентификатор хеша, который называет этот конкретный коммит. Для этого же коммита может быть много других имен (например, имен веток и / или тегов), но есть только один хэш-идентификатор. Вы, вероятно, также знаете, что в коммитах есть метаданные: кто их создал (имя и адрес электронной почты), когда (временная метка) и почему (сообщение для git log показывать). Каждый коммит также имеет родительский хэш-идентификатор, или, точнее, список родителей, обычно только с одной записью. Родитель - это коммит, который приходит непосредственно перед этим, так что Git может пройти через цепочку коммитов, чтобы показать вещи с течением времени. (Коммит, который имеет два родительских хеш-идентификатора, является коммитом слияния. Коммит без родительских хеш-идентификаторов является корневым коммитом, и в любом непустом репозитории есть по крайней мере один, так как первый сделанный коммит не имеет коммитов до него.)

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

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

Чтобы работать с файлами, нам нужно, чтобы Git скопировал их из коммита. Это возвращает файлы в их повседневную форму, где они могут быть прочитаны всеми - редакторами, компиляторами, чем бы вы ни были на вашем компьютере - и, конечно, доступны для записи / изменения. То место, где вы работаете с вашими файлами, является вашим рабочим деревом.

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

Git может остановиться здесь, и другие системы контроля версий, такие как Mercurial (см. Mercurial), делают именно это. Но по разным причинам - многие из них имеют отношение к "иди очень быстро" - Git добавляет третью копию каждого файла. Эта третья копия входит в то, что Git вызывает, по-разному, в индекс, в промежуточную область или в кэш. (Какое имя вы видите, зависит от того, кто или какая часть Git выполняет вызов.) Файлы в индексе в значительной степени имеют ту же форму, что и в коммитах, за исключением того, что в индексе они не заморожены. Они более готовы к замораживанию или "слякоти", если хотите.

Индекс также хранит вкладки в рабочем дереве, так что они тесно спарены: индекс "знает", что находится в рабочем дереве, или, если нет, - если аспект кэша индекса устарел, - знаетэто, что помогает Git быстро выяснить, что изменилось, если что. Более того, когда вы бежите git commitGit на самом деле даже несмотрит на дерево работы (за исключением добавления некоторых комментариев к файлу, который вы редактируете для своего сообщения журнала). Он просто замораживает готовые к использованию файлы из индекса, где индекс получает свою область подготовки имени, чтобы сделать новый коммит.

В конце концов, когда вы работаете с коммитом в Git, у вас всегда естьтри активные копии:

  • HEADкоммит копия заморожена и только для Git.
  • Индексная копия слякотная: Git-only, но не совсем замороженная. Первоначально это соответствуетHEADскопировать, но вы можете перезаписать егоgit add,
  • Копия рабочего дерева нормальная и плавная, и вы можете делать с ней все что угодно.

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

Это оставляет нам проблему, которую нужно решить: что, если во время работы над чем-то нам нужно срочно исправить какую-то ошибку в какой-тодругой ветке? Мы могли бы сделать еще один клон, и это был традиционный ответ. Если мы не находимся в середине конфликтующего слияния, мы могли бы использовать git stash; это был другой ответ. Одно не очень удовлетворительно, а другое бесполезно, если мы находимся в середине слияния.

Итак, введитеgit worktree add, С помощьюgit worktree addВы можете добавить еще одну пару дерева индекса и работы в ваш существующий репозиторий. Есть одно очень сильное ограничение (по хорошей причине, специфичной для реализации): каждое добавленное рабочее дерево должно быть в своей собственной ветви, или же использовать режим "отсоединенного HEAD". То есть, если ваше основное рабочее дерево находится на ветке feature/short, никакоедобавленное рабочее дерево не может использовать эту ветку. Они могут использовать masterили жеhotfix или же develop, но нет feature/short, (Или они могут использовать отдельный HEAD при любом коммите в любом месте репозитория.)

Когда вы закончите с любым из добавленных, дополнительных рабочих деревьев, вы можете простоrm -rfэто, а затем запуститьgit worktree pruneиз одного из других вторичных рабочих деревьев или основного рабочего дерева, чтобы Git выполнял поиск и не находил добавленное рабочее дерево. Это "разблокирует" любую ветвь, добавленную добавленным рабочим деревом.

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

( RomainValeri также упомянулgit-merge-subtree стратегия слияния, которая как бы связана с git subtree в том смысле, что он предназначен для обработки переименования поддерева в одном или двух из трех входов для слияния.)

Эти понятия не похожи, и сравнение кажется странным, за пределами похожего звучания.

git worktree ( doc) - это правильная команда git (тогда как поддерево является вкладом, спасибо Chris за информацию), которое в основном помогает вам управлять несколькими рабочими деревьями в одном репо с помощью нескольких дополнительных подкоманд (list, add, так далее.).

Принимая во внимание, что поддерево, в дополнение к вышеупомянутому вкладу, является одной из доступных стратегий слияния.

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

Другие вопросы по тегам