Программирование с нуля Командная строка и Git: как разработчики работают с кодом
0%

Командная строка и Git: как разработчики работают с кодом

Командная строка и Git: как разработчики работают с кодом

До сих пор мы говорили о самом коде: переменные, циклы, функции, классы. Но у профессии есть вторая половина, о которой в учебниках пишут меньше, — быт разработчика. Как он запускает программу, как хранит её версии, как отдаёт код коллегам и как возвращает вчерашний рабочий вариант, если сегодня всё сломал.

Этим бытом заведуют два инструмента: терминал и Git. Оба выглядят пугающе — чёрное окно и непонятные слова. Оба на самом деле проще, чем кажутся, потому что делают вещи, которые вы и так делаете мышкой, просто другим способом.

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

Часть первая: терминал

Что это вообще такое

Терминал (он же командная строка, консоль, shell) — это программа, в которой вы управляете компьютером не мышкой, а текстом. Вы печатаете название действия, жмёте Enter, компьютер выполняет и печатает ответ.

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

Аналогия. Проводник (Explorer, Finder) — это витрина супермаркета: вы ходите между полками и берёте что видите. Терминал — это разговор с продавцом за прилавком: вы говорите словами, что вам нужно, и получаете это, не обходя зал.

Где аналогия ломается. Продавец переспросит, если вы сказали непонятное. Терминал — нет: он либо выполнит команду буквально, либо ответит короткой ошибкой. Он не догадывается о ваших намерениях. Это его главное свойство: буквальность.

Зачем он нужен, если есть мышка

Честный ответ: для простых вещей мышка удобнее, и никто не создаёт папки в терминале из принципа. Терминал выигрывает в четырёх ситуациях:

  1. Повторяемость. Команду можно записать, отправить коллеге, вставить в инструкцию. Скриншот с движениями мышки так не перешлёшь.
  2. Массовость. Переименовать 500 файлов мышкой — вечер. Одной командой — секунда.
  3. Удалённые машины. Сервер в дата-центре не имеет экрана и мышки. Единственный способ им управлять — текст.
  4. Инструменты разработчика. Git, установщики библиотек, сборщики проектов, запуск тестов — почти все они управляются командами. Мышка к ним просто не прилагается.

Как его открыть

  • Windows. Нажмите Пуск и наберите PowerShell — откройте «Windows PowerShell». Это современный вариант; старый cmd тоже существует, но команды в нём другие.
  • macOS. Cmd + пробел, наберите Терминал или Terminal.
  • Linux. Ctrl + Alt + T в большинстве систем.
  • Внутри VS Code (мы ставили его в статье Первая программа): меню Terminal → New Terminal. Удобнее всего: терминал открывается сразу в папке проекта.

Откроется окно с чем-то вроде C:\Users\Anna> или anna@laptop:~$. Это приглашение (prompt) — знак, что компьютер готов слушать. Печатать его не нужно, он появляется сам.

Из чего состоит команда

Анатомия команды: приглашение, команда, ключи, аргумент

Разберём по частям:

  • Команда — что сделать. Обычно короткое английское слово или сокращение: ls — от list, cd — от change directory, mkdir — от make directory.
  • Ключи (или флаги, опции) — как именно сделать. Начинаются с дефиса: -l, -a. Порядок не важен, несколько ключей можно слить: -la то же самое, что -l -a.
  • Аргумент — над чем сделать: имя файла или папки. Если не указан, команда обычно работает с текущей папкой.

Части разделяются пробелами. Поэтому имя файла с пробелом внутри нужно брать в кавычки: "мои заметки.txt". Это ошибка номер один у новичков — команда получает два аргумента вместо одного и жалуется на несуществующий файл.

Где я нахожусь: путь

Терминал всегда находится внутри какой-то папки. Это называется текущий каталог (current directory), и все команды по умолчанию действуют именно в нём.

Файлы и папки на компьютере устроены как дерево: папки внутри папок. Путь — это маршрут по этому дереву.

Если мы сейчас находимся в папке calc (она подсвечена), то:

  • абсолютный путь к main.py/home/anna/projects/calc/main.py. Он начинается от корня и работает откуда угодно;
  • относительный путь — просто main.py. Он отсчитывается от текущей папки;
  • .. означает «папка на уровень выше». Путь ../shop/app.py — подняться в projects и спуститься в shop;
  • . означает «текущая папка».

На Windows пути пишутся через обратный слэш и с буквой диска: C:\Users\Anna\projects\calc. На macOS и Linux — через прямой слэш: /home/anna/projects/calc. Символ ~ (тильда) на macOS и Linux — сокращение для вашей домашней папки.

Первые команды: навигация

Откройте терминал и попробуйте по очереди. Ничего не сломается — все эти команды только смотрят.

pwd

pwd (print working directory) печатает, где вы находитесь. Ожидаемый вывод:

/home/anna

В PowerShell на Windows pwd тоже работает и напечатает что-то вроде C:\Users\Anna.

ls

ls (list) показывает содержимое текущей папки:

Документы  Загрузки  Изображения  projects

Добавим ключи:

ls -la

-l — подробный вид (размер, дата, права доступа), -a — показать в том числе скрытые файлы, имена которых начинаются с точки. В PowerShell тот же смысл у команды ls -Force или dir.

cd projects

cd (change directory) — перейти в папку. Проверьте pwd — путь изменился.

cd ..

Вернулись на уровень выше. Просто cd без аргументов (или cd ~) вернёт вас в домашнюю папку из любого места.

Два приёма, которые экономят часы:

  • Tab — автодополнение. Наберите cd proj и нажмите Tab: терминал допишет projects сам. Это не только быстрее — это ещё и защита от опечаток.
  • Стрелка вверх — предыдущая команда. Нажмите несколько раз, чтобы пролистать историю. Повторять длинную команду руками не нужно никогда.

Создание, копирование, удаление

mkdir myproject        # создать папку myproject
cd myproject           # зайти в неё

Создать пустой файл:

touch notes.txt        # macOS / Linux

В PowerShell на Windows:

New-Item notes.txt

Дальше — команды, одинаковые на всех системах (в PowerShell они работают как псевдонимы):

cp notes.txt notes-copy.txt    # копировать (copy)
mv notes.txt zametki.txt       # переименовать или переместить (move)
rm zametki.txt                 # удалить (remove)

Внимание. rm удаляет мимо корзины и без вопросов. Восстановить нельзя. Особенно опасна связка rm -rf — она удаляет папку со всем содержимым молча. Никогда не вставляйте команду с rm -rf из интернета, не прочитав её целиком. Пока вы учитесь, удаляйте файлы мышкой — это совершенно нормально.

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

Ради этого всё и затевалось. Создайте в папке myproject файл hello.py (можно в VS Code) с таким содержимым:

# Простая программа, которую мы запустим из терминала
name = input("Как вас зовут? ")   # ждём ввод пользователя
print(f"Привет, {name}!")         # f-строка подставляет значение переменной

Теперь в терминале, находясь в папке с файлом:

python hello.py

Вывод:

Как вас зовут? Анна
Привет, Анна!

Что здесь произошло: python — это команда (программа-интерпретатор), hello.py — аргумент, то есть файл, который ей скормили. Интерпретатор прочитал файл сверху вниз и выполнил.

Если вместо этого вы увидели:

python: command not found

или

'python' is not recognized as an internal or external command

— значит, терминал не знает, где лежит Python. Попробуйте python3 вместо python (частая ситуация на macOS и Linux). Если не помогло — Python установлен без галочки «Add to PATH», и его нужно переустановить с этой галочкой; мы разбирали это в статье Первая программа.

А если увидели:

python: can't open file 'hello.py': [Errno 2] No such file or directory

— Python запустился, но файла в текущей папке нет. Дословно: «не могу открыть файл hello.py: нет такого файла или каталога». Проверьте pwd и ls: скорее всего, вы находитесь не в той папке. Это не поломка, это просто «вы не там».

Программа, которая принимает аргументы

Раз мы уже в терминале, покажу приятный трюк: программа может получать аргументы из команды — ровно так же, как их получают ls или cp.

import sys   # модуль sys даёт доступ к тому, как программу запустили

# sys.argv — список: [имя_файла, первый аргумент, второй аргумент, ...]
if len(sys.argv) < 2:                     # len — длина списка
    print("Использование: python greet.py ИМЯ")
else:
    name = sys.argv[1]                    # [0] — это сам greet.py, [1] — первый аргумент
    print(f"Привет, {name}!")

Сохраните как greet.py и запустите двумя способами:

python greet.py Анна
Привет, Анна!
python greet.py
Использование: python greet.py ИМЯ

Вот и вся магия «настоящих» консольных программ: они читают sys.argv и ведут себя по-разному. Списки мы разбирали в статье Списки, словари и множестваsys.argv самый обычный список строк.

Ещё три вещи, которые надо знать

  • Ctrl + C — прервать выполнение. Если программа зависла в бесконечном цикле или ждёт чего-то вечно, это ваша кнопка спасения.
  • Ctrl + L или команда clear (cls в PowerShell) — очистить экран. Ничего не удаляет, просто убирает визуальный шум.
  • exit — закрыть терминал.

Часть вторая: Git

Проблема, которую он решает

Знакомая картина:

курсовая.docx
курсовая_финал.docx
курсовая_финал2.docx
курсовая_финал_ИСПРАВЛЕННЫЙ.docx
курсовая_финал_ИСПРАВЛЕННЫЙ_вот_этот.docx

С кодом то же самое, только хуже: вы правите работающую программу, ломаете её, и не помните, что именно поменяли двадцать минут назад. Отменить (Ctrl + Z) уже нельзя — редактор закрывали. Вчерашней рабочей версии нет.

Git — это программа, которая ведёт историю изменений вашего проекта. Она умеет:

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

Аналогия. Git — как режим «История версий» в Google Документах, только вы сами решаете, когда сделать точку сохранения, и подписываете каждую своими словами.

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

Git — это не GitHub

Путаница, на которой спотыкаются все. Запомните разницу сразу:

  • Git — программа на вашем компьютере. Работает без интернета. Хранит историю в скрытой папке .git внутри проекта.
  • GitHub (а также GitLab, Bitbucket) — сайт, куда можно выложить копию этой истории: чтобы был бэкап, чтобы показать код другим, чтобы работать вместе.

Git можно использовать вообще без GitHub. GitHub без Git — нельзя.

Четыре места, где живёт ваш код

Это центральная идея Git. Пока она не уложится, команды будут казаться случайным набором слов.

Четыре зоны Git: рабочая папка, индекс, история и сервер

Разберём словами:

  1. Рабочая папка — обычные файлы, которые вы видите и правите в редакторе. Здесь всё как всегда.
  2. Индекс (staging area, «сцена») — черновик следующего снимка. Вы кладёте сюда те изменения, которые хотите сохранить вместе.
  3. История (локальный репозиторий) — цепочка сделанных коммитов в папке .git. Отсюда уже ничего не пропадает.
  4. Сервер (GitHub) — копия истории в интернете.

Зачем нужен индекс? Самый частый вопрос новичка. Представьте: вы за час поправили опечатку в README и заодно переписали функцию расчёта. Это два разных дела, и хочется два разных коммита с разными описаниями. Индекс позволяет сказать: «сейчас сохрани только README, функцию сохраним отдельно».

Аналогия. Индекс — это коробка, в которую вы складываете вещи перед тем, как заклеить её скотчем и подписать. git add — положить вещь в коробку. git commit — заклеить и подписать. Вещи из комнаты (рабочей папки) при этом никуда не деваются.

Установка и первая настройка

Проверьте, установлен ли Git:

git --version
git version 2.43.0

Если команда не найдена — скачайте с git-scm.com/downloads и установите со всеми настройками по умолчанию.

Дальше — единственная настройка, которую делают один раз в жизни. Git подписывает каждый коммит вашим именем, поэтому он должен его знать:

git config --global user.name "Anna Ivanova"
git config --global user.email "anna@example.com"

--global значит «для всех проектов на этом компьютере». Почта попадёт в историю проекта и будет видна всем, кто её откроет, — если это вас смущает, GitHub позволяет использовать специальный служебный адрес вида имя@users.noreply.github.com.

Первый репозиторий

Репозиторий — это папка проекта, за которой Git следит. Создадим её:

mkdir calc
cd calc
git init
Initialized empty Git repository in /home/anna/calc/.git/

Внутри появилась скрытая папка .git — вся история будет храниться там. Удалите её — и проект превратится в обычную папку без истории. Больше туда заглядывать не нужно.

Создайте в папке файл calc.py:

def add(a, b):
    """Складывает два числа и возвращает результат."""
    return a + b

print(add(2, 3))   # ожидаемый вывод: 5

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

git status
On branch main

No commits yet

Untracked files:
  (use "git add <file>..." to include in what will be committed)
        calc.py

nothing added to commit but untracked files present (use "git add" to track)

Переведём дословно, потому что Git всегда подсказывает следующий шаг:

  • On branch main — вы на ветке main (о ветках чуть ниже);
  • No commits yet — снимков ещё нет;
  • Untracked files — «неотслеживаемые файлы»: Git видит calc.py, но пока не следит за ним;
  • в скобках — прямая подсказка, что делать дальше: use "git add".

Git — редкая программа, которая почти всегда пишет в ответе, какую команду набрать следующей. Читайте эти скобки, там ответ.

Первый коммит

git add calc.py

Изменение положено в индекс. Проверьте git status — файл теперь в разделе Changes to be committed.

git commit -m "Добавил функцию сложения"
[main (root-commit) 8f3a1c2] Добавил функцию сложения
 1 file changed, 5 insertions(+)
 create mode 100644 calc.py

Ключ -m (message) задаёт сообщение коммита — описание того, что вы сделали. Без -m Git откроет текстовый редактор и будет ждать, что вы напишете сообщение там (и новички часто застревают в редакторе vim; если это случилось, нажмите Esc, наберите :q! и Enter, чтобы выйти).

8f3a1c2 — начало хеша коммита, его уникального идентификатора. По нему коммит можно найти в истории.

Посмотрим историю:

git log --oneline
8f3a1c2 Добавил функцию сложения

Сделайте ещё одно изменение — добавьте в calc.py функцию вычитания — и повторите цикл:

git add calc.py
git commit -m "Добавил функцию вычитания"
git log --oneline
b1d4e77 Добавил функцию вычитания
8f3a1c2 Добавил функцию сложения

Вот и всё. Этот цикл изменил → add → commit вы будете повторять всю жизнь.

Жизненный цикл файла

Каждый файл в репозитории находится в одном из состояний, и команды переводят его между ними:

Понимая эту схему, вы понимаете 90% повседневного Git.

Что писать в сообщении коммита

Сообщение читают люди — включая вас через полгода. Правила простые:

  • Плохо: фикс, изменения, asdf, работа. Через месяц это ничего не скажет.
  • Хорошо: Исправил деление на ноль в calc.py, Добавил чтение настроек из config.json.
  • Пишите, что сделано, а не что вы при этом чувствовали.
  • Один коммит — одно законченное изменение. Не сваливайте день работы в один снимок «сделал всё».

Чего не должно быть в репозитории: .gitignore

В проекте всегда заводится мусор: временные файлы Python в папке __pycache__, настройки редактора, служебные файлы системы. Хранить их в истории бессмысленно.

Создайте в корне проекта файл с именем .gitignore (да, начинается с точки):

__pycache__/
*.pyc
.venv/
.DS_Store
.vscode/

Звёздочка * означает «любой набор символов», поэтому *.pyc — все файлы с расширением .pyc. Слэш в конце означает папку.

Отдельно и очень важно: в репозиторий нельзя класть пароли, ключи доступа и токены. Если вы закоммитили пароль и выложили на GitHub, считайте его скомпрометированным — удалить его из истории сложно, а роботы сканируют публичные репозитории круглосуточно. Секреты хранят в отдельном файле, который перечислен в .gitignore.

Как отменить и вернуться

Здесь Git окупается.

Посмотреть, что я наменял с последнего коммита:

git diff

Вывод показывает изменения построчно: строки со знаком - удалены, со знаком + добавлены.

Отменить правки в файле и вернуть его как в последнем коммите:

git restore calc.py

Осторожно: несохранённые правки в этом файле пропадут — но именно этого вы и просили.

Вынуть файл из индекса (передумали включать в коммит):

git restore --staged calc.py

Посмотреть проект таким, каким он был в старом коммите:

git checkout 8f3a1c2

Git скажет что-то про detached HEAD — это не поломка, а предупреждение «вы гуляете по прошлому, а не работаете». Вернуться в настоящее:

git switch main

Главное, что стоит запомнить: всё, что попало в коммит, вернуть можно. Всё, что не попало, — нет. Поэтому коммитьте часто.

Ветки

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

Аналогия. Вы пишете книгу и хотите попробовать другую концовку. Делаете копию рукописи, экспериментируете в ней, а оригинал не трогаете. Понравилось — переносите изменения в оригинал; не понравилось — выбрасываете копию.

Где аналогия ломается. Копия рукописи — это отдельные листы бумаги, которые надо потом сверять вручную. Git хранит не копии файлов, а связи между коммитами, и сливает ветки автоматически — вручную придётся вмешаться только там, где обе стороны правили одни и те же строки.

На схеме: основная линия main продолжала жить (в неё внесли правку README), пока в ветке feature-divide делали деление. Потом ветки слили, и обе работы оказались в main.

Команды:

git switch -c feature-divide   # создать ветку и перейти в неё
# ... правим файлы, делаем коммиты ...
git switch main                # вернуться в основную ветку
git merge feature-divide       # влить изменения из ветки в main
git branch -d feature-divide   # удалить ветку, она больше не нужна

Если Git сообщит CONFLICT (content): Merge conflict in calc.py — это конфликт слияния: обе ветки поменяли одни и те же строки, и Git не знает, чью версию оставить. Он вставит в файл разметку:

<<<<<<< HEAD
return a / b
=======
return round(a / b, 2)
>>>>>>> feature-divide

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

GitHub: код в интернете

Пока вся история жила только на вашем диске. Чтобы сделать копию в интернете:

  1. Зарегистрируйтесь на github.com.
  2. Нажмите New repository, задайте имя (например, calc), не ставьте галочки на README и .gitignore — они у нас уже есть.
  3. GitHub покажет готовые команды. Они будут примерно такие:
git remote add origin https://github.com/anna/calc.git
git push -u origin main

git remote add origin ... — запомнить адрес сервера под коротким именем origin (это просто традиция, никакого волшебства в слове нет). git push — отправить коммиты на сервер. Ключ -u связывает вашу ветку с серверной, чтобы дальше хватало просто git push.

Обмен с сервером устроен так:

Четыре команды на все случаи жизни:

  • git push — отправить свои коммиты на сервер;
  • git pull — забрать оттуда чужие;
  • git clone https://github.com/кто-то/проект.git — скачать чужой проект целиком вместе со всей историей;
  • git fetch — посмотреть, что появилось на сервере, ничего не меняя у себя.

Начинайте день с git pull, заканчивайте git push. Этой привычки хватит надолго.

Типичные ошибки и что говорят сообщения

fatal: not a git repository (or any of the parent directories): .git Дословно: «это не git-репозиторий». Вы запускаете команду не в той папке — там нет .git. Проверьте pwd, зайдите в папку проекта или сделайте git init.

nothing to commit, working tree clean «Нечего коммитить, рабочее дерево чистое». Не ошибка. Значит, вы либо ничего не меняли, либо забыли git add.

error: pathspec 'main' did not match any file(s) known to git Ветки с таким именем нет. В старых проектах основная ветка называется master, а не main. Посмотрите список: git branch.

Updates were rejected because the remote contains work that you do not have locally «Отправка отклонена: на сервере есть работа, которой у вас нет». Кто-то (или вы с другого компьютера) уже отправил коммиты. Сделайте git pull, разберитесь с возможным конфликтом, потом git push.

Please tell me who you are Вы не сделали git config user.name и user.email. Git прямо в сообщении пишет нужные команды.

Коммит с одним огромным изменением. Технически не ошибка, но история становится бесполезной. Лучше пять маленьких понятных коммитов, чем один под названием «всё».

Забытый .gitignore. Через неделю в репозитории 900 файлов __pycache__. Заводите .gitignore первым делом в новом проекте.

Практика

Задания идут от простого к сложному. Всё делается в терминале — так и задумано.

1. Освоиться в терминале. Откройте терминал и не трогая мышку: узнайте текущую папку, посмотрите её содержимое, создайте папку praktika, зайдите в неё, создайте внутри пустой файл readme.txt, убедитесь, что он там есть, вернитесь на уровень выше. Подсказка: pwd, ls, mkdir, cd, touch (или New-Item в PowerShell), снова ls, cd ... Пользуйтесь Tab — он допишет имена за вас.

2. Первый репозиторий. Внутри praktika сделайте git init, создайте файл hello.py с одной строкой print("Привет!"), запустите его через python hello.py, затем сделайте коммит с внятным сообщением. Проверьте результат через git log --oneline. Подсказка: после каждого шага набирайте git status и читайте, что он советует в скобках. Это лучший способ запомнить команды.

3. История из трёх коммитов. Добавляйте в hello.py по одной функции за раз — сложение, вычитание, умножение — и после каждой делайте отдельный коммит. Затем посмотрите git log --oneline и git diff между состояниями. Подсказка: чтобы увидеть, что изменилось в конкретном коммите, есть команда git show <первые-7-символов-хеша>.

4. Отмена и .gitignore. Испортите hello.py — удалите половину кода и сохраните. Убедитесь через git status и git diff, что Git это заметил, и верните файл командой git restore. Затем запустите программу так, чтобы появилась папка __pycache__ (для этого нужен второй файл, который импортирует первый), и добавьте .gitignore, чтобы Git перестал её показывать. Подсказка: __pycache__ появляется при import. Создайте main.py со строкой import hello. Про импорт модулей подробнее — в статье Функции.

5. Ветка и слияние (со звёздочкой). Создайте ветку feature-divide, добавьте в ней функцию деления с проверкой на ноль, сделайте коммит. Вернитесь в main, поправьте там что-нибудь другое и тоже закоммитьте. Слейте ветку в main и посмотрите историю командой git log --oneline --graph --all. Подсказка: ключ --graph рисует ветки псевдографикой прямо в терминале — вы увидите ту же картинку, что была на схеме выше. Если получите конфликт — отлично, это лучший способ научиться их решать: откройте файл, оставьте нужный вариант, удалите строки-разделители, git add, git commit.

Мини-итог

Терминал — способ управлять компьютером текстом. Он буквален и ничего не додумывает, но зато повторяем, работает удалённо и умеет всё, что нужно инструментам разработчика. Минимальный набор: pwd, ls, cd, mkdir, python файл.py. Плюс Tab для автодополнения, стрелка вверх для истории и Ctrl + C, чтобы прервать зависшую программу.

Git — история изменений проекта. Ключ к пониманию — четыре зоны: рабочая папка, индекс, локальная история, сервер. Ежедневный цикл умещается в три команды: git status, git add, git commit -m "...". Ветки позволяют экспериментировать, не ломая рабочую версию, а GitHub хранит копию в интернете и служит точкой обмена с коллегами.

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

Куда идти дальше:

Что дальше

У вас теперь есть всё, что нужно для настоящей работы: вы знаете язык, умеете разбирать ошибки, запускаете код из терминала и храните его историю в Git. Не хватает одного — опыта пройти путь целиком.

Пора собрать всё вместе и написать проект от идеи до работающей программы: придумать, разбить на шаги, реализовать, отладить и выложить на GitHub.

Первый проект: от идеи до работающей программы

Нашли неточность? Выделите фрагмент текста — рядом появится жучок.

Нужен разбор именно вашей ситуации?

Статья описывает общий случай. Если у вас частный — можно разобрать его отдельно, платно. А если не хватает целого материала, предложите тему: её оплачивают вскладчину, и она выходит открытой для всех.

Доска запросов