Несколько рабочих каталогов с Git?

Я не уверен, что это что-то поддерживается Git, но теоретически кажется, что он должен работать для меня.

Мой рабочий процесс часто включает в себя мое редактирование файлов в нескольких ветвях одновременно. Другими словами, я часто хочу открыть несколько файлов в одной ветки, пока я редактирую содержимое другого файла в другой ветке.

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

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

Есть ли способ использовать одну .git-папку и иметь два рабочих каталога, поддерживаемых им? Или есть git hardcoded, чтобы в любой момент вывести только один рабочий каталог?

Ответ 1

Git 2.5 предлагает с июля 2015 года замену contrib/workdir/git-new-workdir: git worktree

См. Коммит 68a2e6a Джунио С. Хамано (gitster).

В примечании к выпуску упоминается:

Замена для contrib/workdir/git-new-workdir, который не опирается на символические ссылки и делает совместное использование объектов и ссылок более безопасным, так как заемщики и заемщики знают друг о друге.

Смотрите коммит 799767cc9 (Git 2.5rc2)

Это означает, что теперь вы можете добавить git worktree add <path> [<branch>]

Создать <path> и оформить <branch> в него. Новый рабочий каталог связан с текущим репозиторием, разделяя все, кроме определенных для рабочего каталога файлов, таких как HEAD, index и т.д. В разделе git worktree добавлено:

Git-репозиторий может поддерживать несколько рабочих деревьев, что позволяет вам проверять более одной ветки за раз.
С git worktree add новое хранилище связывается с репозиторием.

Это новое рабочее дерево называется "связанным рабочим деревом", а не "основным рабочим деревом", подготовленным " git init " или " git clone ".
Репозиторий имеет одно основное рабочее дерево (если это не пустой репозиторий) и ноль или более связанных рабочих деревьев.

подробности:

Каждое связанное рабочее дерево имеет собственную директорию sub -d в каталоге репозитория $GIT_DIR/worktrees.
Имя директории private sub -d обычно является базовым именем пути связанного рабочего дерева, возможно, с добавлением номера, чтобы сделать его уникальным.
Например, когда $GIT_DIR=/path/main/.git команда git worktree add/path/other/test-next next создает:

  • связанное рабочее дерево в /path/other/test-next и
  • также создает $GIT_DIR/worktrees/test-next (или $GIT_DIR/worktrees/test-next1 если test-next уже $GIT_DIR/worktrees/test-next1).

В связанном рабочем дереве:

  • $GIT_DIR установлен, чтобы указывать на этот личный каталог (например, /path/main/.git/worktrees/test-next в примере) и
  • $GIT_COMMON_DIR установлен так, чтобы указывать на основное рабочее дерево $GIT_DIR (например, /path/main/.git).

Эти настройки выполняются в файле .git расположенном в верхней директории связанного рабочего дерева.

Когда вы закончите со связанным рабочим деревом, вы можете просто удалить его.
Административные файлы рабочего дерева в хранилище в конечном итоге будут удалены автоматически (см. gc.pruneworktreesexpire в git config), или вы можете запустить git worktree prune в основном или любом связанном рабочем дереве, чтобы очистить любые устаревшие административные файлы.


Предупреждение: все еще есть git worktree "BUGS" git worktree о котором нужно знать.

Поддержка подмодулей является неполной.
НЕ рекомендуется делать несколько проверок суперпроекта.


Примечание: с помощью git 2.7rc1 (ноябрь 2015 г.) вы можете составить список ваших рабочих деревьев.
См совершать bb9c03b, совершать 92718b7, совершают 5193490, совершают 1ceb7f9, совершают 1ceb7f9, совершают 5193490, совершают 1ceb7f9, совершают 1ceb7f9 (08 окт 2015), совершать 92718b7, совершать 5193490, совершают 1ceb7f9, совершают 1ceb7f9 (08 окт 2015), совершают 5193490, зафиксировать 1ceb7f9 (8 октября 2015 г.), зафиксировать 1ceb7f9 (08 октября 2015 г.) и передать ac6c561 (02 октября 2015 г.) Майклом Раппаццо (rappazzo).
(Объединено Junio C Hamano - gitster - в коммите a46dcfb, 26 октября 2015 г.)

worktree: добавить команду ' list '

' git worktree list ' просматривает список рабочих деревьев и выводит подробную информацию о рабочем дереве, включая путь к рабочему дереву, текущую извлеченную ревизию и ветвь, а также, если рабочее дерево пустое.

$ git worktree list
/path/to/bare-source            (bare)
/path/to/linked-worktree        abcd1234 [master]
/path/to/other-linked-worktree  1234abc  (detached HEAD)

Существует также опция формата фарфора.

Формат фарфора имеет строку для каждого атрибута.

  • Атрибуты перечислены с меткой и значением, разделенным одним пробелом.
  • Логические атрибуты (такие как "bare" и "detached") перечислены только в качестве метки и присутствуют только в том случае, если значение равно true.
  • Пустая строка указывает на конец рабочего дерева

Например:

$ git worktree list --porcelain

worktree /path/to/bare-source
bare

worktree /path/to/linked-worktree
HEAD abcd1234abcd1234abcd1234abcd1234abcd1234
branch refs/heads/master

worktree /path/to/other-linked-worktree
HEAD 1234abc1234abc1234abc1234abc1234abc1234a
detached

Примечание: если вы перемещаете папку рабочего дерева, вам необходимо вручную обновить файл gitdir.

См. Коммит 618244e (22 января 2016 г.) и коммит d4cddd6 (18 января 2016 г.) Нгуеном Тай pclouds Дуй (pclouds).
Помогает: Эрик Саншайн (sunshineco).
(Объединено с Junio C Hamano - gitster - в коммите d0a1cbc, 10 февраля 2016 г.)

Новый документ в git 2.8 (март 2016 года) будет включать:

Если вы перемещаете связанное рабочее дерево, вам необходимо обновить файл ' gitdir ' в каталоге ввода.
Например, если связанное рабочее дерево перемещено в /newpath/test-next и его файл .git указывает на /path/main/.git/worktrees/test-next, то обновите /path/main/.git/worktrees/test-next/gitdir для ссылки /newpath/test-next.


Будьте осторожны при удалении ветки: до git 2.9 (июнь 2016 года) вы могли удалить одну из используемых веток в другом рабочем дереве.

Когда git worktree функция " git worktree ", " git branch -d " позволяла удалить ветку, которая была извлечена в другом рабочем дереве.

См. Коммит f292244 (29 марта 2016 г.) Казуки Ямагучи (rhenium).
Помогает: Эрик Саншайн (sunshineco).
(Объединено Junio C Hamano - gitster - в коммите 4fca4e3, 13 апреля 2016 г.)

branch -d: отказать в удалении ветки, которая в данный момент извлечена

Когда ветка проверяется текущим рабочим деревом, удаление ветки запрещено.
Однако, когда ветвь проверяется только другими рабочими деревьями, удаление некорректно завершается успешно.
Используйте find_shared_symref() чтобы проверить, используется ли ветвь, а не просто сравнивать с текущим рабочим деревом HEAD.


Точно так же до git 2.9 (июнь 2016 г.) переименование ветки, отмеченной в другом рабочем дереве, не корректировало символический заголовок в другом рабочем дереве.

См. Коммит 18eb3a9 (08 апреля 2016 г.) и коммит 70999e9, коммит 2233066 (27 марта 2016 г.) Казуки Ямагучи (rhenium).
(Объединено Junio C Hamano - gitster - в коммите 741a694, 18 апреля 2016 г.)

branch -m: обновить все заголовки для каждого рабочего дерева

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

Это текущее поведение, /path/to/wt HEAD не обновляется:

  % git worktree list
  /path/to     2c3c5f2 [master]
  /path/to/wt  2c3c5f2 [oldname]
  % git branch -m master master2
  % git worktree list
  /path/to     2c3c5f2 [master2]
  /path/to/wt  2c3c5f2 [oldname]
  % git branch -m oldname newname
  % git worktree list
  /path/to     2c3c5f2 [master2]
  /path/to/wt  0000000 [oldname]

Этот патч исправляет эту проблему, обновляя все соответствующие заголовки рабочего дерева при переименовании ветки.


Механизм блокировки официально поддерживается git 2.10 (3 квартал 2016 г.)

См. Коммит 080739b, коммит 6d30862, коммит 58142c0, коммит 346ef53, коммит 346ef53, коммит 58142c0, коммит 346ef53, коммит 346ef53 (13 июня 2016 г.) и коммит 984ad9e, коммит 6835314 (03 июня 2016 г.) от pclouds Thái Ngọc Duy (pclouds).
Предложил: Эрик Саншайн (sunshineco).
(Объединено Junio C Hamano - gitster - в коммите 2c608e0, 28 июля 2016 г.)

git worktree lock [--reason <string>] <worktree>
git worktree unlock <worktree>

Если связанное рабочее дерево хранится на переносном устройстве или общем сетевом ресурсе, который не всегда монтируется, вы можете предотвратить git worktree lock его административных файлов, git worktree lock команду git worktree lock, дополнительно указав --reason чтобы объяснить, почему рабочее дерево заблокировано.,

<worktree>: если последние компоненты пути в пути рабочего дерева уникальны среди рабочих деревьев, его можно использовать для идентификации рабочих деревьев.
Например, если вам нужно только рабочие деревья в " /abc/def/ghi " и " /abc/def/ggg ", то " ghi " или " def/ghi " достаточно, чтобы указать на предыдущее рабочее дерево.


В Git 2.13 (второй квартал 2017 года) добавлена опция lock в коммите 507e6e9 (12 апреля 2017 года) от Nguyễn Thái Ngọc Duy (pclouds).
Предложил: Дэвид Тейлор (dt).
peff: Джефф Кинг (peff).
(Объединено Junio C Hamano - gitster - в коммите e311597, 26 апреля 2017 г.)

Разрешить заблокировать рабочее дерево сразу после его создания.
Это помогает предотвратить git worktree add; git worktree lock между " git worktree add; git worktree lock " и " git worktree prune ".

Итак, git worktree add' --lock является эквивалентом git worktree lock git worktree add после git worktree add, но без условия гонки.


Git 2. 17+ (Q2 2018) добавляет git worktree move git worktree remove/git worktree remove: см. Этот ответ.


В Git 2.19 (Q3 2018) добавлена опция " --quiet ", чтобы сделать " git worktree add " менее многословным.

См. Коммит 371979c (15 августа 2018 г.) Элии Пинто (devzero2000).
При поддержке: Мартин Агрен, Дуй Нгуен (pclouds) и Эрик Саншайн (sunshineco).
(Объединено с Junio C Hamano - gitster - в коммите a988ce9, 27 августа 2018 г.)

worktree: добавить --quiet

Добавьте опцию ' --quiet ' в git worktree, как и для других команд git.
" add " - единственная команда, на которую она влияет, поскольку все остальные команды, кроме " list ", в настоящее время по умолчанию молчат.


Обратите внимание, что " git worktree add " используется для "поиска доступного имени с помощью stat, а затем mkdir ", которое склонно к гонке.
Это было исправлено в Git 2.22 (Q2 2019) с использованием mkdir и реакцией на EEXIST в цикле.

См. Коммит 7af01f2 (20 февраля 2019 г.) Михала Суханека (hramrach).
(Объединено Junio C Hamano - gitster - в коммите 20fe798, 09 апреля 2019 г.)

worktree: исправить worktree add расу

Git запускает цикл статистики, чтобы найти доступное имя рабочего дерева, а затем выполняет mkdir для найденного имени.
Включите его в цикл mkdir чтобы избежать повторного вызова worktree, добавьте поиск того же свободного имени и сначала создание каталога.


Git 2.22 (Q2 2019) исправляет логику, чтобы сказать, имеет ли хранилище Git рабочее дерево, защищает " git branch -d " от удаления ветки, которая в настоящий момент извлечена по ошибке.
Реализация этой логики была нарушена для репозиториев с необычным именем, что, к сожалению, является нормой для подмодулей в наши дни.

См. Коммит f3534c9 (19 апреля 2019 г.) Джонатана Тана (jhowtan).
(Объединено Junio C Hamano - gitster - в коммите ec2642a, 08 мая 2019 г.)

Code Pull запрашивает 178 идей

worktree: обновление is_bare эвристики

Когда git branch -d <name> " git branch -d <name> ", Git обычно сначала проверяет, извлечена ли эта ветка в данный момент.
Но эта проверка не выполняется, если каталог Git этого репозитория находится не в " <repo>/.git ", что имеет место, если этот репозиторий является подмодулем, в котором его каталог Git хранится как " super/.git/modules/<repo> ", например.
Это приводит к удалению ветки, даже если она извлечена.

Это связано с тем, что get_main_worktree() в worktree.c устанавливает is_bare для рабочего дерева только с использованием эвристики, согласно которой репо является пустым, если путь к рабочему дереву не заканчивается в " /.git ", и иначе не оголяется.
Этот код is_bare был введен в 92718b7 (" worktree: добавить детали в структуру worktree", 2015-10-08, Git v2.7.0-rc0), следуя эвристике pre-core.bare.

Этот патч делает 2 вещи:

  • Научите get_main_worktree() вместо этого использовать is_bare_repository(), представленную в 7d1864c ("Представьте переменную конфигурации is_bare_repository() и core.bare", 2007-01-07, Git v1.5.0-rc1) и обновлена в e90fdc3 ("Очистить работу"). обработка дерева ", 2007-08-01, Git v1.5.3-rc4).
    Это решает проблему " git branch -d <name> ", описанную выше.

Однако... Если репозиторий имеет core.bare=1 но команда " git " запускается с одного из его вторичных рабочих деревьев, is_bare_repository() возвращает false (что нормально, поскольку доступно рабочее дерево).

И, рассматривая основное рабочее дерево как непокрытое, когда оно голое, вызывает проблемы:

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

Чтобы избежать этого, также проверьте core.bare при установке is_bare.
Если core.bare=1, доверяйте ему, а в противном случае используйте is_bare_repository().

Ответ 2

Дистрибутив git поставляется со встроенным скриптом git-new-workdir. Вы бы использовали его следующим образом:

git-new-workdir project-dir new-workdir branch

где project-dir - это имя каталога, в котором находится ваш репозиторий .git. Этот сценарий создает другой каталог .git со многими символическими ссылками на исходный, за исключением файлов, которые не могут быть общими (например, текущая ветвь), что позволяет вам работать в двух разных ветвях.

Это звучит немного хрупко, но это вариант.

Ответ 3

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

Предостережение. Это, вероятно, не очень хорошее решение, если вам нужно редактировать несколько ветвей одновременно, например, состояния OP. Это для одновременного проверки нескольких ветвей, которые вы не собираетесь редактировать. (Несколько рабочих каталогов, поддерживаемых одной .git-папкой.)

Было несколько вещей, которые я узнал, так как я пришел к этому вопросу в первый раз:

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

  • Тот факт, что вы можете указать местоположение используемого вами репо (расположение вашего .git dir) в командной строке с опцией git --git-dir=

  • Тот факт, что вы можете указать расположение вашей рабочей копии с помощью --work-tree=

  • Что такое зеркальное репо.

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

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

git clone --mirror <remoteurl> <localgitdir> # Where localgitdir doesn't exist yet
mkdir firstcopy
mkdir secondcopy
git --git-dir=<localgitdir> --work-tree=firstcopy checkout -f branch1
git --git-dir=<localgitdir> --work-tree=secondcopy checkout -f branch2

Большое оговорку об этом состоит в том, что для двух копий нет отдельной главы. Итак, после вышеперечисленного, запуск git --git-dir=<localgitdir> --work-tree=firstcopy status покажет все отличия от branch2 до branch1 как незафиксированные изменения - потому что HEAD указывает на branch2. (Вот почему я использую параметр -f для checkout, потому что на самом деле я вообще не планирую никаких изменений локально. Я могу проверить любой тег или ветвь для любого дерева работы, если я использую -f.)

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

Ответ 4

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

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