Skip to content

Instantly share code, notes, and snippets.

@jherax
Last active May 2, 2025 16:01
Show Gist options
  • Save jherax/6a756503065e991197e70e8feb319128 to your computer and use it in GitHub Desktop.
Save jherax/6a756503065e991197e70e8feb319128 to your computer and use it in GitHub Desktop.
Git Alias and Rebase

Git Alias and Git Rebase

WHEN TO DO REBASE

Performing a daily rebase is good, in order to be up-to-date with the changes in the integration branch.

WHY? Because you integrate the progress of the base branch into YOUR branch, so that you will have fewer conflicts to resolve, and the rebase process will take less commits to apply when rebasing against your branch.

💡 TIP You can rebase your current branch against the remote branch by using the alias rebasebr

git rebasebr main

The sooner you REBASE your branch, the fewer conflicts to resolve.

WHAT NOT TO DO

Do not rebase against multiple branches. Try to have only one integration branch. This way we will keep an eye only in one branch, for example, main as your default integration branch.

AVOID as much as possible mutate stable branches such as main, DO NOT rebase main against another branch, and DO NOT perform an interactive rebase on main. Remember that the git rebase command rewrites the branch’s history (SHAs). That is becasuse when performing a rebase or rebase -i, you can reorder, edit, merge, or delete commits, hence the identity (SHA) of each commit affected will change.

Example 1

  • Let's say this is the last commit on main: 6ace7bf4 [US-703] Fixed bug #12 on MultiSelect component,
  • Then we perform an interactive rebase to merge old commits: git rebase -i HEAD~4.
  • The history on main has changed, and the last commit has a new SHA: c18b70b2 [US-703] Fixed bug #12 on MultiSelect component.

After reordering or merging commits, the identity of the subsequent commits will change, giving them a new SHA. That means that my local branch main has diverged from the remote branch main. So to upload my changes to the server we will have to force the push: git push --force-with-lease origin main. But this is a BAD PRACTICE, because usually main is protected, but also, performing a forced-push on main will affect to all team members. Basically the SHAs on my mutated main are different from the other guys, not because there are new commits, but because the existing commits have a different SHA.

💡 IMPORTANT

If you have to deal with that problem, you can use the powerful rebase --onto.

REBASE ONTO

You can rebase a part of a branch using a specific commit in your branch as the starting point to rebase against another branch (or SHA).

The syntax for Git command is: git rebase [--onto <new-base>] [<old-base> [<target-branch>]]

In our previous case, after the main branch was mutated, we can run git rebase --onto by specifying the new-base (main) and the old-base commit (starting point) in our target-branch.

# current branch: feat-x

# get latests changes of remote main
git fetch origin main

# look for the old-base SHA commit
git log --oneline
# 6ace7bf4 is the last commit (old-base) not belonging to my branch feat-x

# git rebase [--onto <new-base>] [<old-base> [<target-branch>]]
git rebase --onto origin/main 6ace7bf4 feat-x

With the above command we are telling to git rebase --onto to apply origin/main as the new-base and replace the old-base SHA, to finally update the target-branch feat-x with the new history line.

💡 TIP The previous command can be achieve using the alias rebaseonto
git rebaseonto origin/main 6ace7bf4

🔍️ Read more about rebase --onto:

INTERACTIVE REBASE

The git rebase -i help us to reorganize commits in our branch. The following are the possible actions you can perform:

# Commands:
# p, pick <commit> = use commit
# r, reword <commit> = use commit, but edit the commit message
# e, edit <commit> = use commit, but stop for amending
# s, squash <commit> = use commit, but meld into previous commit
# f, fixup <commit> = like "squash", but discard this commit's log message
# x, exec <command> = run command (the rest of the line) using shell
# d, drop <commit> = remove commit
# l, label <label> = label current HEAD with a name
# t, reset <label> = reset HEAD to a label
# m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]

Let's assume these are the commits in our branch, where {1} represents the oldest commit, and {4} represents the most recent commit.

{1} sha-0b2-1 [US-753] Fixed issue #16 on Linear component
{2} sha-9fa-2 753 WIP
{3} sha-774-3 753 WIP 2
{4} sha-bb0-4 [US-703] Fixed bug #12 on MultiSelect component

The alias git rebaseii X allows you to edit the last X commits, so that we can reorganize commits in our branch, modify messages, remove, reorder or meld commits. This also is a GOOD PRACTICE before a PR, to reduce noise and facilitate code review.

# us-753 is our current branch.
# Rebase the last 4 commits.
$ git rebaseii 4

The editor will show the prompt with the commands for the last 4 commits:

pick  sha-0b2-1 [US-753] Fixed issue #16 on Linear component
fixup sha-9fa-2 753 WIP
fixup sha-774-3 753 WIP 2
pick  sha-bb0-4 [US-703] Fixed bug #12 on MultiSelect component

# Commands:
# p, pick <commit> = use commit
# r, reword <commit> = use commit, but edit the commit message
# e, edit <commit> = use commit, but stop for amending
# s, squash <commit> = use commit, but meld into previous commit
# f, fixup <commit> = like "squash", but discard this commit's log message
# x, exec <command> = run command (the rest of the line) using shell
# d, drop <commit> = remove commit
# l, label <label> = label current HEAD with a name
# t, reset <label> = reset HEAD to a label
# m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]

In this scenario we are going to "fixup" (meld) the two WIP... commits into the predescessor commit, that is to meld 753 WIP 2 and 753 WIP into [US-753] Fixed issue #16 on Linear component.

After saving changes, our new log will be:

c18b70b2 [US-753] Fixed issue #16 on Linear component
6ace7774 [US-703] Fixed bug #12 on MultiSelect component

🔍️ Read more about rewriting-history:

GIT ALIAS

All git alias used in this document assumes main as the default integration branch.
See git-alias.sh, git-alias.ini and NEW ALIAS.

REGISTER ALIAS

You can register the aliases in two ways:

  1. Run git-alias.sh: sudo chmod +x git-alias.sh then bash git-alias.sh
  2. Open a terminal and run: code ~/.gitconfig or git config --global -e, and paste the content of git-alias.ini into the [alias] placeholder.

NEW ALIAS

newbr

Creates a new branch starting from the current branch.
First, check for updates in the current branch, then apply updates, and finally creates the new branch and check out to it.

# Alias:
# git pull origin <current-branch> --rebase && git checkout -b <new-branch>
$ git newbr new-branch

Why use lowercase when naming branches?

Because it reduces errors in the file system when dealing with different platforms.
Linux is case-sensitive for file names, while Windows is not.

When you create a branch, git internally creates a folder for that branch.
A folder named us-753 is not the same as US-753 in a linux server, but for Windows it is the same. Just avoid headaches.

rmbr

Removes a branch from your local and remote.

# Alias:
# git branch -D <branch-name>; git push origin --delete <branch-name>
$ git rmbr branch-name

currentbr

Gets the name of your current working branch.
Useful for creating other scripts.

# Alias:
# git branch | grep \* | cut -d " " -f2
$ git currentbr

syncbr

Update references from remote branches and prints the list of remote branches. HEAD and main are not listed.

# Alias:
# git remote update origin --prune && git branch --remote
$ git syncbr

commitall

Adds all untracked and unstaged files, and creates a new commit with a message.

# Alias:
# git add -A && git commit -a -m "message"
$ git commitall "[US-741] My commit message"

amend

Append all untracked and unstaged files to the last commit. No message is added. The SHA of the last commit is modified.

# Alias:
# git add -A && git commit -a --amend --no-edit
$ git amend

pushf

Pushes the current branch to the server with the --force-with-lease flag, to check changes in remote and perform a force-push of your branch, useful when the git amend alias is used.

# Alias:
# git push --force-with-lease origin <current-branch>
$ git pushf

Commit and push changes

A basic example to commit changes:

# creates a new commit message including all changes
$ git commitall "[US-753] New commit"

# add new changes to the last commit
$ git amend
$ git pushf

pullbr

Performs a rebase of the current branch against the remote branch. Gets the latest changes on my remote branch and synchronize it with my local branch.

# Alias:
# git pull origin <current-branch> --rebase
$ git pullbr

resetbr

Reset an specific local branch whith the remote branch.

# Alias:
# git checkout <branch> && git fetch origin <branch> && git reset --hard origin/<branch>
$ git resetbr main

rebaseii

Performs an interactive rebase on your local branch. See the INTERACTIVE REBASE section.

# Alias:
# git rebase -i HEAD~<max-commits>
$ git rebaseii 5

rebasebr

Performs a rebase against another remote branch.

# Alias:
# git fetch origin <branch> && git rebase origin/<branch>
$ git rebasebr main

rebaseonto

Peforms a rebase against another branch changing the old-base SHA.
Useful when the target branch has been mutated.
See the REBASE ONTO section.

# Alias:
# git rebase --onto <branch> <old-base-SHA> <current-branch>
$ git rebaseonto main 6ace7bf4
$ git rebaseonto integration 6ace7bf4

mergeto

  1. Checkout to the target branch and update it from remote
  2. Merges your feature branch into the target branch
  3. Push the target branch to the server
  4. Delete the merged branch from both, local and server
# Alias:
# git resetbr main && git mergebr <feature-branch> && git rmbr <feature-branch>
$ git mergeto main

Let's assume our current branch is feat-x, so for the previous command we update the local main branch with the latest remote changes, then merge the feat-x branch into main, and finally we remove the feat-x branch.

mergebr

Merges an specific branch into the destination branch.

For the next example, we are going to merge the feat-x branch into main. This alias is similar to mergeto except that mergebr does not remove the merged branch.

  1. Checkout to the target branch and update it from remote
  2. Merge the feature branch into the target branch
  3. Push the target branch to the server
# Alias:
# git checkout main && git pullbr && git merge feat-x && git push origin main
$ git mergebr feat-x main

Merges feat-y branch into the default main branch.

# Alias:
# git checkout main && git pullbr && git merge feat-y && git push origin main
$ git mergebr feat-y

cleanmerged

Removes all merged branches into the target branch.

  1. Checkout to the target branch and update it from remote
  2. List all merged branches into the target branch
  3. Removes the merged branches

This method is destructive. Do not use it unless you know what you are doing!

# Alias:
# git checkout <branch> && git branch --remote --merged <branch> | xargs git rmbr
$ git cleanmerged main

untrack

Temporarily untrack changes in a specific file, so it will be excluded from commits.

# Alias:
# git update-index --assume-unchanged <path>
$ git untrack path/to/file

track

Track changes again from an untracked file, so it will be included in commits.

# Alias:
# git update-index --no-assume-unchanged <path>
$ git track path/to/file

logn

Show structured info about commits in one-line format: sha date message author refs By default the last 10 commits are listed, but you can pass an argument with the number of commits to display.

# Alias:
# git log --graph --abbrev-commit --decorate --date=short --format=format:"custom-format" -10
$ git logn
$ git logn 20

logauthor

List all commits in the current branch authored by an specific user, starting from a given date (yyyy-MM-dd).

# Alias:
# git log --pretty="custom-format" --date=short --author=david.rivera --since=2018-10-01
$ git logauthor david.rivera 2018-10-01

List all commits in the current branch authored by an specific user, between a given date range (yyyy-MM-dd).

# Alias:
# git log --pretty="custom-format" --date=short --author=david.rivera --since=2018-10-01 --until=2018-11-01
$ git logauthor david.rivera 2018-10-01 --until=2018-11-01

Show commits in all local branches authored by an specific user, starting from a given date (yyyy-MM-dd).

# Alias:
# git log --pretty="custom-format" --date=short --author=david.rivera --since=2018-10-01 --all
$ git logauthor david.rivera 2018-10-01 --all

List all commits in the current branch authored by an specific user that modified a specific file, starting from a given date (yyyy-MM-dd).

# Alias:
# git log --pretty="custom-format" --date=short --author=david.rivera --since=2018-10-01 --follow -- path/to/file
$ git logauthor david.rivera 2018-12-01 --follow -- path/to/file

🔍️ Learn more about pretty-format at https://git-scm.com/docs/pretty-formats.

[alias]
co = checkout
cp = cherry-pick
st = status -s
untrack = !git update-index --assume-unchanged
track = !git update-index --no-assume-unchanged
logn = "!f() { n=${1:-10}; git log --graph --abbrev-commit --decorate --date=short --format=format:\"%C(blue)%h%Creset %C(green)(%ad)%Creset %s %C(red)%an%Creset%C(yellow)%d%Creset\" -$n; }; f"
logauthor = "!f() { a=\"$1\"; b=\"$2\"; shift 2; git log --date=short --pretty=\"format:%C(green)%ad%Creset %C(yellow)%h%Creset %C(white)%s%Creset\" --author=$a --since=$b $@; }; f"
currentbr = "!f() { git branch | grep \\* | cut -d \" \" -f2; }; f"
remotebr = "!f() { br=${1-main}; git branch --remote | cut -c10- | grep -vE \"HEAD$|main$|${br}$\"; }; f"
syncbr = !git remote update origin --prune && echo -e \"\\e[36mRemote branches...\" && git remotebr
newbr = !git pullbr && git checkout -b
rmbr = "!f() { git branch -D $1 2>/dev/null; git push origin --delete $1 2>/dev/null; }; f"
commitall = !git add -A && git commit -a -m
amend = !git add -A && git commit -a --amend --no-edit
pushf = "!f() { git currentbr | xargs git push --force-with-lease origin; }; f"
pullbr = "!f() { br=$(git currentbr); git pull origin ${br} --rebase; }; f"
resetbr = "!f() { br=${1-main}; git checkout ${br} && git fetch origin ${br} && git reset --hard origin/${br}; }; f"
rebaseii = "!f() { git rebase -i HEAD~$1; }; f"
rebaseonto = "!f() { git rebase --onto $1 $2 $(git currentbr); }; f"
rebasebr = "!f() { br=${1-main}; git fetch origin ${br} && git rebase origin/${br}; }; f"
mergebr = "!f() { br=${2-main}; git checkout ${br} && git pullbr && git merge $1 && printf \"\\nPushing to origin ${br} ...\\n\"; git push origin ${br}; }; f"
mergeto = "!f() { br=$(git currentbr); git resetbr $1 && printf \"\\nMerging branch ${br} into $1 ...\\n\"; git mergebr ${br} $1 && git rmbr ${br}; }; f"
cleanmerged = "!f() { br=${1-main}; git resetbr ${br} && git branch --remote --merged ${br} | cut -c10- | grep -vE \"HEAD$|main$|${br}$\" | xargs git rmbr; }; f"
#!/bin/bash
# @see
# https://cutt.ly/git-aliases
# @see
# https://git-scm.com/docs/pretty-formats
# Default Integration Branch: main.
# If you use another integration branch, just replace
# the "-main" name by the branch name you are using.
git config --global alias.co 'checkout'
git config --global alias.cp 'cherry-pick'
git config --global alias.st 'status -s'
git config --global alias.untrack '!git update-index --assume-unchanged'
git config --global alias.track '!git update-index --no-assume-unchanged'
git config --global alias.logn '!f() { n=${1:-10}; git log --graph --abbrev-commit --decorate --date=short --format=format:"%C(blue)%h%Creset %C(green)(%ad)%Creset %s %C(red)%an%Creset%C(yellow)%d%Creset" -$n; }; f'
git config --global alias.logauthor '!f() { a="$1"; b="$2"; shift 2; git log --date=short --pretty="format:%C(green)%ad%Creset %C(yellow)%h%Creset %C(white)%s%Creset" --author=$a --since=$b $@; }; f'
git config --global alias.currentbr '!f() { git branch | grep \* | cut -d " " -f2; }; f'
git config --global alias.remotebr '!f() { br=${1-main}; git branch --remote | cut -c10- | grep -vE "HEAD$|master$|${br}$"; }; f'
git config --global alias.syncbr '!git remote update origin --prune && echo -e "\e[36mRemote branches..." && git remotebr'
git config --global alias.newbr '!git pullbr && git checkout -b'
git config --global alias.rmbr '!f() { git branch -D $1 2>/dev/null; git push origin --delete $1 2>/dev/null; }; f'
git config --global alias.commitall '!git add -A && git commit -a -m'
git config --global alias.amend '!git add -A && git commit -a --amend --no-edit'
git config --global alias.pushf '!f() { git currentbr | xargs git push --force-with-lease origin; }; f'
git config --global alias.pullbr '!f() { br=$(git currentbr); git pull origin ${br} --rebase; }; f'
git config --global alias.resetbr '!f() { br=${1-main}; git checkout ${br} && git fetch origin ${br} && git reset --hard origin/${br}; }; f'
git config --global alias.rebaseii '!f() { git rebase -i HEAD~$1; }; f'
git config --global alias.rebaseonto '!f() { git rebase --onto $1 $2 $(git currentbr); }; f'
git config --global alias.rebasebr '!f() { br=${1-main}; git fetch origin ${br} && git rebase origin/${br}; }; f'
git config --global alias.mergebr '!f() { br=${2-main}; git checkout ${br} && git pullbr && git merge $1 && printf "\nPushing to origin ${br} ...\n"; git push origin ${br}; }; f'
git config --global alias.mergeto '!f() { br=$(git currentbr); git resetbr $1 && printf "\nMerging branch ${br} into $1 ...\n"; git mergebr ${br} $1 && git rmbr ${br}; }; f'
git config --global alias.cleanmerged '!f() { br=${1-main}; git resetbr ${br} && git branch --remote --merged ${br} | cut -c10- | grep -vE "HEAD$|master$|${br}$" | xargs git rmbr; }; f'
echo;
echo "@git: all aliases registered!"
echo "@see: https://cutt.ly/git-aliases"

Configuring tools

In order to use rebase and other commands, it is recommended to have properly configured the git editor.

Difftool

Set the shared configuration for difftool and mergetool.

git config --global mergetool.keepTemporaries false
git config --global mergetool.keepBackup false
git config --global mergetool.prompt false
git config --global difftool.prompt false

# Enable "reuse recorded resolution"
# https://cutt.ly/git-rerere
git config --global rerere.enabled true

Now we are going to configure VS Code as the default tool.

# https://stackoverflow.com/a/36644561/2247494
git config --global core.editor "code --reuse-window --wait"
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.trustExitCode true
git config --global mergetool.vscode.cmd 'code --wait $MERGED'

Other difftools

Other editors

  • VS Code

    git config --global core.editor "code --wait"
  • Sublime Text

    git config --global core.editor "subl -n -w"
  • Atom

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

🔍️ Read more about Associating text editors with Git.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment