Git на практике. Учимся поддерживать репозиторий в порядке

Підписуйтеся на Telegram-канал «DOU #tech», щоб не пропустити нові технічні статті.

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

Для начала хотелось бы описать мое видение «правильного» репозитория. Основным отличием такого репозитория является чистая история коммитов. Каждый из этих коммитов должен быть осмысленной атомарной единицей изменений в проекте. Это значит, что наша история не должна содержать коммиты с сообщениями по типу «feature in progress». Ваша задача как разработчика научиться делить все вносимые изменения на такие атомарные единицы. Описанный ниже материал поможет вам этого добиться.

Stash

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

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

Допустим, мы внесли какие-то изменения:

git status

On branch feature
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
	modified:   file

no changes added to commit (use "git add" and/or "git commit -a")

Сохраним наши изменения в stash:

git stash

Saved working directory and index state WIP on feature: cdb8f82 Merge pull request #2 from germankhivrenko/feature

Также мы можем просмотреть список таких сохраненных изменений:

git stash list

stash@{0}: WIP on feature: cdb8f82 Merge pull request #2 from germankhivrenko/feature

Чтобы вернуть изменения из stash:

git stash apply

On branch feature
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
	modified:   file

no changes added to commit (use "git add" and/or "git commit -a")

По умолчанию применяются последние изменения из списка, и чтобы выбрать конкретные мы можем указать индекс:

git stash apply --index 0

Теперь мы знаем как переключать контекст задач и не загрязнять репозиторий.

Cherry-pick

Переходим к cherry-pick. Эта команда позволяет вставить выбранный вами коммит (и конечно же его изменения) в текущую ветку. Это полезно, когда мы хотим перенести конкретные изменения из другой ветки, но не хотим сливать ее полностью.

Представим, что у нас есть две ветки main и release с такой историей.

В main:

commit 818136b3eec70b04ca27b5de55abb1dc5de36cb9 (HEAD -> main)
    bad changes

commit ffd31c519d29eae6f9573f42562708ae8034a0f4
    cherry-pick me

commit 7128c5d11ef768dc21b1171752502231fb274b21
    Initial commit

В release:

commit 7128c5d11ef768dc21b1171752502231fb274b21 (HEAD -> release)
    Initial commit

Мы хотим получить изменения коммита с сообщением «cherry-pick me», но не хотим иметь изменения commit-а с сообщением «bad changes» в ветке release. Для этого мы должны сделать cherry-pick нужного коммита:

git cherry-pick ffd31c519d29eae6f9573f42562708ae8034a0f4

Для выбора коммита мы используем его hash. Теперь все готово, и мы можем увидеть нужные изменения в release:

commit e6a95034d392d295741a14ab0eaf084258116f5d (HEAD -> release)
    cherry-pick me

commit 7128c5d11ef768dc21b1171752502231fb274b21
    Initial commit

Примечание: во время выполнения cherry-pick могут возникнуть конфликты, после их решения Вы можете завершить cherry-pick c помощью команды git cherry-pick --continue.

Сама суть этой команды заставляет задуматься над атомарностью коммита. Правильная история коммитов очень сильно помогает при использовании команды cherry-pick.

Rebase

В сети достаточно информации со сравнением merge и rebase (как мне кажется, один из самых распространенных вопросов по поводу Git), так что я не стану их сравнивать, а просто расскажу, как я использую rebase в повседневной рабочей жизни.

Для ясности кратко рассмотрим цикл разработки какого-то функционала с точки зрения Git. Разработчик берет за основу общую ветку (обычно она называется dev), создает новую ветку и вносит в нее свои изменения, потом создает merge/pull request, чтобы залить свои изменения в общую ветку.

Я советую делать rebase перед созданием merge/pull request-а своей ветки в общую. Все это делается для того, чтобы решить потенциально возможные конфликты, а также поддерживать чистоту истории в репозитории. Чистая и понятная история сильно облегчает потенциально возможные манипуляции над репозиторием в будущем.

Итак, зачем вообще что-то делать перед созданием merge/pull request-а? Главной целью для слияния своей ветки с общей перед созданием это решение возможных конфликтов. Держу пари, каждый разработчик когда-то видел сообщение по типу «There merge conflicts» или «Cannot merge automatically». Следовательно, перед нами стоит выбор: merge и rebase. Конечно, rebase не всегда уместен, но в данной ситуации стоит выбирать именно его. Для наглядности посмотрим на разницу между merge и rebase в следующем примере.

Допустим, нам нужно реализовать какой-то новый функционал. Для начала мы переключаемся на общую ветку (в нашем примере main) и делаем pull, чтобы подтянуть последние обновления:

git checkout main
git pull origin main

Создаем ветку feature из main для локальной разработки:

git checkout -b feature

Представим, что мы реализовали новый функционал и сделали новый коммит:

git add .git commit -m “implemented feature”

Поскольку над нашим репозиторием трудится множество людей разработчиков, пока мы реализовывали наш функционал, в общей ветке появились изменения, которые конфликтуют с нашими. Поэтому мы должны предотвратить возможные конфликты:

git pull --rebase origin main

Потом мы должны решить те самые конфликты (если они присутствуют) и затем продолжить:

git rebase --continue

Примечание: rebase перезаписывает Ваш созданный коммит, hash-ы старого и нового коммитов отличаются.

После чего мы можем отправлять наши изменения на сервер:

git push origin feature

И теперь можно спокойно создавать наш merge/pull request и не переживать по поводу конфликтов.

Теперь давайте посмотрим на историю коммитов нашей общей ветки после слияния нашего request-а (для этого переключитесь на main и сделайте pull):

git log --pretty=short

commit eb560c0af5cfb63073592650bcb3e9050342b6bb (HEAD -> main, origin/main, origin/HEAD)
Merge: 795882a 9f5011e
    Merge pull request #1 from germankhivrenko/feature

commit 9f5011eeed9d6ffd5f693e7136599bc13f93a768 (origin/feature, feature)
    implemented feature

commit 795882a02fc51fea1b2f46df8a87c2bec3d6dc86
    added some changes

Коммит с сообщением «added some changes» — это те самые изменения, которые были добавлены другим разработчиком во время нашей работы над feature. Итого, мы с нашей стороны имеем два коммита. Один из них несет смысловую нагрузку (разработанный нами функционал), а другой — это merge-коммит двух других коммитов (мы можем это увидеть из его описания: Merge: 795882a 9f5011e), его за нас создала система.

Теперь давайте взглянем на историю коммитов, в случае если бы мы использовали git pull origin main вместо git pull --rebase origin main, то есть использовали merge вместо rebase. Прежде всего, после решения конфликтов, нам бы пришлось создать новый коммит:

git add .
git commit -m “resolved merge conflicts”

Взглянем на историю коммитов main ветки:

commit cdb8f82bd78dfbcb9381147ad30a5f44f7c8072e (HEAD -> main, origin/main, origin/HEAD)
Merge: 795882a eb36d47
    Merge pull request #2 from germankhivrenko/feature

commit eb36d479e83f899b5dcb7b25fc881c7fa5ff6f16 (origin/feature-1, feature-1)
Merge: 69beef2 795882a
    resolved merge conflicts

commit 69beef25fb0ad295fda1471c9c46f8e9d777b821
    implemented feature

commit 795882a02fc51fea1b2f46df8a87c2bec3d6dc86
    added some changes

Вместо 3 коммитов получаем 4, где коммит с сообщением «resolved merge conflicts» не несет никакой смысловой нагрузки.

Если вам нужно синхронизировать вашу ветку и общую по ходу разработки, использование merge может существенно загрязнять историю, особенно если такая синхронизация проходит часто.

Reset & revert

Далее уделим немного внимания удалению и исправлению уже существующих в репозитории изменений и коммитов. Рассмотрим команды reset и revert.

Допустим, мы хотим добавить изменения к предыдущему коммиту. Для этого нам нужна команда reset с параметром —soft или —mixed (mixed используется по умолчанию, если указывать параметры). Вводим:

git reset --soft HEAD~1

Запись HEAD~1 означает, что мы хотим перейти на один коммит назад от текущего положения HEAD. Чтобы посмотреть, что же произошло, можно использовать git log и git status. В списке коммитов больше не будет коммита, который мы удалили, а изменения этого коммита остались в рабочей директории в статусе staged. Далее можно дополнить/исправить эти изменения и сделать новый коммит.

Если мы хотим просто удалить коммит и его изменения следует применять reset с параметром —hard, он удалит коммит их изменения не останутся в нашей рабочей директории.

Также для изменения последнего коммита в Git существует параметр —amend для команды commit, но мне почему то больше нравится пользоваться reset.

Стоит отметить, что описанные выше подходы именно изменяют историю коммитов в репозитории, что не всегда является безопасным. В общих ветках, которые обычно названы как master, dev или main не принято вносить изменения в историю коммитов, так как это может иметь негативные последствия. Также, если попробовать изменить коммит который уже есть на сервере, например, с помощью git reset и попробовать отправить текущую ветку на сервер, то мы получим подобное сообщение:

git push origin main

To github.com:germankhivrenko/git-in-practice.git
 ! [rejected]        main -> main (non-fast-forward)
error: failed to push some refs to 'git@github.com:germankhivrenko/git-in-practice.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.

Git советует нам сначала сделать pull, потом решить конфликты, создать новый коммит и уже потом попробовать отправить наши изменения еще раз. Все это делается для того, чтобы не допустить изменения истории коммитов на сервере. Конечно, это можно обойти с помощью параметра -f (—force) для команды push:

git push -f origin main

И если изменять историю на сервере в своих ветках, созданных для разработки конкретного функционала, до слияния их в общую вполне приемлемо, то изменять историю таких веток как master крайне не рекомендуется. Тут на помощь к нам приходит revert. Эта команда может удалить изменения выбранного коммита посредством создания нового коммита. Таким образом можно удалять изменения, но не изменять историю коммитов.

Примечание: revert может вызывать merge конфликты, после их решения нужно продолжить revert с помощью git revert --continue.

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

👍НравитсяПонравилось24
В избранноеВ избранном21
LinkedIn

Лучшие комментарии пропустить

Я таки предпочитаю для временного переключения на задачу с другой ветки сделать незаконченный коммит с комментом DRAFT, вместо stash. Если работа будет продолжена, то докомитить с amend куда удобнее, чем вспоминать что ты где то там что то прятал. В принципе не мудрено даже хук запилить чтобы не давал коммитить без amend, если последний был с комментом DRAFT, хотя и пофиксить не запушенное то не беда.

Допустимые теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter
Допустимые теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter
Такая опция хороша, когда мы хотим переключиться на другую ветку, например, чтобы срочно пофиксить баг, но текущие изменения не готовы, чтобы сделать коммит.

git worktree

Мне кажется, что stash больше используется чтобы перенести изменения в другую ветку, всё таки при переключении проще git commit -a -m tmp и потом при возврате что-нить вроде git reset HEAD^

Из того, что я делаю часто ещё, это git add -i some_file, что позволяет добавить в индекс только часть правок, например отладочные принты. Или добавить небольшой фикс, например, к прошлому коммиту (git commit —amend —no-edit) или к любому другому коммиту в истории (git commit -m fix-00face, git rebase -i 00face^, после чего надо просто перенести его после нужного и поменять pick на fixup)

Далее, для быстрой синхронизации между машинами в сети я часто юзаю что-то вроде git remote add laptop ssh://user@server/path/to/repository

Вот ещё интересный скрипт, который позволяет докоммитить в бранч разницу до другой бранчи:

git checkout b2       # We are starting from branch b2
git checkout -b tmp   # We creating a temporary branch for safety reason
git reset b1          # Now tmp is pointer to b1, but current file are from b1 (maybe --soft for indexing?)
git add ...           # Add changes
git commit            # And commit them!
git diff HEAD b2      # Check that we did not do any changes
git checkout b1 && git reset --hard tmp && git branch -d tmp

Плюс за rebase в фича ветках, минус — за stash. Сам двумя руками за squash. Предпочитаю избегать «наслаждения» десятками бессмысленных коммитов «изменил одну букву», «изменил её обратно» и т.д. (при чём, с мерджами и обычными коммитами вразброс для полного счастья, чтобы история выглядела максимально похожей на кусок понятно какой субстанции).

--force-with-lease безопаснее

чому checkout для світчингу між бранчами? вже мабуть рік як для цього є АПІ switch
усім хто писав про проблеми с git stash — у вас або декомпозиція задач хромає або workflow поганий, це ж класична проблема редагування одного файлу багатьма, навіть довелось гуглити git stash problem :)

„git switch” и „git restore” — это просто подмножества от „git checkout”.

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

а мы просто запретили делать рибейз в master и stage ветки

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

и жизнь наладилась.

Ну, я про свои фича бранчи и говорю: если приходит конфликт, разбитый на 7 коммитов, то при рибейзе в свою фича бранчу этот конфликт придется решать 7 раз, и при этом не видно общей картины конфликта. Это ад )
А в мастер понятное дело никто руками не лезет локально, только после аппрува фича бранчи на сервере выполняется мердж в мастер (а оттуда уже все вытягивают на свои локальные машины).

при рибейзе в свою фича бранчу этот конфликт придется решать 7 раз

git-scm.com/docs/git-rerere не помогает?

За переписування публічної історії (rebase, squash, etc) давно пора відбирати клавіатури і видавати віники.

таким обычно занимаются
— зеленые июни, по незнанию
— лиды и архитекты, т.к. имеют «god mod»

публічної історії

1. локальной истории (очепятки и проч)
2. геррит, эниван?

Приватні гілки на те й приватні, щоб там хоч на голові можна було ходити :)

Про Герріт я не поняв. Знаю що це, але не працював.

с герритом только через ребейз можно работать

одно дело, как заапрувленый код попадает в основную ветку, а другое — как ты обновляешь свой коммит

Що там недостатньо додати черговий коміт в feature-гілку/MR/PR/чи_як_воно_там_зветься щоб він просто з’явився у рецензента?

насколько мне известно — нет. коммит-ребейз+скваш-пуш

По-моему в геррите как и в любой другой code-review можно настроить обычные коммиты в ветку и пулл реквест на мерж в master/release/other
Все зависит от того, как вы свой воркфлоу настроите.

хз. я такого не встречал. да и нету в геррите пулл-реквестов, он сам по себе пулл-реквест тэкскээть

В коментарях жалілись на stash та конфлікти — в таких випадках
git stash branch має допомогти

Як зробити, щоб Idea бачила перейменовані / переміщені файли не як видалені / створені?

Я таки предпочитаю для временного переключения на задачу с другой ветки сделать незаконченный коммит с комментом DRAFT, вместо stash. Если работа будет продолжена, то докомитить с amend куда удобнее, чем вспоминать что ты где то там что то прятал. В принципе не мудрено даже хук запилить чтобы не давал коммитить без amend, если последний был с комментом DRAFT, хотя и пофиксить не запушенное то не беда.

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

Тоже к этому пришли. И даже в репо разрешено пушить.

И даже в репо разрешено пушить.

Що мається на увазі?

ну пушить незаконченные коммиты в общак на ремоут, а не только хранить в локальном репо.

Якщо мається на увазі свій форк репи на сервері, то в чому снес взалагі якось обмежувати роботу із нею? В github/gitlab проблем з форками немає. А якщо в майстер-репу заливати без МР та код-ревью — це щось новеньке, навіть якщо якийсь девелопмент-бранч.
От едине, де додаткові умови пушу можна обговорювати — про роботі із геррітом, але й там можна просто заливати приватні патч-сети, які нікому не видимі, поки не готові.

Якщо мається на увазі свій форк репи на сервері,

мова про коміт незакінченого коду

А якщо в майстер-репу заливати без МР та код-ревью

ніхто draft коміти у загальні бранчі master, stage, hotfix, bugfix не заливає.

тобто ви робите припущення для якихось супер ідіотів :)

які нікому не видимі, поки не готові.

тому й дозволено заливати драфти у дев бранчі, що буває корисно подивитися заздалегіть, як там виходить.
а коли взагалі треба обговорити проблемку на «80%» реалізованого, то взагалі самий простий спосіб — подивитися той драфт у себе в IDE

тобто ви робите припущення для якихось супер ідіотів :)

Я роблю припущення виходячи із наявної інофрмації :) Було б більше інформації, були б інші припущення.

тому й дозволено заливати драфти

Так драфти для gerrit-а — це стандартний механізм зберігання-обміну кодом, не передаючи його в CI. Ось мене й збило з толку, чому

И ДАЖЕ в репо разрешено пушить

? В чому підступ? :)

Я роблю припущення виходячи із наявної інофрмації :)

яка була неповною.
а далі — ваш особистий вибір, чим доповнювати.

? В чому підступ? :)

бо є така «бестпрактика» що у репо не повинно бути непрацюючого коду

за такє правовірні можуть побити камінням.

або, у нас в пих світі — сінкати файли прямісінько на прод. за такє теж — аутодафе
а ми інколи так робимо. буває :)

+++
или, как вариант, просто сделать ещё один коммит потом и засквошить их (работаю через TortoiseGit и там это очень легко и быстро)

Теж таким часто користуюся. Правда, я потім не amend роблю, а reset —soft HEAD~1.

Користуюсь все життя вбудованими гуі клієнтами в jetbrains ide, майже ніколи не треба писати руками команди в консолі. Я щось втрачаю?

Не думаю, что ГУИ это плохо. Главное понимать какие есть инструменты и когда (и как) ими пользоваться.

Если вам так удобнее, и вы понимаете «как оно там работает», и в состоянии починить, когда «ой все сломалось», то — нет, не теряете.

Починить репозиторий гита очень просто — «rm -rf .git» + клон заново.

В некотором классе гитовых проблем это решение будет ещё и самым оптимальным.

А яка різниця? Принципи гіту треба і в гуі розуміти. Плюс консолею буває точніше.

Так. Швидкість, можливість автоматизації команд. Ну і через ssh підключення гуі не працює.

Хз може intellij вміє, по ссш стукатись так точно

Якщо ти користуєшся лише push, pull та commit та тобі цього вистачає, то може й не треба. Переваги командного рядку:
1. Пошук відповідей. Коли ти не знаєш як зробити шось, то зазвичай шукаєш у мануалі або Google. Команди набагато точніші, замість скріншотів з позначенням куди клікати. Також комʼюніті значно більше.
2. Автоматизація. Часті послідовності дій можна поєднати у скрипти (bash, python). Це простіше ніж Selenity та інші засоби GUI.
3. Пошук в історії. Коли ти щось робив два тижні тому, але забув в деталях що саме, то можна подивитися history та відтворити. Якщо брати GUI, то... як? Записати відео можна, але як шукати? Це моя велика головна біль з GUI, я памʼятаю, що я це робив, але забув де воно було.

Кожен раз коли у вас виникає ідея «о, а тут я можу зробити git stash» зупиніться, видихніть і зробіть копію репо в якій і працюйте над іншою гілкою. Це дозволить уникнути необхідності розбиратися у конфліктах які не дають витягти файли зі стеша.

Що стосується rebase — відео «Гітле про git» розкриває цю тему.

Кожен раз коли у вас виникає ідея «о, а тут я можу зробити git stash» зупиніться, видихніть і зробіть копію репо в якій і працюйте над іншою гілкою. Це дозволить уникнути необхідності розбиратися у конфліктах які не дають витягти файли зі стеша.

Так та ні, коли треба зберегти контекст та свічнутися в іншу гілку (для перевірки чогось, наприклад), то сташ — логічніший, якщо лише код не готовий до проміжного комміта

Так, спочатку свіжевипущені програмісти гигикають з того як у тих хто в індустрії вже дуже давно ціла купа гілок одного репо в різних директоріях. А потім коли їм тривіально треба файли з різних гілок порівняти, чи сташ не мержиться, а ребейс робить лише все гірше вони сидять і сумно переписують усе вручну заново. Потім проходить рік-два, вони перестають вірити рекламі і теж вже мають кілька копій одного репо в яких можуть працювати одночасно та незалежно.

Не дай моєму доу тайтлу ввести себе в оману. Не «свіжевипущений». І не гигакую. Я навів життєвий приклад коли до стешу покласти зміни може бути краще. Декілька копій окремого репо — то інший випадок

Я не про тебе говорив. А про те що в цілому менш досвідчені деви сильно вірять в магію технологій які усе порішають варто лише на них перейти і «робити все правильно».

Але стаття як на мене більше не про «магію» а просто про можливості технологій якими багато хто і так користується

Так, можливо я побачив у написаному того, що туди не закладалося. І стеш дійсно зручний коли треба швиденько перейти на інший бренч і потім невдовзі повернутися назад.
Але вже ребейс вимагає розуміння того, що саме відбувається. Мені доводилося бачити команди в яких ребейс було заборонено використовувати після того як команда кілька днів провела переписуючи та відновлюючи вручну результати «ща ми швиденько тут ребейсом все порішаємо».

Ну щодо ребейзу там є теж приклад, використовувати лише в локальні (особисті) гілки. Щоб не руйнувати іншим флоу. Наприклад можна перед ПР привести до тями локальну гілку. Або як в статті — розрулити конфлікти з публічною гілкою локально та зробити гарну історію коммітів, яку можна потім використовувати як квазі-документацію
Ребейз публічної гілки — то табу (або тре домовитися і стопнути девелоп. приклад: треба зробити у деві/стейджі всі комміти «зеленими» за якихось причин)

Такі люди просто не вміють користуватися гітом

Копирование целого репозиория может тянуть за собой неудобства посерьезнее чем конфликты, например, настройки окружения. Все зависит от проекта, но каждый раз так делать может быстро надоесть. Плюс git stash используется не только для того чтобы переключится на работу в другой ветке. Пример из жизни: локально я разрабатываю в одной ветке (с докер сетапом), а на стейдже используется другая ветка со старым сетапом (без докера), то есть я должен разрабатывать и тестить в первой ветке, но коммитить в другую) Тут мне обычно помагает git stash. Я и считаю, что это далеко не последний случай, где Вам может помочь git stash. Так что, не думаю, что стоит быть таким категоричным. И спасибо, что прочли)

Кстати, тоже не понимаю, откуда такой хейт по отношению к stash... для сценариев вида «переключиться временно на другую ветку» в моём лично опыте stash был крайне полезным инструментом.

Ага, я теж любитель тимчасово переключаюсь на нову гілку. Тепер у мене сім сотень сташнутих змін (за 1.5 роки).

Якщо ви робите копії свого репозиторія, навіщо вам гіт?

гіт для того ж, для чого й усім іншим. Копії — щоб були одночасно кілька копій доступні.

git — г-но, переписывание истории — зло. Пользуйтесь mercurial, обретите счастье!

Ты устал, отдохни :) Добро это пластик. Но это не точно. А если серьезно — гит неплох для многих задач. Но да в нем есть куча проблем, если, к примеру, менеджить бинарники. Переписывание истории же при общем согласии тимы может помочь исправить случайные косяки с историей, которые не перекрыли раньше ci/cd
Хммм... Я как-то комментирую воздух. Что за баг?

Меркуриал хорош, но есть фатальные недостатки
— переименование делается через delete/add, что сильно раздувает размер репозитория
— когда размер репо приближается к гигабайту, начиает сильно тормозить. Простое клонирование репозитория — приключение на целый день
+ им мало кто умеет поьзоваться, например создают «branch» вместо «bookmark» (аналог «branch» из git)

dev.to/...​ville/on-git-history-12c2
Если есть желание совместно писать статьи — можешь скооперироваться вот с этим автором. Он мой давний знакомый, можете делать 2 версии (английский для dev.to и украинский для dou). У него в разработке есть еще несколько статей по проблеме, насколько я знаю. Если неудобно напрямую — могу «подружить» вас в телеграмме.

Спасибо за предложение, но по данной теме пока ничего пистать не хочется)

Автор явно не потрапляв в ситуацію коли стеш не спрацьовує бо стешились з іншого коміта) При цьому нормально розрулити як конфлікт при мержі не виходить бо стеш просто не аплається.. Я двічі бачив таку ситуацію і обидва рази це був повний фейл і повторне написання/перенос коду

Я доречі дуже часто використовую стеш і теж не потрапляв до такої ситуації. Завжди є конфлікт і є «ми зберегли стеш про всяк випадок бо не аплаївся».
Тобто можно розрулити конфлікт в теорії а потім дропнути стеш. Ну то можливо тому що я тримаю там лише «свіжі» спроби і роблю локальні гілки/комміти коли воно ± працює як я хотів

А почему не получаеться решить конфликты? Я частенько комичю стешы с других коммитов — просто решаю конфликты.

Ну там виходить щось типу кеннот апплай стеш і все, ваш код живе в цьому стеші вічно) тобто до того щоб розрулювати конфлікти і не доходить

Як я вже писав вище — стеш аплаіться (не зустрічав випадків коли ні, але то може специфіка використання стешу, от чесно не дуже хочу лізти дивитися сорси Лінуса). Тобто зміни є, але конфлікти треба вирішувати. А стеш потім дропнути.

стеш не спрацьовує бо стешились з іншого коміта

Там сохраняется, из какого комита делался стеш. Если стеш не зааплаился, то
— можно мержить руками, как при мерж-конфликтах
— можно откатиться на старый комит, создать новый бранч, зааплаить стеш, и опять мержить руками (или попросить кого-то умного, чтобы смержил)

жаль мат, даже в цензурной версии выглядит не к месту.

глаз режет

в украинском языке мат режет слух, в русском звучит довольно органично

в украинском языке мат режет слух

Треба просто «сука» замінити на «курва».

Так это уже другой язык:

O kurwa, coś poszło bardzo nie tak, powiedz że Git ma jakiś magiczny wehikuł czasu!?!
O kurwa, zrobiłem(am) commit i zaraz potem zauważyłem(am), że muszę dodać jedną małą zmianę!
O kurwa, muszę zmienić opis mojego ostatniego commitu!

O kurwa, nie tylko polacy korzystaja z tego slowa

На логотипе git изображено единственное действие, понятное в этой системе.

Спасибо за статью.

Подскажите, как в потоке разработки правильно подходить к обновлению ключевых веток (dev, stage, master):
1. последовательный перенос «функционала» (с тестированием в каждой среде):
feature —> dev —> stage —> master

2. или перенос «функционала» независимо отдельно на каждую ветку:
feature —> dev
feature —> stage
feature —> master

Как в этом случае избежать генерации системных коммитов об merge?

Конкретно у нас в репе нет ключевых веток, только master, а далее деплоится на dev, staging и в конце на прод. Хотфиксы по тому же маршруту идут.

В нормальном мире — никак. Но чисто теоретически можно ребазировать ветки локально (например dev на stage) и смержить stage с dev, и после это напрямую пушить stage на сервер.

Такие merge коммиты бывают полезны если что-то не туда замержили, то проще ревертить один коммит

Подскажите, как в потоке разработки правильно подходить к обновлению ключевых веток (dev, stage, master):

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

Из «знаменитых» есть
— git flow nvie.com/...​sful-git-branching-model
— git lab flow docs.gitlab.com/...​e/topics/gitlab_flow.html
— github flow guides.github.com/introduction/flow

Подписаться на комментарии