Version Control with Git

1. What is Version Control?

When contributors take too much time to push code to the remote repository, there's a high chance to happen Merge Conflicts.

A merge conflict happen when same line of code was changed and git can't fix it alone. So it must be solve manually.

The best practice to avoid it is to push and pull often to/from remote repository.

Continuous Integration: integrate your code changes frequently.

2. Basic Concepts of Git

Parts of git:

3. Setup Git Repository Remote and Local

Main players:

Local Repository

# cloning a repo
git clone <repository-URL>

Inside the repository directory there's a subdir named .git/. It has information about the repository and is used only locally.

4. Working with Git

Working Directory --git add--> Staging Area --git commit--> Local repository

# status of local git repo
git status

# add a file to the staging area
git add FILENAME

# commit the files in the staging area to the local repository
git commit

# see the history of changes (commits) in the local repository
git log

# pushing the local repository content to the remote one
git push

5. Initialize a Git project locally

Project locally is NOT a git repository yet:

# existing_directory is not yet a git repository
# (meaning: doesn't have a '.git' directory)
cd existing_directory

# say that this is going to be a git repo
git init

# set a remote repository for it
git remote add origin <git-repository-URL>

# adding files to staging area
git add .

# commit to local repo
git commit -m 'Initial commit'

# push to remote setting an upstream branch named 'master'
git push --set-upstream origin master

6. Concept of Branches

The concept of branches exist in order to cleanly divide the work of different developers.

Best practices is to create branches for each feature and each bugfix.

Examples:

# show the current branch you're working
git branch

# pulling updates from the remote repository (which may include new branches)
git pull

# switching to another branch
git checkout <branchname>

# creating a new local branch and switch to it right away
git checkout -b <new-branchname>

# pushing the newly created local branch to the remote repo
git push -u origin <new-branchname>

NOTE before creating a new branch and start working on it, it's import to switch back to master, in order to base your branch on master.

Common practice: having the master and the develop branches

master vs. master+develop

7. Merge Requests

8. Deleting Branches

Keep only branches that are being actively being worked.

# delete a branch locally
git branch -d <branchname>

# delete a remote branch
git push <repo> --delete <branchname>

9. Rebase

When you try to push changes to a repo and the remote repo has a commit (from another dev) you don't have locally, you need to git pull and it'll automatically merge the changes into your repo by creating a new commit. This is useful but add some "pollution" to your commit history.

In order to avoid such pollution, use the command git pull -r, and it'll just insert the commit you don't have before your commit.

# avoid "Merge branch..." pollution in commit history
git pull -r

10. Resolving Merge Conflicts

Happens when more than one developer change code in the same line of a file. Even if you try to git pull -r you'll receive a CONFLICT message.

When such situation happens YOU must tell git which change to take. Open the file where the conflict happens in your editor and fix the conflicts. And then git rebase --continue.

# pulling remote changes and rebase
git pull -r

# a conflict happens, fix it in your editor

# continue with the rebase
git rebase --continue

# push changes to remote
git push

11. .gitignore file

Used to exclude certain folders or files from git to be tracked.

# removing tracked-but-now-ignored files from the repository
git rm -r --cached removed_directory/

Useful link: https://gitignore.io/

12. git stash

Scenario where git stash is useful:

  1. Making changes to the current branch
  2. Notice that something isn't working anymore - "Did I break it with my changes?"
  3. Hide changes temporarily away to test if it works without my code changes: git stash
  4. Bring changes back to my local working directory: git stash pop

13. Going back in history

# seeing the history
git log

# NOTE: 'detached HEAD' state means you are not in the most
# uptodate commit

# choose the commit hash you want to test
git checkout <commit-hash>

# if you want to create a new branch from the current state
git checkout -b <new-branch-name>

# if you want to go back to the latest commit
git checkout <branch-name>

14. Undoing commits

Undoing and removing commits that were not yet pushed to the remote repository:

# reverting a commit
# the '--hard' option discards the changes made in the commits being reverted.
git reset --hard HEAD~1

# the number after the tilde '~' sets the amount of commits to be reverted
# example reverting last 3 commits:
git reset --hard HEAD~3

# reverting the commit but keeping the changes
# (this is equivalent to use --soft)
git reset HEAD~1

# once you're happy with the changes you've made, let's ammend that commit
git commit --amend -m 'commit message'

Undoing and removing commits that were already pushed to the remote repository

WARNING: Don't do this in master or develop branch! Only do this when working alone in a branch!

# reverting a commit
git reset --hard HEAD~1

# force push a new commit history to the remote repository
git push --force

Reverting changes through a new commit actually changing the files to the previous state.

# create a new commit changing the commit but in the reverse way
git revert <commit-hash>

15. Merging branches

# example: you're on a new branch and the master branch was
# changed by another dev, and you want such changes in your
# new branch.

# go to the master branch and pull the changes
git checkout master
git pull

# go back to your branch
git checkout <branch-name>

# merge the changes from master into your branch
git merge master

16. Git for DevOps

Situations where you, as a DevOps Engineer, need git: