Skip to content

Git Basics

ChrisMurphy3 edited this page Nov 9, 2017 · 10 revisions

Lesson 0 Installing Git

Lesson 0.1: What is git

  • Distributed source version control
  • Made by Linus Torvalds.
  • What the linux project uses!

Lesson 1: Configuring Git

1.1 Three levels of configuration

  • Local: Specific to the repo.
  • Global: For all repositories of the user. Most common
  • System: For build computers, for example. Uses the whole system.

1.2 Basic Configuration settings

This commands gets the user or sets the user

$ git config --global user.name
cmurphy
$ git config --global user.email
[email protected]

The gitconfig file can be edited:

$ cat ~/.gitconfig
[user]
	name = cmurphy
	email = [email protected]
[gc]
	autoDetach = false

1.3 Configuring Line endings

  • Windows uses Carriage Return Line Feed (CRLF)
  • Linux/Mac uses only Line Feed (LF)

The recommended setting is:

  • Windows should put the CR when pulling:
    $ git config --global core.autocrlf true
    
  • Linux uses this so files removes CR and leaves LF:
    $ git config --global core.autocrlf input
    

1.4 Configuring aliases

Aliases allow to create own git commands with different options to make them easier to use. They can be checked by cat ~/.gitconfig.

Some useful aliases are:

  • Run status in silent mode:
    $ git config --global alias.s "status -s"
    
  • Log on special options
    $ git config --global alias.lg "log --oneline --all --graph --decorate"
    

Lesson 2: Getting Started with Git

2.1 Creating your first Git repository

Git status gives the status of the git repo, and shows an error if there is no repo on the present directory.

$ git status
On branch master
Your branch is up-to-date with 'origin/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:   cmurphy/Git/Git_and_Github_Lessons/02_GettingStarted_with_git.md

no changes added to commit (use "git add" and/or "git commit -a")

Git init allows to make a new repository

$ git init web1
Initialized empty Git repository in C:/cmurphy/Documents/cmurphy/web1/.git
$ cd web1/
$ git status
On branch master

Initial commit

nothing to commit (create/copy files and use "git add" to track)

2.2 Committing in Git

Git uses a 3 stage approach:

  1. Non staged files
  2. Staging area. We can change files
  3. Repository.

The Getting Started - Git Basics illustrates this as follows:

Git has three main states that your files can reside in: committed, modified, and staged. Committed means that the data is safely stored in your local database. Modified means that you have changed the file but have not committed it to your database yet. Staged means that you have marked a modified file in its current version to go into your next commit snapshot.

This leads us to the three main sections of a Git project: the Git directory, the working directory, and the staging area.

Working directory, staging area, and Git directory.

Figure 1-6. Working directory, staging area, and Git directory.

Figure 1-6. Working directory, staging area, and Git directory.

The Git directory is where Git stores the metadata and object database for your project. This is the most important part of Git, and it is what is copied when you clone a repository from another computer.

The working directory is a single checkout of one version of the project. These files are pulled out of the compressed database in the Git directory and placed on disk for you to use or modify.

The staging area is a file, generally contained in your Git directory, that stores information about what will go into your next commit. It’s sometimes referred to as the “index”, but it’s also common to refer to it as the staging area.

The basic Git workflow goes something like this:

You modify files in your working directory.

You stage the files, adding snapshots of them to your staging area.

You do a commit, which takes the files as they are in the staging area and stores that snapshot permanently to your Git directory.

If a particular version of a file is in the Git directory, it’s considered committed. If it has been modified and was added to the staging area, it is staged. And if it was changed since it was checked out but has not been staged, it is modified. In Git Basics, you’ll learn more about these states and how you can either take advantage of them or skip the staged part entirely.

$ touch index.html
$ git status
On branch master

Initial commit

Untracked files:
  (use "git add <file>..." to include in what will be committed)

        index.html

nothing added to commit but untracked files present (use "git add" to track)

$ git add .
$ git status
On branch master

Initial commit

Changes to be committed:
  (use "git rm --cached <file>..." to unstage)

        new file:   index.html
$ touch index.css
$ git status
On branch master

Initial commit

Changes to be committed:
  (use "git rm --cached <file>..." to unstage)

        new file:   index.html

Untracked files:
  (use "git add <file>..." to include in what will be committed)

        index.css
$ git add .
$ git status
On branch master

Initial commit

Changes to be committed:
  (use "git rm --cached <file>..." to unstage)

        new file:   index.css
        new file:   index.html

$ git commit -m "Added home page"
[master (root-commit) 57f2084] Added home page
 2 files changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 index.css
 create mode 100644 index.html

2.3 Understanding a Git commit

  • The hash allows to know the unique identifier for a commit
  • Shows insertions and deletions
  • Shows a code for the files, symbolic links, one for executables and one for everything else.

2.4 The benefits of the staging area

  • Do meaningful commit messages
  • Using git status -s on untracked files:
    $ git s // also git status -s
    ?? about.css
    ?? about.html
    ?? contact.css
    ?? contact.html
    
  • To make commits in groups, not using git add . or individual files:
    $ git add ab*
    $ git status -s
    A  about.css // A stands for 'Added'
    A  about.html
    ?? contact.css
    ?? contact.html
    $ git commit -m "Added about us page"
    

2.5 Git log for viewing history

  • Git log allows us to look at history
  • git log gives a complete log with complete sha1 hash, author, name, email, full commit message, date and time of commit.
  • For more concise:
    $ git log --oneline --decorate
    78ec186 (HEAD, master) Added contact us page
    84f53ea Added about us page
    
  • The HEAD is where we currently committed. Is the particular point in the git history where we are checked out. Is the stuff we have in the current working directory. You can think of HEAD is a reference to the top of the current branch (tree).

Lesson 3: Getting Started with GitHub

Clone the Repo

git clone [email protected]:ibm-cork-coderdojo-projects/git_beginners.git
cd git_beginners
echo " # cmurphy : member" >> README.md
git add README.md
git status
git commit -m "first commit"
git push -u origin master

3.1 Creating a repository in GitHub

3.2 Uploading your repo to GitHub

Create a new repository on the command line

echo "# web1" >> README.md
git init
git add README.md
git commit -m "first commit"
git remote add origin https://github.com/ibm-cork-coderdojo-projects/git_beginners_2.git
git push -u origin master

Push an existing repository from the command line

git remote add origin  https://github.com/ibm-cork-coderdojo-projects/git_beginners_2.git
git push -u origin master

3.3 Creating a repository after starting to code

  • Git repos can be initialized after the files already exist.

Lesson 4: Files in Git—Renaming, Deleting and Ignoring

4.1 How to rename a file in Git

There are two ways:

  1. Using git mv filename.old filename.new. This moves the file to the staging area, but does not commit it.
  2. Using another mean. This will make git consider the old file deleted and added a new one. To maintain the history (add all files even deleted files):
$ git add -A

Keep in mind that git add . in git versions before 2.0 does not add the deleted files to the staging area. Git is able to determine is the same file by using a similarity index a decimal between 0-1 where 0 is no similarity and 1 is the same. Values of similarityIndex >= 0.5 is determined by git that is the same file. For this reason, in general you should not rename files on the same commit that changes are made. This could be different for other tools. Also, don't remove a file from one place and the same commit add another similar file for the same reason.

4.2 Deleting a file in Git

Also two options:

  1. Using git rm fileToDelete. This removes the file and stages the deletion.
  2. Using another mean, e.g. the file explorer, etc. This will mark the file deleted but not staged. Use
$ git add -A

to stage the changes.

4.3 Ignoring files using a .gitignore file

Ignoring is useful to mark files so they are not in the repository. To do that, we use the .gitignore file. Making the ignore file will already put it into effect, if any files is affected, i.e. if there is a test.log file in the path that has not been staged and the contents of the .gitignore file are:

*.log

then the test.log will be ignored. Note that the .gitignore file is designed to be shared. If in doubt, put it on the ignore

A different git ignore file in a different directory of the file. But avoid this, since having a single file allows for a centralized place for ignoring files.

4.4 Global gitexcludes and other Git ignore options

Is a blanket case, but has risks, since it ignores files in all projects you work with. To create:

$ git config --global core.excludesfile ~/.gitignore

Note: Use only for file you know no body in your team will use.

To locally ignore files, use the .git/info/exclude file.

4.5 Git ignore precedence

The precedence is as follows:

  1. The global .gitignore
  2. The project root .gitignore
  3. The local subdirectory .gitignore

Precedence matters, so closer to the 1 on the scale, the higher priority. Also, the precedence always matter in the file. The file is read from top to bottom.

4.6 Git commit -a

  • The command git commit -am does "add" as well as "commit". Has a warning message, so it only works into modified tracked files. Does not work on untracked files.

Lesson 5: Branching, Merging and Rebasing

5.1 Introducing branching

  • The purpose of a branch is to allow to create an independent line of work

  • Is a local operation

  • $ git branch shows the existing branch

  • The master branch is the default branch. Don't use trunk, thats not git-like. The master is the production branch

  • Feature branches should be done every time a new feature is introduced. For example for creating a search feature:

    $ git branch search
    $ git checkout search
    
  • When reading git log --oneline --all --graph --decorate, start from top to bottom.

  • To push a branch to the remote we need to create it and then create a corresponding branch on the remote:

    $ git checkout -b a_branch
    $ git push -u origin a_branch
    
    • The -u option is just short for --set-setupstream. This will add an upstream tracking reference for the current branch.

5.2 Merging a branch

  • To bring a branch in a branch, go back to the branch you want to merge into and then merge the branch.
    $ git checkout master
    $ git merge search
    
  • To delete a branch after the merge. This does not delete the commits from the branch.
    $ git branch -d search
    

5.3 Creating a fast forward merge

There are two types of merges in git most commonly: fast forward and recursive.

  • The fast forward merge:
    • To make a branch and checkout directly: git checkout -b categories
    • Then checkout the branch to whcih to merge into and then merge the branches into it
      $ git checkout master
      $ git merge products
      Updating 6c863ad..43b37e8
      Fast-forward
      products.hmtl | 0
      1 file changed, 0 insertions(+), 0 deletions(-)
      create mode 100644 products.hmtl
      

5.4 Introducing recursive merges

  • No difference in history makes a fast forward merge, i.e. no difference between the master and the current branch. It is assumed the master just advances to the status of the branch.
  • When both branches have different commits, the resolve needs to be done by a recursive merge, putting two streams and creating a new commit to bring them together.
    • This usually opens an editor and expects a commit message. Some OS defaults the commit message.

      $ git merge categories
      Merge made by the 'recursive' strategy.
      categories.html | 0
      1 file changed, 0 insertions(+), 0 deletions(-)
      create mode 100644 categories.html
      $ git lg
      *   1f2a155 (HEAD -> master) Merge branch 'categories'
      |\  
      | * d5853d8 (categories) Added categories
      * | 43b37e8 Commited products page
      |/  
      * 6c863ad Added search page
      
  • Recursive merges show where the branch was from. Sometimes the fast forward merges is not easy to see from the merged branch.

5.5 “No fast forward” recursive merges

When fast forward merges are not wanted but will happen, is possible to mark them explicitly for that:

$ git log --oneline --all --graph --decorate
* 282f1cc (HEAD -> my_account) Added my account css
* 2373699 Added my account page
*   1f2a155 (master) Merge branch 'categories'
|\  
| * d5853d8 Added categories
* | 43b37e8 Commited products page
|/  
* 6c863ad Added search page
$ git merge --no-ff my_account
Merge made by the 'recursive' strategy.
account.css  | 0
account.html | 0
2 files changed, 0 insertions(+), 0 deletions(-)
create mode 100644 account.css
create mode 100644 account.html

5.6 Resolving merge conflicts

  • This will happen when two branches or more modify the same files. There cannot be fast forward for this cases.
    $ git lg
    *   af67ff0 (master) Merge branch 'homepage_redesign'
    |\  
    | * d9ee191 Implemented home page redesign
    |/  
    | * abbbdac (HEAD -> cart) Added link on home page for shopping cart
    | * 48e6bf3 Added shopping cart
    |/  
    $ git merge cart
    Auto-merging home.htm
    CONFLICT (content): Merge conflict in home.htm
    Automatic merge failed; fix conflicts and then commit the result.
    
  • When merging conflicts, git status is your friend, it tells us where we are at and what we need to do. The unmerged path has to be fixed before the commit. Git only needs a text editor for it
    $ git status
    On branch master
    Your branch is ahead of 'origin/master' by 18 commits.
      (use "git push" to publish your local commits)
    You have unmerged paths.
      (fix conflicts and run "git commit")
    
    Changes to be committed:
    
    	new file:   cart.html
    
    Unmerged paths:
      (use "git add <file>..." to mark resolution)
    
        both modified:   home.htm
    $ vim home.htm
    <<<<<<< HEAD
    Company Logo!
    
    Links:
    - Products
    - Categories
    
    Copyrigth 2016
    =======
    link to cart
    >>>>>>> cart
    
    • The equals shows the different sides and the branch where is different. Don't add stuff in merges, just resolve them!
      • To resolve, use git add .
        $ git add .
        $ git status
        On branch master
        Your branch is ahead of 'origin/master' by 18 commits.
          (use "git push" to publish your local commits)
        All conflicts fixed but you are still merging.
          (use "git commit" to conclude merge)
        
        Changes to be committed:
        
        	new file:   cart.html
        	modified:   home.htm
        $ git commit
        

5.7 Git Diff

  • git diff allows to see the differences of modified files.

  • git help diff gives the usage of the command (or any other git command)

  • For example, if some changes happen in home.htm

    $ git diff
    diff --git a/home.htm b/home.htm
    index ea50146..db1180d 100644
    --- a/home.htm
    +++ b/home.htm
    @@ -5,7 +5,7 @@ Links:
     - Categories
     - Cart
     - About
    +- History
     - My Account
     -- Checkout
    
  • git diff shows only unstaged changes, for staged changes use git diff --staged

  • git diff HEAD shows the difference between the working directory and the last commit made (unstaged/staged changes, since there can be staged and unstaged changes on the same file)

    $ git s
    MM home.htm
    $ git diff --staged
    diff --git a/home.htm b/home.htm
    index ea50146..db1180d 100644
    --- a/home.htm
    +++ b/home.htm
    @@ -5,7 +5,7 @@ Links:
     - Categories
     - Cart
     - About
    +- History
     - My Account
    -- Checkout
    
     Copyrigth 2016
    $ git diff
    diff --git a/home.htm b/home.htm
    index db1180d..188179d 100644
    --- a/home.htm
    +++ b/home.htm
    @@ -1,9 +1,6 @@
     Company Logo!
    
     Links:
    -- Products
    -- Categories
    -- Cart
     - About
     - History
     - My Account
    $ git diff HEAD
    diff --git a/home.htm b/home.htm
    index ea50146..188179d 100644
    --- a/home.htm
    +++ b/home.htm
    @@ -1,11 +1,8 @@
     Company Logo!
    
     Links:
    -- Products
    -- Categories
    -- Cart
     - About
    +- History
     - My Account
    -- Checkout
    
     Copyrigth 2016
    

5.8 Introducing rebasing

Rebasing is an intermediate tool to improve the quality of the experience when collaborating. Two things use rebasing in git, they should be treated differently because they are made for different things:

  • git rebase: Change the starting point of the branch (base) before making merges
  • git rebase -i (interactive): Rewriting history to change order of commits, squash together or clean up for sharing with other people

5.9 Rebasing a branch

Assume two feature branches

$ git lg
* 6ffc391 (feature2) Added feature2
| * bece78a (feature1) Added feature1
|/  
* 23ff48b (HEAD -> master) Changed homepage links

After merging one, instead of keeping both feature branches, we can rebase feature2 (the starting point) for it to appear in the history after feature1. The base of feature 2 is 23ff48b Changed homepage links:

*   8e48a0e (HEAD -> master) Merge branch 'feature1'
|\  
| * bece78a Added feature1
|/  
| * 6ffc391 (feature2) Added feature2
|/  
* 23ff48b Changed homepage links

We want to rebase it so it appears in 8e48a0e (HEAD -> master) Merge branch 'feature1'. To do that:

$ git checkout feature2
Switched to branch 'feature2'
$ git rebase master
First, rewinding head to replay your work on top of it...
Applying: Added feature2
$ git lg
* dcd08f7 (HEAD -> feature2) Added feature2
*   8e48a0e (master) Merge branch 'feature1'
|\  
| * bece78a Added feature1
|/  
* 23ff48b Changed homepage links
*   b249d89 Merge branch 'checkout'

This will 'undo' the work of feature2, move to the HEAD of master and then redo the work using that as the base. The merge from feature2 to master can occur then.

5.10 Handling rebase conflicts

Assume 2 branches with conflicting changes. Merge one into master and the second one will create a conflict. The question is to whether rebase or merge the conflict. Fortunately is resolved the same. The merge conflict looks like this:

$ git rebase master
First, rewinding head to replay your work on top of it...
Applying: Featuring el cuatro
Using index info to reconstruct a base tree...
M	home.htm
Falling back to patching base and 3-way merge...
Auto-merging home.htm
CONFLICT (content): Merge conflict in home.htm
error: Failed to merge in the changes.
Patch failed at 0001 Featuring el cuatro
The copy of the patch that failed is found in: .git/rebase-apply/patch

When you have resolved this problem, run "git rebase --continue".
If you prefer to skip this patch, run "git rebase --skip" instead.
To check out the original branch and stop rebasing, run "git rebase --abort".

Note the line When you have resolved this problem, run "git rebase --continue". instead of suggesting git commit. Git status will tell us what to do:

$ git status
rebase in progress; onto e1215af
You are currently rebasing branch 'feature4' on 'e1215af'.
  (fix conflicts and then run "git rebase --continue")
  (use "git rebase --skip" to skip this patch)
  (use "git rebase --abort" to check out the original branch)

Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

	new file:   feature4.html

Unmerged paths:
  (use "git reset HEAD <file>..." to unstage)
  (use "git add <file>..." to mark resolution)

	both modified:   home.htm

After the conflict resolution, the merge can continue with git rebase --continue:

$ git add .
$ git status
rebase in progress; onto e1215af
You are currently rebasing branch 'feature4' on 'e1215af'.
  (all conflicts fixed: run "git rebase --continue")

Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

	new file:   feature4.html
	modified:   home.htm

$ git rebase --continue
Applying: Featuring el cuatro
cmurphy@cmurphy-pc ~/Documents/Projects/web1 $ git lg
* 85fa1d9 (HEAD -> feature4) Featuring el cuatro
*   e1215af (master) Merge branch 'feature3'
|\  
| * fc45c92 link to feature 3
| * e9b6c22 feature 3

5.11 Renaming branches

  1. Rename your local branch. If you are on the branch you want to rename:

    $ git branch -m new-name
    

    If you are on a different branch:

    $ git branch -m old-name new-name
    
  2. Delete the old-name remote branch and push the new-name local branch.

    $ git push origin :old-name new-name
    
  3. Reset the upstream branch for the new-name local branch. Switch to the branch and then:

    $ git push origin -u new-name