Giter Club home page Giter Club logo

effective-git's Introduction

Git Tips and Tricks for Effective Developers

Two key advices on Git

  • Use git in command line. Don't use apps. Don't use git buttons embedded in your IDE (VSCode, IntelliJ etc.). Git command line client is just a more efficient tool. Much like riding a bycicle: once you learn how to use it, you can use it for the rest of your life.
  • Spend some time to learn git. It can save you countless hours in future. Avoid using unreliable tutorials and courses. Instead consider Atlassian's online textbook. Check out recomendations below.

Some good guides on Git

Guide Purpose
https://www.atlassian.com/git A very good textbook. There are parts both for beginners and advanced users
https://ohshitgit.com/ Common mistakes and problems explained. For everyone
https://learngitbranching.js.org/ Interactive Git simulator. It's my top recomendation for complete beginners

Git daily scenarios with tips

Disclaimer. Here I consider usage of standard feature branch workflow. This flow is widely used in modern microservice architecture and CI/CD pipelines.

Feature branch workflow

Create a new branch, work on it for a while, push, pass tests and builds, finally create a Pull Request.

# Create new branch and checkout it
git checkout -b JIR-123-new-feature

# Change your code, do commit the changes
git add file_1.py
git add file_2.py
git commit -m 'JIR-123 changed file_1 and file_2'

# This will create a new branch on the server
git push -u origin HEAD

# Your build is failed! Fix it
git add file_1.py

# This approach helps you not to spam commits like 'fix', 'fix', 'fix'
# Caution. Use only in your personal branch!
git commit --amend --no-edit
# no-edit keeps commit message unchanged. If you want to change it use
git commit --amend
# Force push, rewrite the history
git push -f

# In a shared branch just create new commit
git commit -m 'JIR-123 fixed file_1'

# At this point of time you may want to create a Pull Request

Pull Request review

Go through multiple iterations of code review. Commit the changes. Squash 'fix' commits after you finally get your approve.

# Checkout your branch
git checkout JIR-123-new-feature

# Fix after the first review iteration
git add file_1.py
git commit -m 'JIR-123 changed file_1.py'
git push

# Fix after the second review iteration
git add file_1.py
git commit -m 'JIR-123 changed file_1.py'
git push

# Finnaly, your PR is approved
# Reduce number of commits using "squash" for better readability
# Option 1. Leave one commit in the branch
git rebase -i master
# Option 2. Squash only 'fix' commits
git rebase -i HEAD~2
# Force push, rewrite the history
git push -f

# Your reviewer approves again. You're allowed to merge

Freecodecamp.org: Tutorial on squashing

Note. Some Git hosting services provide an option to merge with squash in UI.

Why you shoudn't use git commit amend / push -f during code review

When you rewrite the history, the reviewer can't see what changed from the previous iteration, and it becomes quite annoying to check that you fixed the code in a way it was intended

Merge conflicts

Disclamer. Actually, developers are devided on two camps in the question of conflict solving. The first one prefers rebases. The second one prefers merges. This guide encourages using rebases, since they produce linear history which is much easier to read and maintain.

Atlassian blog: Merge or rebase?

Regular rebases allows you not to get too far behind of master or your main branch. Yes, you will have to solve conflicts more frequently but in rather small portions. Keeping your branch too far away from master may lead to a very painful merge at the end.

# When you come to work, in your feature branch
git checkout JIR-123-new-feature
# Keep you uncommited changes to the temporary storage
git stash
# Do rebase
# Caution. Use only in your personal branch!
git rebase master

# You will probably need to solve conflicts

# If something went wrong
git rebase --abort

# If you fixed the conflicts
git add file_1.py
git rebase --continue

# If you want to return evertything back
git checkout origin/JIR-123-new-feature
git branch -f JIR-123-new-feature

# If rebase is ok

# Return uncommited changes
git stash pop
# Force push, rewrite the history
git push -f

# After rebase you will have zero conflicts with master

Preparing commit

Add only necessary changes to your commit. Avoid committing .DS_Store and other unwanted files.

# Bad approach
git add .
# You will end up with unwanted files

# Option 1. Add all files and directories manually
git add file_1.py
git add dir_1

# Option 2. Add only changed files automatically
# Adds no new files
git add -u
# Add new files manually
git add file_2.py

# Don't forget to check the status
git status

git commit -m 'JIR-123 changed some files'

Problem solving

# You occasionally added an unwanted file to staging
git add file_1.py
# Solution
git reset file_1.py

# You occasionally commited unwanted file
git add file_1.py file_2.py
git commit -m 'JIR-123 changed something'
# Solution
# Cancel you last commit. Return to the previous one
# All changes are in staging
git reset --soft HEAD~1
# Remove unwanted file from staging
git reset file_1.py
# Commit again
git commit -m 'JIR-123 changed something'

# Sometimes you want to abandon some changes before adding files to staging
# This is equialent to git reset --hard but for a single file
git checkout file_3.py
# Disclamer: there is a more safe version
# It's necessay if the branch and the file have the same names. Not happen in practice
git checkout -- file_3.py

It's highly recommended to undestand how reset works. The official documentation page may seem quite vague, so check out this short and very short explanation on StackOverflow.

More explanations of how to use git checkout for reseting changes can be found in this StackOverflow topic.

Git effective setup

Better git log

You may know that git log has many formatting options. Although, all predefined formats (e.g. --oneline and --short) have some drawbacks. So, the best way is to set the format string manually.

This code is inpired by this StackOverflow answer but have some differences

Add to your ~/.gitconfig

[alias]
lg = log --abbrev-commit --decorate --format=format:'%C(bold blue)%h%C(reset) - %C(bold green)(%ar)%C(reset) %C(white)%s%C(reset) %C(dim white)- %an%C(reset)%C(auto)%d%C(reset)' --first-parent
lgg = log --abbrev-commit --decorate --format=format:'%C(bold blue)%h%C(reset) - %C(bold green)(%ar)%C(reset) %C(white)%s%C(reset) %C(dim white)- %an%C(reset)%C(auto)%d%C(reset)' --graph

What the format provides you

  • Short commit hash
  • Relative time
  • Commit message
  • Author name
  • Branches and tags
  • All oneline
Command Scope Use Case
git lg Commits from the current branch. No commits from merged feature branches To check what came from the server. To check that your made your commit in a right place. To explore a new repository
git lgg Commits from the current branch with feature branches. Draws the graph To check out commits from feature branches
git lgg --all Commits from all branches. Draws the graph To explore non-merged branches

Alt text Alt text

Git status with less

git status may become huge. Particularly, when you add dependencies in you repo (like we do in golang).

In such cases git status command returns a very long output that could be annoying. It is possible to use less to solve it (I personally use bat as less substitution)

git status | less

But such output will loose colors which reduces its readability. Add the following to ~/.gitconfig to fix it

[color]
status = always

Fuzzy search for branch checkout

git checkout branch-name can be very annoying in a production level repository because of a very large number of branches. I recommend to use fzf command-line tool to perform fuzzy search over branches.

A detailed tutorial on how to set up this feature can be found in this post

Here is how it looks

Alt text

TLDR

  1. Install zsh if you havn't alredy
  2. Add the following code to your .zshrc/.bashrc config
  3. Use gch command instead of git checkout
fzf-git-branch() {
    git rev-parse HEAD > /dev/null 2>&1 || return

    git branch --color=always --all --sort=-committerdate |
        grep -v HEAD |
        fzf --height 50% --ansi --no-multi --preview-window right:65% \
            --preview 'git log -n 50 --color=always --date=short --pretty="format:%C(auto)%cd %h%d %s" $(sed "s/.* //" <<< {})' |
        sed "s/.* //"
}

fzf-git-checkout() {
    git rev-parse HEAD > /dev/null 2>&1 || return

    local branch

    branch=$(fzf-git-branch)
    if [[ "$branch" = "" ]]; then
        echo "No branch selected."
        return
    fi

    # If branch name starts with 'remotes/' then it is a remote branch. By
    # using --track and a remote branch name, it is the same as:
    # git checkout -b branchName --track origin/branchName
    if [[ "$branch" = 'remotes/'* ]]; then
        git checkout --track $branch
    else
        git checkout $branch;
    fi
}

alias gb='fzf-git-branch'
alias gch='fzf-git-checkout'

effective-git's People

Contributors

ledovsky avatar

Stargazers

 avatar Alexander Belyatskiy avatar Nikita Kuznetsov avatar  avatar Mikael avatar  avatar Max Tushewski avatar  avatar  avatar Anastasia Voznyuk avatar Maverick Sachin avatar  avatar Mohamed E. (Amine) BRIKI ๐Ÿ‡ต๐Ÿ‡ธ avatar Nina Chelysheva avatar  avatar  avatar  avatar Kamronbek avatar  avatar Georgii Afanasev avatar  avatar Vasiliy Gorelov avatar Ekaterina Fomina avatar  avatar Nikolay Karelin avatar Alexander avatar Tair Ospanov avatar D. M. avatar  avatar Gerasimov Maxim avatar MaxManchenko avatar  avatar Alexey Mukhin avatar  avatar Ivan Sedykh avatar  avatar Sergey Tarabara avatar Anton Semenistyy avatar Dmitry Unanyants avatar Latyshev Evgeniy avatar

Watchers

 avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.