Вернуть файл к состоянию последнего коммита (аналог svn revert) можно командой git checkout файл.
Уточнение: файл будет возвращен к зафиксированному состоянию, если после коммита была явно дана команда git add файл. То есть, откатываются изменения, сделанные после git commit или git add.
Если файл был удален, то нужно указать версию; например git checkout HEAD файл.
Так можно откатить и всю папку (в т.ч. рабочий каталог): git checkout ..
Для отмены изменений на уровне рабочей копии служит команда git reset. Она "отматывает" историю изменений назад до указанного момента (в том числе отменяет коммиты), не трогая физические файлы:
git reset файл
С ключом --hard переписываются и файлы.
git reset --hard HEAD^- отменить последний коммитgit reset --hard HEAD~2- отменить два последних коммита
Отменять коммиты можно, только если они не опубликованы в общий репозиторий (не было git push).
Отменить добавление нового файла в индекс можно командой git rm --cached файл.
- история изменений, по одной строке на каждый коммит -
git log --oneline - вариант сжатого формата истории коммитов:
--pretty=format:"%h %cd %s" - то же с выделением цветом:
--pretty=format:"%C(auto)%h %C(green)%cd%C(reset) %s"(опция%C(auto)включает использование цветов по умолчанию для стандартных частей отформатированной строки, эти цвета недоступны через прямое указание) - метка:
--pretty=format:"%(describe:tags=true)" - формат даты задается отдельным аргументом:
--date=format:"%d.%m.%Y %H:%M" - всё вышеперечисленное:
git log --pretty=format:" %C(yellow)%h %Cgreen%cd%Creset %s %C(red) %(describe:tags=true)%C(reset)" --date=format:"%d.%m.%Y %H:%M"
Полный список меток можно посмотреть командой git help log в секции pretty.
- распечатать сообщение указанного коммита:
git log (коммит) --format=%B -n 1
в качестве идентификатора коммита достаточно первых пяти символов его хэш-суммы либо специального имени типаHEAD - дополнить последний коммит в одну команду с сохранением сообщения:
git commit --amend --no-edit - фильтрация по строке в тексте коммита:
git log --grep="шаблон"
(можно указывать опцию несколько раз, результат будет объединением; при--all-match=1- пересечением) - вывод истории только для локальной ветки, отпочковавшейся от
master:
git log master..(обратить внимание на две точки в конце!)
подробнее см. https://stackoverflow.com/a/4649377/
Без клонирования репозитория к себе не обойтись, но это можно сделать в сокращенном виде (см. https://stackoverflow.com/a/60952814/589600):
git clone --filter=blob:none --no-checkout --single-branch --branch master git://some.repo.git .
git loggit log --all --full-history -- путь/файл
или, если не известен путь:
git log --all --full-history -- "**/файл"
--all- предписывает команде охватить все коммиты всех веток--full-history- (выясняется)--- разделитель аргументов
Источник: stackoverflow.com.
Посмотреть последнюю версию файла можно с помощью команды
git show HEAD^:путь-к-файлу
Первую строку нужно отделять от остального текста двойным переводом строки. Тогда в короткий формат git log войдет только она. В противном случае туда попадет сообщение полностью, что снизит удобочитаемость списка.
Чтобы редактор vi открывался сразу в режиме ввода, файл ~/.gitconfig должен содержать секцию [core]:
[core]
editor = 'vim' -c 'startinsert'
Добавить сокращение: git config alias.<имя> '<команда>'. Лушче давать команду с ключом --global, чтобы иметь к нему доступ из-под своего пользователя ОС в любом месте.
Например:
git config --global alias.st 'status -s'
git config --global alias.lg 'log --pretty=format:" %C(auto)%h %Cgreen%cd%Creset %s" --date=format:"%d.%m.%Y %H:%M"'
git config --global alias.ci 'commit --no-status'Посмотреть список сокращений: git config --get-regexp alias. Без уточнения области видимости типа --system или --global будут показаны сокращения всех уровней. Область видимости нужно указывать до alias.
Удалить сокращение можно командой git config --unset alias.имя.
- откатить рабочий каталог к ревизии № rev. -
git checkout (rev.)(допустим четырехзначный формат);git checkout (rev.) -- [файл]- откатить конкретный файл - посмотреть старую версию файла (в т.ч. удалённого):
git show коммит:path/to/file - убрать файл из-под контроля git, оставив его при этом на диске:
git rm --cached файл; очень важна при этом опция--cached- без неё команда удалит файл и с диска git commit --no-status- начать с пустого сообщения для коммита в редакторе, безgit diffgit ls-files -o- просмотр списка неотслеживаемых файлов;--exclude-standard- исключить из списка игнорируемые,--directory- не разворачивать содержимое неотслеживаемых каталогов (в список тогда попадут также пустые каталоги - они никогда не отслеживаются)git status --ignored- показывать полный список игнорируемых файлов
- клонировать репозиторий в непустой каталог (
git clone ...) нельзя; инициализировать в непустом каталоге (git init) — можно - конфликты при
content mergeбез прямого пересечения бывают, если изменения в разных ветках сделаны в соседних строках; если между зонами изменений есть хотя бы одна строка, слияние проходит автоматически - безусловно принять свою версию при конфликте можно, дав команду
git checkout --ours файл, а затем -git add файл - при назначении вышестоящего репозитория (куда будет отправляться
git pull) не важно, был ли он создан раньше дочернего; если дочерний был создан как отдельно стоящий (не клонированием), то зависимость устанавливается двумя командами:git remote add origin (путь к файлу .git)- при первом
git pushнужно явно указать название репозитория (origin), ветку (master), и аргумент-u(--set-upstream):
git push -u origin master- чтобы назначить вышестоящий репозиторий, необязательно делать
push; специально для этого можно дать командуbranchс тем же аргументом:git branch -u origin master, однако для этого вышестоящий репозиторий уже должен иметь коммиты, с пустым такое не получится
- поменять upstream-ветку можно с помощью
git remote set-url (ветка) (url), например:
git remote set-url origin ssh://... - выявить причину неполадок при соединении по SSH поможет просмотр опции
git config core.sshCommandи установка её в"ssh -v"(как было, например, в в этом случае) - включить цветной вывод (если уже не включен):
git config --global color.ui true - отправить локальную ветку в вышестоящий репозиторий:
git push origin ветка - получить id самого первого коммита:
git rev-list --max-parents=0 HEAD(см. stackoverflow № 1007545); потом можно, например, просмотреть его сообщение -git log <id> - чтобы переключиться на ветку из вышестоящего репозитория, которой еще нет в локальном, нужно сначала выполнить
git fetch origin веткаи уже потом на переключиться на неё -git checkout ветка
Потому что возникают ошибки из-за разных идентификаторов пользователя ОС, которые на каждой машине уникальны, даже если имена пользователей совпадают (видимо, идентификатор присваивается самим git):
fatal: detected dubious ownership in repository at 'D:/s/portliss/1/vendor/one234ru/html-dynamic'
'D:/s/portliss/1/vendor/one234ru/html-dynamic' is owned by:
'S-1-5-21-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxx'
but the current user is:
'S-1-5-21-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxx'
To add an exception for this directory, call:
git config --global --add safe.directory D:/s/portliss/1/vendor/one234ru/html-dynamic
От этих ошибок можно избавиться, выполнив команду из сообщения.
Если используется Composer, и были подключены пакеты в виде git-репозиториев, то эти ошибки возникнут для каждого из них.
Избавиться от ошибок во всех репозиториях сразу можно с помощью варианта команды для всех каталогов: --add safe.directory "*". Но лучше вообще избегать этой ситуации.
git checkout master
git merge --squash dev
git checkout --theirs .
git commit -aПолезно, когда при разработке было сделано много промежуточных коммитов, которые по отдельности интереса не представляют, и все изменения просто нужно перенести в основную ветку в виде единственного коммита, чтобы не засорять историю изменений. При этом dev-ветка должна быть впереди master!
Для этого используется опция --squash команды git merge.
Если полученные изменения относятся к существующим файлам, они будут помечены как конфликт. Нужно скомандовать git безусловно принять вновь пришедшие изменения - git checkout . с опцией --theirs.
Частный случай: пустая ветка master (точнее, ее отсутствие). Такое бывает в начале разработки.
Когда пора делать первый коммит в основную ветку, нужно дать команду git checkout --orphan master. Она добавит все файлы из рабочего каталога текущей ветки в новую, останется только выполнить git commit.
git pull origin masterЭто намного удобней, чем давать последовательность команд
git checkout master
git pull
git checkout branch_name
git merge masterВ том числе потому, что некоторые редакторы (например, PhpStorm) незамедлительно реагируют на физическое наличие на диске открытых файлов, и если файл удаляется с диска (что может происходить при переключении на master-ветку, если файл добавлен в ветке branch_name), то вкладки с ними автоматически закрываются и их приходится потом открывать заново.
-
Получить суммарные изменения между двумя коммитами:
git diff коммит_1 коммит_2 каталог -
Получить только имена изменённых файлов позволяет опция
--name-only. Вот так, например, выглядит команда для получения такого списка относительно предпоследнего коммита:git diff --name-only HEAD~1При желании можно, например, добавить маски файлов:
git diff {...} *.tpl *.css *.js.Вывести не только имена и статусы - команда
--name-status. -
Получить изменения по дате:
git diff HEAD 'HEAD@{2020-10-01 12:00:00}' -- файл
Вместо точного времени можно указывать интервал относительно текущего момента - 'HEAD@{3 weeks ago}', а также указывать дату без временной части.
Источник - stackoverflow.com (a/9658178 и a/41303758)
-
Вывести список файлов, в которых есть конфликты слияния:
git diff --diff-filter=UU- unmerged.Файлы остаются помеченными как имеющие конфликт, даже если если метки конфликтов из них удалены (вручную или с помощью
git checkout --theirs). Пометка исчезает, только когда файл добавляется в индекс вручную. Впрочем, для выполнения коммита это необязательно. -
Исключить файлы из вывода -
'!:маска', например:git diff --name-only HEAD~1 ':!*.scss'
Посмотреть список всех локальных настроек: git config --list
Посмотреть список всех возможных настроек: git help config, секция Variables
Есть три уровня действия настроек: системный, текущего пользователя и конкретного репозитория (подробнее см. здесь).
Файлы .gitconfig имеют структуру:
[раздел]
переменная = значениекоторая соответствует команде
git config раздел.переменная = значение
Выполнение команды git config и редактирование файла .gitconfig вручную имеют одинаковый эффект.
Для более удобной работы в оболочке bash (в т.ч. под Windows) существуют специальные shell-скрипты. Они размещены в публичном репозитории git (см. каталог contrib/completion).
Чтобы использовать заложенные в них возможности, нужно скачать их из репозитория куда-нибудь на рабочий компьютер (например, в свой же домашный каталог) и подключить в файле .bashrc.
Например, автодополнение команд по нажатию Tab (позволяет не печатать команды полностью; действует как на подкоманды, так и на их опции):
curl --output-dir ~ -O https://raw.githubusercontent.com/git/git/master/contrib/completion/git-completion.bash
# -O - использовать имя файла из ссылки
. ~/git-completion.bashДля включения в системное приглашение информации о репозитории git нужно подключать файл git-prompt.sh и вызывать функцию __git_ps1:
export PROMPT_COMMAND='PS1="$(__git_ps1)"'
# даст приглашение типа
# (название ветки)То, что возвращает __git_ps1, определяется значениями переменных типа GIT_PS1_* (например, GIT_PS1_SHOWDIRTYSTATE - показывать ли звёздочку в случае, если есть неотслеживаемые файлы), полный список и описание которых можно найти в самом sh-файле.
export PROMPT_COMMAND='PS1="$(__git_ps1)"'
GIT_PS1_SHOWDIRTYSTATE=1
Также перечислены в статье.
Если git-часть приглашения требуется окружить пробелами или другими символами, нужно передать функции аргумент с меткой %s:
git_command='__git_ps1 "%s "'
# даст приглашение типа
# (название ветки) >Проверить работу функции можно непосредственно из командной строки, находясь в каталоге репозитория:
echo __git_ps1
Хуки - это скрипты, которые могут выполняться при наступлении различных событий: при создании коммита, при получении коммита (на сервере) и пр. Подробнее - тут (en).
Пример - хуки для Composer.
При обычном клонировании связанные репозитории запрошены не будут. Запросить их можно, указав команде ключ --recurse-submodules:
git clone --recurse-submodules (repository) (local folder)
Рекомендуется всегда выполнять команду с этим ключом, т.к. подмодули, как правило, содержат файлы, необходимые для работы всей системы. (Вообще странно, почему эта опция не включена по умолчанию.)
Если требуется внести в подчиненный репозиторий изменения, рекомендуется проверить, что указатель HEAD установлен на ветку master (бывает, что репозиторий имеет отсоединенный HEAD), просто посмотрев на результат команды git branch.
Подмодули также нужно инициализировать в upstream-репозитории, если туда была отправлена локальная ветка (git push origin ветка):
Работа над подмодулем должна быть локализована в каком-то подкаталоге. Перед тем, как инициализировать подмодуль в проекте, его нужно опубликовать на github или каком-то другом хранилище, после чего выполнить команду
git submodule add https://...Докальный каталог, где велась разработка подмодуля до его публикации, нужно переименовать или вообще удалить, чтобы он не мешал исполнению команды, которая попытается создать каталог с тем же именем.
После того, как подмодуль таким образом зарегистрирован, нужно сделать коммит в основной проект и отправить его в вышестоящий репозиторий. После этого там появится каталог подмодуля, но он будет пуст (весьма странно, что git так работает, потому что при такой схеме можно отправить в вышестоящий репозиторий проект в нерабочем состоянии). Подмодуль нужно вручную инициализировать. Для этого в каталоге проекта в вышестоящем репозитории нужно дать команду
git submodule init (путь к каталогу подмодуля)
git submodule update (путь к каталогу подмодуля)
Команда вида git submodule init (локальный каталог) не сработает, т.к. она ожидает пути к централизованному хранилищу, откуда потом можно будет забирать изменения.
Можно, однако, сначала перейти в каталог подмодуля, а потом последовательно выполнить команды git submodule init и git submodule update без указания каталога, как это сделано в примере из документации.
git submodule update --recursive --init подмодуль
При внесении изменений в подмодуль в вышестоящем репозитории git pull из него не обновляет подмодуль, вместо этого его каталог помечается как измененный. Чтобы изменения вступили в силу, нужно выполнить команду git submodule update подмодуль.
В конце работы рекомендуется просмотреть содержимое файла .gitmodules и исправить имена модулей с автоматически сгенерированных из путей на более удобные и понятные.
Обновление модулей не происходит автоматически при отправке изменений в вышестоящий репозиторий, это нужно делать отдельной командой, вручную или через хуки.
Если вышестоящий репозиторий при этом является production-копией, как это имеет место в схеме push-to-deploy, обновление модулей должно следовать сразу же за командой push, т.к. сразу после push система может оказаться в нерабочем состоянии: код проекта обновился, а подчиненные модули - нет.
Если планируется не только чтение, но и внесение изменений, нужно соединяться не по https, а по ssh, причем *обязательно от имени пользователя git: [email protected].
Чтобы это сработало, нужно добавить свой публичный SSH-ключ через настройки учетной записи. Подробная инструкция здесь.
Проверить работу ключа можно, выполнив команду ssh -vT [email protected] (см. docs.github.com).
Поменять URL репозитория можно так:
git remote set-url origin [email protected]:<user>/<repository>.gitПри первой отправке изменений в пустой, только что созданный, репозиторий нужно явно установить (обычно - продублировать) название будущей ветки. Делается это с помощью ключа -u/--set-upstream:
git push --set-upstream origin master
или, в общем случае
git push --set-upstream origin ветка
Такая процедура связана с тем, что в пустом репозитории на сервере github веток ещё нет. Подробнее см. https://stackoverflow.com/q/17096311/
Делать это можно только при наличии коммитов в локальной ветке. При пустой ветке команда не сработает.
Также нельзя обойтись одной только командой git push без создания репозитория через веб-интерфейс Github.
Если прямое соединение с помощью ssh проходит успешно, а команды git не проходят, нужно посмотреть вывод git config core.sshCommand - не указано ли там имя пользователя явно (как было в этом случае).
Технически любой gist - это просто репозиторий на Github, процедура работы с которым упрощена:
- названием является хэш типа
f3cef177af2a86fbf0a8deb46c515b3b - при внесении правок через веб-интерфейс не требуется заполнять сообщения commit (что видно в
git log)
Метки (tags)
Часто применяются для указания номеров версий, которые потом используются в т.ч. Composer'ом.
git tag -l - просмотреть список меток
Создать метку без подписи:
git tag название
# например, git tag v1.0Создать метку с подписью (аннотированную):
git tag -a v1.0 -m "Подпись"Метка будет приписана к последнему коммиту.
Можно назначать метку задним числом для прошлых коммитов. Для этого контрольную сумму коммита или ее часть нужно указать в конце команды:
git tag -a v1.0 abcde01
Метки сами не отправляются в вышестоящий репозиторий. Нужно либо отправлять каждую поименнно:
git push origin имя_меткилибо отправить их все сразу:
git push origin --tags
Ключевой момент: открываем composer.json и вручную добавляем туда запись в раздел repositories:
"repositories": [
{
"type": "git",
"url": "ssh://user@host:port/path"
}
]Также обязательно нужен раздел autoload типа
{
"autoload": {
"psr-4": {"Namespace\\": "./"}
}
}После этого нужно дать команду composer require. При этом надо иметь в виду, что если проекту не назначаются версии в виде меток git (tags), команде нужно явно указать ветку в виде названия с префиксом dev-. Например, для ветки master команда будет выглядить так:
composer require vendor/package:dev-master
В противном случае обычная команда выдаст ошибку:
Could not find a version of package vendor/package matching your minimum-stability (stable). Require it with an explicit version constraint allowing its desired stability.