Когда я подумал, что Git уже не может быть сложнее, я открыл для себя git worktree. Либо это синоним поддерева, либо функция, о которой я никогда не знал. Рабочее дерево такое же, как поддерево, или они разные. Если они разные, то чем они отличаются и какую проблему решает worktree?
В чем разница между git-worktree и git-subtree?
Ответы (2)
Они очень разные. Чтобы понять их правильно, давайте определим work-tree (или "рабочее дерево", или "рабочее дерево", или почти любой вариант этих написаний) относительно индекса. и фиксировать.
Вы уже знаете, что коммиты сохраняют моментальные снимки и что каждая фиксация имеет уникальный хэш-идентификатор, который называет эту конкретную фиксацию. Может быть много других имен (например, имена веток и/или тегов) для одного и того же коммита, но есть только один хэш-идентификатор. Вы, вероятно, также знаете, что у коммитов есть метаданные: кто их сделал (имя и адрес электронной почты), когда (отметка времени) и почему (сообщение для git log
для отображения). Каждая фиксация также имеет хэш-идентификатор parent — или, скорее, список родителей, обычно с одной записью. Родительский коммит — это коммит, который идет непосредственно перед этим, чтобы Git мог пройти в обратном направлении по цепочке коммитов, чтобы показать что-то с течением времени. (Фиксация с двумя родительскими хэш-идентификаторами называется объединенной фиксацией. Фиксация без отсутствия родительских хэш-идентификаторов является корневой фиксацией, и хотя бы один в любом непустом репозитории, поскольку перед первым коммитом не было коммитов.)
Все, включая файлы, внутри коммита полностью заморожено на все время. Вы не можете изменить ничего из этого, ни одного бита, и причина этого в том, что хэш-идентификатор на самом деле является криптографической контрольной суммой всего содержимого коммита. Если бы вы каким-то образом изменили всего один бит, контрольная сумма была бы другой, так что это был бы другой коммит с другим хэш-идентификатором.
Это означает, что все файлы, хранящиеся внутри любого коммита, замораживаются. Они также сжаты в специальный формат только для Git, который может прочитать только Git. Это отлично подходит для истории, но как мы когда-нибудь закончим работу? Здесь на сцену выходит рабочее дерево.
Чтобы работать с файлами, нам нужно, чтобы Git скопировал их из коммита. Это возвращает файлам их повседневную форму, где они доступны для чтения всем — редакторам, компиляторам, всем, что есть на вашем компьютере — и, конечно же, доступны для записи/изменения. Место, где вы работаете с вашими файлами, является вашим рабочим деревом.
Таким образом, между текущим коммитом (выбранным) и рабочим деревом есть две копии каждого файла: замороженная копия в коммите и полезная копия в дерево работы.
На этом можно было бы остановиться на Git и других системах контроля версий, таких как Mercurial (см. mercurial) сделайте именно это. Но по разным причинам (многие из них связаны с «очень быстрой работой») Git добавляет третью копию каждого файла. Эта третья копия попадает в то, что Git называет по-разному: индекс, индекс или кеш. (Какое имя вы видите, зависит от того, кто или какая часть Git выполняет вызов.) Файлы в индексе имеют почти ту же форму, что и в коммитах, за исключением того, что в индексе они не замороженный. Они более готовы к заморозке или «слякоти», если хотите.
Индекс также хранит вкладки в рабочем дереве, так что они тесно связаны друг с другом: индекс «знает», что находится в рабочем дереве, а если нет — если аспект кэширования индекса устарел — он знает это, что помогает Git быстро выяснить, что изменилось, если что-то изменилось. Более того, когда вы запускаете git commit
, Git даже не просматривает рабочее дерево (кроме добавления комментариев к файлу, который вы будете редактировать для сообщения журнала). Он просто замораживает готовые файлы из индекса, где индекс получает свое имя staging area, чтобы сделать новую фиксацию.
В конце концов, когда вы работаете с фиксацией в Git, у вас всегда есть три активных копии:
- Копия коммита
HEAD
заморожена и доступна только для Git. - Копия индекса слащавая: только для Git, но не совсем замороженная. Изначально он соответствует копии
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 subtree
представляет собой причудливый сценарий оболочки, который позволяет вам извлечь часть вашего существующего репозитория в новый, который вы будете использовать в другом месте, или взять существующий, который вы используете в другом месте, и попытаться вернуть что-то из него. Так что это передача из одного репозитория в другой — или, по крайней мере, настройка для него в некоторых случаях.
(RomainValeri также упомянул стратегию слияния git-merge-subtree
, которая как бы связана со git subtree
тем, что она направлена на обработку переименования поддерева в один или два из трех входов для слияния.)
Эти понятия не похожи, и сравнение кажется странным, если не считать похожего звучания.
git worktree
(doc) — это правильная команда git (тогда как поддерево — это вклад, спасибо Chris для информации), который в основном помогает вам управлять несколькими рабочими деревьями в одном и том же репо с помощью нескольких дополнительных подкоманд (list
, add
и т. д. .).
Принимая во внимание, что поддерево, в дополнение к вышеупомянутому вкладу, является одним из доступных объединить стратегии.
Но, как я уже сказал, эти два понятия особо не связаны, даже если один из них может использовать слияние поддеревьев в контексте репозитория с несколькими рабочими деревьями... что, как я полагаю, не является частью вашего вопрос.