Skip to content

Latest commit

 

History

History
261 lines (216 loc) · 13 KB

File metadata and controls

261 lines (216 loc) · 13 KB

Домашнее задание к занятию «Ветвления в Git»

Цель задания

В процессе работы над заданием вы потренеруетесь делать merge и rebase. В результате вы поймете разницу между ними и научитесь решать конфликты.

Обычно при нормальном ходе разработки выполнять rebase достаточно просто. Это позволяет объединить множество промежуточных коммитов при решении задачи, чтобы не засорять историю, поэтому многие команды и разработчики предпочитают такой способ.

Инструкция к заданию

  1. В личном кабинете отправьте на проверку ссылку на network графика вашего репозитория.
  2. Любые вопросы по решению задач задавайте в чате учебной группы.

Инструменты/ дополнительные материалы, которые пригодятся для выполнения задания

Тренажер https://learngitbranching.js.org/, где можно потренироваться в работе с деревом коммитов и ветвлений.


Задание. Ветвление, merge и rebase

  1. Предположим, что есть задача написать скрипт, выводящий на экран параметры его запуска. Давайте посмотрим, как будет отличаться работа над этим скриптом с использованием ветвления, merge и rebase. Создайте в своем репозитории каталог branching и в нем два файла merge.sh и rebase.sh с содержимым:
#!/bin/bash
# display command line options

count=1
for param in "$*"; do
    echo "\$* Parameter #$count = $param"
    count=$(( $count + 1 ))
done

Этот скрипт отображает на экране все параметры одной строкой, а не разделяет их.

  1. Создадим коммит с описанием prepare for merge and rebase и отправим его в ветку main.

Подготовка файла merge.sh

  1. Создайте ветку git-merge.
  2. Замените в ней содержимое файла merge.sh на
#!/bin/bash
# display command line options

count=1
for param in "$@"; do
    echo "\$@ Parameter #$count = $param"
    count=$(( $count + 1 ))
done
  1. Создайте коммит merge: @ instead * отправьте изменения в репозиторий
  2. И разработчик подумал и решил внести еще одно изменение в merge.sh
#!/bin/bash
# display command line options

count=1
while [[ -n "$1" ]]; do
    echo "Parameter #$count = $1"
    count=$(( $count + 1 ))
    shift
done

Теперь скрипт будет отображать каждый переданный ему параметр отдельно.

  1. Создайте коммит merge: use shift и отправьте изменения в репозиторий.

Изменим main

  1. Вернитесь в ветку main.
  2. Предположим, что кто-то, пока мы работали над веткой git-merge, изменил main. Для этого изменим содержимое файла rebase.sh на следующее
#!/bin/bash
# display command line options

count=1
for param in "$@"; do
    echo "\$@ Parameter #$count = $param"
    count=$(( $count + 1 ))
done

echo "====="

В этом случае скрипт тоже будет отображать каждый параметр в новой строке.

  1. Отправляем измененную ветку main в репозиторий.

Подготовка файла rebase.sh

  1. Предположим, что теперь другой участник нашей команды не сделал git pull, либо просто хотел ответвиться не от последнего коммита в main, а от коммита когда мы только создали два файла merge.sh и rebase.sh на первом шаге.
    Для этого при помощи команды git log найдем хэш коммита prepare for merge and rebase и выполним git checkout на него примерно так: git checkout 8baf217e80ef17ff577883fda90f6487f67bbcea (хэш будет другой).
  2. Создадим ветку git-rebase основываясь на текущем коммите.
  3. И изменим содержимое файла rebase.sh на следующее, тоже починив скрипт, но немного в другом стиле
#!/bin/bash
# display command line options

count=1
for param in "$@"; do
    echo "Parameter: $param"
    count=$(( $count + 1 ))
done

echo "====="
  1. Отправим эти изменения в ветку git-rebase, с комментарием git-rebase 1.
  2. И сделаем еще один коммит git-rebase 2 с пушем заменив echo "Parameter: $param" на echo "Next parameter: $param".

Промежуточный итог

Мы сэмулировали типичную ситуации в разработке кода, когда команда разработчиков работала над одним и тем же участком кода, причем кто-то из разработчиков предпочитает делать merge, а кто-то rebase. Конфликты с merge обычно решаются достаточно просто, а с rebase бывают сложности, поэтому давайте смержим все наработки в main и разрешим конфликты.

Если все было сделано правильно, то на странице network в гитхабе, находящейся по адресу https://github.com/ВАШ_ЛОГИН/ВАШ_РЕПОЗИТОРИЙ/network будет примерно такая схема:
Созданы обе ветки

Merge

Сливаем ветку git-merge в main и отправляем изменения в репозиторий, должно получиться без конфликтов:

$ git merge git-merge
Merge made by the 'recursive' strategy.
 branching/merge.sh | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)
$ git push
#!/bin/bash
Enumerating objects: 1, done.
Counting objects: 100% (1/1), done.
Writing objects: 100% (1/1), 223 bytes | 223.00 KiB/s, done.
Total 1 (delta 0), reused 0 (delta 0), pack-reused 0

В результате получаем такую схему:
Первый мерж

Rebase

  1. А перед мержем ветки git-rebase выполним ее rebase на main. Да, мы специально создали ситуацию с конфликтами, чтобы потренироваться их решать.
  2. Переключаемся на ветку git-rebase и выполняем git rebase -i main. В открывшемся диалоге должно быть два выполненных нами коммита, давайте заодно объединим их в один, указав слева от нижнего fixup. В результате получаем что-то подобное:
$ git rebase -i main
Auto-merging branching/rebase.sh
CONFLICT (content): Merge conflict in branching/rebase.sh
error: could not apply dc4688f... git 2.3 rebase @ instead *
Resolve all conflicts manually, mark them as resolved with
"git add/rm <conflicted_files>", then run "git rebase --continue".
You can instead skip this commit: run "git rebase --skip".
To abort and get back to the state before "git rebase", run "git rebase --abort".
Could not apply dc4688f... git 2.3 rebase @ instead *

Если посмотреть содержимое файла rebase.sh, то увидим метки, оставленные гитом для решения конфликта:

cat rebase.sh
#!/bin/bash
# display command line options
count=1
for param in "$@"; do
<<<<<<< HEAD
    echo "\$@ Parameter #$count = $param"
=======
    echo "Parameter: $param"
>>>>>>> dc4688f... git 2.3 rebase @ instead *
    count=$(( $count + 1 ))
done

Удалим метки, отдав предпочтение варианту

echo "\$@ Parameter #$count = $param"

сообщим гиту, что конфликт решен git add rebase.sh и продолжим ребейз git rebase --continue.

И опять в получим конфликт в файле rebase.sh при попытке применения нашего второго коммита. Давайте разрешим конфликт, оставив строчку echo "Next parameter: $param".

Далее опять сообщаем гиту о том, что конфликт разрешен git add rebase.sh и продолжим ребейз git rebase --continue. В результате будет открыт текстовый редактор предлагающий написать комментарий к новому объединенному коммиту:

# This is a combination of 2 commits.
# This is the 1st commit message:

Merge branch 'git-merge'

# The commit message #2 will be skipped:

# git 2.3 rebase @ instead * (2)

Все строчки начинающиеся на # будут проигнорированны.

После сохранения изменения, гит сообщит

Successfully rebased and updated refs/heads/git-rebase

И попробуем выполнить git push, либо git push -u origin git-rebase чтобы точно указать что и куда мы хотим запушить. Эта команда завершится с ошибкой:

git push
To github.com:andrey-borue/devops-netology.git
 ! [rejected]        git-rebase -> git-rebase (non-fast-forward)
error: failed to push some refs to '[email protected]:andrey-borue/devops-netology.git'
hint: Updates were rejected because the tip of your current branch is behind
hint: its remote counterpart. Integrate the remote changes (e.g.
hint: 'git pull ...') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.

Это произошло, потому что мы пытаемся перезаписать историю. Чтобы гит позволил нам это сделать, давайте добавим флаг force:

git push -u origin git-rebase -f
Enumerating objects: 10, done.
Counting objects: 100% (9/9), done.
Delta compression using up to 12 threads
Compressing objects: 100% (4/4), done.
Writing objects: 100% (4/4), 443 bytes | 443.00 KiB/s, done.
Total 4 (delta 1), reused 0 (delta 0), pack-reused 0
remote: Resolving deltas: 100% (1/1), completed with 1 local object.
To github.com:andrey-borue/devops-netology.git
 + 1829df1...e3b942b git-rebase -> git-rebase (forced update)
Branch 'git-rebase' set up to track remote branch 'git-rebase' from 'origin'.

Теперь можно смержить ветку git-rebase в main без конфликтов и без дополнительного мерж-комита простой перемоткой.

$ git checkout main
Switched to branch 'main'
Your branch is up to date with 'origin/main'.

$ git merge git-rebase
Updating 6158b76..45893d1
Fast-forward
 branching/rebase.sh | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

В качестве результата работы по всем заданиям приложите ссылку на .md-файл в вашем репозитории


Правила приема домашнего задания

В личном кабинете отправлена на проверку ссылка на network графика вашего репозитория.

Критерии оценки

Зачет - выполнены все задания, ответы даны в развернутой форме, приложены соответствующие скриншоты и файлы проекта, в выполненных заданиях нет противоречий и нарушения логики.

На доработку - задание выполнено частично или не выполнено, в логике выполнения заданий есть противоречия, существенные недостатки.