pr_workflow.rst 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459
  1. .. _doc_pr_workflow:
  2. Pull request workflow
  3. =====================
  4. .. highlight:: shell
  5. The so-called "PR workflow" used by Godot is common to many projects using
  6. Git, and should be familiar to veteran free software contributors. The idea
  7. is that only a small number (if any) commit directly to the *master* branch.
  8. Instead, contributors *fork* the project (i.e. create a copy of it, which
  9. they can modify as they wish), and then use the GitHub interface to request
  10. a *pull* from one of their fork's branches to one branch of the original
  11. (often named *upstream*) repository.
  12. The resulting *pull request* (PR) can then be reviewed by other contributors,
  13. which might approve it, reject it, or most often request that modifications
  14. be done. Once approved, the PR can then be merged by one of the core
  15. developers, and its commit(s) will become part of the target branch (usually
  16. the *master* branch).
  17. We will go together through an example to show the typical workflow and
  18. associated Git commands. But first, let's have a quick look at the
  19. organisation of Godot's Git repository.
  20. Git source repository
  21. ---------------------
  22. The `repository on GitHub <https://github.com/godotengine/godot>`_ is a
  23. `Git <https://git-scm.com>`_ code repository together with an embedded
  24. issue tracker and PR system.
  25. .. note:: If you are contributing to the documention, its repository can
  26. be found `here <https://github.com/godotengine/godot-docs>`_.
  27. The Git version control system is the tool used to keep track of successive
  28. edits to the source code - to contribute efficiently to Godot, learning the
  29. basics of the Git command line is *highly* recommended. There exist some
  30. graphical interfaces for Git, but they usually encourage users to take bad
  31. habits regarding the Git and PR workflow, and we therefore recommend not to
  32. use them. In particular, we advise not to use GitHub's online editor for code
  33. contributions (although it's tolerated for small fixes or documentation changes)
  34. as it enforces one commit per file and per modification,
  35. which quickly leads to PRs with an unreadable Git history (especially after peer review).
  36. .. seealso:: The first sections of Git's "Book" are a good introduction to
  37. the tool's philosophy and the various commands you need to
  38. master in your daily workflow. You can read them online on the
  39. `Git SCM <https://git-scm.com/book/en/v2>`_ website.
  40. The branches on the Git repository are organized as follows:
  41. - The ``master`` branch is where the development of the next major version
  42. occurs. As a development branch, it can be unstable
  43. and is not meant for use in production. This is where PRs should be done
  44. in priority.
  45. - The stable branches are named after their version, e.g. ``3.0`` and ``2.1``.
  46. They are used to backport bugfixes and enhancements from the ``master``
  47. branch to the currently maintained stable release (e.g. 3.0.2 or 2.1.5).
  48. As a rule of thumb, the last stable branch is maintained until the next
  49. major version (e.g. the ``2.0`` branch was maintained until the release of
  50. Godot 2.1).
  51. If you want to make PRs against a maintained stable branch, you will have
  52. to check if your changes are also relevant for the ``master`` branch.
  53. - There might be feature branches at time, usually meant to be merged into
  54. the ``master`` branch at some time.
  55. Forking and cloning
  56. -------------------
  57. The first step is to *fork* the `godotengine/godot <https://github.com/godotengine/godot>`_
  58. repository on GitHub. To do so, you will need to have a GitHub account and to
  59. be logged in. In the top right corner of the repository's GitHub page, you
  60. should see the "Fork" button as shown below:
  61. .. image:: img/github_fork_button.png
  62. Click it, and after a while you should be redirected to your own fork of the
  63. Godot repo, with your GitHub username as namespace:
  64. .. image:: img/github_fork_url.png
  65. You can then *clone* your fork, i.e. create a local copy of the online
  66. repository (in Git speak, the *origin remote*). If you haven't already,
  67. download Git from `its website <https://git-scm.com>`_ if you're using Windows or
  68. macOS, or install it through your package manager if you're using Linux.
  69. .. note:: If you are on Windows, open Git Bash to type commands. macOS and Linux users
  70. can use their respective terminals.
  71. To clone your fork from GitHub, use the following command:
  72. ::
  73. $ git clone https://github.com/USERNAME/godot
  74. .. note:: In our examples, the "$" character denotes the command line prompt
  75. on typical UNIX shells. It is not part of the command and should
  76. not be typed.
  77. After a little while, you should have a ``godot`` directory in your current
  78. working directory. Move into it using the ``cd`` command:
  79. ::
  80. $ cd godot
  81. We will start by setting up a reference to the original repository that we forked:
  82. ::
  83. $ git remote add upstream https://github.com/godotengine/godot
  84. $ git fetch upstream
  85. This will create a reference named ``upstream`` pointing to the original
  86. godotengine/godot repository. This will be useful when you want to pull new
  87. commits from its ``master`` branch to update your fork. You have another
  88. ``remote`` reference named ``origin``, which points to your fork.
  89. You only need to do the above steps once, as long as you keep that local
  90. ``godot`` folder (which you can move around if you want, the relevant
  91. metadata is hidden in its ``.git`` subfolder).
  92. .. note:: *Branch it, pull it, code it, stage it, commit, push it, rebase
  93. it... technologic.*
  94. This bad take on Daft Punk's *Technologic* shows the general
  95. conception Git beginners have of its workflow: lots of strange
  96. commands to learn by copy and paste, hoping they will work as
  97. expected. And that's actually not a bad way to learn, as long as
  98. you're curious and don't hesitate to question your search engine
  99. when lost, so we will give you the basic commands to know when
  100. working in Git.
  101. In the following, we will assume that you want to implement a feature in
  102. Godot's project manager, which is coded in the ``editor/project_manager.cpp``
  103. file.
  104. Branching
  105. ---------
  106. By default, the ``git clone`` should have put you on the ``master`` branch of
  107. your fork (``origin``). To start your own feature development, we will create
  108. a feature branch:
  109. ::
  110. # Create the branch based on the current branch (master)
  111. $ git branch better-project-manager
  112. # Change the current branch to the new one
  113. $ git checkout better-project-manager
  114. This command is equivalent:
  115. ::
  116. # Change the current branch to a new named one, based on the current branch
  117. $ git checkout -b better-project-manager
  118. If you want to go back to the ``master`` branch, you'd use:
  119. ::
  120. $ git checkout master
  121. You can see which branch you are currently on with the ``git branch``
  122. command:
  123. ::
  124. $ git branch
  125. 2.1
  126. * better-project-manager
  127. master
  128. Updating your branch
  129. --------------------
  130. This would not be needed the first time (just after you forked the upstream
  131. repository). However, the next time you want to work on something, you will
  132. notice that your fork's ``master`` is several commits behind the upstream
  133. ``master`` branch: pull requests from other contributors would have been merged
  134. in the meantime.
  135. To ensure there won't be conflicts between the feature you develop and the
  136. current upstream ``master`` branch, you will have to update your branch by
  137. *pulling* the upstream branch.
  138. ::
  139. $ git pull upstream master
  140. However, if you had local commits, this method will create a so-called "merge
  141. commit", and you will soon hear from fellow contributors that those are not
  142. wanted in PRs. Then how to update the branch without creating a merge commit?
  143. You will have to use the ``--rebase`` option, so that your local commits are
  144. replayed on top of the updated upstream ``master`` branch. It will effectively
  145. modify the Git history of your branch, but that is for the greater good.
  146. Therefore, the command that you should (almost) always use is:
  147. ::
  148. $ git pull --rebase upstream master
  149. Making changes
  150. --------------
  151. You would then do your changes to our example's
  152. ``editor/project_manager.cpp`` file with your usual development environment
  153. (text editor, IDE, etc.).
  154. By default, those changes are *unstaged*. The staging area is a layer between
  155. your working directory (where you make your modifications) and the local git
  156. repository (the commits and all the metadata in the ``.git`` folder). To
  157. bring changes from the working directory to the Git repository, you need to
  158. *stage* them with the ``git add`` command, and then to commit them with the
  159. ``git commit`` command.
  160. There are various commands you should know to review your current work,
  161. before staging it, while it is staged, and after it has been committed.
  162. - ``git diff`` will show you the current unstaged changes, i.e. the
  163. differences between your working directory and the staging area.
  164. - ``git checkout -- <files>`` will undo the unstaged changes to the given
  165. files.
  166. - ``git add <files>`` will *stage* the changes on the listed files.
  167. - ``git diff --staged`` will show the current staged changes, i.e. the
  168. differences between the staging area and the last commit.
  169. - ``git reset HEAD <files>`` will *unstage* changes to the listed files.
  170. - ``git status`` will show you what are the currently staged and unstaged
  171. modifications.
  172. - ``git commit`` will commit the staged files. It will open a text editor
  173. (you can define the one you want to use with the ``GIT_EDITOR`` environment
  174. variable or the ``core.editor`` setting in your Git configuration) to let you
  175. write a commit log. You can use ``git commit -m "Cool commit log"`` to
  176. write the log directly.
  177. - ``git log`` will show you the last commits of your current branch. If you
  178. did local commits, they should be shown at the top.
  179. - ``git show`` will show you the changes of the last commit. You can also
  180. specify a commit hash to see the changes for that commit.
  181. That's a lot to memorise! Don't worry, just check this cheat sheet when you
  182. need to make changes, and learn by doing.
  183. Here's how the shell history could look like on our example:
  184. ::
  185. # It's nice to know where you're starting from
  186. $ git log
  187. # Do changes to the project manager with the nano text editor
  188. $ nano editor/project_manager.cpp
  189. # Find an unrelated bug in Control and fix it
  190. $ nano scene/gui/control.cpp
  191. # Review changes
  192. $ git status
  193. $ git diff
  194. # We'll do two commits for our unrelated changes,
  195. # starting by the Control changes necessary for the PM enhancements
  196. $ git add scene/gui/control.cpp
  197. $ git commit -m "Fix handling of margins in Control"
  198. # Check we did good
  199. $ git log
  200. $ git show
  201. $ git status
  202. # Make our second commit
  203. $ git add editor/project_manager.cpp
  204. $ git commit -m "Add a pretty banner to the project manager"
  205. $ git log
  206. With this, we should have two new commits in our ``better-project-manager``
  207. branch which were not in the ``master`` branch. They are still only local
  208. though, the remote fork does not know about them, nor does the upstream repo.
  209. Pushing changes to a remote
  210. ---------------------------
  211. That's where ``git push`` will come into play. In Git, a commit is always
  212. done in the local repository (unlike Subversion where a commit will modify
  213. the remote repository directly). You need to *push* the new commits to a
  214. remote branch to share them with the world. The syntax for this is:
  215. ::
  216. $ git push <remote> <local branch>[:<remote branch>]
  217. The part about the remote branch can be omitted if you want it to have the
  218. same name as the local branch, which is our case in this example, so we will
  219. do:
  220. ::
  221. $ git push origin better-project-manager
  222. Git will ask you for your username and password, and the changes will be sent
  223. to your remote. If you check the fork's page on GitHub, you should see a new
  224. branch with your added commits.
  225. Issuing a pull request
  226. ----------------------
  227. When you load your fork's branch on GitHub, you should see a line saying
  228. *"This branch is 2 commits ahead of godotengine:master."* (and potentially some
  229. commits behind, if your ``master`` branch was out of sync with the upstream
  230. ``master`` branch.
  231. .. image:: img/github_fork_make_pr.png
  232. On that line, there is a "Pull request" link. Clicking it will open a form
  233. that will let you issue a pull request on the godotengine/godot upstream
  234. repository. It should show you your two commits, and state "Able to merge".
  235. If not (e.g. it has way more commits, or says there are merge conflicts),
  236. don't create the PR, something went wrong. Go to IRC and ask for support :)
  237. Use an explicit title for the PR and put the necessary details in the comment
  238. area. You can drag and drop screenshots, GIFs or zipped projects if relevant,
  239. to showcase what your work implements. Click "Create a pull request", and
  240. tadaa!
  241. Modifying a pull request
  242. ------------------------
  243. While it is reviewed by other contributors, you will often need to make
  244. changes to your yet-unmerged PR, either because contributors requested them,
  245. or because you found issues yourself while testing.
  246. The good news is that you can modify a pull request simply by acting on the
  247. branch you made the pull request from. You can e.g. make a new commit on that
  248. branch, push it to your fork, and the PR will be updated automatically:
  249. ::
  250. # Check out your branch again if you had changed in the meantime
  251. $ git checkout better-project-manager
  252. # Fix a mistake
  253. $ nano editor/project_manager.cpp
  254. $ git add editor/project_manager.cpp
  255. $ git commit -m "Fix a typo in the banner's title"
  256. $ git push origin better-project-manager
  257. That should do the trick, but...
  258. Mastering the PR workflow: the rebase
  259. -------------------------------------
  260. On the situation outlined above, your fellow contributors who are particularly
  261. pedantic regarding the Git history might ask your to *rebase* your branch to
  262. *squash* or *meld* the last two commits together (i.e. the two related to the
  263. project manager), as the second commit basically fixes an issue in the first one.
  264. Once the PR is merged, it is not relevant for a changelog reader that the PR
  265. author made mistakes; instead, we want to keep only commits that bring from
  266. one working state to another working state.
  267. To squash those two commits together, we will have to *rewrite history*.
  268. Right, we have that power. You may read that it's a bad practice, and it's
  269. true when it comes to branches of the upstream repo. But in your fork, you
  270. can do whatever you want, and everything is allowed to get neat PRs :)
  271. We will use the *interactive rebase* ``git rebase -i`` to do this. This
  272. command takes a commit hash as argument, and will let you modify all commits
  273. between that commit hash and the last one of the branch, the so-called
  274. *HEAD*. In our example, we want to act on the last two commits, so we will
  275. do:
  276. ::
  277. # The HEAD~X syntax means X commits before HEAD
  278. $ git rebase -i HEAD~2
  279. This will open a text editor with:
  280. ::
  281. pick 1b4aad7 Add a pretty banner to the project manager
  282. pick e07077e Fix a typo in the banner's title
  283. The editor will also show instructions regarding how you can act on those
  284. commits. In particular, it should tell you that "pick" means to use that
  285. commit (do nothing), and that "squash" and "fixup" can be used to *meld* the
  286. commit in its parent commit. The difference between "squash" and "fixup" is
  287. that "fixup" will discard the commit log from the squashed commit. In our
  288. example, we are not interested in keeping the log of the "Fix a typo" commit,
  289. so we use:
  290. ::
  291. pick 1b4aad7 Add a pretty banner to the project manager
  292. fixup e07077e Fix a typo in the banner's title
  293. Upon saving and quitting the editor, the rebase will occur. The second commit
  294. will be melded into the first one, and ``git log`` and ``git show`` should
  295. now confirm that you have only one commit with the changes from both previous
  296. commits.
  297. .. note:: You could have avoided this rebase by using ``git commit --amend``
  298. when fixing the typo. This command will write the staged changes
  299. directly into the *last* commit (``HEAD``), instead of creating a new
  300. commit like we did in this example. So it is equivalent to what we
  301. did with a new commit and then a rebase to mark it as "fixup".
  302. But! You rewrote the history, and now your local and remote branches have
  303. diverged. Indeed, commit 1b4aad7 in the above example will have changed, and
  304. therefore got a new commit hash. If you try to push to your remote branch, it
  305. will raise an error:
  306. ::
  307. $ git push origin better-project-manager
  308. To https://github.com/akien-mga/godot
  309. ! [rejected] better-project-manager -> better-project-manager (non-fast-forward)
  310. error: failed to push some refs to 'https://akien-mga@github.com/akien-mga/godot'
  311. hint: Updates were rejected because the tip of your current branch is behind
  312. hint: its remote counterpart.
  313. This is a sane behaviour, Git will not let you push changes that would
  314. override remote content. But that's actually what we want to do here, so we
  315. will have to *force* it:
  316. ::
  317. $ git push --force origin better-project-manager
  318. And tadaa! Git will happily *replace* your remote branch with what you had
  319. locally (so make sure that's what you wanted, using ``git log``). This will
  320. also update the PR accordingly.
  321. Deleting a Git branch
  322. ---------------------
  323. After your pull request gets merged, there's one last thing you should do: delete your
  324. Git branch for the PR. There won't be issues if you don't delete your branch, but it's
  325. good practice to do so. You'll need to do this twice, once for the local branch and another
  326. for the remote branch on GitHub.
  327. To delete our better project manager branch locally, use this command:
  328. ::
  329. $ git branch -d better-project-manager
  330. Alternatively, if the branch hadn't been merged yet and we wanted to delete it anyway, instead
  331. of ``-d`` you would use ``-D``.
  332. Next, to delete the remote branch on GitHub use this command:
  333. ::
  334. $ git push origin -d better-project-manager