Skip to content

ondrejsika/git-training

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

124 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Ondrej Sika (sika.io) | ondrej@sika.io | course ->

Git Training

Install Git

Download installer from https://git-scm.com or use package manager.

Mac

brew install git

Linux

sudo apt install git

Windows

https://git-scm.com/downloads/win

winget install -e --id Git.Git
choco install git

Editor

I prefer VS Code, you can download it here: https://code.visualstudio.com/download

Or download it using package manager:

Mac

brew install --cask visual-studio-code

Windows

choco install vscode

Install slu

SikaLabs Utils

Mac

brew install sikalabs/tap/slu

Linux

curl -fsSL https://raw.githubusercontent.com/sikalabs/slu/master/install.sh | sudo sh

Windows

scoop install https://raw.githubusercontent.com/sikalabs/scoop-bucket/master/slu.json

Course

About Me - Ondrej Sika

Freelance DevOps Engineer, Consultant & Lecturer

  • Complete DevOps Pipeline
  • Open Source / Linux Stack
  • Cloud & On-Premise
  • Technologies: Git, Gitlab, Gitlab CI, Docker, Kubernetes, Terraform, Prometheus, ELK / EFK, Rancher, Proxmox, DigitalOcean, AWS

Star, Create Issues, Fork, and Contribute

Feel free to star this repository or fork it.

If you found bug, create issue or pull request.

Also feel free to propose improvements by creating issues.

Chat

For sharing links & "secrets".

Slack & Newsletter

Join my Slack for future discussion & help.

Subscribe to my Newsletter for future DevOps topics.

Overview of Git Storage

detlas

snapshots

Git Cheat Sheets

Basic Configuration

I prefer global configuration (using --global) stored in your home directory applied to all repositories.

You can configure just one repo, you can call git config from you repository with flag --local.

git config --global user.name "Ondrej Sika"
git config --global user.email "ondrej@ondrejsika.com"

You can also use environment variables GIT_AUTHOR_NAME, GIT_AUTHOR_EMAIL, GIT_COMMITTER_NAME, GIT_COMMITTER_EMAIL for temporary override of user name and email.

export GIT_AUTHOR_NAME="Ondrej Sika"
export GIT_AUTHOR_EMAIL=ondrej@ondrejsika.com
export GIT_COMMITTER_NAME="Ondrej Sika"
export GIT_COMMITTER_EMAIL=ondrej@ondrejsika.com

Rebase workflow (if you want to use rebase workflow)

WARNING: Apply only if you want to use rebase workflow!

git config --global merge.ff only
git config --global pull.rebase true

Init Default Branch

git config --global init.defaultBranch main
git config --global init.defaultBranch master

GPG sign tags by default

git config --global tag.gpgSign true

or for example disable only for local repo

git config --local tag.gpgSign false

Git Editor

Git use by default Vim or editor from EDITOR environment variable. If you want to use different editor, you can configure it.

git config --global core.editor vim

or

git config --global core.editor emacs

You can use GUI editors like VS Code too:

git config --global core.editor "code --wait"

See Associating text editors with Git on Github Help to use your editor on your platform.

Sources:

Auto Setup Remote on Push

From Git version 2.37.0, Git can automatically set the upstream when pushing a new branch:

git config --global --add --bool push.autoSetupRemote true

Source: https://twitter.com/ji/status/1546948817462800384

Git PS1

If you want to see your branch in terminal prompt you have to use git-prompt.sh.

It works on Unix (ZSH & Bash). If you use Windows, it works by default in Git Bash and there is no way how add it into CMD or PowerShell.

Install On Unix:

wget https://github.com/git/git/raw/master/contrib/completion/git-prompt.sh
mv git-prompt.sh ~/.git-prompt.sh
echo ". ~/.git-prompt.sh " >> ~/.bashrc

You have to add __git_ps1 to your PS1 variable.

Bash Example:

export PS1='\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]$(__git_ps1)\$ '

Save it to .bashrc:

echo "export PS1='\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]$(__git_ps1)\$ '" >> ~/.bashrc

Aliases

You can create own git aliases:

git config --global alias.<alias> <command>

Example:

git config --global alias.co checkout
git config --global alias.br branch
git config --global alias.ci commit
git config --global alias.st status

Usage of aliases is git co for git checkout, git ci for git commit, ...

Those aliases work on every platform (even Windows).

My Git Aliases

From ondrejsika/dotfiles

alias st='git status'
alias sta='git status --untracked-files=all'
alias di='git diff'
alias dis='git diff --staged'
alias dit='git diff | tig'
alias dist='git diff --staged | tig'
alias ci='git commit'
alias co='git checkout'
alias br='git branch'
alias ad='git add'
alias fa='git fetch --all --prune'
alias ga='gitk --all'
alias glo='git log --oneline '

I also use alias completion using complete alias, eg: complete -F _complete_alias st for st alias.

slu git

slu git url open

With alias alias guo="slu git url open"

guo
slu git url get
slu git use-ssh

VS Code and Git

Demo Gitlab

Gitlab Upgrade Path

https://gitlab-com.gitlab.io/support/toolbox/upgrade-path/

SSH Key Setup

SSH keys allow you to authenticate with GitHub/GitLab without entering a password every time.

Generate SSH Key

ssh-keygen -t ed25519 -C "your_email@example.com"

Accept the default file location (~/.ssh/id_ed25519) and optionally set a passphrase.

Add Key to SSH Agent

Mac / Linux:

eval "$(ssh-agent -s)"
ssh-add ~/.ssh/id_ed25519

or just

ssh-add

Add Public Key to GitHub / GitLab

Copy your public key:

cat ~/.ssh/id_ed25519.pub

Then paste it into:

Test the Connection

ssh -T git@github.com
ssh -T git@gitlab.com
ssh -T git@gitlab.sikademo.com

You should see a welcome message confirming your identity.

New Repository

Create on Github (eg.: example-repository) and clone it.

git clone git@github.com:ondrejsika/example-repository.git
cd example-repository

or create it locally

mkdir example-repository
cd example-repository
git init

git clone

Clone a remote repository to your local machine:

git clone <url>

Example:

git clone git@github.com:ondrejsika/example-repository.git

Clone into a specific directory:

git clone <url> <directory>

Example:

git clone git@github.com:ondrejsika/example-repository.git my-repo

Gitignore

File .gitignore defines files ignored by Git. Those files doesn't exist for Git. This is a simple example for Next.js project.

# Mac
.DS_Store

# Editor
.vscode
.idea
*.swp
*.swo
*~

# Generic
*.log
*.backup
*.local.sh
*.local.yml
*.local.yaml
*.local.json
*.local.txt

# NodeJS
node_modules

# NodeJS
.next
out

This example gitingore has been generated by slu file-templates gitignore --node --nextjs

Github Gitignore Templates

http://github.com/github/gitignore

EditorConfig

File .editorconfig define editors behavior, like spaces vs tabs or tab size, for example.

root = true
[*]
indent_style = space
indent_size = 2
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
end_of_line = lf
max_line_length = off

slu file-templates: gitignore & editorconfig

Gitignore

slu file-templates gitignore
slu ft gi
slu file-templates gitignore --terraform --node
slu ft gi --terraform --node

Editorconfig

slu file-templates editorconfig
slu ft ec
slu file-templates editorconfig --go --python
slu ft ec --go --python

Basic Commands

git status

Show status of repository. See which files are edited or want to be committed.

git status

Show all untracked files in status

git status --untracked-files=all

git add

Add file to next commit

git add <path>

Examples

git add index.html
git add .

Partial git add

You can use -p to switch into interactive mode and select part of changed file, which you want to commit.

git add -p <path>

git diff for new changes

You can see changes before git add or git commit.

See new changes in files managed by Git (not in new files):

git diff

If you want to see staged changes (added, prepared for commit), you have to use:

git diff --staged

git restore

Discard changes in the working directory (revert file to last committed state):

git restore <file>

Unstage a file (remove from index without discarding changes):

git restore --staged <file>

Vim Cheat Sheet

git commit

Save prepared changes to repository

Create commit from all staged changes

git commit

Create commit from all changes (not new files)

git commit -a

Commit one file (not new files)

git commit <file>

Specify message in parameter instead of open vim

git commit -m "<message>"

Combination of -a -m params

git commit -am "<message>"

Update latest commit

git commit --amend

Conventional Commits

https://www.conventionalcommits.org/

<type>[(<scope>)]: <message>

Types:

  • feat
  • fix
  • chore

My additional types:

  • init
  • VERSION
  • content
  • ci
  • docs
  • refactor
  • cleanup

My format with prefix:

[[prefix]] <type>[(<scope>)]: <message>

Prefixes:

  • [auto]

git log

Show history of commits

git log
git log --oneline
git log --oneline --graph --all

--graph draws a branch/merge graph in the terminal. --all shows all branches, not just the current one.

git show

Show details of a specific commit (message, author, diff):

git show <ref>

Examples:

git show HEAD
git show HEAD~1
git show 47bdfb7
git show v1.0.0

Browsing history

Tig

Simple terminal history browser for Git

Install

Mac

brew install tig

Linux

sudo apt install tig
Usage
# only actual branch
tig

# all branches
tig --all
Key Bindings
Key Action
j / k or / Move up / down
enter Open commit / view details
tab Switch between views
q Close current view
Q Quit tig
r Refresh
/ Search
n / N Next / previous search result
d Show diff
s Show status view
l Show log view
b Show blame view
? Show help
Tig Cheat Sheet

Lazygit

Terminal UI for Git with a more visual and interactive experience.

Install

Mac

brew install lazygit

Linux

sudo apt install lazygit
Usage
lazygit
Navigation
Key Action
h / l or / Switch between panels
j / k or / Move up / down in a list
[ / ] Switch between tabs within a panel
enter Confirm / open selected item
esc Go back / cancel
q Quit lazygit
? Show help / all keybindings
Basic Shortcuts
Key Action
space Stage / unstage file or hunk
a Stage / unstage all files
c Commit staged changes
p Push
P Pull
f Fetch
b Open branch menu (create, checkout, delete, merge, rebase)
z Undo last action
e Edit file in editor
/ Filter / search in current panel

Gitk

Graphic commit log. Distributed with Git.

# only actual branch
gitk

# all branch
gitk --all

Remote Repository (Github, Gitlab)

If you have cloned repository, git clone has added configuration of repository.

Check it by:

git remote -v

and you will see:

ondrej@sika-macbookpro:~/example-repository (master)$ git remote -v
origin	git@github.com:ondrejsika/example-repository.git (fetch)
origin	git@github.com:ondrejsika/example-repository.git (push)

If you've created repository by git init you see nothing.

Add Remote Repository

To add remote repository, you have to use:

git remote add <name> <url>

For example:

git remote add origin git@github.com:ondrejsika/example-repository.git

Now you can push & share your code with collaborators. Check git remote -v.

Rename & Remove Remote Repository

If you want to rename remote repository, use:

git remote rename <name> <new name>

If you want delete remote, use:

git remote remove <name>

git push

Push your commits to remote repository (Github).

# Push new branch to repository
git push <remote> <branch> -u

# Push commit
git push

git fetch

Download new commits and branches from remote repository without applying them to your local branches.

git fetch

Fetch from all remotes:

git fetch --all

Fetch and remove remote-tracking branches that no longer exist on the remote:

git fetch --prune

Fetch from all remotes and prune stale branches:

git fetch --all --prune

Unlike git pull, git fetch never changes your working directory or local branches — it only updates the remote-tracking references (e.g. origin/main). You can inspect the changes before merging or rebasing.

git pull

Pull new commits from remote repository (Github).

git pull

git pull is shorthand for git fetch followed by git merge (or git rebase if configured).

Working with Branches

Stash

Git stash is used for temporarily postpone your changes to make your working directory clean.

That's required by some Git commands like git rebase, ... or sometimes for git checkout, git cherry-pick, ...

If you want to stash changes, use:

git stash

And check status using git status.

If you want to see, which files are stashed, use:

git stash show

If you want to see patch, add -p:

git stash show -p

If you want to apply stashed changes and remove stash, use:

git stash pop

And check git diff and git stash show.

If you have multiple stashes you work only with the latest.

List all stashes:

git stash list

If you want to specify other stash you can use stash@{0}. For example:

git stash show stash@{1}
git stash show -p stash@{1}

More about stash in official documentation - https://git-scm.com/docs/git-stash

List Branches

# Show local branches
git branch

# Show all branches (with the branches of remote repository - on Github)
git branch --all

Switch vs Checkout

Switch is new command which implements part of checkout functionality.

See: https://stackoverflow.com/a/70454786/5281724

Create a Branch

Create branch (and don't switch to it)

git branch <new_branch> [<branch_from>]

Switch branch

git checkout <branch>
git switch <branch>

Create branch and switch to it

git checkout -b <new_branch> [<branch_from>]
git switch -c <new_branch> [<branch_from>]

Switch Branch

git checkout <branch>
git switch <branch>

Push & Pull Branch

# Push commits to remote repository (Github)
git push <remote> <branch> -u

# Pull new commits to my branch
git pull

Merging Branches

You can merge branches locally or on Github / Gitlab using Pull / Merge Requests.

Merge hell

Conflict Resolution

When rebasing, Git may hit a conflict and mark the file:

<<<<<<< HEAD
your changes
=======
incoming changes
>>>>>>> feature-branch

To see which files have conflicts:

git status

To see the conflicting changes:

git diff

Resolve the conflict by editing the file to keep what you want, then:

git add <file>
git rebase --continue

To abort and go back to the state before the rebase:

git rebase --abort

Rebase

See my czech article about rebase: https://ondrej-sika.cz/git/rebase/

Merge (fast-forward only)

After rebasing your branch on top of master, merge it with fast-forward only:

git merge --ff-only <branch>

Git Reset

Reset HEAD (current branch) to specific state.

Set HEAD to specific state, but don't change files in working directory.

git reset <commit>

If you want also reset files, use --hard:

git reset --hard <commit>

Remove Last Commit

For example, you want to remove last commit but want to keep changes:

git reset HEAD~1

See git status and git diff, files from last commit are now in changed.

If you want remove last commit with its changes, use:

git reset --hard HEAD~1

And see (git status, git diff), no changes.

Interactive Rebase

Create some demo commits:

touch A
git add A
git commit -m A
touch B
git add B
git commit -m B
touch C
git add C
git commit -m C
touch D
git add D
git commit -m D
touch E
git add E
git commit -m E
touch F
git add F
git commit -m F
touch G
git add G
git commit -m G
touch H
git add H
git commit -m H

You can rewrite history, join commits, update messages, reorder commits, ...

git rebase -i <ref>

Example:

git rebase -i HEAD~6

Available actions in the editor:

Action Description
pick Keep the commit as-is
reword Keep the commit but edit its message
edit Pause rebase to amend the commit
squash Merge into the previous commit, combining messages
fixup Merge into the previous commit, discarding this message
drop Remove the commit entirely

Cherry Pick

Copy commit (ref) to actual HEAD.

git cherry-pick <ref>

Example:

git cherry-pick v1.0.x
git cherry-pick 47bdfb7

git reflog

Reflog shows a history of reference. By default shows a HEAD. You can undo any git operations even reset.

git reflog
git reflog <branch>

git tag

Create tag:

git tag <tag> [<ref>]

Example:

git tag v1.0.0
git tag v1.0.0 HEAD~1
git tag v1.0.0 master
git tag v1.0.0 075615a

List tags:

git tag

Push tag:

git push <remote> <tag>

Example:

git push origin v1.0.0

Push all tags:

git push <remote> --tags

Example:

git push origin --tags

Delete tag (not recommended):

git tag -d <tag>

Example:

git tag -d v1.0.1

Delete tag from server:

git push <remote> :<tag>

Example:

git push origin :v1.0.2

Detached HEAD

You enter detached HEAD state when you check out a specific commit or tag directly instead of a branch. HEAD points to a commit, not a branch ref — any commits you make here are not on any branch and can be lost.

git checkout <commit>
git checkout v1.0.0

To go back to a branch:

git switch <branch>

To save your work as a new branch:

git switch -c <new-branch>

git blame

See authors of actual code

git blame <file>

See authors of code in specific revision

git blame <rev> <file>

See only lines from 1 to 10

git blame -L 1,10 <file>

Submodules

Clone repository with submodules:

git clone --recursive <repo_url>

If you have cloned repository without --recursive you have to:

git submodule update --init
# for nested submodules
git submodule update --init --recursive

Add submodule to repository:

git submodule init
git submodule add <submodule_repo_url> [<path>]

Add submodule and track specific branch:

git submodule add -b <branch> <submodule_repo_url> [<path>]

Update tracked branch:

git submodule set-branch --branch <branch> <path>

Update remote repository:

git submodule set-url <path> <newurl>

Update submodule from remote repository

git submodule update --remote

Pull changes & pull submodules

git pull --recurse-submodules

Execute command for each submodule:

git submodule foreach 'git reset --hard'
# including nested submodules
git submodule foreach --recursive 'git reset --hard'

Thank you! & Questions?

That's it. Do you have any questions? Let's go for a beer!

Ondrej Sika

Do you like the course? Write me recommendation on Twitter (with handle @ondrejsika) and LinkedIn (add me /in/ondrejsika and I'll send you request for recommendation). Thanks.

Wanna to go for a beer or do some work together? Just book me :)

Extra

git bisect

Git bisect helps you find commit which introduce a bug

Start bisect session

git bisect start

Select good commit

git bisect good <ref>

Set bad commit

git bisect bad <ref>

Now check if actual working tree contains bug.

If yes

git bisect bad

If not

git bisect good

Repeat it until bisect print out the commit which introduce a bug.

To close bisect session, use:

git bisect reset

GPG Commit Signing

git config --global commit.gpgsign true
git config --global user.signingkey B000780A20CF1013F7A59081775D8A020903EF6B

Releases

Sponsor this project

Packages

Used by

Contributors

Languages