HEAD - указатель на вершину(последний коммит) текущей ветки, снимок последнего созданного коммита/изменений. При переключении веток, указывает на последний коммит в ветке.
рабочая область - каталог в котором находится копия репозитория, это все хранится в файловой системе.
область индекса/индекс - изменения в файлах, которые будут зафиксированны при создании коммита, это все хранится в гите.
fast-forward - при мердже означает просто перенос HEAD
После добавления файла в индекс и изменения его, только добавленные изменения будут зафиксированы в коммите, то что было изменено позже - зафиксировано не будет.
Команды
Работа с ветками
git branch --no-merged
- посмотреть локальные ветки, которые не были объединены с текущей выбранной веткой
git branch --merged
- локальные ветки, которые уже были "слиты" в текущую активную ветку(их можно смело убивать, только надо убедиться относительно какой именно ветки вызывается эта команда!)
git branch -d branchname
- удаляем локально ветку branchname
git branch -D branchname
- если ветка branchname
еще не была никуда слита, и мы понимаем что она нам не нужна - ее удалить можно только принудительно (-D
)
git checkout -b branchname
- создать новую ветку с именем branchname
от текущей
git checkout -b localbranch origin/remotebranch
- позволяет создать локальную ветку localbranch
(с которой можно работать) из указателя на удаленную ветку origin/remotebranch
. Новая локальная ветка будет отслеживать изменения удаленной ветки.
git branch --track remotename/branchname
- выполнит ту же операцию. Будет создана локальная ветка с именем branchname
, которая будет отслеживать remotename/branchname
git branch -vv
- выведет список локальных веток с указанием настроенных для них удаленных веток, а так же дополнительной информацией насколько локальная ветка опережает/отстает от удаленной. Информация выводится исходя из того, какие данных об удаленных ветках есть на компьютере! Команда не выполняет подключение к серверу. Чтобы посмотреть актуальную информацию, сперва нужно извлечь данные с удаленных серверов командами git fetch origin
или git fetch --all
и потом уже смотреть вывод этой команды
Сохранение изменений
git commit -v
- показывает дифф того что будет зафиксированно в коммите
Удаленный репозиторий
git fetch remotename
- скачать изменения с удаленного репозитория remotename
и положить их в стороне(вроде кэша), локальные ветки, которые уже отслеживают подтянутые изменения не будут затронуты(изменения в них не применятся)
git fetch --all
- скачать изменения со всех удаленных репозиториев
git push remotename --delete branchname
- удаляем ветку branchname
с удаленного репозитория remotename
git push
- без аргументов отправит текущую активную ветку на удаленный репозиторий
git remote add remotename url
- добавить для текущего репозитория еще один удаленный репозиторий с именем remotename
, который расположен на сервере по url
git pull remotename branchname
- скачать с удаленного сервера remotename
ветку branchname
и слить ее с текущей веткой
git push remotename localbranchname:remotebranchname
- если локально создали ветку с каким-то одним названием(localbranchname
), а потом поняли что название ветки не очень, а как создавать новую ветку - не знаешь - можно отправить эту ветку на удаленный сервер remotename
с другим именем(remotebranchname
)
git fetch origin
- загрузит с сервера origin
ветки, но не создаст для них локальные копии для работы, зато теперь известен весь список веток хранящихся на сервере(в виде указателей на удаленные ветки origin/branchname
)
git merge origin/branchname
- позволяет слить загруженную удаленную ветку origin/branchname
в текущую ветку
git push origin -u localbranch:remotebranch
- если необходимо изменения из локальной ветки localbranch
опубликовать в уже существующей ветке на сервере remotebranch
. Такое может быть необходимо, когда один два разработчика начали реализацию одного функционала, но по какой-то причине в ветках с разными именами. Перед выполнением команды необходимо подтянуть изменения с удаленного сервера git fetch origin
, чтобы получить изменения в remotebranch
, и слить их в свою ветку git merge origin/remotebranch
Интерактивный режим работы
git add -i
- включает интерактивный режим добавления файлов в индекс.
Числами/буквами осуществляется выбор команд, для добавления/удаления из индекса, откатывания изменений. Все изменения выводятся небольшими блоками и для каждого блока принимается решение - добавлять в индекс или нет.
Удобно если было несколько правок в файле и надо разбить их на несколько коммитов.
Операцию частичной обработки блоков изменений можно делать и в упрощенном режиме:
git add -p
или git add --patch
- добавление изменений в индекс частями
git stash save -patch
- прячем изменения частями
git reset --patch
- убираем части изменений из индекса
git checkout --patch
- отменяем локальные изменения частями
Навигация в дереве коммитов
git reflog
- Показывает журнал ссылок, в котором хранятся указатели на HEAD. В этом журнале git сохраняет данные о каждом изменении вершины
ветки. Чтобы посмотреть куда ссылался указатель 5 коммитов назад можно воспользоваться командой - git show @{5}
, чтобы посмотреть состояние какой-либо ветки достаточно указать её название - git show master@{5}
.
В скобки можно передать дату git show master@{2018–09–01}
или относительную дату git show @{yesterday}
/git show @{2.months.ago}
Знак ^
в конце ссылки означает “обозначает предка коммита”. Для истории вида:
e325a7a5fb commit a
2464581e3d commit b
e97d228792 commit c
команда git show 2464581e3d^
покажет изменения внесенные коммитом commit c
.
После символа можно указать число - git show 2464581e3d^2
, чтобы посмотреть второго предка коммита. Но такой синтаксис применяется только для коммитов слияния. Первый родитель указывает на коммит в ветке которая была активна в момент слияния, второй предок — из ветки которая сливалась в текущую.
Знак ~
в конце ссылки так же указывает на предка - прямого предка в истории коммитов.
Чтобы не запутаться в том какую навигацию когда использовать можно запомнить простое правило:
^
- как объединение двух путей(две ветки объединились в одну), используем в коммитах слияния, ~
- прямая(хоть и чуть извилистая) дорога к следующему предку коммита.
HEAD~3
так же можно записать как HEAD^^^
. Если же мы хотим перейти в ветку которая сливалась в текущую и там найти предка то надо указать, что нам нужен второй предок для конкретного коммита - HEAD^^2^
. Эти способы навигации можно комбинировать между собой.
Диапазон коммитов обозначается двумя точками - ..
. Эта запись позволяет посмотреть какие коммиты достижимы из одного и не достижимы из другого (дифф в коммитах между двумя ветками например или какие были изменения за 3 последних коммита HEAD~3..HEAD)
Если ветка branchA
выглядит так: A -> B -> C -> D
, а ветка branchB
так: A -> B -> E -> F
(branchB
сделан из branchA
после коммита B
), то чтобы узнать какие изменения одной ветки не слиты в другую воспользуемся командой: git log branchA..branchB
, в выводе мы увидим что коммиты E
и F
не слиты в ветку branchA. Если же поменять местами названия веток, то результат будет C
и D
, очевидно.
Прятанье изменений
git умеет прятать текущие изменения в буфер, например работали над определенным блоком кода и была найдена ошибка, которая требует немедленного исправления. Тут на помощь приходит команда stash
.
git stash
- спрятать текущие(отслеживаемые гитом) изменения в рабочей области в буфер. При таком сохранении git автоматически добавляет в качестве комментария к этим изменениям - сообщение последнего коммита в этой ветке. Это не совсем удобно и понятно.
git stash save "comment for stash"
- позволяет сохранить изменения и добавить к ним понятный комментарий "comment for stash", чтобы позже было проще понять что за изменения сохранены в буфере.
git stash list
- показать список того что было спрятано в буфер.
Этот буфер работает по принципу стэка - FILO.
git stash apply
- применяет к рабочей области изменения с вершины буфера(то что было спрятано последним) и не удаляет изменения из буфера. Если нужно применить более старые изменения - можно указать ссылку на них - git stash apply stash@{3}
.
git stash pop
- применяет к рабочей области изменения из буфера и удаляет их(в буфере), так же можно указать ссылку на конкретную запись в буфере - git stash pop stash@{3}
.
git stash apply --index
- сразу вернет состояние спрятанным файлам: индесирован/неиндексирован
git stash drop stash@{0}
- удалить из буфера последние спрятанные изменения, без применения их к рабочей области.
git stash --keep-index
- прячет только файлы, которые не проиндексированы командой git add
git stash --include-untracked
- спрячет измененные файлы, проиндексированные и неотслеживаемые, тоже самое можно сделать с git stash -u
Интересное: если из буфера вытащили изменения, потом сверху еще добавили руками изменений, и захотели отменить то что вернули из буфера то это можно сделать!!! Команды git stash unapply
нет, но можно применить изменения РЕВЕРСИВНО о_О:
git stash show -p | git apply -R
Можно указать индекс изменений git stash show stash@{1} -p | git apply
git stash show
- список файлов и немного статистики по изменениям.
git stash show -p
- вывод изменений в файлах которые лежат в буфере.
в эти команды так же можно передать ссылку на элемент буфера: git stash show stash@{1} -p
Если изменения лежали в буфере очень долго, и их применение приводит к конфликтам — можно вытащить их в отдельную ветку, там актуализировать и слить в нужную ветку. Вытащить скрытые данные из буфера в ветку можно командой: git stash branch branchname stash@{2}
, при этом stash@{2}
будет удален
Чистка рабочей области
Почистить рабочую область можно командой git clean
. Пользоваться этим нужно осторожно - она удаляет все неотслеживаемые файлы без возможности восстановления.
Если есть подозрение, что файлы могут понадобится - можно воспользоваться командой git stash --all
, которая удалит мусорные файлы, но при этом спрячет их в буфер.
Если решение об удалении хлама принято окончательно - лучше использовать git clean -f -d
. Флаги включают удаление неотслеживаемых файлов и директорий (-f - force
). К этой команде можно добавить параметр -n
, чтобы посмотреть имитацию очистки рабочей директории.
Важно помнить, что git clean
не удаляет игнорируемые файлы, которые скрываются через .gitignore. Чтобы удалить и их нужно добавить параметр -x
. У команды clean
так же есть интерактивный режим удаления, включается он флагом -i
Поиск
Команда git grep funcname
позволяет искать строку funcname
в текущем рабочем каталоге. Так же можно указать регулярное выражение.
С флага -n
можно указать как много строк показывать для найденных вхождений, например git grep -n3 funcname
вернет по 3 строки вверх и вниз от включения строки funcname
.
Параметр --count
покажет количество включений строки поиска в каждый файл, а флаг -p
добавит в вывод имя метода в котором найдена эта строка(для js возвращает имя класса):
app/components/foo.js=export default class A {
app/components/foo.js: item.disabled=false
app/components/foo.js: item.disabled=true
Флаг --and
- позволяет искать сложные комбинации в одной строке, флаг --break
- добавляет пустые строки между разными файлами в выводе поиска,
флаг --heading
- выводит сперва название файла, а затем все включения в нем.
Для поиска в истории можно использовать git log
с параметром -S
:
git log -Sprocess --oneline
- эта команда выведет все коммиты в которых была добавлена/удалена строка process
, флаг --oneline
чтобы вывести сокращенную информацию о коммитах:
67c9287e95 add check check for key existance
028468202a fix condition
Найдя хэш коммита, можно воспользоваться командой git diff 85c32a7e95
чтобы посмотреть изменения.
Для более сложного поиска можно использовать параметр -G
, в который передаются регулярные выражения для поиска в истории. Параметр -L
в команде git log
позволяет вывести историю конкретной строки или функции в определенном файле:
git log -L :showModal:my-app/components/table/info.js
правда у меня этот метод ничего не нашел, ни для js, ни для php кода, возможно потому что git не смог понять как в js искать функции
Cигнатура такого поиска выглядит так:
git log -L :funcName:pathToFile
или так:
git log start,end:pathToFile
- в этом варианте start
это номер строки начиная с которой смотреть историю, end
- номер строки до которой смотреть историю.