GitHub: руководство для начинающего контрибьютора
Представим себе что вы хотите исправить ошибку или добавить фичу в проект на GitHub.
Если это что-то простое, вроде опечатки в README.md
, то это делается в два клика прямо на GitHub. Поговорим о более сложном случае, когда нужно не просто исправить ошибку, но и запустить необходимые скрипты для проверки, разбить работу на несколько коммитов, и так далее.
Спешите? Все команды сразу.
К делу
Начать следует с форка репозитория проекта, который планируется дополнить. Это делается нажатием кнопки "Fork" на странице репозитория прямо на GitHub.
Чтобы далеко не искать подходящий пример, сделайте форк репозитория с файлами для статьи о внедрении PHPUnit.
Затем склонируйте себе локально исходный репозиторий. Важно клонировать не ваш форк, а репозиторий исходного проекта. С таким подходом ветка main
(или master
) будет постоянно указывать на исходный проект.
$ git clone https://github.com/sanmai/phpunit-primer
Перейдем в каталог с клоном и посмотрим, какие удалённые репозиторий настроены.
$ cd phpunit-primer
$ git remote -v
origin https://github.com/sanmai/phpunit-primer (fetch)
origin https://github.com/sanmai/phpunit-primer (push)
За редким исключением, всем удалённым репозиториям в Git присваиваются имена. По умолчанию первый добавленный репозиторий называется origin
, но в нашем случае это не подходит. Репозиторий исходного проекта переименуем в upstream
, из чего будет понятно что оттуда делается только pull.
$ git remote rename origin upstream
Для верности можно бесповоротно сломать возможность сделать push, запретить выгружать любые коммиты обратно. В команде ниже вместо disabled
можно использовать любой другой несуществующий URL.
$ git remote set-url --push upstream disabled
С такой настройкой сделать push будет просто невозможно.
$ git remote -v
upstream https://github.com/sanmai/phpunit-primer (fetch)
upstream disabled (push)
$ git push
fatal: 'disabled' does not appear to be a git repository
fatal: Could not read from remote repository.
Please make sure you have the correct access rights
and the repository exists.
Аналогично можно сделать с веткой main
даже если та указывает на ваш собственный репозиторий: вы не сможете по ошибке выгрузить какие-то коммиты прямо в ветку main
, минуя открытие PR из отдельной ветки.
Мы готовы к тому, чтобы подключить ваш форк, упомянув его SSH-ссылкой.
$ git remote add origin git@github.com:username/phpunit-primer.git
Ваш форк в Git будет называться origin
, с тем расчетом чтобы команды в обычных подсказках, которые показывает Git, работали без необходимости что-то менять перед копированием и вставкой. Как, например, при первом пуше из новой ветки:
$ git push
fatal: The current branch test has no upstream branch.
To push the current branch and set the remote as upstream, use
git push --set-upstream origin test
Что ещё?
Как правило, недостаточно запретить пушить в main
. Можно по ошибке сделать коммит в main
, затем начать новую ветку и получить очень некрасивую историю и отвергнутый PR.
Избежать этого можно если запретить коммиты в main
(и master
) хуком .git/hooks/pre-commit
с таким содержанием:
#!/bin/sh
set -e -x
test $(git rev-parse --abbrev-ref HEAD) != "main"
test $(git rev-parse --abbrev-ref HEAD) != "master"
С таким хуком при попытке коммита в main
будет выводиться ошибка:
$ git checkout main
$ git commit
+ git rev-parse --abbrev-ref HEAD
+ test main != main
Готово!
Все готово к началу работы. Дальше каждый раз одно и то же.
Загружаем последние изменения с исходного проекта в ветку
main
.$ git checkout main $ git pull
Делаем новую ветку с понятным названием на основе ветки
main
.$ git checkout -b fix-for-issue-42 Switched to a new branch 'fix-for-issue-42'
Вносим всевозможные изменения, запускаем тесты и так далее.
$ composer install $ git diff $ git add -p $ git diff --cached $ php vendor/bin/phpunit $ git commit
Выгружаем коммиты с работой из ветки обратно на GitHub.
$ git push --set-upstream origin fix-for-issue-42 Total 0 (delta 0), reused 0 (delta 0) To github.com:username/phpunit-primer.git * [new branch] fix-for-issue-42 -> fix-for-issue-42 Branch 'fix-for-issue-42' set up to track remote branch 'fix-for-issue-42' from 'origin'.
Открываем PR, ждем одобрения ведущих разработчиков.
Радуемся сообщению о принятии изменений.
Всё сразу
Если задать входные данные переменными:
UPSTREAM=example/example
MASTER=$USER/$(basename $UPSTREAM)
То все команды для начала работы и настройки копии будут следующие:
git clone https://github.com/$UPSTREAM
cd $(basename $UPSTREAM)
git remote rename origin upstream
git remote set-url --push upstream disabled
git remote add origin git@github.com:$MASTER.git
tee .git/hooks/pre-commit <<'EOF'
#!/bin/sh
set -e -x
test $(git rev-parse --abbrev-ref HEAD) != "main"
test $(git rev-parse --abbrev-ref HEAD) != "master"
EOF
chmod +x .git/hooks/pre-commit