Welcome | Get started | Dive into Lino | Contribute | Topics | Reference | More

Git cheat sheet

Cloning a repository

When you clone a repository from GitLab or GitHub, the git clone command adds a remote named "origin", pulls down all Git data, creates a pointer named origin/master to the remote's master branch, and a pointer master to your own local master branch, starting at the same place as origin’s master branch.

Make a pull request

Branching

My summary after reading the Branching chapter of Scott Chacon's Pro Git book:

  • master : the default branch that will be selected after cloning your repo. The name is purely conventional and has no special meaning for Git itself.

  • HEAD : pointer to the "current branch" (the one that is checked out).

  • Create a new branch called "20141022": git branch 20141022

  • Select a branch : git checkout 20141022

  • Shortcut to create and select : git checkout -b 20141022

  • Starting and selecting a branch will not modify your local modifications.

  • List all branches: git branch

  • See which branches are already merged into HEAD : git branch --merged

  • See all the branches that contain work you haven’t yet merged : git branch --merged

  • Merge a branch into current branch: git merge 20141022 (in case of a merge conflict, start reading at Basic Merge Conflicts)

  • Delete a branch: git branch -d 20141022

  • Common names for long-term branches: develop, proposed, next.

Remote branches

When you want to share a branch with the world, you need to push it to a remote that you have write access to. For example:

$ git checkout -b myfeature  # create a local branch
$ git push origin myfeature  # make it public
$ # ... add files and commit changes
  • Remote branches : (remote)/(branch)

When pulling such a remote branch, keep in mind the subtle difference between git pull and git fetch, where the following command:

$ git pull origin myfeature

will pull the content of the remote branch and merge it with the current local branch. On the other hand, the following command:

$ git fetch origin myfeature

will pull the content of the remote branch but will NOT merge it with the current branch. In such a case it is safer to use the later command.

Later the user can safely checkout the content of the fetched branch by using the following command:

$ git checkout myfeature

TODO: Continue to read https://git-scm.com/book/en/Git-Branching-Remote-Branches

Contributing pull requests to foreign projects

Most projects don't use the "shared repository model" (several users writing to a repo) but the "fork & pull" model as explained in Using pull requests).

Example: I have a fork of Ahmet's ablog project. Ahmet made changes in ablog and asked me to test them. So I need to merge his changes into the local copy of my fork.

So if I want to contribute to Ahmet's ablog project, I need to fork the project on GitHub (using their web interface) and then get a clone of this fork:

$ git clone git@github.com:lsaffre/ablog.git

Now I make my changes:

$ e ablog/__init__.py

When I decided that I want to share my local changes, I create a branch, commit it and push it to my repo:

$ git checkout -b feed_encoding
$ git commit -m "Added encoding utf-8 to file atom.xml"
$ git push origin feed_encoding

Now their web interface sees my branch and allows me to turn it into a pull request.

Merge from upstream

Every local project repository has a set of tracked repositories, also called "remotes". The default remote (the place from where my local repo has been taken) is called origin.

List all remotes:

$ git remote -v
origin   git@github.com:lsaffre/ablog.git (fetch)
origin   git@github.com:lsaffre/ablog.git (push)

First I must add Ahmet's repo as a new remote, which is usually called upstream:

$ git remote add upstream git@github.com:abakan/ablog.git

My local repo now has two remotes:

$ git remote -v
origin      git@github.com:lsaffre/ablog.git (fetch)
origin      git@github.com:lsaffre/ablog.git (push)
upstream    git@github.com:abakan/ablog.git (fetch)
upstream    git@github.com:abakan/ablog.git (push)

Now I can fetch all changes from the upstream repository:

$ git fetch upstream

Before continuing, make sure where you want the changes from upstream to go. Usually you want them to go to master, so you must select this branch:

$ git checkout master

And finally I can merge them into my local repo:

$ git merge upstream/master

fetch upstream looks up the specified remote, fetches any data from it that you don’t yet have, and updates your local database, moving your upstream/master pointer to its new position.

How to update the most recent commit message

You can rewrite the most recent commit message with amend:

$  git commit --amend -m "new commit message"

This will change the commit id, i.e. actually you are creating a new commit that replaces the old one.

TODO:

  • How to return back to my local changes?

  • What was this?

    $ git pull upstream master
    

Merge from upstream while local branch active

I had started a branch in my local copy of ablog:

$ git status
On branch trans_estonian
nothing to commit, working directory clean
$ git push origin trans_estonian
Everything up-to-date

Accept a pull request

Example: cuchac posted a pull request for a branch which he named export_excel_datetime (on his fork of project lino).

Check that there are no local changes in my repo:

$ go lino
$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
nothing to commit, working directory clean

Check out his branch into a new branch inbox in order to test the changes:

$ git checkout -b inbox master
$ git pull git@github.com:cuchac/lino.git export_excel_datetime
remote: Counting objects: 6, done.
remote: Compressing objects: 100% (3/3), done.
remote: Total 6 (delta 4), reused 5 (delta 3)
Unpacking objects: 100% (6/6), done.
From github.com:cuchac/lino
 * branch            export_excel_datetime -> FETCH_HEAD
Merge made by the 'recursive' strategy.
 lino/modlib/export_excel/models.py | 21 +++++++++++++++++++--
 1 file changed, 19 insertions(+), 2 deletions(-)

Test the changes:

$ inv test
[localhost] local: python setup.py -q test
...........................................
----------------------------------------------------------------------
Ran 43 tests in 36.290s

OK

Done.

Reactivate master and merge the changes:

$ git checkout master
M   docs/tutorials/pisa/pisa.Person-1.pdf
Switched to branch 'master'
Your branch is up-to-date with 'origin/master'.

$ git merge --no-ff inbox
Merge made by the 'recursive' strategy.
 lino/modlib/export_excel/models.py | 21 +++++++++++++++++++--
 1 file changed, 19 insertions(+), 2 deletions(-)

Note: is the --no-ff option necessary?

Push everything to the master:

$ git push origin master
Counting objects: 43, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (11/11), done.
Writing objects: 100% (11/11), 1.39 KiB | 0 bytes/s, done.
Total 11 (delta 8), reused 0 (delta 0)
To git@github.com:lsaffre/lino.git
   988adf9..55961b9  master -> master

And finally delete the inbox branch:

$ git branch -v --merged
  inbox  bfd3f39 Merge branch 'export_excel_datetime' of github.com:cuchac/lino into inbox
* master 55961b9 Merge branch 'inbox'

$ git branch -d inbox
Deleted branch inbox (was bfd3f39).

How to fetch a remote pull request

git fetch origin pull/999/head:my-branch
git checkout my-branch

Where 999 is the number of the pull request and my-branch the name of the branch.

Bibliography