← Back to Projects

Git Tutorial

October 2023

GIT Tutorial

Source code: vnk8071/git_tutorial

Overview

Version control is a system that records changes to a file or set of files over time so that you can recall specific versions later. It allows you to revert files or project to a previous version, track modifications and modifying individuals, and compare changes. It is essential for the integrity of the project and the people working on it.

And last but not least, 80% of the time we’re just going to use about 20% of the available git commands.

Configuration

git config --global user.name "name"
git config --global user.email "email"

Workflow

git_workflow @source: A successful Git branching model

Commands and definitions

# Command Definition
1 git clone <url>.git Clone a repository into a new directory
2 git checkout -b <branch_name> Create a new branch and switch to it
3 git add . Add all files to staging area
4 git commit -m "message" Commit changes to head
5 git push origin <branch_name> Push changes to remote repository
6 git log Show commit logs
7 git revert <commit_hash> Revert a commit
8 git reset --hard <commit_hash> Reset to a commit
9 git branch List all local branches
10 git branch -r List all remote branches
11 git branch -a List all local and remote branches
12 git branch -d <branch_name> Delete a local branch
13 git push origin --delete <branch_name> Delete a remote branch
14 git checkout <branch_name> Switch to a branch
15 git checkout - Switch to the previous branch
16 git checkout -- <file_name> Discard changes to a file
17 git merge <branch_name> Merge a branch into the active branch
18 git fetch Fetch changes from remote repository
19 git pull Fetch and merge changes from remote repository
20 git stash Stash changes in a dirty working directory
21 git stash list List all stashed changesets
22 git stash pop Apply stashed changes to working directory
23 git stash drop Discard stashed changesets
24 git rebase Reapply commits on top of another base tip
25 git rebase -i HEAD~<number_of_commits> Rebase interactive
26 git rebase --continue Continue rebase after resolving conflicts
27 git rebase --abort Abort rebase

Note:

  • git pull = git fetch + git merge
  • git pull --rebase = git fetch + git rebase

Details in Git Cheat Sheet and Book

Basic flow

git clone <url>.git
git checkout -b <branch_name>
git add .
git commit -m "message"
git push origin <branch_name>

Example: Follow the instructions in flow.py: basic_flow

Check remote branches: basic_flow_push_origin

Common workflow patterns

Single branch workflow

  • Use a single branch for all changes.
  • Use tags to mark important commits. single_branch
# Benefits Drawbacks
1 It is simple. It is not recommended to use in remote branches.
2 It is easy to resolve conflicts. It is not recommended to use in large projects.
3 It is easy to revert a commit. It is not recommended to use in colaborating with others.

single_branch_workflow @source: A successful Git branching model

Branch based development workflow

  • The master/main is never committed to directly.
  • New features are developed in separate branches, and then if colaborating with others, merged could be approved by pull request into the master/main branch.

branch_based_development @source: Trunk Based Development

# Benefits Drawbacks
1 It is easy to revert a commit. It is harder to resolve conflicts.
2 It is easy to review changes. It is not recommended to use in local branches.
3 It is easy to collaborate with others. Need dedicated time to review changes.

Back in time

Revert

git log
git revert <commit_hash>
git commit -m "[REVERT] <commit_hash>"
git push origin <branch_name>

Example: Follow the instructions in revert.py: revert_log

We want to revert the commit 0fcd910e9488b06d2206ff59c556e92a03a6f4ca:

git revert 0fcd910e9488b06d2206ff59c556e92a03a6f4ca
git commit -m "[REVERT] 0fcd910e9488b06d2206ff59c556e92a03a6f4ca"

Result:

[git-flow 7e41a10] Revert "UPDATE github link into doc projects"
 7 files changed, 14 deletions(-)

after_revert_log

We can see that the commit 0fcd910e9488b06d2206ff59c556e92a03a6f4ca is reverted.

Reset

git log
git reset --hard <commit_hash>
git commit -m "[RESET] <commit_hash>"
git push origin <branch_name>

after_revert_log

We can see that the commit 0fcd910e9488b06d2206ff59c556e92a03a6f4ca is reset.

Branches

Create a branch

git checkout -b <branch_name>
git push origin <branch_name>

Example: Follow the instructions in branch.py:

git checkout -b git-flow

basic_branch

git push origin git-flow

basic_branch_push_origin

Delete a branch

git branch -d <branch_name>
git push origin --delete <branch_name>

Merge

git checkout <branch_target>
git merge <branch_name>
git push origin <branch_target>

basic_merge

Follow the instructions in merge.py: Ìf merge conflict, we need to resolve it first.

git checkout main
git merge git-flow

Example:

<<<<<<< HEAD
This is the first line of the main branch.
=======
This is the first line of the git-flow branch.
>>>>>>> git-flow

basic_resolve_conflict

Then accept the changes could be current | incoming | both and commit:

git add .
git commit -m "Resolve conflict"
git push origin main

Check changes

git status
git log
git diff <commit_hash_1> <commit_hash_2>
git diff <branch_name_1> <branch_name_2>

Remote

remote_git

Before we can push to a team repository, we need to pull and resolve conflicts first.

git pull

Then we can push to the team repository.

git push origin <branch_name>

Stash

Using git stash to save changes in a dirty working directory and then pull latest changes from remote repository.

git stash save
git pull

Then we can apply stashed changes to working directory.

git stash pop

or

git stash apply

Example:

git checkout main
git pull

Then raise a bug and fix it.

error: Your local changes to the following files would be overwritten by pull:
    README.md
Please commit your changes or stash them before you pull.
Aborting

In this case, we can stash changes and pull latest changes from remote repository.

git stash save
git pull

Then we can apply stashed changes to working directory.


## Rebase
Similar to merge, but rebase reapply commits on top of another base tip.
```git
git rebase <branch_name>

Example: It squashes all commits of into one commit and reapply on top of .

basic_rebase

Then it rewrites the history of and we need to force push to the remote repository.

basic_rebase_master

# Benefits Drawbacks
1 It keeps the history clean. It is harder to resolve conflicts.
2 It is easier to revert a commit. It loses the context of the commits.
3 Using in local branches. It is not recommended to use in remote branches.

Squash

Using squash to combine multiple commits into one commit.

git rebase -i HEAD~<number_of_commits>

Note: Not recommended to use in remote branches when colaborating with others.

Less used commands

| # | Command | Definition | | — | — | — | | 1 | git rename <old_name> <new_name> | Rename a file | | 2 | git remote rename <old_name> <new_name> | Rename a remote | | 3 | git restore --staged <file_name> | Unstage a file |

Use cases

Git merge vs rebase

git merge feature main

This creates a new “merge commit” in the feature branch that ties together the histories of both branches, giving you a branch structure that looks like this:

git_merge_feature

git checkout feature
git rebase main

This moves the entire feature branch to begin on the tip of the main branch, effectively incorporating all of the new commits in main. But, instead of using a merge commit, rebasing re-writes the project history by creating brand new commits for each commit in the original branch.

git_rebase_feature

or we can interactive rebase:

git checkout feature
git rebase -i main
pick 33d5b7a Message for commit #1
fixup 9480b3d Message for commit #2
pick 5c67e61 Message for commit #3

git_rebase_feature_interactive

Finally, the feature branch has all of the commits from main and a nice, clean history:

git checkout feature
git rebase -i main
git checkout main
git merge feature

git_merge_feature_main

@source: Git merge vs rebase

Git reset vs revert

git checkout hotfix
git reset HEAD~2

The two commits that were on the end of hotfix are now dangling, or orphaned commits. This means they will be deleted the next time Git performs a garbage collection. In other words, you’re saying that you want to throw away these commits. This can be visualized as the following: git_reset_hotfix

git checkout hotfix
git revert HEAD~2

Reverting undoes a commit by creating a new commit. This is a safe way to undo changes, as it has no chance of re-writing the commit history. This can be visualized as the following:

git_revert_hotfix

@source: Git reset vs revert

Git hooks

Git hooks are scripts that Git executes before or after events such as: commit, push, and receive. Git hooks are a built-in feature - no need to download anything. Git hooks are run locally.

Install pre-commit:

pip install pre-commit
brew install pre-commit
conda install -c conda-forge pre-commit

Then run pre-commit install to install the git hook scripts into .git/hooks/:

pre-commit install

Pre-commit hook

Add the following to .pre-commit-config.yaml:

repos:
  - repo: https://github.com/pre-commit/pre-commit-hooks
    rev: v4.4.0
    hooks:
      - id: check-case-conflict
      - id: trailing-whitespace
      - id: check-yaml
      - id: end-of-file-fixer
      - id: requirements-txt-fixer
  - repo: https://github.com/pre-commit/mirrors-autopep8
    rev: 'v2.0.2'
    hooks:
      - id: autopep8
        args: [--in-place, --aggressive, --aggressive, --recursive]

Auto enable pre-commit hook:

$ git config --global init.templateDir ~/.git-template
$ pre-commit init-templatedir ~/.git-template

When we commit, the pre-commit hook will run:

git add .
git commit -m "ADD latest git tutorial and ADD edit page"

pre_commit

@source: Git pre-commit hooks

Future work

  • Practice make perfect.
  • So far so good.