11 Git tips to level up your workflow

Becoming a Git power user is on the bucket list of every developer. Today we prepared 11 Git tips that will help you level up your workflow and bring you one step closer to Git mastery.

Tip #1

Keep your commits organized

You just wanted to fix that one feature, but in the meantime got into the flow, took care of a tricky bug and spotted a very annoying typo. One thing led to another, and suddenly you realised that you’ve been coding for hours without actually committing anything. Now your changes are too vast to squeeze in one commit…

git add -p <filename>

With git add -p (or git add --patch) you can choose which parts of code from a file you want to include in your commit. After running the command you will get the list of the options you can add to git add -p

By choosing s you can split the hunk into smaller pieces. From there you can simply choose the chunks you want to stage for commit (and omit those you don’t) by navigating with y and n (or go for any other option from the list).

Tip #2

View branch sorted by date

display a list of all local branches and sort them based on the date of their last commit.

# sort desc (-committerdate)
git branch --sort=-committerdate
# sort asc (committerdate)
git branch --sort=-committerdate

If you’d like to make a custom format you can use for-each-ref with --sort option and--format option to write your format.

git for-each-ref --sort='-committerdate' --format='%(refname)%09%(committerdate)' refs/heads

In the above command, I print the refname first then commitdate in --formatoption the output will be like this

refs/heads/branch_name commitdate
refs/heads/branch_name2 commitdate
# real output
refs/heads/new_design Wed Apr 20 12:24:21 2022 +0200
refs/heads/design_assets Wed Apr 20 11:30:30 2022 +0200

If you want to print the datefirst then refnamethe option format will be like this --format='%(committerdate)%09%(refname)%'

Let’s say you don’t want to print refs/heads and want o print just the branch name each time, how we can do this? by using sed , let’s see how we can do this.

git for-each-ref --sort='-committerdate' --format='%(refname)%09%(committerdate)' refs/heads | sed 's-refs/heads/--'#output
branch_name commitdate
branch_name2 commitdate
#real output
new_design Wed Apr 20 12:24:21 2022 +0200
design_assets Wed Apr 20 11:30:30 2022 +0200

I find these commands incredibly helpful when returning to work from a weekend or just jumping from project to project. Hopefully, you can use these commands too!

to display a list of all local branches and sort them based on the date of their last commit, you can do this

Tip #3

View merged or un-merged branches

If you want to see a list of all merged local branches into a specific branch (master - main- etc…), in the following snippet I see all branches that merged into master

git branch --merged master

If you want to see a list of all merged local branches into HEAD

git branch --merged

If you want to see a list of branches that have not been merged

git branch --no-merged

if you used -a option you’ll list all branches including remote branches

git branch -a --no-merged

Tip #4

Creating aliases

Use the command below to create aliases, replacing <alias> with the name of the alias and <command> with the command to be aliased:

git config --global alias.<alias> <command># Exgit config --global alias.s 'git status'

Useful aliases

https://gist.github.com/AbdlrahmanSaberAbdo/1afa6fe548a939859f23efa20cad3066

Tip #5

Create a commit with a different date

Sometimes, you might run into a situation where you need to create a commit with a different date than the current one. Luckily, you can handle this using GIT_AUTHOR_DATE and GIT_COMMITTER_DATE:

GIT_AUTHOR_DATE='Mon May 18 19:32:10 2020 -0400' \
GIT_COMMITTER_DATE='Mon May 18 19:32:10 2020 -0400'\
git commit -m 'Commit from the past'

As shown in the example above, you can set both values to any date you like and your code will be committed on that date. Note that the format for the values above is 'date +"%s %z"', also referred to as internal raw git format, but you can also use other formats, such as RFC 2822 ('Mon, 18 May 2020 19:32:10 -0400'), ISO 8601 ('2020-05-18 19:32:10 -0400'), local ('Mon May 18 19:32:10 2020'), short ('2020-05-18') or relative (5.seconds.ago, 2.years.3.months.ago, '6am yesterday').

Tip #6

Create a commit by a different author

Creates a new commit by the specified author, actually, I don’t know the purpose of it but it’s also a trick you should know, be careful while reviewing the code, it might not the developer who’s pushed the code 😅, I made a post on LinkedIn wondering what’s the purpose of it with video, you can see it from here

  • Use git commit -m <message> to create a new commit with the specified <message>.
  • Use the --author option to change the <name> and <email> of the commit's author.
git commit -m <message> --author="<name> <email>"git commit -m "Fix the network bug" --author="Duck Quackers <cool.duck@qua.ck>"

Tip #7

View differences in changes

Displays differences between staged or unstaged changes and the last commit.

  • Use git diff to view the differences between your unstaged changes and the last commit.
  • You can use the --staged option to view differences between your staged changes and the last commit instead.
git diff [--staged]# Displays the differences between unstaged changes and the last commit
git diff
# Displays the differences between staged changes and the last commit
git diff --staged

Tip #8

Take me back (when everything worked!)

Not your best day. You made changes you shouldn’t have and now everything is broken… Is there a way to undo those commits?

Git keeps track of updates to the tip of branches using a mechanism called referencelogs, orreflogsMany Git commands accept a parameter for specifying a reference or “ref”, which is a pointer to a commit. Common examples include git checkoutor git reset.

git reflog

you can get the record of all the commits done in Git.

Now you just need to find the commit prior to the one that caused all the hassle. HEAD@{index} represents the specified commit, so just replace the index with the correct number and run:

git reset HEAD@{index}

The default action for git reset is git reset --mixed. It means that the changes in your working directory will be preserved but not staged (since the index was modified to match the chosen commit, the changes are not in the index anymore).

Other options are:

# Doesn’t modify the index or the working tree, leaving your changes staged for commit.git reset --soft# Use with caution, as it resets both the index and working tree. Uncommitted changes and all commits after will be removed.git reset --hard

And now, you can start over from the point when everything in your repository worked like a charm. Remember to use it only locally, as modifying a shared repository is considered a serious crime.

Tip #9

View a visual graph of the repository

Prints a visual graph of all commits and branches in the repository.

  • Use git log --pretty=oneline --graph --decorate --all to view a visual graph of the whole repository's history.
git log --pretty=oneline --graph --decorate --allgit log --pretty=oneline --graph --decorate --all
# * 3050fc0de Fix typo
# * c191f90c7 Initial commit

Tip #10

See commits in a specific date range

If you’re looking for a commit and don’t want to search between all commits you can search by date by using the following command

  • Use git log --since=<date-from> --until=<date-to> to view a log of all commits between <date-from> and <date-to>.
  • You can use it only --since=<date-from> to see all commits since a specific date or only --until=<date-to> to view all commits up to a specific date.
git log [--since=<date-from>] [--until=<date-to>]git log --since='Apr 1 2021' --until='Apr 4 2021'
# commit c191f90c7766ee6d5f24e90b552a6d446f0d02e4
# Author: 30 seconds of code
# Date: Tue Apr 6 11:11:08 2021 +0300
# [...]

git log --since='2 weeks ago'
# commit c191f90c7766ee6d5f24e90b552a6d446f0d02e4
# Author: 30 seconds of code
# Date: Tue Apr 6 11:11:08 2021 +0300
# [...]

Tip #11

Merges a branch into the current branch, creating a merge commit.

  • Use git checkout <target-branch> to switch to the branch into which you want to merge.
  • Use git merge --no-ff -m <message> <source-branch> to merge a branch into the current branch, creating a merge commit with the specified <message>.
  • The --no-ff flag prevents git merge from executing a "fast-forward" if it detects that your current HEAD is an ancestor of the commit you're trying to merge. A fast-forward is when, instead of constructing a merge commit, git just moves your branch pointer to point at the incoming commit. This commonly occurs when doing a git pull without any local changes.

So when I can use --no-ff ?

Occasionally you want to prevent this behavior from happening, typically because you want to maintain a specific branch topology (e.g. you’re merging in a topic branch and you want to ensure it looks that way when reading history). In order to do that, you can pass the --no-ff flag and git merge will always construct a merge instead of fast-forwarding.

Similarly, if you want to execute a git pull or use git merge in order to explicitly fast-forward, and you want to bail out if it can't fast-forward, then you can use the --ff-only flag. This way you can regularly do something like git pull --ff-only without thinking, and then if it errors out you can go back and decide if you want to merge or rebase.

Let’s know the difference between non-fast-forward merge and fast-forward merge, rebase, squash.

Explicit Merge (aka non-fast-forward): Creates a new merge commit. (This is what you will get if you used --no-ff.)

Fast Forward Merge: Forward rapidly, without creating a new commit:

Rebase: Establish a new base level:

Squash: Crush or squeeze (something) with a force so that it becomes flat:

Might be you’re asking now what’s the difference between fast-forward and rebase merge?

I’ll make another blog explain each one in-depth, but let me give you a quick answer now to sure you fully understand.

Fast-Forward maintains the same base and tries to merge all file changes from the same changes after the shared base.

Rebase “detaches” your branch, and then applies commit after commit on top of the base (as if you just checked out a fresh e.g. master branch), and THEN, tries to, apply the changes done on the new base. The rebase is usually used before you’d want to merge into master, so that it applies the topic-commits on top of master, without merge conflicts.

Hope this article is useful.

Let’s connect on LinkedIn, Twitter

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Abdlrahmansaber

Abdlrahmansaber

Software engineer, Problem solver, Geek.