

Play Git Like A Violin - mmphosis
http://www.metacircus.com/hacking/2011/02/18/play-git-like-a-violin.html

======
patio11
Swiping that first one - I have _hundreds_ of commits which were just one or
two character tweaks after I had hit the commit button. Often, they squash
bugs. (Hah, test run completed and now I realize the error of my ways...)

More articles like this, please?

~~~
hayeah
Glad you like it. Another weird thing I do is that "g" is not just an alias,
it's a function in my ~/.bashrc

So "g" (without any argument) is "g status", with arguments, g is effectively
an alias for git. A micro-optimization, true.

Another git feature I use quite a bit is the history rewrite. "git fuss 5"
allows me to fiddle with the last 5 commits. I should write another article to
explain git fuss. History rewrite sounds like a dirty thing. But my git
workflow involves doing a whole bunch of temporary commits, so I can track
small incremental steps with git. History rewrite is pretty legit for this
usage pattern.

    
    
      g() {
          if [[ $# == '0' ]]; then
              git status
          else
              case $1 in
                  fuss)
                      shift
                      git rebase -i HEAD~"$1";;
                  *)
                      git "$@";;
              esac
          fi
      }

~~~
dustingetz
> History rewrite sounds like a dirty thing

well you're only rewriting local history, so you're a-ok. history re-writing
becomes a dirty word when you re-write history that someone else may have
already seen. i know you already know this.

~~~
cpeterso
> history re-writing becomes a dirty word when you re-write history that
> someone else may have already seen.

It seems like git (or some friendlier wrapper) could track this for you. For
example, if you've pushed changes to a remote repo, then git could mark those
changes as "published" in your local repo and warn you when you later try to
rewrite that branch's history.

------
jarin
I do the same thing, and then I look like a dummy when I go to someone else's
computer and keep typing "git st", "git co", "gphm" (git push heroku master),
etc.

~~~
zoul
It's a pity that git doesn't also accept unique prefixes for each command like
Subversion does. Is that by design?

~~~
JonnieCache
The help.autocorrect git-config variable allows it:

 _Automatically correct and execute mistyped commands after waiting for the
given number of deciseconds (0.1 sec). If more than one command can be deduced
from the entered text, nothing will be executed. If the value of this option
is negative, the corrected command will be executed immediately. If the value
is 0 - the command will be just shown but not executed. This is the default._

I think the alias system is better though.

------
mcobrien
I use bash aliases for the same thing:

alias gs='git status'

alias gc='git commit -m'

alias gca='git commit -a -m'

alias gd='git diff'

I spend most of my time with gs and gd, then usually gca my changes all at
once, or add those I want and use gc.

~~~
falcolas
I do the same.

    
    
      alias co='git checkout'
      alias gb='git branch'
      alias gd='git diff'
      alias gr='git reset --hard'
      alias gs='git status'
      alias gc='git commit'
      alias ga='git add'
    

But I'm moving away from using git status as much, since adding the following
to my $PS1:

    
    
      get_branch () {
      GS=$(git status 2>&1)
      if [ $? -eq 0 ]
      then
        STAR='*'
        echo $GS | grep 'nothing to commit' > /dev/null 2>&1 && STAR=''
        echo -ne "$(echo $GS | grep 'On branch' | cut -d' ' -f4)${STAR}"
      else
        echo -ne '_'
      fi
      }
    

It's a bit slow some days (up to a second to pop up a prompt when the box is
busy), but the constant visual reference to my branch name & uncommitted
changes is nice.

~~~
mattyb
You may find this useful:

[http://git.kernel.org/?p=git/git.git;a=blob_plain;f=contrib/...](http://git.kernel.org/?p=git/git.git;a=blob_plain;f=contrib/completion/git-
completion.bash;hb=HEAD)

It can tell you if your working directory is dirty, if you've got staged
changes, what branch/tag you're on, and of course does completion also.

------
silentbicycle
I'm surprised more people don't do this stuff. AFAIK, the only single-letter
Unix command or widely installed program is 'w', the rest are up for grabs.

------
yogsototh
I trully believe that no one should use "git reset --hard" unless really know
what he is doing (understand for beginer).

This is why, I aliased an "uncommit". You can see the details in this
article[1] I had written for my friend who were learning git.

usage:

    
    
        git uncommit 3
    

effect: add another point in the history where it is said you get back 3
commit in time. Which is better in most case than modifying the history when
you want to push it.

[1]: [http://yannesposito.com/Scratch/en/blog/2009-11-12-Git-
for-n...](http://yannesposito.com/Scratch/en/blog/2009-11-12-Git-
for-n00b/conf-et-install/)

------
gtani
<http://www.opsb.co.uk/?p=56>

<http://paulbarry.com/articles/2009/01/20/my-git-workflow>

<http://www.viget.com/inspire/terminal-aliases-for-git/>

<http://git.or.cz/gitwiki/Aliases>

------
ch0wn
This one is pretty neat: "git commit -a --amend -C HEAD" Happens to me all the
time I forgot to stage a certain file or made a small typo.

~~~
adimitrov
You don't really need '-C HEAD' at all. The default behavior is to just reuse
the last commit message, which is, implicitly, HEAD.

~~~
cmurphycode
That doesn't work for me. git commit -a --amend prompts for commit message in
$editor git commit -a --amend -C complains about lack of input

Maybe this is a git version specific thing.

------
kirubakaran
If you are an Emacs user, use magit. Changed my life.

------
sfvisser
These aliases are truly useful, but watch out for mistakes.

I can still vividly remember the moment I mistakenly typed in "g co src/"
instead of "g ci src/". I immediately changed my checkout alias to "cho".

~~~
Peaker
That's one of the things I hate about git (I like git a lot, in general). It
makes it too easy to make irreversible damage.

"git clean", "git reset --hard", "git checkout" all provide ways to
irreversibly trash the working tree.

"git clean" has no other function except doing irreversible deletions, so
that's OK, IMO.

"git reset --hard" is a pretty useful way to make a branch jump around between
places, so having a _secondary_ feature of trashing the working tree is
unacceptable, IMO.

"git checkout" is a useful way to take a file from a specific commit. The fact
it may also trash uncommitted changes is also a _secondary_ feature. I think
without "--force", "checkout" should refuse to irreversibly lose content.

~~~
198d
If you take a look at the man pages for all of those commands you'll see they
explicitly mention that your working tree will be affected. They are written
explicitly to do that. 'git reset' can be called with '--mixed' or '--keep'
which might be more along the lines of what you're looking for. If you're ever
unsure about the result of a given command make a copy of your current working
tree before applying it. I like git because it explicitly doesn't hold your
hand through things like this. It expects you to know what you're about to do.

~~~
Peaker
> If you take a look at the man pages for all of those commands you'll see
> they explicitly mention that your working tree will be affected.

I'm not complaining that these commands mismatch the spec. I'm complaining
that the spec for these commands is badly designed.

> They are written explicitly to do that

I agree about git clean, but git reset --hard and git checkout do more than
just changing the working tree.

> If you're ever unsure about the result of a given command make a copy of
> your current working tree before applying it. I like git because it
> explicitly doesn't hold your hand through things like this. It expects you
> to know what you're about to do.

You misunderstood my problem. I know exactly what these commands do.

I consider "reverting my changes in the working tree" to be a _separate_ and
_irreversible_ thing of whatever "git reset" and "git checkout" do, and want
git to ask for approval before accidentally doing irreversible damage.

The main thing protecting me from accidental errors/deletions/etc is my
revision control system. But in this case, the irreversible damage is done
_BY_ the revision control system.

Here are a few examples of what I mean:

* I jump to the wrong shell. In it, I have an old "git status" that says my working tree is clean, but at the wrong location. I forget that I already moved it, and started working on a feature. I use "git reset --hard <correct-place>" and without warning, I __also __get my working tree changes irreversibly lost without any question.

* I press <up> a few times in my shell, to reach a previous command, hit <return>. OOPS, that command was not the one I intended. Instead it was a "git reset --hard <someplace>" or perhaps a "git checkout"!

* I may execute a command like "git checkout <refspec> <some_path>" during a merge in order to pick some version of that file. If I accidentally press <return> too early, I may lose all of my working tree changes in the directory.

I don't actually lose my working tree changes with git, because I'm aware of
these issues, so I am _very_ careful about which commands I replay.

But it would be nice to know that since I have a revision control backup of my
files, I don't need to be as careful, as long as I don't use "clean", "rm" and
other commands meant to lose information.

P.S: It would be nice if "checkout" stored a stash or such of any overwritten
content so it isn't irreversible unless given a flag not to.

tl;dr: Good UI design dictates that user operations should be reversible
whenever possible. Irreversible operations should require explicit
confirmation (or at least "--force") and ideally should have no other effect
except the specific irreversibility.

~~~
dedward
While all of what you say rings true - it's been said before and bears
repeating - git isn't a version control system as much as it is a set of
version control tools from which you can design a workflow that meets your
needs.

~~~
moe
That's a poor excuse for bad defaults.

The canonical way to use git is by the git syntax. Many (most?) people don't
build scripts and aliases around it. It works just fine when used raw.

However, I'm with Peaker in that losing your working copy is enough of a
nuisance to deserve an interactive prompt, just like 'rm' prompts by default.
Confident users could always disable the prompt with an environment-variable
or .gitconfig flag.

~~~
fr0sty
'rm' prompts by default? since when?

Btw, which defaults are, in your opinion, "bad"?

------
sumeetjain
Love the first one.

Have you considered putting your dotfiles on GitHub? That way other people can
fork them for their own use, and you can also browse your Fork Queue to see if
others have made interesting additions/changes.

Here's mine (mostly forked from a friend's):
<https://github.com/sumeetjain/dotfiles>

As an example, I have one git function (called 'gpa') that shoves everything
in the staging area into a single commit and immediately pushes it.

`gpa "the commit message"`

------
cpeterso
I like easygit (eg). It's training wheels wrapper for git. You use "real" git
commands, but easygit has safer defaults and extra sanity checks (like
forgetting to stage modified files). The help messages are more verbose and
use more consistent terminology than git's man pages. For example, easygit
always uses the term "staged" instead of
"index/staged/add/hard/soft/mixed/cached/HEAD/etc."

<http://people.gnome.org/~newren/eg/>

------
sjs
Most git commands I use on a daily basis have 1-3 letter shell aliases:

[https://github.com/samsonjs/config/blob/master/zsh/zshrc#L23...](https://github.com/samsonjs/config/blob/master/zsh/zshrc#L238-291)

Previously on reddit:
[http://www.reddit.com/r/programming/comments/b0o6z/short_but...](http://www.reddit.com/r/programming/comments/b0o6z/short_but_sweet_shell_aliases_and_global_aliases/)

------
dustingetz
the point aliases is to make executing the command fast enough that you aren't
conscious of actually typing the command, which is one less thing to distract
you. if you go to a computer without the alias, you'll probably interrupt your
thought flow with every command. so in many work/team situations, the (larger)
cost of changing terminals outweighs the (smaller) benefit of aliases.

