IDEA+Git (ветки, пулл реквесты). ОЧЕНЬ подробно! Новый интерфейс, подводные камни. Установка с 0.

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

Мы разберем нюансы и неочевидные моменты создания нового проекта, инициализацию git и будет подробно о создании веток и Pull Request’ов. Все, что понадобится в рамках взаимодействия со студентами KotlinSprint. Чтобы соблюдать грамотный git-flow при отправке задач на код-ревью. Все апдейты будут для последней стабильной на сегодняшний день версии IDEA.

Среду разработки буду ставить через установщик ToolBox, проект создам с нуля на чистой MacOS (без инструментов разработчика). Но все сказанное актуально и для Windows. Кроме создания проекта все также актуально и для Android Studio.

И перед началом напомню еще раз, что это именно техническое обновление к уроку по настройке git в IDEA. Не забудьте посмотреть видео про концепцию командной разработки, что такое жизненный цикл задачи итд.

Установка IntelliJ IDEA через ToolBox App

Итак, у нас есть голая MacOS, на которую только что был поставлен установщик продуктов JetBrains — ToolBox. Я рекомендую использовать именно его, потому что это легкий и наглядный инструмент мониторинга версий и своевременного обновления ПО от JetBrains.

Ищу в списке IntelliJ IDEA Community Edition — бесплатная общедоступная версия. Ее функционала хватит с головой для наших задач по разработке и работе с git. При клике на “Установить” начнется загрузка последней стабильной версии. Их на самом деле больше, но если вы начинающий — не нужно никому усложнять жизнь.

IntelliJ IDEA Community Edition

Более того, прежде чем разбирать чью-то проблему с настройкой окружения, первым делом мы сихронизируемся по версиям, чтобы отсечь сразу неактуальные баги. Обновиться будет легко — если новая версия доступна, возле установленного продукта появляется кнопка “Обновить”.

IDEA установилась. Последнюю стабильную версию у меня вы видите на экране. Запускаем.

Новый проект в IntelliJ IDEA

Окей, настройки импортировать неоткуда. Принимаем соглашения, не делимся статистикой и все. Можно создавать проект.

В первой части все стандартно.

  • Готовим место на вашей машине, именуем проект.
  • Репозиторий пока не создаем, его проинициализируем в открытом проекте.
  • Язык Kotlin.
  • Система сборки Gradle.

Установка JDK (SDK)

JDK (или SDK) у меня пока вообще нет, так как ось голая. Будем ставить и по клику на Add SDK выбираем скачать JDK. Самый первый, который без приписки Android.

Установка JDK (SDK)

Откроется окно с выбором версии. Я, не долго думая, выбираю самую последнюю (21), остальное оставляю без изменений. Особенно, Location, чтобы ничего не сломать.

Все установилось и я жму “Создать проект”, но появляется следующее уведомление. Его не надо игнорировать. Там говорится, что текущая версия Gradle, которая поставлялась с данной версией IDEA, поддерживает версии JDK до 19.

Установка JDK (SDK) версия 19

У нас же установлена 21 и с такой версией продолжать создание проекта нельзя — он просто не соберется. Поэтому мы говорим “Нет” настолько свежему JDK и идем скачивать рабочую 19 версию. У вас могут быть другие значения, либо ошибка может отсутствовать вовсе, либо вы создадите проект и эта ошибка появится в консоли – всегда читайте ошибки и что от вас хотят. Тогда они становятся не такими страшными.

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

Инициализация локального git-репозитория

Все готово и можно инициализировать git-репозиторий. На маке система запросит установку инструментов разработчика, на windows система предложит установить git, если ранее он не был установлен.

Инициализация git-репозитория

Пока идет установка обращу ваше внимание на иконку с уведомлениями. В этом разделе дублируется вся всплывающая внизу информация. Там можно увидеть пропущенные всплывающие сообщения, вызвать предложенное обновление компонентов или изучать ошибки.

После установки всех необходимых для git компонентов, можно инициализировать репозиторий. В моем случае пришлось еще перезапустить IDEA, чтобы все завелось. Готово. Создалась основная ветка по умолчанию main (либо это может быть master), файлы окрасились в красный цвет, что говорит о том, что гит их видит, но пока не отслеживает. Так будет со всеми новыми файлами, которые вы будете создавать в проекте в будущем.

Инициализация репозитория

.gitignor’ы — фикс игнора конфиг файлов

Отлично, вспоминаем первое видео про git. Что там нужно было сделать далее? Создать файл .gitignore и заигнорить из отслеживания ненужные для репозитория файлы. Чтобы вот в этой вкладке создания коммита пропали созданные (или измененные) конфигурационные файлы и файлы сборки. Посмотрим на проект внимательнее.

IDEA автоматически сгенерировала файлы .gitignore. Целых 2 штуки. Один из них в корне проекта, другой в скрытой системной папке .idea.

В окне создания коммита они тоже отображены оба и тот, который в папке .idea в списке первый. С соответствующей пометкой папки, в которой он лежит.

Игнорирование файлов

Вот в чем здесь дело. Большая часть конфиг файлов и файлов сборки уже проигнорирована. Соответствующие инструкции прописаны в корневом .gitignore — откройте и убедитесь в этом сами. Более того — часть файлов из папки .idea тоже проигнорирована, но не вся.

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

Как пофиксить? Очень просто. Открываем корневой .gitignore и прописываем одну строку “.idea/*”. Таким образом мы заигнорили вообще все файлы в папке .idea.

Игнорирование всех файлов .idea

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

Initial Commit — первый, инициализирующий коммит

Важный нюанс. Это лучше проворачивать ДО Initial Commit, потому, что после коммита изменений с конфиг файлами — выпиливать их придется только с помощью консольных команд. Об этом я рассказываю уже в рамках практики.

Теперь можно создать первый Initial Commit, не забудьте добавить в стейдж новые и измененные файлы. Отмечаем галками все, что нужно. Напомню, при работе с несколькими ветками одновременно будьте внимательны что и куда комитите. Чтобы в одну ветку с задачей не попали изменения, не относящиеся к конкретной выполняемой задаче. Под сообщением коммита отображаются две кнопки: Commit и Commit and Push. В первом случае коммит произойдет только локально. Это нам и нужно, так как наш проект еще не был опубликован на GitHub.

Initial Commit

Далее может появиться предупреждение о формате представления разделения строки. Просто жмем Fix and Commit (можно отметить галку “больше не спрашивать”).

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

Важный нюанс. Это лучше проворачивать ДО Initial Commit, потому, что после коммита изменений с конфиг файлами — выпиливать их придется только с помощью консольных команд. Об этом я рассказываю уже в рамках практики.

Теперь можно создать первый Initial Commit, не забудьте добавить в стейдж новые и измененные файлы. Отмечаем галками все, что нужно. Напомню, при работе с несколькими ветками одновременно будьте внимательны что и куда комитите. Чтобы в одну ветку с задачей не попали изменения, не относящиеся к конкретной выполняемой задаче. Под сообщением коммита отображаются две кнопки: Commit и Commit and Push. В первом случае коммит произойдет только локально. Это нам и нужно, так как наш проект еще не был опубликован на GitHub.

Далее может появиться предупреждение о формате представления разделения строки. Просто жмем Fix and Commit (можно отметить галку “больше не спрашивать”).

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

Вкладка Git

Хорошо, из окна коммита пропали изменения, а это значит что все “сохранилось” успешно. При изменении содержимого файлов (а также при их переименовании или перемещении) здесь будут видны изменения. Если у вас много разных измененных файлов и вы выполняете несколько задач параллельно, повторю, внимательно следите за тем, что коммитите. Не нужно бездумно отмечать галками все файлы – добавляйте в стейдж только то, что хотите закоммитить в текущую рабочую ветку.

Окей, теперь посмотрим git-log. Откроем вкладку Git, внутри должна открыться вкладка Log. Здесь мы видим наш единственный коммит в локальную ветку main. При клике на него справа будут те изменения, которые он сохранил. Любой файл можно открыть и посмотреть код. Это может быть наглядно и полезно, когда файлы перезаписываются и в окне изменений подсвечен свежий код.

git-log

Слева отображается наша единственная ветка main. В разделе Local, что соответственно означает, что она локальная. То есть на вашем устройстве.

Публикация проекта на GitHub

Теперь повторим флоу публикации проекта на GitHub. То есть загрузим проект в удаленный репозиторий. Выбираем Git → GitHub → Share…

Загрузим проект в удаленный репозиторий

В открывшемся окне задаем:

  • Имя репозитория (можно оставить без изменений).
  • Ставим или убираем галку приватности репозитория (приватность можно будет поменять позже в настройках репозитория).
  • В разделе Remote оставляем стандартную пометку удаленного репо — origin.
  • В разделе Shared by у меня не подключено ни одного аккаунта – добавляю свой акк с помощью авторизации через GitHub.

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

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

Вкладка гит

Теперь обращаю внимание на вкладку Git – закономерно появился еще один раздел Remote, который говорит о том, что на удаленном сервере с технической пометкой origin хранится такая же ветка main.

Звездочка напротив ветки означает, что эта ветка главная (production грубо говоря), а значок лейбла в локальных ветках говорит нам какая сейчас ветка активна. Активную ветку еще можно вывести в правом нижнем углу, кликнув по панели правой кнопкой мыши. И еще я хочу добавить Memory Indicator.

Создание веток

Окей, перейдем к работе с ветками в новых версиях IDEA. Объяснять буду, как и в предыдущем видео, на примере нашего взаимодействия с учениками в рамках практики KotlinSprint.

Согласно нашему рабочему флоу, сейчас стоят такие цели:

  • создать ветку для выполнения задачи
  • внести какие-то изменения и закомитить их
  • создать пулл реквест и отправить на проверку
  • влить успешно выполненное задание в мастер

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

Создание файла первой задачи

Итак, мы находимся в главной ветке main (или master). Первое, что нужно запомнить – новые рабочие ветки создаем исключительно из главной ветки. Представим, что вы хотите начать выполнение 1 задачи 1 урока. Создадим пакет для этого урока и файл внутри, в котором будет выполняться задание.

Задача1 урок1

При добавлении нового файла система спросит хотим ли мы добавить этот файл в отслеживание. Мы говорим “Да” отслеживанию, а также отмечаем галкой “Больше не спрашивать”.

Внутри файла я напишу стандартную функцию main(), обозначив таким образом, что внутри будет запускаться некий мой рабочий код. Попутно уберу хинты с именем автора — здесь будет только один автор кода. Внутри функции напишу рандомный код — допустим это будет решение 1 задачи 1 урока (то, что я пишу здесь — это только для демонстрации).

Создание ветки для файла первой задачи

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

Создание новой ветки
  • Из верхнего меню — New Branch создаст ветвление от текущей активной ветки (main)
  • Из панели git-log — клик ПКМ на названии ветки вызовет меню, где явно прописано “Создать новую ветку от main”.
  • Или из панели слева, или сочетанием клавиш (консольные команды рассматриваем в расширенном курсе по Git в рамках практики по Kotlin).

Жмем “создать” и прописываем имя. Мой проект называется KotlinSprint, поэтому беру первые буквы, номер урока и номер задачи. Затем некое осмысленное название о чем задача. В названии ветки все слова разделяются дефисом.

Нейминг ветки

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

Коммит в рабочую ветку

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

Каждый коммит должен начинаться с префикса проекта и задачи, чтобы вы в том числе легко могли ориентироваться в списке коммитов, когда их станет много. После обозначения префикса через пробел можно описать что было сделано (2-5 слов). Если у вас есть уточняющий вопрос по задаче — задавайте его в ЛС или в комментарий на странице пулл реквеста.

Кнопка Commit сделает коммит в локальную ветку. И чтобы коммит улетел на сервер (в удаленный репозиторий) придется дополнительно вызывать команду Push. Поэтому, когда все проверено и вы готовы пушить коммит, нажимайте Commit and Push. Появится окно подтверждения — список файлов, название локальной ветки и origin ветки. Все окей, жмем Push.

Создание комммита

Все успешно запушилось. Во вкладке с уведомлениями также можно убедиться, что все прошло без ошибок. Открываем страницу с репозиторием на GitHub.

Создание Pull Request

GitHub умеет отслеживать ветки, которые в него пушат. И автоматически предлагает создать Pull Request для новой ветки. То есть предлагает создать запрос на слияние изменений из ветки 1-1, в которой разработчик пилил какую-то фичу. В основную ветку main (или master). Где хранится только проверенный код. Запрос на слияние позволяет наглядно делиться этими изменениями, как в нашем случае — вы отправляете свое решение на код-ревью.

Итак, можно сразу перейти к созданию пулл реквеста, нажав на кнопку Compare && pull request.

Создание Pull Request

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

Для этого переходим во вкладку Pull requests. Жмем New pull request. И выбираем строго справа-налево ветки “откуда” брать изменения и “куда” их вливать. То есть справа указываем нашу рабочую ветку, слева остается по умолчанию основная

ветка. Если все сделать правильно, ниже подтянутся изменения для конкретной ветки и задачи.

Прожимаем Create pull request в первый раз,

Принудительное создание PR.

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

Когда я приступлю к проверке, то по этой ссылке в пулл реквесте я буду оставлять комментарии к конкретным строчкам кода. Либо к задаче целиком — зависит от ситуации и от масштаба бедствия.

Внесение доработок в Pull Request

Допустим, я оставил какой-то развернутый комментарий и отправил ваше решение на доработку. Вы переходите в свой файл с задачей, которая требует правок и вносите какие-то доработки в код.

Как только я изменил файл — слева в окне коммита сразу появился наш измененный файл. То есть система определила, что появились новые изменения, которые еще не закомичены. Причем можно кликнуть на этот файл и посмотреть что конкретно было модифицировано. Слева это старая версия файла, справа обновленная. Это удобно, когда у вас большой проект, было отредактировано много файлов и вы просматриваете что вы там написали.

Теперь можно делать новый коммит. Сперва убедитесь, что вы находитесь в соответствующей ветке. Затем добавляем файл в стейдж (отмечаем галкой), затем пишем сообщение коммита. Префикс по прежнему оставляем, он верный, а сообщение рекомендуется написать также осмысленное — что было сделано в паре слов.

Все, теперь жму сразу Commit and Push. Таким образом коммит сразу уйдет на сервер.

Новый коммит

В окне git-log появился новый коммит, напротив него пометка origin & KS-1-1 — это значит, что коммит запушен в ветку 1-1 и эта ветка сейчас в удаленном репозитории. И так как пулл реквест все еще открыт (в статусе ожидания доработок), то новый коммит подтянется прямо в него.

Просмотр обновленного Pull Request

Убедитесь в этом самостоятельно, перейдя на страницу созданного ранее пулл реквеста. Причем, если нажать на этот коммит, то также наглядно можно увидеть конкретные изменения этого коммита. А если хотите посмотреть последнюю версию изменений в PR целиком — нажимайте на File changed в верхней вкладке.

В другой вкладке Pull Requests вы увидите все пулл реквесты. Смерженные ПРы или закрытые самостоятельно будут переходить в раздел Closed.

Слияние пулл реквеста (Merge Pull Request)

Предположим, что ваша следующая правка оказалась финальной. В таком случае после код-ревью пулл реквест получает статус approved. То есть код полностью проверен, он верный и эта задача может быть влита в основную ветку main (или master). После аппрува (и только после него) дополнительно придет оповещение в бот о принятии задачи. И тогда вы самостоятельно мержите текущую задачу в мастер. То есть прожимаем большую кнопку Merge pull request. Коммит при слиянии можно оставить без изменений и жмем подтверждение.

Merge pull request

Отлично. На странице PR отображается сообщение об успешном влитии рабочей задачи в основную ветку.

Кстати, GitHub предлагает еще защитить ветку от неправомерных слияний (на главной странице репозитория вы увидите сообщение Your main branch isn’t protected). На практике я этого не требую, но вы можете в качестве самостоятельной работы разобраться в этом вопросе и защитить свою ветку. Поставьте ограничение, чтобы в main можно было мержить что-то только через пулл реквест, который имеет минимум 1 аппрув. Их может быть несколько, когда один PR проверяют несколько человек из команды разработки.

Проверка влитых в main изменений на GitHub

Окей. Убедимся в успешном влитии сначала на странице удаленного репозитория. Сперва перейдем на главную страницу репозитория. Тут мы видим две наши ветки — оставим состояние main ветки. На второй строке видно, что минуту назад был сделан такой-то коммит в такой-то папке. Название коммита мы могли изменить перед подтверждением слияния на предыдущем шаге.

Ну и мы можем провалиться в файловую систему

Файловая система

и воочию увидеть файл, который оказался в ветке main. Как вы помните, до слияния этот файл был только в рабочей ветке 1-1. На этом экране также можно переключаться между ветками проекта и наблюдать в каком состоянии проект в той или иной версии.

Параллельное выполнение задач

Вернемся в среду разработки. Здесь все по старому — мы в рабочей ветке 1-1 и перед нами открыт файл, который недавно редактировали.

Теперь представим, что мы продолжили выполнять задачи и выполнили одновременно 2 и 3 задачи. Создаю файл для задачи 1-2 и 1-3. Полагаем, что внутри уже есть выполненное решение. То, что я создаю файлы находясь в ветке 1-1 пока ничего не значит. До того момента, как я не соберусь что-то коммитить.

Согласно нашему флоу под каждую задачу необходимо создать по ветке. Окей, а как мы создаем ветку? Правильно, всегда из основной ветки. Поэтому сперва переключимся в главную ветку main. Делается это по клику на ветку и Checkout.

Новая ветка для новой задачи

Что мы тут видим. Только 2 недавно созданных файла 1-2 и 1-3. Они окрашены в цвет отличный от всех остальных файлов, значит эти изменения нигде не закоммичены. Поэтому куда бы вы не переключались — новые файлы всегда будут так и висеть. Чего не скажешь о модифицированных файлах, потому что в новой ветке файл может тоже отличаться и возникнут конфликты.

Хорошо, а где первая задача? Мы же влили ее в main и даже проверили на сервере, что она действительно оказалась в основной ветке. Если переключиться в ветку 1-1 — задача на месте. Но в main ее нет. Вернемся в main. Дело в том, что Merge мы произвели только на сервере, то есть на удаленном репозитории, в удаленной ветке main (помните, которая с пометкой origin).

Обновление main ветки

Но локальная ветка main еще не знает о том, что в нее что-то слили. Поэтому все, что нам надо это выполнить обновление основной ветки. Для этого я выбираю ее и жму Update.

Обновление ветки main

Произошло обновление или иными словами Fetch, и слитые ранее в мейн изменения теперь видны и в локальном мейне. Все хорошо, все по плану. Обратите внимание и на изменения в git-log — появился новый коммит, который мы сделали, когда недавно влили рабочую ветку в основную. Теперь эта информация видна и в локальном проекте.

Новые ветки для следующих задач

Окей. Ну и у нас остались выполненные, но не отправленные на проверку еще вторая и третья задачи. Создадим же для них ветки. Проверяем, что мы находимся в главной обновленной ветке и создаем KS-1-2. При создании мы сразу переключились в нее. Поэтому можно смело коммитить соответствующую задачу. Открываем окно коммита и добавляем в стейдж только ту задачу (точнее тот файл с задачей), который хотим закоммитить в ветку 1-2. Корректируем сообщение коммита и жмем коммит и пуш.

Корректировка следующего коммита

Теперь то же самое для задачи 3. Новую ветку из мейна можно создать и не переключаясь в нее принудительно. Достаточно выбрать ветку и в контекстном меню выбрать New Branch from Main. Задаем соответствующий нейминг и делаем коммит задачи номер 3.

Исследование git-log

Посмотрим внимательнее на git-log. Здесь наглядно видно, что из коммита, где было сделано слияние выросло две ветки. 1-2 и 1-3. Это говорит о том, что мы все делаем корректно. Могу назвать одну из самых частых ошибок студентов — это создание новой рабочей ветки не из мейна или мастера, а из предыдущей рабочей. Так можно делать, только если четко понимая зачем и как потом разрешить вероятные конфликты в коде. Но по нашему педагогическому гит-флоу так делать не нужно.

Пулл реквесты для новых рабочих веток с решениями

Еще раз вернемся на GitHub, чтобы увидеть там наши свежие запушенные ветки и создать для них запросы на слияние в основную ветку (или пулл реквесты). Здесь я просто прожимаю Compare & Pull Request, убеждаюсь что это тот ПР с корректными изменениями и подтверждаю создание. В title можно развернуто написать о чем будет этот пулл реквест. При этом префикс сохраняется. Проворачиваем то же самое со второй веткой.

Великолепно. На странице со списком пулл реквестов у нас два открытых и один закрытый (он уже смержен). Внутри можно просматривать историю коммитов, измененные файлы и историю нашего обсуждения кода. Удобный и наглядный инструмент.

Последний чекап основной ветки

Наконец, вернемся в проект и закрепим кое-какие фундаментальные вещи. Сейчас мы в рабочей ветке 1-3. Файл с задачей 1-1 виден, потому, что на момент бранчевания из мейна он уже был влит туда. Файл 1-2 не виден тут, потому что пока он находится только в своей ветке 1-2. Ну и файл 1-3 тут виден, соответственно, так как в эту ветку мы его и закоммитили.

Переходим в мейн и видим, что тут только 1-1. Все логично, потому что ветки 1-2 и 1-3 все еще висят на ревью. То есть мы работаем над улучшением кода в отдельно взятых задачах, чтобы не аффектить остальной проект. В этом суть командной разработки и разделения ответственности. Когда отдельные задачи будут полностью допилены и проверены, тогда после аппрува они попадают в основную production ветку.

Теперь я смержу ветку с 3 задачей на GitHub (полагаем, что задача доделана и заапрувлена). Делаю обновление мейна, чтобы слитые изменения прилетели в локальный проект. Все прошло успешно — в мейне появилась 3 задача, а в git-log мы видим новую запись. Все смержилось и ветка наглядно закрылась туда, откуда ранее отбранчевалась.

Ветка 1-2 все еще висит на ревью и ждет своего часа.

Заключение

И это конец! В рамках практики по Kotlin мы выполняем задания, соблюдая правила работы с git. Так, как это принято во всех компаниях, где работает больше одного человека в команде. Все манипуляции в этом видео и даже больше вы научитесь выполнять на автоматизме, не задумываясь.

Для тех, кто собрался стать Android-разработчиком

Пошаговаясхема
Пошаговая
схема

Описание процесса обучения от основ Kotlin до Android-разработчика

Бесплатныеуроки
Бесплатные
уроки

Авторский бесплатный курс по основам языка программирования Kotlin

Обучающийбот
Обучающий
бот

Тренажер и самоучитель по Котлин – бесплатные тесты и практика

Поделиться уроком

Ответить

Ваш адрес email не будет опубликован. Обязательные поля помечены *