Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revision Previous revision
Next revisionBoth sides next revision
devops:git [2020/03/27 14:22] – [Откат изменений] admindevops:git [2020/05/28 21:33] – [Разбиение коммитов и распределение их по веткам] admin
Line 1: Line 1:
 +много рецептов: https://webhamster.ru/mytetrashare/index/mtb0/
 +====== Ветвление и слияние веток ======
 +Клонируем репозиторий:
 +  git clone https://....
 +Создаем ветку:
 +  git branch new-branch
 +и переключаемся на нее:
 +  git checkout new-branch
 +или обе команды в одной (создаем и сразу переключаемся на ветку):
 +  git checkout -b new-branch
 +Увидеть какие ветки есть можно так:
 +  git branch -a
 +===== Слияние веток =====
 +Например - есть две ветки **master** и **new-branch**. \\
 +Когда говорят, что нужно слить ветку **new-branch** с веткой **master**, то это значит, что нужно выполнить переключение на ветку **master**:
 +  git checkout master
 +и выполнить слияние ветки **new-branch**:
 +  git merge new-branch
 +===== Разрешение конфликтов при слиянии =====
 +Конфликт возникает, если изменения в одном и том же файле были произведены в двух ветках и мы пытаемся слить эти ветки. \\
 +Для того, чтобы увидеть суть конфиликта нужно видеть три состояния:
 +  - Состояние первой ветки
 +  - Состояние второй ветки
 +  - Общее начальное состояние веток до изменений.
 +Включить отображение различий и общего начального стсоояния можно так:
 +  git config merge.conflictstyle diff3
 +Допустим, была ветка **master**, от которой ответвились две ветки - **develop** и **feature**, в которых были произведены изменения в одном и том же файле. \\
 +При попытке слияния ветки **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
 +  ...
 +  <<<<<<< HEAD
 +  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
 +  >>>>>>> feature
 +  }
 +Тут три фрагмента:
 +  * Первый принадлежит ветке **develop**:
 +<code>func sum (a, b int) int {
 +  return a + b
 +}</code>
 +  * Второй - принадлежит общему предку - коммиту в ветке **master**:
 +<code>func sum (a, b int) int {
 +  t := b + a
 +  return t
 +}
 +</code>
 +  * Третий - ветке **feature**
 +<code>func sum(a, b int) int {
 +        t := a + b
 +        return t
 +}
 +</code>
 +Теперь нужно как-то разрешить конфликт. Например, мы знаем, что нужно оставить самые последние версии (по времени внесения изменений). \\
 +Отлично написано тут: https://www.rosipov.com/blog/use-vimdiff-as-git-mergetool/ \\
 +Для разрешения конфликта будем использовать дефолтную утилиту **vimdiff**. \\
 +Настраиваем git для использования **vimdiff** в качестве **mergetool**:
 +<code>
 +git config merge.tool vimdiff
 +git config mergetool.prompt false
 +</code>
 +Приступаем к разрешению конфликта:
 +  git mergetool
 +Листаем вниз и видим конфликт:
 +<code>  func sum (a, b int) int {                func sum (a, b int) int {                func sum(a, b int) int {                
 +    return a + b                          |    t := a + b                            |          t := a + b                      
 +  ----------------------------------------|    return t                              |          return t                        
 +  ----------------------------------------|  ----------------------------------------|  ----------------------------------------
 +  ----------------------------------------|  ----------------------------------------|  ----------------------------------------
 +  ----------------------------------------|  ----------------------------------------|  ----------------------------------------
 +  ----------------------------------------|  ----------------------------------------|  ----------------------------------------
 +  ----------------------------------------|  ----------------------------------------|  ----------------------------------------
 +  ----------------------------------------|  ----------------------------------------|  ----------------------------------------
 +  ----------------------------------------|  ----------------------------------------|  ----------------------------------------
 +./main_LOCAL_25754.go   44,          97% ./main_BASE_25754.go    45,2           97% ./main_REMOTE_25754.go  45,2           97%
 +  <<<<<<< HEAD                                                                                                                  
 +  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                                                                                                       47,          95%</code>
 +Тут мы видим:
 +  - слева - состояние ветки в которую мерджим изменения (обозначены **LOCAL**)
 +  - в середине - общий предок (**BASE**)
 +  - справа - состояние ветки которую мы мерджим (**REMOTE**)
 +  - Внизу - конфликт
 +Нужно оставить изменения, которые содержатся в ветке **REMOTE**. Для этого переключаемся между окошками с помощью **Ctrl + w,j** на нижнее окошко, листам вниз до конфликта и жмем последовательно:
 +  Esc
 +  :diffg RE
 +  :wqa
 +Эта последовательность команд переводит редактор в режим команд (кнопочка **Esc**), затем применяем изменения из ветки **REMOTE**, а затем сохраняем изменения. \\
 +Измнения из **LOCAL** или **BASE** применяются соответственно командами:
 +  :diffg BA
 +  :diffg LO
 +И наконец можно выполнить commit:
 +  git commit -a -m "Branch 'feature' merged to 'develop'"
 +====== Переключиться на нужный коммит ======
 +Находим нужный коммит с помощью 
 +  git log
 +И переключаемся на него:
 +  git checkout <commit_hash>
 +
 +====== Тегирование коммитов ======
 +Тегируем текущий коммит и пушим тег:
 +  git tag <tag_name>
 +  git push <remote_name> <branch_name> <tag_name>
 +Например:
 +  git tag ops.07
 +  git push origin master ops.07
 +
 +====== Откат изменений ======
 +  git reset --hard
 +Откат определенных коммитов (**rebase** & **cherry-pick** vs. **revert**): https://www.pixelstech.net/article/1549115148-git-reset-vs-git-revert \\
 +  git revert ...
 +  
 +====== Объединение коммитов ======
 +https://git-scm.com/book/ru/v1/%D0%98%D0%BD%D1%81%D1%82%D1%80%D1%83%D0%BC%D0%B5%D0%BD%D1%82%D1%8B-Git-%D0%9F%D0%B5%D1%80%D0%B5%D0%B7%D0%B0%D0%BF%D0%B8%D1%81%D1%8C-%D0%B8%D1%81%D1%82%D0%BE%D1%80%D0%B8%D0%B8 \\
 +Объединить коммиты можно с помощью **interactive rebase**:
 +  git rebase -i HEAD~3
 +Откроется тектовый редактор, в котором в начале будут перечислены коммиты (в данном случае - 3 штуки, начиная с самого старого) и применяемые к ним действия (по умолчанию - **pick**). Для того, чтобы объединить коммиты нужно для самого первого (старого) оставить **pick**, а для остальных прописать **squash** (или сокращенно **s**). В результате, изменения в коммитах объединятся в один (самый старый). 
 +
 +===== Объединение всех коммитов ветки =====
 +  git reset `echo "Total Squash Commit" | git commit-tree HEAD^{tree}`
 +
 +===== Разбиение коммитов и распределение их по веткам =====
 +Предствьте себе, что случилась неприятность - вы недумая коммитили в master, в одном коммите могли оказаться изменения, касающиеся разных фич. И всё было хорошо, пока кто-то не захотел сделать ревью и увидел ХАОС. Что нужно - нужно разбить сделанные коммиты по веткам фич. Для этого - нужно разбить все старые коммиты и потом применить их к нужным веткам. Как разбить коммит, который зарыт глубоко в истории?? Поможет  rebase! Что он делает - применяет коммиты последовательно к тому, на котором мы делаем rebase. Как вмешаться в этот процесс - запустить его в интерактивном режиме, когда мы можем указать что делать с каждым коммитом.\\
 +Допустим - у нас поверх последнего хорошего коммита выполнено уже 4 нехороших хаотичных.
 +Первое - выполняем интерактивный ребейс:
 +  git rebase -i HEAD~4
 +Либо прямо делаем **rebase**, указав хеш коммита:
 +  git rebase -i <LAST_GOOD_COMMIT>
 +Откроется окно редактора, в котором будет список коммитов, начиная с самого старого. На против каждого будет стоять **pick**. Если сейчас ничего не менять - то ничего и не произойдет. Все коммиты применятся и мы откажемся на последнем. Но! Если для первого поставить вместо **pick** - **edit**, сохраним файлик и выйдем, то мы окажемся на этом коммите. А дальше - магия **git**. \
 +Отменяем коммит, на котором мы находимся в данный момент (который был закоммичен последним с нашей точки зрения - а это тот, для которого мы указали **edit**):
 +  git reset HEAD~
 +Проверим, что изменения откатились и увидим список измененных в этом коммите файлов:
 +  git status
 +Например, файлы разбиты по каталогам feature1 и feature2 (будем считать так для простоты). Нам надо разбить изменения в этих каталогах на два коммита. Последовательно добавляем в stage каталоги (или файлы) и коммитим:
 +  git add ./feature1/*
 +  git commit -m 'feature1 commit'
 +  git add ./feature2/*
 +  git commit -m 'feature2 commit'
 +В итоге наш крупный коммит был разбит на два. А теперь - продолжим **rebase**:
 +  git rebase --continue
 +Всё. \\
 +Теперь эту процедуру можно повторить для остальных крупных беспорядочных коммитов. \\
 +А потом - ответвить от последнего хорошего коммита ветки и применять на эти ветки коммиты, соответствующие фичам:
 +  git checkout <LAST_GOOD_COMMIT>
 +  git checkout -b feature1
 +  git cherry-pick <FEATURE1_SHA1>
 +и для второй фичи:
 +  git checkout <LAST_GOOD_COMMIT>
 +  git checkout -b feature2
 +  git cherry-pick <FEATURE2_COMMIT_SHA1>
 +
 +
 +
 +
 + 
 +====== Скачать из репозитория git одну единственную папку ======
 +<code>mkdir charts
 +cd charts
 +git init
 +git remote add origin https://github.com/helm/charts.git
 +git config core.sparseCheckout true
 +echo "stable/jenkins" > .git/info/sparse-checkout
 +git pull origin master</code>
 +или
 +  git archive --format tar --remote ssh://server.org/path/to/git HEAD docs/usage > /tmp/usage_docs.tar
 +  
 +====== Почистить репозиторий git ======
 +Допустим, у нас не было файлика **.gitignore** и в репозиторий попало много ненужного. \\
 +Теперь я хочу избавиться от ненужных файлов в репозитории. \\
 +Для этого:
 +  * делаем коммит текущего состояния, вместе с файликом **.gitignore**
 +  * удаляем все ненужные файлики из репы
 +  * удаляем все файлики из индекса репозитория ( отдельный файлик можно удалить так: git rm --cached foo.txt )
 +<code>git rm -r --cached .</code>
 +  * и добавляем все файлики обратно в индекс:
 +<code>git add .</code>
 +  * Коммитим состояние
 +<code>git commit -m ".gitignore fix"</code>
 +
  
  • devops/git.txt
  • Last modified: 2021/12/01 09:01
  • by admin