Git - Tips and Workflow Guidelines

This document presents diverse functionalities of git. Those functionalities will be put into context and the main usage will be presented. The main purpose of this document is to act as a reminder of what git can do and how it is used inside Systerel. This document is aimed to those who already know the basic use of git and want to go a little deeper into what you can do and why you should use a tool over another.

The first part will go into configuration, history management and useful tools for developing with git. The later part of this document will go through Systerel’s workflow integrating git. In appendices, you will find some configurations and templates that you can use for your own projects. To keep it simple, the configuration of the server will not be touched upon here.

In case you have any questions, do not forget to refer to the official git documentation. It contains all information regarding the mechanisms described here. But you will also find a lot of git experts in Systerel!

What is Git ?

In a sentence

Git is an open-source distributed version control tool used throughout the world for programming and development.

In more details

Git is an open-source project created by Linus Torvalds (Linux’ creator). It is a version control tool, meaning it is used to save and version projects for development. Git is also a distributed tool, it is oriented toward remote and shared work, allowing people from around the world to work on the same project at the same time. Although this tool tends to follow the same philosophy as Linux in terms of development or usage, you will be able to use it with Windows without any issue.

Git allows to store files and the modifications later made to those files. Each group of saved modifications is known as a commit. Using the history tree, you can revert to a previous state of the different files.

Whether you use it locally to version personal projects, or remotely to work with a team, git is a very useful and powerful tool that you can integrate in your workflow.

Some Vocabulary

  • branch: A pointer to a version of the repository, identified by a name.
  • commit: Group of modifications, with meta-data added (commiter, date, hash id).
  • fork: A copy of a repository not linked to the original repo.
  • HEAD: Reference to the current commit you are working with.
  • index: Staging space of your repo, all modifications you will commit go to your index.
  • local: Your local repo is the copy of the remote repository you will be working with on your computer.
  • patch: Group of modifications between two versions of the project.
  • remote: The remote repo is the repository everyone is working with, pushing to and pulling from it.
  • repo: The repo, or repository, is the directory that contains your project and all git’s meta-data.
  • tag: A tag allows to identify a specific commit, with a name, to note releases or versions in your history.
  • working tree: The working tree (or working directory) is the copy of the local repo you are directly working on.

For other specific vocabulary, you can find definition in the official documentation.

Tips and Advices

Git Configuration

Configuration Levels

There are multiple level of configuration:

  • system” will affect all users on the computer: <path>/etc/gitconfig
  • global” will affect every git repo for the current user: ~/.gitconfig
  • local” will affect only the associated git repo: <path_to_repo>/.git/config
  • each level overrides the previous one in case of conflict

You can directly modify the text files of selected configuration or use git config --<level> <category>.<setting> <value> command line. Example, for git config --global "FirstName LASTNAME", you will get in ~/.gitconfig:

    name = FirstName LASTNAME

Tool Configuration

Using git configuration, you can select which external tool will be used depending on the command you are running.

If you wish to replace vim with emacs, vscode, notepad, gedit…

$ git config --global core.editor <editor_name>

    editor = <editor_name>

To set up other tool for other command, meld for diff for example:

    tool = meld
    prompt = false
[difftool "meld"]
    cmd = Meld.exe $LOCAL $REMOTE

You can also use other external tools that use other default configuration. For example, starship or oh my zsh are both framework that include a custom git configuration.

Prompt Customization

To not get lost in your repos, branches, and other references, it is advised to configure the terminal you will be using, to suit your workflow. You should at least show the current branch you are using when in a git repo. You can refer to the prompt configuration in appendix to set up your prompt. If you wish to use it as is, just copy it to the end of your .bashrc or equivalent and restart you terminal.

End-of-line Format

Allows converting automatically Windows line endings (CRLF) in Linux line endings (LF) and vice versa. This parameter allows three options: true, false, input.

  • true will convert LF from the git repo to CRLF on your working tree:
    • use if you work on Windows in project with both line endings
    • this behavior can be a default depending on the editor you use
  • input will convert CRLF to LF if you check out on Linux: use if you work with Linux in project with both line endings
  • false will not cause any conversion, keep CRLF and LF as is: use on Windows with a homogenous line endings project or in case where different line endings are meaningful and should not be changed

Using the true or input settings can cause some issues, for example by converting the end-of-line of binary files. Git uses heuristic to identify wether a file need convertion or not. Those heuristic can be wrong in some cases and be the cause of bigger issues. Unless you have a specific use case, it is advised to just turn of this feature by setting it to false. You can set it by using git config --global core.autocrlf false.

External Tools

If you plan to have a basic use of git, to commit, merge, rebase…, you will be able to find some tools to help you in those endeavors. Tools, like “lazygit” or “gitk” for example, can improve your workflow. Still, in order to proceed with some of the more advanced operations, it may be required to use the command line interface directly.

Git Commit

Commit Name and Message

Configure a commit template that will open by default with the command git commit (without -m):

$ git config --global commit.template <PATH_TO_TEMPLATE.txt>

The text file must be written in plain text where a # character starts a comment (which will not be part of the commit message). This feature should be used to remind you of good practices related to writing a good commit. These good practices can change from project to project, but the following advice are always valid:

  • The title of the commit should be shorter than 50 characters
  • Keep a blank line between title and further body
  • Keep a homogenous format for the title for all commits
  • Wrap comments at 72 characters to properly display with other tools (git log for example)

You will find in appendix a file that you can use or adapt for your template, reminding you of the good practices to follow.

Regarding the content of the commit message, use it to: - give a summary of the changes (so that one can get rapidly an idea of what has changed without having to look to file modifications in detail) - explain why the change was made (e.g., cause of the change, ticket number, change request) - give any other piece of information related to the change (e.g., rationale for the approach taken, what has been tried but did not work)

This information will be useful later on, when you will try to understand why/how something was made.

Commit Good Practices

While planning your commit, you should keep in mind some recommendations. You should, as much as possible, keep your commit targeted on one topic, it will be easier to read later if you do not mix your features, bug fixes or refactors on the same commits. If you need to add a new library with many files or rename part of your files, keep it in a dedicated commit, to bring clarity to your history. Avoid adding big files or binaries to your commits. It will greatly increase the size of your repo while not being pertinent if it needs to change regularly. You can use external references (like LFS) to track your large files without impacting your repo.

As a reminder, for each commit: - One topic: fix, feature, refactor, doc, style… - One target: no multiple features - No compiled files: as long as they are reproducible locally - No big files: it will hinder your repo’s performances

Another advice would be to push only commit that can be compiled. This will enable you to use the git bisect command, when you find a bug, to find the commit that added the bug.

Working with Branches

A git branch is a reference to a commit. It is used to track features or versions. As suggested by the name, branches can diverge from each other. You can later use merge or rebase to either close a branch by melding it to another or by moving it in the history. When working with git, you will always be using a branch. By default, it could be “master”, be it will most certainly depends on what you are doing. When working on feature, a branch is usually created, to not hinder work of other people working in the same environment.

By using branches, you can also have multiple local configuration for the same repo, each branch corresponding to a given part of the history of the project. Also, keep in mind that branches can act as “safeguards”. If you need to prepare a big rebase, modifications or other manipulation that could destroy your repo, create a new branch on your current status, do your modifications on it, doing so, you will keep your original branch if needs be. Branches are associated with each repo. You can therefore have local-only branches if you need, and you can choose to not pull every remote branches.

Usually, branches can be used to mark versions of the project. It can also denote the status of development for example with “feature” branches merged on a “dev” branch itself merged on a “master” once the project is stable and ready for release.

If you have multiple branches that depends on each other, you should try to use merge commits as rebase could lead easily to some issues depending on the order or rebasing.

Git Merge/Rebase

There are two ways to combine work coming from two distinct git branches. You can use merge if you need to keep all the commits’ history. If this isn’t needed, you can use rebase instead. Each of these two commands have both pros and cons, so depending on your project you might use one or the other by default.

If you struggle to choose between the two commands, you can ask yourself the following questions:

  • Do you need to keep all commit history? => use merge
  • Do you prefer to have a clear and linear history? => use rebase

Keep also in mind that when you need to manage conflicts, merge and rebase act in different ways. Merge will add a new commit, combining your current branch with the target one. All conflicts resolution are added in the “merge commit” created. Rebase will instead “replay” all the commits from your current branch onto the target one, creating therefore completely new commits but with the same modifications. If your commit produce conflicts, the modification ensued to resolve those will be put into the conflicting commit. You won’t be able to distinguish which modification comes from your branch and which are due to the conflict resolution.

Git Pull/Fetch

The command git fetch updates your local repo up to the current status of the remote repo. It will not apply those modifications to your working tree. To apply those modifications, you can use either merge or rebase.

The command git pull is a combination of two commands: git fetch and then git <merge|rebase>. The choice between merge and rebase depends on your configuration. By default, it will be merge, but you can use git config --global pull.rebase true to have git pull use rebase instead.

    rebase = true

To avoid any issue with an involuntary merge or rebase commit, it is better practice to just use git fetch followed by either command you need.

Interactive Rebase

You may sometimes need to reorganize your commits, regarding their order, name and description, removing some or adding some files. For all of those operations, you can use git rebase -i <Commit_Ref>. It will open a new window that will allow you to make multiple operation. For further information on this topic you can refer to the documentation. Some important point to keep in mind are the following:

  • modify only local commit, else it will cause issues to your colleagues
  • beware that if you change the order of commit, it may have bad repercussion if you modify something yet to be added
  • don’t forget to correct the title/comment of the newly created commits
  • if you are not sure about the operation you are doing, don’t forget to create a new branch, to keep a status of your current branch before any modification

The default interface used by git is quite unfriendly and can be complex to use at start. If you often need to process rewriting of history but do not like the UI, tools like “lazygit” are advised.

Merge/Pull Requests

Some environment tools like Gitlab or Github have a functionality that allow to associate a feature to a branch and simplify the process of feedback and review. Gitlab uses “merge requests” whereas Github or Azure DevOps uses “pull requests”. The concept stay the same: a user posts an issue by opening a ticket; a merge/pull request is open from that ticket, creating a branch and access to a review tool to comment and approve/disapprove commits. Once the modifications are ready to be accepted and merged to the master, the merge/pull request is merged and closed, keeping all comments and review in archive. Once the merge/pull request is ready to be closed, it can be merged or rebased (even if it’s called merge request!) to the target branch.

In Systerel, merge request are fully integrated in the S2OPC’s development process. They are used to keep track of tickets currently being worked on, and to proceed with the review process.

Multiple Remote Repository

For the same local repository, you can have multiple remote servers associated. This feature has some uses such as: - Having two remote repos, one private with every commit and branches and one public with only certain commits - Store direct copies of the repo for saving/CI purposes - On a bridge computer between two networks, having two remotes allow to transfer a repo from one network to the other

In order to add a repository, use the command:

$ git remote add <remote_name> <remote_url>

As always, you can use ssh or https URL for your configuration. The URL of each remote can use different protocols.

To list remotes, use:

$ git remote -v

In order to push on a remote, you just have to specify which in you command (by default it will be “origin”):

$ git push <remote_name>

You can also fetch from a specific remote, or fetch from all remotes at once:

$ git fetch --all

Amending Commit and Force Push

While you can amend and remove commit, you must beware of only proceed to modification on your local-only commits. If you modify a commit that is already on the remote repo, pushing those modifications may create some issues as other people may have local commit referencing those pre-modification commits.

To prevent user mistakenly pushing modified commit, the “—force” option is mandatory when pushing a modification of commit history. Using external tools configuration or server hooks, you can prohibit “force push” from happening, based on user right for example. In any case, you should refer to your project git manager before trying to change your repo history.

If you need to execute a force push, you should do it with the following command:

$ git push --force-with-lease --force-if-includes

Those option avoid cases where you would erase some commit, by aborting your push operation.

Renaming Files

When you rename a file (with git mv), git will see it as a deletion of the old file (git rm) and by the addition of the new file (git add). But, as git track files using their content, git can use this information to assume that the file was renamed as the content did not change. Git will therefore be able to provide the history of the file before the change of name, using --follow option on git log for example.

If you rename the file, and you modify it in one commit, git (and external tools) might not be able to assume that it is not a new file as the content is not the same after changing name. You could therefore lose the ability to follow commits of the old named file. Moreover, mixing renaming and modification may make git loose track of the renaming. This is due to git uses of heuristics to identify renaming, if mixed with modifications, it has a higher probability of failing.

If you plan to rename some files in your repository, it is highly advised to rename all needed files in one commit and make modification in later commit to keep the history of those files after changing their names.

With some languages, like Java, the names of files are directly linked to the content of these files. Modifying those without renaming them will lead to a bad project status. To avoid losing the follow function of git, you should process the refactor of files in independent commits.

Big Files

Due to how git works internally, adding a big file to the repo will always have an impact even though another commit removes this file. It is therefore highly advised to not commit big files, or files that will change every commit like binaries. If these files can easily be generated, you can keep those in the working tree and add them to the .gitignore.

If you still need those files to be in your repo’s history, you can use git lfs (git Large File System). It will add links in your repo, those links will point to your big files stored externally from your repo.

Sub Module

If you have multiple projects, A and B for example, that use a project C in common, you might want to set up C as a submodule of A and B. The three projects will be independent git repos, each with their history. But, A and B will have a link to C and cloning either will also clone C’s repo. Also note that when using a project as submodule, it will be a specific commit of that project, allowing to “lock” it to a state that works for your project.

Set up Submodule

In order to add a project as a submodule to another, do:

$ git submodule add <repo_url>

You can now commit the file .gitmmodules.

When you clone or pull a repo that has a .gitmodules files, to get the submodule repo, do:

$ git submodule init
$ git submodule update

Managing Submodule - Pushing Modifications

When you work with a submodule, the version of this module will be tracked in your repository that includes it. You can find the commit hash of that module that you are using within commits, that you can log with git log -p <submodule_dir_path>.

You can modify a submodule directly from its directory, using it as a normal repository, changing files then adding those to commit. If you push or pull from the submodule repository, you will update the submodule’s repository only. The modification will still be notified by git status on the parent repository. In order to keep your submodule aligned with the parent repository, you will need to git add <submodule_dir_path> then commit and push it.

As a reminder, the workflow is the following when working with submodules:

I need to modify the sources of the submodule:
    * modify files in submodule *
    $ cd <submodule_dir_path>
    $ git add <changed_files>
    $ git commit
    $ git push
    $ cd <parent_repository>
    $ git add <submodule_dir_path>
    $ git commit
    $ git push

I need to pull remote modifications for my submodule:
    $ cd <submodule_dir_path>
    $ git pull
    $ cd <parent_repository>
    $ git add <submodule_dir_path>
    $ git commit
    $ git push

If you wish to update all your submodules with their remote repos, you can use git submodule update --remote.

Managing Submodule - Pulling Modifications

If you pull commits that affect both your parent repository and submodules, the modifications will be applied to the parent repo but not to the submodules. In order to do so, you will need the update the submodules by using git submodule update --init --recursive. Both option are used to initialize new submodules that you could be pulling, and update submodules of submodules.

You can have this command execute for every pull that you do with the option submodule.recurse set to true. You can set it up with git config --<config_level> submodule.recurse true.

Cleaning your Repo

From time to time, it can be useful to proceed to a cleaning of your repo. If you need to reduce the repo memory on disk, the command git gc will compact it for you. And if you wish to remove untracked files from the working tree (due to deleting a branch for example), use git clean.

Browsing History

Once your repository starts to grow, you will need to visualize the history of commits/branches. In order to do so, you can use the git log command. It is a highly configurable command with many options. If you need to print the history of specific files, use git log -- <files_path>, separating each path by a space. If you want the log for specific lines, you can use the option -L <first_line_nb>,<last_line_nb>:<file_path>.

The option -p will print the modifications contained by each commit shown.

Don’t forget to use aliases for configurations that you find useful. You will find example in the appendices of this document. If you need something more specific, please refer to the official documentation.

To visualize your repo’s history, you can also use external tools such as “gitk”. Run it with gitk in your git directory to visualize only your current branch or with gitk --all to show all branches.

Blaming Modifications

While you are writing your code, you may want to find out who did some modification to the part you are working on. Using the command git blame <file_path>, you will see, for each line, the commit and commiter that last changed the line. If you want to check out this information for a specific part, use the option -L <first_line_nb>,<last_line_nb>. Likewise, use the option --color-line to identify more clearly the output of the command.

Some tools have integrated “git blame”. For example, if you are using VScode, you can use extensions that will show you the git blame of current line at all time.


Git offers the possibility to create aliases in order to ease the use of complex commands. In order to do so, you can add the [alias] section in a git configuration file and add aliases with name = command. To use this alias, just use git name. You can add as many aliases, but beware of having multiple definitions with the same name.

If you need your alias to execute some shell instructions, you must use the following format:

# "f" is for "function"
name = "!f() { command; }; f" 

Furthermore, if you need argument with your alias, you must keep that format, adding argument where needed:

name = "!f() { command ${1}; }; f" 

Use it with: git name argument_$1.

You will find in appendices a list of alias used in Systerel. Feel free to use and adapt those according to your convenience.


Instead of using archive of full git repo, you can use the git bundle command. It is useful when you want to create backups of part or full repo. It can also be useful to save only the tracked files of your repo whereas a zip would take every file.

In order to create a bundle, you can use the following command:

$ git bundle create name.bundle master

You can specify the branch you want the bundle to be created from, replace “master” with corresponding name. If you want to take all branches, use --all option.

Once you have a bundle, you can create a new repo from it with git clone name.bundle. If needed, you can later update the origin URL to match with a server. You can also fetch from that bundle, incrementally add commits to the bundle or use it in other process. Don’t forget to go through documentation for more information about this topic

Bundles can be useful if you need to exchange work in absence of a distant repository. It also allows to exchanges commit history without giving access to a repository.


The stash functionality allows to store temporarily changes without creating a commit for it. It can be useful if you want to keep local configuration that should not go into the remote for example.

To save a stash with a message:

$ git stash push -m "my_stash_name"

To list stashes:

$ git stash list

To apply and remove the nth stash:

$ git stash pop stash@{n}

To apply and remove a stash by name:

$ git stash pop stash^{/my_stash_name}

To apply the nth stash:

$ git stash apply stash@{n}

To apply a stash by name:

$ git stash apply stash^{/my_stash_name}


A hook is a script that triggers when a command is launched or when an event happens. Using git, you can have hooks of two kind:

  • client-side hooks, that are setup and triggered only locally.
  • server-side hooks, triggered by everyone using the associated remote repo.

While hooks placed on a remote are enforced to everyone, you cannot force a user to use local hooks. Still, you can use local hooks to make some verifications before pushing your work. To setup a hook, write a script (shell, python, perl…), and put it into the /.git/hooks directory with the name corresponding to the trigger you are looking for. By default, you will find sample scripts for each trigger. You can activate these hook by removing “.sample” in the name.

Client-side hook can be useful to launch lint or format verification before you commit, using pre-commit trigger (see sample for whitespace verification). You can also use pre-rebase, for example, to abort rebase that would include commit already on the remote (see sample).

Some external tools can also be used to managed more complex hooks. Using pre-commit (see doc) tool or some language-specific like rusty-hook can be beneficial to you workflow.


Tools and platforms that integrates git, such as Gitlab, Github, Azure… often offer some configuration directly in their UI, without needing to manipulate the server git configuration. This can be of help often to ease the setup of hooks, CI, lint… Most of those tools also provide a “merge request” mechanism (name depending on the platform). It eases and clarify the development process, by creating a branch for each new feature, triggering reviews before being merged into the master branch. Some tools can also provide tracking of tickets, for review or quality purposes.

Workflow Example

We will now go over some example of git integration to the workflow of some Systerel’s projects.



S2OPC is an open-source implementation of the OPCUA protocol. While the repo is public, only Systerel employees can contribute. The project is hosted on GitLab, with an external, public repo and an internal private copy for client-specific developments.

Git Usual Workflow
  • When a topic needs development, a ticket is opened on Gitlab.
  • Then, once the description is complete and workload is attributed, a merge request is created for that topic.
  • While developing, the work is pushed to the repo, using Gitlab tools for review by peers.
  • A CI (Continuous Integration) is also setup to trigger with pushed work. It is used to run some test on the newly-pushed code, or to run some lint tools.
  • All commits are signed (see doc) to ensure identity of commiter.
  • Only rebase are used, in order to keep a linear and clean history, once the merge request is done, it is rebased on the main branch.
  • Branches are used for versioning the project.


Most of the above information comes from the main documentation site which contains all the documentation for git in English and French, among other languages.


Commit Template

# Commit title, use format define for your project
# No caps, no end-line point, be concise
# No more than 50 chars -------- which is here:  v

# Remember blank line between title and body.

# Commit body, explain why, not how
# Wrap at 72 chars ----------------------------------- which is here:  v

# footer 
# add relevant info, co-commiter, ...

Bashrc Example for User Prompt

Provided by MBO. Print branch name when in git repository.

# If in a Git repository, output "[branch+-%=*?^]", where
# "branch" is the current branch
# "+" if files have been added to the working directory but not the index
# "-" if files have been removed from the working directory but not the index
# "%" if files have been renamed in the working directory but not the index
# "=" if files have been copied in the working directory but not the index
# "?" if files exist in the working directory that have not been added or ignored
# "^" if the index is not empty
# If not in a Git repository, produce no output.
git_prompt() {
local branch=$(git branch --no-color 2>/dev/null | sed -n '/* \(.*\)/ s//\1/p')
if [[ -z $branch ]]; then return; fi

local status=$(git status --porcelain 2>/dev/null)

local add=$(echo "$status" | sed -n '/^.A.*$/      s//+/p' | head -n 1)
local del=$(echo "$status" | sed -n '/^.D.*$/      s//-/p' | head -n 1)
local mod=$(echo "$status" | sed -n '/^.M.*$/      s//*/p' | head -n 1)
local ren=$(echo "$status" | sed -n '/^.R.*$/      s//%/p' | head -n 1)
local cop=$(echo "$status" | sed -n '/^.C.*$/      s//=/p' | head -n 1)
#  local unk=$(echo "$status" | sed -n '/^??.*$/      s//?/p' | head -n 1)
local dir=$(echo "$status" | sed -n '/^[ADMRC].*$/ s//^/p' | head -n 1)

echo " [$branch$add$del$ren$cop$mod$unk$dir]"

PS1="\[\033[0;35m\]\u\[\033[0;37m\]@\[\033[0;33m\]\h\[\033[0;37m\]:\[\033[0;36m\]\w\[\033[0;32m\]\$(git_prompt)\[\033[0m\] \$ "

List of Aliases

# provided by MCL
    # some shortcuts
    st = status -s
    sw = switch
    co = checkout

    # log one line per change
    slog = log  --pretty=format:"%C(yellow)%h\\ %C(blue)%ad%C(red)%d\\ %C(cyan)%an\\ %C(auto)%s" --date=format:"%y-%m-%d\\ %H:%m"
    # log one line per change with graph view
    glog = log --pretty=format:"%C(yellow)%h\\ %ad%Cred%d\\ %Creset%s%Cblue\\ [%cn]" --decorate --date=short --graph
    # same as before but for all branches
    glogall = "!git glog  $(git rev-list -g --all)"
    # full log for all branch, view as a graph
    logall = "!git log --graph --decorate $(git rev-list -g --all)"

    # show branches sorted by age of activity
    wip = for-each-ref --sort='authordate:iso8601' --format=' %(color:green)%(authordate:relative)%09%(color:white)%(refname:short)' refs/heads
    # smart log: show simplified logs (tags, heads, merge,…)
    sl = log --graph --all --decorate --oneline --simplify-by-decoration
    overview = sl

    # remove a branch locally and on origin
    rmbranch = "!f(){ git branch -d ${1} && git push origin --delete ${1}; };f"
    # show HEAD sha1
    id = rev-parse HEAD
    # show incoming changes
    incoming = "!git remote update -p; git log ..@{u}"
    # show outgoing changes
    outgoing = log @{u}..
    # show big files in repository
    bigfiles = "!f(){ git rev-list --objects --all | git cat-file --batch-check='%(objecttype) %(objectname) %(objectsize) %(rest)' | sed -n 's/^blob //p' | sort --numeric-sort --key=2 | cut -c 1-12,41- | $(command -v gnumfmt || echo numfmt) --field=2 --to=iec-i --suffix=B --padding=7 --round=nearest; };f"
    # Does a git grep in all branches
    grepall = "!f(){ git grep \"${1}\" $(git rev-list --all); };f"

# provided by NBG
    ci = commit
    cia = commit --amend
    br = branch
    fp = fetch --prune
    rbsm = rebase -i master

    sh = show --color-words
    shn = !git sh --name-status
    shm = !git sh master..
    shmn = !git shm --name-status

    # print local modifications
    di = diff --color-words
    din = !git di --name-status
    dim = !git di master..
    dimn = !git dim --name-status

    ls = log --pretty=format:%C(yellow)%h%Cred%d\\ %Creset%s%Cblue\\ [%an] --abbrev-commit --graph --decorate
    lsm = !git ls master..$@
    lsn = !git ls --name-status
    # log current branch's commit than diff with master
    lsmn = !git lsn master..$@

# provided by PAB
    # log with a graph view
    graph = log --oneline --graph --decorate --all
    # log with a graph view with inforamtion on signature
    gr = log --pretty=format:\"%C(auto)%h%d %C(cyan)%G? %Creset%s\" --abbrev-commit --graph --decorate --all
    overview = gr --simplify-by-decoration

To get more example, you can go to ohmyzsh git plugin to see a bigger list of aliases.