Using Git from the command line

When I was a Git beginner I used TortoiseGit. TortoiseGit had all the features I had ever needed at the time. I could check out branches, stage files for commit, commit changes, push the branches, and do merges. I could even do a “fetch’n rebase.” Over time, as I became more and more familiar with Git, I switched over to using the command line.

I use Git from the command line for several reasons:

  • It is much faster than using a GUI. With a GUI I have to find the places where I need to click, click on the right buttons or items, make sure the right checkboxes are checked, click in the textbox so I can type my commit message, switch between keyboard and mouse again, and so on. With the command line I just type my desired command (e.g., git commit -m "Some nice commit message"), hit Enter, and then I’m done.
  • I think in terms of Git commands. I’d rather just type the commands than translate them into a sequence of actions the GUI requires me to take.
  • Git is much more powerful from the command line. All Git features are available in the command line. On the other hand, GUIs omit some less common or advanced features such as reverting a merge commit.
  • Because I type the commands in myself, it is easier to understand what Git is actually doing. In contrast, GUIs are an abstraction layer built on top of the Git commands and often hide (or make less visible) important details that I would see in the command line.
  • Sometimes I work in environments where there is no desktop GUI, and Git must be used from the command line.

Below I will go over some common Git commands. This documentation is of course not comprehensive, but they should cover most of the use cases I’ve run into.

Shortcuts

Configuration

NOTE: For the below git config commands, add the --global flag to read/write configuration settings at the user-specific level (~/.gitconfig), or --system to read/write the settings at the system-wide level ($(prefix)/etc/config). If neither of these flags are used, the settings are read or applied at the project level.

To list all the configuration options in your project:

git config --list

To set your name and email in the commits you author:

git config user.name "Your Name"
git config user.email "your.name@example.com"

To automatically prune remote-tracking branches that no longer exist in the remote after each fetch/pull:

git config fetch.prune true

To set the behavior of git push (without any other parameters) to push the current branch to a remote branch of the same name:

git config push.default current

To tell Git to not mess with line endings on checkout or push (i.e., checkout as is, commit as is):

git config core.autocrlf false
  • This is important in situations where you’re working in Windows but for technical reasons some files need to have Unix line endings.

Listing branches

To list all your local branches:

git branch

To list all remote branches:

git branch -r

To list all your local branches matching some pattern:

git branch -l "feature/some-pattern-*"

To list all local branches that have been merged into your current branch:

git branch --merged

Listing tags

To list all tags:

git tag

To list all tags matching some pattern:

git tag -l "1.2.*"

Branch operations

To create a new branch at the HEAD:

git branch new-branch
  • If the new branch already exists, add the -f option to force the creation.
  • To create a new branch somewhere else, add a starting point as the fourth parameter.

To rename the current branch:

git branch -m new-branch
  • If the new branch already exists, use either -mf or -M in place of -m to force the renaming.

To delete one or more branches:

git branch -d branch-1 branch-2
  • If a branch already exists, use either -df or -D in place of -d to force the deletion.

Tag operations

To create a new local tag at the HEAD:

git tag 1.2.3
  • To create a new tag somewhere else, add a starting point as the fourth parameter.
  • If the tag already exists, use -f or --force to update the tag locally.
  • Remember, a tag is not yet in the remote until it is pushed.

To delete one or more tags:

git tag -d 1.0.1 1.0.2

Checking out branches

To checkout an existing branch:

git checkout some-branch
  • You can also specify a tag or SHA-1 in place of the branch name.
  • Add the --detach option to enter a detached state.

To checkout a new branch at the HEAD:

git checkout -b new-branch
  • If the new branch already exists, use either -bf or -B to force the checkout and reset that branch to the current HEAD.

To checkout the last branch you were on previously:

git checkout -

To enter a detached state:

git checkout --detach
  • Add a starting point as the fourth parameter to reset to that point before detaching.

File operations

To stage the changes in one or more files or directories for commit:

git add path/to/file path/pattern/*

To unstage the changes in one or more files or directories:

git restore --staged path/to/file path/pattern/*

To remove unstaged changes from one or more files or directories, while preserving the staged changes:

git restore path/to/file path/pattern/*

To revert (hard reset) one or more files or directories:

git checkout -- path/to/file path/pattern/*
  • There must be spaces on both sides of the -- separator.
  • Add a starting point before the -- separator to change the file’s contents to whatever they are at that point.

To remove one or more files:

git rm path/to/file path/pattern/*
  • Add the -r option if you need to recursively remove a directory.
  • Add the --cached option to remove the file from the Git index without removing it from your filesystem. (I suggest only doing this if you’re adding said file to .gitignore.)

To remove all untracked files recursively:

git clean -df

Displaying the status

To show the working tree status:

git status

Displaying diffs

To show changes that have not yet been staged:

git diff

To show changes that have been staged:

git diff --cached

To show both staged and unstaged changes at once:

git diff HEAD
  • To show the changes since a different starting point, replace HEAD with that revision.

To show changes from one revision to another:

git diff revision-1 revision-2
  • The starting revision comes first, followed by the destination revision.
  • Normally, you should put the earlier revision first. Reversing the order of the revision parameters would reverse the diff.
  • If the revisions are on separate branches that have diverged, the resulting changes would be the reverse diff from the first revision down to the merge-base of the two revisions, plus the forward diff from the merge-base to the second revision.

To show which files have been changed without showing the actual diff:

git diff --stat
  • The width of the output usually defaults to 80 characters. If you see file names being truncated, you can increase the width, like in this example:
git diff --stat=200

To show the contents of the last commit:

git show

To show the contents of any other commit:

git show some-commit

Committing changes

To commit staged changes only:

git commit
  • This will bring up a text editor (usually Vim) where you can edit the commit message. By default, lines beginning with # will not be part of the commit message.

To set the commit message inside the command, bypassing the text editor:

git commit -m "Some nice commit message"

To stage all changes before committing:

git commit -a
  • NOTE: This will not add new files to the commit. The quickest way to add all changes to the index, including the untracked (but not ignored) files, is to run git add ..

To amend the last commit:

git commit --amend

Resetting

To remove all uncommitted changes from the current working tree (hard reset):

git reset --hard
  • If you add a starting point, it moves the current branch to that spot in addition to removing all uncommitted changes.
  • I commonly use git reset --hard HEAD~1 to completely undo my last commit.

To unstage (but retain) all uncommitted changes (mixed reset):

git reset
  • The --mixed option is enabled by default. You may choose to add it explicitly if you’d like.
  • If you add a starting point, it moves the current branch to that spot, but the working tree is preserved. That is, the difference between the starting point and where the HEAD was is added as unstaged changes.

To move the current branch while retaining both the working tree and index:

git reset --soft some-starting-point
  • This is similar to a mixed reset except that the difference between the starting point and where the HEAD was becomes staged.
  • You can use git reset --soft HEAD~1 if you need to edit your last commit but want to keep the existing changes staged.

Merging

To merge a branch (or branches) into the current branch:

git merge some-branch
  • You may also merge tags and SHA-1s.
  • Typically, the best practice is to merge only one branch at a time. If you merge multiple branches at once, this is called an “octopus merge.”
  • By default, merges are fast-forward (-ff) if the branch to merge already contains the HEAD.
  • Use the --no-ff option to create a merge commit even if the branch to merge already contains the HEAD.

To continue merging after all conflicts have been resolved, you have two options:

git commit
git merge --continue
  • The difference is that git merge --continue simply calls git commit after checking if there is a merge in progress.

To abort a merge (especially when there is a conflict):

git merge --abort

Rebasing

To replay commits from your current branch onto another branch, beginning after the point where the branches diverged:

git rebase some-branch
  • This will drop the affected merge commits from the rebase TODO list. To include merge commits, add the -r or --rebase-merges option.

To perform an interactive rebase:

git rebase -i some-branch

To continue rebasing after all conflicts have been resolved:

git rebase --continue

To abort a rebase (especially when there are conflicts):

git rebase --abort

Cherry-picking

To cherry-pick one or more commits:

git cherry-pick commit-1 commit-2
  • Commits are cherry-picked in the order you supply them.
  • If you supply a branch name, the commit that the branch is pointing to will be cherry-picked.
  • Add the -n or --no-commit option to cherry-pick the changes from those commit without committing them to the current branch.

To cherry-pick commits that are on another branch but not in HEAD:

git cherry-pick ..some-branch

To continue cherry-picking after all conflicts are resolved:

git cherry-pick --continue

To abort a cherry-pick (especially when there are conflicts):

git cherry-pick --abort

Reverting commits

To revert one or more commits:

git revert commit-1 commit-2
  • Commits are reverted in the order you supply them.
  • A commit is created for each commit you revert.
  • If you supply multiple commits, Git will stop after each commit and make you run git revert --continue to patch the commits one-by-one until you are done.
  • Add the -n or --no-commit option to undo the changes from those commits without committing them to the current branch. By following this action with git commit, you can put all those reverts into a single commit.
  • The above command will not work for merge commits. To revert the changes that were introduced into the current branch by a merge commit:
git revert -m 1 some-merge-commit
  • There is some documentation written by Linus Torvalds giving details on how to deal with faulty merges. It is common to continue development on the offending branch after the merge commit has been reverted. To do this, first fast-forward (a.k.a. reset) the offending branch to the commit that reverted the merge, then revert the revert.

To continue reverting (especially after all conflicts have been resolved):

git revert --continue

To abort a revert (especially when there are conflicts):

git revert --abort

Reading from the repository

To update the remote-tracking branches without merging:

git fetch
  • If you don’t have fetch.prune enabled, you can add the -p option to prune remote-tracking branches that no longer exist in the remote. The same applies when you run git pull.

To do both a fetch and an immediate merge of the upstream remote-tracking branch into your current branch:

git pull
  • Add the -r or --rebase option to do a rebase instead of a merge. If the local and upstream branches have diverged, the best practice is to do a rebase to replay the commits on top of the upstream.
  • If there is no upstream assigned to the current branch, this will do a fetch only and then complain that there is no upstream.

Writing to the repository

To perform the default push behavior:

git push
  • Use the above command to push the current branch if push.default is set to current.
  • Otherwise, you can tell Git explicitly which branches or tags to push.
git push origin branch-1 branch-2
  • Add the -u or --set-upstream option to have the local branch track the remote branch as the upstream.
  • Add the -f or --force option to force a push even if the local branch and remote branch have diverged. This option is often necessary if you need to rebase a branch after you had already pushed it. Please use caution, though, as work can be lost if you are not careful.

To remove one or more remote branches or tags:

git push origin -d branch-1 branch-2 

Displaying commit logs

To show the commit logs on the current branch:

git log

To show the commit logs with a text-based graphical representation of the history:

git log --graph

To show the commit logs on a different branch:

git log some-branch

To show the commit logs for one or more files or directories:

git log -- path/to/file path/pattern/*
  • When filtering by directory, commits that changed any file inside that directory or recursive subdirectories are shown.
  • To exclude merge commits from the logs, add the --no-merges option before the -- separator.

Annotations

To show which revision and author last modified each line of a file:

git blame path/to/file
  • Add a revision as the following parameter to show the file and annotations as it was at that revision.

Leave a Reply

Your email address will not be published. Required fields are marked *