Как стать автором
Обновить

Git. Скачем между ветками как древесные лягушки

Уровень сложностиПростой
Время на прочтение6 мин
Количество просмотров14K
Всего голосов 59: ↑59 и ↓0+70
Комментарии55

Комментарии 55

И всё-таки worktree или wortree?

Спасибо, поправил.

Пожалуйста, я уж думала, что я чего-то не понимаю))

Спасибо добрый человек, я как раз пилю гуи для этой цели в компании(надо много линковать+микрофронты), очень облегчит дело

Спасибо за обратную связь! Уверен, с worktree будет удобно

Эх, знал бы я об этом 2 часа назад) Спасибо!

`git stash drop` случайно сделали?)

Я из тех самых людей, которые stash-ат и меняют ветку) Но там часть зависимостей не в гите, проект довольно старый, и нет уверенности, что они потом нормально подтянутся, и что я ничего не забыл)

Правда, я ещё из тех мерзких людей, которые используют UI (SourceTree), не знаю, умеет ли он в worktree. Ну, есть только один способ проверить)) К тому же, всё равно часть приходится делать в консоли (например, на одном из проектов были теги с аннотациями). Плюс одно действие.

Переходите на винду, у нас есть Git Extensions

А если серьёзно, то, судя по скриншотам, теги с аннотациями SourceTree поддерживает, ради них точно нет смысла возвращаться в терминал. Что же до worktree - многие (но, увы, не все) программы прекрасно работают с ними если открыть заранее созданный worktree как отдельный репозиторий.

Дерево норм тема.

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

Чем не нравится вариант делать ветку A, а затем отводить от нее ветки А1, А2... Аn (можно с тем же worktree)? И когда они готовы, мержить их в А? Кажется, так проще будет самому не запутаться.

Если сделать ветку A от master, то git pull перестанет принимать в неё обновления из master.
Вроде нашёл ключик --force для git worktree add, буду наблюдать, что из этого получится.

Вы можете вручную задать upstream ветку origin/master для вашей рабочей ветки А:

git branch --set-upstream-to=origin/master

Тогда это вообще прекрасно, если пуши будут попадать в master!

А если и пуши в master, и pull из master-а, то чем это отличается просто от использования локальной ветки master, просто с другим названием? Не совсем понимаю.

Раньше я делал несколько копий репозитория, в каждой копии пилил какую-то фичу и пушил по мере готовности. worktree позволит иметь один репозиторий, экономя на повторах папки .git, а также fetch можно делать единожды, он затронет все копии.

А, кажется, понял. Спасибо)

git worktree add <path> --detach <branch_name>

Попробуйте GitButler

Посмотрел их презенташку. Мне кажется, мне это не нужно - управлять каждым минимальным изменением в файлах. Это хорошо, когда примеры простенькие - "поменял цвет фона" - изменение в единственной строчке. Если же одно изменение это 15 мест в разных файлах, а другое изменение 20 мест в файлах, частично пересекающихся с первыми, получается какой-то микро-менеджмент изменений.

Для справки:

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

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

Давненько приглядывался к worktree, но не могу заставить себя попробовать - как-то всегда хватало stash/временный commit/diff > apply

Может быть, жизнь заставит, если придется работать над 3-4 задачами условно одновременно. Если в дополнении к этому окажется, что чистая сборка 30 минут (такое тоже было), то тут только копии (worktree) проекта держать.

Надо будет попробовать.

Обучаю нейросети, код храню в git. Стараюсь хранить все эксперименты, один эксперимент - один коммит.

Бывают сложности, если есть очередь из задач на обучение. Код для задачи берётся из рабочего каталога, и может так получиться, что когда она попадёт на исполнение, там заcheckoutен уже не тот коммит.

Пока решаю эту проблему с помощью python executable zip archives

Docker по независящим от меня причинам использовать не могу.

Ещё один минус: не поддерживаются подмодули

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

Спасибо, добавлю к статье.

А в черепахе это есть?

Черепахи в прыжках по веткам замечены не были

Хм, я вроде раньше пользовался (сэкономил на clone), но что-то не понравилось (уже не помню, что именно), и вернулся к варианту 3.

Imho зря вы такой длинный текст для такой простой штуки раскатали. Сравнивать с вариантами 1 и 2 (временные ветки и stash) вообще бессмысленно, разработчики, которым они не подходят, и так знают об этом (например, мне надо открывать в xcode два разных воркспейса – для iOS и MacOS, но они имеют общие подпроекты утилит сборки, и XCode этого стерпеть уже не может). А сравнение со вторым клоном очень простое, одного-двух абзацев бы хватило.

зря вы такой длинный текст

На всякий случай написал, чтобы и новичку было полезно и понятно все. Для пользователей вроде вас оставил во введении предложение сразу перескочить к разделу "Мой вариант использования git worktree".

Сравнивать с вариантами 1 и 2 (временные ветки и stash) вообще бессмысленно, разработчики, которым они не подходят, и так знают об этом

Как я в статье и сказал, последние 10 лет вижу, как люди буквально мучаются от того, что у них все тормозит, лагает, бесятся, что нужно clean build делать. Фразу о том, что человек не может показать код, потому что ему на ветку нужно прыгать, слышал не далее, как месяц назад. Я эту статью написал в том числе для того, чтобы коллегам скинуть. И все коллеги как раз 1 и 2 и используют.

А сравнение со вторым клоном очень простое, одного-двух абзацев бы хватило.

А разве у меня больше?

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

В мастер же обычно напрямую никто ничего не пушит. Вместо этого создают ветки от мастера и потому создают ПР в мастер. Можно создать ветку от мастера без чекаута на мастер:

> git checkout -b feature1 master

А если случайно "зачекаутились" от другой ветки, можно просто вернуть ее содержание на мастер:

> git fetch # чтобы потом на свежий мастер обновиться
> git reset --hard origin/master

Если у вас с гитом работает небольшая команда – обычно людям дают самим мёржить ветки в мастер. А то и одиночные коммиты делать прямо в него.

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

ЗЫ: При виде "git reset" до сих пор вздрагиваю, хотя много лет прошло... Мне в своё время пришлось освоить git reflog практически сразу: я как-то в hg привык, что ты не можешь в одно движение разломать себе репу.

А вот в моем случае, например, worktree скорее дает меньше маневра, нежели второй честно откопированный репозиторий.

Рабочий проект весит больше полутерабайта, которые примерно пополам разделены между .git и остальной частью репо. Вот и выходит, что каждый раз, когда мне нужно создать worktree, у меня начинается копирование ~300Gb, и это занимает катастрофическое время. Ни о какой скорости и продуктивности для хотфикса и речи нет. Вот буквально вчера попробовал и на n-ой минуте тщательного копирования файликов гитом я просто прервал создание worktree.

А так как (если я конечно все правильно понял), worktree намертво привязан к одной ветке, то мне сильно дешевле просто иметь второй клон репо, который будет выкачан единожды, но теперь у меня в распоряжении есть два репо, где я могу прыгать между любыми двумя ветками, как бабуин, без ограничений.

Да, это занимает уйму места, но что поделать.

Ветка меняется как обычно.

Из ограничений: нельзя удалить ветку, на которую ссылается дерево.

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

А так как (если я конечно все правильно понял), worktree намертво привязан к одной ветке

Ветку в каждом worktree можно поменять, точно так же как меняешь в копии проекта, которую "склонил". Разница только в том, что папка.git будет общей, т.е. только в одном проекте достаточно сделать `git fetch`. И нельзя одну и ту же ветку в держать в основном проекте и в worktree.

Кстати, по поводу того, что .git 300gb. Если большая история, можно сэкономить, не держа все изменения за все времена.

> git clone --depth 300 <project url>.

Команда выше заберет только последние 300 коммитов.

Что же, значит я действительно не так понял worktree. Попробую улучшить качество жизни сегодня же :)

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

В общем, спасибо @Deosis и @arturdumchev за наводки. Мои предположения о несменяемости ветки в worktree были неверны. Теперь я тоже перешел на git worktree и, добавив дополнительный флаг --ignore-other-worktrees к алиасу для команды git checkout, могу делать все то же, что делал раньше с полноценным клоном репозитория, но с меньшим количеством занятого места

Проблемы git worktree есть (частные но тем не менее):

Eclipse не умеет с ними работать. Соответственно, если разработка в eclipse - вся работа с git уходит в ком. строку. Вообще вся, даже diff не посмотреть. Eclipse не понимает, что это репозиторий.

vscode devcontainers. Если .devcontainer в репозитории, то в контейнере открывается одно worktree, и там внезапно не оказывается основного репозитория, и работа git тоже ломается. Надо городить костыли с другой точкой монтирования. Я пока не нашел разумного решения.

Amend, с одной m

Спасибо, исправил.

Сколько ж Миша-часов могло быть сэкономлено... Спасибо за статью!

Я правильно понимаю, что нет какой-то "активной" версии кода когда используем деревья? Я имею в виду, когда я делаю чекаут на ветку, я получаю другую версию кода в той же самой директории. При этом моя ИДЕ остается открытой на том же проекте. А для того чтобы работать в стиле wortree мне надо для каждого дерева создавать проект в ИДЕ и деражть окрытыми несколько версий ИДЕ?

В этом и суть. Есть несколько "активных" веток. В каждой открыта своя IDE, можно компилировать, запускать, отлаживать сразу одновременно несколько фич. Чтобы не тратить время на восстановление контекста при возврате к предыдущей задаче.

Ага, IntellijIDEA пытается помогать, и когда в рамках одного проекта переключаешь ветку, то она открывает те же файлы, которые были открыты. Но все равно она восстанавливает не весь контекст, и может понадобиться clean build делать.

Когда я в Neovim работал на Clojure-проекте, проблем открывать другую папку вообще не было, дело 200 мс. Сейчас на Java/Kotlin с IntellijIDEA. Открыть другой проект подольше, но жить можно.

Зачем создавать проект в IDE, когда надо просто открыть лежащий в репозитории?

Ещё можно отмапить worktree на виртуальный диск чтобы пути в ide не менять

Чем git worktree отличается от того, чтобы вызывать git clone с другим именем папки?

git worktree позволяет централизованно управлять репозиторием. Простыми словами: достаточно вызывать git fetch в любой папке, чтобы обновления были видны во всех.

объяснение плохое и не отражающее сути.

Суть в том, что git хранит содержимое всех файлов в хранилище объектов в папке .git, откуда распаковывает их в рабочую папку (worktree в их терминологии), по умолчанию - в родительскую по отношению к .git.

Команда git clone копирует и рабочее дерево, и хранилище объектов.

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

объяснение плохое и не отражающее сути.

Не соглашусь с вами. Моя статья о том, как и зачем пользовать worktree, а не о деталях реализации.

Пользователя, который держит несколько "clone-ов" проекта, проще убедить фразой "достаточно вызывать git fetch в любой папке, чтобы обновления были видны во всех", чем вашими тремя абзацами, которые он с большей вероятностью пропустит, читая статью по диагонали.

git diff $(git rev-parse HEAD)^

Зачем такая сложность? Можно git diff HEAD^, а вообще просто git show

Вы правы. У меня остался алиас с незапамятных времён. Поправлю в статье.

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории