Git Как откатить ошибку слияния

внешний интерфейс Git
Git Как откатить ошибку слияния

Оригинальный текст был опубликован в колонке Zhihu.Фронтальный продуктовый магазин, Добро пожаловать в мою колонку, просьба указывать источник для перепечатки

Сегодня не будем о фронтенде, поговорим о git. Выяснено, что сегодняшние дети играют в набор фреймворков, и они не смогут дождаться, пока они поиграют с какими-то предметными инженерными штучками. Git — такой хороший инструмент, как учебный класс может игнорировать его важность?

Поговорим о рабочем процессе git

Много людейЧто за система Git?, до сих пор в неведении. Настоятельно рекомендуется сначала понять основные идеи и принципы работы git.subversionилиperforceТем, кто использует опыт, нужно отказаться от того, что они видели и узнали раньше, и заново принять такую ​​новую идею. Мы не будем здесь повторять его принципы, давайте представим его простой рабочий процесс. Git управляет тремя разными ящиками со своей собственной ментальной структурой.Commit History,INDEX,Working Directory.

  • Commit HistoryИстория, хранит все версии снимков, представленных посредством ссылки на текущую указатель заголовка ветви, указывая на представление новой ветви.
  • INDEXИндекс, также называемый промежуточной областью. Это файл, содержащий снимок списка файлов, которые должны быть зафиксированы.
  • Working DirectoryРабочий каталог — это список файлов, распакованных из текущей версии сжатых данных в репозитории git. Таким образом, список файлов исходного кода вашего проекта, который вы видите на локальном диске, на самом деле является песочницей, открытой для вас git. Вы можете вносить любые изменения до тех пор, пока не перенесете изменения файла в промежуточную область и не запишете моментальный снимок в историю.

Поняв значение этих трех, давайте попробуем понять рабочий процесс git. Начало всего, между хаосом, мы должны сделать большое дело и несколько раз нажать на клавиатуру в терминале

git init 

Сначала открылся Хаос, превратившись в три царства:HEAD,INDEX,Working Directory. Это то, что мир выглядел как в начале. Гитический репозиторий, кажется, Бог, отвечающий за три сфера. а такжеWorking DirectoryЭто место, которое Он назначил вам для производства и работы, где вы можете свободно творить. Для безопасности и упорядоченного управления нам необходимо передать наши добавленные и измененные файлы в репозиторий git. Git сначала пометит измененные файлы и поместит их в промежуточную область, а затем git найдет содержимое файлов в промежуточной области и навсегда сохранит их в виде снимков в репозиторий git.HEADуказатель на этот последний снимок.

Как показано на рисунке, суммируйте следующие три шага.

  1. Измените файл в рабочем каталоге.
  2. Постановка файла помещает моментальный снимок файла в область подготовки.git add
  3. Зафиксируйте обновление, найдите файлы в промежуточной области и навсегда сохраните моментальный снимок в каталоге репозитория Git.git commit

Основной рабочий процесс git заключается в непрерывном повторении этих трех шагов, и, наконец, каталог репозитория git формирует стек моментальных снимков Каждый раз, когда создается новая версия, HEAD будет указывать на эту версию.

Здесь мы создали следующие файлы:

├── README.md
├── v1.js
├── v2.js
└── v3.js

Формируется история коммитов следующей фигуры


3aa5dfb v3  (<- HEAD)
        |
5aab391 v2
        |
ff7b88e v1
        |
95d7816 init commit

Давайте посмотрим, как использовать checkout, reset, revert для работы с этим каталогом склада.

проверить, сбросить или вернуться?

checkout

Идея систем контроля версий заключается в «безопасном» хранении копий проектов, чтобы вам никогда не приходилось беспокоиться о том, что вы необратимо испортите свою кодовую базу. После того, как вы создали историю своего проекта, git checkout — это удобный способ «распаковать» сохраненные снимки в ваш рабочий каталог.git checkoutКоммиты могут быть извлечены, отдельные файлы могут быть извлечены, и даже ветки (здесь опущены) могут быть извлечены.

git checkout 5aab391

Проверьте v2, текущий рабочий каталог и5aab391Точно так же вы можете просмотреть эту версию файла редактирования, запуска и тестирования не будут сохранены в репозиторий git. Ты сможешьgit checkout masterилиgit checkout -вернуться в исходное рабочее состояние.

git checkout 5aab391 v1.js

Чтобы проверить изменения версии v2 в v1.js, извлекается только файл v1.js5aab391Версия. Таким образом, это повлияет на ваше текущее рабочее состояние, оно перезапишет содержимое файла v1.js в текущем состоянии как5aab391Версия.所以除非你清楚你在做什么,最好不要轻易的做这个操作。但这个操作对于舍弃我当前的所有改动很有用:比如当前我在v1.js上面做了一些改动,但我又不想要这些改动了,而我又不想一个个去还原,那么我可以git checkout HEAD v1.jsилиgit checkout -- v1.js

сброс сброс

а такжеgit checkoutТакой же,git resetЕсть много применений.

git reset <file>

Удалите определенные файлы из промежуточной области, не меняя рабочий каталог. Он раскэширует этот файл без перезаписи каких-либо изменений.

git reset

Сбросьте промежуточную область, чтобы она соответствовала самой последней фиксации, но оставьте рабочий каталог без изменений. Он удаляет все файлы без перезаписи каких-либо изменений, что дает вам возможность сбросить подготовленный моментальный снимок.

git reset --hard

плюс--hardПосле маркировки он скажет git сбросить изменения в кеше и рабочем каталоге, то есть: сначала очистите свою промежуточную область, а затем очистите все ваши неустановленные изменения, поэтому убедитесь, что вы хотите их выбросить, прежде чем использовать Отбросить все локальные задания.

git reset <commit>

Переместите указатель текущей ветки HEAD на , сбросьте буфер до этого коммита, но не меняйте рабочий каталог. Все последующие изменения остаются в рабочем каталоге, что позволяет повторно зафиксировать историю проекта с помощью более чистого атомарного снимка.

git reset --hard <commit>

Переместите указатель текущей ветки HEAD на , сбросьте и буфер, и рабочий каталог на этот коммит. Он не только очищает незафиксированные изменения, но также очищает все коммиты после .

Как можно заметить,git resetНекэширование или отмена серии коммитов отменит некоторые изменения в вашем текущем рабочем каталоге, такие операции имеют определенную степень опасности. Начнем с относительно безопасного способаrevert

вернуть отменить

git revertСнимки используются для вывода уже представленных. Но реализация совершенно отличается и сбрасывается. Выяснение того, как отменить представленные изменения, представленные, а затем вышли в последний раз с новым коммитным изменениям, а не удалять представление из истории проекта.

git revert <commit>

Создает новую фиксацию, которая отменяет изменения, внесенные , а затем применяет ее к текущей ветке.

Например:

81f734d commit after bug
        |
3a395af bug
        |
3aa5dfb v3  (<- HEAD)
        |
5aab391 v2
        |
ff7b88e v1
        |
95d7816 init commit

мы в3a395afввели ошибку, которую мы явно вызвали из-за3a395afКогда возникает ошибка, лучше исправить ошибку с помощью новой отправки.git revert , пусть он поможет вам устранить эту ошибку.

git revert 3a395af

получил ответ

cfb71fc Revert "bug"
        |
81f734d commit after bug
        |
3a395af bug
        |
3aa5dfb v3  (<- HEAD)
        |
5aab391 v2
        |
ff7b88e v1
        |
95d7816 init commit

В это время изменения бага были отозваны, и был сгенерирован новый коммит, ноcommit after bugне был Цинчу.

Так по сравнению сreset,revertЭто не изменяет историю проекта, это безопасная операция для коммитов, которые уже были опубликованы в общем репозитории. Второйgit revert Может отменить любую фиксацию в истории коммитов, иresetудалит коммит из истории и все последующие коммиты, что является варварством.

Кроме тогоrevertВ дизайне также есть соображение, которое заключается в том, чтобы отозвать представление публичного репозитория. А почему бы и нетreset, вы можете подумать сами. Давайте используем неприятность (откат неправильного слияния), чтобы объяснить эту операцию.

операция слияния

по сравнению с обычнымcommit, когда используешьgit merge <branch>При слиянии двух веток получается новаяmerge commit. когда мыgit show <commit>Появится похожее сообщение:

commit 6dd0e2b9398ca8cd12bfd1faa1531d86dc41021a
Merge: d24d3b4 11a7112
Author: 前端杂货铺 
...............

Merge: d24d3b4 11a7112В этой строке указан след версии родителя, в котором были объединены две ветви.

Например, в приведенном выше проекте мы открыли ветку dev и проделали некоторые операции, теперь ветка выглядит так:

init -> v1 -> v2 -> v3  (master)
           \      
            d1 -> d2  (dev)

Когда мы почти закончили разработку в dev

#git:(dev)
git checkout master 
#git:(master)
git merge dev

В это время был сформирован Merge Commit.faulty merge

init -> v1 -> v2 -> v3 -- faulty merge  (master)
           \            /
            d1  -->  d2  (dev)

В настоящее времяfaulty mergeЕсть два родителя, v3 и d2.

Откатить неудачное слияние

После этого слияния разработка продолжилась в dev, и другая волна людей сливала код из других веток для мастеринга. становится таким:

init -> v1 -> v2 -> v3 -- faulty merge -> v4 -> vc3 (master)
        \  \            /                     /
         \  d1  -->  d2  --> d3 --> d4  (dev)/
          \                                 / 
           c1  -->  c2 -------------------c3 (other)

В это время вы обнаружите, что слияние в прошлый раз, кажется, внесло ошибку в общий мастер ветки. Эта ошибка приводила к тому, что другие ученики в команде не сдавали тест, или это была онлайн-ошибка, и если ее вовремя не исправить, начальника ругали.

В это время первой мыслью должно быть откатить код, но как откатить. использоватьresetЭто не реально, потому что это слишком мошеннически, вы же возьмете чужой код, поэтому сможете только им пользоваться.revert. а такжеrevertИзначально он был разработан именно для этого.

Как это работает? Первое, что приходит на ум, это вышеgit revert <commit>, но, похоже, это не работает.

git revert faulty merge
error: Commit faulty merge is a merge but no -m option was given.
fatal: revert failed

Это связано с тем, что Git не знает, какую ветку оставить при попытке отменить слияние двух веток. Поэтому нам нужно сказать git, что мы сохраняем эту ветку.mилиmainline.

git revert -m 1 faulty merge

-mЗначение параметра сзади может быть 1 или 2, в соответствии с порядком родителя.Приведенный выше список: 1 означаетv3, 2 представляетd2Таким образом, эта операция сохранит изменения основной ветки и отменит изменения, объединенные с веткой dev.

история коммитов становится

init -> v1 -> v2 -> v3 -- faulty merge -> v4 -> vc3 -> rev3 (master)
          \            /                     
           d1  -->  d2  --> d3 --> d4  (dev)

здесьrev3представляет собой обычный коммит, содержимое которого содержитfaulty mergeКоллекция [обратных операций] коммитов, объединенных с dev, которые были отменены.

Это еще не конец, мы должны помнить, что из-за того, что мы отказались от коммитов, которые были слиты dev ранее, и в следующий раз, когда dev сливается с master, те, которые были заброшены ранее, в него не включаются. тогда что нам делать?

Восстановить предыдущий откат

Это очень просто, почему бы нам не отозвать коммит предыдущего мастера с помощью [анти-операции]?

git checkout master
git revert rev3
git merge dev

В этот момент история коммитов становится

init -> v1 -> v2 -> v3 -- faulty merge -> v4 -> vc3 -> rev3 -> rev3` -> final merge (master)
          \            /                                               /
           d1  -->  d2  --> d3 --> d4  --------------------------------(dev)

Суммировать

Выше приведены некоторые из операций, о которых я хочу поговорить с кодом отката git.Если что-то не так, пожалуйста, поправьте меня. Кроме того, Git — это искусство и очень тонкий дизайн.Когда вы используете его, вы находите все больше и больше интересных вещей и молча благодарите людей, которые разработали git. Я также надеюсь, что независимо от того, являетесь ли вы новичком или глубоким ныряльщиком в области фронтенда, в погоне за популярными фреймворками не забудьте изучить эти базовые инструменты.

Ссылаться на