Irbisa · Шпаргалка

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

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

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 src/cart/cart.tsgit status --short                  # UU src/cart/cart.tsgit log --merge --oneline -- src/cart/cart.ts   # 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 уже отслеживает, остаётся отслеживаемым, что бы ни говорили шаблоны.

    echo "dist/" >> .gitignoregit status --short              # the build output still shows as modified git rm -r --cached distgit add .gitignoregit commit -m "chore: stop tracking dist"…
  7. 07

    После мержа конфликтуют и package.json, и package-lock.json. Как их разрешить и почему нельзя просто удалить lock-файл и переустановить зависимости?

    package.json исправьте руками, оставив зависимости обеих сторон, затем запустите npm install --package-lock-only (или pnpm install): пакетный менеджер прочитает lock-файл с конфликтом, объединит обе стороны и запишет чистый.

    git merge main# CONFLICT (content): Merge conflict in package.json# CONFLICT (content): Merge conflict in package-lock.json # 1) package.json by hand: keep both sides' dependencies# 2) let npm rebuild the lockfile from the conflicted one…
  8. 08

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

    # main, already pushed:#   c3 Add retry     <- HEAD#   b2 Add client#   a1 Init# c3 changed src/api/client.ts; 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: в индекс, в рабочую копию или никуда.

  9. 09

    Как привести в порядок коммиты ветки интерактивным 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…
  10. 10

    После 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…
  11. 11

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

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

    git bisect startgit bisect bad                 # HEAD: the cart total is wronggit bisect good v2.7.0         # the last release where it was right # src/cart/total.regression.test.ts is new and untrackedgit bisect run sh -c '…
  12. 12

    Каким должно быть хорошее сообщение коммита и как 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…
  13. 13

    Каким должен быть хороший pull request и как вы ревьюите чужой?

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

  14. 14

    В чём разница между GitFlow, GitHub flow и trunk-based development и что бы вы выбрали?

    GitFlow держит долгоживущие develop и main, а также ветки release и hotfix, и рассчитан на плановые релизы с версиями.

  15. 15

    Что должно быть в pre-commit хуке и почему CI всё равно должен запускать те же проверки?

    Pre-commit хук должен запускать быстрые самоисправляющие проверки только по застейдженным файлам, например форматтер и быстрый линт.

    npm install --save-dev husky lint-stagednpx husky init                         # adds "prepare": "husky" and .husky/pre-commitecho "npx lint-staged" > .husky/pre-commit # package.json#   "lint-staged": {…
  16. 16

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

    Каждый pull request получает собственную развёрнутую копию приложения по уникальному URL, собранную из его ветки, и ревьюеры, QA и дизайнеры прокликивают изменение, а не представляют его по диффу.

  17. 17

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

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

    # 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 .env.production# or replace the value wherever it appears ("old==>new" per line):…
  18. 18

    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 src/cart/cart.ts, 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 приносит только то, что появилось в ветке после, то есть один фикс.