Skip to content

Latest commit

 

History

History
709 lines (554 loc) · 44.5 KB

Git.md

File metadata and controls

709 lines (554 loc) · 44.5 KB

Основные понятия Git

Как работает Git

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

В сравнении со всеми другими системами контроля версий, Git имеет уникальный подход к работе со своими данными. Все остальные системы хранят набор файлов и списки изменений (дельты) этих файлов с течением времени.

Файл Версия I Версия II Версия III
A.txt delta I delta II
B.txt delta I delta II

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

Git рассматривает данные не как таблицы изменений конкретных файлов, а как поток снимков (stream of snapshots).

Каждый снимок (shapshot) означает сохранение определённого состояния проекта. Система запоминает, как выглядит каждый файл проекта на момент сохранения (делает снимок) и сохраняет ссылку на этот снимок. Если файл не изменился, то Git не запоминает его вновь, а создаёт ссылку на идентичную версию файла из предшествующего снимка.

Файл Версия I Версия II Версия III
A.txt A1 A2 A2
B.txt B1 B1 B2

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

Благодаря такому подходу Git чем-то похож на файловую систему.

Состояния файлов

Git делит все файлы на отслеживаемые и неотслеживаемые.

Отслеживаемые (tracked) файлы — файлы, которые были в последнем снимке состояния проекта, неотслеживаемые (untracked) файлы — все остальные.

Также имеются категория игнорируемых (ignoring) файлов. Изменения этих файлов Git игнорирует.

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

Пример содержимого .gitignore.

node_modules/
logs/
dist/
.env

Состояния отслеживаемых файлов

  • Неизменённый (Unmodified). Файл не изменён.
  • Изменённый (Modified). Файл изменён локально.
  • Подготовленный (Staged). Файл изменён локально и помечен для включения в следующий коммит.
  • Зафиксированный (Committed). Версия файла сохранена в истории Git.

Три области Git

  • Рабочая директория (Working Directory). Файлы распаковываются из сжатой базы данных репозитория и располагаются на локальном диске для чтения и записи. Здесь происходит работа с ними до тех пор, а затем они переходят
  • Область подготовленных файлов (Staging Area). Здесь содержатся сведения о подготовленных файлах и их изменениях, которые должны попасть в следующий коммит. Эта область является частью папки .git.
  • Папка .git (.git directory, Repository). Здесь хранятся метаданные (данные о данных) и Git-объекты текущего проекта, в том числе история коммитов.

Коммит и индекс

Коммит (Commit) — отметка (точка, этап) в истории Git. К этой точке можно вернуться. Вся история проекта состоит из цепочки связанных друг с другом коммитов. Каждый коммит имеет родительский коммит и зависит от него.

Близкими по смыслу коммиту понятиями являются версия (version) и снимок (snapshot).

Уникальным идентификатором коммита является его хеш.

commit 54e2f882f077cb0f4a1ca0600eada25cc96c7e5a
commit ec1b065a072c545ca2849e0c05b60c520bdc39e4

Индекс (Index) — снимок следующего намеченного коммита.

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

/* добавить изменённый файл */
git add <filename>

/* добавить папку с изменёнными файлами */
git add <directory>

/* добавить все изменённые файлы */
git add .

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

git commit

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

git commit -m "Commit message here"

Ветвление

Все системы контроля версий поддерживают возможность ветвления.

Ветка (Branch) — независимая линия разработки проекта.

Ветка состоит из последовательности коммитов.

Базовый коммит ветки (Base commit) — коммит, с которого началась (была создана) ветка.

Будем обозначать латинискими буквами хеши коммитов: A, B, C и т.д.

/* Ветвление */
feature              |                  F —— G
                     |                /
develop              |          C —— D —— E
	             |         /
master (основная)    |   A —— B

На изображении выше базовым коммитом для ветки master является коммит A, для ветки BC, для featureD.

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

От основной ветки создаются новые ветки, от них тоже при необходимости создаются ветки.

Базовым коммитом новой ветки становится последний на момент создания коммит текущей ветки.

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

Для управления ветками используется команда branch.

/* создание новой ветки */
git branch <branch_name>

/* список всех веток */
git branch -a

/* переименование ветки */
git branch -m <old_name> <new_name>

/* удаление ветки */
git branch -D <branch_name>

Для переключения между ветками используется команда checkout.

/* переключение на ветку branch_name */
git checkout <branch_name>

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

HEAD и верхушка ветки

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

Это позволяет Git хранить ветку не как последовательность коммитов, а просто как ссылку на последний её коммит.

Верхушка ветки (Branch tip, Branch head) — последний коммит ветки. У каждой ветки есть одна вершутка.

HEAD — указатель на текущую ветку (указатель на последний коммит текущей ветки). HEAD может быть только один в текущий момент времени для всего проекта.

Когда мы создаём новую ветку, её базовым коммитом становится тот, на который ссылается HEAD.

Если открыть файл HEAD в папке .git, то можно увидеть, что он содержит ссылку на текущую ветку.

cat .git/HEAD
/* ref: refs/heads/master */

checkout develop
cat .git/HEAD
/* ref: refs/heads/develop */

Если открыть папку refs/heads, то там можно видеть, что Git хранит для каждой ветки отдельный файл, в котором хранится хеш последнего коммита ветки.

cat ./git/refs/heads/master
/* 1ed2bf4eebbcd0515a638b48550a7eb81c7c01e5 */

Основные команды Git

merge

Команда merge позволяет слить (смержить) истории двух веток в одну, то есть из двух последовательностей коммитов создать одну.

Целевой ветка (target branch) сливается в текущую ветку (current branch), которую также называют рабочей.

git merge <target_branch>

При слиянии изменения затрагивают только текущую ветку: целевая ветка остаётся без изменения.

Как работает merge

Git просматривает цепочку коммитов обеих веток, пытаясь найти их общий коммит. Обычно такой коммит имеется (как минимум, начальный коммит).

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

Если общий коммит между двумя ветками найден, то возможны два случая

  • Только в одной ветке были новые коммиты с момента общего коммита. В таком случае одна ветка является продолжением другой. Используется fast-forward merge.
  • Обе ветки имеют новые коммиты с момента общего коммита. Это означает, что они развивались параллельно, независимо от друга. Используется true merge.

Fast-forward merge

Fast-forward merge (перемотка вперёд) используется, если одна ветка является продолжением другой.

Возможны два случая: целевая ветка длиннее или короче текущей.

Рассмотрим случай, когда целевая ветка впереди (длиннее) текущей. Тогда при слиянии веток указатель на последний коммит текущей ветки (верхушка ветки) сдвигается на последний коммит целевой ветки. После такого слияния истории двух веток становятся идентичными.

/* до слияния веток develop и master целевая ветка develop была
впереди на 2 коммита C и D */
develop          |          C —— D
	         |         /
master (current) |   A —— B
git checkout master
git merge develop
/* после слияния верхушки веток указывают на один и тот же коммит D */
develop          |          C —— D
	         |         /
master (current) |   A —— B —— C —— D

Если отменить последний коммит в ветке master, то в ней отменится только коммит D.

/* отмена последнего коммита при помощи git reset HEAD~ */
develop          |          C —— D
	         |         /
master (current) |   A —— B —— C

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

В случае, когда целевая ветка позади (короче) текущей, ничего не произойдёт, поскольку текущая ветка уже содержит все актуальные изменения (содержит все коммиты целевой ветки).

git checkout develop
git merge master

Fast-forward merge не будет применён при использовании флага --no-ff, применится true merge.

git merge --no-ff branch_name

True merge

Если текущая и целевая ветки развивались независимо друг от друга в течение какого-то времени, тогда каждая из них имеет новые коммиты с момента общего коммита веток и использовать fast-merge не получится. В этом случае применяется true merge (3-way merge), которые использует 3-х сторонний алгоритм (3-way algorithm). Алгоритм так называется, поскольку учитываются 3 стороны (состояние до изменений, изменения целевой ветки, изменения текущей ветки).

При применении true merge создаётся особый тип коммита, имеющий сразу два родительских коммита, — merge commit. В нём содержатся новые изменения, которые были в целевой ветки, но не были в текущей.

/* до слияния веток с момента общего коммита B целевая ветка develop 
имеет 2 коммита C и D, текущая ветка master имеет один коммит E */
develop          |          C —— D
	         |         /
master (current) |   A —— B —— E
git checkout master
git merge develop
/* после слияния в текущей ветке master появился merge commit H,
содержащий в себе все изменения коммитов C, D, E */
develop          |           C —— D
	         |         /       \
master (current) |   A —— B —— E —— H

Как и в случае fast-forward merge, изменения true merge затрагивают только текущую ветку, поэтому merge commit создаётся только в текущей ветке (коммит H появился только в master).

Аналогичный результат бы получился, если бы ветка develop была текущей, а master — целевой. Разница лишь в том, что в этом случае коммит H хранился бы только в develop.

Если из master удалить последний коммит, то состояние текущей ветки станет таким, каким оно было до слияния. Таким образом, чтобы отменить все последствия слияния двух веток стратегией true merge, достаточно удалить только merge commit.

/* отмена последнего коммита при помощи git reset HEAD~ */
develop          |          C —— D
	         |         /
master (current) |   A —— B —— E

Конфликты при true merge и их разрешение

Если новые коммиты сливающихся веток затрагивают одни и те же файлы и по-разному изменяют их, возникают конфликты слияния (merge conflicts). Git не может автоматически разрешить их, поскольку изменения производились параллельно. Разработчик должен сам решить, какие изменения стоит оставить.

Для отображения конфликтов по умолчанию использует 2 версии файла и следующий синтаксис.

  • <<<<<<< — изменения коммита текущей ветки.
  • >>>>>>> — изменения коммита целевой ветки.
  • ======= — разделяющая полоса.
<<<<<<<
/* изменения в текущей ветке */
=======
/* изменения в целевой ветке */
>>>>>>>

Можно настроить команду merge таким образом, чтобы также показывалось и состояние до изменений. За это отвечает свойство merge.conflictStyle со значением diff3. Синтаксис: |||||||.

<<<<<<<
/* изменения в текущей ветке */
|||||||
/* до изменений */
=======
/* изменения в целевой ветке */
>>>>>>>

Чтобы разрешить конфликт, следует выбрать необходимые изменения и убрать всё лишнее, затем эти изменения добавляются в merge commit.

Пример конфликта в одном из файлов (в коммите текущей ветки используется const, в коммите целевой ветки — let).

<<<<<<< HEAD (Current Change)
let name = 'Notes';
=======
const name = 'Notes';
>>>>>>> develop (Incoming Change)

В этом примере можно оставить следующую строку и добавить её в merge commit.

let name = 'Notes';

rebase

Как работает rebase

Базовый коммит ветки (Base commit) — коммит, с которого начинается (создана) ветка.

Перебазирование (Rebasing) — перемещение последовательности коммитов к новому базовому коммиту.

git rebase <base>

Перебазирование переписывает историю текущей ветки.

Когда мы указываем ветку в качестве <base> для команды rebase, берётся последний коммит этой ветки.

/* до перебазирования целевая ветка develop по сравнению с master
имеет новый коммиты C и D, базовым для неё является коммит B */
develop (current) |          C —— D
	          |         /
master            |   A —— B —— E
git checkout develop
git rebase master
/* после перебазирования базовым коммитом для develop стал коммит E
(последний в master), C* и D* — копии коммитов C и D с новыми хешами */
develop (current) |                C* —— D*
	          |               /
master            |   A —— B —— E

Если бы перебазировался не develop, а master, то изменились бы все коммиты ветки master с момента их общего коммита с develop (в данном случае это только коммит E).

git checkout master
git rebase develop
/* после перебазирования базовым коммитом для master остался коммит A
(поскольку начало историй обеих веток совпадают), E* — копия
коммита E с новым хешем */
develop          |          C —— D
	         |         /
master (current) |   A —— B —— C —— D —— E*

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

При перебазировании возможны такие же конфликты, как и при true merge. Решаются они аналогично.

rebase vs merge

Самое основное отличие заключается в том, что rebase перезаписывает историю, а merge только дополняет её.

Fast-forward просто копирует коммиты из одной ветки в конец ветки.

True merge создаёт новый merge commit, содержащий все необходимые текущей ветке изменения целевой ветки (с необходимыми правками, если были конфликты).

Недостаток fast-forward merge: не может работать с ветками, которые развивались параллельно.

Недостаток true merge: merge commits загрязняют историю приложения.

Rebase позволяет заменять базовый коммит текущей ветки на другой коммит. Это позволяет достигнуть идеальной линейной истории путём её постоянного изменения, поскольку можно всегда размещать новые ветки в конце базовой. Тем не менее, эта история будет характерна только текущей ветке.

Если rebase затронет коммиты, которые не были созданы в текущей ветке, то при слиянии с другой веткой Git увидит две разные истории и создаст большой merge commit, который использует обе версии. Появится дублирование одних и тех же изменений.

Таким образом, rebase лучше использовать только для новых коммитов, если есть необходимость как-то подправить их. Если затрагиваются коммиты, которые имеются в других ветках и в будущем есть вероятность того, что эти ветки сольются вместе, rebase лучше не использовать.

Другие возможности rebase и интерактивный режим

Помимо перебазирования команда rebase имеет интерактивный режим, который позволяет полностью переписать историю определённого числа коммитов. Для перехода в интерактивный режим используется флаг -i. Для выбора N последнимх коммитов используется указатель HEAD~N.

git checkout develop
git rebase -i HEAD~2 /* изменение истории двух последних коммитов текущей ветки */

В этом случае будет открыт текстовый редактор со следующим содержимым.

pick C Message for the commit C
pick D Message fof the commit D

# Rebase B..D onto B
#
# Commands:
#  p, pick = use commit
#  r, reword = use commit, but edit the commit message
#  e, edit = use commit, but stop for amending
#  s, squash = use commit, but meld into previous commit
#  f, fixup = like "squash", but discard this commit's log message
#  d, drop <commit> = remove commit
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
#
# However, if you remove everything, the rebase will be aborted.
#
# Note that empty commits are commented out

До символов # показывается список всех выбранных для редактирования коммитов. По умолчанию к каждому из них принимается команда pick (оставить как есть), но её можно заменить текстом на одну из следующих:

  • reword - изменение сообщения коммита (окно для изменения сообщения появится после).
  • squash - совместить коммит с предыдущим (далее надо будет набрать общий текст для нового скомбинированного коммита).
  • fixup - совместить коммит с предыдущим (с отменой сообщения коммита).
  • drop - удалить коммит и его изменения из истории (это можно также сделать, удалив строку с коммитом из списка).
  • Также можно менять строки в списке местами, тогда соответствующие им коммиты также поменяются местами в истории.

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

Если нужно перезаписать сообщение последнего коммита, то можно вместо rebase использовать команду commit с флагом --ammend:

git commit --amend -m "Updated last commit message"

pull и fetch

Команда git fetch используется для того, чтобы получить информацию о последних изменениях на удалённой ветке (origin/). Таким образом можно узнать, были ли изменения вообще.

git fetch
/*
From github.com:YourName/RepositoryName
   2eefe71..ac391ab  develop   -> origin/develop
   fca7c62..c31477c  feature/1 -> origin/feature/1
 * [new branch]      feature/2 -> origin/feature/2
 * [new branch]      feature/3 -> origin/feature/3
*/

Выше можно видеть, что ветки develop и feature/1 отличаются от своих одноимённых удалённых веток хешем последних коммитов, а ветки feature/2 и feature/3 новые и их нет локально.

Команда git fetch помимо информации об изменениях скачивает и сами изменения, но их не слияние с локальной веткой не происходит. Это можно проверить командой git diff.

git diff origin/develop
/*
diff --git a/Git.md b/Git.md
index abe21d5..e207862 100644
+++ b/client/Dockerfile
- Hello
+ Hello, Notes!
*/

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

Команда git pull также, как и git fetch получает изменения и информацию о них, но дополнительно сливает изменения в локальную ветку.

По сути, git pull объединяет в себе две команды: git fetch и git merge.

Откат изменений с reset, checkout и revert

Обычно HEAD указывает на верхушку ветки (branch tip).

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

Все три команды reset, checkout, revert позволяют откатывать (undo) изменения, но делают это по-разному.

Команда checkout перемещает указатель HEAD.

/* до checkout HEAD ветки совпадал с верхушкой (tip) 
ветки master и указывал на коммит E */
                     (HEAD,
	             master)        
A ——— B ——— С ——— D ——— E
git checkout B
/* после checkout */
  (detached
     HEAD)           (master)
A ——— B ——— С ——— D ——— E

Если ввести git branch, то он выдаст ветку (HEAD detached at B).

Если ввести git log, то коммит B в текущей ветке будет последним.

/* git log */
    (HEAD)
A ——— B

Таким образом, при помощи команды checkout Git позволяет переключиться на определённый снимок проекта в прошлом, не изменяя при этом реальную ветку. Можно сделать какие-то тестовые изменения, посмотреть или скопировать какие-то файлы, а затем вернуться на полную версию ветки.

Команда revert выбирает коммит и создаёт новый коммит, который откатывате изменения выбранного коммита.

/* до revert */
	        (HEAD,
	        master)        
A ——— B ——— С ——— D
git revert C
/* после revert создаётся коммит E, отменяющий все изменения коммита D,
и таким образом возвращающий состояние проекта на момент коммита B */
	              (HEAD,
	              master)        
A ——— B ——— С ——— D ——— E

Если при помощи revert откатывается не последний коммит (например, C), то могут появиться конфликты (поскольку коммит D зависеть от некоторых изменений коммита C).

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

Команда reset сбрасывает все изменения и историю до определённого коммита.

/* до reset */
	        (HEAD,
	        master)        
A ——— B ——— С ——— D
git reset B
/* после reset */
   (HEAD,
   master)        
A ——— B

Полезные возможности Git

Отмена последнего коммита

git reset HEAD~

Перенос коммитов из одной локальной ветки в другую

Например, перенос N коммитов из локальной ветки A и локальную ветку B.

git checkout B
git merge A
git checkout A
git reset --hard HEAD~N # удаление N коммитов из ветки A

Git flow

Фича (Feature) — новая функциональность.

Разработка новой фичи

  • Разработка новых фич начинается с ветки develop, от которой создаётся новая ветка feature/name, где name - название фичи.
  • Разработчик переключается на новую ветку и начинает работать с ней.
  • После завершения фичи создаётся Pull Request.
  • Ветка feature/name сливается с (merge into) веткой develop.
  • Ветка feature/name удаляется.
  • Разработчик переключается обратно на ветку develop.

Релиз в production

  • От ветки develop создаётся ветка release/vX.X.X.
  • Ветка release/vX.X.X при необходимости помечается тэгом vX.X.X.
  • Разрешены мелкие исправления (minor bug fixes) в ветке release/vX.X.X.
  • Ветка release/vX.X.X сливается с веткой master.
  • Ветка release/vX.X.X сливается обратно (back-merge) с веткой develop.
  • Ветка release/vX.X.X удаляется.
  • Разработчик переключается обратно на ветку develop.

Hotfix в production

  • Если в production найден серьёзный баг, который нужно быстро исправить, от ветки master создаётся ветка hotfix/name, в которой делаются необходимые исправления.
  • Ветка hotfix/name сливается с веткой master.
  • Ветка hotfix/name сливается с веткой develop.
  • Ветка hotfix/name удаляется.

SSH Github & Gitlab

  • Открыть Bash.

Генерация ключей

  • Сгенерировать ключ для Github при помощи ssh-keygen -t rsa -C "email" -f ~/.ssh/id_rsa_github, где нужно заменить email на свой. id_rsa_github - название файла, где будет лежать приватный ключ. Команда также автоматически генерирует публичный ключ id_rsa_github.pub в той же папке.

  • Ввести ключевую фразу и повторить её.

  • Сгенерировать ключ для Gitlab при помощи ssh-keygen -t rsa -C "email" -f ~/.ssh/id_rsa_gitlab, где нужно заменить email на свой.

  • Ввести ключевую фразу и повторить её.

Cоздание ключа на Github

  • Скопировать публичный ключ ~/.ssh/id_rsa_github.pub для Github. Например, вывести его на экран при помощи cat ~/.ssh/id_rsa_github.pub и скопировать через Ctrl + C.
  • Открыть на Github Settings > SSH keys и нажать на добавление нового ключа.
  • Вставить скопированный ключ, придумать название для него и сохранить.

Cоздание ключа на Gitlab

  • Скопировать публичный ключ ~/.ssh/id_rsa_gitlab для Gitlab.
  • Открыть на Gitlab Settings > SSH keys.
  • Вставить скопированный ключ, придумать название для него и сохранить.

Добавление ключа в SSH-agent

  • Добавить SSH-ключ для GitHub в SSH-agent ssh-add ~/.ssh/id_rsa_github. Если агент не запущен, то нужно сперва его запустить eval $(ssh-agent -s) или ssh-agent bash.
  • Добавить SSH-ключ для GitLab в SSH-agent ssh-add ~/.ssh/id_rsa_gitlab.
  • Проверить, что ключи добавлены через ssh-add -L.

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

Псевдоним (Alias) — аббревиатура, позволяющая избежать написания длинной последовательности команд.

  • Создадим файл .bashrc в корневой папке (в Windows: `C:/Users//) и поместим там следующее.
alias sa="eval `ssh-agent -s` ssh-add ~/.ssh/id_rsa_gitlab"

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

Конфигурация

  • Создать файл touch ~/.ssh/config.
  • Вставить туда следующее
# config for github
Host github.com
   HostName github.com
   User git
   IdentityFile ~/.ssh/id_rsa_github
# config for gitlab
Host gitlab.com
   HostName gitlab.com
   User git
   IdentityFile ~/.ssh/id_rsa_gitlab
  • Сохранить изменения.

Проверка

  • Попробовать сделать git pull через SSH.
  • Дополнительная проверка для Github: ssh -T git@github.com (режим отладки: ssh -T git@github.com).
  • Дополнительная проверка для Gitlab: ssh -T git@gitlab.com (режим отладки: ssh -T git@gitlab.com).

Git Config

Вывод конфига

git config -l

Имя пользователя и почта

/* имя пользователя */
git config --global user.name "Your Username"
/* электронная почта */
git config --global user.email "your@email"

Git Bash

Командная оболочка (Shell) — терминальное приложение (terminal app), используемое для взаимодействия с ОС посредством письменных команд.

Bash (Bourne again shell, "Born again shell", "возрождённый" shell) — усовершенствованная версия ранней командной оболочки Bourne shell, исполняющей файлы формата .sh в UNIX. Bash является командной оболочкой по умолчанию для Linux и macOS.

Git Bash — пакет, устанавливающий Bash, некоторые базовые утилиты и Git на Windows.

Убить запущенный процесс

Чтобы на определённом порте убить запущенный процесс, нужно узнать его PID (Process Identifier).

netstat -ano | findstr :PORT /* например, :3000 */
/* Скопировать PID из последнего стобца результата и вставить в команду ниже */
tskill PID