Введение
Функция cherry-pick в Git позволяет применять определенные коммиты из одной ветки в другую. Хотя эта функция мощная, иногда может потребоваться отменить операцию cherry-pick из-за ошибок или конфликтов. В этой лабораторной работе вы узнаете, как выполнить cherry-pick, а затем использовать различные методы для его отмены при необходимости. К концу работы вы получите практический опыт работы с операциями cherry-pick и навыки восстановления после распространенных проблем.
Настройка тестового репозитория
На этом шаге мы создадим тестовый Git-репозиторий для практики операций cherry-pick. Это обеспечит безопасную среду для экспериментов с различными командами Git.
Создание нового Git-репозитория
Начнем с создания нового каталога для нашего тестового репозитория и инициализации его как Git-репозитория:
mkdir -p ~/project/cherry-pick-lab
cd ~/project/cherry-pick-lab
git init
Вы должны увидеть вывод, аналогичный следующему:
Initialized empty Git repository in /home/labex/project/cherry-pick-lab/.git/
Настройка конфигурации пользователя Git
Прежде чем мы сможем делать коммиты, нам нужно настроить имя пользователя и адрес электронной почты для Git:
git config --local user.name "LabEx User"
git config --local user.email "labex@example.com"
Создание начальных коммитов в основной ветке
Давайте создадим несколько начальных коммитов в основной ветке:
## Create and commit the first file
echo "## Cherry Pick Lab" > README.md
git add README.md
git commit -m "Initial commit with README"
## Create and commit a second file
echo "console.log('Hello, world!');" > app.js
git add app.js
git commit -m "Add main application file"
Просмотр истории коммитов
Давайте проверим историю коммитов, чтобы убедиться, что все настроено правильно:
git log --oneline
Вы должны увидеть вывод, аналогичный следующему:
abcd123 (HEAD -> main) Add main application file
efgh456 Initial commit with README
Фактические хеши коммитов будут отличаться в вашей системе. Запишите хеш коммита для "Add main application file", так как мы будем использовать его позже.
Создание ветки разработки (Feature Branch)
Теперь давайте создадим ветку разработки, в которой мы внесем некоторые дополнительные изменения:
git checkout -b feature-branch
Вы должны увидеть вывод, аналогичный следующему:
Switched to a new branch 'feature-branch'
Теперь давайте добавим несколько коммитов в эту ветку разработки:
## Create and commit a new feature file
echo "function newFeature() { return 'awesome'; }" > feature.js
git add feature.js
git commit -m "Add new feature function"
## Modify the README file
echo -e "## Cherry Pick Lab\n\nThis repo demonstrates git cherry-pick operations." > README.md
git add README.md
git commit -m "Update README with project description"
Теперь у нас есть основная ветка с двумя коммитами и ветка разработки с двумя дополнительными коммитами. На следующем шаге мы будем использовать cherry-pick, чтобы применить один из коммитов ветки разработки к основной ветке.
Выполнение операции Cherry-pick
На этом шаге мы узнаем, как использовать команду cherry-pick для применения определенного коммита из одной ветки в другую. Это полезно, когда вы хотите выборочно включить изменения из одной ветки в другую.
Понимание Cherry-pick
Cherry-picking в Git позволяет вам выбрать определенный коммит из одной ветки и применить его к другой ветке. В отличие от слияния (merging) или перебазирования (rebasing), которые обычно применяют несколько коммитов, cherry-picking применяет только один коммит за раз.
Переключение обратно в основную ветку
Сначала давайте переключимся обратно в основную ветку, в которую мы хотим применить коммит из ветки разработки:
git checkout main
Вы должны увидеть вывод, подтверждающий переключение:
Switched to branch 'main'
Просмотр коммитов ветки разработки
Перед cherry-picking давайте рассмотрим коммиты в ветке разработки, которые мы, возможно, захотим применить к основной ветке:
git log feature-branch --oneline
Это покажет все коммиты в ветке разработки, включая те, которые общие с основной веткой. Вы увидите вывод, аналогичный следующему:
1234abc Update README with project description
5678def Add new feature function
abcd123 Add main application file
efgh456 Initial commit with README
Запишите хеш коммита для "Add new feature function" (в этом примере это 5678def). Мы будем использовать этот хеш на следующем шаге.
Cherry-picking коммита
Теперь давайте выполним cherry-pick коммита "Add new feature function" из ветки разработки в нашу основную ветку:
git cherry-pick [COMMIT_HASH]
Замените [COMMIT_HASH] фактическим хешем, который вы записали ранее. Например:
git cherry-pick 5678def
Если cherry-pick успешен, вы увидите вывод, аналогичный следующему:
[main 98765ab] Add new feature function
1 file changed, 1 insertion(+)
create mode 100644 feature.js
Проверка Cherry-pick
Давайте убедимся, что cherry-pick сработал, как ожидалось:
git log --oneline
Теперь вы должны увидеть коммит, выбранный с помощью cherry-pick, в истории вашей основной ветки:
98765ab (HEAD -> main) Add new feature function
abcd123 Add main application file
efgh456 Initial commit with README
Вы также можете проверить, что файл существует:
ls -la
Вы должны увидеть feature.js в списке вывода:
total 16
drwxr-xr-x 3 labex labex 4096 Jan 1 00:00 .
drwxr-xr-x 3 labex labex 4096 Jan 1 00:00 ..
drwxr-xr-x 8 labex labex 4096 Jan 1 00:00 .git
-rw-r--r-- 1 labex labex 29 Jan 1 00:00 app.js
-rw-r--r-- 1 labex labex 42 Jan 1 00:00 feature.js
-rw-r--r-- 1 labex labex 16 Jan 1 00:00 README.md
Операция cherry-pick успешно применила коммит из ветки разработки в основную ветку. На следующем шаге мы узнаем, как отменить этот cherry-pick, если это необходимо.
Отмена Cherry-pick с помощью Git Reset
Теперь, когда мы успешно выполнили cherry-pick коммита, давайте узнаем, как отменить эту операцию. На этом шаге мы будем использовать команду git reset, которая является наиболее простым способом отмены недавнего cherry-pick.
Понимание Git Reset
Команда git reset перемещает указатель текущей ветки к указанному коммиту, эффективно "отменяя" любые коммиты, которые были после этой точки. Существует три основных режима git reset:
--soft: Перемещает указатель ветки, но оставляет изменения в подготовленном состоянии (staged)--mixed(по умолчанию): Перемещает указатель ветки и отменяет подготовку изменений (unstages)--hard: Перемещает указатель ветки и отбрасывает все изменения
Для отмены cherry-pick мы будем использовать опцию --hard, чтобы полностью удалить коммит, выбранный с помощью cherry-pick, и его изменения.
Проверка текущего статуса
Сначала давайте проверим наш текущий статус, чтобы убедиться, что мы находимся в основной ветке с коммитом, выбранным с помощью cherry-pick:
git log --oneline -n 3
Вы должны увидеть вывод, аналогичный следующему:
98765ab (HEAD -> main) Add new feature function
abcd123 Add main application file
efgh456 Initial commit with README
Отмена Cherry-pick с помощью Git Reset
Чтобы отменить операцию cherry-pick, мы будем использовать git reset с опцией --hard, чтобы переместить указатель ветки на один коммит назад:
git reset --hard HEAD~1
Эта команда указывает Git сбросить ветку к коммиту, предшествующему текущему HEAD (часть ~1 означает "один коммит назад").
Вы должны увидеть вывод, аналогичный следующему:
HEAD is now at abcd123 Add main application file
Проверка сброса
Давайте проверим, что cherry-pick был отменен:
git log --oneline
Вы должны увидеть, что коммит, выбранный с помощью cherry-pick, больше не находится в истории:
abcd123 (HEAD -> main) Add main application file
efgh456 Initial commit with README
Давайте также проверим, был ли удален файл feature.js:
ls -la
Вывод не должен включать feature.js:
total 12
drwxr-xr-x 3 labex labex 4096 Jan 1 00:00 .
drwxr-xr-x 3 labex labex 4096 Jan 1 00:00 ..
drwxr-xr-x 8 labex labex 4096 Jan 1 00:00 .git
-rw-r--r-- 1 labex labex 29 Jan 1 00:00 app.js
-rw-r--r-- 1 labex labex 16 Jan 1 00:00 README.md
Поздравляем! Вы успешно отменили операцию cherry-pick с помощью git reset. Этот метод чистый и простой, но он перезаписывает историю, поэтому его следует использовать только для локальных изменений, которые не были отправлены в общий репозиторий.
Отмена Cherry-pick с помощью Git Revert
На предыдущем шаге мы использовали git reset для отмены cherry-pick. Однако git reset перезаписывает историю, что может быть проблематично, если вы уже отправили свои изменения в общий репозиторий. На этом шаге мы узнаем, как использовать git revert для безопасной отмены cherry-pick без перезаписи истории.
Понимание Git Revert
Команда git revert создает новый коммит, который отменяет изменения, внесенные предыдущим коммитом. В отличие от git reset, который удаляет коммиты из истории, git revert добавляет новый коммит, который противодействует изменениям, сохраняя историю коммитов.
Повторное выполнение Cherry-pick
Сначала давайте снова выполним cherry-pick коммита, чтобы у нас было что отменять:
## Get the commit hash from the feature branch
FEATURE_HASH=$(git log feature-branch --oneline | grep "new feature" | cut -d ' ' -f 1)
## Cherry-pick the commit
git cherry-pick $FEATURE_HASH
Вы должны увидеть вывод, аналогичный следующему:
[main 98765ab] Add new feature function
1 file changed, 1 insertion(+)
create mode 100644 feature.js
Проверка текущего статуса
Давайте убедимся, что cherry-pick был успешен:
git log --oneline -n 3
ls -la
Вы должны увидеть коммит, выбранный с помощью cherry-pick, в истории и файл feature.js в списке каталогов.
Отмена Cherry-pick
Теперь давайте используем git revert, чтобы отменить cherry-pick, сохраняя историю:
git revert HEAD --no-edit
Флаг --no-edit указывает Git использовать сообщение коммита по умолчанию, не открывая редактор.
Вы должны увидеть вывод, аналогичный следующему:
[main abc9876] Revert "Add new feature function"
1 file changed, 1 deletion(-)
delete mode 100644 feature.js
Проверка Revert
Давайте проверим историю коммитов:
git log --oneline -n 4
Вы должны увидеть как коммит, выбранный с помощью cherry-pick, так и коммит отмены:
abc9876 (HEAD -> main) Revert "Add new feature function"
98765ab Add new feature function
abcd123 Add main application file
efgh456 Initial commit with README
Теперь давайте проверим, был ли удален файл feature.js:
ls -la
Вывод не должен включать feature.js:
total 12
drwxr-xr-x 3 labex labex 4096 Jan 1 00:00 .
drwxr-xr-x 3 labex labex 4096 Jan 1 00:00 ..
drwxr-xr-x 8 labex labex 4096 Jan 1 00:00 .git
-rw-r--r-- 1 labex labex 29 Jan 1 00:00 app.js
-rw-r--r-- 1 labex labex 16 Jan 1 00:00 README.md
Хотя и git reset, и git revert достигают одного и того же конечного результата (удаление изменений, внесенных с помощью cherry-pick), они делают это разными способами:
git resetудаляет коммит из истории, что может вызвать проблемы, если коммит был передан другим пользователям.git revertдобавляет новый коммит, который отменяет изменения, сохраняя историю коммитов, что безопаснее для общих репозиториев.
Выбор между этими методами зависит от вашей конкретной ситуации:
- Используйте
git resetдля локальных изменений, которые не были переданы - Используйте
git revertдля изменений, которые были отправлены в общий репозиторий
Обработка конфликтов Cherry-pick
Иногда, когда вы выполняете cherry-pick коммита, Git может столкнуться с конфликтами, если изменения в коммите конфликтуют с изменениями в вашей текущей ветке. На этом шаге мы узнаем, как обрабатывать конфликты cherry-pick и как прервать операцию cherry-pick.
Создание сценария с потенциальными конфликтами
Сначала давайте создадим сценарий, который приведет к конфликту cherry-pick:
## Switch to main branch and modify README.md
git checkout main
echo -e "## Cherry Pick Lab\n\nThis is the main branch README." > README.md
git commit -am "Update README in main branch"
## Switch to feature branch and make a conflicting change to README.md
git checkout feature-branch
echo -e "## Cherry Pick Lab\n\nThis README has been updated in the feature branch." > README.md
git commit -am "Update README in feature branch"
Попытка Cherry-pick с конфликтами
Теперь давайте вернемся в основную ветку и попробуем выполнить cherry-pick коммита из ветки feature:
git checkout main
CONFLICT_HASH=$(git log feature-branch --oneline | grep "Update README in feature" | cut -d ' ' -f 1)
git cherry-pick $CONFLICT_HASH
Поскольку обе ветки изменили одни и те же строки в README.md, вы должны увидеть конфликт:
error: could not apply a1b2c3d... Update README in feature branch
hint: after resolving the conflicts, mark the corrected paths
hint: with 'git add <paths>' or 'git rm <paths>'
hint: and commit the result with 'git commit'
Просмотр конфликта
Давайте рассмотрим конфликт:
git status
Вы должны увидеть вывод, указывающий на конфликт в README.md:
On branch main
You are currently cherry-picking commit a1b2c3d.
(fix conflicts and run "git cherry-pick --continue")
(use "git cherry-pick --abort" to cancel the cherry-pick operation)
Unmerged paths:
(use "git add <file>..." to mark resolution)
both modified: README.md
no changes added to commit (use "git add" and/or "git commit -a")
Давайте посмотрим на содержимое конфликтного файла:
cat README.md
Вы должны увидеть что-то вроде:
## Cherry Pick Lab
<<<<<<< HEAD
This is the main branch README.
=======
This README has been updated in the feature branch.
>>>>>>> a1b2c3d... Update README in feature branch
Разрешение конфликта
Чтобы разрешить конфликт, нам нужно отредактировать файл и решить, какие изменения сохранить. Давайте изменим README.md, чтобы включить оба изменения:
echo -e "## Cherry Pick Lab\n\nThis is the main branch README.\n\nThis README has also been updated with content from the feature branch." > README.md
Теперь давайте отметим конфликт как разрешенный и продолжим cherry-pick:
git add README.md
git cherry-pick --continue
Git откроет редактор с сообщением коммита по умолчанию. Сохраните и закройте редактор, чтобы завершить cherry-pick.
Прерывание Cherry-pick
Иногда вы можете решить, что не хотите разрешать конфликты и предпочитаете отменить операцию cherry-pick. Давайте создадим еще один конфликт, а затем прервем cherry-pick:
## Create another conflicting commit in feature branch
git checkout feature-branch
echo "// This will conflict with app.js in main" > app.js
git commit -am "Modify app.js in feature branch"
## Try to cherry-pick this commit to main
git checkout main
ANOTHER_CONFLICT=$(git log feature-branch --oneline | grep "Modify app.js" | cut -d ' ' -f 1)
git cherry-pick $ANOTHER_CONFLICT
Вы должны увидеть еще один конфликт. На этот раз давайте прервем cherry-pick:
git cherry-pick --abort
Вы должны увидеть, что операция cherry-pick была отменена, и ваш рабочий каталог был восстановлен в предыдущее состояние:
git status
Output:
On branch main
nothing to commit, working tree clean
Обработка конфликтов во время операций cherry-pick является важным навыком для пользователей Git. У вас есть три варианта, когда вы сталкиваетесь с конфликтом:
- Разрешить конфликт вручную, затем использовать
git addиgit cherry-pick --continue - Пропустить конфликтующий коммит с помощью
git cherry-pick --skip - Прервать всю операцию
cherry-pickс помощьюgit cherry-pick --abort
Лучший подход зависит от конкретной ситуации и требований вашего проекта.
Резюме
В этой лабораторной работе вы получили практический опыт работы с функцией cherry-pick Git и изучили несколько способов отмены операций cherry-pick:
- Вы создали тестовый репозиторий с несколькими ветками и коммитами для практики.
- Вы выполнили операцию
cherry-pick, чтобы применить определенный коммит из одной ветки в другую. - Вы узнали, как отменить
cherry-pickс помощьюgit reset, что подходит для локальных изменений. - Вы изучили, как безопасно отменить
cherry-pickс помощьюgit revert, который сохраняет историю. - Вы попрактиковались в обработке конфликтов
cherry-pickи узнали, как прервать операциюcherry-pick.
Эти навыки бесценны при работе с Git в реальных проектах. Cherry-picking позволяет вам выборочно применять изменения между ветками, а знание того, как отменить cherry-picks, помогает вам восстанавливаться после ошибок и поддерживать чистую историю Git.
Помните, что разные методы отмены служат разным целям:
- Используйте
git resetдля локальных изменений, которые не были переданы. - Используйте
git revertдля изменений, которые были отправлены в общий репозиторий. - Используйте
git cherry-pick --abortдля отмены выполняющейся операцииcherry-pick.
Понимая эти варианты, вы можете выбрать наиболее подходящий метод для вашей конкретной ситуации.



