### Практика

[Полезности при работе с git](https://gist.github.com/1234ru/d15722f9a76ab7f901afa0003bd0dfef/)

### Полезные дополнения

>`git --no-pager (любая команда)` - позволяет вывод показывать в терминале, не в виме. 
>Например: `git --no-pager config --list | grep alias`


>`git show branch:file | vim -` - показывает вывод в vim, не в vi (как по дефолту).

> `git co -` рекурсивно вернет тебя обратно к предыдущей ветке

  <details><summary>Open</summary>
  <p>
    
  По аналогии с `cd -` в терминале:

  `git: (develop) git checkout -` - возвращает на предыдущую переключенную ветку.

  `git: (bugfix/popov/) git checkout -` - повторный ввод команды вовзравит в ветку `develop`.

  Оператор `-` представляет собой сокращение для синтаксиса `@{-1}`, который позволяет переключиться на любое количество чекаутов назад. Так что если вы, к примеру, создали ветвь `feature/thing-a`, потом `feature/thing-b`, а потом `bugfix/thing-c`, то параметр `@{-2}` вернет вас к `feature/thing-a`
    
  </p>
  </details>

> `git cherry -v develop | wc -l` - подсчет коммитов до develop

---

#### Устранение бага - бинарный поиск по коммитам

1. [git bisect](https://habr.com/ru/articles/591447/)

<details><summary>Open</summary>
<p>

За логарифмическое время мы сможем отдебажить код при помощи бинарного поиска, который уже встроен в git: `git bisect`

</p>
</details>

---
  
#### Создание, удаление, переименовывание веток: 

<details><summary>Open</summary>
<p>
  
1) Создание ветки:
	
* git checkout -b bugfix
	
то же самое, что и:  git branch bugfix + git checkout bugfix
	
* git push --set-upstream [1] bugfix

2) Удаление ветки:
	
* git checkout develop 				# переключаемся на любую ветку

* git branch -d/-D your_branch 			# удаляем локальную; -D force удаление
  
* git push [1] --delete your_branch 		# удаляем удаленную
`[origin] - то, что мы прописывали в git push [1] HEAD:[your branch]`

 Если появляется ошибка `A branch named 'bugfix/...' already exists`, то заново прописать с флагом -D `git branch -D your_branch`
	
3) Переименовывание ветки:

* git branch -m old_branch new_branch        	# Rename branch locally

* git push origin :old_branch                	# Delete the old branch

* git push --set-upstream origin new_branch  	# Push the new branch, set local branch to track the new remote
	
</p>
</details>

---
  
#### Извлечение файла из другой ветки

<details><summary>Open</summary>
<p>
  
  Пример команды: `git show some-branch:some-file.js | vim -`
  
  Иногда бывает удобно посмотреть на какой-либо файл в другой ветке, не переключаясь на неё. 
  Это можно сделать с помощью команды `git show some-branch-name:some-file-name.js`, которая выведет содержимое файла в указанной ветке прямо в терминал.
  
  А с помощью перенаправления вывода можно сохранить этот файл в указанное место на диске, например, если вы заходите открыть два файла одновременно в своём редакторе: `git show some-branch-name:some-file-name.js > deleteme.js`

  Примечание: если вам нужно всего лишь сравнить два файла, то можно выполнить такую команду: `git diff some-branch some-filename.js`
  
</p>
</details>

---
  
#### Удалить локальные изменения/откат коммитов:

<details><summary>Open</summary>
<p>

  * `git reset --hard {{some-commit-hash}}` — вернуться на определённый коммит в истории. Все изменения, сделанные после этого коммита пропадут.
  
  ```
  Если я хочу отменить все внесённые изменения и начать работу с чистого листа, я использую команду `git reset --hard HEAD`.
  
  git reset --hard [1]/yourBranch - более точно указываем к чем мы хотим откатить (к оригинальной ветка, которая хранится удаленно). 
  
  git reset --hard HEAD~1 - назад на 1 коммит
  ```
  
  * `git reset {{some-commit-hash}}` — вернуться на определённый коммит в истории. Все изменения, сделанные после этого коммита, получат состояние «Not staged for commit» - надо делать git add и git commit. Чтобы вернуть их обратно, нужно использовать команды git add и git commit.
  
  ```
  Если я хочу отредактировать изменения и/или закоммитить файлы в другом порядке, я использу git reset {{some-start-point-hash}}.
  ```
  
  * `git reset --soft {{some-commit-hash}}` — вернуться на определённый коммит в истории. Все изменения, сделанные после этого коммита, получат состояние «Staged for commit». Чтобы вернуть их обратно, нужно использовать команду git commit.
  
  ```
  Если я просто хочу взять три последних коммита и слить их в один большой коммит, я использую команду git reset --soft {{some-start-point-hash}}
  ```

  или если хочется изменить только файл
 
* `git checkout (our file)` - заменяет ваш локальный файл на оригинальной из удаленного репозитория (без конкретного указания откуда, он будет заменять текущие незакоммиченный файл на тот же файл из HEAD)

</p>
</details>

---

#### Возвратить "навсегда" удаленные коммиты

<details><summary>Open</summary>
<p>
	
  Способ 1:
	
```console
➜ git reflog
## Находим потерявшийся коммит. И возвращаемся к нему
➜ git checkout a38f9gdade[commit hash]
## Или
➜ git reset --hard a38f9gdade 
## Создаем ветку и пушим изменения
```

  Способ 2:

Утилита `git fsck` проверяет внутреннюю базу данных на целостность. Если выполнить её с ключом --full, будут показаны все объекты, недостижимые из других объектов:
	
```console
➜ git fsck --full
```

В нашем случае потерянный коммит указан после слов «dangling commit» («висячий коммит»). Его можно восстановить аналогичным образом, создав новую ветку, указывающую на этот SHA-1.
	
</p>
</details>

---

#### Merge

<details><summary>Open</summary>
<p>
  
* git checkout master
* git merge my_branch
  
My_branch слилась в master 

**Merge-конфликт** все, что выше `=======` - это HEAD, все, что ниже до `>>>>>>>` - это то, что мы сливали в мастер (My_branch)
  
Merge при конфликтах становится опасной утилитой - не всегда можно заметить какие строчки добавлены или файлы (а они могут влиять на работу программы). Справитсья с такой проблемой поможет команда `git mergetool`. Выведется vimdiff, который покажет полную разницу в файлах.
  
</p>
</details>

---
  
#### Rebase/squash

<details><summary>Open</summary>
<p>

1. Ребейз на новую ветку

Куда: [1]/release
Откуда: bugfix

	git checkout [1]/release && git fetch && git pull && git checkout bugfix
  
	git rebase [1]/release

	git push -f
  
  Только n коммитов ребейзнуть [ссылка:](https://stackoverflow.com/questions/39084984/how-to-rebase-only-last-two-commits-without-the-whole-branch#:~:text=First%20create%20the%20branch%20other_feature%20at%20the%20same%20commit%20as%20feature%20.&text=Rebase%20the%20previous%20two%20commits%20onto%20master%20.&text=Checkout%20feature%20.&text=Reset%20feature%20to%20the%20commit%20where%20you%20want%20it.)

	git co branch1
	
	git rebase -i --onto (branch2) HEAD~3
	
	branch1 rebased to branch2

2. squash

`git rebase -i HEAD~4` - в интерактивном режиме выбирает 4 коммита(включая головной), чтобы с ними что-то делать. Открывается вим и снизу вверх показаны коммиты по новизне (снизу последний).

Задача: 4 коммиты текста превратить в 2 (соединить коммиты "added third text", "added second text" и "added additional text")
```console
* 7ae83e1 2 hours ago [eldaroid]  | added third text
* a3db998 2 hours ago [eldaroid]  | added second text
* ee5273f 2 hours ago [eldaroid]  | added additional text
* bdb22e5 2 hours ago [eldaroid]  | file1
```

`git rebase -i HEAD ~4`, открывается следующее:

```console
pick bdb22e5 file1
f ee5273f added additional text
f a3db998 added second text
r 7ae83e1 added third text
```
Что произойдет? Коммит a3db998 склеится с ee5273f и потом 7ae83e1 склеится с тем, который получится в результате склеивания a3db998 и ee5273f. Текст коммита у ee5273f и a3db998 выкинется. Нас перекинет в окно, где можно будет изменить текст коммита у 7ae83e1 (изменили "added additional text" на "added text")

После дерево будет выглядить так (важно отметить, что хеши у последних 2х коммитов изменились):
```console
* 08e436b 3 hours ago [eldaroid]  | added text
* bdb22e5 3 hours ago [eldaroid]  | file1
```

3. Pull --rebase

Удаленная ветка: A--B--C. Вы работаете: A--B--C--(D) - D еще не на удаленной репе. Кто то в вашей ветке делает удаленный коммит: А--В--С--Е. Теперь вы не можете запушить (D), появляется ошибка: 

```console
! [rejected]        master -> master (fetch first)
error: failed to push some refs to 'https://github.com/eldaroid/iosBasics.git'
hint: Updates were rejected because the remote contains work that you do
hint: not have locally. This is usually caused by another repository pushing
hint: to the same ref. You may want to first integrate the remote changes
hint: (e.g., 'git pull ...') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.	
```

Решение: `git pull --rebase` = делает `git fetch` + `git rebase`. Получается у нас следующая картина: А--В--С--Е--(D). Теперь пушим изменения `git push`. Получается следующяя картина: А--В--С--Е--D.
	
</p>
</details>

---

#### Alias git


---

#### Количество коммитов по авторам

<details><summary>Open</summary>
<p>

Количество коммитов по авторам с 22 июня 2021 г. по 9 сентября 2021 г.:
```console
➜ git shortlog -s -n --since="22-06-2021" --before="2022-09-01"	
```

С определенной даты до сегодня:

```console
➜ git shortlog -s -n --since="22-06-2021"
```	

</p>
</details>

---

#### Если clone слишком большой

<details><summary>Open</summary>
<p>

```console
➜ git config --global core.compression 0
➜ git config --global http.postBuffer 1048576000
➜ git config --global http.maxRequestBuffer 100M
➜ git clone
```

```
git config --global http.maxRequestBuffer 100M --depth=1 - также может помочь, означает, что надо засквошить все коммиты в 1 последний. Когда это сработает, перейдите в новый каталог и получите оставшуюся часть клона: git fetch --unshallow  и git pull --all
``` 

Также это можно добавить в [gitconfig](/1%20Common/1.1%20Configs/1.1.3%20gitconfig.md), чтобы не прописывать каждый раз
</p>
</details>

---

#### Глубина клонирования репозитория

`git clone --depth 1 https://github.com/v1s1t0r1sh3r3/airgeddon.git` # создается "мелкая" копию (или shallow clone) и скачивает только один последний коммит

---

[1.2.3 GitFlow Theme Folder](./1.2.3%20Flow/) | [Back To iTWiki Contents](https://github.com/eldaroid/iTWiki) |  [1.2.5 Git Hooks Theme Folder](../1.2%20Git/1.2.5%20GitHook/)
