Comments 52
и только визуализацию дерева коммитов оставить на откуп графическим утилитамgit log --graph ??????
А быстрое построение — это на проектах каких объемов? У меня на работе репозиторий, в котором около 260000 коммитов, и GitKraken переваривает его неспешно (к сожалению, найти адекватную замену идеальному TortoiseGit на Linux не так-то просто).
GitKraken тормознутая поделка на Electron. Sublime Merge не смотрели?
Мне ГитКракен нравится своей кроссплатформенностью и функциями по интеграции с различными git платформами.
Но очень в нём не хватает гибкости, особенно в плане force. У меня на многих рабочих репозиториях тупо отказывается нормально работать там, где tortoise git всё делает на ура. А поддержка с pro аккаунтом помочь не может, постоянно отвечают мол "да да, увы но это будет с очень низким приоритетом".
В частности, что очень плохо сделано почти во всех гуи (включая TortoiseGit и Github Desktop) — работа с submodules.
В частности, что очень плохо сделано почти во всех гуи (включая TortoiseGit и Github Desktop) — работа с submodules.
отображение или именно активная работа (включая модификацию)?
К тому же, submodules — это реально очень опасный инструмент. Я не видел еще ни одного человека, который умеет с ним работать безошибочно. Разве что вообще использовать subtree и прочие аналоги.
1. Коммит в сабмодуль и коммит его в родительский модуль.
2. Push изменений родительского модуля вместе со всеми закоммиченными в него изменениями сабмодулей.
3. Pull изменений в модуль вместе с его сабмодулями.
Главная причина, по которой это всё работает через задницу — это сделано через задницу в самом git. Но GUI могли бы упростить процедуру и реализовать более полноценную поддержку. Но не хотят.
Для сравнения можно посмотреть, как это сделано в системе контроля версий здорового человека — Mercurial.
Для сравнения можно посмотреть, как это сделано в системе контроля версий здорового человека — Mercurial.
согласен, но сколько людей пользуются mercurial?
По факту — mercurial умирает. Все на git'е
Думаю, что разочарую Вас. В "моем" QGit концептуально все так же, как и в "классическом".
Касательно работы с субмодулями, то там все примитивно: заходим в директорию субмодуля, запускаем QGit, работаем с этим субмодулем. Поднимаемся на директорию выше — уже работаем с основным проектом.
Я запускаю QGit из Krusader-а по F1, по 'Q' — выход, и "побежал" в другую директорию. QGit с открытым деревом проекта у меня весь день не "висит".
260000 — что ж это за реп такой?! Заинтриговали :) Я к сожалению с такими объемами не встречался. Максимум, что я видел это 54000 (субмодуль qtbase).
QGit (оригинальный, не мой) кэширует дерево коммитов, и хранит этот кеш в бинарном виде. Это существенно ускоряет повторный старт QGit. Кеш живет одни сутки, на следующий день он будет пересоздан. Видимо это сделано для того чтобы кэш не протухал. Но для больших репов этого все равно недостаточно, т.к. в этом случае уже начинает тормозить Qt-шная отрисовка. Я немного изменил порядок отрисовки: вначале явно рисуется только ~1.5 экрана. Все остальное рисуется фоном. Поэтому у пользователя возникает ощущение, что все построилось быстро. И пока пользователь тянется мышкой что бы что-нибудь нажать или проскролить — дерево, скорее всего, уже будет достроено.
Было бы интересно погонять ваши 260000 коммитов.
Было бы интересно погонять ваши 260000 коммитов.
https://github.com/torvalds/linux
Вот тут почти миллион, гоняйте на здоровье :)
Холодный старт
28.03.2021 20:34:28 INFO LWP19694 [qgit.cpp:102] QGit is running (version: 3.0.1; gitrev: b9ba2e3)
28.03.2021 20:34:29 ERROR LWP19694 [cache.cpp:105] Unable to load file-cache
28.03.2021 20:34:41 DEBUG LWP19694 [dataloader.cpp:126] Exited while parsing
...
Первые два экрана построены, далее нажата 'Q'
28.03.2021 20:35:51 INFO LWP19694 [cache.cpp:45] Saving cache. Please wait...
28.03.2021 20:35:51 INFO LWP19694 [cache.cpp:80] Compressing data...
28.03.2021 20:35:53 INFO LWP19694 [cache.cpp:95] Cache saved
28.03.2021 20:35:56 INFO LWP19694 [qgit.cpp:136] QGit is stopped
Кэшированный старт
28.03.2021 20:38:00 INFO LWP19961 [qgit.cpp:102] QGit is running (version: 3.0.1; gitrev: b9ba2e3)
28.03.2021 20:38:13 DEBUG LWP19961 [dataloader.cpp:126] Exited while parsing
...
28.03.2021 20:38:17 DEBUG LWP19961 [dataloader.cpp:126] Exited while parsing
Первые два экрана построены, далее нажата 'Q'
28.03.2021 20:38:27 INFO LWP19961 [qgit.cpp:136] QGit is stopped
Просто для информации: при отображении первый двух экранов потребляет ~2.2 Гига, если проскролить дерево до конца вниз — будет больше 6-ти.
Обычный корпоративный реп системы из банковского сегмента, разрабатывается с 2008 года.
формат конфиг-файла изменен с INI на YAML;
лучше бы на TOML. Аргументы? YAML хоть и человекочитаем, но имеет много подводных камней. Часть можно прочитать по ссылке https://noyaml.com
Для YAML есть наработки (врапперы), для TOML — нет, вот и вся причина. Использую yaml-cpp библиотеку (спецификация 1.2).
А недостатки наверное можно найти у любого формата. Если апеллировать к вашей ссылке, то мысль о том, что в yaml можно sql-запрос засунуть меня никогда не посещала — теперь буду знать, что так тоже можно ;)
Toml хоть и человекочитаем, эта человекочитаемость теряется на сколько-нибудь сложных файлах. Писал раз конфиг для telegraf и не смог в toml выразить какую-то довольно очевидную настройку, (не помню, то ли вложенные в словари таблицы, то ли в таблицы словари, то ли глубина вложенности была больше). В YAML это было бы очевидно.
А уж якоря и ссылки в YAML — это просто киллер фича для DRY.
Вложенные настройки прекрасно на TOML отрабатывают:
oom_score = 0
[grpc]
uid = 0
gid = 0
max_recv_message_size = 16777216
max_send_message_size = 16777216
[debug]
address = ""
uid = 0
gid = 0
[metrics]
address = "127.0.0.1:1338"
grpc_histogram = false
[cgroup]
path = ""
[plugins]
[plugins.cgroups]
no_prometheus = false
[plugins.cri]
stream_server_address = "127.0.0.1"
stream_server_port = "0"
enable_selinux = false
sandbox_image = "k8s.gcr.io/pause:3.1"
stats_collect_period = 10
systemd_cgroup = false
enable_tls_streaming = false
max_container_log_line_size = 16384
[plugins.cri.containerd]
snapshotter = "overlayfs"
no_pivot = false
[plugins.cri.containerd.default_runtime]
runtime_type = "io.containerd.runtime.v1.linux"
runtime_engine = ""
runtime_root = ""
[plugins.cri.containerd.untrusted_workload_runtime]
runtime_type = ""
runtime_engine = ""
runtime_root = ""
[plugins.cri.cni]
bin_dir = "${SNAP}/opt/cni/bin"
conf_dir = "${SNAP_DATA}/args/cni-network"
conf_template = ""
[plugins.cri.registry]
[plugins.cri.registry.mirrors]
[plugins.cri.registry.mirrors."docker.io"]
endpoint = ["https://registry-1.docker.io"]
[plugins.cri.registry.mirrors."local.insecure-registry.io"]
endpoint = ["http://localhost:32000"]
[plugins.cri.registry.mirrors."gcr.io"]
endpoint = ["https://gcr.io"]
[plugins.cri.registry.configs]
[plugins.cri.registry.configs.auths]
[plugins.cri.registry.configs.auths."https://gcr.io"]
auth = "b2F1dGgy..."
[plugins.diff-service]
default = ["walking"]
[plugins.linux]
shim = "containerd-shim"
runtime = "${RUNTIME}"
runtime_root = ""
no_shim = false
shim_debug = true
[plugins.scheduler]
pause_threshold = 0.02
deletion_threshold = 0
mutation_threshold = 100
schedule_delay = "0s"
startup_delay = "100ms"
А уж якоря и ссылки в YAML — это просто киллер фича для DRY
Хахаха. Если у вас конфиг файлы под управлением любого SCM, то темплейтинг должен происходить не на уровне конфиг файла, а в момент доставки конфига на целевую машину. Это бест пректис.
Если же Вы не пользуетесь системами управления конфигурацией — у Вас проблемы посерьёзнее, чем якоря или их отсутствие в YAML.
Касательно же DRY — с якорями — удачи в отладке. Весьма неочевидно, как именно отрендерится YAML в конечном итоге.
Писал раз конфиг для telegraf и не смог в toml выразить какую-то довольно очевидную настройку, (не помню, то ли вложенные в словари таблицы, то ли в таблицы словари, то ли глубина вложенности была больше).
Если интересно — давайте попробуем написать эту настройку )
Если интересно — давайте попробуем написать эту настройку )
Я не помню, к сожалению. Помню, что там были вложенные массивы таблиц и что у них были абсолютно, феерично, неочевидные и противоестественные синтаксис и семантика (достаточно второй пример по ссылке почитать). Для языка, ориентированного на читабельность, это просто эпик фэйл, по-моему.
Ваш пример почти полностью состоит из вложенных словарей, он был бы также человекочитаем и в YAML, да и в JSON.
Хахаха. Если у вас конфиг файлы под управлением любого SCM, то темплейтинг должен происходить не на уровне конфиг файла, а в момент доставки конфига на целевую машину. Это бест пректис.
Если же Вы не пользуетесь системами управления конфигурацией — у Вас проблемы посерьёзнее, чем якоря или их отсутствие в YAML.
Вы как-то смотрите на проблему только из своей области. У меня пет-проект читает конфиг из YAML, там есть дублирующиеся части конфига, которые я очень удобно заменил якорями и ссылками на них. Никакого автодеплоя на 100 машин с разными конфигурациями там нет. Зачем мне SCM?! В .gitlab-ci.yml одинаковые куски конфига в разделах "only:" я заменил якорями. Как я тут применю эти best practices для SCM? (В .gitlab-ci.yaml можно файлы подключать, но это неудобно, громоздко, и опять же, зачем, если можно стандартные средства языка использовать).
Касательно же DRY — с якорями — удачи в отладке. Весьма неочевидно, как именно отрендерится YAML в конечном итоге.
Я согласен, что там не самый очевидный синтаксис, но ни в одном другом языке той же направленности вообще нет такой фичи.
То, что у YAML есть недостатки, я согласен. Но TOML не кажется мне достойной заменой.
То, что у YAML есть недостатки, я согласен. Но TOML не кажется мне достойной заменой.
Предложите лучше!
В .gitlab-ci.yaml можно файлы подключать, но это неудобно, громоздко, и опять же, зачем, если можно стандартные средства языка использовать).
В гитлаб до сих пор не смогли совместить якоря YAML и include других .gitlab-ci файлов. Что хуже — там якоря не покрывают кейсы, когда, например, скрипт сборки надо из нескольких якорей собрать (ну, не работает мерж списков — хотя ишью заведены)
На мой взгляд TOML удобен и более читаем для плоских простых конфигураций. Как только начинается вложенность это перестаёт хорошо читаться и появляется избыточная писанина с дублированием путей. Даже в вашем примере:
[plugins]
[plugins.cri]
[plugins.cri.registry]
[plugins.cri.registry.mirrors]
[plugins.cri.registry.mirrors."docker.io"]
Сколько раз тут продублировано слово "plugins"? В YAML не надо во вложенных структурах дублировать путь до корня, совершенно естественное описание иерархии через отступы:
plugins:
cri:
registry:
mirrors:
docker.io:
Описание в TOML массивов из словарей с двойными скобками тоже не радует читаемостью.
В общем, я для себя решил, что если конфиг простой и плоский, то использую TOML, если иерархический то YAML. Плюс в YAML есть якоря, что тоже бывает удобно, да хоть тот же merging:
default: &default_params
foo: 1
bar: 2
some1:
<<: *default_params
spam: 3
some2:
<<: *default_params
hello: 4
В YAML не надо во вложенных структурах дублировать путь до корня, совершенно естественное описание иерархии через отступы:
Неестественное. Python по той же причине с одной стороны — очень удобен для чтения, но абсолютно не пригоден для рефакторинга без применения специализированных редакторов. Забыл поменять индентацию и поехало. Я уж не говорю о том, что я сейчас много с кубом работаю и самый звиздец — это шаблонизация YAML. {{ nindent 4 }} и попробуй только ошибиться в цифирке.
Касательно ТОМЛ и примера выше — не уверен, но может быть его можно сократить. Не выглядит ужасно.
И по поводу «якорей» я тоже высказался выше — насколько они хороши при записи, настолько же они плохи при просмотре окончательного конфига или пайплайна в gitlab (ну, и плюс ограничения, которые с ними есть).
Согласиться могу только лишь с тем, что все эти форматы — вкусовщина. А учитывая, что лучшего нет — каждый выпендривается как может.
Графический клиент для работы с git не должен просто копировать консольный UX. Просто посмотреть лог и список коммитов и в консоли можно. В GUI должен быть более высокоуровневый UI/UX для работы с системой контроля версий. Вот навскидку несколько примеров:
- выбрать несколько коммитов и сделать их squash или удалить
- выбрать коммиты и сделать с ними интерактивный rebase с удобным UI
- Перетаскивание коммитов мышкой из одной ветки в другую (например, по ошибке закоммитили не в ту ветку)
- редактирование информации в коммитах и применение фильтров, например, поменять email
- undo/redo любых действий
И т. д. А так это ну гуй и гуй, и что с ним, что без него — одна петрушка.
Некоторые из таких высокоуровневых концепций когда-то были реализованы в клиенте gitup для macos.
Это что называется "на любителя". Я как раз ценю QGit, за то, что там нет всего Вами перечисленного.
На самом деле в QGit есть механизм "Actions", он позволяет самостоятельно создавать не очень сложные команды "на каждый день": push, pop, fetch, stash, и т.д. В моем списке таких команд 11. Часто я эти команды юзаю из консоли, но иногда и из QGit.
Я как раз ценю QGit, за то, что там нет всего Вами перечисленного
Как будто всё вышеперечисленное как-то сильно мешает если этим не пользоваться. Я большую часть времени пользуюсь клиентом в IDE (IntelliJ IDEA). Там есть удобные высокоуровневые инструменты, механики и абстракции над разными VCS (я пользуюсь Git и Perforce). Удобно, когда такой инструмент интегрирован в среду разработки, все изменения сразу видишь в редакторе, тут же можно коммитить, лог смотреть, историю редактировать и т. п. Но в то же время никто насильно этим пользоваться не заставляет, терминал всегда в вашем распоряжении.
Так это и есть staging patches, в IDEA можно тыкать в чекбоксы для каждого изменения и точно так же включать/отключать изменённые куски кода при коммите.
Понятно. Суть в том как изменения объединять в патчи. IDEA пытается объединять в патчи изменённые строки, следующие просто друг за другом. Тут ещё надо подумать над тем как сделать для этого удобный UI.
Вообще это опасный механизм, таким образом можно легко закоммитить сломанный код.
У git gui, да и в консоли, можно разбить chunk на более мелкие, вплоть до одной строчки, и комитить их по отдельности.
В VS Code и в SmartGit можно при комите редактировать индекс как обычный файл, т.е. можно откатить ненужные строчки.
В целом, и то, и то — удобный UI, имхо.
Еще IDEA игнорирует stage. Если добавить в индекс строчку через git, то IDEA этого не увидит.
Да. Для себя проблему решил, делая "мусорный" коммит со всеми изменениями, а потом reset HEAD~ и набирание уже полезных коммитов через compare with local. Вот там уже можно хоть строчку, хоть пол-строчки поделить. А заодно собрать, прогнать тесты и закоммитать.
то есть биндить git alias
Буквально недавно попадался форк QGit…
Ага, вот и оно — GitQlient.
Что ли мейнтенеры QGit прям так провоцируют на форкинг?
И еще — почему бы свой форк не назвать иначе, раз уж стукнулись жеп не получается PR?
Посмотрел по диагонали код GitQlient. Действительно, можно найти кодовые элементы от QGit. По тому что я увидел на форк это не тянет, может на прообраз. Это скорее похоже на новое, и как мне показалось, добротно проработанное решение, но никак не на форк.
По поводу нового названия для моего форка: несморя на доработки — основной объем кодовой базы все еще остается оригинальным. Да и по духу, и по названию — QGit мне нравится :) Поэтому я наверное пока воздержусь от переименований.
Незнание — тоже сила!
А почему не получилось отправить изменения в начальный проект? Вроде те что в списке незначительных, вполне полезные и безобидные.
Частично ответ на этот вопрос уже есть в статье. Попробую ответить более развернуто. Первоначально я отправлял свой доработки мантейнеру (Cristian Tibirna). Самые первые предложения отправлялись в виде diff-ов по почте (тогда QGit еще не было на GitHub). Они рассматривались, обсуждались, и принимались. Если Вы когда нибудь занимались такой деятельностью, то должны знать, что процесс этот не быстрый. Например, сейчас я отправляю мелкие фиксы в Krusader, процесс их принятия занимает 4-5 недель. С QGit по срокам было примерно так же. Нужно понимать, что Кристиан не автор проекта QGit, то есть код проекта для него в некоторой степени чужероден. Поэтому рассмотрение сторонних правок требует больше времени, чем если бы это делал автор. И не забывайте, что мантейнеры в таких проектах это добровольцы, они выполняют работу по поддержке в свое личное время.
Как уже было написано, мы не сошлись с Кристаном по вопросу внедрения C++11. Что мне нужно было делать в этой ситуации? Ждать когда мантейнер примет решение, что уже пора внедрять?! Или смириться и писать код на C++98/2003?
Я использую QGit в своей работе, и мне хотелось иметь удобный, эффективный (в моем понимании) инструмент, и у меня была возможность сделать QGit таковым. Поэтому я перестал тратить время на создание PR, обсуждения, ожидания что их примут, а просто пошел вперед. Я делал инструментария для себя, при этом долгое время старался сохранить совместимость с основным проектом. Со временем это становилось делать все труднее, потому что помимо разных полезностей в проект попадает и рефакторинг.
Публично решил рассказать о своей работе только после того, как сделал механизм проверки орфографии, посчитал, что это может быть полезно не только мне. Но перед тем как это сделать — я написал информ-письмо Кристиану, кратко рассказал про проверку орфографии, о том что совместимость с основным проектом потеряна, и о том, что в перспективе собираюсь рассказать о своей работе публично. Реакции от мантейнера не последовало. Через две недели я начал писать данную заметку.
P.S.
Выложить свое решение — это здорово, но недостаточно. Если вы не занимаетесь сборкой проектов каждый день — процесс может оказаться нетривиальным. Именно поэтому я подготовил DEB-пакеты, что бы можно было просто попробовать мое решение, а не тратить время на разбирательство с системой сборки.
Вставить проверку синтаксиса в QT на базе hunspell — это около 100 строчек кода, недавно (с месяц назад?) на хабре была статейка про это.
Это был один из рабочих вариантов. Но потом решил, что "третий уровень Sonnet" — это не мой путь. Поэтому постарался сделать добротное, в моем понимании, решение.
Вставить проверку синтаксиса в QT на базе hunspell — это около 100 строчек кода
Так я и не говорил, что hunspell — это сложно, примерно 100 строк и получилось ;) Ну может еще 100 на загрузку/сохранение пользовательских словарей.
Основная заморочка была с детектом языка.
А по функциональности, если в языке есть какое-то слово (а hunspell проверяет по словарю), то либо детектор так-же выдаст этот язык либо, что еще хуже, выдаст неправильный язык и проверка hunspell не пройдет.
В конфиге языки и так указываются, точнее словари. А вот языковые триграммы "зашиты" в код в виде ресурсов, это сделано для быстрой инициализации (прием взят из Sonnet). Сейчас есть RU, EN, но можно и расширить.
Про пример с немецкой опечаткой: методика определения языка по триграммам как раз устойчива к разовым опечаткам, позволяет корректно детектировать, например английский, даже если в слове случайно появился символ с умляутом из немецкого. Исключения могут составить слова из трех букв (размер одной триграммы), но в трех буквах вроде редко ошибаются.
Теперь про методику детектирования языков по словарям: допустим мы проверили слово по всем словарям и не нашли соответствия. Подсветили слово как ошибочное. Но на самом деле это не ошибка, а исключение. Нам нужно добавить слово в список исключений. В какой словарь будем добавлять? В этом случае в контекстном меню нужно будет сформировать субменю для каждого доступного словаря, и пусть пользователь сам принимает решение куда добавлять. Рабочий вариант?! Да, вполне рабочий. Но я решил сделать детекцию через триграммы, чтобы в контекстном меню сразу "направлять" пользователя в нужный словарь
Хмм А чем плох форк официального Github Destop https://github.com/shiftkey/desktop
А я очень благодарен этой статье за "триграммы" совсем недавно в ручную сидел и создавал список подобного – очень круто, что уже есть готовое решение. Однако, интересно, есть ли готовое транслитерисованные триграммы… Например, если человек по русски пишет хелоу – и мы определяли из этого английский язык с какой-то долей вероятности… Как составляют триграммы? Паркинг текста? Я не очень понял на каком основании им присуждается "вес".
что уже есть готовое решение
"Готовое решение" подходит для QGit, не факт, что оно подойдет для ваших задач. Но как базовое решение можно Sonnet или что-то подобное использовать.
Например, если человек по русски пишет хелоу – и мы определяли из этого английский язык с какой-то долей вероятности…
У меня это определится как 100%-но русское слово, так как есть только русскоязычные триграммы. Если бы в слове была последовательность из трех латинских символов, то появилась бы вероятность английского или немецкого, или другого языков.
Возможно, если создать отдельный словарь транслитерисованных триграмм, тогда вероятность появится. Думаю это должно сработать.
Или как вариант рассмотреть нейросетевые алгоритмы. Наш директор иногда берется за такие задачи, но это уже коммерческая история.
Как составляют триграммы?
"Война и мир" без французских слов.
… на каком основании им присуждается "вес".
Частота встречаемости в тексте
Не стану здесь описывать механизм принятия решения в Sonnet, или в моем механизме. Иначе получится отдельный (уже тематический) абзац к статье :)
Если есть потребность узнать как это работает — можем сконнектиться и обсудить.
xneur тоже использует словарь триграмм (там автор назвал это протоязыком) и получал он его как раз парсингом текстов, вроде в том числе "Войны и мира".
QGit, улучшения