Skip to content

Add Git Bootcamp page #144

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Mar 16, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
250 changes: 250 additions & 0 deletions gitbootcamp.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,250 @@
.. highlight:: console

.. _gitbootcamp:

Git Bootcamp and Cheat Sheet
============================

In this section, we'll go over some commonly used Git commands that are
relevant to CPython's workflow.

.. contents::


Forking CPython GitHub Repository
---------------------------------

You'll only need to do this once.

1. Go to https://github.com/python/cpython.

2. Press ``Fork`` on the top right.

3. When asked where to fork the repository, choose to fork it to your username.

4. Your fork will be created at https://github.com/<username>/cpython.


Cloning The Forked CPython Repository
-------------------------------------

You'll only need to do this once. From your command line::

$ git clone [email protected]:<username>/cpython.git
$ cd cpython
$ git remote add upstream [email protected]:python/cpython.git


Listing the Remote Repositories
-------------------------------

To list the remote repositories that are configured, along with their urls::

$ git remote -v


Creating and Switching Branches
-------------------------------

.. note::
Never commit directly to the ``master`` branch.

Create a new branch and switch to it::

# creates a new branch off master and switch to it
$ git checkout -b <branch-name> master

This is equivalent to::

# create a new branch off 'master', without checking it out
$ git branch <branch-name> master
# check out the branch
$ git checkout <branch-name>

To find out which branch you are in now::

$ git branch

The current branch will have an asterisk next to the branch name. Note, this
will list all of your local branches.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lately I've been using git status instead of git branch, as it tells the current branch at the beginning.
Should this be mentioned instead/in addition to git branch?


To list all the branches, including the remote branches::

$ git branch -a

To switch to a different branch::

$ git checkout <another-branch-name>


Delete Local Branch
-------------------

To delete branch that you no longer need::

$ git branch -D <branch-name>


Staging and Committing Files
----------------------------

1. To show the current changes::

$ git status
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe mention git diff HEAD here?


2. To stage the files to be included in your commit::

$ git add path/to/file1 path/to/file2 path/to/file3

3. To commit the files that have been staged (done in step 2)::

$ git commit -m "bpo-XXXX: This is the commit message."


Reverting Changes
-----------------

To revert changes to a file that has not been committed yet::

$ git checkout path/to/file

If the change has been committed, and now you want to reset it to whatever
the origin is at::

$ git reset --hard HEAD
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the difference between this and git reset --hard HEAD^ (note the trailing ^)?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure... I don't normally use the ^

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I find this section a bit confusing/misleading.
When compared to HG, the git checkout <path> is equivalent to hg revert <path>, and it only reverts local changes to <path> that haven't been committed yet.
OTOH, git reset --hard HEAD seems equivalent to hg rollback, i.e. it undoes the last commit and edit the history (and I assume this doesn't work if the commit has been pushed already -- this is not mentioned but should be added).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are two more scenarios where I used hg revert that are not covered here:

  1. how to revert all changes in the working copy (i.e. the equivalent of hg revert -a -- git reset? git reset --hard?).
  2. how to revert the fix while leaving the test to verify if they fail without the fix.

The second case works differently since we are using PRs. With HG I could apply a patch and do hg revert Lib/ to revert all the changes in Lib while leaving the tests unchanged. I think the git equivalent would be something like git checkout master Lib/, after I pulled a PR as described in a later section.



Stashing Changes
----------------

To stash away changes that are not ready to be committed yet::
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Coming from HG, the concept of staging and stashing are foreign. While I am now somewhat familiar with them, I'd prefer a goal-oriented approach, i.e.:

If you want to temporarily revert changes that are not ready to be committed yet, use::

   $ git stash

You can then retrieve those changes by using::

   $ git stash pop

(Feel free to change the wording if it doesn't accurately reflect what git stash does.)


$ git stash

To re-apply last stashed change::

$ git stash pop


Pushing Changes
---------------

Once your changes are ready for a review or a pull request, you'll need to push
them to the remote repository.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"...push them to your GitHub fork."


::

$ git checkout <branch-name>
$ git push origin <branch-name>


Creating a Pull Request
-----------------------

1. Go to https://github.com/python/cpython.

2. Click ``compare across forks`` link.

3. Select the base fork: ``python/cpython`` and base branch: ``master``.

4. Select the head fork: ``<username>/cpython`` and base branch: the branch
containing your changes.

5. Press ``Create Pull Request`` button.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't it easier to just go on my fork, and press the "Compare & pull request" button?
See e.g. https://www.drupal.org/files/pull_request_test_highlighted.png

I'm not sure when that button is available, but so far I've always found it after pushing a new branch.

Edit: after reading below I'm not sure if this works for other branches, but maybe it does?



Syncing With Upstream
---------------------
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would be easier to configure the remote to upstream. This could be explained either in the "Cloning The Forked CPython Repository" section, or in this section, as an alternative to the provided commands.


Scenario:

- You forked the CPython repository some time ago.
- Time passes.
- There have been new commits made in upstream CPython repository.
- Your forked CPython repository is no longer up to date.
- You now want to update your forked CPython repository to be the same as
upstream.

Solution::

$ git checkout master
$ git pull --rebase upstream master
$ git push origin master
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FWIW I've been using git pull -v since it shows where it's pulling from (IIRC without -v it doesn't say, and by default using git pull in a branch, pulls from master and not from upstream). Here you are mentioning the branches explicitly, so maybe it's not necessary (although it might be if you accidentally reverse the order).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Inline comments would be useful:

   $ git checkout master  # switch to the `master` branch
   $ git pull --rebase upstream master  # pull new changes from `upstream` to `master`
   $ git push origin master  # push the new changes to my local fork (`origin`)


The `--rebase` is only needed if you have local changes to the branch.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Above you mentioned that you should never commit to master, so I would assume --rebase is never needed.


Another scenario:

- You created ``some-branch`` some time ago.
- Time passes.
- You made some commits to ``some-branch``.
- Meanwhile, there are recent changes from upstream CPython repository.
- You want to incorporate the recent changes from upstream into ``some-branch``.

Solution::

$ git checkout some-branch
$ git fetch upstream
$ git rebase upstream/master
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I recently came across this scenario, and the solution I used was:

git pull -v (if remote == upstream)
git pull -v upstream master (if not)
git checkout <branch>
git rebase master

This has the advantage of also updating the local master. I think this also assumes that the first command is done in the master branch, otherwise it doesn't work (whereas the alternative should always work).

Perhaps this should also mention two other things:

  1. rebasing might result in conflicts (with a link to a section that explains how to solve them);
  2. when is it necessary to update/rebase? IOW should I always update before every commit, or I can just update my pr without updating?



Backporting Merged Changes
--------------------------
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Who is the target here? Are contributors supposed to do this or is it only for core devs?
Perhaps this should be clarified at the beginning of the page, with a note stating something like "These commands apply to all contributors, unless otherwise specified." and then add notes like "These commands only apply to core-devs." to the relevant sections.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think core dev who merged the PR is expected to do the backport, mainly because it involves removing needs backport to X.Y label, and applying cherry-pick for X.Y label. Contributor don't have the right to apply and remove labels themselves. It's fine to ask the contributor to do the cherry-pick themselves, but core devs should still apply/remove the appropriate labels.

For now I will just state here that the core dev is expected to do the backport. Once the cherry-picking bot is in place, this section will just be obsolete.


A pull request may need to be backported into one of the maintenance branches
after it has been accepted and merged into ``master``. It is usually indicated
by the label ``needs backport to X.Y`` on the pull request itself.

Use the utility script `cherry_picker.py <https://github.com/python/core-workflow/tree/master/cherry_picker>`_
from the `core-workflow <https://github.com/python/core-workflow>`_
repository to backport the commit .

The core developer who merged the pull request is expected to do the backport.


Downloading Other's Patches
---------------------------

Scenario:

- A contributor made a pull request to CPython.
- Before merging it, you want to be able to test their changes locally.

Set up the following git alias::

$ git config --global alias.pr '!sh -c "git fetch upstream pull/${1}/head:pr_${1} && git checkout pr_${1}" -'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the third variant of what I believe is the same thing. The other two I saw are:

  1. git fetch <cpythonorigin> pull/<prnumber>/head:pr/<prnumber> that creates a pr/prnumber branch.
  2. Adding fetch = +refs/pull/*/head:refs/remotes/upstream/pr/* under [remote "upstream"] in the .git/config and then use git checkout pr/prnumber .

The first one seem equivalent to the alias, except that it needs to be done manually every time. The second one doesn't require to create an additional alias but it needs to be added to each .git/config (I guess it's also possible to add it with git config ..., and maybe even set it as global. The alias also seem to invoke sh, so I guess it won't work on Windows.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This alias was suggested by @zware. I don't actually know about the other variants. So I'll just leave this as is.


The alias only needs to be done once. After the alias is set up, you can get a
local copy of a pull request as follows::

$ git pr <pr_number>


Accepting and Merging A Pull Request
------------------------------------

Pull requests can be accepted and merged by a Python Core Developer.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A question about "merging etiquette": if another core-dev submitted a PR, and it looks good to me, should I go ahead and merge it, or should I just leave a positive review and let the original core-dev merge it?
I think the latter is better, but I've seen the former happen.
Perhaps this could be clarified here.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps this is to be asked at core-workflow or python-committers? :)


1. At the bottom of the pull request page, click the ``Squash and merge``
button.

2. Adjust and clean up the commit message. Replace the reference
to GitHub PR #XXX into GH-XXX.

Example of good commit message::

bpo-12345: Improve the spam module (GH-777)

* Add method A to the spam module
* Update the documentation of the spam module

Example of bad commit message::

bpo-12345: Improve the spam module (#777)

* Improve the spam module
* merge from master
* adjust code based on review comment
* rebased

3. Press the ``Confirm squash and merge`` button.
3 changes: 3 additions & 0 deletions index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ contributing to Python:
* :doc:`help`
* PEPs_ (Python Enhancement Proposals)
* :doc:`gitdevs`
* :doc:`gitbootcamp`

.. _branchstatus:

Expand Down Expand Up @@ -161,6 +162,7 @@ Guide for contributing to Python:
* :doc:`buildbots`
* :doc:`coverity`
* :doc:`gitdevs`
* :doc:`gitbootcamp`

It is **recommended** that the above documents be read in the order listed. You
can stop where you feel comfortable and begin contributing immediately without
Expand Down Expand Up @@ -299,6 +301,7 @@ Full Table of Contents
buildslave
gitdevs
motivations
gitbootcamp


.. _Buildbot status: https://www.python.org/dev/buildbot/
Expand Down