csswizardry / csswizardry.github.com

My site.
https://csswizardry.com
463 stars 90 forks source link

Got any neat Git tips? #66

Open csswizardry opened 7 years ago

csswizardry commented 7 years ago

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

matijs commented 7 years ago

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
astorije commented 7 years ago

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 commented 7 years ago

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 commented 7 years ago

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 😅.

MarioSo commented 7 years ago

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"

remy commented 7 years ago

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.

astorije commented 7 years ago

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.

chutten commented 7 years ago

-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 ))

astorije commented 7 years ago

-p is my favourite flag.

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

pedrorijo91 commented 7 years ago

I have 2 aliases that I use all the time:

msankhala commented 7 years ago

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

rafaelrinaldi commented 7 years ago

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

list branches

Boldewyn commented 7 years ago

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.

ford-prefect commented 7 years ago

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.

lloeki commented 7 years ago

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
bryankennedy commented 7 years ago

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'  
tbirrell commented 7 years ago

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.

berkus commented 7 years ago

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)

davethegr8 commented 7 years ago

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`
lloeki commented 7 years ago

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

raggi commented 7 years ago

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

krishicks commented 7 years ago

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.

akavel commented 7 years ago

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.).

statico commented 7 years ago

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.

harto commented 7 years ago

I use this alias to quickly amend my last commit:

instamend = commit --all --amend --no-edit
gabssnake commented 7 years ago

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  
aelaa commented 7 years ago

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

kaushalmodi commented 7 years ago

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:

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

magit

chrismccoy commented 7 years ago

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

i have some handy 1 liners here

KittyGiraudel commented 7 years ago

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\" -"
stowball commented 7 years ago

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 
rohieb commented 7 years ago

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 :-(

dgoosens commented 7 years ago

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

albocc commented 7 years ago

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

dgoosens commented 7 years ago

@albocc depends how fast you commit... lol

pjg commented 7 years ago

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

najor commented 7 years ago

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

thelitek commented 6 years ago

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}'
c24w commented 6 years ago

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

toni-sharpe commented 6 years ago

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.

tennisfar commented 6 years ago

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'
dgoosens commented 6 years ago

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

lshapz commented 6 years ago

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

cmbuckley commented 6 years ago

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

Favourites:

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

jakeparis commented 2 years ago

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

git log --graph --decorate --pretty=oneline --abbrev-commit --all
GammaGames commented 5 months ago

Just came across your post, thought I'd share!
I always disliked git's default status command so I wrote a little script that prints out the changed files along with number of lines changed image

Not sure how you'd alias it, but the main part of the function is:

if [[ $(git diff --stat --cached) ]]; then
    git diff --stat=$COLUMNS --cached --color | sed \$d
fi
if [[ $(git diff --stat) ]]; then
    git diff --stat=$COLUMNS --color | sed \$d
fi
if [[ $(git ls-files --others --exclude-standard) ]]; then
    git ls-files --others --exclude-standard | sed  's/^/ /'
fi

It already had some of the tweaks you suggested, like showing word differences and ignoring whitespace in diffs. I might have to add a few of your ideas too, I could see changelog and recap being useful when people start asking for reports

toni-sharpe commented 5 months ago

reflog

for those who know, I need say no more. You can merrily skip with your knowlegde onwards. Or correct me. Probably the latter.

For those who don't, it's basically a track of everything that happened, along with its commit. Try it, git reflog it's not even a trick, tbh, it's a command but it's "tricked" me out of out so many problems I'm mentioning it!

What you'll see is below, a long list of every twist and turn your work took, in a more precise way than commit history. It has helped me in many ways, so next time you're tabgled up in git, even if you thought you just lost work for good, then try this.

cd6eda5 HEAD@{26}: checkout: moving from main to 398
d25172b HEAD@{27}: commit: is shadow causing perf issues again
9f444be HEAD@{28}: checkout: moving from 398 to main
cd6eda5 HEAD@{29}: reset: moving to HEAD
cd6eda5 HEAD@{30}: commit: feat 398 key focus and persistence on menu
33123c4 HEAD@{31}: commit: garden keep this in data for now
b020c6d HEAD@{32}: rebase (finish): returning to refs/heads/398
b020c6d HEAD@{33}: rebase (pick): garden avoid all capitals
9f444be HEAD@{34}: rebase (start): checkout HEAD~2
c536ba7 HEAD@{35}: reset: moving to HEAD
toni-sharpe commented 5 months ago

Also git + bash is more like git^bash