Как стать автором
Обновить

Комментарии 44

Хоть и много букв, но осилил.
Огромное спасибо за статью!
Вы сущий молодец! Такую статью забабахать! С конфликтами разобрали все по кусочкам. Люто плюсую.
На самом деле git — это просто и понятно.
НЛО прилетело и опубликовало эту надпись здесь
… хотя все равно понятно только 10%
Как говорится в мануалах, «Пользуясь git, легко прострелить себе ногу, но зато потом легко восстановить предыдущую ногу, и слить её с бедром.»

(«It is easy to shoot your foot off with git, but also easy to revert to a previous foot and merge it with your current leg.»)
Было бы очень круто добавить в начало поста оглавление, чтобы перепрыгивать к нужному месту (#anchor)
Спасибо за пост!
Добавил в «избранное», внуки дочитают. А если серьезно, то разделяйте в след. раз на несколько частей ;)
Про rebase.
Конечно, такое никуда не годится!… Что же делать, чтобы история оставалась красивой и прямой?

Не раскрыта тема почему не годится, зачем иметь красивую историю, и каковы недостатки изменения истории. История России тоже на самая красивая, но это не повод её переписывать.
Собственно я потому и писал про опасности rebase (1 и 2), что во всех вводных статьях про Git пишут о преимуществах rebase как о чем-то само собой разумеющемся, а про недостатки — ни слова.
Если используешь rebase — надо знать обо всех минусах этого подхода и придерживаться строгих правил.

В остальном по всей видимости отличная статья!
Вот, что пишут про rebase в Git Pro:
"Не перемещайте коммиты, которые вы уже отправили в публичный репозиторий.
Если вы будете следовать этому указанию, всё будет хорошо. Если нет — люди возненавидят вас, вас будут презирать ваши друзья и семья."
Запушенные коммиты трогать нельзя (только в экстремальных случаях, например запушили конфиденциальные данные), это вроде как очевидно.
Но это другой вопрос, rebase имеет массу других недостатков. Грамотно сделать rebase — сложно и трудозатратно.
Да, так и есть. Этот тот самы git push origin branch --force.
Представьте, вы работаете над фичёй, пушите туда изменения, а кто-то «добрый» взял и принудительно переписал общую ветку своей историей, да ещё и старой. Ваша работа и работа других пропала. Точнее локально оно осталось, но теперь вам надо всё перестраивать. Я бы возненавидел такой сюрприз. Но если бы меня предупредили заранее, что ветка будет перестраиваться — я бы принял меры и, например, ничего пока не делал бы с ней.
сколько писали статью? Такой труд. ужас. Пока пролистал, как будет пару часов займусь чтением. Но выглядит монументально!
В течении двух недель по вечерам или когда время было.
Это, конечно, накладывает свой отпечаток — статья слегка сыроватая получилась, надо будет допилить до приличного вида.
то у вас скорее всего будет Windows + msysgit (git-bash) + TortoiseGit и т.д.

Вместо черепашки (или по крайней мере рядом с ней) я бы упомянул Git Extensions, потому что инструмент очень достойный.
А еще есть SourceTree от создателей Jira/BitBucket/…

В версии 1.0 для Windows будет также доступен еще и Mercurial. При беглом просмотре SourceTree очень понравился после Tortoise.
Добавил ссылки в конец статьи.
Использую SmartGit. Дружелюбно, комфортно. Также перешёл после Tortoise.
SourceTree изначально был написан Стивом Стритингом, автором движка OGRE. Потом уже софтину купили ребята из Atlassian. Оффтоп, но просто хочется, чтобы был известен реальный автор :)
Спасибо за качественную статью. До этого времени боялся git, теперь стало немного понятнее. Однозначно в избранное.
Можно сохранить и продавать как книгу. Очень круто.

Кстати, на днях gurugray выложил визуализатор для git.
Помогает увидеть как там всё работает. Новичкам полезно потыкать.
Статья фундаментальная, но довольно сырая и скомканая, а местами так вобще может сбить новичка столку. К примеру:

«Будут скачены новые коммиты, обновлены только удалённые ветки и тэги.»
Если бы я не понимал, что вы имеете ввиду, я бы решил что имеется ввиду removed, а не remote, что само по себе звучит очень странно.

Я бы на вашем месте выложил статью на github. Усилиями сообщества можно было бы ее подправить и получился бы отличный и полный вводной мануал в git.
Да, статья сыровата. Добавил в скобках пояснение, что имеется ввиду remote.
И выложил всё на github.
К сожалению, нет пока времени переводитьв markdown, поэтому там лежит исходник статьи.
Спасибо, почерпнул немного новой информации из вашей статьи.

И, всё-таки, новичкам я бы посоветовал начать с интерактивного курса — githowto.com/ru
Добавил в конец статьи, но всё же считаю более важным новичкам сразу объяснить как устроен git — это не займёт много времени, но сразу даст много понимания. Будет ясно почему те или иные вещи делаются именно так, как они делаются.
практически не использую ветки… странно но задачи очень атомарные. Ну clone — да, забыл ) но его редко используешь — простительно :)
Спасибо за статью.

Несколько комментариев по поводу работы в Windows (об этом, как обычно водится в статьях про гит, практически ни единого слова) из личного опыта:
1. Ключи. Да, здесь я не нашёл упоминания о генерации и типах ключей (согласен, возможно, это не полностью относится к данной теме). Лично я столкнулся с проблемой, что некоторые ключи почему-то не подходили — приходилось генерить новые. О генерации rsa ssh ключей можно найти в поисковиках.
2. При установке msysgit могут возникнуть проблемы: не хватка некоторых библиотек. Я, к сожалению, уже не помню каких именно (очень давно дело было), но вы точно без труда найдёте их в сети. Поэтому нужно быть готовым к этому и не стоит пугаться. Даже без явных ошибок msysgit может установиться некорректно и начать сыпать ошибки уже при непосредственно работе с репозиториями. В этом случае рекомендую сохранять спокойствие и просто переустановить его.
3. Уже не столько про винду, сколько про удобство. Во всех адекватных IDE для популярных ЯП имеется встроенная поддержка гита, и можно без лишних телодвижений работать. Как правило настройки по гиту находятся в пунктах типа «СКВ».

Напоследок отмечу, что проблемы с msysgit были у меня примерно год назад. Возможно, сейчас ситуация исправилась.
Мощная статья, почерпнул много интересного. Спасибо за труды.
Понял, исправлюсь.
Эм. Веткой ошибся. :) Сорри. Комменты правильные. С Виндой действительно возникают такие проблемы.
Git сохраняет в commit только изменения над файлами, которые вы проделали в рабочем каталоге. Множество изменений и даёт нам состояние файла(ов) на определённый момент. Сохраняется набор изменений и имена файлов (объектов), которые относятся к этому изменению.

В корне не согласен! Отличие гит и меркуриал от СВН как раз в том, что коммит — это именно снапшоты всех файлов, а не изменений в сравнении с предыдущим. Если файл не менялся — то сохраняется линк на его предыдущую версию. Именно благодаря этому в гите очень быстро реализуются такие возможности, как:
  • «мгновенный» чекаут любого коммита (версии). Вернуться на один коммит назад стоит столько же, сколько вернуться к самому первому коммиту (за исключением времени на чтение/запись файлов в файловой системе). Это обусловлено именно тем, что самый первый коммит хранит все файлы, как они были закомичены, как и самый последний коммит. В СВН возвраты к версиям должны пройти назад по всем ревизиям и последовательно применить патчи.
  • «мгновенное» переключение между бранчами. Причины и ограничения — как и в предыдущем примере.
  • быстрый merge: если у вас 2 ветки и в каждой 100500 коммитов — для гита это то же самое, что смержить в ветки по 1 коммиту. ибо он просто будет брать и «сливать» готовые файлы. В СВН мержин работает совсем иначе. Если я не ошибаюсь, слияние там просто формирует новый патч, а также делает метку, в какую ветку идти при откате назад.
  • rebase: этого вообще нет в СВН. Здесь уже нужны последовательные патчи ветки, котороую мы ребейзим, а применятся они будут для формирования снапшотов на коммите, на который мы «накатываем»


При этом, т.к. в репозитории все сжимается компрессором — его размер растет слабо, ибо если мы сделали даже миллиард коммитов с малыми изменениями — компрессор сожмет все отлично, т.к. будут повторятся огромные участки кода! Только бинарники здесь «вносят» большие вклады. Но с бинарниками в СВН та же трабла.

А вот когда мы просим сделать diff — тут-то гиту и приходится сравнивать два файла и формировать патч.

Прувы:
git-scm.com/book/ru/Введение-Основы-Git
habrahabr.ru/company/badoo/blog/163853/
Спасибо, что заметили.
Мысль ушла вперёд и я записал совершенно не то, что хотел сказать.
Срочно исправлю, т.к. это важно и нельзя вводить людей в заблуждение.
>Отличие гит и меркуриал от СВН как раз в том, что коммит — это именно снапшоты всех файлов, а не изменений в сравнении с предыдущим.

Насколько мне рассказывали, на самом деле для эффективного хранения (tm) гит может начать хранить таки диффы, и востанавливать файлы по неким фиксированным состояниям и цепочкам диффов.

В .git/objects лежат таки пожатые цельные состояния файлов, но упомянутый мной механизм, вероятно, включается при упаковке.

В холиваре на счет merge vs rebase пытаюсь придерживаться золотой середины. На что надо обратить внимание новичкам (может следует вынести в основную статью):
  • <b>rebase</b> «поменяет» все коммиты ветки, которую вы ребейзите. Это выльется в то, что вы теперь не сможете сделать push без force! (если вы ранее делали push этого бранча, разумеется)
  • Чем длинне ваша ветка (т.е., чем больше коммитов вы сделали от «корня», который перемещаете) — тем дольше и сложнее будет rebase, тем больше вероятность конфликтов и вам прийдется править конфликты для каждого конфликтного коммита, коммитить его и продолжать дальше ребейз (в мерже, например, конфликты будут только по сравнению с конечными состояниями файлов)
  • т.к. rebase делается сразу для пачки коммитов — возможна ситуация, что у вас будут «некомпилируемые коммиты». Т.е., вы наложите изменения файлов, но при этом, возможно, какие-то патчи сделали «нерабочие» коммиты, где неподключена библиотека, переопределена функция и т.п. Это выльется в проблему, когда нужно будет откатиться назад, на «сребейзнутый» коммит и окажется, что этот коммит «невалидный»


Из моей практики и общих рекомендаций:
  • Если сомневаешься — делай <b>merge</b>. Он всегда обратим, в отличии от rebase. Если нужны изменения из другой ветки — можно мержить другую ветку в свою хоть каждый день. Проблем не будет. Можно делать cherry-pick, если нужен ровно один патч.
  • Ребейзи только «свои» ветки, т.е., если ветку создал не ты, или с ней работает несколько человек — не ребейзи ее! (но если уж что-то важное — то предупреди всех, что делал ребейз и им нужно будет обновиться с --force)
  • rebase нестрашен для веток, которые не пушились на сервер. Тогда не будет конфликтов с репозиторием
  • У вас перемешаются даты коммитов! Будет очень сложно отследить кто и когда сделал реально коммит. По истории будет казаться, что коммит был позже (выше в графе), но может оказаться, что его делали позже
  • Никогда не делайте ребейз master бранча!. Мастер-бранч как раз попадает по всем вышеперечисленным пунктам-ограничениям!


Вообще, я «осознал» пока что только одно нормальное приктическое применение ребейза на таком примере цикла разработки:
  1. мы выпускаем новый релиз на основе последнего коммита в master. Ставим на него тег (если надо). Все далее master становится «незыблемым» до следующего релиза.
  2. на основе этого тега-коммита мы создаем ветку/ветки для нового релиза и кодим исключительно в этих ветках, не трогая мастер
  3. ВНЕЗАПНО нам срочно нужно пофиксить баг в последнем релизе и выпустить новый! Что делаем? Фиксим баг, коммитим в мастер (если надо — ставим тег), выпускаем новые релиз с фиксом. Но получается, что все наши ветки на следующий релиз не содержат новый фикс из мастера…
    rebase — Ваш выход! Все ветки для нового релиза ребейзятся на основе последнего коммита в мастере. А так как мы хорошо читали эту статью и делали все, как здесь написано — то наши атомарные коммиты не вызывают больших конфликтов. И в конце мы получаем наши ветки такими, как буд-то они начались с последней версии мастера!
  4. Когда мы готовы делать очередной релиз: мы мержим все ветку в одну, например release100. В этой ветке все проверяем, фиксим конфликты, потом баги. Когда мы уверены, что релиз готов — мержим release100 в master. А так как мы в мастер до этого ничего не коммитили — этот мерж делается как fast-forward. А нам только этого и нужно!
Добавлю свою имху:
rebase — для «централизованный» модели разработки, например, когда используется git-svn, или разработчики просто привычны к линейной истории коммитов.
merge — для распределённой модели разработки, когда ничто не мешает иметь структуру графа коммитов в его натуральном виде.

Лично мне очень по нраву rebase — он приводит набор коммитов к более актуальному состоянию, история становится более линейной (сложно отвыкнуть от cvs/svn), избавляет от мёрж-коммитов. Но есть и недостатки, о которых вы написали, — сбрасываются все даты коммитов, и rebase можно делать только своим, личным веткам. Тут я вас полностью поддерживаю.
И чем rebase hotfix-а во все ветки лучше чем merge этого же hotfix-а в те же ветки?
Не побоюсь повторить предыдущих ораторов — отличная статья, титанический труд! Спасибо и респект!
В статье пропущено описание 3-х коммитов: добавления файла trash.txt и пары строк в него (должно быть где-то перед разделом «git fetch»).
Столько лет прошло, а статья все еще настолько полезна…
И можно вопрос от начинающего?
Я имею минимальный опыт программирования, c git не имел. Начал изучать программирование микроконтоллеров для небольших домашних поделок. Естественно начинаю со всяких тестовых примеров, которые желательно пройти и сохранить на будущее в качестве справки.
Например, чтобы научиться работать с экраном на dev board надо начать с простого типа вывода текста, примитивных линий. Потом уже со шрифтами повозиться, картинки/иконки выводить… Под каждое такое иметь отдельную папку в PlatformIO (VSCode) — перебор.
Хочу завести репозиторий типа OLED_test и в нем какую-то фичу проверил — сохранил результат. Переключился на другую фичу. И в будущем легко посомтреть тот или иной вариант для справки.
Вот как это лучше сделать?
Сначала думал так:
Работать в master. Как получил результат и пора переключаться на другое — сделать новый бранч, перейти в него, закоммитить, вернуться обратно в master, начать в нем работу над тестированием новой фичи.
После статьи думаю, что правильнее держать в master совсем базовый код (основные include, void setup) и от него клонировать в новую ветку (git checkout -b oled/simple, git checkout -b oled/fonts...) и сразу работать в правильной ветке.
Но внутри них по идее тоже может быть несколько «работающих полезных» вариантов. Вероятно их каким-то образом помечать надо. Просто осмысленными комментариями при коммитах? Или какие-то тэги или еще чего?
При этом я могу работать с двух компов, т.е. реально это еще и через github должно синхронизироваться. Т.е. push достаточно часто, чаще, чем полностью рабочий вариант.
Можете кратко намекнуть, как бы вы такое сделали (ну или сказать, что я фигню какую-то задумал)?
Я бы начал с того, что убрал гит из уравнения. У вас должен быть некий проект. Он живёт где-то в каталоге и как-то организован и понятен. Если внутри него есть какие-то фичи (которые являются полностью самостоятельными) — то они то же как-то лежат в этих папках. Всё. Если у вас 10 проектов — значит 10.

Теперь добавляем гит. Это как «вселенная проекта» — каждый коммит — состояние вселенное на определённый момент времени. Вы можете двигаться вперёд и назад по времени. Фича бранчи в данном случае — альтернативное состояние вселенной, которое не влияет на основную.

Когда большая команда разрабатывает проект, фича бранч создаётся, чтобы разрабатывать и проверять новую фичу, не мешая проекту. Если фича не стабильна, ломает всё или не совместима — можно продолжать её разрабатывать, в то время как основная ветка (часто master) выходит в прод. Предполагается, что каждая такая ветка рана или поздно будет «влита» в мастер. Т.е. в мастере будут все фичи, который условно стабильны.
В моем случае «сливать» фичи не предполагается. Просто «достать» ту или иную при неоходимости. Просто чтобы не держать в хранилище кучу папок с практически одинаковым содаржимым. Основной проект будет не то, что отдельной веткой, а совсем другим репозиторием. И нужные фичи туда переносить руками из «тестового репозитория», где есть коммит с работающим датчиком температуры, другой — с каким-то другим датчиком…
Но идею я понял. И даже структуру тестовой проги пересмотрю. Тот же вывод на экран инфы от разных датчиков я предполагал делать просто меняя код. А теперь понял, что все-таки надо под каждый датчик отдельну. процедуру делать, а из основного кода просто разные вызывать.
В общем, спасибо, прояснилось!
Зарегистрируйтесь на Хабре , чтобы оставить комментарий

Публикации

Истории