В процессе работы над заданием вы потренеруетесь делать merge и rebase. В результате вы поймете разницу между ними и научитесь решать конфликты.
Обычно при нормальном ходе разработки выполнять rebase
достаточно просто.
Это позволяет объединить множество промежуточных коммитов при решении задачи, чтобы не засорять историю, поэтому многие команды и разработчики предпочитают такой способ.
- В личном кабинете отправьте на проверку ссылку на network графика вашего репозитория.
- Любые вопросы по решению задач задавайте в чате учебной группы.
Тренажер https://learngitbranching.js.org/, где можно потренироваться в работе с деревом коммитов и ветвлений.
- Предположим, что есть задача написать скрипт, выводящий на экран параметры его запуска.
Давайте посмотрим, как будет отличаться работа над этим скриптом с использованием ветвления, 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
Этот скрипт отображает на экране все параметры одной строкой, а не разделяет их.
- Создадим коммит с описанием
prepare for merge and rebase
и отправим его в ветку main.
- Создайте ветку
git-merge
. - Замените в ней содержимое файла
merge.sh
на
#!/bin/bash
# display command line options
count=1
for param in "$@"; do
echo "\$@ Parameter #$count = $param"
count=$(( $count + 1 ))
done
- Создайте коммит
merge: @ instead *
отправьте изменения в репозиторий - И разработчик подумал и решил внести еще одно изменение в
merge.sh
#!/bin/bash
# display command line options
count=1
while [[ -n "$1" ]]; do
echo "Parameter #$count = $1"
count=$(( $count + 1 ))
shift
done
Теперь скрипт будет отображать каждый переданный ему параметр отдельно.
- Создайте коммит
merge: use shift
и отправьте изменения в репозиторий.
- Вернитесь в ветку
main
. - Предположим, что кто-то, пока мы работали над веткой
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 "====="
В этом случае скрипт тоже будет отображать каждый параметр в новой строке.
- Отправляем измененную ветку
main
в репозиторий.
- Предположим, что теперь другой участник нашей команды
не сделал
git pull
, либо просто хотел ответвиться не от последнего коммита вmain
, а от коммита когда мы только создали два файлаmerge.sh
иrebase.sh
на первом шаге.
Для этого при помощи командыgit log
найдем хэш коммитаprepare for merge and rebase
и выполнимgit checkout
на него примерно так:git checkout 8baf217e80ef17ff577883fda90f6487f67bbcea
(хэш будет другой). - Создадим ветку
git-rebase
основываясь на текущем коммите. - И изменим содержимое файла
rebase.sh
на следующее, тоже починив скрипт, но немного в другом стиле
#!/bin/bash
# display command line options
count=1
for param in "$@"; do
echo "Parameter: $param"
count=$(( $count + 1 ))
done
echo "====="
- Отправим эти изменения в ветку
git-rebase
, с комментариемgit-rebase 1
. - И сделаем еще один коммит
git-rebase 2
с пушем заменивecho "Parameter: $param"
наecho "Next parameter: $param"
.
Мы сэмулировали типичную ситуации в разработке кода, когда команда разработчиков
работала над одним и тем же участком кода, причем кто-то из разработчиков
предпочитает делать merge
, а кто-то rebase
. Конфликты с merge обычно решаются достаточно просто,
а с rebase бывают сложности, поэтому давайте смержим все наработки в main
и разрешим конфликты.
Если все было сделано правильно, то на странице network
в гитхабе, находящейся по адресу
https://github.com/ВАШ_ЛОГИН/ВАШ_РЕПОЗИТОРИЙ/network
будет примерно такая схема:
Сливаем ветку 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
В результате получаем такую схему:
- А перед мержем ветки
git-rebase
выполним ееrebase
на main. Да, мы специально создали ситуацию с конфликтами, чтобы потренироваться их решать. - Переключаемся на ветку
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 'git@github.com: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 графика вашего репозитория.
Зачет - выполнены все задания, ответы даны в развернутой форме, приложены соответствующие скриншоты и файлы проекта, в выполненных заданиях нет противоречий и нарушения логики.
На доработку - задание выполнено частично или не выполнено, в логике выполнения заданий есть противоречия, существенные недостатки.