Git & Github

A crash course

2019 Antoine Mayerowitz

“Git is too complicated”

Overview

  1. What is git ?
  2. Setting up
  3. Repositories
  4. The three states
  5. Typical workflow
  6. Branches
  7. Merging
  8. When it gets dirty
  9. Github
  10. Going further
What is git?

What is git?

“Git is a free and open source distributed version control system designed to handle everything from small to very large projects with speed and efficiency.”

Basically, git allows you to keep track of every changes and:

  • Who made these changes
  • What are these changes
  • When did it changes
Setting up

Setting up

Mac

                antoine@gitcrashcourse$ ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
                antoine@gitcrashcourse$ brew install git
             

Windows

Download and install

GNU/Linux

It depens on your distribution, but you probably already know that.

Basic config

                  antoine@gitcrashcourse$ git config --global user.name "<My name>"
                  antoine@gitcrashcourse$ git config --global user.email <My email>
              
Repositories

Repositories

A git repository is like a git project folder. It contains all the history of every files in it.

There are two ways of setting a Git repository:

  1. Init a repository from a local directory
  2. Clone an existing remote repository

We will learn the first method for now !

git init:

Initiate a git repository

              antoine@~$ mkdir gitcrashcourse && cd gitcrashcourse <- create a new folder and go into it
              antoine@gitcrashcourse$ git init
              Initialized empty Git repository in /Users/antoine/gitcrashcourse/.git/
            

That's it! You got your first repository

The three states

The three states

Your local repository consists of three "trees" maintained by git.

  1. The Working Directory which holds the actual files. This is where you work
  2. The Index which acts as a staging area.
  3. The HEAD which points to the last commit you've made.

DON'T PANIC, we'll get through it in the next section

Typical Workflow

Typical Workflow

Let's make some changes in our new repo!
                antoine@gitcrashcourse$ echo "Hello World" > hello_world.txt <- creates a text file
                antoine@gitcrashcourse$ cat hello_world.txt <- print the content of our file
                Hello World
            
Now let's save this badass code!

git status:

See the state of your local repository

              antoine@gitcrashcourse$   git status
              On branch master

              No commits yet
              
              Untracked files:
                (use "git add ..." to include in what will be committed)
              
                hello_world.txt
              
              nothing added to commit but untracked files present (use "git add" to track)
           

Hey look, git tells us that there is a new file!

git add:

Add file(s) to the staging state to track them.

              antoine@gitcrashcourse$ git add hello_world.txt
              antoine@gitcrashcourse$ git status
              On branch master

              No commits yet
              
              Changes to be committed:
                (use "git rm --cached file..." to unstage)
              
                new file:   hello_world.txt
             

Now git tracks our file, but it is not commited yet

git commit:

Save tracked changes from the staging area to the HEAD.

            antoine@gitcrashcourse$ git commit -m "my first commit"
            [master (root-commit) acaad7c] my first commit
              1 file changed, 1 insertion(+)
              create mode 100644 hello_world.txt
             

Done!... Well ... what've changed ?

Git allows you to track changes, remember ?

git log:

See the commits history.

              antoine@gitcrashcourse$ git log
              Author: Antoine Mayerowitz < antoine@mayerowitz.io > <- Who
              Date:   Tue Apr 2 13:32:33 2019 +0200 <- When

              my first commit <- What
             

Let's recap !

  • We add to tell git to track our file.
  • We stage (also using add...) to tell git the current state of the file.
  • Finally we commit to save the changes we made on tracked files.

Exercise: Add changes to hello_world.txt and commit those changes!

                antoine@gitcrashcourse$ date >> hello_world.txt <- Add new line with the date
                antoine@gitcrashcourse$ cat hello_world.txt
                Hello World
                  Tue Apr  2 13:48:52 CEST 2019
            
                antoine@gitcrashcourse$ git status
                On branch master
                    Changes not staged for commit:
                      (use "git add < file >..." to update what will be committed)
                      (use "git checkout -- < file >..." to discard changes in working directory)
                    
                      modified:   hello_world.txt
                    
                    no changes added to commit (use "git add" and/or "git commit -a")
            
                antoine@gitcrashcourse$ git add hello_world.txt
                antoine@gitcrashcourse$ git status
                On branch master
                    Changes to be committed:
                      (use "git reset HEAD < file >..." to unstage)
                    
                      modified:   hello_world.txt
            
                antoine@gitcrashcourse$ git commit -m "my second commit"
                [master a7a9d44] my second commit
                1 file changed, 1 insertion(+)
                antoine@gitcrashcourse$ git status
                On branch master
                    nothing to commit, working tree clean
            

Yeah!

                antoine@gitcrashcourse$ git log
                commit a7a9d4417359b9a201a71fb1b1d63ac045e2abce (HEAD -> master)
                    Author: Antoine Mayerowitz < antoine@mayerowitz.io >
                    Date:   Tue Apr 2 14:00:34 2019 +0200
                    
                        my second commit
                    
                    commit acaad7c5f17eed84ece418e3df981559de09bb01
                    Author: Antoine Mayerowitz < antoine@mayerowitz.io >
                    Date:   Tue Apr 2 13:32:33 2019 +0200
                    
                        my first commit
            
Branches

Branches

What are branches ?

  • A parallel version of your repository
  • The "master" branch is git's default

Why using branches ?

  • To isolate your work from others
  • To experiment new things
  • To keep your workspace clean

When to use branches ?

  • When you develop a new feature
  • When you don't want to overwrite previous code yet

Tip: Do not edit your Master branch directly when you work within a team. It's better practice to create another branch and merge it when you are ready

Create a branch

                antoine@gitcrashcourse$ git checkout -b development
                Switched to a new branch 'development'
           

You can also use git branch <branchname> but you won't checkout automatically to this branch

Making some changes

Let's add some experimental things to our new branch

                antoine@gitcrashcourse$ echo "Experimental code" >> hello_world.txt
                antoine@gitcrashcourse$ cat hello_world
                Hello World
                    Tue Apr  2 13:48:52 CEST 2019
                    Experimental code
             

Check the status

                  antoine@gitcrashcourse$ git status
                  On branch development
                      Changes not staged for commit:
                        (use "git add <file> ..." to update what will be committed)
                        (use "git checkout -- <file>..." to discard changes in working directory)
                      
                        modified:   hello_world.txt
                      
                      no changes added to commit (use "git add" and/or "git commit -a")
               

Notice that Git tells us we are on the development branch

Stage and commit

              antoine@gitcrashcourse$ git add hello_world.txt
              antoine@gitcrashcourse$ git commit -m "Experimental feature"
              [development 9344d4e] Experimental feature
                  1 file changed, 1 insertion(+)
            

List all branches

              antoine@gitcrashcourse$ git branch
              * development
              master
            

The master branch is the one created by default!

Switch branch

Maybe you will want to go back on master branch?

                antoine@gitcrashcourse$ git checkout master
                Switched to branch 'master'
                Your branch is up to date with 'origin/master'.
                antoine@gitcrashcourse$ git branch
                development
                * master
                antoine@gitcrashcourse$ cat hello_world.txt
                Hello World
                    Tue Apr  2 13:48:52 CEST 2019 
            

Exercise:

  • Create a new branch test
  • Switch to this branch and create a new file bad_idea.txt with some text in it
  • Stage and commit this file
  • Switch back to master and delete this branch with git branch -D <branchname>
Merging

Merging

What if I want to get the changes of one branch into another?

Git merge !

Merging dev into master

Be sure to be on master !

                antoine@gitcrashcourse$ git checkout master
                antoine@gitcrashcourse$ git merge development
                Updating a7a9d44..9344d4e
                Fast-forward
                 hello_world.txt | 1 +
                 1 file changed, 1 insertion(+)
            
So simple!

There can be conflicts!

Let's create some modifications in development:

                  antoine@gitcrashcourse$ git checkout development
                  antoine@gitcrashcourse$ sed -i '' 's/World/Friends/' hello_world.txt <- replace World by Friends
                  antoine@gitcrashcourse$ git add hello_world.txt
                  antoine@gitcrashcourse$ git commit -m "change line 1"
              

And also in master:

                  antoine@gitcrashcourse$ git checkout master
                  antoine@gitcrashcourse$ sed -i '' 's/World/You/' hello_world.txt
                  antoine@gitcrashcourse$ git add hello_world.txt
                  antoine@gitcrashcourse$ git commit -m "change line 1"
              

Our two files should look like this:

master

                  Hello You
                  Tue Apr  2 13:48:52 CEST 2019
                  Experimental code
              

development

                    Hello Friends
                    Tue Apr  2 13:48:52 CEST 2019
                    Experimental code
                

What will happen when we'll merge?

Let's try to merge automatically

Don't forget to go on the master branch !

                antoine@gitcrashcourse$ git merge development
                Auto-merging hello_world.txt
                    CONFLICT (content): Merge conflict in hello_world.txt
                    Automatic merge failed; fix conflicts and then commit the result.
            

Oupsie! Guess we'll have to do it by hand.

What does our file looks like ?

                <<<<<<< HEAD
                Hello You
                =======
                Hello Friends
                >>>>>>> development
                Tue Apr  2 13:48:52 CEST 2019
                Experimental code
              

We need to manually edit the file and keep our favorite version.

Don't forget to delete the git tags during the process! You can also make any other changes you like, just make it work!

Save your file when your done.

                  Hello Friends
                  Tue Apr  2 13:48:52 CEST 2019
                  Experimental code
                

Let's finish this merging !

We're close..

                  antoine@gitcrashcourse$ git add hello_world.txt
                  antoine@gitcrashcourse$ git commit -m "Fix merge conflict"
                  [master 5059be6] Fix merge conflict
                

Done !

Exercise:

  • Create a new branch.
  • Create a new file mastering_git.txt with some text.
  • Stage and commit those changes.
  • Merge your newly created branch into master.
When it gets dirty

When it gets dirty

It's human to make some mistakes. Here are some ways to revert them.

Undo unstaged local changes:

git checkout <myfile>

                antoine@gitcrashcourse$ echo "some text" >> hello_world.txt
                antoine@gitcrashcourse$ cat hello_world.txt
                Hello Friends
                    Tue Apr  2 13:48:52 CEST 2019
                    Experimental code
                    some text
                antoine@gitcrashcourse$ git checkout hello_world.txt
                antoine@gitcrashcourse$ cat hello_world.txt
                Hello Friends
                    Tue Apr  2 13:48:52 CEST 2019
                    Experimental code
              

Undo staged changes:

git reset HEAD <myfile>

                  antoine@gitcrashcourse$ echo "some staged changes" >> hello_world.txt
                  antoine@gitcrashcourse$ git add hello_world.txt
                  antoine@gitcrashcourse$ git status
                  On branch master
                    Changes to be committed:
                    (use "git reset HEAD ..." to unstage)
                                 modified:   hello_world.txt
                  antoine@gitcrashcourse$ git reset HEAD hello_world.txt <- unstaging
                  Unstaged changes after reset:
                      M	hello_world.txt
                  antoine@gitcrashcourse$ git checkout hello_world.txt <- undo changes
                

Undo commited changes!

git revert <myfile>

                  antoine@gitcrashcourse$ echo "some committed changes" >> hello_world.txt
                  antoine@gitcrashcourse$ git add hello_world.txt
                  antoine@gitcrashcourse$ git commit -m "commit to revert"
                  [master afd6c39] commit to revert
                      1 file changed, 1 insertion(+)
                  antoine@gitcrashcourse$ git log
                  commit afd6c398e5e6fe00d31d3218762be5035e635ef4 (HEAD -> master)
                      Author: Antoine Mayerowitz 
                      Date:   Tue Apr 2 17:29:30 2019 +0200
                      
                          commit to revert
                      [...]  
                  antoine@gitcrashcourse$ git revert --no-edit afd6c398e5e6fe00d31d3218762be5035e635ef4
                

You can also use git reset to cancel a commit but we won't cover that

Bonus: Ignoring files

You can use the .gitignore to ignore some extensions

                  antoine@gitcrashcourse$ zip hello_world.zip hello_world.txt
                  antoine@gitcrashcourse$ git status
                  On branch master
                      Untracked files:
                        (use "git add ..." to include in what will be committed)
                        hello_world.zip
                      
                  antoine@gitcrashcourse$ echo "*.zip" > .gitignore <- ignore all zip files
                  antoine@gitcrashcourse$ git status
                  On branch master
                      Untracked files:
                        (use "git add < file >..." to include in what will be committed)
                        .gitignore <- No more zip files !
                

Having a gitignore in your project is great to keep it clean !

Github

Github

Git ≠ Github

Github is a commercial website that allows users to host Git repositories. It comes with popular extra features.

We'll also need to learn a bit of extra git commands ...

But first let's create an account.

Create a new repository:

Give it a name and the description you like.

A common practice is to give the repo the same name as your directory.

We will use the third method:

                    antoine@gitcrashcourse$ git remote add origin https://github.com/SuperMayo/gitCourseExample.git <- Do not copy-paste !!!!
                    antoine@gitcrashcourse$ git push -u origin master
                    Counting objects: 20, done.
                        Delta compression using up to 4 threads.
                        Compressing objects: 100% (12/12), done.
                        Writing objects: 100% (20/20), 1.83 KiB | 939.00 KiB/s, done.
                        Total 20 (delta 2), reused 0 (delta 0)
                        remote: Resolving deltas: 100% (2/2), done.
                        To https://github.com/SuperMayo/gitCourseExample.git
                         * [new branch]      master -> master
                        Branch 'master' set up to track remote branch 'master' from 'origin'.
                

Github may ask you your credential for the first time.

Go back to your repository on Github ...

We've just seen some new functions:

  • git remote add: sets an online repository (by convention it's called "origin").
  • You can check your remote repositories with git remote

  • git push: sends local commit to the given remote repository
  • The -u option is used only once to define the upstream (=default) remote. Then you use it like git push <remote name> <branch name>

Let's add the development branch as well.
Try to do it yourself!

                  antoine@gitcrashcourse$ git push origin development
                

What happen if someone else changes something on the remote repository ?

Let simulate that by editing directly on github!

Now go back to your console.

If I try to push new changes...

                    antoine@gitcrashcourse$ git add .gitignore
                    antoine@gitcrashcourse$ git commit -m "add gitignore"
                    antoine@gitcrashcourse$ git push origin master
                    o https://github.com/SuperMayo/gitCourseExample.git
                        ! [rejected]        master -> master (non-fast-forward)
                       error: failed to push some refs to 'https://github.com/SuperMayo/gitCourseExample.git'
                       hint: Updates were rejected because the tip of your current branch is behind
                       hint: its remote counterpart. Integrate the remote changes (e.g.
                       hint: 'git pull ...') before pushing again.
                       hint: See the 'Note about fast-forwards' in 'git push --help' for details.
                

I get an error because my local repo is "behind" the remote.

I need to get the updates from the remote.

git pull !

Git pull will download and merge the remote repo with your HEAD.

                    antoine@gitcrashcourse$ git pull --no-edit
                    Merge made by the 'recursive' strategy.
                        hello_world.txt | 1 +
                        1 file changed, 1 insertion(+)
                    antoine@gitcrashcourse$ git status
                    On branch master
                        Your branch is ahead of 'origin/master' by 2 commits.
                          (use "git push" to publish your local commits)
                        
                        nothing to commit, working tree clean
                

Finally, we can push our work !

                  antoine@gitcrashcourse$ git push origin master
                  Counting objects: 5, done.
                      Delta compression using up to 4 threads.
                      Compressing objects: 100% (4/4), done.
                      Writing objects: 100% (5/5), 616 bytes | 616.00 KiB/s, done.
                      Total 5 (delta 0), reused 0 (delta 0)
                      To https://github.com/SuperMayo/gitCourseExample.git
                         d627d09..3e7310b  master -> master
              

DONE !

Github at its best

Usually, when working within a team, you want to keep a "stable" version of your repo(most of the time it's the master branch). You also want your teammates to validate your work before merging it into master.

Pull Requests !

A pull request is the way to ask the admin(s) of a remote repository to incorporate your changes

Let's imagine that you work on our previous project. You just created a new feature, added new data, cleaned some files ...

Go back to your console!

                    antoine@gitcrashcourse$ git checkout -b new-feature
                    antoine@gitcrashcourse$ echo "New feature to be reviewed" > feature.txt
                    antoine@gitcrashcourse$ git add * <- the star is a way to stage everything in our repo
                    antoine@gitcrashcourse$ git commit -m "New feature to do X"
                    antoine@gitcrashcourse$ git push origin new-feature
                    Counting objects: 3, done.
                        Delta compression using up to 4 threads.
                        Compressing objects: 100% (2/2), done.
                        Writing objects: 100% (3/3), 352 bytes | 352.00 KiB/s, done.
                        Total 3 (delta 0), reused 0 (delta 0)
                        remote:
                        remote: Create a pull request for 'new-feature' on GitHub by visiting:
                        remote:      https://github.com/SuperMayo/gitCourseExample/pull/new/new-feature
                        remote:
                        To https://github.com/SuperMayo/gitCourseExample.git
                         * [new branch]      new-feature -> new-feature
                  

Now you want those changes to be reviewed by your teammates before incorporating them in the master branch.

Go back to Github!

Go on the pull request tab.

Select the branch you wish to merge.

A lot of info here. When you are ready you can create the pull request.

It's a good thing to write a message to explain what you've done!

Yeah!

To go further

To go further

Many other things to cover:

  • Git fetch, rebase, stash, ...
  • Issues
  • Forks
  • Citable code
  • Continuous integration, Readme, Projects, Organizations, ...

And many more ...

IT'S DANGEROUS TO GO ALONE! TAKE THIS.

Thank you!