csswizardry.github.com icon indicating copy to clipboard operation
csswizardry.github.com copied to clipboard

Got any neat Git tips?

Open csswizardry opened this issue 8 years ago • 48 comments

As per my Git article, does anyone have any useful snippets they’d like to share?

csswizardry avatar May 23 '17 15:05 csswizardry

Undo changes to one (or more) file(s) in a commit instead of reverting the entire commit:

git show commit-hash -- path/to/file.html | git apply --reverse

matijs avatar May 23 '17 15:05 matijs

Great article, @csswizardry!


Working copy cleanup

Deleting local branches that have been merged and deleted:

git branch --merged | grep -v \"^\\s*master$\" | grep -v \"\\*\" | xargs -n 1 git branch -d

I aliased it as delete-merged and since I use it daily, also as dm.

I always use this in conjunction with the following (aliased as pru) which deletes all stale remote-tracking branches (assuming your upstream is called origin, which is almost always in my personal case):

git remote prune origin

astorije avatar May 23 '17 15:05 astorije

Context switching

I have several projects for work and several open source projects I work on during my personal time. To deal with this and make sure I use the correct email address + correct signing key, I use the following:

  1. Set up user.name only (no email) and force git to refuse a commit without an email address set up
  2. Enable GPG signing
  3. Set up "profiles"
  4. After cloning a repo, switch to correct profile (here with git perso or git cht)

It probably seems convoluted but it has worked well for me in the past. I'm sure they could be (or there is?) a plugin doing that out there, just never looked for it, and this is actually simple enough.

astorije avatar May 23 '17 15:05 astorije

Branch naming convention

I like to have my branches named as astorije/my-branch so it's easy to spot in GitHub's branch list and in the command line. It's a nice convention often met in open source projects, and I even managed to convince my entire team to adopt it 🎉.

But I really don't want to type 8 extra characters when creating a branch, so I set up this alias:

cb = "!f() { git checkout -b astorije/$@; }; f"

Now I just need to type git cb my-branch to create astorije/my-branch 😅.

astorije avatar May 23 '17 15:05 astorije

two of my favorite git aliases are:

List all Submodules alias gsub="grep path .gitmodules | sed 's/.*= //'"

List Tags in a usefull way alias gt="git tag -l --sort=v:refname | tail -n8"

MarioSo avatar May 23 '17 16:05 MarioSo

Best git tip I saw shared on twitter was the :/ filter for latest match. i.e. git log :/"fix: font" will show latest commit matching the text fix: font.

remy avatar May 23 '17 19:05 remy

What am I about to commit?

git config --global alias.staged 'diff --staged'

Then run git staged before committing to double-check what's in the index.


Do not stash what is staged

git stash --keep-index will stash everything that has not been git added yet (when interactively adding stuff to the stage).


Select what must be staged

I have aliased ap to git add -p and have never used git add . since then. Always pick what you are adding to the stage, and never commit something unwanted by inattention.

astorije avatar May 23 '17 20:05 astorije

-p is my favourite flag.

git checkout -p HEAD~ will let you pick and choose which hunks you want to unstage from the present commit in case you didn't mean that -a on your last git commit

git log -p -- path/to/file gives the diffs made to the file inline with the log messages. Good for fuzzy text searches.

git add -p allows you to choose what changes you want to add. Make two commits' worth of changes in one file? This lets you interactively chose which of those should be added at the moment. Check the s (split) and e (edit) flags for if one "chunk" has elements of both.

(( BONUS ROUND: If you haven't used git rebase -i to reorganize and squash local changes, you're missing out ))

chutten avatar May 23 '17 20:05 chutten

-p is my favourite flag.

Yep, me too, and it even works with git stash :D

astorije avatar May 24 '17 06:05 astorije

I have 2 aliases that I use all the time:

  • my custom one liner log: l1 = log --format='%Cgreen %h %C(white) %G? %Cred%ai %C(bold)%<(15)%ar %Creset %C(cyan)%<(30)%ae %C(yellow) %s'
  • alias to commit work in progress (useful for end of the day, but feature still not complete). cwip = commit -S -m ':construction: WIP'. Note that it will still open the git commit message editor to fill in the details

pedrorijo91 avatar May 24 '17 07:05 pedrorijo91

I use this to fetch pull request by id to local branch. git fetch origin pull/<id>/head:<branch-name>

There are lots of git tips on this repo https://github.com/git-tips/tips There is npm package to show git tip each time you open a new terminal. https://github.com/nirajpandkar/git-tip

msankhala avatar May 24 '17 11:05 msankhala

I recently put together a way to find (with fuzzy search) and list branches interactively. Check it out.

list branches

rafaelrinaldi avatar May 24 '17 13:05 rafaelrinaldi

In one repository I need to check in JS/CSS compilation results next to the source files. To get an idea of the changes in those compiled files I use this alias:

wdiff = diff -w --word-diff-regex=. --color-words -U0

It configures git-diff to produce the absolutely most minimal diff possible.

Boldewyn avatar May 24 '17 14:05 Boldewyn

git rebase -i --autosquash --autostash

Really handy in projects that don't do merge commits (read, everything I work with).

git reflog

Lost a commit in a rebase? Did a pull and want to go back to a previous state? git reflog gives you the hash corresponding to the last several values of HEAD so you can examine and checkout the point that you're interested in.

ford-prefect avatar May 24 '17 14:05 ford-prefect

I replaced the placeholders in your blog post with actual commands that attempt to Do The Right Thing when no argument is provided:

[alias]
	recap = !git log --all --oneline --no-merges --author=${1-$(git config user.email)}
	today = !git log --all --since=00:00:00 --oneline --no-merges --author=${1-$(git config user.email)}
	changelog = !git log --oneline --no-merges ${1-$(git describe --abbrev=0)}..HEAD
	upstream = !git log --oneline --no-merges HEAD..${1-$(git branch -lvv | perl -ne '/^\\*.*\\[(.*?)\\]/ and print "$1\n"')}
	local = !git log --oneline --no-merges ${1-$(git branch -lvv | perl -ne '/^\\*.*\\[(.*?)\\]/ and print "$1\n"')}..HEAD

lloeki avatar May 24 '17 14:05 lloeki

I really liked your diff tips, but instantly was curious whether you could do the same word diff'ing in git-add's --patch mode. You can! (at least since 2.9).

If you want to see color-words in patch mode, just run:

git -c interactive.diffFilter="git diff --color-words" add -p

I set this up as an alias to my commonly used alias in my bash profile:

alias gap='git -c interactive.diffFilter="git diff --color-words" add -p'  

bryankennedy avatar May 24 '17 15:05 bryankennedy

My favorite is: alias.catchup !git fetch; git rebase origin/master.

For catching up those random feature branches you haven't had to touch in months.

tbirrell avatar May 24 '17 15:05 tbirrell

My $0.02 tip:

Get and use http://gitup.co/ - excellent graphical tool to do rebases, merges and visualising what you and others been up to.

(Hint: tap Cmd+D to see commits descriptions along with the graphical view)

berkus avatar May 24 '17 15:05 berkus

For things like git recap or git today, you don't have to manually configure your email if you set up the alias to include git config --get user.email, like so:

git log --all --oneline --no-merges --author=`git config --get user.email`

davethegr8 avatar May 24 '17 17:05 davethegr8

@tbirrell this is git pull --rebase, which you can make the default with git config [--global] pull.rebase true (and more).

lloeki avatar May 24 '17 17:05 lloeki

The --topo-order flag for git log is critical for helping people not hate merge heavy logs.

raggi avatar May 24 '17 18:05 raggi

You can replace "Check Which Changes You’re About to Pull" and "Review What You’re About to Push" with a single command:

git log ...@{u} --left-right --graph

It's short for git log HEAD...@{upstream} --left-right --graph.

Note: It only works when you have a tracking branch set for the current branch.

This will show you the commits that the current branch has that the configured tracking branch does not have, and the reverse:

< 123456 local commit not on remote
< 654321 another local commit not on remote
> abcdef a commit on the remote not found locally
> 8sadf6 another commit on the remote not found locally

You can flip the ... around if you like seeing the angle brackets face the other way:

git log @{u}... --left-right --graph

I explain it in more detail in this blog post, along with similar little things I like to do in git.

krishicks avatar May 24 '17 20:05 krishicks

I have my personal "cheat-sheet" of non-trivial, but often enough needed, git magical incantations listed here. Initially purely about git, later I started including other Linux stuff too (like how to exit from a hanged ssh session, etc.).

akavel avatar May 24 '17 20:05 akavel

I use my quicklog alias dozens of times a day, which shows branches, tags, commit lines, and relative dates in wonderfully fervent colors:

image

% git help quicklog
`git quicklog' is aliased to `log --oneline --decorate -10 --pretty=format:'%C(yellow)%h%C(reset)%C(auto)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset''

% git help quicklog-long
`git quicklog-long' is aliased to `log --oneline --decorate --pretty=format:'%C(yellow)%h%C(reset)%C(auto)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset''

% which gl
gl: aliased to git quicklog -n 20

% which gll
gll: aliased to git quicklog-long

% which st
st: aliased to git status

gl is great for answering, "What's been happening in this branch." gll is great for, "What's been happening since the beginning of all time." And since they're just git log commands, combining gll with arguments is always useful, like gll release-1.0..release-1.5 --author=statico.

statico avatar May 24 '17 22:05 statico

I use this alias to quickly amend my last commit:

instamend = commit --all --amend --no-edit

harto avatar May 25 '17 03:05 harto

Unstage added files: unstage = reset HEAD --

Delete last commit: squash = reset --hard HEAD~1

Discard current changes: nah = reset --hard && git clean -df

Shameful and time-saving aliases:

puhs = push  
psuh = push  
pshu = push  
spuh = push  
sphu = push  

gabssnake avatar May 25 '17 13:05 gabssnake

Have shell alias gup (git update) = git checkout master && git pull && git checkout - && git rebase master, to check conflicts before merging.

aelaa avatar May 25 '17 13:05 aelaa

I am surprised no one mentioned magit. It takes out the need to have these many heavily customized aliases.

Here's a recording of how I made this commit using magit:

I do this in the recording to stage, commit and push:

  • s (stage)
  • c c (commit)
  • (Type the commit message)
  • P p (push) .. Somehow the network latency takes push for few more seconds than usual to finish.

Sorry about the mouse pointer distraction.. I not use the pointer to show anything.. please ignore that if you can.

magit

kaushalmodi avatar May 25 '17 17:05 kaushalmodi

https://gist.github.com/chrismccoy/8775224

i have some handy 1 liners here

chrismccoy avatar May 28 '17 06:05 chrismccoy

Learnt quite a few things in this thread, thank y’all! Oh, and thanks for the article @csswizardry! I added a few tips to my list of aliases.

Leaving it here if someone want to pick stuff. :)

[alias]
  # The basic aliases
  s = status
  cm = commit -m
  cp = cherry-pick

  # Branch related aliases
  br = branch
  co = checkout
  com = checkout master
  cod = checkout develop

  # Syncing related aliases
  pur = pull --rebase
  prune = fetch --prune

  # Rebase related aliases
  ri = rebase -i
  rb = "!sh -c \"git rebase -i HEAD~$1\" -"
  rc = rebase --continue
  ra = rebase --abort
  rs = rebase --skip
  rod = rebase origin/develop
  rom = rebase origin/master

  # Stash related aliases
  poop = stash pop

  # Push related aliases
  pom = push origin master
  pod = push origin develop
  force = push --force-with-lease

  # Mistake related aliases
  abort = checkout -- .
  wait = reset HEAD
  undo = reset --soft HEAD^
  amend = commit --amend --no-edit

  # Diff related aliases
  changes = diff --name-status
  dic = diff --cached
  diffstat = diff --stat
  lg = log --pretty=oneline --abbrev-commit --graph --decorate
  count = "!f() { git rev-list --count HEAD ^${1-develop}; }; f"

  # Log related aliases
  lg = log --pretty=oneline --abbrev-commit --graph --decorate
  overview = log --all --oneline --no-merges
  changelog = "!sh -c \"git log --oneline --no-merges $1..HEAD\" -"

KittyGiraudel avatar May 28 '17 14:05 KittyGiraudel

I have a million shortcut aliases, but some of my favourites are:

[alias]
  track = "!f() { git branch --set-upstream-to=origin/$1 $1; }; f"
  # git track branch-name (to track with origin)

  del = branch -D
  # git del branch-name (to delete locally)

  undo = reset --soft HEAD~1
  # git undo (to undo the last commit and leave the files there)

  stan = "!f() { git stash apply stash@{$1}; }; f"
  # git stan 3 (to apply the 3rd item in the stash)

and of course:

[help]
  autocorrect = 1
  # to fix typos 

stowball avatar Jun 02 '17 05:06 stowball

Congratulations if you scrolled down this far :sparkles:

Working with open source in a Linux distribution context, I often want to know if a certain commit made it into a release. I only recently learned how to do that: use the --contains option to git branch or git tag:

~/p/mediawiki-core.git (master) $ git tag --contains d4385537bcd8284936cbcafcc84718dcc9b52181
1.29.0-rc.0
~/p/mediawiki-core.git (master) $ git branch --contains d4385537bcd8284936cbcafcc84718dcc9b52181
* master

...ok, it seems I have to wait :-(

rohieb avatar Jun 05 '17 21:06 rohieb

I just like to have an up to date git --log in a CLI window...
Created a bash alias with this command:

while true; do clear; git log --oneline --graph --all --decorate -n20; sleep .5; done

basically, it shows the 20 last lines of git log (decorated) and refreshes this every .5 seconds

dgoosens avatar Jun 06 '17 12:06 dgoosens

@dgoosens Does it really need to refresh every half a second? :wink:

albocc avatar Jun 06 '17 12:06 albocc

@albocc depends how fast you commit... lol

dgoosens avatar Jun 06 '17 13:06 dgoosens

All my tweaks: https://github.com/pjg/dotfiles/blob/master/.gitconfig

pjg avatar Jun 08 '17 12:06 pjg

One of the best Tips I have is the autocomplete option https://git-scm.com/book/en/v1/Git-Basics-Tips-and-Tricks#Auto-Completion. You can autocomplete branch names and git commands.

Also some alias as: co = checkout checkout undo = reset --soft HEAD^ undo last commit squash = rebase -i HEAD~ squash

Also I have activated the simple push so every time I make a push only my actual branch is push. [push] default = simple

najor avatar Jun 13 '17 07:06 najor

Previous branch is @{-1}. You can use it in some nice aliases. Checkout branch I was on previously:

gprev='git checkout @{-1}'

and merge previous:

gmergeprev='git merge @{-1}'

thelitek avatar Aug 31 '17 21:08 thelitek

@thelitek you can do git checkout - to toggle between your most recent branches :)

c24w avatar Aug 31 '17 21:08 c24w

git add --patch is probably my favourite, it's tidied my commits up no end. With the array of options for applying to each hunk as it comes up you can really pull apart some work you did into meaningful, atomic commits.

toni-sharpe avatar Jan 04 '18 13:01 toni-sharpe

To see updates:

alias gitup='git fetch origin ; git branch -v -a'

Some simple non-git ones, but in the long run (and while adding those aliases you like from above) these two might be helpful:

alias vibr='vi ~/.bash_profile'
alias br='source ~/.bash_profile ; echo --- reloaded'

tennisfar avatar Feb 13 '18 15:02 tennisfar

I use this git/bash command to list the files that have been modified between two commits:

git log --name-only --pretty=oneline --full-index %%COMMIT-N%%..%%COMMIT%% | grep -vE '^[0-9a-f]{40} ' | sort | uniq

This comes in pretty handy, for instance, when you need to update a remote server via FTP.

Lately wrote a little script to make its usage even easier... You can check it out here:
https://gitlab.com/snippets/1689817

dgoosens avatar Feb 13 '18 21:02 dgoosens

I don't have my own command to share, but I would like to put in a request for anchor links at each h2 on your article so I can link back to / bookmark specific commands

lshapz avatar Mar 20 '18 14:03 lshapz

My dotfiles: https://github.com/cmbuckley/dotfiles/blob/master/files/gitconfig

Favourites:

  • du = diff @{u} HEAD — diff with upstream branch
  • sd = !sh -c 'git stash drop stash@{${1-0}}' - — drop stash (default latest, git sd 1 to drop explicit stash)
  • sp = !sh -c 'git stash pop stash@{${1-0}}' - — pop stash (same as above)
  • ss = !sh -c 'git stash show stash@{${1-0}} -p --no-prefix' - — show stash patch (same as above)

All of my complex user-interface stuff (graphs, interactive blame etc) is done with tig.

cmbuckley avatar Mar 20 '18 17:03 cmbuckley

This gives a nice treemap view of the commits on a repo:

git log --graph --decorate --pretty=oneline --abbrev-commit --all

jakeparis avatar Sep 14 '21 13:09 jakeparis