DEV Community

Muna Mohamed
Muna Mohamed

Posted on

What is your favourite Git command?

I'm curious to know, what is your favourite Git command?

Mine is "git commit --amend", which let's you change your last commit message. I manage to mess up a commit message at least once a day šŸ˜…

For the sake of clarity, please include what the git command does so we can all learn from one another! šŸ˜„

Latest comments (90)

Collapse
 
elgordino profile image
Gordon Johnston
git fetch origin branch:branch

Often when changing branches you might do

git checkout branch
git pull

Which is fine, but if your local 'branch' is way behind origin then this can result in a lot of filesystem thrashing

If you do

git fetch origin branch:branch
git checkout branch

Then you will checkout in to a branch that has already been fast forwarded, avoiding all the thrashing.

Collapse
 
kkm000 profile image
Cy "kkm" K'Nelson • Edited

I'm using surprisingly few every day, I realized, and most of them have been already mentioned. Okay, I have a couple tricks up the sleeve. And I'll name my favorite command later. A bit of suspense, ok?

#1. Make your common command short

git config --edit [--global]

This sounds mundane, but look how far you can get with it:

[alias]
  b  = branch
  bb = branch --all
  bv = branch -vv
  co = checkout
  d  = diff
  dd = diff --staged
  lg = log --graph --format='%C(142)%h %C(36)%ad%C(auto)%d %s' --date=format:%y%m%d
  s  = status --short --branch
  ss = status --no-short
  w  = show
[pull]
  rebase = true
[rerere]
  enabled = true
[rebase]
  autosquash = true
[push]
  followTags = true
[grep]
  lineNumber = true
  patternType = perl
[completion]
  commands = ls-files ls-remote ls-tree rev-parse -citool -gui -gitk -request-pull -send-email -shortlog -whatchanged -credential-gcloud.sh

Besides aliases, I am including a few often missed great defaults to other common commands. YMMV, of course, but I'll go over them, in this and next sections.

  • pull.rebase = true: If you are working through a pull request workflow, you want your commits stay on top of the source branch. You may get conflicts on a pull, but if you do, this means you will get them anyway when sending a PR, so this only saves you same embarrassment. But once you resolved them and then continue on your branch...
  • rerere.enabled = true (for "REcord REbase REsolution" or something like that) is the best thing since bottled beer! Without it, on another pull you'll get the same conflicts. With it, Git remembers how you resolved them, and applies the recorded resolution. Don't see them bastards again!
  • completion.commands = ...: hide/show what you get after a 'git <TAB>'. Those with the '-' are hidden from the default set. Those without are added if normally hidden. And since a package so helpfully decided to put 'git-credential-gcloud.sh' on the PATH, why would I want a non-command 'credential-gcloud.sh' in the completion list? Hide it! If you use "lower-level" commands, like ls-files or ls-remote, expose them to autocompletion! Note: This is new in 2.20, broken in 2.21, and fixed by 2.24.
  • push.followTags = true pushes all annotated tags reachable from the commit you're pushing. Might have been the default, but that would break compatibility with the Git past behavior and piss off a lot of graybeards. I'm only 51 years young, and am already pissed off all too easily. YMMV.

And now (...drum roll...) 'git s' is my favorite command. Succinct and readable output..

2. git grep

No-one's favorite? C'mon! Where are all calls to this function in my project? 'git grep PATTERN' runs grep on your worktree files from the current directory and all down below recursively; see man for more. The [grep] settings above add grep switches '-P' and '-n', respectively. Non-Perl regexps are even more 1980's than disco balls!

3. Three future PRs in one branch? Set rebase.autosquash=true

git commit --fixup <committish>

is what you really want. You work on adding three features at once, and, unfortunately, all of them are dependent. You want to send the first in a PR, then the second, then the third--this is the only way to keep PRs smaller and reviewable. Even found yourself doing this?

$ git lg -3
* d0835482 200423 Add flapdoodle enabled by bamboozler
* 28eb1f47 200421 Replace kaboodler with bamboozler
* e0ce67fc 200421 Fix threading to enable use of bamboozler

Now you're working on adding the flapdoodle, but also fixed another threading bug. No biggie. Stage the fix for the top commit first (git add -p, if needed), and amend the top commit (git commit --amend --no-edit). That's a well-known trick. But now commit all the remaining changes, that threading bug that your brand new flapdoodle uncovered, thanks to the bamboozler:

$ git commit -a --fixup e0ce67

After some testing, you fix more of the flapdoodle and commit a fixup, but then... oh no, what an embarrassing comment typo in the threading fix! So you commit another fixup. _Applying a fixup to the previous fixup reduces chances of a conflict, but doesn't eliminate the possibility.

$ git lg -6
* 6c022160 200426 fixup! fixup! Fix threading to enable use of bamboozler
* 6f34aa90 200426 fixup! Add flapdoodle enabled by bamboozler
* e0ce67fc 200426 fixup! Fix threading to enable use of bamboozler
* 6f34aa90 200426 Add flapdoodle enabled by bamboozler
* 28eb1f47 200421 Replace kaboodler with bamboozler
* e0ce67fc 200421 Fix threading to be able to switch to bamboozler
* . . . .  (origin/master)

And now is a magic time! Note that the --autosquash switch is best set your default setting: it affects only fixups, and is required for the fixup magic to work.

$ git rebase -i --autosquash  HEAD~6  # or origin/master.

And, wonderfully, when an editor opens, fixups are already marked to be applied as fixups, no room for error. Just save the script with no changes, and the rebase leaves you with three clean separate commits, each with the original message. Fork a branch off the bottommost one, send a PR, after it's accepted pull the remote master, rebase your branch on it (if you applied reviewer's comments, you'll get conflicts in that commit, but you just 'git rebase --skip' your initial version of the commit; you might get more conflicts because of these changes in the remaining upper commits, which you'll need to resolve), fork another branch from the bottommost commit... You got the idea. Another option is to 'git cherry-pick' the second bottommost commit to a new off-maser branch to sent it for a review.

4. Not Git proper, but git rev-parse...

...can be wrestled into a very powerful command-line parser for complex tools written in bash, with Git-style subcommands and help messages. Since this is not about Git proper, I'll just leave a link to the parser source and a representative tool sourcing and using it. Search for the occurrences of substrings ArgParse and OPT_, and you'll grok it. The first file is well-commented but still ugly when fixes a couple of Git idiosyncrasies, but the second, with the code which uses it... well, I would not marry it either, bit it's still much simpler and readable with the parser than without it. git rev-parse may provide a lot of leverage if you're facing a task of writing a 5K-line-long bash code tool suite for IaC management of a scientific computation cluster in the cloud...

Collapse
 
bam92 profile image
Abel Lifaefi Mbula

git commit -am'text here'

Collapse
 
mcabreradev profile image
MiguelƔngel Cabrera

git reset --hard

Collapse
 
jdforsythe profile image
Jeremy Forsythe

git bisect

Collapse
 
waylonwalker profile image
Waylon Walker • Edited

$&*! I have been working on MASTER !

git stash
git checkout -b new_branch
git stash apply
Collapse
 
mihaylov profile image
Petar Petrov

Mine is rebase

git rebase -i Because its like a swiss army knife.

Collapse
 
waylonwalker profile image
Waylon Walker

I nearly always get the direction of this backwards and screw up my repo

Collapse
 
geraalcantara profile image
Gerardo Alcantara

Mine is a "git command combo".

git remote add old-project ../old-project
git fetch old-project
git checkout -b feature/merge-old-project
git merge -S --allow-unrelated-histories old-project/master
git push origin feature/merge-old-project
git remote rm old-project

Merging 2 Git Repositories With History

šŸ’ Dance

Collapse
 
hamstu profile image
Hamish Macpherson
git nevermind

It's not a real git command, but it's an alias to wipe out any uncommitted changes, new files, etc. Basically gets you back to a clean state (i.e., the the last commit.) I do it all the time! (Warning: there's no going back once you run it though!)

This is how to set it up in your ~/.gitconfig:

[alias]
nevermind = !git reset --hard HEAD && git clean -d -f

Collapse
 
hayderimran7 profile image
Imran Hayder

haha good one :D

Collapse
 
munamohamed94 profile image
Muna Mohamed

Ooo, that's an interesting one! Very fitting alias too, haha šŸ˜„! Will have to add that one to the toolbox šŸ‘šŸ¾. Thanks, Hamish!

Collapse
 
hamstu profile image
Hamish Macpherson

Glad you like it Muna! I love the name too, it always matches how I'm feeling when I run it. šŸ˜…

Collapse
 
kev_barbe profile image
Kevin Barbe

This is also one of my favorites, my ridiculous alias for this one is gloga, standing for graphical log all (branches).

Collapse
 
guha profile image
Arghya Guha

git init since it marks the start of a new exciting project, probably šŸ˜€

git commit --amend is a personal favorite too.

Collapse
 
waylonwalker profile image
Waylon Walker

ooohh git commit --amend is a good one

Collapse
 
ucavalcante profile image
Ulisses Cavalcante

It's hard to chose but I think it's

git reflog
Collapse
 
waylonwalker profile image
Waylon Walker

I have never touched reflog, what is it?

Collapse
 
kkm000 profile image
Cy "kkm" K'Nelson

A little hands-on tutorial. A ref is any file under .git/refs, and a few well-known others, e.g. .git/HEAD: branch heads, tags, etc. Each of them is a simple one-line file containing either a full SHA, or a name of another ref, called a symbolic ref. And example of a symbolic ref is normally the HEAD: type cat .git/HEAD, and it prints ref: refs/heads/master. It's a ref that is akin to a symlink to another ref. Now do cat .git/refs/heads/master. This is a normal, non-sybolic ref to a SHA.

Every time a ref changes (e.g., when you check out another branch, or detach HEAD by checking out a SHA), the old pointer would be irreversibly lost. For convenience, Git can store the old value in the reflog (reflog can be disabled, but enabled by default in non-bare repos). Git locally keeps a log of previous pointers, with the date of modification. These are kept under .git/logs, and the directory mirrors the structure of that above: HEAD's log is in logs/HEAD, .git/refs/heads/master's log is in .git/logs/refs/heads/master, and so on. Try cat .git/logs/HEAD.

Refs are symbolic names for points in history. Try these command in order (assuming you are on the master branch:
(1) git log -1 --oneline , which is a shorthand for
(2) git log -1 --oneline HEAD, which Git resolves (remember that little HEAD file above?) into
(3) git log -1 --oneline refs/heads/master.
(4) git log -1 --oneline master is also special: Git checks if one of refs/heads/master or refs/tags/master exists (I forgot in which order), and also ends up showing you git log -1 --oneline refs/heads/master. All these log commands yield the same output.

reflog is the command that lets you see the history of these ref changes. Try git reflog (a shorthand for git reflog show HEAD), and git reflog show --all, and you'll grok it at once. `man git-reflog has all the rest you need.

Collapse
 
robertobutti profile image
Roberto B.
git commit -m "adding a feature" .

It means that I almost completed a feature šŸš€šŸš€šŸš€

Collapse
 
theooliveira profile image
Theo Oliveira • Edited

I know the one I hate. Rebase. I am still learning so I am confused about it's use

Collapse
 
waylonwalker profile image
Waylon Walker • Edited

I almost always get interactive rebase backwards. For some reason -i confuses the heck out of me and I avoid it more than I should.

Though I really like to utilize a rebase with master regularly to make sure I dont get behind.

git fetch --all
git rebase master
Collapse
 
munamohamed94 profile image
Muna Mohamed

You and me both, Theo! A senior dev recommended using Git Fork, which makes using git rebase a lot easier because you can visually see what's going on with the branches and commits. Do check it out!

Collapse
 
ankurk91 profile image
Ankur K
git push origin dev -f
Collapse
 
waylonwalker profile image
Waylon Walker

I just learned about

git config --global push.default current

Turns that into

git push -f