Irbisa · Шпаргалка

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

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

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 Sources/Cart/Cart.swiftgit status --short                  # UU Sources/Cart/Cart.swiftgit log --merge --oneline -- Sources/Cart/Cart.swift   # 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 "xcuserdata/" >> .gitignoregit status --short             # the .xcuserstate file still shows as modified git rm -r --cached '*xcuserdata*'   # every xcuserdata folder in the repogit add .gitignoregit commit -m "chore: stop tracking xcuserdata"…
  7. 07

    Ваша ветка и main конфликтуют в project.pbxproj и Package.resolved. Как разрешить каждый файл и как сделать, чтобы конфликты в .pbxproj не возвращались?

    В project.pbxproj оставьте записи обеих сторон (каждый добавленный файл встречается в нескольких секциях) и проверьте, что файл читается и проект собирается.

    git merge main# CONFLICT (content): Merge conflict in App.xcodeproj/project.pbxproj# CONFLICT (content): Merge conflict in .../swiftpm/Package.resolved # project.pbxproj: keep both sides' entries in every section, thenplutil -lint App.xcodeproj/project.pbxproj    # "OK", or fails on a leftover marker…
  8. 08

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

    # main, already pushed:#   c3 Add retry     <- HEAD#   b2 Add client#   a1 Init# c3 changed Sources/Networking/APIClient.swift; 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 v4.2.0         # the last release where it was right # CartTotalRegressionTests.swift is new and untracked, in the Checkout# package's Tests/CheckoutTests folder, so SwiftPM compiles it at every step…
  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 хук должен запускать быстрые самоисправляющие проверки только по застейдженным файлам, например форматтер и быстрый линт.

    # lefthook.yml: committed; `lefthook install` wires .git/hooks after a clonepre-commit:  commands:    format:      glob: "*.swift"      run: swiftformat {staged_files}…
  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 fastlane/AuthKey_ABC123XYZ9.p8# 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 Sources/Cart/Cart.swift, 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 должен обновить библиотеку и всех её пользователей сразу.