Sunday, February 24, 2013

Git tips and tricks

http://www.openlogic.com/wazi/bid/268619/git-tips-and-tricks

You only need a basic command of Git
to make the source code management utility incredibly useful. But Git
offers a range of commands and options that can make your workflow run
even more smoothly. Here are a few Git tips and tricks to make this tool
even greater than you already thought it was.

Aliases in git

There are undoubtedly a few Git commands that you use regularly – git checkout, git commit, and git status,
for example. You can reduce the number of keystrokes you type to invoke
them by using Git aliases. Git stores its aliases (and some other
config options; see below) in the file ~/.gitconfig. You can edit this
file to add alias lines:

[alias]
st = status
co = checkout
cm = commit

Or you can add them with a command like this:

git config --global alias.st "status"

To see what aliases and other config options you have set, run the command git config -l. Aliases are particularly handy for some longer commands, such as some of the commands discussed below. One useful alias is ds = diff --stages,
which shows you a diff of the changes you're about to commit to the
repository – once they're added, but before you commit. It's good
practice to cast a quick eye over those before you commit.

Visualising and managing git branches

If you have lots of branches, it can be useful to see a graphical representation of your Git history. One option for this is gitx, either in its standard version (which should be included in your Git install by default) or using this improved fork. However, if you just want to see a graphical representation of your history on the command line, try

git log --graph --simplify-by-decoration --pretty=format:'%d' --all

simplify-by-decoration shows only commits referred to by a branch or tag, and the only output here is a ref name (%d;
see the PRETTY FORMATS section of the git log manpage for more format
info). A more verbose version shows all commits, with their subject
lines, author, date, and abbreviated commit hash, in pretty colors:

Add --simplify-by-decoration to that last version to get a cross between the two – simplified, with only certain commits, but with more commit info.
Once you've had a look at a tree, you may notice that you have a lot
of branches that seem to have already been merged. This is especially
true if your workflow makes a lot of use of Git branches. To find out
which branches have been merged into other branches, try git branch --merged, or use git branch --no-merged to show the unmerged branches. You can then manually delete merged branches with git -d. (Thanks to Chris Kelly for this tip.)

See more Git log history

git log is useful for reviewing your commit history, but
it's quite basic. It shows only commit ID, author, date, and commit
message. I often want to also know which file was changed. You have a
few options for doing this:

git log --stat: gives pretty output showing which files
changed and how many changes were in each (additions and deletions).
Unfortunately, though, it does not show added files.

git log --name-status: shows files changed and whether
they were added, modified, or deleted, but doesn't show the nature of
changes or the number of changes overall.

git log --name-only: just shows commit info and names of files involved, but not what happened to them.

Using these you should be able to get the information you want.
You can also use the git whatchanged command, which
shows the commit logs and diff output for each commit. The default diff
output is Git's internal format; for a textual diff, which is more
useful to a human reader, try git whatchanged -p, though this is usually overkill if all you want is to check which files were changed.

Ignoring files

If you accidentally add a file you'd rather have ignored, you can unstage it from the commit with git rm:

git rm --cached unwantedfile.txt

You can then add it to the local or the global .gitignore file to ignore it in future.

Amending and reversing changes

You may sometimes commit something you didn't want to, or commit too early. Try running git rebase -i
if you wind up making multiple commits that should have been all in
one, or if you wish to consolidate a bunch of commits for code review.
Make sure your changes are up-to-date and that you're on the branch
you've been working on, then type git rebase -i master to
squash the commits you've made on that branch into one commit on the
master branch. You'll see a screen that looks a bit like this:

pick afa7532 Array handling methods
pick b860afa Reading from notebook file into array
pick df1af7b Setting up notebook file methods
# Rebase cb44197..df1af7b onto cb44197
#
# Commands:
# p, pick = use commit
# r, reword = use commit, but edit the commit message
# e, edit = use commit, but stop for amending
# s, squash = use commit, but meld into previous commit
# f, fixup = like "squash", but discard this commit's log message
# x, exec = run command (the rest of the line) using shell
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
# However, if you remove everything, the rebase will be aborted.

You can reorder the lines if you like, so for example you could edit the above file like so:

to squash all three into a single commit. Once you save the file and
exit the editor, the changes are committed to the master. If you change
your mind before that, delete all the lines and nothing will happen. You
can also of course rebase against another (non-master) branch.
You can amend a commit with git commit --amend. Make
changes in the local copy of the codebase that you would like to commit
(for example, maybe you forgot to add foo.rb, so type git add foo.rb), then type git commit --amend.
foo.rb will then be included in the last commit (along with everything
that was already there), and you'll have a chance to edit the commit
message. If you make no local changes and just type git commit --amend,
you get a chance to amend the commit message. Alternatively, if you
want to keep your commit message and just amend the commit, use git commit --amend -C HEAD.
To undo a commit altogether, use git reset --soft HEAD^. This undoes the last commit but leaves the changes staged. git reset --hard HEAD^ undoes the commit and deletes all your changes locally; use this with caution!
A slightly different way to approach an individual commit is git cherry-pick.
This command enables you to pick a specific commit and add it to your
branch, without also taking all the other commits with it. This can also
be useful if the branch you're cherry-picking from is so out of date
that it would be hard to merge it all in with your own branch. Check out
the branch you wish to add the commits to, find the commit ID from the
other branch, and use:

git cherry-pick COMMIT_ID

If you run into conflicts, you need to fix them in the normal way.

Patches, or adding changes in bits

Sometimes you might be working on several unrelated changes, and wish
to commit them separately. You can do this on a per-file basis either
by using git add this.file and working through the list, or git add -i to go into the interactive version of git add, which allows you to pick changes and stage untracked files.
You can also use the patch functionality to commit individual chunks of changes to a file. Type git add -p myfile.rb
to be walked through the various chunks of changes that you've made to
myfile.rb, and be given the option to add each to the commit. ? gives you help on the command options once you're in there. (Again, thanks to Chris Kelly for this one.)
Check out the Git man pages for yet more options and tricks!