Git
# Git (менеджер контроля версий кода)
> Помнит всю историю изменений, в т.ч. при командной разработке\
> Локальный репозиторий (на моей машине) / удаленный репозиторий (на сервере)\
> GitHub/Bitbucket/GitLab - облачное хранилище удаленных репозиториев (самые популярные)
## Термины
| Create | Browse | Revert | Update | Branch | Save | Publish |
|---------|--------|----------|--------|----------|--------|---------|
| init | status | reset | pull | checkout | add | push |
| clone | log | checkout | fetch | branch | commit | |
| ------- | show | revert | merge | ------- | | |
| config | diff | | am | workflow | | |
| remote | branch | | | | | |
### Create (инициализация)
```bash
$ git --version
$ git init # создать пустой репозиторий (.git - папка где будет хранится история изменений)
$ git clone https://url.ru # скачать проект к себе (набор дирректорий с файлами) с сервера GitHub
.gitignore # файл с описанием списка файлов на исключение
.gitkeep # пустой файл необходим в случае если необходимо добавить в git пустую директорию
# Есть суперглобальная конфигурацию, глобальная конфигурация, локальная конфигурация
# .git/gitconfig (все изменения только для локальной машины)
$ git config --list # список настроек
$ git config --global user.name "Ivan Litovchenko" # установка автора коммитов
$ git config --global user.email "iv-litovchenko@mail.ru" # установка почты автора коммитов
$ git config --global push.default matching # Настройка для push
$ git config --global push.default simple # Настройка для push
$ git config --global core.fileMode false
$ git config core.fileMode false # Не учитывать права на файлы
$ git remote # список удаленных репозиториев
$ git remote -v # список удаленных репозиториев (подробно)
$ git remote add https://github.com/litovchenko1/site.git # добавить удаленный сервер (облачное хранилище), origin - имя репозитория
$ git remote set-url origin https://iv-litovchenko:@github.com/iv-litovchenko/maptex.git
```
### Browse (обзор изменений)
```bash
# Проверка состояния изменений (зеленые строчки - что-до добавили, красные строчки - что-то удалили)
$ git status
$ git status -u # включая содержимое папок
$ git shortlog
$ git log # если пришли в новую контору и решили посмотреть что там (история изменений)
$ git log --oneline # выведем только заголовок с помощью
$ git log --since=2.weeks # показать коммиты за последние две недели
$ git log -n 3
$ git log -n 10 # количество коммитов
$ git show # посмотреть в наглядном виде
$ git diff
```
### Revert (откат имзеенний)
```bash
# Указатель HEAD - это указатель на текущий коммит
# ID-коммита - это сокращенное название контрольной суммы SHA-1
$ git reset # позволяет перемещаться по указателям
$ git reset HEAD~ # отмена последнего коммита (файлы из данного последнего коммита переходят в статус unstaged, то есть в то состояние, в котором они были до коммита)
$ git reset --hard HEAD~1 # полное удаление последнего коммита
# Например: у вас есть следующие коммиты A←B←C←HEAD. Коммит C самый последний и на него указывает HEAD (указатель на текущее состояние).
# После выполнения команды git reset --hard HEAD~1 вы получите состояние A←B←HEAD (коммит C будет удален). HEAD теперь указывает на коммит B.
# Отмена до состояния репозитория (если мы по экспериментировали и хотим откатится до того состояния как в репозитории)
$ git checkout -- ИМЯ-ФАЙЛА # откатывает до того состояния как в репозитории
$ git checkout . # отменить все изменения
# Отменить изменения сделанные в последнем коммите можно с помощью команды git revert.
# Она делает еще один коммит, но с противоположными изменениями.
# Нужно передать ей хеш коммита, который мы отменяем
$ git revert aa600a43cb164408e4ad87d216bc679d097f1a6c
# Как удалить коммит в gitLab?
$ git reset --hard <последний перед удаляемыми коммит>
$ git push -f
```
### Update (получение изменений)
```bash
$ git fetch # скачивает обновления из удаленного репозитория (remote), но не сливает их с текущей веткой (нужно будет сделать еще git merge)
$ git pull # скачать (забрать) изменения с удаленного репозитория (это команда-псевдоним сразу двух git команд - git fetch и git merge.)
$ git pull origin main # стянуть изменения в мою ветку (например task-18)
$ git push origin master:backup-17-11-2022 # рез. копия проекта: ветки — локальная:удалёная (замена zip-пованию)
```
### Commit (сохранение изменений)
```bash
# Публикация изменений - все файлы могут быть в трех состояниях:
# A) Модифицированные (измененные, но не проиндексированные)
# B) Индексированные (подготовленные для фиксации)
# C) Зафиксированные (сохранены в .git-каталоге)
# Изменения автору проекта (какого-либо расширения) можно отправить в виде реквеста
# Добавление в индекс (индексирование файлов и нахождение изменений в них)
$ git add . # добавить все изменени
$ git add
$ git add
# Удаление из индекса
$ git rm --cached <ИМЯ-ФАЙЛА> # если файл был добавлен по ошибке - удаляем из индекса
$ git rm -r --cached <ИМЯ-ПАПКИ> # если папка была добавлена по ошибке - удаляем из индекса
# Фиксация изменений (сохранение изменений (не любое изменение на проекте, а зафиксированное изменение в репозитории))
$ git commit -am "Коммент - Первый коммит" # зафиксировать изменения + их коммит
$ git commit -m "Коммент - добавляем файл" # только коммит (если без -m - название будет вводится в ручную)
$ git commit # Откроется окно с редактором
$ git push origin master:backup-17-11-2022 # рез. копия проекта: ветки — локальная:удалёная (замена zip-пованию)
```
### Publish (публикация изменений)
```bash
# Для отправки изменений в удаленный репозиторий (например на GitHub) Нужно:
# 1) Создать аккаунт на github
# 2) Создать репозиторий на github
$ git push # отправить/протолкнуть изменения в удаленный репозиторий на сервер
$ git push -u origin master # название сервера удаленного репозитория, - название ветки
$ git push origin ao-1
$ git push origin --all # отправить все сразу
$ git push origin --tags # отправить все теги сразу
$ git tag 1.2.0 # теги добавляются только в ветку
```
### Branch (работа с ветками - по умолчанию ветка master/main)
```bash
# Ветка - это исходный код в независимом паралельном варианте
# Ветки нужны что бы разделить код (например одна ветка для разработки нового функционала, другая ветка для продакшина).
# После ветки сливаются в основную ветку (зависит от workflow).
$ git branch # список веток ("*" звездочкой помечена текущая ветка на которой находимся)
$ git branch -v # список веток с их различием
$ git branch <...BRANCH_NAME...> # создать ветку
$ git branch -D <...BRANCH_NAME...> # удалить ветку
$ git checkout <...NAME...> # переключится на ветку
$ git checkout -b new_f # создать ветку и переключится на нее
# Когда закончили работу с веткой переключаемся на основную, и вливаем в нее нашу ветку
$ git checkout master
$ git merge <...BRANCH_NAME...> # возьмет две ветки, которые мы объединяем, найдет общий базовый коммит, а затем воспроизведет последовательность коммитов из двух веток в базовом коммите, чтобы объединить ветки
$ git rebase <...BRANCH_NAME...> # берет всю вашу функциональную ветку и перемещает ее в конец основной ветки .
# Пример - в ветке таск-92
# да, запушить и влить в мастер либо локально (и снова запушить) либо через мерж или пулл реквест
# 1) сначала коммит
# 2) потом пулл (забрать)
# 3) потом пуш (отправить)
# Мерж конфликтов (объединение изменений одного файла из разных источников)
# 2 разных разработчика поменяли код в 1 и том же файле
# Слева текущая ветка | По центру результат объединения | Справа вливаемая ветка
# Области: зеленые области - нет конфликтов; красные области - зоны конфликтов
# При разгуливании конфликтов можно использовать добавку в стеш (после git pull, после выбор из стеша)
# Модель ветвления (gitflow - подход к работе на основе таск-трекера)
# Ветки создаются на github. На локальной машине они не создаются.
# Под каждую новую задачу создается новая ветка от ветки
# это оригинальная ветка
# - На ветке - задачи тестируются
# - Название новых веток задается как <код_проекта>_<название_изменения>_<№задачи> на основе таск-трекера
# - Ветки создаются от ветки
# - После делается пулл-реквестти в ветку (примите мои изменения)
# - После решения задачи ветка удаляется
# - Каждому релизу присваивается тэг версии X.X.X
# Как организовать работу (тракинг) - TAB Issuse
# 1) Создаем задачу на GitHub [projname - сокращенное название проекта].[1 - номер задачи]
# 2) На основе номера задачи (ID) создаем ветку projname.1_название
# 3) Делаем локальные изменения
# 4) На GitHub делаем Pull Request -> в (merge -> pull request)
# 5) Далее на GitHub Pull Request в
```
## Описание GitHub-сервиса
### Интерфейс
- TAB Issuse - создать баг/задачу (трекинг)
- TAB Fork - создание форка
- TAB Watch - отслеживание репозитория
- Настройка Web-Hook - можно организовать авто-деплой
- https://github.com/settings/tokens (Personal access tokens (classic))
### SSH-ключи для GitHub
1) $ ssh-keygen - команда создает ключ (спрашивает где сохранить, просит придумать пароль)
2) далее берем копируем публичный ключ ($ cat /home/i/ilitovfa/.ssh/id_rsa.pub)
3) далее идем на github и добавляем публичный ключ в разделе SSH-keys
## Правила оформления коммитов
Есть два подхода к сохранению изменений в историю:
- атомарные коммиты — логически отделимые операции разделяются на отдельные коммиты;
- массовый коммит со всеми изменениями по задаче.
Правильно составлять описания коммитов:
- Правило 1: оставляйте пустую строку между заголовком и описанием
- Правило 2: ограничивайте длину заголовка 50 символами (гарантирует читабельность заголовка, позволяет кратко описть изменения)
- Правило 3: пишите заголовок с прописной (заглавной) буквы
- Правило 4: не ставьте точку в конце заголовка описания
- Правило 5: используйте повелительное наклонение в заголовке. Вот примеры (Сделай уборку, Закрой дверь, Вынеси мусор)
- Правило 6: ограничивайте длину строки в теле описания 72 символами
- Правило 7: в теле описания отвечайте на вопросы «что?» и «почему?», а не «как?» Сфокусируйтесь на объяснении причин изменений — на том, как всё работало до изменений и что здесь было не так, и на том, как оно работает сейчас
Коммит должен быть — лаконичным и однородным (не длинным).
Рекомендуется начинать описание коммита со строки длиной до 50 символов, которая обобщает изменения.
За ней должна следовать пустая строка, а затем более подробное описание коммита.
====================
## Как восстановить коммиты из безымянной ветки?
Добрый вечер!
Использую SourceTree.
Я делал коммит в develop. Затем я совершил какие-то действия второпях (Это моя большая ошибка),
которые привели к созданию ветки безымянной, но на которой был HEAD. Несколько дней я записывал в эту безымянную ветку изменения(коммитил).
И вот я решил перейти на ветку develop.
И, черт побери, безымянная ветка пропала, я оказался на ветке develop, мои изменения потерялись.
Дедлайн уже в понедельник, а тут такое!!!
Подскажите, пожалуйста, как мне вернуть свои изменения из безымянной ветки?
Вопрос задан более трёх лет назад
4116 просмотров
Через git reflog ищете хеши потерянных коммитов.
reflog выводит все хеши, где был HEAD.
И потом:
git branch new-branch-name hash
Ну а потом переходите в develop (хотя Вы и так вроде там) и мержите потерянные изменения:
$ git checkout develop
$ git merge new-branch-name
Естественно, это всё через консоль надо делать.
Главное, делать это в том хранилище, где были коммиты, и до git gc, иначе информация о недостижимых коммитах будет удалена.
## Как отменить последний коммит git
Тут нужно понять, что именно необходимо сделать. Потому что под отменой часто понимают удаление последнего коммита. Удалить последний коммит можно очень просто с помощью команды git reset. Причём можно как сохранить изменения в рабочей директории, так и полностью удалить все изменения сделанные в последнем коммите.
git reset HEAD~ # удаляем только коммит
git reset --hard HEAD~ # удаляем коммит и изменения
А вот отменить изменения сделанные в последнем коммите можно с помощью команды git revert. Она делает еще один коммит, но с противоположными изменениями.
git revert aa600a43cb164408e4ad87d216bc679d097f1a6c
# нужно передать ей хеш коммита, который мы отменяем
Обратите внимание, что команда git reset может быть опасна, поскольку она изменяет историю репозитория. Поэтому важно следить за тем, что вы делаете, и убедиться, что вы работаете над локальным репозиторием, а не с удаленным репозиторием, так как при изменении истории удаленного репозитория у других участников могут возникнуть проблемы с синхронизацией своих локальных репозиториев.
## Стэш
Ребят можно пожалйста простыми словами объяснить что такое стэш?
И для чего он нужен.
Это средство временно убрать из рабочей копии изменения , которые пока не нужны или мешают обновлению.
По сути делается следующее: git делает новую особую ветку, переключается на неё, делает комит всего, что надо stashить, (обычно всё что поменялось)
и затем переключается на исходную ветку и апдейтит рабочую копию на неё.
Как эффект - у тебя стираются все изменения, но они не пропадают, а сохраняются в отдельной веточке специального вида.
Потом эти изменения можно обратно затащить в любую ветку.
Это как стэк множества индексов (—staged) версий
Ну, типа недо-коммиты: запушить нельзя, переключиться нельзя. Можно только "развернуть", удалить и т. д. (как reset с индексом работает)
х--
https://jeka.by/ask/231/git-stash-information/
https://jeka.by/ask/240/clean-git-stash/
https://jeka.by/ask/112/git-merge-as-single-commit/
https://jeka.by/ask/198/git-transfer-commit-from-another-branch-cherry-pick/
Это надо в такой вот ситуации:
Ты много мест в коде изменил, но еще не готов сделать комит.
Тебе срочно надо переключиться на другую ветку, к примеру коллега
просит помощи по баге и ее проверке. Как быть? Куда деть не закомиченную работу?
Вот лучше всего взять и спрятать, как проиндексированное, так и то что еще не добавлено в индекс.
В этом и есть суть git stash
## Гит 100МБ проблема если есть большие файлы
Нужно найти все коммиты, которые изменяли файл:
$ git log --pretty=oneline --branches -- BIGFILE.ZIP
$ git filter-branch --tag-name-filter cat --index-filter 'git rm -rf --cached --ignore-unmatch File.zip' --prune-empty -f -- --all
$ git filter-branch --tag-name-filter cat --index-filter 'git rm -rf --cached --ignore-unmatch Folder/' --prune-empty -f -- --all
$ rm -rf .git/refs/original/
$ git reflog expire --expire=now --all
$ git gc --aggressive --prune=now
https://ru.stackoverflow.com/questions/669670/удалить-из-git-файл-большого-размера-попавший-туда-несколько-коммитов-назад
https://onedev.net/post/191
https://gist.github.com/bendasvadim/fc398385810473f9724bad9d42281fb3
P.S. Спасибо, сильно помогло, размер .git уменьшился в 100 раз.
/interactive/content_wiki/soft.Git-id-372.md
Здесь можно оставить комментарий!