Version Control Using Git

SPACE for next slide

Shift+SPACE for previous slide

Prerequisites

Basic terminal commands

Imagining a world without version control systems

Team members keep different copies of the same project

Using a service to send files that were changed

The other person spends some time reviewing the changes

Manually merge the code

More back and forth on messaging services

On completion the boss takes the credit from his co-workers

Time passes

Code breaks

No track of changes

Code needs fixing or write the project from scratch

Vicious loop begins

Aim of VC Systems

  • Can keep multiple working states with the help of branches
  • Can help in reverting to any change made in the past
  • Helps in merging two different branches
  • Retains the time and author of a set of changes
  • Provides an API to query software history

What is Git?

Git is the most popular version control system started by Linus Torvalds as a replacement for BitKeeper.

Save a copy

git-xkcd-save-a-copy.png

Key terms

  • State / Commit / Changeset
  • Branch
  • Remote

Note

Git commands only work when you are currently inside a directory having the .git/ subdirectory.

Dirs where git commands work

If a .git/ dir is at:

~/projects/favproject/.git/

then you can run git commands from:

  • ~/projects/favproject/ or
  • ~/projects/favproject/subdir/

Dirs where git commands don’t work

If a .git/ dir is at:

~/projects/favproject/.git/

then you can not run git commands from:

  • ~/ or
  • ~/favproject/ or
  • ~/projects/favproject/.git/

Lets get started

Open terminal and create a new Git repository

git init ~/newproject  # make .git/
cd ~/newproject
# Now we can run git commands

Setting up Author details

One time setup:

git config --global user.name  'Ratan Tata'
git config --global user.email 'ratantata@tata.com'

On a per repository basis one can do:

git config user.name  'Secret Org'
git config user.email 'secretname@secret.org'

Set up $EDITOR

EDITOR=emacs

You can use the following in your ~/.profile or ~/.bashrc

export EDITOR=emacs

Hello, World! in Python

hello.py:

print("Hello, World!")

Running the script:

python3 hello.py

State

A state comprises of:

  • changes
  • timestamp
  • author
  • id
  • parent id

Creating new states/commits

  • First, select which changes will be added to the state
  • The unselected ones are part of Git’s unstaged changes
  • The selected ones are part of Git’s staged changes
  • Once the selection is done we can commit the changes

git status

Check if files were changed since the last commit. It shows:

  • Selected/Staged files
  • Unselected/Unstaged files
  • Unknown/Untracked files

Ignoring useless files

To ignore some files we need to add a file called .gitignore with the following contents:

*.pyc
__pycache__/

What files are good to ignore?

  • Binaries
  • External dependencies
  • Build outputs
  • Cache
  • Databases

How to select/stage files

git add hello.py   # add to staging area

How to unstage files

git reset HEAD -- hello.c

Commiting the state

Add the state to the history:

git commit    # Opens your $EDITOR

Then type in an appropriate message. Save and exit.

Tip

Keep your changes short and commit messages descriptive.

It is hard to achieve but start from now and hopefully you will start to embrace it and make others happy.

Commit often

This will help you achieve the above.

Tired of commits

git-xkcd-bad-commits.png

Branch

  • After commiting, the states become a part of a branch.
  • The default branch name is master.
  • Local branch names are simply named as <branch>.
  • Corresponding remote branch name are named as <remote>/<branch>.
  • Helps to create different timelines.
  • Technically, it is a pointer to a specific commit.

List all branches

git branch -a

Creating a new branch

git branch test  # branch from current commit

Switching to a branch

git checkout test

Now the commits will be added to test branch.

HEAD

  • HEAD is a special branch
  • Wherever you go, HEAD follows you
  • When you checkout to a commit/branch, you change position of HEAD
  • When you add a new commit, HEAD moves forward along with the branch to which HEAD points to

Change in program

def greetings(name):
    print(f"Hello, {name}!")

if __name__ == '__main__':
    import sys
    greetings(sys.argv[1])

Running the program:

python3 hello.py "Ratan Tata"
Hello, Ratan Tata!

Then?

  1. Check if you made any changes
  2. Select/Add files
  3. Commit

View the log

git log --all --graph \
    --decorate \
    --pretty=oneline \
    --abbrev-commit

It is recommended that you alias this long command in your ~/.bashrc:

alias gitlog='git log --all --graph \
      --decorate \
      --pretty=oneline \
      --abbrev-commit'

You can also run the above command in your current bash session for it to take effect.

Merging two branches

Lets say our feature is complete and we want to merge it into master.

Here master is our destination branch and test is our source branch.

So, first we switch to destination branch using git checkout master.

Then we use git merge test to merge the source branch.

Going deeper

git stash

  • A feature to temporarily store the changes without commiting
  • Since its not commited, you can access it from any branch/commit
  • git stash list lists all the stashes
  • Changes can be brought back using git stash pop
  • Stack based. Which means, poping a stash will bring in the last changes.
  • git stash show -p stash@{1} shows the changes in a stash

git checkout

  • This command changes the state of the repository and allows you to time travel
  • git checkout -b newbranch 09abcd creates a new branch and switches to it starting at 09abcd
  • git checkout 09abcd switches to the commit

git remote

  • Use git remote add <some_name> https://some_url.git to add a new remote
  • After adding remote one can easily refer <some_name> to git pull <some_name>
  • Use git remote remove <some_name> to remove a remote
  • Default remote name is origin
  • To list all remotes do git remote -v

git fetch

  • It is used to fetch branches and tags from a remote
  • If you use multiple remotes, you can use git fetch --all
  • This will only update remote branches with names <remote>/<branch>
  • This will not update local branches with names <branch>

git pull

  • It is used to update local branches after fetching
  • First it does git fetch then git merge <remote>/<branch>
  • Recommended to use git pull --rebase

Some scenarios

Part of feature done but a critical bug fix requires attention

Solution 1

  • git stash
  • fix bug
  • git commit
  • git stash pop

Solution 2

  • git checkout -b newbranch
  • git commit
  • git checkout original
  • fix bug
  • git commit

Modify the last commit message

git commit --amend

Add more files to the last commit

  • git reset --soft HEAD~1 which removes last commit but keeps its changes
  • git add missed-file.txt
  • git commit

Different types of merging strategies

https://www.freecodecamp.org/news/an-introduction-to-git-merge-and-rebase-what-they-are-and-how-to-use-them-131b863785f/

Complexity of git merge

git-xkcd-merge.png

Fast forward

  • git merge --ff <branch>
  • Simplest
  • No merge conflict
  • Branch reference is updated to the latest commit which makes it look like full history was copied
  • It is the default strategy when we try to git pull without --rebase
  • Not always possible

No fast forward

  • git merge --no-ff <branch>
  • Always creates a new commit which has 2 parents, one from current branch and one from the source branch
  • When fast forward fails, git pull without --rebase uses this strategy
  • Always possible
  • New merge commit is like a noise in the commit history

Rebase

  • git rebase <branch>
  • Always possible
  • Clumsier than other two in some cases
  • Doesn’t create any new commit
  • More risky, so don’t rebase on a public branch (like master)
  • Rebase temporary feature branches

The End

The End?

You can start learning more using the following ways:

  • man gittutorial and man gittutorial-2
  • For specific help on commands try:
    • man git-status
    • git help status
    • git status --help
  • Check on the internet for more solutions
  • Reach out to team members if you feel confused