DEV Community

Cover image for 10 insanely useful Git commands you wish existed – and their alternatives
Eyar Zilberman for Datree

Posted on • Updated on • Originally published at datree.io

10 insanely useful Git commands you wish existed – and their alternatives

There’s a git command for that

Git commands aren’t always intuitive. If they were, we would have these 10 commands at our disposal. They would be super useful for accomplishing common tasks like creating or renaming a git branch, removing files, and undoing changes.

For each git command in our wishlist, we’ll show you the commands that actually exist and you can use to accomplish the same tasks. If you’re still learning Git, this list reads like a tutorial and is worth keeping as a cheatsheet.


# 9 – git create branch: create a new branch with git checkout

The fastest way to create a new branch is to actually do it from the git terminal. This way you don’t have to use GitHub UI, for example, if you use GitHub for version control.

This command actually exists in git, only in a different name – $ git checkout.

How to create a branch with git checkout:

One-line command: $ git checkout -b <branch-name> master

-> commit-test git:(master) $ git checkout -b feature-branch master
-> commit-test git:(feature-branch) $
Enter fullscreen mode Exit fullscreen mode

Git tip: Just like with commit messages, having a naming convention for git branches is a good best practice to adopt.


# 8 – git force pull: overwrite local with git pull

You find out you’ve made changes that seemingly conflict with the upstream changes. At this point, you decide to overwrite your changes instead of keeping them, so you do a $ git pull and you get this error message:

-> commit-test git:(master) $ git pull
Updating db40e41..2958dc6
error: Your local changes to the following files would be overwritten by merge:
README.md
hint: Please, commit your changes before merging.
fatal: Exiting because of unfinished merge.
Enter fullscreen mode Exit fullscreen mode

How to overwrite local changes with git pull:

  1. Stash local changes: $ git stash
  2. Pull changes from remote: $ git pull
-> commit-test git:(master) $ git stash
Updating db40e41..2958dc6
Saved working directory and index state WIP on master: d8fde76 fix(API): remove ‘test’ end-point
-> commit-test git:(master) $ git pull
Auto-merging README.md
Merge made by the ‘recurive’ strategy.
README.md     | 1 +
ENDPOINT.js    | 3 ++–
2 files changes, 3 insertions(+), 1 deletions(-)
Enter fullscreen mode Exit fullscreen mode

Git tip: If you want to retrieve your changes just do: $ git stash apply


# 7 – git remove untracked files: delete untracked files from working tree

When having unnecessary files and dirs in your own local copy of a repository, and you want to delete those files, in opposed to just ignore them (with .gitignore), you can use git clean to remove all files which are not tracked by git.

How to remove untracked files and dirs:

  1. Start with a dry-run to see what will be deleted: $ git clean -n -d
  2. After you are sure, run the git clean command with “-f” flag: $ git clean -f -d
-> commit-test git:(master) $ git clean -n -d
Would remove dontTrackDir/untracked_file1.py
Would remove untracked_file2.py
-> commit-test git:(master) $ git clean -f -d
Removing dontTrackDir/untracked_file1.py
Removing untracked_file2.py
Enter fullscreen mode Exit fullscreen mode

Git tip: Instead of untracking files, a good practice is to prevent those files from being tracked in the first place by using .gitignore file.


# 6 – git unstage: unstage file(s) from index

When you’re adding files ($ git add) to the working tree, you are adding them to the staging area, meaning you are staging them. If you want Git to stop tracking specific files on the working tree, you need to remove them from your stage files (.git/index).

How to unstage file(s) from index:

  • Keep the file but remove it from the index: $ git rm --cached <file-name>
-> commit-test git:(master) $ git rm –cached unstageMe.js
rm unstageMe.js
Enter fullscreen mode Exit fullscreen mode
  • To leave the entire working tree untouched, unstage all files (clear your index): $ git reset
-> commit-test git:(master) $ git reset
Enter fullscreen mode Exit fullscreen mode

Git tip: you can also untrack files which already added to git repository based on .gitignore.


# 5 – git undo merge: abort (cancel) a merge after it happened

Sometimes you get in a situation (we’ve all been there) where you merged branches and realize you need to undo the merge because you don’t want to release the code you just merged.

How to abort (cancel) a merge and maintain all committed history:

  1. Checkout to the master branch: $ git checkout master
  2. Run git log and get the id of the merge commit: $ git log --oneline
  3. Revert merge by commit id: $ git revert -m 1 <merge-commit-id>
  4. Commit the revert and push changes to the remote repo. You can start putting on your poker face and pretend “nothing’s happened”.
-> commit-test git:(master) $ git log –oneline
812d761 Merge pull request #524 from datreeio/DAT-1332-resolve-installation-id
b06dee0 feat: added installation event support
8471b2b fix: get organization details from repository object

-> commit-test git:(master) $ git revert -m 1 812d761
Revert “Merge pull request #524 from datreeio/DAT-1332-resolve-installation-id”
[master 75b85db] Revert “Merge pull request #524 from datreeio/DAT-1332-resolve-installation-id”
1 file changed, 1 deletion(-)
-> commit-test git:(master) $ git commit -m “revert merge #524”
-> commit-test git:(master) $ git push
Enter fullscreen mode Exit fullscreen mode

Git tip: Instead of reverting merge, working with pull requests and setting up or improving your code review process can lower the possibility of a faulty merge.


# 4 – git remove file: remove file(s) from a commit on remote

You wish to delete a file (or files) on remote, maybe because it is deprecated or because this file not supposed to be there in the first place. So, you wonder, what is the protocol to delete files from a remote git repository?

How to remove file(s) from commit:

  1. Remove your file(s): $ git rm <file-A> <file-B> <file-C>
  2. Commit your changes: $ git commit -m "removing files"
  3. Push your changes to git: $ git push
-> commit-test git:(delete-files) $ git rm deleteMe.js
rm ‘deleteMe.js’
-> commit-test git:(delete-files) $ git commit -m “removing files”
[delete-files 75e998e] removing files
1 file changed, 2 deletions(-)
delete mode 100644 deleteMe.js
-> commit-test git:(delete-files) $ git push
Enter fullscreen mode Exit fullscreen mode

Git tip: When a file is removed from Git, it doesn’t mean it is removed from history. The file will keep “living” in the repository history until the file will be completely deleted.


# 3 – git uncommit: undo the last commit

You made a commit but now you regret it. Maybe you committed secrets by accident – not a good idea – or maybe you want to add more tests to your code changes. These are all legit reasons to undo your last commit.

How to uncommit (undo) the last commit:

  • To keep the changes from the commit you want to undo: $ git reset --soft HEAD^
  • To destroy the changes from the commit you want to undo: $ git reset --hard HEAD^
-> commit-test git:(undo-commit) $ git commit -m “I will regret this commit”
[undo-commit a7d8ed4] I will regret this commit
1 file changed, 1 insertion(+)
-> commit-test git:(undo-commit) $ git reset –soft HEAD^
-> commit-test git:(undo-commit) $ git status
On branch undo-commit
Changes to be committed:
(use “git reset HEAD <file>…” to unstage)

    modified: README.md
Enter fullscreen mode Exit fullscreen mode

Git tip: Git pre-commit hook is a built-in feature that lets you define scripts that will run automatically before each commit. Use it to reduce the need to cancel commits.


# 2 – git diff between branches

When you are working with multiple git branches, it’s important to be able to compare and contrast the differences between two different branches on the same repository. You can do this using the $ git diff command.

How to get the diff between two branches:

  • Find the diff between the tips of the two branches: $ git diff branch_1..branch_2
  • Produce the diff between two branches from common ancestor commit: $ git diff branch_1...branch_2
  • Comparing files between branches: $ git diff branch1:file branch2:file
-> commit-test git:(diff-me) $ git diff master..diff-me
diff –git a/README.md b/README.md
index b74512d..da1e423 100644
— a/README.md
+++ b/README.md
@@ -1,2 +1,3 @@
# commit-test
-Text on “master” branch
+Text on “diff-me” branch
Enter fullscreen mode Exit fullscreen mode

Git tip: diff-so-fancy is a great open source solution to make your diffs human readable.


# 1 – git delete tag: remove a tag from branch

In the case of a “buggy” release, you probably don’t want someone to accidentally use the release linked to this tag. The best solution is to delete the tag and remove the connection between a release and its co-related tag.

How to delete tag by removing it from branch:

  1. If you have a remote tag to delete, and your remote is origin, then simply: $ git push origin :refs/tags/<tag-name>
  2. If you also need to delete the tag locally: $ git tag -d <tag-name>
-> commit-test git:(delete-tag) $ git push origin :refs/tags/v1.0.0
To github.com:datreeio/commit-test.git
– [deleted]         v1.0.0
-> commit-test git:(delete-tag) $ git tag -d v1.0.0
Deleted tag ‘v1.0.0’ (was af4d0ea)
Enter fullscreen mode Exit fullscreen mode

Git tip: Not sure when or why to use tags? Read here to learn more (TL;DR: automatic releasing)


# 0 – git rename branch: change branch name

As I mentioned, having a branch naming convention a good practice and should be adopted as part of your coding standards, and it is especially useful in supporting automation of git workflows. But what to do when you find out your branch name is not aligned with the convention, after already pushing code to the branch? Don’t worry, you can still rename your branch.

How to rename branch name after it was created:

  1. Checkout to the branch you need to rename: $ git checkout <old-name>
  2. Rename branch name locally: $ git branch -m <new-name>
  3. Delete old branch from remote: $ git push origin :<old-name> <new-name>
  4. Reset the upstream branch for the new branch name: $ git push origin -u <new-name>
-> commit-test git:(old-name) $ git branch -m new-name
-> commit-test git:(new-name) $ git push origin :old-name new-name
Total 0 (delta 0), reused 0 (delta 0)
To github.com:datreeio/commit-test.git
–  [deleted]             old-name
* [new branch]      new-name -> new-name
-> commit-test git:(new-name) $ git push origin -u new-name
Branch new-name set up to track remote branch new-name from origin.
Everything up-to-date
Enter fullscreen mode Exit fullscreen mode

Git tip: Want to make sure all branch names will always follow your convention? Set a Git-enforced branch naming policy.


What's next?

Found some useful commands? you can also set alias commands for them!
Relevant alias to this blog post are provided by @mfrata in his comment - you can thank him :)


Originally posted on https://datree.io/resources/git-commands

Latest comments (17)

Collapse
 
stecman profile image
Stephen Holdaway

It'd be worth mentioning for #5 that reverting a merge commit is something you want to avoid if possible as it creates a mess when you want to merge your branch again later.

If your merge hasn't been pushed to a shared branch yet, git reset --hard <original-branch-head> is preferable as it actually removes all trace of the merge.

From the git revert docs:

Reverting a merge commit declares that you will never want the tree changes brought in by the merge. As a result, later merges will only bring in [commits introduced since the reverted merge]. This may or may not be what you want.

See the revert-a-faulty-merge How-To for more details.

Collapse
 
eyarz profile image
Eyar Zilberman

I agree, and this is also what I recommended in the git tip :)

Regarding using git reset command, you are correct, but I wanted to address the more complex scenario - when it was pushed to a shared branch.

Collapse
 
gergelypolonkai profile image
Gergely Polonkai

Starting with #9 on a “10 things…” list? I see what you did there ☺

This is an awesome list. The only thing i find confusing is your shell prompt. I guess itʼs really useful (in colour, i assume?) but seeing it here in white on black, especially that x in place of good olʼ $ is really confusing (even though i completely understand you got rid of the dollar sign; i did, too).

Collapse
 
eyarz profile image
Eyar Zilberman

I started the list at #9 because developers have only nine fingers ;)

I first created the "terminal-feel" (with color) on my original blog post, and it looked awesome! I was sorry I wasn't able to copy the design to here, but I didn't want to use images instead of code and lose the "copy-paste" functionality...

I agree about changing the x to $, it makes more sense in black & white - so I update the terminals. Thank you for helping me make this post better! :)

Collapse
 
cameronblandford profile image
Cameron • Edited

Thanks for this great post, I learned a lot! It’s worth noting that git stash apply does the same thing as git stash pop except it’s non-destructive and doesn’t delete the stashed changes from your stash history! That way if you mess up while re-adding changes from the stash (which has happened to me before, especially during a stash merge conflict), you can easily re-implement the same stashes changes! Definitely would recommend as a preferred command.

Collapse
 
eyarz profile image
Eyar Zilberman

This is why I love the DEV community - you learn something new every day...

Thanks to you, this is what I learned today:
git stash pop is git stash apply && git stash drop. git stash pop applies the top stash and removes it, while git stash apply does the same but leaves the stash in the stack.

Therefore, it is recommended to use $ git stash apply in this use case - I will update the post :)

Collapse
 
vedgar profile image
Vedran Čačić • Edited

What have I just pulled?

git diff HEAD HEAD^1

Or something like that, I never remember. ,-]

Collapse
 
strahinjalak profile image
Strahinja Laktovic

Love the post and the way it's written, I certainly learned a thing or two, going to bookmark it. :)

Collapse
 
eyarz profile image
Eyar Zilberman

Thank you for the feedback - it's motivating me to write more content!

Collapse
 
yucer profile image
yucer

The number one in my missing git command is git showtool.

I can't live without an external diff tool. We already have "git difftool" but it is very common the need to inspect which changes were added by a commit.

Collapse
 
eyarz profile image
Eyar Zilberman

+1 cool command!
This one will be added to the next article in this series ;)

Collapse
 
yucer profile image
yucer

Good idea. With the title you'd made the post attractive, and that is a motivation for the people to learn.

Nevertheless I guess that the names of those "missing comands" could be proposed according to the git naming conventions.

For example, there is already a subcommand "git branch". The missing one would be "git branch create" instead of "git create branch".

Collapse
 
eyarz profile image
Eyar Zilberman

I agree, but I tried to find the right microcopy balance between "human-friendly" VS "git oriented" commands.

I preferred to give more weight to the "human-friendly" microcopy:
For example, the command $ git undo merge is human-friendly command while the more git orientated command should be (I guess) $git merge --undo.

Collapse
 
art4 profile image
Art4

Great post. I learned some hints. Thank you 😊

One typo in #8: It must be $ git stash pop instead of $ git pop

Collapse
 
eyarz profile image
Eyar Zilberman • Edited

Thank you for the QA :)
I fixed it here and on the original post.

Collapse
 
mfrata profile image
Matheus Frata

Great post Eyar!!

You could have mentioned the git alias feature, in order to use these in a much more intuitive way. For instance, I have set git uncommit just like you mentioned:

  • uncommit = reset HEAD^

There are others that are useful for me:

History tree

  • tree = log --oneline --graph --decorate

Intuitive way to unstage files

  • unstage = reset HEAD --

Show the current aliases

  • alias = config --get-regexp ^alias\\.

Restore deleted file from upstream

  • restore = "!git checkout $(git upstream) -- #@"

... which depends on

  • upstream = rev-parse --abbrev-ref --symbolic-full-name @{u}
Collapse
 
eyarz profile image
Eyar Zilberman

I wanted to add information regarding the alias feature, but I was afraid it would make the post too much long for reading.

I will update the post, and I will add a link to your comment so readers will still have a reference for git alias - thanks!