Skip to content

FurkanEdizkan/Git-Version-Control-Tutorial

Repository files navigation

            

All Contributors

GitHub forks GitHub Repo stars GitHub

Git GitHub GitLab

Git Version Control Tutorial

This repository contains

  • Quick and Advanced Git Tutorial
  • Advanced Git topics and examples

Table of Contents
  • Git
  • Git-Plus
  • Contribute
  • License
  • References
  • Contributors
  • Git

    • Download & install Git

    For Debian/Ubuntu

    apt-get install git

    • Check git version & installation
    git --version

    • Initialize git configurations
    git config --global user.name "user_name"
    git config --global user.email "email"

    • Configure the main branch name as "main" (For older Git versions)

      The latest version of git comes with the default branch name as "main".

      Some older version "master" name is hard coded, so they needed to be changed manually.

    git config --global init.defaultBranch main

    • Configure Visual Studio Code for Git functions
    git config --global core.editor 'code --wait --new-window'
    git config --global diff.tool vscode
    git config --global difftool.vscode.cmd'code --wait --diff $LOCAL $REMOTE'
    git config --global merge.tool vscode
    git config --global mergetool.vscode.cmd'code --wait $MERGED'
    • Unset a git configuration
    git config --global --unset <option>
    git config --global --unset core.editor # Remove core.editor from configuration

    In order to work on the GitHub repositories, we either need to create PAT or generate an SSH key pair. If we are not planning to use GitHub we can skip this step.

    • Personal Access Token (PAT)

      Generated PAT will be used instead of a user password for Git operations connected to GitHub. Don't forget it and store it in a safe place.

      GitHub ➡️ Settings ➡️ Developer Settings ➡️ Personal Access Token

    • SSH

      We need to create a new SSH key, generated key pair will be used to authenticate to GitHub. Generate a new ssh-key and add public key to GitHub-SSH and GPG keys.

      GitHub ➡️ Settings ➡️ SSH and GPG keys

    ssh-keygen -t ed25519 -C "email" # Create a new SSH key
    eval "$(ssh-agent -s)" # Start SHH-agent
    ssh-add ~/.ssh/id_ed25519 # Add SSH key 
    cat ~/.ssh/id_ed25519.pub # Copy the ed25519 public key

    • Create a new Git repository

      Create new repository, every file already inside will be untracked condition

    git init
    • Clone Git repository

      Clone a remote repository to local system

    git clone <repository_link(HTTPS or SSH)>

    • Create a gitignore file

      Gitignore file is used to ignore files in the repository that we don't want to track changes or avoid uploading them to remote repositories.

    .gitignore Description
    venv/ Ignore all "venv" folders
    *.orig Ignore all files ending with ".orig"
    *.py[cod] Ignore all files ending with ".pyc", "pyo" and "pyd"
    !dont_ignore_this_file Don't ignore this file
    ignore_this_file Ignore this file
    /database Ignore "database" named folder under "/"
    doc/*.txt Ignore all files ending with ".txt" under "doc/" folder
    doc/**/*.pcd Ignore all files ending ".pcd" under "doc/" and it's sub folders
    touch .gitignore # Create .gitignore file

    • Create a git commit message template file

      To keep git history clean and understandable, every commit done to any repository needed to be in a clear format. We need to use commit templates, repositories suggest we use.

    touch .gitmessage # Create .gitmessage file
    git config --global commit.template ~/.gitmessage

    • Create a GitHub pull request template file

      GitHub pull requests are used for reviewing the process of adding new feature branches to repositories. It is a review state of the feature. To keep a feature or change clear and understandable, we use the given pull request template.

    mkdir .github # Create a .github folder
    touch .github/pull_request_template.md # Create pull_request_template.md file

    • Create a contributing.md template file

      Open-source projects are usually supported by contributors. To determine how someone can contribute and help to our project, we define a contributing guide.

    touch .contributing.md # Create .contributing.md file

    • Check git repository status

      Repository status information gives what has changed inside our repository.

      Git tracks each and every change done to tracked files, no data can be lost or corrupted, without willingly removing files from the repository.

    git status

    • Add changes to the Staging area

      Inside a git repository, files can either be tracked or untracked. Untracked changes are not tracked by git.

      Tracked files can either be unmodified, modified, or staged. We can check file states inside our repository with git status. Before committing changes, we put them inside the staging area with git add.

    git add <changed_file> # Add changed file to stage area
    git add . # Stage all changes

    Git Version 2.x

    Command New Files Modified Files Deleted Files Description
    git add -A Stage all changes
    git add . Stage all changes
    git add --ignore-removal . Stage only new and modified files
    git add -u Add modified and deleted files to stage area

    source

    • Commit staged files

      Stages changes need to be committed. When a commit has been made, the current state of the project is saved inside git.

    git commit # Commit staged changes
    git commit -a  # Commit all changes, skip the staging area
    git commit -m "<commit_message>" # Commit directly with passed commit 
    git commit -a -m "<commit_message>"
    • Amend a commit

      With the optional --amend command, we can modify the last commit. Staged changes will be added inside the previous commit.

    git commit --amend

    • Git Pointers

      Inside git, each commit is saved with a unique SHA1 hash.

      Also, some important commits have pointers. Creating a branch or tag creates a unique pointer name to direct commit.

      The HEAD pointer always points to the current commit. As we make new commits, change branches/tags or return to past commits, the HEAD pointer will also move with us.

    • Git History

      Git tracks the detailed history of each commit done. We can inspect changes done inside each commit, revert them or turn the project back to the state in which the commit was made.

    git log # Show git history
    • Git Commit Details

      Inside each commit, author, commit date, commit message, and changes done recorded.

    git show <commit_id> # Show commit details
    git show HEAD # Show HEAD details
    • Inspect Changes

      Differences between two commits can be observed

    git diff # Inspect current changes compared to the latest commit(HEAD)
    git diff --staged # Inspect changes inside the staged area compared to the latest commit(HEAD)
    git diff <commid_id> # Inspect changes between current changes and given commit_id
    git diff <commit_id> <commit_id> # Inspect changes between given two commits
    • Git difftool

      Git allows us to use different tools for git operations. By default, git uses a system editor. We can manually use these tools or change git config preferences and change default git tools.

    git difftool # Open git difftool
    git difftool --toll=<tool> # Open given git difftool
    git difftool <commid_id> # Inspect changes between current and given commit
    git difftool <commit_id> <commid_id> # Inspect changes between give to commits
    git difftool HEAD~x #  Inspect changes between current and "x" previous commits

    • Undoing changes

      Git reset is a powerful tool used for undoing changes inside git.

      We can return to an older commit and revert history to it.

      There are 3 options for git reset. By default git reset uses --mixed option.

    git reset --soft # Revert changes from git history back to current commit, keep changes in the stage area.
    git reset --mixed # (Default) Revert changes from git history and staging area till current commit, keep changes as local changes.
    git reset --hard # (!!Destructive) Revert changes back to the current commit, and delete all saves inside git till this commit.

    • Revert changes

      Git allows us to directly reverse apply commits. git revert create a new commit reverting the given commit.

    git revert <commit_id> # Revert given commit changes
    • Restore changes to a file

      We can restore changes done to file.

    <make a change to a file>
    git restore <file>
    • Unstage changes back to index area

      Staged changes can be unstaged back.

    --make a change to a file--
    git add <file>
    git restore --stage <file>

    • Untrack files inside git repositories

      When we want to delete files from a repository, we either directly delete the files or we use git rm.

    git rm # Remove files from the repository and file system and untrack
    git rm --cached # Untrack file but keep it inside file system

    • Tagging important development points

      During development, important waypoints can be tracked by git, for example, version 1.0 of a project is an important waypoint.

      There are 2 tag options, lightweight and annotated. Lightweight tags are just pointers to certain commits, however, annotated tags are more complex tags. Annotated tags are stored as full objects.

    git tag # Show tag list
    git tag <tag_name> # Create lightweight tag
    git tag -a <tag_name> -m "tag_message" # Create annotated tag and add tag message

    • Checkout to a commit

      With checkout we can change our HEAD pointer to a any commit inside history. When we checkout to a commit, which not the latest inside its commit tree or has no pointer assigned to it like tag or branch, we enter into detached HEAD state.

      Detached HEAD state is not an error, it is just a warning to user. We can view changes and make experimental changes inside detached HEAD state, however in order to make a change we need to create an new branch and commit our changes into the branch.

    git checkout <commit_id> # Checkout to a commit
    git checkout <branch> # Checkout to a branch
    git checkout <tag> # Checkout to a tag
    git checkout HEAD~2 # Checkout to 2 commit earlier of HEAD pointer

    • Create branches

      Branching is creating an isolated copy of the current branch or commit. A branch is just a pointer to a certain commit object. With branching, we can isolate our work from main/master branches and continue our development without affecting other branches.

      It is good practice to create a new branch per feature, make development inside it, then merge it into a main/master branch. After development end on a branch and it is merged, it can be deleted, to minimize individual branch count.

    git branch # List branches
    git branch -a # List all branches 
    git branch <branch_name> # Create new branch
    git branch -m <current_name> <new_name> # Change name of a branch
    git branch -d <branch> # Delete branch
    git branch -m <branch_name> # Create new branch and checkout to it
    git checkout -b <branch_name> # Create new branch and checkout to it
    git switch -c <branch_name> # Create new branch and checkout to it
    • Merge branches

      When we want to apply changes inside an branch into other branch, we merge them together. After merge both branch pointers will point to the same new merge commit.

    git merge <branch_name> # Merge named branch into current branch
    • Merge conflicts

      When merging branches git will try to merge all changes possible, however, if there are different edits on the same lines on both branches, the merge will fail, and merge conflicts will happen.

      Merge conflicts, needed to be handled by hand. When merge conflicts arise, git will automatically mark the problem file and highlight the conflicting changes inside with "===", "<<<", and ">>>". As the user, we need to manually resolve the conflict by removing "<<< current_change === incoming_change >>>" and writing the changes we want to keep. After resolving the conflict, we need to git add and git commit the conflict. This commit will automatically fill the commit message as merge messge.

    git merge <branch_name>
    --merge conflict--
    cat <conflicting_file>
    ...
    <<<<<<< HEAD
    current changes
    =======
    incoming changes
    >>>>>>> feature_branch
    ...
    
    • Git mergetool

      Git allow us to use, other tools to resolve merge conflicts. These tools can allow us to resolve conflicts more easly and faster.

    git mergetool # Use default mergetool
    git mergetool --tool=<tool> # Uses selected mergetool

    • Git stash

      When we want to save our changes without making a commit we use the git stash command.

      Stashed changes can be transferred and applied to different branches.

    git stash # Stash changes
    git stash list # Show stash list
    git stash pop <stash_id> # Apply stashed changes
    git stash drop <stash_id> # Remove stashed changes
    git stash clear # Clear all stashed changes

    • Git rebase

      Rebase is a specialized tool used for rewriting commit history and integrating changes from one branch to another.

      Changing git history is always dangerous and causes data loss if not handled properly.

      Rebasing takes a branch's base commit with its following commits, changes its base position to another commit, and applies them to the changed position.

      It is a controversy if git history should be edited. Git history shows every change done during the production process, keeping it clear and understandable will help in almost every case.

      The controversy is, you will deploy your project and people will view it. Do we want everybody to know every dirty mistake or trashed feature development we did during the prodcution phase? Housekeeping git history can clean things we don't want to show others.

      Choose what you want to do with git rebase, however personally, I suggest don't change the git history. Use git rebases just to apply changes between branches.

    git switch <feature_branch> # Switch to feature branch
    git rebase <feature_branch> <main_branch> # Apply changes done inside feature branch into tip of main branch

    • Remote repositories

      Remotes are versions of our repositories that are stored on a server. A single repository can have multiple different remote repositories.

      When defining a remote, we gave it a unique name, when we want to use a certain remote, we specify its name. By default, origin is used for the remote name.

      If a repository is cloned, it will come with its own remote linked to cloned link. However, if a new repository wanted to add a remote we need to add a remote link to our repository.

    git remote # Show remote list
    git remote show <remote_name> # Show remote details
    git remote add <remote_name> <remote_link> # Add remote to repository
    git remote rename <remote_name> <new_remote_name> # Change remote name to <new_remote_name>
    • Pull changes from remotes and apply

      Before we push our changes, we need to check if there are may change to our current branch. We need to pull changes from remote repositories. git pull command pulls changes done to our branch on the remote repository and tries to apply changes to the branch.

      This can cause merge conflicts if there are multiple developers using same branch and making commits to it.

    git pull # Pull changes from remote
    git pull origin master # Pull changes on **master** branch from **origin** remote
    git pull <remote> <branch> # Pull changes on given branch from given remote
    • Fetch changes done to all remotes

      The fetch command downloads all changes done to all branches on the current remote. However it will not apply remote changes to branches, it will just update the remote/branch. If we want to apply changes on the remote branch we need to pull changes done to the current branch.

    git fetch # Download all changes from remotes
    git fetch -p # Download all changes and delete unused removed remotes
    • Push changes

      When we want to upload our changes to remote repositories, we push them. If no remote and/or branch is mentioned by default, the push command will push changes on the current branch to tracked remote.

    git push # Push changes to remote
    git push <remote> <branch> # Push changes done on branch to remote
    git push -d <remote> <branch> # Delete a branch from remote repository

    Git-Plus

    • Commit to past

      It is not recommended to play or trick git history, but it is possible.

    git commit --date='year-month-day hour:minutes:seconds' -m "message"

    source

    • Delete a file permanently from Git Repository and History

      During development, unwanted files could end up inside our git repository.

      Committed files can be removed locally, however, if they are stored inside the git repository they needed to be removed manually and forcefully.

      This is a dangerous command, which will rewrite git history and make edit existing commits.

      Don't use it, if it is a must to use.

      Instead use git-filter-repo

    git filter-branch --index-filter “git rm -rf --cached --ignore-unmatch
    <file>” HEAD

    source

    • Bundling repository

      To share a repository, we need to push to a remote repository, however, a network connection might not be up always.

      To share a repository, git has a function to store the repository inside a single file that can be transferred.

    git bundle creates a repo.bundle HEAD master # Bundle a repository on the master branch
    git clone repo.bundle repo # Clone a bundled repository to local
    • Git GUI Clients

      There are many usefull git gui clients, it is a good thing to know what is happening inside git with terminal commands, however gui clients will accelerate your git usage.

      List of git GUI clients

    Contribute

    We welcome every contribution, suggestion and improvement

    We will try to address all issues as soon possible

    See the contributing guide for more details

    TODO (Completed)

    License

    Distributed under the MIT License. See LICENSE for more information.

    References

    Learning

    Logos & Images

    Contributors


    Furkan Edizkan

    💻 🖋 📖 🎨 🚧

    All Contributors

    🎨 🔧

    Alim Kerem Erdoğmuş

    🔧 ⚠️ 📓 📢

    Ramazan Akkulak

    ⚠️