Differences
This shows you the differences between two versions of the page.
Both sides previous revision Previous revision Next revision | Previous revision Next revisionBoth sides next revision | ||
devops:git [2019/12/06 11:07] – [Скачать из репозитория git одну единственную папку] admin | devops:git [2020/05/28 21:33] – [Разбиение коммитов и распределение их по веткам] admin | ||
---|---|---|---|
Line 1: | Line 1: | ||
+ | много рецептов: | ||
+ | ====== Ветвление и слияние веток ====== | ||
+ | Клонируем репозиторий: | ||
+ | git clone https:// | ||
+ | Создаем ветку: | ||
+ | git branch new-branch | ||
+ | и переключаемся на нее: | ||
+ | git checkout new-branch | ||
+ | или обе команды в одной (создаем и сразу переключаемся на ветку): | ||
+ | git checkout -b new-branch | ||
+ | Увидеть какие ветки есть можно так: | ||
+ | git branch -a | ||
+ | ===== Слияние веток ===== | ||
+ | Например - есть две ветки **master** и **new-branch**. \\ | ||
+ | Когда говорят, | ||
+ | git checkout master | ||
+ | и выполнить слияние ветки **new-branch**: | ||
+ | git merge new-branch | ||
+ | ===== Разрешение конфликтов при слиянии ===== | ||
+ | Конфликт возникает, | ||
+ | Для того, чтобы увидеть суть конфиликта нужно видеть три состояния: | ||
+ | - Состояние первой ветки | ||
+ | - Состояние второй ветки | ||
+ | - Общее начальное состояние веток до изменений. | ||
+ | Включить отображение различий и общего начального стсоояния можно так: | ||
+ | git config merge.conflictstyle diff3 | ||
+ | Допустим, | ||
+ | При попытке слияния ветки **feature** с веткой **develop**: | ||
+ | git checkout develop | ||
+ | git merge feature | ||
+ | будет создан коммит, | ||
+ | Auto-merging main.go | ||
+ | CONFLICT (content): Merge conflict in main.go | ||
+ | Automatic merge failed; fix conflicts and then commit the result. | ||
+ | Увидеть суть конфликта можно в конце листинга указанного файла: | ||
+ | cat ./main.go | ||
+ | ... | ||
+ | <<<<<<< | ||
+ | func sum (a, b int) int { | ||
+ | return a + b | ||
+ | ||||||| merged common ancestors | ||
+ | func sum (a, b int) int { | ||
+ | t := a + b | ||
+ | return t | ||
+ | ======= | ||
+ | func sum(a, b int) int { | ||
+ | t := a + b | ||
+ | return t | ||
+ | >>>>>>> | ||
+ | } | ||
+ | Тут три фрагмента: | ||
+ | * Первый принадлежит ветке **develop**: | ||
+ | < | ||
+ | return a + b | ||
+ | }</ | ||
+ | * Второй - принадлежит общему предку - коммиту в ветке **master**: | ||
+ | < | ||
+ | t := b + a | ||
+ | return t | ||
+ | } | ||
+ | </ | ||
+ | * Третий - ветке **feature** | ||
+ | < | ||
+ | t := a + b | ||
+ | return t | ||
+ | } | ||
+ | </ | ||
+ | Теперь нужно как-то разрешить конфликт. Например, | ||
+ | Отлично написано тут: https:// | ||
+ | Для разрешения конфликта будем использовать дефолтную утилиту **vimdiff**. \\ | ||
+ | Настраиваем git для использования **vimdiff** в качестве **mergetool**: | ||
+ | < | ||
+ | git config merge.tool vimdiff | ||
+ | git config mergetool.prompt false | ||
+ | </ | ||
+ | Приступаем к разрешению конфликта: | ||
+ | git mergetool | ||
+ | Листаем вниз и видим конфликт: | ||
+ | < | ||
+ | return a + b | t := a + b | t := a + b | ||
+ | ----------------------------------------| | ||
+ | ----------------------------------------| | ||
+ | ----------------------------------------| | ||
+ | ----------------------------------------| | ||
+ | ----------------------------------------| | ||
+ | ----------------------------------------| | ||
+ | ----------------------------------------| | ||
+ | ----------------------------------------| | ||
+ | ./ | ||
+ | <<<<<<< | ||
+ | func sum (a, b int) int { | ||
+ | return a + b | ||
+ | ||||||| merged common ancestors | ||
+ | func sum (a, b int) int { | ||
+ | t := a + b | ||
+ | return t | ||
+ | ======= | ||
+ | func sum(a, b int) int { | ||
+ | t := a + b | ||
+ | return t | ||
+ | main.go | ||
+ | Тут мы видим: | ||
+ | - слева - состояние ветки в которую мерджим изменения (обозначены **LOCAL**) | ||
+ | - в середине - общий предок (**BASE**) | ||
+ | - справа - состояние ветки которую мы мерджим (**REMOTE**) | ||
+ | - Внизу - конфликт | ||
+ | Нужно оставить изменения, | ||
+ | Esc | ||
+ | :diffg RE | ||
+ | :wqa | ||
+ | Эта последовательность команд переводит редактор в режим команд (кнопочка **Esc**), затем применяем изменения из ветки **REMOTE**, а затем сохраняем изменения. \\ | ||
+ | Измнения из **LOCAL** или **BASE** применяются соответственно командами: | ||
+ | :diffg BA | ||
+ | :diffg LO | ||
+ | И наконец можно выполнить commit: | ||
+ | git commit -a -m " | ||
+ | ====== Переключиться на нужный коммит ====== | ||
+ | Находим нужный коммит с помощью | ||
+ | git log | ||
+ | И переключаемся на него: | ||
+ | git checkout < | ||
+ | |||
+ | ====== Тегирование коммитов ====== | ||
+ | Тегируем текущий коммит и пушим тег: | ||
+ | git tag < | ||
+ | git push < | ||
+ | Например: | ||
+ | git tag ops.07 | ||
+ | git push origin master ops.07 | ||
+ | |||
+ | ====== Откат изменений ====== | ||
+ | git reset --hard | ||
+ | Откат определенных коммитов (**rebase** & **cherry-pick** vs. **revert**): | ||
+ | git revert ... | ||
+ | | ||
+ | ====== Объединение коммитов ====== | ||
+ | https:// | ||
+ | Объединить коммиты можно с помощью **interactive rebase**: | ||
+ | git rebase -i HEAD~3 | ||
+ | Откроется тектовый редактор, | ||
+ | |||
+ | ===== Объединение всех коммитов ветки ===== | ||
+ | git reset `echo "Total Squash Commit" | ||
+ | |||
+ | ===== Разбиение коммитов и распределение их по веткам ===== | ||
+ | Предствьте себе, что случилась неприятность - вы недумая коммитили в master, в одном коммите могли оказаться изменения, | ||
+ | Допустим - у нас поверх последнего хорошего коммита выполнено уже 4 нехороших хаотичных. | ||
+ | Первое - выполняем интерактивный ребейс: | ||
+ | git rebase -i HEAD~4 | ||
+ | Либо прямо делаем **rebase**, указав хеш коммита: | ||
+ | git rebase -i < | ||
+ | Откроется окно редактора, | ||
+ | Отменяем коммит, | ||
+ | git reset HEAD~ | ||
+ | Проверим, | ||
+ | git status | ||
+ | Например, | ||
+ | git add ./ | ||
+ | git commit -m ' | ||
+ | git add ./ | ||
+ | git commit -m ' | ||
+ | В итоге наш крупный коммит был разбит на два. А теперь - продолжим **rebase**: | ||
+ | git rebase --continue | ||
+ | Всё. \\ | ||
+ | Теперь эту процедуру можно повторить для остальных крупных беспорядочных коммитов. \\ | ||
+ | А потом - ответвить от последнего хорошего коммита ветки и применять на эти ветки коммиты, | ||
+ | git checkout < | ||
+ | git checkout -b feature1 | ||
+ | git cherry-pick < | ||
+ | и для второй фичи: | ||
+ | git checkout < | ||
+ | git checkout -b feature2 | ||
+ | git cherry-pick < | ||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | ====== Скачать из репозитория git одну единственную папку ====== | ||
+ | < | ||
+ | cd charts | ||
+ | git init | ||
+ | git remote add origin https:// | ||
+ | git config core.sparseCheckout true | ||
+ | echo " | ||
+ | git pull origin master</ | ||
+ | или | ||
+ | git archive --format tar --remote ssh:// | ||
+ | | ||
+ | ====== Почистить репозиторий git ====== | ||
+ | Допустим, | ||
+ | Теперь я хочу избавиться от ненужных файлов в репозитории. \\ | ||
+ | Для этого: | ||
+ | * делаем коммит текущего состояния, | ||
+ | * удаляем все ненужные файлики из репы | ||
+ | * удаляем все файлики из индекса репозитория ( отдельный файлик можно удалить так: git rm --cached foo.txt ) | ||
+ | < | ||
+ | * и добавляем все файлики обратно в индекс: | ||
+ | < | ||
+ | * Коммитим состояние | ||
+ | < | ||
+ | |||