Live data from Hacker News

Git tips from the trenches

ochronus.com

21–30 of 47 posts

Re: Git tips from the trenches

#21

I'd like to mention a feature that's been making my life oh so much easier: git bisect If you're ever looking for "the commit that broke feature XYZ", git bisect is your trusty minion.

Git bisect is wonderful. TortoiseHg also has a bisect command in the Workbench. (But command line hg doesn't seem to have it.) Here's a tip for anyone using bisect with a Rails app (or any system that uses database migrations): I do a rake db:migrate after a pull to make sure the database schema is up to date. So the first time I used git bisect on a Rails app, I figured I would use db:migrate after each bisect step.…

[deleted]

Re: Git tips from the trenches

#22
My all-time favorite git tip is adding the '--graph' flag to git log, which will show the log with a branch graph. But while you're at it, might as well go all the way:

git log --graph --abbrev-commit --decorate --date=relative --format=format:'%C(bold blue)%h%C(reset) - %C(bold green)(%ar)%C(reset) %C(white)%s%C(reset) %C(dim white)- %an%C(reset)%C(bold yellow)%d%C(reset)' --all

(Kudos to the unremembered internet person who posted this in the first place)

Re: Git tips from the trenches

#24
post #5

Worth it just for this: git rev-list --all | xargs git grep ' '

`git grep` is such a weird command: it defaults to being pointlessly redundant with `grep` (with a few default ignores). Contrast with hg grep, which defaults to searching the whole history (although it stops after finding the historical first match, `—all` will display all matches).

"git grep" is a lot faster than grep in a large codebase. One obvious reason is that "git grep" ignores non-checked-in files in the project directory. But I also notice a speed difference even when the project directory is clean.

Re: Git tips from the trenches

#26
One that I use the whole time is:

git status --untracked=no

This shows only files that are tracked. I tend to do a lot of work which leaves files that I don't want to check in lying around in my git repo, this eliminates these and lets me see exactly what I have been working on. The slight caveat to this is when you are working on a new file that you have not yet checked in ever.

This goes hand in hand with:

git add -u

Which only adds untracked files. With aliased commands this usually results in a flow like this:

> git stu

> git adu

Re: Git tips from the trenches

#27

Earlier quoted context omitted.

`git grep` is such a weird command: it defaults to being pointlessly redundant with `grep` (with a few default ignores). Contrast with hg grep, which defaults to searching the whole history (although it stops after finding the historical first match, `—all` will display all matches).

"git grep" is a lot faster than grep in a large codebase. One obvious reason is that "git grep" ignores non-checked-in files in the project directory. But I also notice a speed difference even when the project directory is clean.

By default grep is going through all of the .git directly, which is the part `git grep` filters out. `ag` also filters them out (and is only slightly slower than git grep by default, with all the colors and stuff), or you can tell grep to only check relevant files with e.g. `grep $PATTERN $(git ls-tree --full-tree --name-only -r HEAD)`.

On my machine, using postgres's repository, I get the following:

    > time git grep foo > /dev/null                                                           
    0.22s user 0.25s system 151% cpu 0.312 total
    > time ag foo > /dev/null                                                                     
    0.85s user 0.19s system 174% cpu 0.596 total
    > time grep foo $(git ls-tree --full-tree --name-only -r HEAD) > /dev/null                    
    0.13s user 0.10s system 93% cpu 0.255 total
grep's faster than git grep. In fact, grep is already as fast as git grep just ignoring .git:

    > time grep foo -r . --exclude-dir=.git > /dev/null
    0.15s user 0.16s system 91% cpu 0.338 total

Re: Git tips from the trenches

#28

I'd like to mention a feature that's been making my life oh so much easier: git bisect If you're ever looking for "the commit that broke feature XYZ", git bisect is your trusty minion.

Git bisect is wonderful. TortoiseHg also has a bisect command in the Workbench. (But command line hg doesn't seem to have it.) Here's a tip for anyone using bisect with a Rails app (or any system that uses database migrations): I do a rake db:migrate after a pull to make sure the database schema is up to date. So the first time I used git bisect on a Rails app, I figured I would use db:migrate after each bisect step.…

If you need to more fiddling to get things working in each bisected commit, you can launch the process manually with 'git bisect start', then pass in refs to 'git bisect bad' and 'git bisect good' to indicate a known-bad and a known-good commit.

At that point, git will check out the "middle" revision and you can do whatever's needed to decide if you should mark it as either good or bad with 'git bisect [good|bad]'. This will check out the new "middle" - lather, rinse, repeat until you get down to one commit.

When you're done, 'git bisect reset' will take you back to the present.

While this isn't quite as quick as the automated version, it's a lifesaver when tracking down a regression in a library whose dependencies have changed radically (finding what b0rked your tests between Rails 3.0 and 4.0, for instance).

Re: Git tips from the trenches

#29

Earlier quoted context omitted.

"git grep" is a lot faster than grep in a large codebase. One obvious reason is that "git grep" ignores non-checked-in files in the project directory. But I also notice a speed difference even when the project directory is clean.

By default grep is going through all of the .git directly, which is the part `git grep` filters out. `ag` also filters them out (and is only slightly slower than git grep by default, with all the colors and stuff), or you can tell grep to only check relevant files with e.g. `grep $PATTERN $(git ls-tree --full-tree --name-only -r HEAD)`. On my machine, using postgres's repository, I get the following: > time git grep…

You need to take the effect of the page cache into account. Since you are not clearing the page cache after each test, the test after it benefits from the contents. So running 'git grep' first disadvantages it, compared to everything else.

I ran a test on a large repository and here are my results. The repository was Hadoop, and is available from git://github.com/apache/hadoop-common.git.

  cmccabe@keter:~/hadoop4> du -cksh .
  375M    .
  375M    total
  sudo -- sh -c 'sync ; echo 3 > /proc/sys/vm/drop_caches'
  cmccabe@keter:~/hadoop4> /usr/bin/time git grep 'class TestDefaultNameNodePort'                                                                              
  hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/TestDefaultNameNodePort.java:public class TestDefaultNameNodePort {
  0.11user 0.34system 0:00.74elapsed 61%CPU (0avgtext+0avgdata 60512maxresident)k
  260256inputs+0outputs (19major+9718minor)pagefaults 0swaps

  sudo -- sh -c 'sync ; echo 3 > /proc/sys/vm/drop_caches'
  cmccabe@keter:~/hadoop4> /usr/bin/time grep -rI --exclude .git 'class TestDefaultNameNodePort' *
  hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/TestDefaultNameNodePort.java:public class TestDefaultNameNodePort {
  0.13user 0.56system 0:02.40elapsed 29%CPU (0avgtext+0avgdata 5584maxresident)k
  252792inputs+0outputs (2major+414minor)pagefaults 0swaps
So you can see that it is faster, even when excluding the .git directory.

Running grep a second time without clearing the cache gives a bogus result:

  cmccabe@keter:~/hadoop4> /usr/bin/time grep -rI --exclude .git 'class TestDefaultNameNodePort' *
  hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/TestDefaultNameNodePort.java:public class TestDefaultNameNodePort {
  0.03user 0.04system 0:00.08elapsed 97%CPU (0avgtext+0avgdata 5584maxresident)k
  0inputs+0outputs (0major+416minor)pagefaults 0swaps
This is because the data is all in the page cache at that point, so we're not actually accessing the disk.

I was curious about the true source of the speedup, and so I checked the output of the 'perf' tool. git had 1,922 CPU migrations, whereas grep had 52. Following up on this, you can see that git is spawning a bunch of threads, whereas grep only has one thread.

  cmccabe@keter:~/hadoop4> strace -f -e trace=clone git grep 'class TestDefaultNameNodePort' 2>&1 | grep -c '] +++ exited with '                                 
  8
 cmccabe@keter:~/hadoop4> strace -f -e trace=clone grep -rI --exclude=.git 'class TestDefaultNameNodePort' *  2>&1 | grep -c '] +++ exited with '                                               
  0
I also think git might be cheating and using a simpler regex engine than grep, but at this point I got bored. Case closed.

Re: Git tips from the trenches

#30

My personal favorites: > git-rerere will prevent you from getting stuck resolving the same merge conflicts repeatedly, by remembering how you resolved them the last time. Also, instead of passing any arguments to "git-log", I usually just use "tig", an ncurses display of the commits: https://blogs.atlassian.com/2013/05/git-tig/ Finally, when I was first taught Git, I was told that I should never need to comment out c…

> Also, instead of passing any arguments to "git-log", I usually just use "tig", an ncurses display of the commits: https://blogs.atlassian.com/2013/05/git-tig/

Agree, tig is awesome and in my opinion the best git GUI (or at least representation). Use the normal commandline tools for commiting/cutting/rebasing/... and tig to see where everything is at!

Post reply on HN