Irbisa · Шпаргалка

Git и командная работа

Merge и rebase, конфликты, reset и revert, cherry-pick, stash, reflog и bisect, стратегии ветвления, pull request и код-ревью, соглашения о коммитах, секреты в истории, pubspec.lock и сгенерированные файлы

Junior-разработчик · 18 вопросов

  1. 01

    Что такое коммит, ветка и HEAD в Git и что означает «detached HEAD»?

    Коммит хранит снимок всего проекта вместе с родительскими коммитами, автором и сообщением, и идентифицируется хешем от всего этого.

  2. 02

    В чём разница между git fetch и git pull и что меняет git pull --rebase?

    git fetch скачивает новые коммиты и сдвигает ветки удалённого отслеживания вроде origin/main, но никогда не трогает вашу ветку и ваши файлы.

    git fetch origingit log --oneline main..origin/main    # what others pushedgit log --oneline origin/main..main    # what only you have git pull --rebase                      # fetch, then replay your commits on topgit config --global pull.rebase true   # the default from now on
  3. 03

    В чём разница между merge и rebase и почему нельзя делать rebase ветки, в которой работают другие?

    Merge соединяет две истории merge-коммитом и оставляет все существующие коммиты как есть.

    # feature/cart was cut from main, and main has moved sincegit switch feature/cartgit rebase main                      # your commits replayed on top: new hashesgit push --force-with-lease          # only because the branch is yours alone git switch main…
  4. 04

    Как пошагово разрешить конфликт слияния и чего нельзя делать никогда?

    Откройте каждый файл с конфликтом, поймите, что хотела каждая сторона, напишите версию, которая сохраняет оба намерения, и удалите маркеры.

    git merge main# CONFLICT (content): Merge conflict in lib/cart/cart.dartgit status --short                  # UU lib/cart/cart.dartgit log --merge --oneline -- lib/cart/cart.dart   # who changed it on each side # edit it: keep both intentions, delete <<<<<<< ||||||| ======= >>>>>>>…
  5. 05

    Что делают git stash и git cherry-pick и какие ловушки есть у каждой из них?

    git stash откладывает незакоммиченные изменения и оставляет чистую рабочую копию; git stash pop возвращает их обратно.

  6. 06

    Как работает .gitignore и почему Git продолжает отслеживать файл, который вы туда добавили?

    .gitignore лишь не даёт добавить неотслеживаемые файлы; файл, который Git уже отслеживает, остаётся отслеживаемым, что бы ни говорили шаблоны.

    # android/.gitignore already lists /local.properties, yet:git ls-files android/local.properties    # prints the path: the file is trackedgit status --short                       #  M android/local.properties git rm --cached android/local.propertiesgit commit -m "chore: stop tracking android/local.properties"…
  7. 07

    Как сделать так, чтобы все разработчики и CI собирали проект одной версией Flutter, и что для этого кладётся в git?

    Закрепите точную версию в файле внутри репозитория: в .fvmrc от FVM, который пишет fvm use 3.38.0, или точной версией flutter: в разделе environment файла pubspec.yaml.

    fvm use 3.38.0           # writes .fvmrc, links .fvm/flutter_sdk, updates .gitignoregit add .fvmrc .gitignoregit commit -m "build: pin Flutter 3.38.0" # a teammate after cloningfvm install              # installs the version named in .fvmrc…
  8. 08

    После git merge main конфликтуют и pubspec.yaml, и pubspec.lock. Как разрешить их, не правя lock-файл руками?

    pubspec.yaml разрешите руками, оставив зависимости обеих сторон, затем возьмите pubspec.lock из main и запустите flutter pub get: pub сохранит все версии, зафиксированные в main, и решит только ваши добавления.

    git merge main# CONFLICT (content): Merge conflict in pubspec.yaml# CONFLICT (content): Merge conflict in pubspec.lock # 1) pubspec.yaml by hand: keep both sides' new dependencies# 2) main's lock, then let pub add your packages on top…
  9. 09

    Каждая команда ниже выполняется отдельно, начиная с одной и той же запушенной истории. Что покажут git log и git status после каждой и какая безопасна для запушенной ветки?

    # main, already pushed:#   c3 Add retry     <- HEAD#   b2 Add client#   a1 Init# c3 changed lib/data/api_client.dart; the working tree is clean. git reset --soft HEAD~1    # Agit reset HEAD~1           # B (--mixed is the default)git reset --hard HEAD~1    # Cgit revert HEAD            # D

    A, B и C сдвигают main обратно на b2 и отличаются только тем, куда попадает изменение из c3: в индекс, в рабочую копию или никуда.

  10. 10

    Как привести в порядок коммиты ветки интерактивным rebase перед мержем и почему пушить с --force-with-lease, а не с --force?

    git rebase -i origin/main показывает список коммитов ветки; если заменить pick на squash, fixup, reword или drop или переставить строки, коммиты перепишутся в историю, которую приятно читать.

    git fetch origingit rebase -i --autosquash origin/main # the todo list Git opens, after your edits# (--autosquash already moved the fixup! commit under its target):pick 3f9c2e1 # feat: cart badge…
  11. 11

    После git reset --hard или неудачного rebase коммиты будто пропали. Как их вернуть и когда это невозможно?

    Reset или rebase не удаляет коммиты, а лишь перестаёт на них указывать.

    $ git reset --hard HEAD~2          # oops: two commits "gone"$ git refloga872130 HEAD@{0}: reset: moving to HEAD~2d6eb664 HEAD@{1}: commit: Debounce search7a7b367 HEAD@{2}: commit: Add search fielda872130 HEAD@{3}: checkout: moving from main to feature/search…
  12. 12

    Как git bisect находит коммит, который что-то сломал, и как автоматизировать поиск через git bisect run?

    Вы помечаете один коммит плохим, а более старый хорошим, и Git ищет делением пополам среди коммитов между ними: извлекает средний, вы проверяете его и отвечаете good или bad, и диапазон сокращается вдвое, пока не останется один коммит.

    git bisect startgit bisect bad                 # HEAD: the cart total is wronggit bisect good v1.4.0         # the last release where it was right# Bisecting: 37 revisions left to test after this (roughly 5 steps) # test/cart_total_regression_test.dart is new and untracked…
  13. 13

    Каким должно быть хорошее сообщение коммита и как Conventional Commits превращают историю в номера версий и changelog?

    Хорошее сообщение коротким заголовком в повелительном наклонении говорит, что делает коммит, а в теле объясняет зачем.

    feat(cart): show a discount badge on eligible items The badge reads the rule from /v2/discounts instead of theclient-side list, so marketing can change rules without a release. Closes #418…
  14. 14

    Что делает pull request удобным для ревью и как вы поступаете с комментариями, с которыми не согласны?

    Делайте PR маленьким и об одном, объясняйте, зачем он нужен и как проверен, и просматривайте свой дифф раньше всех остальных.

  15. 15

    Ваша фича-ветка живёт три недели и теперь конфликтует с половиной main. Как её влить и как избежать такого в следующий раз?

    Влейте main в ветку сейчас одним осознанным мержем, разрешите конфликты и прогоните тесты, а результат по возможности отправьте несколькими pull request, которые реально отревьюить.

  16. 16

    Вы закоммитили секрет и запушили его. Что делать и почему недостаточно удалить его новым коммитом?

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

    # 0) Revoke the secret at the provider and ship the new one. Only then:git clone git@github.com:acme/shop.git shop-clean && cd shop-clean # drop the file from every commitgit filter-repo --sensitive-data-removal --invert-paths --path config/prod.json# or replace the value wherever it appears ("old==>new" per line):…
  17. 17

    PR #42 сломал оформление заказа, поэтому его merge откатили в main. Автор исправил ветку и влил её снова, но скидок в main по-прежнему нет. Почему?

    git switch maingit merge --no-ff feature/discounts   # PR #42: two feature commitsgit revert -m 1 HEAD                  # checkout broke: undo the mergegit push git switch feature/discounts# add a guard in lib/cart/cart.dart, away from the lines the feature changedgit commit -am "fix: skip checkout for an empty cart"git switch maingit merge feature/discounts           # merges cleanly

    Revert отменяет изменения, но не историю: два коммита PR #42 по-прежнему в main, поэтому второй merge приносит только то, что появилось в ветке после, то есть один фикс.

  18. 18

    Когда стоит держать несколько приложений и общие библиотеки в одном монорепозитории, а не в отдельных репозиториях, и чего стоит каждый вариант?

    Монорепозиторий выбирают, когда код меняется вместе: приложения делят дизайн-систему, API-клиент и модели, и один pull request должен обновить библиотеку и всех её пользователей сразу.