Git Ready2015-10-01T00:51:12+00:00http://gitready.com/Nick Quarantonick@quaran.tointeractive rebase status2015-09-30T00:00:00+00:00http://gitready.com/intermediate/2015/09/30/interactive-rebase-status<p>With <a href="https://github.com/git/git/blob/v2.6.0/Documentation/RelNotes/2.6.0.txt">git 2.6</a> it’s now easier than ever to keep track of your work during an interactive rebase.</p>
<p>Previously, if you were rebasing interactively and had hit a conflict or stopped to reword a commit, git status would look like this:</p>
<pre>
$ git rebase -i HEAD~5
$ git status
rebase in progress; onto 0927cd6
You are currently rebasing branch 'testbranch' on '0927cd6'.
(fix conflicts and then run "git rebase --continue")
</pre>
<p>This only tells you what branch you started with and the target of your rebase. If you want to get information about which commit you’vestopped on, you need to turn to “git log”.</p>
<p>With the release of 2.6, git status now produces much more helpful output that <strong>reminds you what you were doing</strong>. It includes which rebase commands have finished already, and what’s still left to do.</p>
<pre>
$ git rebase -i HEAD~5
$ git status
interactive rebase in progress; onto '0927cd6'
Last commands done (2 done):
pick f47cc4d Style edits
pick 903d58c Post about techcrunch article
edit 8cd01c4 Limit width of post content
Next commands to do (1 remaining commands):
pick 6aa9082 Delete zero-sized files
You are currently editing a commit while rebasing branch 'testbranch' on '0927cd6'.
nothing to commit, working directory clean
</pre>
<p>This gives you more context when working with your commit history, so you know why the rebase stopped.</p>gpg-sign releases2014-11-02T00:00:00+00:00http://gitready.com/advanced/2014/11/02/gpg-sign-releases<p>This is a guest post from <a href="http://rsb.io/">Ryan Brown.</a></p>
<p>As a developer you use code written by other people <em>all the time</em>. To keep upstream changes from breaking your code, you depend on release numbers. Libraries like <a href="https://github.com/twbs/bootstrap">bootstrap</a> use <a href="http://gitready.com/beginner/2009/02/03/tagging.html">git tags</a> to track releases and make them available for download.</p>
<p>This strategy is common enough that GitHub has a handy release page right <a href="https://github.com/twbs/bootstrap/releases/tag/v3.3.0">here</a> to download the zip/tar.gz of the tag you need.</p>
<p>You have the tarball, but are you sure you have the right code? Could the <span class="caps">NSA</span> have tampered with it? Could your internet service provider? Could GitHub? That release passes through many hands between the developer’s hard drive and yours.</p>
<p>Well what if we cloned the repo directly? Commits are all hashed, and you can examine the history.</p>
<pre>
$ git clone --branch v3.3.0 https://github.com/twbs/bootstrap
</pre>
<p>Unfortunately, this very site can tell you how to <a href="http://gitready.com/intermediate/2009/01/31/intro-to-rebase.html">alter git history</a>. Someone sneaky could hide a malicious change in the project history. Luckily, git can help. Signed tags use <a href="https://www.gnupg.org/">Gnu Privacy Guard</a> to verify that a tag was made by the developers of the project, and that the contents are correct.</p>
<pre>
$ cd bootstrap
$ git tag --verify v3.3.0
error: 16dbdbd7a2c6cfa3be4e5dcc52249e577c02c84a: cannot verify a non-tag object of type commit.
error: could not verify the tag 'v3.3.0'
</pre>
<p>Dang, doesn’t look like bootstrap signs their tags. Let’s try a project that does sign their tags.</p>
<pre>
$ git clone --branch v1.0.0 https://github.com/hudl/fargo
$ git tag --verify v1.0.0
object 5f63bca56a2f0268e5934655279dc8705fae4079
type commit
tag v1.0.0
tagger Ryan S. Brown <sb@ryansb.com> 1403217530 -0500
Add DNS discovery for Eureka
gpg: Signature made Thu 19 Jun 2014 06:41:01 PM EDT using RSA key ID 7907CCDB
gpg: Good signature from "Ryan Scott Brown (ryansb) <ryansb@csh.rit.edu>"
gpg: aka "Ryan Scott Brown (ryansb) <sb@ryansb.com>"
</pre>
<p>Neat, now you can see the key fingerprint it was signed with, check that the key is valid. The simplest way is to search <a href="http://pgp.mit.edu/pks/lookup?search=ryansb%40csh.rit.edu&op=vindex">pgp.mit.edu</a> for the email address and compare the key ID to confirm that it’s signed by the right person. You can’t totally trust this method, as <strong>anyone</strong> can upload any key, but it’s better (in theory) than downloading unsigned code. It’s best to verify the key through the <span class="caps">GPG</span> web of trust, in person, through another secure medium, or a combination of these methods. The more verification you can get, the more you can trust the integrity of the signed tag.</p>
<p><strong>Note: Version <a href="https://raw.githubusercontent.com/git/git/master/Documentation/RelNotes/1.7.9.txt">1.7.9</a> introduced the ability to sign commits as well as tags.</strong></p>
<h2>How can you sign your releases?</h2>
<p>To sign tags on your own project, you’ll need a <span class="caps">GPG</span> key of your own. Head over to <a href="http://www.dewinter.com/gnupg_howto/english/GPGMiniHowto-3.html#ss3.1">this tutorial</a> to get set up if you don’t already have a key. If you have multiple keys, you need to configure your signing key.</p>
<pre>
git config --global user.signingkey you@email.domain
</pre>
<p>Now you can make a release as normal, but with a signed commit.</p>
<pre>
git tag -s v0.1 -m "the best version yet"
</pre>
<p>The only difference here is the <code>-s</code>. Before you upload the tag be sure to check your signature with <code>git tag --verify v0.1</code>.</p>
<p>If your project has multiple developers there are a few ways to handle signing releases. The project can have a release-signing key with subkeys for each developer, or developers can use their personal key. Both of these work, but document which method you choose. Users need to know what to expect when they check the release signature.</p>
<p>Just signing releases is a great start, but they aren’t any good if your users don’t check them. Make sure to put a note in your <code>README</code> that you sign releases, and where to find the public key your project uses.</p>ribbon/catchup: reading new commits2011-10-21T00:00:00+00:00http://gitready.com/advanced/2011/10/21/ribbon-and-catchup-reading-new-commits<p>I picked up this trick to use Git as a kind of feed-reader on <a href="http://d.hatena.ne.jp/moro/20110719/1311048331">Moro’s blog</a>, so I thought I’d share it here:</p>
<p>Let’s say you want to stay up-to-date with a project – for example, an upstream repository you are contributing to, a smart developer you are trying to learn from, or an awesome library you’d just like to watch. How do you go about following the commits that are being pushed?</p>
<p>You <em>could</em> use <span class="caps">RSS</span> feeds, such as the ones offered by GitHub:</p>
<p style="text-align:center;"><img src="/images/github-feed.png" alt="" /></p>
<p>But let’s be honest: We would much rather read commits and diffs in the shell, like we are used to. (And as a bonus, we won’t be assaulted by webcomics, pictures of kittens, and any number of other distractions our feed reader has in store for us.)</p>
<p>So instead, we display new commits with <code>git log</code>, and use Git’s <a href="http://book.git-scm.com/3_git_tag.html">lightweight tag system</a> to place a “ribbon” marker tag that keeps track of how far we have read.</p>
<p style="text-align:center;"><a href="http://www.flickr.com/photos/beth19/4288525214/"><img src="/images/ribbon-marker.jpg" title="A real-life ribbon marker" alt="A real-life ribbon marker" /></a> <!-- photo CC BY-NC-ND 2.0 on Aug 20, 2011 --></p>
<p>Simply add the following code to your <code>~/.gitconfig</code>:</p>
<pre>
[alias]
ribbon = tag --force _ribbon origin/master
catchup = log --patch --reverse --topo-order _ribbon..origin/master
</pre>
<p>Clone the project you want to watch, and type <code>git ribbon</code> to initialize the ribbon marker.</p>
<p>Now whenever you fetch or pull, use <code>git catchup</code> to read up on the latest changes in the <code>origin/master</code> branch. After you are done reading, update the ribbon marker with <code>git ribbon</code>.</p>
<p>Sweet, isn’t it?</p>
<p>By the way: If you do not like to read the individual commits in topic branches that were merged into <code>origin/master</code>, consider adding <code>--first-parent -m</code> to the catchup log command.</p>
<p style="padding-left:3em;"><i>This is a guest post by <a href="https://twitter.com/jo_liss">Jo Liss</a>. Jo likes JavaScript and created a <a href="http://www.solitr.com/">solitaire game</a>. </i></p>tig, the ncurses front-end to Git2009-07-31T00:00:00+00:00http://gitready.com/advanced/2009/07/31/tig-the-ncurses-front-end-to-git<p style="text-align:center;">This is a guest post from <a href="http://www.atnan.com/">Nathan de Vries</a>.</p>
<p>I’ve never really been a fan of gitk, but early on when I started using Git I found a tool called <a href="http://jonas.nitro.dk/tig/">tig</a>. It’s available in <a href="http://tig.darwinports.com/">MacPorts</a> and Ubuntu (since Gutsy) through <code>apt-get install tig</code>. Tig provides a simple command-line yet visual interface to Git.</p>
<p style="text-align:center;"><a href="http://jonas.nitro.dk/tig/screenshots/main-view-split.png"><img src="/images/main-view-split.png" title="The main view split - log on top, diff on bottom" alt="The main view split - log on top, diff on bottom" /></a></p>
<p>The simplest usage is just running <code>tig</code> when you’re in a git repository. This will bring up visual git-log, but the nice thing about it is that you can navigate up and down the log using the up and down keys (or <code>j</code> and <code>k</code> keys if you’re used to vim keys). Hit <code><enter></code> on a log entry, and it will open a split-pane window with the diff of that commit. Using <code><space></code> will move you through the diff, and up and down will move you between commits. Hitting <code>q</code> will close the split-pane, and hitting <code>q</code> again will close tig altogether.</p>
<p>Another useful aspect of tig is the tree-view. When you launch tig, hit <code>t</code> when you’re in log view and it will bring up a navigatable tree view of the repository. Hit <code><enter></code> to descend into directories or view files, or <code><shift>-B</code> on a file to see an annotated view.</p>
<p style="text-align:center;"><a href="http://jonas.nitro.dk/tig/screenshots/tree-view.png"><img src="/images/tree-view.png" title="The tree view" alt="The tree view" /></a></p>
<p>So far we’ve just been using tig on whichever branch we have checked out at the time, but tig also takes a revision argument (i.e. branch, tag, hash etc.). I personally find this useful for seeing what’s going on in remote branches, by using a command like <code>tig origin/rel-1.5</code>.</p>
<p>Showing another branch from within a different branch can also be incredibly handy if you’d like to <a href="http://gitready.com/intermediate/2009/03/04/pick-out-individual-commits.html">cherry-pick</a> a change from another branch into the current branch. Say I’ve committed a change to <code>master</code> that I’d like to make available to the release branch <code>origin/rel-1.5</code>. All I need to do is checkout the release branch with <code>git checkout -b 1.5 origin/rel-1.5</code>, open tig using <code>tig master</code>, navigate to the changeset I’d like to cherry-pick, and hit <code><shift>-C</code>. Repeat as necessary.</p>
<p style="text-align:center;"><a href="http://jonas.nitro.dk/tig/screenshots/blame-view.png"><img src="/images/blame-view.png" title="The blame view" alt="The blame view" /></a></p>
<p>I haven’t really had a chance to investigate many of the other features of tig, other than <code>tig show [rev]</code> and <code>tig blame [file]</code> which I use every day. If anyone has some more tips as to how to make good use of tig, be sure to share them in the comments!</p>find unmerged commits2009-04-16T00:00:00+00:00http://gitready.com/intermediate/2009/04/16/find-unmerged-commits<p>So you’re chugging along developing in a topic branch when you decide it’s about time that your work needs to brought back into your main development line. With graphical views like <a href="http://gitready.com/intermediate/2009/01/13/visualizing-your-repo.html">gitk or GitX</a>, it’s really easy to figure out what hasn’t been merged in yet. Let’s say we have the following scenario:</p>
<p style="text-align:center;"><img src="/images/cherry-gitx.png" alt="" /></p>
<p>If you want to do this from the command line, you’ve got a few options. One decent way of visualizing this is by using <code>git log</code>, which has plenty of <a href="http://gitready.com/advanced/2009/01/20/bend-logs-to-your-will.html">awesome options available</a> besides this one:</p>
<p><code>git log --pretty=oneline --graph --all</code></p>
<p style="text-align:center;"><img src="/images/cherry-log.png" alt="" /></p>
<p>You could also use the range syntax in <code>git log</code> to get the commits that aren’t merged.</p>
<pre>
$ git checkout master
$ git log ..42-adding-replies
</pre>
<p><code>git log master..42-adding-replies</code></p>
<p>There is another option though: <code>git cherry</code>. This does exactly what we want: tells us which commits aren’t in the branch specified. So if I was on the master branch and I ran:</p>
<pre>
$ git cherry -v master 42-adding-replies
+ a4d0f79fccbbc12a53e8f0e5c2a4ef960ad69ba2 Adding posts in
+ 7e71afd1faf36f17a0ff506e63cd2ca51496dad3 Revert "Adding posts in"
+ 5e815ece05d8813354e60ca1affb8cdb8c5d78fc Adding the right model
+ 956f4cec5684544066a0d261ff8ac80aff7a57ea Cleaning up model
+ 6c6cdb4342ed935f8fbd38f48f51dec469dd1823 Who needs tests?
+ c3481fd0d6279f5bd45c455b915e0b4b1c0d8909 Wrapping this up. Ship it.
</pre>
<p>So what we just did was asked Git what’s not in <code>master</code> that’s in <code>42-adding-replies</code> branch. Just like in the images above it’s simple to see what needs to get merged in still. The <code>-v</code> option will print out the commit message along with the <span class="caps">SHA</span> hash so it’s easier to figure out what exactly you’re looking at. This command also takes in a third, optional argument for picking a starting point or limit. So, if we wanted to just check everything after commit <code>7e71af</code>, you’d get this:</p>
<pre>
$ git cherry -v master 42-adding-replies 7e71af
+ 5e815ece05d8813354e60ca1affb8cdb8c5d78fc Adding the right model
+ 956f4cec5684544066a0d261ff8ac80aff7a57ea Cleaning up model
+ 6c6cdb4342ed935f8fbd38f48f51dec469dd1823 Who needs tests?
+ c3481fd0d6279f5bd45c455b915e0b4b1c0d8909 Wrapping this up. Ship it.
</pre>
<p>As you can see, that skipped the first two commits in our topic branch. If you wanted to check what hasn’t been merged into an upstream branch when not actually on the upstream branch, it’s a little simpler:</p>
<pre>
$ git checkout 42-adding-replies
$ git cherry master
+ a4d0f79fccbbc12a53e8f0e5c2a4ef960ad69ba2
+ 7e71afd1faf36f17a0ff506e63cd2ca51496dad3
+ 5e815ece05d8813354e60ca1affb8cdb8c5d78fc
+ 956f4cec5684544066a0d261ff8ac80aff7a57ea
+ 6c6cdb4342ed935f8fbd38f48f51dec469dd1823
+ c3481fd0d6279f5bd45c455b915e0b4b1c0d8909
</pre>
<p>One really neat aspect about this command is that it actually compares the changesets instead of the commit <span class="caps">SHA</span>, since you may have modified the commit by adding a signoff or changed its parents in some manner. In any case, you can depend on this command to tell you what hasn’t been merged into your upstream branch. Also, don’t confuse this with <a href="http://gitready.com/intermediate/2009/03/04/pick-out-individual-commits.html">cherry-pick</a>, which does something totally different.</p>find ancestor commits2009-04-03T00:00:00+00:00http://gitready.com/intermediate/2009/04/03/find-ancestor-commits<p>Ever seen this message when trying to delete a branch?</p>
<pre>
$ git branch -d docs
error: The branch 'docs' is not an ancestor of your current HEAD.
If you are sure you want to delete it, run 'git branch -D docs'
</pre>
<p>Since the branch you’re currently on doesn’t have the branch you want to delete merged in. This is one of the many ways that Git tries really hard not to lose your data for you. So, how would you find out if a given branch (or commit) is merged into your current branch without having to try and delete it?</p>
<p>The <code>git branch</code> command has a few flags that will help out with this problem. The <code>--contains</code> tag will figure out if a certain commit has been brought in yet into your branch. Perhaps you’ve got a commit <span class="caps">SHA</span> from a patch you thought you had applied, or you just want to check if commit for your favorite open source project that reduces memory usage by 75% is in yet.</p>
<pre>
$ git log -1 tests
commit d590f2ac0635ec0053c4a7377bd929943d475297
Author: Nick Quaranto <nick@quaran.to>
Date: Wed Apr 1 20:38:59 2009 -0400
Green all around, finally.
$ git branch --contains d590f2
tests
* master
</pre>
<p>From these results we can see that commit <code>d590f2</code> has been merged into the <code>tests</code> and <code>master</code> branch.</p>
<p>Back to the original conundrum: how to figure out if a branch has been merged in! The <code>--merged</code> and <code>--no-merged</code> flags can do just this for you. The former will tell you what branches have that <a href="http://book.git-scm.com/4_git_treeishes.html">treeish</a> merged in, while the latter will do the opposite.</p>
<p>In this case, our <code>docs</code> branch is not fully merged into our <code>master</code> branch:</p>
<pre>
$ git branch --merged docs
docs
$ git branch --no-merged docs
config
* master
tests
$ git branch -d docs
error: The branch 'docs' is not an ancestor of your current HEAD.
If you are sure you want to delete it, run 'git branch -D docs'.
$ git branch -D docs
Deleted branch docs (884583c).
</pre>
<p>If you’re brave, you could use a combination of the <code>git rev-parse</code> and <code>git rev-list</code> to find if a commit is in the history of a given branch or not. I originally hacked this together until someone on the <a href="http://gitready.com/beginner/2009/03/02/where-to-find-the-git-community.html">#git <span class="caps">IRC</span> channel</a> let me know about the obvious solution in <code>git branch</code>. <code>rev-parse</code> takes a treeish and converts it into the <span class="caps">SHA</span> it belongs to. <code>rev-list</code> can print out commits in a myriad of different ways and deserves a tip all on its own.</p>
<pre>
$ git rev-list master | grep $(git rev-parse docs)
$ git rev-list master | grep $(git rev-parse tests)
d590f2ac0635ec0053c4a7377bd929943d475297
</pre>
<p>The first command returns nothing at all, since the <code>HEAD</code> commit in <code>docs</code> doesn’t exist in the timeline for the <code>master</code> branch yet. On the other had, grep finds the <code>HEAD</code> commit for tests in <code>master</code> as expected.</p>
<p>Hopefully this saves you some time when dealing with multiple branches and wondering if they’ve been merged in yet. If you have other suggestions for dealing with this situation, leave a comment!</p>what's inside your .git directory2009-03-23T00:00:00+00:00http://gitready.com/advanced/2009/03/23/whats-inside-your-git-directory<p><strong><span class="caps">UPDATE</span></strong>: I’ve recieved some very helpful comments regarding corrections to the various files and what they do. Thanks for letting me know and keeping me on my toes.</p>
<p>One of the things I like best about Git is that it keeps all of its information in one place: your <code>.git</code> directory in your project’s root. If you haven’t been digging around it yet, don’t fret! There’s plenty of goodies to be had within it. Let’s take a look into the important files and folders and try to get a better sense of what’s going on under the hood.</p>
<p>The basic structure looks like this:</p>
<pre>
.
|-- COMMIT_EDITMSG
|-- FETCH_HEAD
|-- HEAD
|-- ORIG_HEAD
|-- branches
|-- config
|-- description
|-- hooks
| |-- applypatch-msg
| |-- commit-msg
| |-- post-commit
| |-- post-receive
| |-- post-update
| |-- pre-applypatch
| |-- pre-commit
| |-- pre-rebase
| |-- prepare-commit-msg
| `-- update
|-- index
|-- info
| `-- exclude
|-- logs
| |-- HEAD
| `-- refs
|-- objects
`-- refs
|-- heads
|-- remotes
|-- stash
`-- tags
</pre>
<p>Let’s go over some of the normal files that you may see living in the base directory:</p>
<ul>
<li><code>COMMIT_EDITMSG</code>: This is the last commit’s message. It’s not actually used by Git at all, but it’s there mostly for your reference after you made a commit.</li>
<li><code>config</code>: Contains settings for this repository. Specific configuration variables can be dumped in here (and even <a href="http://gitready.com/intermediate/2009/02/06/helpful-command-aliases.html">aliases</a>!) What this file is most used for is defining where remotes live and some core settings, such as if your repository is bare or not.</li>
<li><code>description</code>: If you’re using <a href="http://git.or.cz/gitwiki/Gitweb">gitweb</a> or firing up <code>git instaweb</code>, this will show up when you view your repository or the list of all versioned repositories.</li>
<li><code>FETCH_HEAD</code>: The SHAs of branch/remote heads that were updated during the last <code>git fetch</code></li>
<li><code>HEAD</code>: The current ref that you’re looking at. In most cases it’s probably <code>refs/heads/master</code></li>
<li><code>index</code>: The <a href="http://gitready.com/beginner/2009/01/18/the-staging-area.html">staging area</a> with meta-data such as timestamps, file names and also SHAs of the files that are already wrapped up by Git.</li>
<li><code>packed-refs</code>: Packs away dormant refs, this is not the definitive list of refs in your repository (the <code>refs</code> folder has the real ones!) Take a look at gitster’s comment to see more information on this.</li>
<li><code>ORIG_HEAD</code>: When doing a merge, this is the <span class="caps">SHA</span> of the branch you’re merging into.</li>
<li><code>MERGE_HEAD</code>: When doing a merge, this is the <span class="caps">SHA</span> of the branch you’re merging from.</li>
<li><code>MERGE_MODE</code>: Used to communicate constraints that were originally given to <code>git merge</code> to <code>git commit</code> when a merge conflicts, and a separate <code>git commit</code> is needed to conclude it. Currently <code>--no-ff</code> is the only constraints passed this way.</li>
<li><code>MERGE_MSG</code>: Enumerates conflicts that happen during your current merge.</li>
<li><code>RENAMED-REF</code>: Still trying to track this one down. From a basic grep through the source, it seems like this file is related to errors when saving refs.</li>
</ul>
<p>There’s plenty of directories as well:</p>
<ul>
<li><code>hooks</code>: A directory that will fast become your best friend: this contains scripts that are executed at certain times when working with Git, such as after a commit or before a rebase. An entire series of articles will be coming about hooks.</li>
<li><code>info</code>: Relatively uninteresting except for the <code>exclude</code> file that lives inside of it. We’ve seen this before in the <a href="http://gitready.com/beginner/2009/01/19/ignoring-files.html">ignoring files</a> article, but as a reminder, you can use this file to ignore files for this project, but beware! It’s not versioned like a <code>.gitignore</code> file would be.</li>
<li><code>logs</code>: Contains history for different branches. Seems to be used mostly with the <a href="http://gitready.com/intermediate/2009/02/09/reflog-your-safety-net.html">reflog</a> command.</li>
<li><code>objects</code>: Git’s internal warehouse of blobs, all indexed by SHAs.</li>
<li><code>rebase-apply</code>: The workbench for <a href="http://gitready.com/intermediate/2009/01/31/intro-to-rebase.html">rebasing</a> and for <code>git am</code>. You can dig into its <code>patch</code> file when it does not apply cleanly if you’re brave.</li>
<li><code>refs</code>: The master copy of all refs that live in your repository, be they for stashes, tags, remote tracking branches, or local branches.</li>
</ul>
<p>Just one word of wisdom when messing around with Git internals: make sure you know what you’re doing, and if not, have a backup! Messing around with the config files or hooks is pretty simple but I wouldn’t go spelunking in the datastore if I didn’t have to. If for some reason you are as part of your normal workflow, you might be doing it wrong.</p>
<p>There’s plenty more about the internals of Git that we haven’t covered yet. One of the best guides is the <a href="http://book.git-scm.com">Git Community Book</a>, and of course, you can just <a href="http://git.kernel.org/?p=git/git.git;a=summary">download the source for yourself</a> and take a look. If you have more information about what’s going on in the <code>.git</code> folder, let us know in the comments!</p>reorder commits with rebase2009-03-20T00:00:00+00:00http://gitready.com/advanced/2009/03/20/reorder-commits-with-rebase<p>One of the vast uses of <a href="http://gitready.com/intermediate/2009/01/31/intro-to-rebase.html">git rebase -i</a> is reordering commits. Just please, <span class="caps">PLEASE</span> don’t rebase commits that have been pushed publicly. If you’re working with other developers, that will make the merge non fast-forwardable and creates headaches for all involved. Yes, the command allows one to rewrite history, but only do so when the commits are still on your local machine.</p>
<p>Now that the warnings are over, let’s get to the point. The scenario here is that you want to change up the sequence of commits. Perhaps you wanted to push certain changes farther down in history, or for some reason putting that third commit as the first one just makes more sense. So, let’s do just that. Let’s say our history looks like so:</p>
<p style="text-align:center;"><img src="/images/reorder1.png" alt="" /></p>
<p>So, let’s start by using <code>git rebase -i HEAD~3</code>. Your $<span class="caps">EDITOR</span> will pop open with some text similar to this:</p>
<pre>
pick 4c39bca gemspec tweak
pick 85409cf Version bump to 0.4.1
pick eb32194 Regenerated gemspec for version 0.4.1
# Rebase 60709da..eb32194 onto 60709da
#
# Commands:
# p, pick = use commit
# e, edit = use commit, but stop for amending
# s, squash = use commit, but meld into previous commit
#
# If you remove a line here THAT COMMIT WILL BE LOST.
# However, if you remove everything, the rebase will be aborted.
#
</pre>
<p>Reordering is as simple as moving the various ‘pick’ commands around. So if we wanted to swap the first commit with the last:</p>
<pre>
pick eb32194 Regenerated gemspec for version 0.4.1
pick 85409cf Version bump to 0.4.1
pick 4c39bca gemspec tweak
...
$ git rebase -i HEAD~3
Successfully rebased and updated refs/heads/test.
</pre>
<p>Save the file, and hopefully everything will go alright. If not, you’ll probably have a decent merge to take care of. If this gets too messy to take care of, just do a <code>git rebase --abort</code> and you’ll be back where you started. Don’t worry about losing data either, since you can always use the <a href="http://gitready.com/intermediate/2009/02/09/reflog-your-safety-net.html">reflog</a> to pluck out anything you might need. As expected, the history now shows the commits reversed:</p>
<p style="text-align:center;"><img src="/images/reorder2.png" alt="" /></p>
<p>Do note that the commit dates are still reversed, so it may seem a bit strange especially to others working with your repository. Reordering is probably more useful when combined with the other options available inside of interactive rebase, such as <a href="http://gitready.com/advanced/2009/02/10/squashing-commits-with-rebase.html">squashing</a> or editing commit messages. If reordering commits has helped you out (or possibly hurted!) do let us know in the comments.</p>restoring a directory from history2009-03-18T00:00:00+00:00http://gitready.com/intermediate/2009/03/18/restoring-a-directory-from-history<p>It’s quite easy to <a href="http://gitready.com/intermediate/2009/03/16/rolling-back-changes-with-revert.html">revert</a> or <a href="http://gitready.com/beginner/2009/01/11/reverting-files.html">reset</a> a single file from history, but what about pulling an entire directory out of the history?</p>
<p style="text-align:center;"><a href="http://www.flickr.com/photos/stevejaysbestshots/1402673467/"><img src="/images/stump.png" alt="" /></a></p>
<p>The solution is simple:</p>
<p><code>git checkout <treeish> -- /path/to/dir</code></p>
<p>That will bring back the directory from the given “treeish” for the <code>/path/to/dir</code>. Let’s go through an example of this:</p>
<p>First off, let’s remove a directory and then merge in a ton of changes (for future reference, this is going off a refactoring branch of <a href="http://github.com/qrush/jekyll">Jekyll</a>, the static blog engine that generates this site).</p>
<p style="text-align:center;"><img src="/images/checkout1.png" alt="" /></p>
<p>Here’s how the history looks:</p>
<p style="text-align:center;"><img src="/images/checkout2.png" alt="" /></p>
<p>Hopefully this isn’t too confusing. Basically the commit we just made is pretty far down in history, which most likely will be the case you’re in if you need to restore a directory. First off, we need to get the reference to the commit that has the directory you want to pull. In this case, we know the last commit was the merge and the commit before that we deleted the directory. So, the commit we want to reference is the third commit in history, or <code>HEAD~2</code>. You could also reference this by the branch name (<code>test~2</code>) or even go one back from the <span class="caps">SHA</span> of the deletion (<code>f46666d^</code>).</p>
<p>In any case, if you try to checkout a directory from a revision where it doesn’t exist, you’ll get this nice message:</p>
<pre>
$ git checkout test~1 -- bin/
error: pathspec 'bin' did not match any file(s) known to git.
</pre>
<p>So, let’s check out the correct revision and finally get our directory back where it belongs:</p>
<p style="text-align:center;"><img src="/images/checkout3.png" alt="" /></p>
<p>Great, now we’re back in business. From here you can add or commit the file as needed.</p>
<p>If you’re in this situation you might want to consider reverting the commit, which could restore the files that were deleted as well. However, this isn’t always possible and may not be the best way to pull the directory you’re missing back out of history.</p>rolling back changes with revert2009-03-16T00:00:00+00:00http://gitready.com/intermediate/2009/03/16/rolling-back-changes-with-revert<p>We’ve all done it. Perhaps you didn’t have enough coffee that morning, or it was just before lunch. Somehow though, that bug got into the repository, and now you need to get it out. Luckily, <code>git revert</code> is just the scalpel you need to extract that bad commit.</p>
<p style="text-align:center;"><a href="http://www.flickr.com/photos/cheryl/1449240840/"><img src="http://farm2.static.flickr.com/1032/1449240840_a61f776d69_m.jpg" alt="" /></a></p>
<p>Let’s say our history looks like this:</p>
<p style="text-align:center;"><img src="/images/revert1.png" alt="" /></p>
<p>The “revert” command works like so: it basically reverses whatever changes made in the commit passed in by creating a new commit. So, you wanted to revert the last commit you just made on your current branch:</p>
<pre>
$ git revert HEAD
Finished one revert.
[master]: created 1e689e2:
"Revert "Updated to Rails 2.3.2 and edge hoptoad_notifier""
</pre>
<p>Our repository would now look like so:</p>
<p style="text-align:center;"><img src="/images/revert2.png" alt="" /></p>
<p>You can also pass in any <span class="caps">SHA</span> for any commit to revert those changes. Of course, if the commit that you want to revert doesn’t apply cleanly you’re going to have to manually resolve the merge.</p>
<p>By default using this command will bring up your <code>$EDITOR</code> so you can modify the commit message of the revert. Use this to explain why the changes are being backed out! If for some reason you don’t want to edit the commit message, tacking on <code>--no-edit</code> will allow you do so.</p>
<p>Another helpful option is the <code>-n</code> or <code>--no-commit</code> flag. This will simply leave the reverted changes in your working directory and not automatically commit them. If you need to edit files further to complete the revert or possibly revert more than one commit, try out this option.</p>
<p>Finally, dealing with reverting merges is somewhat irksome. You may receive this message when trying to revert one:</p>
<pre>
$ git revert HEAD~1
fatal: Commit 137ea95 is a merge but no -m option was given.
</pre>
<p>With merges, you need to pick one of the merged in commits to revert. By using the <code>-m</code> or <code>--mainline</code> option, you can pick out which commit should be part of the ‘mainline’. This requires a number argument, which is a bit misleading. Let’s look at the merge commit shown above:</p>
<pre>
$ git log HEAD~1 -1
commit 137ea95c911633d3e908f6906e3adf6372cfb0ad
Merge: 5f576a9... 62db4af...
Author: Nick Quaranto <nick@quaran.to>
Date: Mon Mar 16 16:22:37 2009 -0400
Merging in rails-2.3 branch
</pre>
<p>Basically, if we do <code>git revert HEAD~1 -m 1</code>, you’ll get the first commit in the merge reverted (<code>5f576a9</code>). Using <code>-m 2</code> will revert the second commit (<code>62db4af</code>). It’s just a matter of figuring out which commit you need to roll back. The default commit message shows the commit that was reverted as well.</p>
<pre>
$ git revert HEAD~1 --no-edit --mainline 2
Finished one revert.
[master]: created 526b346: "Revert "Merging in rails-2.3 branch""
$ git log -1
commit d64d3983845dfa18a5d935c7ac5a4855c125e474
Author: Nick Quaranto <nick@quaran.to>
Date: Mon Mar 16 19:24:45 2009 -0400
Revert "Merging in rails-2.3 branch"
This reverts commit 137ea95c911633d3e908f6906e3adf6372cfb0ad, reversing
changes made to 62db4af8c77852d2cc9c19efc6dfb97e0d0067f5.
</pre>
<p>The Git documentation suggests that you look at <a href="http://www.kernel.org/pub/software/scm/git/docs/howto/revert-a-faulty-merge.txt">this message from Linus</a> if you need some help resolving merges. Hopefully soon I’ll have some better posts up regarding these kinds of situations. If you know of other great uses of the revert commit (or perhaps horror stories, or how it saved you) let us know!</p>smartly save stashes2009-03-13T00:00:00+00:00http://gitready.com/beginner/2009/03/13/smartly-save-stashes<p>I seem to be using <a href="http://gitready.com/beginner/2009/01/10/stashing-your-changes.html">stashing</a> more and more, and I’ve found that seeing the stash list output looking like this isn’t very helpful:</p>
<pre>
$ git stash list
stash@{0}: WIP on feature1: b50788b... First pass...
stash@{1}: WIP on master: b50788b... First pass...
stash@{2}: WIP on shoulda: e783fb0... Upgrading the rest...
</pre>
<p>Sure, it’s got the commit <span class="caps">SHA</span> and message that your work was based off of, but if you’re anything like me, you forgot what you worked on the moment you stashed the changes and opened up that dreaded bug ticket that took hours to finish.</p>
<p>Instead, stashing like this is a lot better when you’re trying to figure out what you actually threw in there:</p>
<p><code>git stash save "your message here"</code></p>
<p>Now, your stashes will look a lot cleaner and hopefully help you save some time when pulling information out of there.</p>
<pre>
$ git stash list
stash@{0}: On shoulda: Updating instructions
stash@{1}: On master: started merge but need to fix #104 first
stash@{2}: On feature1: Adding some stuff
</pre>
<p>If you need to see what’s been changed for a certain stash, you can simply pass in the treeish for the stash, given in the <code>git stash list</code> output. The <code>stash@{<number>}</code> part shows you how to reference that changeset. Simply pass it into <code>git diff</code> to figure out what was changed:</p>
<pre>
$ git diff stash@{0}
diff --git a/TODO b/TODO
index b0ecaeb..4ca398c 100644
--- a/TODO
+++ b/TODO
@@ -1,4 +1,3 @@
[ ] Easier configuration of Maruka and blahtex directories [mdreid]
[ ] Accurate "related posts" calculator
-[ ] Autobuild
-[ ] Add more awesome.
+[ ] Autobuild
\ No newline at end of file
</pre>
<p>You could also use <code>git show</code> to see the commit it was based off of as well. If you’ve got more stash related tips or others that you can think of, <a href="http://gitready.com/submit.html">let us know!</a></p>easily manage git remote branches2009-03-11T00:00:00+00:00http://gitready.com/advanced/2009/03/11/easily-manage-git-remote-branches<p><a href="http://gitready.com/intermediate/2009/01/09/checkout-remote-tracked-branch.html">Checking out remote branches</a>, <a href="http://gitready.com/beginner/2009/02/02/push-and-delete-branches.html">deleting them</a>, and publishing new ones is part of most Git users’ daily workflow. But seriously, who wants to type <strong>that</strong> much? I certainly don’t, and you shouldn’t have to either.</p>
<p>Enter <a href="http://grb.rubyforge.org/">git_remote_branch</a>, a helpful <a href="http://rubygems.org">RubyGem</a> for just this task. It installs a new executable to help take some of the chore of working with remotes away. Here are some of the commands it has:</p>
<pre>
grb create branch_name [origin_server]
grb publish branch_name [origin_server]
grb rename branch_name [origin_server]
grb delete branch_name [origin_server]
grb track branch_name [origin_server]
</pre>
<p>What’s awesome about it is that it shows what Git commands are running underneath it, so it’s quite easy to figure out exactly what’s going on.</p>
<p style="text-align:center;"><img src="/images/grb1.png" alt="" /></p>
<p>It also has an <code>explain</code> command built in that dumps out the commands directly.</p>
<p style="text-align:center;"><img src="/images/grb2.png" alt="" /></p>
<p>Provided you have <a href="http://rubyforge.org/frs/?group_id=126">RubyGems installed</a>, simply do <code>gem install git_remote_branch</code> and you’re set! Check out the code on <a href="http://github.com/webmat/git_remote_branch/tree">GitHub</a> if you have ideas on how to make it better (or want to write your own helpful commands based off of it!)</p>
<p>If you know of other helpful shortcuts that can help out Git users, <a href="http://gitready.com/submit.html">submit a tip!</a></p>remote tracking branches2009-03-09T00:00:00+00:00http://gitready.com/beginner/2009/03/09/remote-tracking-branches<p>Confused about what exactly a remote tracking branch is? Don’t worry, it’s <a href="http://kerneltrap.org/mailarchive/git/2007/8/4/253944">not just you</a>. Basically, there’s two types of branches: local, and remote-tracking. Local branches are pretty run of the mill, they’re just another path in the <a href="http://gitready.com/beginner/2009/02/17/how-git-stores-your-data.html"><span class="caps">DAG</span></a> that you can commit to. Remote-tracking branches have a few different purposes:</p>
<ol>
<li>They’re used to link what you’re working on locally compared to what’s on the remote.</li>
<li>They will automatically know what remote branch to get changes from when you use <code>git pull</code> or <code>git fetch</code>.</li>
<li>Even better, <code>git status</code> will recognize him how many commits you are in front of the remote version of the branch.</li>
</ol>
<p>Luckily, the <code>git branch</code> command gives us some insight to what branch is what. For most normal, freshly cloned repositories, you’ll see this output:</p>
<pre>
$ git branch
* master
</pre>
<p>This just shows the default local branch, the master branch. If you wanted to see remote branches:</p>
<pre>
$ git branch -r
origin/HEAD
origin/master
</pre>
<p>And finally, if you wanted to see them all:</p>
<pre>
$ git branch -a
* master
origin/HEAD
origin/master
</pre>
<p>When branches are created using the <code>--track</code> option, they will be set up to linked to the remote branch. For example, if you wanted to create a new branch from the master branch from the origin remote, using this would set it up so it would pull from the remote and branch automatically:</p>
<pre>
$ git branch --track feature1 origin/master
Branch feature1 set up to track remote branch refs/remotes/origin/master.
</pre>
<p>From here you can <code>git checkout</code> the branch and work with it, and since it’s tracking the remote branch, it will know where to bring in changes from when you fetch or pull.</p>
<p>Local branches can also be created from any start point, be it a remote tracking branch or any <a href="http://book.git-scm.com/4_git_treeishes.html">treeish</a> passed in. Here are some examples:</p>
<pre>
$ git branch --no-track feature2 origin/master
$ git branch --no-track feature3 HEAD~4
$ git branch --no-track feature4 f21e886
</pre>
<p>Now, in these examples the <code>--no-track</code> option was specified. This was done to ensure that the branches did not derive from a remote tracking branch. You can tweak how this works through your <code>~/.gitconfig</code> file. As the <a href="http://cheat.errtheblog.com/s/git/">Git Cheat Sheet</a> says:</p>
<blockquote>
<p><tt>git config branch.autosetupmerge true</tt><br />
tells git-branch and git-checkout to setup new branches so that git-pull(1)<br />
will appropriately merge from that remote branch. Recommended. Without this,<br />
you will have to add —track to your branch command or manually merge remote<br />
tracking branches with “fetch” and then “merge”.</p>
</blockquote>
<p>Hopefully this post has cleared up some confusion you may have had regarding branches and what exactly remote-tracking does. If you have more ideas on how to explain this better or related resources let us know in the comments or <a href="http://gitready.com/submit.html">submit a tip!</a></p>ignoring doesn't remove a file2009-03-06T00:00:00+00:00http://gitready.com/beginner/2009/03/06/ignoring-doesnt-remove-a-file<p>One problem I see quite often in the #git channel on Freenode is that beginners get confused as to why a file doesn’t disappear from history when they place it into their <a href="http://gitready.com/beginner/2009/01/19/ignoring-files.html">.gitignore</a> file. The answer to this is quite simple! When you tell Git to ignore files, it’s going to <strong>only</strong> stop watching changes for that file, and nothing else. This means that the history will still remember the file and have it.</p>
<p>If you want to remove a file from the repository, but keep it in your working directory, simply use:</p>
<p><code>git rm --cached <file></code></p>
<p>However, this will still keep the file in history. If you actually want to remove it from history, you really have two options: rewrite your repository’s commits, or start over. Both options really suck, and that’s for a good reason: Git tries hard not to lose your data. Just like with <a href="http://gitready.com/intermediate/2009/01/31/intro-to-rebase.html">rebasing</a>, Git forces you to think about these kinds of options since they are destructive operations.</p>
<p>If you did actually want to remove a file from history, <code>git filter-branch</code> is the hacksaw you’re looking for. Definitely read up on its <a href="http://www.kernel.org/pub/software/scm/git/docs/git-filter-branch.html">manpage</a> before using it, since it will literally rewrite your project’s commits. This actually is a great tool for some actions, and can do all sorts of stuff like totally removing an author’s commits to moving the project root folder around. The command to remove a file from all revisions is:</p>
<p><code>git filter-branch --index-filter 'git rm --cached <file>' HEAD</code></p>
<p>This action can definitely be useful when you need to blow out sensitive or confidential information that may have been placed in your repository. More tips in the future will cover some of the other neat things <code>filter-branch</code> can do. If you know of any useful tips regarding it, let us know in the comments or <a href="http://gitready.com/submit.html">submit a tip!</a></p>pick out individual commits2009-03-04T00:00:00+00:00http://gitready.com/intermediate/2009/03/04/pick-out-individual-commits<p>Sometimes you might only want one commit out of a branch, or perhaps you’ll need to pluck a file from only one changeset. This tip is going to go over some ways on how to pull out one individual commit and work with it.</p>
<p style="text-align:center;"><a href="http://flickr.com/photos/waltjabsco/2767960923/"><img src="http://farm4.static.flickr.com/3290/2767960923_92b8e5a8db.jpg" alt="" /></a></p>
<p>The basic case here is that you’re looking at another branch or perhaps someone’s fork of a project, but you only want to bring over one commit, a few commits, or what have you. Luckily, Git has plenty of tools to make this easy for you. Here’s the scenario. There’s been a lot of development on <a href="http://github.com/mojombo/jekyll">jekyll</a> lately, but I only want to bring in one or two specific changesets. The repository looks like this:</p>
<p style="text-align:center;"><img src="/images/pick.png" alt="" /></p>
<p>As you can see, our master branch is at the bottom of this flurry of activity, and there’s been quite a lot of activity above it. However, I just want the commit highlighted to be brought into my repository. Once you’ve got the commit <span class="caps">SHA</span>, you have a few options:</p>
<p>1) Use <code>git cherry-pick</code> to pluck out the commit. This will create a new commit and preserve the old commit’s metadata.</p>
<p>2) Create a patch using <code>git format-patch</code> then bring that in using <code>git am</code>. This allows you to <code>--signoff</code> the commit too! This also makes a new commit.</p>
<p>3) Use <code>git apply</code> with the patch to put the changes into your working directory so you can edit them further.</p>
<p>4) <code>git merge</code> the changes right in, which preserves the original commit (provided there’s no conflicts)</p>
<p>Let’s try out all four. We know the commit <span class="caps">SHA</span> is b50788b, so we can work with that. First off, let’s <a href="http://www.kernel.org/pub/software/scm/git/docs/git-cherry-pick.html">cherry pick</a> the commit.</p>
<pre>
$ git cherry-pick b50788b
Finished one cherry-pick.
[master]: created bcb0d1b: "First pass at rake task."
3 files changed, 63 insertions(+), 3 deletions(-)
create mode 100644 lib/jekyll/task.rb
$ git log --pretty=oneline --abbrev-commit HEAD~3..HEAD
bcb0d1b... First pass at rake task.
2569e9f... update history
2135a53... Using block syntax of popen4 to ensure that subprocesses...
</pre>
<p>As you can see, it created a new commit, and the work has been brought in successfully. Both this method and the third method will produce a history like so, with the new commit on top:</p>
<p style="text-align:center;"><img src="/images/pick-cherry.png" alt="" /></p>
<p>Here’s how to wrap up the commit with <a href="http://www.kernel.org/pub/software/scm/git/docs/git-format-patch.html">format-patch</a> and apply it using <a href="http://www.kernel.org/pub/software/scm/git/docs/git-am.html">git am</a>.</p>
<pre>
$ git format-patch -1 b50788b
0001-First-pass-at-rake-task.patch
$ git am 0001-First-pass-at-rake-task.patch
Applying: First pass at rake task.
$ git log --pretty=oneline --abbrev-commit HEAD~3..HEAD
c05eaa1... First pass at rake task.
2569e9f... update history
2135a53... Using block syntax of popen4 to ensure that subprocesses...
</pre>
<p>This process is normally how projects accept patches over email, but this method works out quite nicely for this purpose as well. Of course, you could pipe <code>format-patch</code> and <code>am</code> into one command if you feel like it, and that will save you having to worry about the file left over.</p>
<p>Next, if we use <a href="http://www.kernel.org/pub/software/scm/git/docs/git-apply.html">git apply</a>, then we can get the changes live and work with them.</p>
<pre>
$ git format-patch -1 b50788b
0001-First-pass-at-rake-task.patch
$ git apply 0001-First-pass-at-rake-task.patch
0001-First-pass-at-rake-task.patch:59: trailing whitespace.
0001-First-pass-at-rake-task.patch:75: trailing whitespace.
private
warning: 2 lines add whitespace errors.
$ git status
# On branch master
# Changed but not updated:
# (use "git add <file>..." to update what will be committed)
# (use "git checkout -- <file>..." to discard changes in working directory)
#
# modified: jekyll.gemspec
# modified: lib/jekyll.rb
#
# Untracked files:
# (use "git add <file>..." to include in what will be committed)
#
# 0001-First-pass-at-rake-task.patch
# lib/jekyll/task.rb
no changes added to commit (use "git add" and/or "git commit -a")
</pre>
<p>Finally, we can simply merge the commit right in, which is quite simple in this case since there’s no conflicts.</p>
<pre>
$ git merge b50788b
Updating 2569e9f..b50788b
Fast forward
jekyll.gemspec | 6 ++--
lib/jekyll.rb | 2 +
lib/jekyll/task.rb | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 63 insertions(+), 3 deletions(-)
create mode 100644 lib/jekyll/task.rb
$ git log --pretty=oneline --graph --abbrev-commit
b50788b... First pass at rake task.
2569e9f... update history
2135a53... Using block syntax of popen4 to ensure that subprocesses...
</pre>
<p>Graphically, we can see that the commit has been brought into the mainline on the far left:</p>
<p style="text-align:center;"><img src="/images/pick-merge.png" alt="" /></p>
<p>As always, if you mess up you can go back one commit after you’ve applied a patch by using <code>git reset --hard HEAD^</code> or possibly even by <a href="http://gitready.com/beginner/2009/01/11/reverting-files.html">reverting files</a>. If things go really haywire you can always <a href="http://gitready.com/intermediate/2009/02/09/reflog-your-safety-net.html">check the reflog</a>. If you have other ways of dealing with this situation, let us know in the comments!</p>where to find the git community2009-03-02T00:00:00+00:00http://gitready.com/beginner/2009/03/02/where-to-find-the-git-community<p>For those just learning about Git, it migt be helpful to figure out where the community of users that use the tool daily hang out. Of course, there’s plenty of resources available online for those who want to learn about how to use it, but sometimes communicating with and participating in discussions is much more beneficial.</p>
<p>This post goes over some of the places where you can find others who are passionate about Git, and hopefully get questions you have answered. If you have a place that’s been left out, let us know in the comments!</p>
<p>1) The #git channel on <a href="http://freenode.net/">FreeNode</a>.</p>
<p>If you prefer real-time communication, <span class="caps">IRC</span> is the best way to get it. Just please be aware: those who help out in the channel are volunteers! Demanding information or simply trolling for help won’t get you very far. If you can, just hang out in the channel and watch the conversation fly by. You might learn something!</p>
<p>2) <a href="http://github.com">Github</a></p>
<p>This site is the hottest place to host open source projects along with your own private code. The benefit here is that you can see plenty of others who are using Git daily, and how they’re using it. There’s plenty of different models of using git that you can observe: everything from single developers working on hobby projects to actively developed projects with tens to hundreds of forks. If you don’t have an account yet, get signed up and check out what projects are active in the <a href="http://github.com/languages">languages</a> you like.</p>
<p>3) The <a href="http://vger.kernel.org/vger-lists.html#git">Git Mailing List</a></p>
<p>The official mailing list for Git developers is a ridiculously active and overall best way to get in touch with those who not only use Git daily, but have played major roles in creating it. If you’ve got a question, it most likely will get answered here. Just make sure to do your <a href="http://letmegooglethatforyou.com">homework</a> before you ask! Also, if you’re looking to contribute back to the Git project, this is where to start.</p>get a file from a specific revision2009-02-27T00:00:00+00:00http://gitready.com/intermediate/2009/02/27/get-a-file-from-a-specific-revision<p>If you know how Git stores data through <a href="http://gitready.com/beginner/2009/02/17/how-git-stores-your-data.html">blobs, trees, and commits</a> hopefully it should make sense why it’s a bit annoying to get a file from a specific revision out of your repository. What you want is inside of a blob from whichever commit, so simply saying I want to see this commit won’t cut it. Now, you could reset the working directory back to the commit you want to see then look at the file, but that’s lame.</p>
<p>Enter <code>git show</code>, which is an awesome tool for this job. This command is quite versatile and deserves several tips on what it can do, but let’s stick to the task at hand: we want to pull a file’s contents out from a specific revision. Usually the command would be done like so:</p>
<p><code>git show <treeish>:<file></code></p>
<p>So let’s say we want to go back four commits from our current <span class="caps">HEAD</span>, and we want the index.html file.</p>
<p><code>git show HEAD~4:index.html</code></p>
<p>You could of course pass any valid <a href="http://book.git-scm.com/4_git_treeishes.html">treeish</a> into the command. It will accept the actual SHA1 of the blob as well, but that’s pretty unlikely for most use cases. Probably the best use of this command is to see what the file looked like and perhaps write its contents out to a new file (or replace the old one!) if so desired.</p>
<p>Check out some of the other uses of this command at its <a href="http://www.kernel.org/pub/software/scm/git/docs/git-show.html">manpage</a>, and of course if you have other useful hints with it, let us know by <a href="/submit.html">submitting a tip!</a></p>keep either file in merge conflicts2009-02-25T00:00:00+00:00http://gitready.com/advanced/2009/02/25/keep-either-file-in-merge-conflicts<p>Sometimes when trying to resolve a merge, you may want to keep one file instead of the other. You don’t need to open up the files and fix the potentially hundreds of conflicts, you just want to choose the one you want and be done with it. Sadly, this isn’t exactly clear in older versions of Git, but more recent ones have made it easier. Big thanks to <a href="http://kevinold.com">Kevin Old</a> for <a href="http://www.kevinold.com/2009/02/24/better-git-conflict-resolution-between-binaries-with-theirs.html">his post on the subject</a> which reminded me about this issue.</p>
<p>So, the scenario is: you’re in the middle of a merge, and you want to keep one file or the other.</p>
<pre>
$ git merge master
Auto-merged _layouts/default.html
CONFLICT (content): Merge conflict in _layouts/default.html
Auto-merged index.html
CONFLICT (content): Merge conflict in index.html
Automatic merge failed; fix conflicts and then commit the result.
</pre>
<p>There’s two unmerged files here. According to the <a href="http://www.kernel.org/pub/software/scm/git/docs/git-checkout.html">git checkout</a> manpage, there’s a <code>--theirs</code> and <code>--ours</code> options on the command. The former will keep the version of the file that you merged in, and the other will keep the original one we had.</p>
<p>The following commands will keep the original file for index.html, and then use the merged in file only for _layouts/default.html.</p>
<pre>
git checkout --ours index.html
git checkout --theirs _layouts/default.html
</pre>
<p>Sadly, these options are only in Git versions 1.6.1 and up. If you have an older version and don’t feel like upgrading, there’s ways to get around this. To emulate <code>--theirs</code>, we’d do:</p>
<pre>
git reset -- _layouts/default.html
git checkout MERGE_HEAD -- _layouts/default.html
</pre>
<p>And for <code>--ours</code>:</p>
<pre>
git reset -- index.html
git checkout ORIG_HEAD -- index.html
</pre>
<p>Of course, once you’ve got the conflicts worked out, <code>git add</code> whatever changes need to be added in, and <code>git commit</code> away. If you’ve run into other problems with merging that could possibly help out others, comment away!</p>finding who committed what2009-02-23T00:00:00+00:00http://gitready.com/beginner/2009/02/23/finding-who-committed-what<p>Sometimes you may find it necessary to figure out just who committed that bug, or perhaps compliment a coworker on how efficiently an algorithm was implemented. Or maybe not, you just want to know who broke the build. Luckily, the <code>git blame</code> command can help with figuring out exactly who’s responsible for which line and what commit it came from.</p>
<p>The basic usage is simply <code>git blame <file></code>. The console output usually looks like so (check out the full image!):</p>
<p style="text-align:center;"><a href="http://farm4.static.flickr.com/3606/3304779985_2d1842b5f9_o.png"><img src="http://farm4.static.flickr.com/3606/3304779985_6c93865703.jpg" alt="" /></a></p>
<p>For those confused at what this wall of text consists of, it shows the abbreviated commit <span class="caps">SHA</span>, the file name it originated from, the commit author and date, line number, and then the actual line of code.</p>
<p>That’s great and all, but there’s plenty of other ways to get your blame on. If your code is up on GitHub, you get blame information included:</p>
<p style="text-align:center;"><a href="http://farm4.static.flickr.com/3463/3305616220_a7b2850e62_o.jpg"><img src="http://farm4.static.flickr.com/3463/3305616220_05a91c8e70.jpg" alt="" /></a></p>
<p>Another great way to see this information is with <a href="http://wiki.github.com/krig/git-age">git-age</a>, which is a viewer written in PyGtk. It’s actually quite neat, it shows the Gravatar associated with the commit’s email, and shows older commits with a darker gray background.</p>
<p style="text-align:center;"><a href="http://farm4.static.flickr.com/3454/3305608128_94edf84e1b_o.png"><img src="http://farm4.static.flickr.com/3454/3305608128_7000ca6fa2.jpg" alt="" /></a></p>
<p>If you know of any other tricks that this command can do or other useful viewers, let us know in the comments!</p>what git is not2009-02-19T00:00:00+00:00http://gitready.com/beginner/2009/02/19/what-git-is-not<p>There are obviously many reasons why Git is awesome (and why it sucks too), and there comes a point where it helps to dispel some of the rumors and issues surrounding Git. The following list attempts to show what Git <strong>is not</strong>. If you have your own reasons, feel free to contribute them to the comments and they may be added in.</p>
<h3>1. Git is not Subversion with some added sugar sprinkled in.</h3>
<p>Git works a lot differently than <span class="caps">SVN</span> and <span class="caps">CVS</span>. Probably the biggest difference is that Git stores content primarily, and it works mostly by taking snapshots of the information available. (This is why Git is commonly referred to as a ‘dumb information tracker’). Its algorithm for storing changes is fundamentally different from Subversion, and it much more efficient at doing so.</p>
<p>Also, if you’re used to having all of your projects in one huge repository, Git doesn’t really work like that either. Repositories are meant mostly for single projects, and then you could use <a href="http://book.git-scm.com/5_submodules.html">submodules</a> that link to other repos if needed. A tip covering how to deal with this situation will definitely be coming in the future.</p>
<p>The differences between Git and <span class="caps">SVN</span> could be in their own series of tips, but the <a href="http://git.or.cz/course/svn.html">Git-<span class="caps">SVN</span> Crash Course</a> does a great job for those considering making the switch with drawing parallels.</p>
<h3>2. Git is not expensive network or space wise.</h3>
<p>Local commits are a huge advantage to using Git, and it means that your workflow can be made a lot smoother since it’s not talking over the network to a central server for most actions. If you want to know more about how this works, check out <a href="http://gitready.com/beginner/2009/01/18/the-staging-area.html">this post on the staging area</a> or <a href="http://gitready.com/beginner/2009/01/21/pushing-and-pulling.html">this one on pushing and pulling</a>.</p>
<p>Another awesome advantage is that there’s <strong>one</strong> place where git stores its files for your repository (usually the <code>.git</code> directory) and it doesn’t litter your working copy with thousands of hidden directories and files like <span class="caps">SVN</span> does.</p>
<h3>3. Git is not just for Linux kernel hackers or those who fly on airplanes all day to conferences.</h3>
<p>Git can be <a href="http://gitready.com/beginner/2009/01/27/installing-git.html">installed</a> on virtually every modern operating system, and it definitely works on Windows. <span class="caps">GUI</span> support isn’t there 100% on Windows, but plenty of work is being done on integrating into Explorer and to the various IDEs available. There’s plenty of slick tools available on other operating systems such as <a href="http://gitx.frim.nl/">GitX</a> on <span class="caps">OSX</span>.</p>
<h3>4. Git is not hard to set up.</h3>
<p>Setting up a Git repository is as simple as doing <code>git init</code> in any directory. It can’t get much simpler for that. Sharing your changes with others is when things get a bit more interesting. Usually <a href="http://gitready.com/intermediate/2009/01/24/sharing-your-changes.html">sharing your changes</a> is one or two commands away. Hosting your changes somewhere the right way can be a little tricky though: usually for self setup the best way to go is using <a href="http://scie.nti.st/2007/11/14/hosting-git-repositories-the-easy-and-secure-way">gitosis</a>, which is an tool that helps with getting <span class="caps">SSH</span> keys for users set up for commit access.</p>
<p>Update 26-Oct-2011: Note that the last commit of gitosis is from <a href="http://eagain.net/gitweb/?p=gitosis.git">2009</a>. <a href="https://github.com/sitaramc/gitolite/">Gitolite</a> nowadays seems to be better supported.</p>
<h3>5. Git is not hard to learn.</h3>
<p>Git’s <a href="http://www.kernel.org/pub/software/scm/git/docs/user-manual.html">manpages</a> are quite extensive (and verbose), but there are plenty of other guides available for learning online. Some of the best are listed in the resources section in this site’s footer! For those new to Git, I usually recommend the <a href="http://book.git-scm.com/">Git Community Book</a> and running through some of the <a href="http://gitcasts.com">GitCasts</a> videos. (Reading this site counts too!)</p>
<h3>6. Git is not complex.</h3>
<p>Yes, there’s a lot of alien terminology and some concepts that aren’t instantly familiar to every newcomer, but the underlying concepts that the system is based on are fundamentally and purposefully simple. One great example is the <a href="http://gitready.com/beginner/2009/02/17/how-git-stores-your-data.html">blob-tree-commit structure</a>. Once the basic concepts behind Git are grasped, it’s really easy to make the tool work the way you want it instead of letting it force you into a specific workflow. Sure, too much flexibility could be a bad thing, but when it offers so much power and ease of use, why not?</p>temporarily ignoring files2009-02-18T00:00:00+00:00http://gitready.com/intermediate/2009/02/18/temporarily-ignoring-files<p>Usually <a href="http://gitready.com/beginner/2009/01/19/ignoring-files.html">ignoring files</a> is quite simple with Git. However, you may need to quickly hide changes in a file, perhaps for an entire development session or other reasons. Luckily there’s a simple way around this, thanks to some clever manual diving from <a href="http://www.pagebakers.nl/2009/01/29/git-ignoring-changes-in-tracked-files/">Eelco Wiersma</a>.</p>
<p>His main problem was using <code>git commit -a</code>, which automatically adds files that are modified into the commit object. This is a neat shortcut, but make sure you <a href="http://gitready.com/beginner/2009/01/18/the-staging-area.html">understand the staging area</a> if you find yourself running this command all the time.</p>
<p>So, to temporarily ignore changes in a certain file, run:</p>
<p><code>git update-index --assume-unchanged <file></code></p>
<p>Then when you want to track changes again:</p>
<p><code>git update-index --no-assume-unchanged <file></code></p>
<p>Obviously there’s quite a few caveats that come into play with this. If you <code>git add</code> the file directly, it will be added to the index. Merging a commit with this flag on will cause the merge to fail gracefully so you can handle it manually.</p>
<p>Let’s go over a quick example of using the command. Changes have been made to a few files in my working directory:</p>
<pre>
$ git status
# On branch master
#
# Changed but not updated:
# (use "git add <file>..." to update what will be committed)
#
# modified: README.textile
# modified: Rakefile
# modified: TODO
#
no changes added to commit (use "git add" and/or "git commit -a")
</pre>
<p>If I ran <code>git commit -a</code> from here, all of the files would be added into the new commit. However, I want to temporarily ignore the changes in one of the files:</p>
<pre>
$ git update-index --assume-unchanged README.textile
$ git status
# On branch master
#
# Changed but not updated:
# (use "git add <file>..." to update what will be committed)
#
# modified: Rakefile
# modified: TODO
#
no changes added to commit (use "git add" and/or "git commit -a")
</pre>
<p>So if we commit the work now then turn the flag off, we can see that Git didn’t lose the original changes to the <span class="caps">README</span>. From there, you could now add them into a new commit, or <a href="http://gitready.com/beginner/2009/01/11/reverting-files.html">revert back to the latest copy</a>.</p>
<pre>
$ git update-index --no-assume-unchanged README.textile
$ git status
# On branch master
# Your branch is ahead of 'origin/master' by 4 commits.
#
# Changed but not updated:
# (use "git add <file>..." to update what will be committed)
#
# modified: README.textile
#
no changes added to commit (use "git add" and/or "git commit -a")
</pre>
<p>Check out the man page for <code>git update-index</code> <a href="http://www.kernel.org/pub/software/scm/git/docs/git-update-index.html">here</a>. If you know of other clever tricks with the index, leave a comment or <a href="/submit.html">submit a tip!</a></p>how git stores your data2009-02-17T00:00:00+00:00http://gitready.com/beginner/2009/02/17/how-git-stores-your-data<p>This is an extremely broad overview on how the Git object model works, based mostly on the <a href="http://book.git-scm.com/1_the_git_object_model.html">Git Community Book</a>. Future posts will definitely look into the object model in more depth, but this information is definitely essential to those who are learning Git. The images from this post were taken from my presentation on <a href="http://litanyagainstfear.com/blog/2008/12/05/open-source-collaboration-with-git-and-github/">Open Source Collaboration with Git and GitHub.</a></p>
<p>The most basic data storage is the blob. Git stores <strong>just</strong> the contents of the file for tracking history, and not just the differences between individual files for each change. The contents are then referenced by a 40 character <a href="http://en.wikipedia.org/wiki/SHA1">SHA1 hash</a> of the contents, which means it’s pretty much guaranteed to be unique. Pretty much every object, be it a commit, tree, or blob has a <span class="caps">SHA</span>, so learn to love them. Luckily, they’re easily referenced by the first 7 characters which are usually enough to identify the whole string.</p>
<p>One awesome advantage to storing only the content means that if you have two or more copies of the same file in your repository, Git will only store one copy internally. A blob can be represented like so:</p>
<p style="text-align:center;"><img src="/images/object1.png" alt="" /></p>
<p>The next object is a tree. These can be thought of as folders or directories: they contain other blobs and trees.</p>
<p style="text-align:center;"><img src="/images/object2.png" alt="" /></p>
<p>Finally, this brings us to the most important object: the commit. Commits can be thought of as snapshots: they know what the trees looked like at one point in time. They also have some other information associated with them, such as the author, date, and a message.</p>
<p style="text-align:center;"><img src="/images/object3.png" alt="" /></p>
<p>Commits are organized in a <a href="http://en.wikipedia.org/wiki/Directed_acyclic_graph">Directed Acyclic Graph</a>. For those who missed that lecture in Data Structures about it, basically it means that the commits “flow” in one direction. Usually this direction is simply the path of history for your repository, which could be very simple or quite complex if you have branches. From a broad standpoint it will look something like this:</p>
<p style="text-align:center;"><img src="/images/object4.png" alt="" /></p>
<p>This all becomes much more apparent when using a tool like <a href="http://gitready.com/intermediate/2009/01/13/visualizing-your-repo.html">GitX</a>. You can clearly see the commit objects and their associated data, and then drill down from there to see the commit’s tree.</p>
<p style="text-align:center;"><img src="/images/object5.png" alt="" /></p>
<p>So now hopefully when you see some of the strange terminology in your commits, you’ll understand a little more of how it works. Check out the awesome guide at <a href="http://eagain.net/articles/git-for-computer-scientists/">Git for Computer Scientists</a> and <a href="http://jointheconversation.org">Scott Chacon’s</a> talk on <a href="http://gitcasts.com/git-talk">Getting Git</a>.</p>convert git-svn tag branches to real tags2009-02-16T00:00:00+00:00http://gitready.com/advanced/2009/02/16/convert-git-svn-tag-branches-to-real-tags<p>This tip has been generously donated from <a href="http://beardedmagnum.com">Alexis Midon</a>. Thanks! His original post is <a href="http://beardedmagnum.com/2009/02/15/converting-git-svn-tag-branches-to-real-tags/">here</a>.</p>
<p>Alexis found out that in the process of converting from Subversion to Git, tags get a bit confused and show up as branches instead once converted over. This can be pretty inconvenient, especially when using <code>git branch</code> since a ton of branches would show up such as <code>tag/1.2</code>, and so on. A little bit of scripting and Git magic can clear this up easily.</p>
<p>He followed the standard process for converting a svn repo:</p>
<pre>
$ mkdir rails
$ cd rails
$ git svn init -t tags -b branches -T trunk <path to svn repo>
Initialized empty Git repository in .git/
$ git svn fetch
</pre>
<p>Next he whipped up a little script to convert all of the tag branches into <a href="http://gitready.com/beginner/2009/02/03/tagging.html">actual tags</a>, and then make sure they’re deleted properly.</p>
<pre>
$ git-for-each-ref refs/remotes/origin/tags | cut -d / -f 5- |
while read ref
do
git tag -a "$ref" -m"say farewell to SVN" "refs/remotes/origin/tags/$ref"
git push origin ":refs/heads/tags/$ref"
git push origin tag "$ref"
done
</pre>
<p>If you’ve created scripts that help with converting over to Git from any other <span class="caps">SCM</span>, let us know in the comments or <a href="http://gitready.com/submit.html">submit your own tip!</a></p>list remote branches2009-02-13T00:00:00+00:00http://gitready.com/intermediate/2009/02/13/list-remote-branches<p>Sometimes you may need to figure out what <a href="http://gitready.com/beginner/2009/01/25/branching-and-merging.html">branches</a> exist on a remote repository so you can pull them down and check them out, merge them into your local branches, etc. If you’re using <a href="http://github.com">GitHub</a> or <a href="http://git.or.cz/gitwiki/Gitweb">gitweb</a> to host your repository it’s usually easy to determine the branch names, but if you need to get them in general or for scripts it’s not exactly clear.</p>
<p style="text-align:center;"><a href="http://flickr.com/photos/joiseyshowaa/3100342708/"><img src="http://farm4.static.flickr.com/3163/3100342708_b12c4a36d6.jpg" alt="" /></a></p>
<p><strong><span class="caps">UPDATE</span>:</strong> The comments have enlightened me quite a bit…there seems to always be more than one way to skin a cat using Git. The easiest way is just to use the <code>git branch</code> commands’ various options. <code>-a</code> shows all local and remote branches, while <code>-r</code> shows only remote branches.</p>
<pre>
$ git branch
* master
$ git branch -a
* master
origin/1-2-stable
origin/2-0-stable
origin/2-1-stable
origin/2-2-stable
origin/3-0-unstable
origin/HEAD
origin/master
$ git branch -r
origin/1-2-stable
origin/2-0-stable
origin/2-1-stable
origin/2-2-stable
origin/3-0-unstable
origin/HEAD
origin/master
</pre>
<p>So, once you know the name of the branch it’s quite simple to <a href="http://gitready.com/intermediate/2009/01/09/checkout-remote-tracked-branch.html">check them out.</a> If you have color options on it’s also quite easy to tell which branches aren’t pulled down since they’re listed in red.</p>
<p>There’s also another way to do figure out what branches are on your remote by actually using the remote related commands, <code>git remote</code> and <code>git ls-remote</code>. The former displays plenty of information about the remote in general and how it relates to your own repository, while the latter simply lists all references to branches and tags that it knows about.</p>
<pre>
$ git remote show origin
* remote origin
URL: git://github.com/rails/rails.git
Remote branch merged with 'git pull' while on branch master
master
Tracked remote branches
1-2-stable 2-0-stable 2-1-stable 2-2-stable 3-0-unstable master
$ git ls-remote --heads origin
5b3f7563ae1b4a7160fda7fe34240d40c5777dcd refs/heads/1-2-stable
71926912a127da29530520d435c83c48778ac2b2 refs/heads/2-0-stable
2b158543247a150e8ec568becf360e7376f8ab84 refs/heads/2-1-stable
b0792a3e7be88e3060af19bab01cd3d26d347e4c refs/heads/2-2-stable
d6b9f8410c990b3d68d1970f1461a1d385d098d7 refs/heads/3-0-unstable
f04346d8b999476113d5e5a30661e07899e3ff80 refs/heads/master
</pre>
<p>The <code>ls-remote</code> command returns the SHA1 hash of the latest commit for that reference, so it is quite easy to parse out and get to the exact commit you need if you’re doing some scripting. The <code>--heads</code> option lists only branch names since the command can list tags too.</p>
<p>If you have any other uses for these commands or an easier way to figure out branches that live on a remote, comment away!</p>easily fetching upstream changes2009-02-12T00:00:00+00:00http://gitready.com/intermediate/2009/02/12/easily-fetching-upstream-changes<p>This tip comes from <a href="http://blog.davglass.com/">Dav Glass</a>, whose work on <a href="http://developer.yahoo.com/yui/"><span class="caps">YUI</span></a> at <a href="http://github.com/yui">GitHub</a> requires him to bring in commits frequently. So, he’s created a <a href="http://gitready.com/intermediate/2009/02/06/helpful-command-aliases.html">helpful alias</a> so he can merge in changes easily.</p>
<p>First off, he’s got a consistent naming scheme for his upstream remote:</p>
<p><code>git remote add upstream git://github.com/user/repo.git</code></p>
<p>Just throw this in your <code>.gitconfig</code> and you’re all set:</p>
<pre>
[alias]
pu = !"git fetch origin -v; git fetch upstream -v; git merge upstream/master"
</pre>
<p>Now <code>git pu</code> will grab all of the latest changes from both remotes, and then merge in the commits from upstream.</p>
<p>How is this different from just doing a <code>git pull upstream master</code>? This brings in changes from two different sources: his own fork and the main repository (the upstream). Doing a <a href="http://gitready.com/beginner/2009/01/21/pushing-and-pulling.html">pull</a> usually only brings changes in from one source. If you’re confused about how this works, check out the History section of <a href="http://eagain.net/articles/git-for-computer-scientists/#history">Git for Computer Scientists</a> for some graphs on how the fetching and merging process works.</p>
<p>Of course, there’s plenty of different ways you could tackle this problem. For example, you could use <a href="http://gitready.com/intermediate/2009/01/31/intro-to-rebase.html">rebase</a> or even <a href="http://gitready.com/advanced/2009/02/11/pull-with-rebase.html">pull with rebase</a> instead of merging. It all depends on how you want to organize your repository’s history, and what’s easiest for you.</p>
<p>If you have aliases or suggestions to make this process easier, let us know!</p>pull with rebase2009-02-11T00:00:00+00:00http://gitready.com/advanced/2009/02/11/pull-with-rebase<p>Users of Git are hopefully aware that a <code>git pull</code> does a <code>git fetch</code> to pull down data from the specified remote, and then calls <code>git merge</code> to join the changes received with your current branch’s work. However, that may not always be the best case. You can also <a href="http://gitready.com/intermediate/2009/01/31/intro-to-rebase.html">rebase</a> the changes in, and that may end up being a lot cleaner. This can be done simply by tacking on the <code>--rebase</code> option when you pull, like so:</p>
<p><code>git pull --rebase <remote name> <branch name></code></p>
<p>So, why is this useful? Sometimes it’s easier not to merge in the upstream content and it’s better just to reapply your work on top of the incoming changes. For long term changes, it is probably best to merge, but for smaller changesets history will stay cleaner with rebase. So let’s say I wanted to use rebase instead of merging to bring in upstream changes from the main <a href="http://github.com/mojombo/jekyll">jekyll</a> repository into my <a href="http://github.com/qrush/jekyll">fork</a>. So the repository looks like this right now:</p>
<p style="text-align:center;"><img src="/images/pull1.png" alt="" /></p>
<p>Just for demonstration purposes, I’ve got mojombo’s master checked out so you can see that there’s a few new commits that my master branch doesn’t have: (The three commits starting at ‘mojombo’ and going down to ‘mojombo/master’ aren’t in the above graph)</p>
<p style="text-align:center;"><img src="/images/pull2.png" alt="" /></p>
<p>So, let’s bring in the changes using rebase from the remote for mojombo’s repository at his master branch: (warnings removed)</p>
<pre>
$ git pull --rebase mojombo master
From git://github.com/mojombo/jekyll
* branch master -> FETCH_HEAD
First, rewinding head to replay your work on top of it...
Applying: Making rake test happy on 1.8.7
Applying: Starting on yaml categories
Applying: Adding support for setting post categories...
Applying: Added publish flag to posts, not preventing...
Applying: Making sure that posts flagged as published...
Applying: Adding explanations for new YAML front matter...
Applying: Removing some bad formatting in the README
</pre>
<p>Now if we look at the master branch’s history again:</p>
<p style="text-align:center;"><img src="/images/pull3.png" alt="" /></p>
<p>You can see that my work (everything from the ‘mojombo’ label up) has been rebased on top of the work already in mojombo’s repository. Great! So what’s the difference between this and a normal pull? Let’s find out.</p>
<pre>
$ git reset --hard origin/master
HEAD is now at 60709da Removing some bad formatting in the README
$ git pull mojombo master
From git://github.com/mojombo/jekyll
* branch master -> FETCH_HEAD
Merge made by recursive.
VERSION.yml | 2 +-
jekyll.gemspec | 7 ++++---
2 files changed, 5 insertions(+), 4 deletions(-)
</pre>
<p>So first I brought the repository back to where my original state was, then just did a normal pull. Since it’s a merge, it appears as such:</p>
<p style="text-align:center;"><img src="/images/pull4.png" alt="" /></p>
<p>Now you can see the upstream changes were brought in, and a new commit was made to denote that the merge happened. Sometimes you may want to delineate history like that, but not always. It’s really up to you and how you want to build your history. A related note: if you’d like to always use rebase instead of merging when doing <code>git pull</code>, check out this <a href="http://tumbl.strelau.net/post/47338904/git-pull-rebase-by-default">awesome tip</a> on how to set your configuration options to do so.</p>squashing commits with rebase2009-02-10T00:00:00+00:00http://gitready.com/advanced/2009/02/10/squashing-commits-with-rebase<p>The <a href="http://gitready.com/intermediate/2009/01/31/intro-to-rebase.html">rebase</a> command has some awesome options available in its <code>--interactive</code> (or <code>-i</code>) mode, and one of the most widely used is the ability to squash commits. What this does is take smaller commits and combine them into larger ones, which could be useful if you’re wrapping up the day’s work or if you just want to package your changes differently. We’re going to go over how you can do this easily.</p>
<p><strong>A word of caution:</strong> Only do this on commits that haven’t been pushed an external repository. If others have based work off of the commits that you’re going to delete, plenty of conflicts can occur. Just don’t rewrite your history if it’s been shared with others.</p>
<p>So let’s say you’ve just made a few small commits, and you want to make one larger commit out of them. Our repository’s history currently looks like this:</p>
<p style="text-align:center;"><img src="/images/squash1.png" alt="" /></p>
<p>The last 4 commits would be much happier if they were wrapped up together, so let’s do just that through interactive rebasing:</p>
<pre>
$ git rebase -i HEAD~4
pick 01d1124 Adding license
pick 6340aaa Moving license into its own file
pick ebfd367 Jekyll has become self-aware.
pick 30e0ccb Changed the tagline in the binary, too.
# Rebase 60709da..30e0ccb onto 60709da
#
# Commands:
# p, pick = use commit
# e, edit = use commit, but stop for amending
# s, squash = use commit, but meld into previous commit
#
# If you remove a line here THAT COMMIT WILL BE LOST.
# However, if you remove everything, the rebase will be aborted.
#
</pre>
<p>So, a few things have happened here. First of all, I told Git that I wanted to rebase using the last four commits from where the <code>HEAD</code> is with <code>HEAD~4</code>. Git has now put me into an editor with the above text in it, and a little explanation of what can be done. You have plenty of options available to you from this screen, but right now we’re just going to squash everything into one commit. So, changing the first four lines of the file to this will do the trick:</p>
<pre>
pick 01d1124 Adding license
squash 6340aaa Moving license into its own file
squash ebfd367 Jekyll has become self-aware.
squash 30e0ccb Changed the tagline in the binary, too.
</pre>
<p>Basically this tells Git to combine all four commits into the the first commit in the list. Once this is done and saved, another editor pops up with the following:</p>
<pre>
# This is a combination of 4 commits.
# The first commit's message is:
Adding license
# This is the 2nd commit message:
Moving license into its own file
# This is the 3rd commit message:
Jekyll has become self-aware.
# This is the 4th commit message:
Changed the tagline in the binary, too.
# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
# Explicit paths specified without -i nor -o; assuming --only paths...
# Not currently on any branch.
# Changes to be committed:
# (use "git reset HEAD <file>..." to unstage)
#
# new file: LICENSE
# modified: README.textile
# modified: Rakefile
# modified: bin/jekyll
#
</pre>
<p>Since we’re combining so many commits, Git allows you to modify the new commit’s message based on the rest of the commits involved in the process. Edit the message as you see fit, then save and quit. Once that’s done, your commits have been successfully squashed!</p>
<pre>
Created commit 0fc4eea: Creating license file, and making jekyll self-aware.
4 files changed, 27 insertions(+), 30 deletions(-)
create mode 100644 LICENSE
Successfully rebased and updated refs/heads/master.
</pre>
<p>And if we look at the history again…</p>
<p style="text-align:center;"><img src="/images/squash2.png" alt="" /></p>
<p>So, this has been a relatively painless so far. If you run into conflicts during the rebase, they’re usually quite easy to resolve and Git leads you through as much as possible. The basics of this is fix the conflict in question, <code>git add</code> the file, and then <code>git rebase --continue</code> will resume the process. Of course, doing a <code>git rebase --abort</code> will bring you back to your previous state if you want. If for some reason you’ve lost a commit in the rebase, you can use the <a href="http://gitready.com/intermediate/2009/02/09/reflog-your-safety-net.html">reflog</a> to get it back.</p>
<p>There’s plenty of other uses for <code>git rebase -i</code> that haven’t been covered yet. If you have one you’d like to share, <a href="/submit.html">please do so!</a> <a href="http://gitcasts.com">GitCasts</a> also has a <a href="http://gitcasts.com/posts/rebasing">fantastic video</a> on this process as a whole that also covers some more complex examples of the command.</p>reflog, your safety net2009-02-09T00:00:00+00:00http://gitready.com/intermediate/2009/02/09/reflog-your-safety-net<p>We’ve covered the <a href="http://www.kernel.org/pub/software/scm/git/docs/git-reflog.html">reflog</a> command briefly in a previous article on how to <a href="http://gitready.com/advanced/2009/01/17/restoring-lost-commits.html">restore lost commits</a> but it was never fully explained. Today we’ll look into what it does and how you can use it as a safety net to recover your work.</p>
<p style="text-align:center;"><a href="http://flickr.com/photos/paradisecircus/3222479388/"><img src="http://farm4.static.flickr.com/3462/3222479388_abcb084c1a.jpg?v=0" alt="" /></a></p>
<p>Once again the man pages are pretty terse about what this command actually does:</p>
<blockquote>
<p>git-reflog – Manage reflog information</p>
</blockquote>
<p>This definition is a little better, from later in the document:</p>
<blockquote>
<p>Reflog is a mechanism to record when the tip of branches are updated. This command is to manage the information recorded in it.</p>
</blockquote>
<p>Basically every action you perform inside of Git where data is stored, you can find it inside of the reflog. Git tries really hard not to lose your data, so if for some reason you think it has, chances are you can dig it out using <code>git reflog</code>. What this means is that you can use it as a safety net: you shouldn’t be worried that a merge, rebase, or some other action will destroy your work since you can find it again using this command.</p>
<p>The most common usage of this command is that you’ve just done a <code>git reset</code> and moved your <code>HEAD</code> back a few commits. But oops, you need that bit of code you left in the second commit. Crap. Now what? Running <code>git reflog</code> will probably result in something like this:</p>
<p style="text-align:center;"><img src="/images/reflog.png" alt="" /></p>
<p>What this shows is a list of commits that Git still has in its storage. The first 7 characters are the beginning of the commit’s SHA1 hash, followed by the commit’s pointer, action, and message. You can see that not just commits are listed: switching branches, merges, rebases, and more are shown. The important part is the commit pointer and the SHA1: once you have that, you can do a <code>git show</code> to see the diff, or perhaps a <code>checkout</code>, <code>cherry-pick</code>, or <code>merge</code> depending on how you want to get the change back into your history.</p>
<p>You can also use the <code>--all</code> option to get more detailed information about different branches and even the stash:</p>
<p style="text-align:center;"><img src="/images/reflog-all.png" alt="" /></p>
<p>This command is also used for another purpose: deleting old entries that you won’t need anymore. This may be done to conserve space in your repository, or perhaps since you want to take out the garbage every once in a while. You could knock off individual reflogs using the <code>delete</code> subcommand, but the <code>expire</code> subcommand is much more useful since it can be given a date to remove entries from.</p>
<p>An example of using this command to quickly pack up your repository can be found on <a href="http://www.newartisans.com/blog/">John Wiegley’s</a> post on <a href="http://www.newartisans.com/blog/2008/04/diving-into-git.html">Diving into Git</a>, where he compresses his repository with the following commands:</p>
<pre>
$ git reflog expire --expire=1.minute refs/heads/master
$ git fsck --unreachable
$ git prune
$ git gc
</pre>
<p>Basically this removes all reflogs that are older than a minute for the master branch, finds and deletes any commits that aren’t being used, then does some general cleanup on the whole repository to further compress it. This could have had its own tip, but it’s probably better to illustrate a great use of the subject’s subcommands in your workflow.</p>
<p>As always, check out the <a href="http://www.kernel.org/pub/software/scm/git/docs/git-reflog.html">manpage</a> for the other options, and if you have other uses for this command let us know!</p>helpful command aliases2009-02-06T00:00:00+00:00http://gitready.com/intermediate/2009/02/06/helpful-command-aliases<p>A great way to make your life using Git easier is to add aliases for commands that you use all the time into your <code>.gitconfig</code> file. It might not be as elegant as adding shortcuts to your shell, but at least this will work consistently across all shells and is a breeze to set up. The <a href="http://cheat.errtheblog.com/s/git">Git Cheat Sheet</a> suggests adding this block to your config file:</p>
<pre>
[alias]
st = status
ci = commit
br = branch
co = checkout
df = diff
lg = log -p
</pre>
<p>Once you’ve got this block added to your config file, it should work immediately:</p>
<pre>
$ git st
# On branch master
# Untracked files:
# (use "git add <file>..." to include in what will be committed)
#
# _posts/2009-02-06-helpful-command-aliases.textile
nothing added to commit but untracked files present (use "git add" to track)
</pre>
<p>You can also add aliases like so, and they will get added to your <code>.gitconfig</code> file automatically.</p>
<pre>
$ git config --global alias.rb rebase
</pre>
<p>For the <span class="caps">SVN</span> converts, Alex Soto has suggested a few alias helpers that will help with interacting with Subversion repositories:</p>
<pre>
[alias]
spull = !git-svn fetch && git-svn rebase
spush = !git-svn dcommit
</pre>
<p>There’s also plenty of other advanced commands at the <a href="http://git.or.cz/gitwiki/Aliases">GitWiki</a>. If you’ve got an alias that others could find useful, comment or <a href="/submit.html">submit</a> away and it will be added!</p>bash auto completion2009-02-05T00:00:00+00:00http://gitready.com/advanced/2009/02/05/bash-auto-completion<p>This tip comes from the ever resourceful <a href="http://cardarella.blogspot.com/">Brian Cardarella</a>, who has a gist on <a href="http://gist.github.com/58383">how to install and set up auto completion</a> with Git. It’s based off of <a href="http://spearce.org">Shawn O. Pierce’s</a> bash completion script. Just what will it do for you?</p>
<blockquote>
<p>The contained completion routines provide support for completing:</p>
<ul>
<li>local and remote branch names</li>
<li>local and remote tag names</li>
<li>.git/remotes file names</li>
<li>git ‘subcommands’</li>
<li>tree paths within ‘ref:path/to/file’ expressions</li>
<li>common —long-options<br />
</blockquote></li>
</ul>
<p>Installation is really easy: just download/wget/curl the files and put them in your home directory, edit your <code>.bash_profile</code> and you’re set. <a href="http://blog.ericgoodwin.com/">Eric Goodwin</a> also has a great writeup of <a href="http://blog.ericgoodwin.com/2008/4/10/auto-completion-with-git">how to pull the script down and install it</a> if you haven’t compiled git from source. He also has found a <a href="http://blog.infinitered.com/entries/show/4">fantastic article</a> on bash’s various startup files if this is all new to you.</p>
<p>For <span class="caps">OSX</span> users, you can also use MacPorts to install the script. <a href="http://m.onkey.org/2008/4/12/if-you-see-this">Pratik Naik</a> has a really easy way of installing it if you used the <code>+bash_completion</code> option. If not, it’s probably easier to just deactivate your current version and reinstall it with that option added.</p>
<p>If you know how to accompish this in other shells, comment away or <a href="/submit.html">submit a tip!</a></p>converting from svn2009-02-04T00:00:00+00:00http://gitready.com/beginner/2009/02/04/converting-from-svn<p>You’re probably reading this for one of a few reasons:</p>
<ul>
<li>You’re a longtime <span class="caps">SVN</span> user and want to see what Git is all about</li>
<li>You want to know how much of a pain switching to Git is</li>
<li>You hate <span class="caps">SVN</span> and want to see what’s better</li>
</ul>
<p>Instead of contributing to the mass of tutorials already written about the subject, I figured I would take the <s>easy</s> useful way out and compose a list of great tutorials on how to accomplish a migration to Git for those who are familiar with <span class="caps">SVN</span>. If you have more links, please comment away and I’ll add them in.</p>
<p><strong>Transition Tutorials</strong><br />
<em>These tutorials describe just how different the two version control systems are and go over how they work on a (mostly) high level.</em></p>
<ul>
<li><a href="http://andy.delcambre.com/2008/03/04/git-svn-workflow.html">Git <span class="caps">SVN</span> Workflow</a></li>
<li><a href="http://git.or.cz/gitwiki/GitSvnComparsion">GitSvnComparsion</a></li>
<li><a href="http://utsl.gen.nz/talks/git-svn/intro.html">An introduction to git-svn for Subversion/<span class="caps">SVK</span> users and deserters</a></li>
</ul>
<p><strong>Command Tutorials</strong><br />
<em>These tutorials focus on learning commands that perform common actions between the two systems.</em></p>
<ul>
<li><a href="http://git.or.cz/course/svn.html">Git – <span class="caps">SVN</span> Crash Course</a></li>
<li><a href="http://flavio.castelli.name/howto_use_git_with_svn">Howto use Git and svn together</a></li>
<li><a href="http://michael-prokop.at/blog/2007/12/03/git-svn-in-30-minutes/">git[-svn] in 30 minutes</a></li>
</ul>
<p><strong>Migration Tutorials</strong><br />
<em>These tutorials elaborate on how you can import your history from <span class="caps">SVN</span> and how to work with others who may not be converted yet.</em></p>
<ul>
<li><a href="http://weblog.redlinesoftware.com/2008/2/24/converting-subversion-repositories-to-git">Converting Subversion repositories to Git</a></li>
<li><a href="http://notahat.com/posts/25">Converting a Shared Subversion Repository to Git</a></li>
<li><a href="http://pauldowman.com/2008/07/26/how-to-convert-from-subversion-to-git/">How to convert from Subversion to Git</a></li>
<li><a href="http://www.robbyonrails.com/articles/2008/04/10/git-svn-is-a-gateway-drug">git-svn is a gateway drug</a></li>
</ul>
<p>Tips related to git-svn are still more than welcome, be it configuration options, bugs/issues you ran into, etc. <a href="/submit.html">Submit away</a> if you have great ideas!</p>tagging2009-02-03T00:00:00+00:00http://gitready.com/beginner/2009/02/03/tagging<p>Tagging in Git is a great way to denote specific release versions of your code, or perhaps if you need a way to refer to exactly one commit in your history for some reason. This post is going to over the right (and wrong) ways to use <code>git tag</code>.</p>
<p>Probably the best way to describe a tag is a post-it note that refers to one commit. It contains a name, so something like <code>v1.0.0</code> or <code>production</code>, and a message too if you want. <a href="http://eagain.net/articles/git-for-computer-scientists/">Git for Computer Scientists</a> visualizes a tag like so:</p>
<p style="text-align:center;"><img src="http://eagain.net/_images/git-storage.6.png" alt="" /></p>
<p>So, how does one create a tag? Just <code>git tag v1.0.0</code> right? <span class="caps">WRONG</span>. You <strong>usually</strong> don’t want to do that. In fact, some suggest that this command <a href="http://www.rockstarprogrammer.org/post/2008/oct/16/git-tag-does-wrong-thing-default/">does the wrong thing by default</a>. Without arguments, <code>git tag</code> creates a “lightweight” tag that is <a href="http://book.git-scm.com/3_git_tag.html">basically a branch that never moves</a>. Lightweight tags are still useful though, perhaps for marking a known good (or bad) version, or a bunch of commits you may need to use in the future. Nevertheless, you probably don’t want to push these kinds of tags.</p>
<p>Normally, you want to at least pass the <code>-a</code> option to create an unsigned tag, or sign the tag with your <span class="caps">GPG</span> key via the <code>-s</code> or <code>-u <key-id></code> options. Once this has been done you can then use <code>git describe</code> to figure out how many commits you’ve created since the last tag or the given tag. <a href="http://gitfu.wordpress.com/">Git-fu</a> has a <a href="http://gitfu.wordpress.com/2008/05/25/git-describe-great-another-way-to-refer-to-commits/">great tutorial</a> on how to use this command (and it deserves a tip of its own for the future too!).</p>
<p>So let’s make a new tag and see how we can refer to it even after commits have been made, then we’ll push it to a remote. It’s a lot easier than you think.</p>
<pre>
$ git tag -a v1.0.0 -m "Creating the first official version."
$ git show v1.0.0
tag v1.0.0
Tagger: Nick Quaranto <nick@quaran.to>
Date: Tue Feb 3 20:37:45 2009 -0500
Creating the first official version.
commit a8d1b55c5d4bdec843d9942cabf1b678bc1d4eed
Merge: 00b9675... 1b487b8...
Author: Nick Quaranto <nick@quaran.to>
Date: Sun Nov 30 00:41:08 2008 -0500
Merge branch 'master' of git@github.com:qrush/config
$ git describe --tags
v1.0.0
$ touch test
$ git add test
$ git commit -am "Adding test files"
Created commit a7aafb8: Adding test files
0 files changed, 0 insertions(+), 0 deletions(-)
create mode 100644 test
$ git describe --tags
v1.0.0-1-ga7aafb8
$ git push --tags
Counting objects: 40, done.
Compressing objects: 100% (37/37), done.
Writing objects: 100% (40/40), 29.32 KiB, done.
Total 40 (delta 15), reused 9 (delta 2)
To git@github.com:qrush/config.git
* [new tag] v1.0.0 -> v1.0.0
</pre>
<p>The second describe command shows us that we’re one commit ahead of where the last tag was done. This is an easy way to figure out how much work has been done since the last commit. Also, the <code>--tags</code> option was used to push here, but just the one tag could have been pushed with <code>git push origin v1.0.0</code>. On GitHub (or on your remote) you should see the tag pushed up:</p>
<p style="text-align:center;"><img src="/images/tag.png" alt="" /></p>
<p>Another side note, if you have pushed tags that you want to move or rename, Git makes it ridiculously annoying to do so. Check out the <a href="http://www.kernel.org/pub/software/scm/git/docs/git-tag.html#_on_re_tagging">manpage</a> for an explanation as to why it’s complicated and should be done with caution.</p>
<p>If you have a unique way of integrating tags into your Git workflow, let us know in the comments or even <a href="http://gitready.com/submit.html">submit a tip so others can learn!</a></p>push and delete remote branches2009-02-02T00:00:00+00:00http://gitready.com/beginner/2009/02/02/push-and-delete-branches<p>This is an action that many Git users need to do frequently, but many (including the author) have forgotten how to do so or simply don’t know how. Here’s the definitive guide if you’ve forgotten.</p>
<p>So let’s say you have <a href="http://gitready.com/beginner/2009/01/25/branching-and-merging.html">checked out a new branch</a>, committed some awesome changes, but now you need to share this branch though with another developer. You can push the branch up to a remote very simply:</p>
<p><code>git push origin newfeature</code></p>
<p>Where <code>origin</code> is your remote name and <code>newfeature</code> is the name of the branch you want to push up. This is by far the easiest way, but there’s another way if you want a different option. <a href="http://zorched.net">Geoff Lane</a> has created a <a href="http://www.zorched.net/2008/04/14/start-a-new-branch-on-your-remote-git-repository/">great tutorial</a> which goes over how to push a ref to a remote repository, fetch any updates, and then start tracking the branch.</p>
<p>Deleting is also a pretty simple task (despite it feeling a bit kludgy):</p>
<p><code>git push origin :newfeature</code></p>
<p>That will delete the <code>newfeature</code> branch on the <code>origin</code> remote, but you’ll still need to delete the branch locally with <code>git branch -d newfeature</code>.</p>
<p>There’s a script called <a href="http://git-wt-commit.rubyforge.org/#git-publish-branch">git-publish-branch</a> created by <a href="http://all-thing.net/">William Morgan</a> that can easily automate this process if you find yourself performing these actions frequently. It also makes deleting remote branches feel a bit more natural. Know of better or easier ways to do the above tasks? Let us know in the comments or <a href="http://gitready.com/submit.html">submit your own tip!</a></p>push to only bare repositories2009-02-01T00:00:00+00:00http://gitready.com/advanced/2009/02/01/push-to-only-bare-repositories<p>Typically Git allows you to build whatever kind of workflow you’d like. Instead of saying “you must use it this way”, Git lets you figure out what best works for you and your organization. Like every system though, there are caveats and gotchas, and this tip goes over one of them. Let’s go over some definitions about the subject first:</p>
<p><strong>bare repository</strong>: a repository cloned using the <code>--bare</code> option, only includes the files/folders inside of the <code>.git</code> directory<br />
<strong>non-bare repository</strong>: a normal clone, has a working directory with checked out files</p>
<p>There’s easy ways to <a href="http://gitready.com/intermediate/2009/01/24/sharing-your-changes.html">share your changes</a> with Git, but sometimes you want to <a href="http://gitready.com/beginner/2009/01/21/pushing-and-pulling.html">push and pull</a> from a repository instead. The best practice here is when you want to push changes, don’t push to a non-bare repository. In other words, from the <a href="http://git.or.cz/gitwiki/GitFaq#head-b96f48bc9c925074be9f95c0fce69bcece5f6e73">GitFaq</a>:</p>
<blockquote>
<p>A quick rule of thumb is to never push into a repository that has a work tree attached to it, until you know what you are doing.</p>
</blockquote>
<p>The lesson here is that if you’re going to push changes, make a bare repository clone with <code>git clone --bare</code>. From this point, you could host the changes from with <a href="http://www.kernel.org/pub/software/scm/git/docs/git-daemon.html">git daemon</a> so others can access them. (Tips on this command will be coming!) The reason why Git was built to be unhappy with pushing to non-bare repositories is because one of its main goals is to <strong>not</strong> lose your data.</p>
<p>If you do want to for some reason, measures are in place so you don’t accidentally lose your changes. Once you have pushed to a non-bare repository, you’d have to <code>git reset --hard HEAD</code> to throw your changes out, and then do a <code>git checkout -f</code> to bring the pushed changes in. Even if you did lose some work that was committed, you could use <code>git reflog</code> to pull the objects back out of Git’s datastore.</p>
<p>Now that you know what it takes to push to a non-bare repository, hopefully you’ll take the easier route and just use the <code>--bare</code> option. If for some reason you don’t want to, now you know what can be done to work around it.</p>intro to rebase2009-01-31T00:00:00+00:00http://gitready.com/intermediate/2009/01/31/intro-to-rebase<p>Git’s <a href="http://www.kernel.org/pub/software/scm/git/docs/git-rebase.html">rebase</a> command is hard to understand for newcomers, and the <a href="http://www.kernel.org/pub/software/scm/git/docs/git-rebase.html">manpage’s</a> description doesn’t help at all:</p>
<blockquote>
<p>git-rebase – Forward-port local commits to the updated upstream head</p>
</blockquote>
<p>Um, what? This is helpful if you know how Git works, but not at all if you’re just starting out. Thanks to <a href="http://www.travisswicegood.com/">Travis Swicegood</a>, we have a better metaphor:</p>
<p style="text-align:center;"><a href="http://flickr.com/photos/hatrick/3174148419/"><img src="http://farm4.static.flickr.com/3120/3174148419_51d09db6e5.jpg?v=0" alt="" /></a></p>
<p>A cleaver. Rebase helps to cut up commits and slice them into any way that you want them served up, and placed exactly where you want them. You can actually rewrite history with this command, be it reordering commits, squashing them into bigger ones, or completely ignoring them if you so desire.</p>
<p>Why is this helpful? One of the most common use cases is that you’ve been working on your own features/fixes/etc in separate branches. Instead of creating ugly merge commits for every change that is brought back into the master branch, you could create one big commit and let rebase handle attaching it. Another frequent use of rebase is to pull in changes from a project and keep your own modifications in line. Usually by doing merges, you’ll end up with a history in which commits are interleaved between upstream and your own. Doing a rebase prevents this and keeps the order in a more sane state. For some examples of how this looks graphically, visit the end of <a href="http://eagain.net/articles/git-for-computer-scientists/">Git for Computer Scientists</a> or <a href="http://jbowes.dangerouslyinc.com/2007/01/26/git-rebase-keeping-your-branches-current/">James Bowes’ post on the subject</a>.</p>
<p>So let’s go through a simple example of using rebase. I’m going to check out a new branch for my feature, and hack on it for a bit, and commit my changes.</p>
<pre>
$ git checkout -b newfeature
Switched to a new branch "newfeature"
[.. changed some files, made a few commits ..]
$ git checkout master
Switched to branch "master"
[.. changed one file, committed ..]
</pre>
<p>So right now, our history looks like this (screenshots taken from <a href="http://gitx.frim.nl/">gitx</a>):</p>
<p style="text-align:center;"><img src="/images/rebase1.png" alt="" /></p>
<p>Now I want to bring the changes back into the master branch. Now, from here I could merge my changes in with <code>git merge newfeature</code>. If I did that, here’s how the commit history would look:</p>
<p style="text-align:center;"><img src="/images/rebase2.png" alt="" /></p>
<p>If we did a <code>git rebase newfeature</code> instead, our commit history would look like:</p>
<p style="text-align:center;"><img src="/images/rebase3.png" alt="" /></p>
<p>So you can see how it ends up a lot cleaner and compact. Since these changes were relatively simple, merging was really simple and didn’t require any work to do. Future tips will cover resolving merge problems, the different merging algorithms available, and of course rebase’s interactive mode. This post was meant mostly for getting the basics down of what the command does. If you have any neat tricks that you usually do with rebase, <a href="http://gitready.com/submit.html">submit a tip!</a></p>finding what has been changed2009-01-30T00:00:00+00:00http://gitready.com/intermediate/2009/01/30/finding-what-has-been-changed<p>Frequently you may want to easily see what has been changed as you’re working. Perhaps you just went out for a bite to eat and temporarily forgot, or maybe you need to check to see just what will be added into your newest commit. There’s a few Git commands that can help with this and make it very easy to figure out what has been modified.</p>
<p>Probably the easiest option is doing a <code>git diff</code>. It will print out the lines that have changed in your working directory compared to what’s stored in <code>HEAD</code>. So changing just one line in a <span class="caps">README</span> file would give me this output:</p>
<p style="text-align:center;"><img src="/images/diff.png" alt="" /></p>
<p>Provided your color options are turned on, it should be really easy to see what lines have been added, changed, or removed. There’s tons of other options for this command, but we’ll cover them and the other diff related helpers in future tips.</p>
<p>Using <code>git diff</code> will compare what is in the <a href="http://gitready.com/beginner/2009/01/18/the-staging-area.html">staging area</a> and what’s last been committed. However, you may want to see what files were modified in the last commit. You could play around with the various <a href="http://gitready.com/advanced/2009/01/20/bend-logs-to-your-will.html">logging options</a>, or use <code>git whatchanged</code>. This shortcut brings in the commit message, author information, and prints out exactly what files were touched for that changeset. So, if you wanted to see what the last commit changed:</p>
<pre>
$ git whatchanged -n 1
commit 698192122d725da2bc79f273571d91dba8b645a8
Author: Nick Quaranto <nick@quaran.to>
Date: Wed Jan 28 09:22:46 2009 -0500
Adding support for setting post categories through YAML
if not specified by directory structure
:100644 100644 92e4ce1... de43f33... M .gitignore
:100644 100644 0706818... 81213b3... M lib/jekyll/post.rb
:100644 100644 9aabcdd... 611d6d6... M test/helper.rb
:100644 100644 56e5e42... 373545d... M test/test_generated_site.rb
:100644 100644 713eec0... 202ea55... M test/test_post.rb
:100644 100644 03bf166... 7bcf6de... M test/test_site.rb
</pre>
<p>Of course, plenty of other options exist for this command at its <a href="http://www.kernel.org/pub/software/scm/git/docs/git-whatchanged.html">manpage</a>. If you have good ideas or ways to figure out what has changed in your repository from commit to commit, let us know!</p>exporting your repository2009-01-29T00:00:00+00:00http://gitready.com/intermediate/2009/01/29/exporting-your-repository<p>Previously there was a tip that covered <a href="http://gitready.com/intermediate/2009/01/24/sharing-your-changes.html">sharing changes</a> but that included all of your repository’s history. What if you just want to export a certain commit’s changes? Or just one folder? What if you wanted to make an archive of the repository for backup? Fear not, for Git can do all that and more. Thanks to <a href="http://stackoverflow.com/questions/160608/how-to-do-a-git-export-like-svn-export">Stack Overflow</a> for providing with some helpful hints to add into this post.</p>
<p>If your need is to just make a quick backup of your repository, doing a <code>git archive</code> will help. So if you wanted to get zip file packed with your repository’s files:</p>
<p><code>git archive HEAD --format=zip > archive.zip</code></p>
<p>The archive command normally packages repos in tarballs, so you can easily pipe it to your favorite data compression program:</p>
<p><code>git archive HEAD | gzip > archive.tar.gz</code></p>
<p>You can also archive a remote using the <code>--remote=<repo></code> option. Just be aware that this does not work with GitHub remotes, as <a href="http://groups.google.com/group/github/browse_thread/thread/cfcbcb1dc5f41f16">they encourage you to use the download button instead.</a> With any other remote it should work fine though, and check the <a href="http://www.kernel.org/pub/software/scm/git/docs/git-archive.html">manpage</a> if you’re having issues.</p>
<p>What if you don’t want a compressed version of the files? That’s possible too thanks to the <code>checkout-index</code> command. Basically, it copies everything on your index into a different folder. Exporting your repo would then be:</p>
<p><code>git checkout-index -f -a --prefix=/path/to/folder/</code></p>
<p>The <code>-f</code> option overwrites files, and the <code>-a</code> option means all files and folders. Just don’t forget the trailing slash on the <code>--prefix</code> option, as it’s very important! Omitting it will make the command think you want to prefix every file name with that argument instead.</p>
<p>If you wanted to just export a specific file or folder (in this case everything in the bin/ folder and the readme):</p>
<p><code>git checkout-index -f --prefix=/path/to/folder/ bin/* README.textile</code></p>
<p>Nice! You can also chain this command with <code>find</code> if you wanted to export all header files for example. Check out all you can do with <a href="http://www.kernel.org/pub/software/scm/git/docs/git-checkout-index.html">checkout-index at its manpage.</a> <a href="http://github.com/dasch">Daniel Schierbeck</a> has wrapped this process up into a little script called <a href="http://github.com/dasch/git-export/tree">git-export</a> that is worth a look if you need to do this often.</p>zsh git status2009-01-28T00:00:00+00:00http://gitready.com/advanced/2009/01/28/zsh-git-status<p>Sure, you could have status shown in your <a href="http://gitready.com/advanced/2009/01/23/status-in-your-prompt.html">bash prompt</a> but that’s not your only option for shells! <a href="http://www.zsh.org/">zsh</a>, or <a href="http://en.wikipedia.org/wiki/Zsh">Z Shell</a> is another popular command line interface that is in use by plenty of programmers, and there’s quite a few scripts that will get your repo’s status shown easily and quickly.</p>
<p><a href="http://github.com/jcorbin">Joshua Corbin</a> has thrown together a fantastic set of scripts dubbed <a href="http://github.com/jcorbin/zsh-git">zsh-git</a> that provides a great mix of colors and information about your repository. The basics are explained on the <a href="http://www.wunjo.org/zsh-git/">project page</a> but images are a lot more fun.</p>
<p>This is what the shell looks by default. Plenty of colors, and even using both sides of the screen! In a repository with no changes, it shows the branch name and where <span class="caps">HEAD</span> is currently pointing:</p>
<p style="text-align:center;"><img src="/images/zsh-normal.png" alt="" /></p>
<p>Once a change is made, a ! appears (<code>git status</code> is run since the author can’t break habits easily) If untracked files are created, it adds ? to the prompt, and adding files causes a + to be printed to the prompt. Also, if you’re tracking the branch, it will alert you and let you know when you’re ahead in commits.</p>
<p style="text-align:center;"><img src="/images/zsh-workflow.png" alt="" /></p>
<p>If you’re looking for a more <span class="caps">DIY</span> version, <a href="http://www.jukie.net/~bart">Bart Trojanowski</a> has a <a href="http://www.jukie.net/~bart/blog/20071219221358">great tutorial on adding branch status</a> that can be easily extended. If you’re looking for another nice and easy zsh setup, <a href="http://github.com/mattfoster/zshkit/tree/master">zshkit</a> and its various forks are fun to use and come packaged with plenty of helper commands.</p>
<p>Of course, if you have other zsh scripts or different shells that deserve their own tip, <a href="http://gitready.com/submit.html">submit one!</a></p>installing git2009-01-27T00:00:00+00:00http://gitready.com/beginner/2009/01/27/installing-git<p>This is probably the most basic tip: installing the system itself! Turns out that it’s easier than you think to start using Git on your system. This tip will continue to be updated with the latest and easiest ways to install Git on your favorite operating system.</p>
<p>If this list doesn’t have your favorite operating system’s directions, if links have become outdated, or you have an easier way let us know in the comments! Also, if you’re having snags getting Git installed/compiled give a shout.</p>
<p style="text-align:center;"><a href="http://flickr.com/photos/15708236@N07/2754478731/"><img src="http://farm4.static.flickr.com/3047/2754478731_6cac6d30a8_m.jpg" alt="" /></a></p>
<p><strong>Windows</strong></p>
<p>Yes, it works! There are plenty of awesome guides, but <a href="http://github.com/nathanj">nathanj’s</a> <a href="http://nathanj.github.com/gitguide/">Illustrated Guide to Git on Windows</a> is simply the best. It has a tutorial on how to get started using the system as well, and you can get started on it by downloading <a href="http://code.google.com/p/msysgit/">Git on MSys</a>. Another option available to Windows users is <a href="http://techblogging.wordpress.com/2008/04/11/compiling-and-installing-git-on-windows-under-cygwin/">compiling from source</a> with <a href="http://www.cygwin.com/">Cygwin</a>.</p>
<p><strong><span class="caps">OSX</span></strong></p>
<p>On 10.4 (Tiger), install <a href="http://macports.org">MacPorts</a> and run <code>sudo port install git-core</code>. You could also <a href="http://larrytheliquid.com/2007/12/29/compiling-git-and-git-svn-on-osx-tiger/">compile from source manually if that didn’t work.</a></p>
<p>On 10.5 (Leopard), it’s a lot easier thanks to the <a href="http://code.google.com/p/git-osx-installer/">Git <span class="caps">OSX</span> Installer</a> project. Just pick the latest and greatest version for your CPU’s architecture, and you’re set.</p>
<p><strong>Linux</strong></p>
<p>Installing on your favorite distro is quite simple:</p>
<p style="text-align:center;"><code>apt-get install git-core</code><br />
or<br />
<code>yum install git-core</code></p>
<p>If you want to compile from source on Ubuntu, <a href="http://chrisolsen.org">Chris Olsen</a> has a <a href="http://chrisolsen.org/2008/03/10/installing-git-on-ubuntu/">fantastic tutorial</a>.</p>
<p>For more options, check out the <a href="http://book.git-scm.com/2_installing_git.html">Git Community Book</a> or the <a href="http://git.or.cz/gitwiki/Installation">GitWiki</a>!</p>text-based graph2009-01-26T00:00:00+00:00http://gitready.com/intermediate/2009/01/26/text-based-graph<p>Just a short and interesting tip today about <code>git log --graph</code>. If you’re confused about where branches are headed or how merges worked, and you’re either too lazy to fire up <code>gitk</code>, <code>gitx</code>, or the <a href="http://github.com/qrush/jekyll/network">GitHub Network Graph</a>, you can get a really simple and fast graphical representation of your commits with this command.</p>
<p>Doing a <code>git log --graph</code> produces this for my clone of the <a href="http://github.com/qrush/jekyll">jekyll</a> repo, which has changes not pushed from yesterday’s post on <a href="http://gitready.com/beginner/2009/01/25/branching-and-merging.html">merging and branching.</a> However, in this form it’s not really helpful:</p>
<p style="text-align:center;"><img src="/images/graphfail.png" alt="" /></p>
<p>Let’s slim that down a bit to <code>git log --graph --pretty=oneline --abbrev-commit</code> so we can get commits compressed and only show 7 characters from the SHA1:</p>
<p style="text-align:center;"><img src="/images/graph.png" alt="" /></p>
<p>Much better! Of course, <a href="http://gitready.com/intermediate/2009/01/13/visualizing-your-repo.html">there’s plenty of other ways to visualize your repository</a> as well.</p>
<p><strong><span class="caps">UPDATE</span>:</strong> This command is included only in Git versions 1.5.6 and up.</p>branching and merging2009-01-25T00:00:00+00:00http://gitready.com/beginner/2009/01/25/branching-and-merging<p>Branching in git is easier than you’d think. It’s fast (40 characters written to a file), simple (one command to create a branch), and efficient (it doesn’t create a whole copy of your current working state). The branches you create don’t have to exist in the remote repository, so you can use them to test out new features or bug fixes without breaking what’s already working. Perhaps <a href="http://whygitisbetterthanx.com/#cheap-local-branching">Why Git is Better Than X</a> puts it best:</p>
<blockquote>
<p>Git will allow you to have multiple local branches that can be entirely independent of each other and the creation, merging and deletion of those lines of development take seconds. […] Git makes this process incredibly easy and it changes the way most developers work when they learn it.</p>
</blockquote>
<p>That’s nice and all, but you may still be afraid to use branches just because of the stigmas associated with your previous (or lack thereof) version control system’s way of handling this topic. Worry no longer, we’re going to go over a simple example of branching and merging, and resolving a conflict.</p>
<p>I’m working once again with the <a href="http://github.com/qrush/jekyll">jekyll</a> repository. I’m going to check out a new branch, make some changes in a file, and then merge it back into the master branch.</p>
<pre>
$ git checkout -b fixes
Switched to a new branch "fixes"
$ vim lib/jekyll/core_ext.rb
$ git commit -am "Adding cutoff method to String"
Created commit 670e353: Adding cutoff method to string
1 files changed, 15 insertions(+), 1 deletions(-)
$ git checkout master
Switched to branch "master"
$ git merge fixes
Updating e53ac7a..670e353
Fast forward
lib/jekyll/core_ext.rb | 16 +++++++++++++++-
1 files changed, 15 insertions(+), 1 deletions(-)
</pre>
<p>And that’s it! If we wanted to delete the branch, doing a <code>git branch -d fixes</code> would remove it. Since it’s so easy to create a branch and work on it separately, integrating this proces into your workflow can be quite beneficial. For instance, <a href="http://blog.hasmanythrough.com">Josh Susser</a> has a great post about how he <a href="http://blog.hasmanythrough.com/2008/12/18/agile-git-and-the-story-branch-pattern">uses branches to work on user stories.</a></p>
<p>That’s a really simple example of a fast-forward merge though, and is not always the case of what happens. Let’s go through a change I made on the same line of a file in both my master branch and a new branch and see how Git reacts:</p>
<pre>
$ vim lib/jekyll/core.rb
$ git commit -am "Causing a merge on purpose"
Created commit 8aba87e: Causing a merge on purpose
1 files changed, 2 insertions(+), 2 deletions(-)
$ git checkout -b conflicts
$ vim lib/jekyll/core.rb
$ git commit -am "Changing cutoff default"
Created commit 6041ddd: Changing cutoff default
1 files changed, 1 insertions(+), 1 deletions(-)
$ git checkout master
Switched to branch "master"
$ git merge conflicts
Auto-merged lib/jekyll/core_ext.rb
CONFLICT (content): Merge conflict in lib/jekyll/core_ext.rb
Automatic merge failed; fix conflicts and then commit the result.
</pre>
<p>Opening up the file will reveal that git shows us the difference in versions for this hunk of text:</p>
<p style="text-align:center;"><img src="/images/conflicts.png" alt="" /></p>
<p>If we do a <code>git status</code> it should still show our conflict. Since we want to keep the one from my new version, simply delete the lines that Git plopped in there and the old version. Then just <code>add</code> and <code>commit</code> the file as normal, and your merge is resolved!</p>
<pre>
$ git status
# On branch master
#
# Changed but not updated:
# (use "git add <file>..." to update what will be committed)
#
# unmerged: lib/jekyll/core_ext.rb
#
$ vim lib/jekyll/core.rb
$ git commit -am "Fixing conflict!"
Created commit 9c8e9fd: Fixing conflict!
</pre>
<p>This creates a special commit that has two parent commits from each of the branches that we merged:</p>
<pre>
$ git show HEAD
commit 9c8e9fd335381fe6a97708f7b3cd1d5acf670d2d
Merge: 8aba87e... 6041ddd...
Author: Nick Quaranto <nick@quaran.to>
Date: Sun Jan 25 13:22:03 2009 -0500
Fixing conflict!
</pre>
<p>Future tips will cover using helpers for this process, like <a href="http://www.kernel.org/pub/software/scm/git/docs/git-mergetool.html">git-mergetool</a> and <code>gitk --merge</code>. If you know of good tutorials on these or other ways to do merging, <a href="http://gitready.com/submit.html">submit a tip!</a> In the meantime check out <a href="http://gitcasts.com/posts/branching-and-merging">Scott Chacon’s gitcast on this topic</a> or the <a href="http://book.git-scm.com/3_basic_branching_and_merging.html">Git Community Book’s guide.</a> if you’d like more information on the subject.</p>sharing your changes2009-01-24T00:00:00+00:00http://gitready.com/intermediate/2009/01/24/sharing-your-changes<p>Git’s distributed nature does not rely on central servers to host and broadcast your code. There’s more options available to you if for some reason your main server goes down, or perhaps when <a href="http://ozmm.org/posts/when_github_goes_down.html">GitHub goes down</a>.</p>
<p>Probably the easiest way to quickly export and share your code in this case is by making a bare clone of your repository, which contains only the stuff in the <code>.git</code> directory that’s usually at your project’s root folder. Since this one folder has all of the history stored in it, you can easily extract anything you need from it. Simply do:</p>
<p><code>git clone --bare ~/Dev/ruby/jekyll jekyll.git</code></p>
<p>and then upload the folder to a server somewhere, share it for others to find on your machine, etc. Copying it down onto your machine and doing these commands will restore the repository:</p>
<pre>
$ mkdir test
$ mv jekyll.git test/.git
$ cd test
$ git init
Reinitialized existing Git repository in /Users/qrush/Dev/test/.git/
$ git checkout -f
</pre>
<p>So we’ve created a new folder for the repo, changed the folder name back to <code>.git</code>, woke git back up and restored all the changes from the latest commit.</p>
<p>You could also use the <code>git-daemon</code> to quickly serve up files using the git:// protocol. It will automatically serve up projects in subfolders, so for my ruby directory doing:</p>
<p><code>git daemon --base-path=~/Dev/ruby --export-all</code></p>
<p>will then allow you to clone the jekyll repository on another machine using:</p>
<p><code>git clone git://<ip-address>/jekyll</code></p>
<p>Make sure to check that port 4918 is open on your network for this transfer. If not, just configure a different one using the <code>--port</code> option. Refer to the <a href="http://www.kernel.org/pub/software/scm/git/docs/git-daemon.html">manpage</a> if it still doens’t work for you.</p>
<p>Using <span class="caps">TCP</span> is boring! What if you want to be able to get my changes over <span class="caps">HTTP</span>? Well, you’re in luck, Git can serve that up too. Doing these three commands should do the trick:</p>
<pre>
git --bare update-server-info
mv hooks/post-update.sample hooks/post-update
chmod a+x hooks/post-update
</pre>
<p>These basically prepare Git for access via a web browser. Provided Apache or your favorite server is set up to host that directory, you should be able to clone over http like so:</p>
<p><code>git clone http://yoursite.com/yourrepo.git</code></p>
<p>There’s plenty of other options as well. You could use <a href="http://toolmantim.com/articles/sharing_git_repositories_via_os_xs_built_in_web_sharing">OSX’s built in web sharing</a> along with the previous technique to host it from your own machine. You could also use an ssh address if you have an ssh account set up on the server you want to share your code from.</p>
<p>If you’ve got any other handy ideas on how to share your repository, let us know in the comments!</p>bash git status2009-01-23T00:00:00+00:00http://gitready.com/advanced/2009/01/23/bash-git-status<p>Yeah, we all know about the <code>git status</code> command but that’s just way too many characters to type again and again. Why bother with those 10 keyboard strokes when you could have your shell simply output git’s working state? Sounds awesome, right? Luckily a few hackers have thrown together some scripts to do just this in your bash prompt. If you have these or similiar scripts working in other shells, <a href="http://gitready.com/submit.html">submit a tip about it!</a></p>
<p style="text-align:center;"><a href="http://flickr.com/photos/levitateme/195355984/" title="I need one of these for IRC."><img src="http://farm1.static.flickr.com/72/195355984_7d6153610b.jpg" alt="" /></a></p>
<p>Probably the most widely used and known one <a href="http://henrik.nyh.se/2008/12/git-dirty-prompt">shows your current branch name and if anything’s changed.</a> Using this script in your <code>.bashrc</code> will give you a prompt like so:</p>
<pre>
# When clean...
user@host ~/dir[master]$
# When dirty...
user@host ~/dir[master*]$
</pre>
<p>So then it’s much easier to tell when you need to do a commit. You can check out <a href="http://gist.github.com/31631">plenty of variants of this script at Gist.</a> This hack also evolved from <a href="http://www.simplisticcomplexity.com/2008/03/13/show-your-git-branch-name-in-your-prompt/">showing just your branch name</a> so feel free to build upon it or use it as you like.</p>
<p>Oh, you wanted more? Well, there is a neat project called <a href="http://github.com/lvv/git-prompt/tree/master">git-prompt</a> that can give you all sorts of information about the repository in your bash prompt. You can figure out if individual files are tracked or modified, figure out if merge conflicts are resolved, and even determine if your <code>HEAD</code> is detached. <a href="http://volnitsky.com/project/git-prompt/">Check out the project page</a> for more information on what it can do. Here’s a little demo of what it can show:</p>
<p style="text-align:center;"><a href="http://volnitsky.com/project/git-prompt" title="It shows commit SHAs too! Badass."><img src="http://farm4.static.flickr.com/3492/3221797568_41a9803e01_o.png" alt="" /></a></p>
<p>If you’ve got any other helpful prompt-related tips let us know and we’ll add it in!</p>count your commits2009-01-22T00:00:00+00:00http://gitready.com/intermediate/2009/01/22/count-your-commits<p>Ever wondered how many commits you’ve contributed to a project? Or perhaps, which coworker has really done nothing (or maybe they have huge changes and fewer commits!) Well, wonder no more, for <code>git shortlog</code> is a nice way to find out.</p>
<p>I’m running this on my <a href="http://github.com/qrush/jekyll">clone of jekyll</a>, which is how this blog is generated:</p>
<pre>
$ git shortlog -s -n
135 Tom Preston-Werner
15 Jack Danger Canty
10 Chris Van Pelt
7 Mark Reid
6 remi
3 Mikael Lind
3 Toby DiPasquale
2 Aristotle Pagaltzis
2 Basil Shkara
2 John Reilly
2 PJ Hyett
1 Marc Chung
1 Nick Gerakines
1 Nick Quaranto
1 Tom Kirchner
</pre>
<p>The <code>-s</code> option squashes all of the commit messages into the number of commits, and the <code>-n</code> option sorts the list by number of commits.</p>
<p>This command could also be useful for changelogs, since you could easily dump all the changes each person has done. There’s a few other neat options: <code>-e</code> will append emails, and you can control columns widths with <code>-w</code>. Check out the <a href="http://www.kernel.org/pub/software/scm/git/docs/git-shortlog.html">manpage</a> for more information.</p>pushing and pulling2009-01-21T00:00:00+00:00http://gitready.com/beginner/2009/01/21/pushing-and-pulling<p>Today we’re going to review another basic yet powerful concept that Git among other version control systems of its type has: distribution! As you may know, your commits are all local, and repositories are simply clones of each other. That means the real work in distributing your projects is in synchronizing the changes via <code>git push</code> and <code>git pull</code>.</p>
<p>If you’re new to Git, you may think that this is too much overhead and one that leads to a breakdown of control. Look at it this way: if your central server goes down, you’re usually hosed and prevented from working and collaborating with others. Since all of the work involved with actually creating revisions is done on your own machine, you can code whether the network is down without the permission of others or being subject to network issues. Did I mention it’s a lot faster too for most routine operations? Check out some more of advantages (and disadvantages) of <span class="caps">DVCS</span> at <a href="http://en.wikipedia.org/wiki/Distributed_revision_control#Vs_Centralised">Wikipedia</a>.</p>
<p><a href="http://osteele.com">Oliver Steele</a> has whipped up a great image of how pushing and pulling works:</p>
<p style="text-align:center;"><img src="http://osteele.com/images/2008/git-transport.png" alt="" /></p>
<p>The topmost part of the diagram is easy, that’s committing your changes to <a href="http://gitready.com/beginner/2009/01/18/the-staging-area.html">the staging area</a>. Once that’s done, your version control is essentially in place, but now we want to synchronize it with our remote repository. This could be on a hosting site like <a href="http://github.com">GitHub</a>, your work’s main git server, a production machine, or even another coworker’s repository. Once the changes have been delivered, others can <code>pull</code> them down and work with them. With most actions in Git there’s a few options, but let’s stick with <code>pull</code> for today.</p>
<p>Let’s go through a real world example. I’ve just added the <a href="http://twitter.com/gitready">Twitter</a> link at the bottom of this blog. I want to <code>push</code> my changes up to the project’s <a href="http://github.com/qrush/gitready">GitHub repository</a> so I can update the server. The syntax of this command is usually <code>git push <remote> <branch></code>. A remote is basically the address of a cloned repository. It’s got pretty much all of the same data and history, it’s just waiting to get updated. Usually most projects work with an <code>origin</code> remote, and the <code>master</code> branch by default.</p>
<pre>
$ git commit -am "Adding twitter link"
Created commit f2cd831: Adding twitter link
1 files changed, 1 insertions(+), 0 deletions(-)
$ git push origin master
Counting objects: 7, done.
Compressing objects: 100% (4/4), done.
Writing objects: 100% (4/4), 407 bytes, done.
Total 4 (delta 2), reused 0 (delta 0)
To git@github.com:qrush/gitready.git
361303d..f2cd831 master -> master
</pre>
<p>Now our remote repository is updated, and if you visit GitHub <a href="http://github.com/qrush/gitready/commits/master">you’d be able to see the commits</a>. The output this command prints out has to deal with how Git transfers over the various blobs of data that have changed, and then lets us know that the repository has been updated by showing the changed SHA1.</p>
<p>But what about <code>pull</code>? We can use that to update any other repositories with the commits I just synchronized. The project’s crappy deploy script does exactly that:</p>
<pre>
$ git pull origin master
remote: Counting objects: 7, done.
remote: Compressing objects: 100% (4/4), done.
remote: Total 4 (delta 2), reused 0 (delta 0)
Updating 361303d..f2cd831
Fast forward
_layouts/default.html | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)
</pre>
<p>The output shows us that the repository living on the server has some changes to bring in from remote repository, and it proceeds to bring them in. This process would be exactly the same if you wanted to bring in changes that another person committed to your repository. Those who have <a href="http://github.com/qrush/gitready/network/members">forked the gitready repository</a> on GitHub can also now get the changes I’ve made. Future tutorials will go over that process more in depth.</p>
<p>If you can think of any other ideas or concepts that were missed (we’ll save refspecs for later tutorials), let us know.</p>bend logs to your will2009-01-20T00:00:00+00:00http://gitready.com/advanced/2009/01/20/bend-logs-to-your-will<p><code>git log</code> is an extremely powerful command with plenty of options that are helpful for figuring out what work has been done on your repositories and just who’s done it. This post enumerates a few of the more useful options. Most of these tips were farmed from Scott Chacon’s <a href="http://gitcasts.com/posts/git-log">gitcast on git log</a> and R. Tyler Ballance’s <a href="http://unethicalblogger.com/posts/2008/12/git_protip_learning_your_history_git_log">git protip series</a>.</p>
<p><code>git log -<n></code></p>
<p>Show the log for <code>n</code> number of commits. For example, <code>git log -2</code> for the last two commits.</p>
<p><code>git log --stat</code></p>
<p>Show the log with output for files changed and insertions/deletions. Basically the normal output of <code>git commit</code> appended to each message.</p>
<p><code>git log --name-status</code></p>
<p>Attaches <span class="caps">SVN</span>-like add/modified/deleted for each commit. Very basic but still gives a decent idea about what’s changed.</p>
<p><code>git log --pretty=oneline</code></p>
<p>Compresses each commit to its SHA1 and message on one line. Pipe to <code>wc -l</code> if you want to count commits!</p>
<p><code>git log origin..HEAD</code></p>
<p>See if there’s any commits that have not been pushed to your <code>origin</code> remote. (Thanks for the tip, Ryan Bates!)</p>
<p><code>git log <file></code></p>
<p>See all commits that affected only the file given.</p>
<p><code>git log --no-merges --author=dave</code></p>
<p>See all commits that dave has worked on, and ignore any merge commits to reduce noise.</p>
<p><code>git log --since="1 week ago"</code></p>
<p>View commits that have happened since last week. Could easily be replaced with <code>yesterday</code>, <code>1 year ago</code>, <code>3 months ago</code>, <code>1/20/09</code> and so on. There’s also other time based options: <code>--after</code>, <code>--until</code>, and <code>--before</code> if you want to get creative.</p>
<p><code>git log --grep='^Bump'</code></p>
<p>Search through commit messages to find ones that start with the string “Bump”. This will take in any regular expression, so if you’re looking for that one commit you did and all you can remember is a part of the message, <code>--grep</code> will find it.</p>
<p><code>git --no-pager log</code></p>
<p>Don’t want to use <code>less</code> to view your commits? This option will just give you the straight output if you need it.</p>
<p>Of course, check out the <a href="http://www.kernel.org/pub/software/scm/git/docs/git-log.html">manpage</a> to see all of the options available to you. If you have a nice tip that was missed and you’d like to share, let us know in the comments and I’ll update the post.</p>ignoring files2009-01-19T00:00:00+00:00http://gitready.com/beginner/2009/01/19/ignoring-files<p>We don’t need Git to version everything in our projects, be it compiled source, files with passwords, or temporary files that editors love to create. Usually keeping stuff out of your VCS’ hands is a task that is hard to manage and annoying to set up. Not with Git! Using the <code>.gitignore</code> file along with some other options, we’re going to learn how to set up per-project and per-user ignores.</p>
<p style="text-align:center;"><a href="http://flickr.com/photos/miskan/7240060/"><img src="http://farm1.static.flickr.com/4/7240060_1332e880ff.jpg" alt="" /></a></p>
<p>The easiest and simplest way is to create a <code>.gitignore</code> file in your project’s root directory. The files you choose to ignore here take affect for all directories in your project, unless if they include their own <code>.gitignore</code> file. This is nice since you have one place to configure ignores unlike SVN’s svn:ignore which must be set on every folder. Also, the file itself can be versioned, which is definitely good.</p>
<p>Here’s a basic <code>.gitignore</code>:</p>
<pre>
$ cat .gitignore
# Can ignore specific files
.DS_Store
# Use wildcards as well
*~
*.swp
# Can also ignore all directories and files in a directory.
tmp/**/*
</pre>
<p>Of course, this could get a lot more complex. You can also add exceptions to ignore rules by starting the line with <code>!</code>. See an example of this at the <a href="http://github.com/guides/ignore-for-git">GitHub guide on ignores</a>.</p>
<p>Two things to keep in mind with ignoring files: First, if a file is already being tracked by Git, adding the file to <code>.gitignore</code> won’t stop Git from tracking it. You’ll need to do <code>git rm --cached <file></code> to keep the file in your tree and then ignore it. Secondly, empty directories do not get tracked by Git. If you want them to be tracked, they need to have something in them. Usually doing a <code>touch .gitignore</code> is enough to keep the folder tracked.</p>
<p>You can also open up <code>$GIT_DIR/info/exclude</code> (<code>$GIT_DIR</code> is usually your <code>.git</code> folder) and edit that file for project-only ignores. The problem with this is that those changes aren’t checked in, so use this only if you have some personal files that don’t need to be shared with others on the same project.</p>
<p>Your final option with ignoring folders is adding a per-user ignore by setting up a <code>core.excludesfiles</code> option in your config file. You can set up a <code>.gitignore</code> file in your <span class="caps">HOME</span> directory that will affect all of your repositories by running this command:</p>
<p><code>git config --global core.excludesfile ~/.gitignore</code></p>
<p>Read up on the <a href="http://www.kernel.org/pub/software/scm/git/docs/gitignore.html">manpage</a> if you’d like to learn more about how ignores work. As always, if you have other ignore-related tips let us know in the comments.</p>the staging area2009-01-18T00:00:00+00:00http://gitready.com/beginner/2009/01/18/the-staging-area<p>One of the most essential concepts to Git is that of the staging area. Its use can fundamentally change how you work, for the better! Let’s go over how exactly it works and what you’ll need to know to use it.</p>
<p>With most other version control systems, there’s 2 places to store data: your working copy (the folders/files that you’re currently using) and the datastore (where the version control decides how to pack and store your changes). In Git there’s a third option: the staging area (or index). It’s basically a loading dock where you get to determine what changes get shipped away.</p>
<p style="text-align:center;"><a href="http://flickr.com/photos/mundane_joy/2441544705/"><img src="http://farm4.static.flickr.com/3259/2441544705_4c6f7e9b78.jpg" alt="" /></a></p>
<p>Since the working directory and what gets saved by Git are essentially decoupled, this allows the developer to build up their commits however they want, and not in a fashion where the <span class="caps">VCS</span> tells you. Since there’s a layer between when Git actually saves the data, you gain a lot more flexibility and control.</p>
<p>Using the index is quite simple with the <code>git add</code> and <code>git commit</code> commands. Basically, you <code>add</code> files onto the index, and once you’re satisfied with the changes <code>commit</code> them:</p>
<p style="text-align:center;"><a href="http://whygitisbetterthanx.com/#the-staging-area"><img src="http://whygitisbetterthanx.com/images/index1.png" alt="" /></a></p>
<p>Once they’re in the repository you can <code>push</code> them to remote locations, <code>merge</code> them into other branches, and much more. There’s also actions that can be performed on the staging area itself, such as <a href="http://gitready.com/beginner/2009/01/10/stashing-your-changes.html">temporarily stashing your changes</a>.</p>
<p>Let’s go through just a basic example of using the staging area. I just made some changes:</p>
<pre>
$ git status
On branch master
Changed but not updated:
(use "git add <file>..." to update what will be committed)
modified: README.md
modified: about.html
Untracked files:
(use "git add <file>..." to include in what will be committed)
help.txt
no changes added to commit (use "git add" and/or "git commit -a")
</pre>
<p>So in this example we have 2 files that Git knows about, and one it does not: help.txt. If we do <code>git add .</code>, that will add everything that has been changed or any new files that have not been tracked yet. The add command doesn’t store the data yet, it simply places it on the loading dock, ready for the next <code>git commit</code> truck to ship it away.</p>
<pre>
$ git add .
$ git status
On branch master
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
modified: README.md
modified: about.html
new file: help.txt
</pre>
<p>Just like the prompt says, you can use <code>git reset HEAD <file></code> to restore files back to their modified state. This way, you can commit exactly what you wanted. <a href="http://gitready.com/advanced/2009/01/15/piecemeal-staging.html">You can also commit specific lines of files if you really wanted.</a> If you’re wondering about how to revert files, <a href="http://gitready.com/beginner/2009/01/11/reverting-files.html">there’s a whole tip dedicated to that as well.</a> From here, doing a <code>git commit</code> will move all of the files into Git’s data storage, and you’re set!</p>
<pre>
$ git commit -m "Adding stuff"
Created commit e793200: Adding stuff
2 files changed, 3 insertions(+), 0 deletions(-)
create mode 100644 help.txt
</pre>
<p>If you’re looking for more information on the index, check out these fantastic posts:</p>
<ol>
<li><a href="http://tomayko.com/writings/the-thing-about-git">The Thing About Git</a></li>
<li><a href="http://book.git-scm.com/1_the_git_index.html">Git Book – The Git Index</a></li>
</ol>
<p>If you know of other resources that explain the index, let us know in the comments!</p>restoring lost commits2009-01-17T00:00:00+00:00http://gitready.com/advanced/2009/01/17/restoring-lost-commits<p>So, you just did a <code>git reset --hard HEAD^</code> and threw out your last commit. Well, it turns out you really did need those changes. You’ll never be able to implement that algorithm that perfectly twice, so you need it back. Don’t fear, git should still have your commit. When you do a reset, the commit you threw out goes to a “dangling” state. It’s still in git’s datastore, waiting for the next garbage collection to clean it up. So unless you’ve ran a <code>git gc</code> since you tossed it, you should be in the clear to restore it.</p>
<p>For these examples, I’m working with the <a href="http://github.com/gitready/gitready">code for this blog</a>. From the top, we just ran:</p>
<pre>
$ git show-ref -h HEAD
7c61179cbe51c050c5520b4399f7b14eec943754 HEAD
$ git reset --hard HEAD^
HEAD is now at 39ba87b Fixing about and submit pages so they don't look stupid
$ git show-ref -h HEAD
39ba87bf28b5bb223feffafb59638f6f46908cac HEAD
</pre>
<p>So our <code>HEAD</code> has been backed up by one commit. At this point if we wanted it back we could just <code>git pull</code>, but we’re assuming that only our local repository knows about the commit. We need the SHA1 of the commit so we can bring it back. We can prove that git knows about the commit still with the <code>fsck</code> command:</p>
<pre>
$ git fsck --lost-found
[... some blobs omitted ...]
dangling commit 7c61179cbe51c050c5520b4399f7b14eec943754
</pre>
<p>You can also see the that git knows about the commit still by using the <code>reflog</code> command:</p>
<pre>
$ git reflog
39ba87b... HEAD@{0}: HEAD~1: updating HEAD
7c61179... HEAD@{1}: pull origin master: Fast forward
[... lots of other refs ...]
</pre>
<p>So, we now have our SHA1: <code>7c61179</code>. If we want to get immediately apply it back onto our current branch, doing a <code>git merge</code> will recover the commit:</p>
<pre>
$ git merge 7c61179
Updating 39ba87b..7c61179
Fast forward
css/screen.css | 4 ++++
submit.html | 4 ++--
2 files changed, 6 insertions(+), 2 deletions(-)
</pre>
<p>This command will bring your lost changes back and make sure that <code>HEAD</code> is pointing at the commit. From here you can continue to work as normal! You could also checkout the SHA1 into a new branch, but really a merge is the fastest and easiest way to restore that lost commit once you have the hash. If you have other ways let us know in the comments!</p>
<p>If you want some more options on what to do in this situation, <a href="http://programblings.com/">Mathieu Martin’s</a> <a href="http://programblings.com/2008/06/07/the-illustrated-guide-to-recovering-lost-commits-with-git">illustrated guide to recovering lost commits with Git</a> has plenty for you.</p>cleaning up untracked files2009-01-16T00:00:00+00:00http://gitready.com/beginner/2009/01/16/cleaning-up-untracked-files<p>Our first reader submitted tip comes from <a href="http://blog.davglass.com/">Dav Glass</a>, and it elaborates on a command used to keep your repository nice and tidy. Have a tip you’d like to share? <a href="http://gitready.com/submit.html">Submit it!</a></p>
<p>Files and directories may pile up in your working directory that are left over from merges, generated, or perhaps got mistakenly put there. Whatever the case, you don’t need to ignore them in your <code>.gitignore</code>, you just need to remove them. Running</p>
<p><code>git clean -n -d <path></code></p>
<p>will do a ‘dry run’ of the command and show you just what files and folders are going to be removed. Running it on the <a href="http://github.com/qrush/gitready">gitready</a> gives this output:</p>
<pre>
Would remove _posts/2009-01-16-cleaning-up-untracked-files.textile
</pre>
<p>Which definitely would be bad if it was removed. I haven’t added the post to the staging area yet, so the file appears as untracked. If you only want files to be cleaned up and not empty directories, take out the <code>-d</code> option. Once you’re sure that you do want to blow away all of those files, doing</p>
<p><code>git clean -d <path></code></p>
<p>actually performs the deletion. If you omit the <code><path></code> git will perform it on your current directory. Also, you may need to throw in the <code>-f</code> option depending on permissions and other situations that may crop up.</p>
<p>Cleaning also has a few other helpful options: if you want to perform a normal clean and clear out all the files that git usually ignores, the <code>-x</code> flag will help immensely. If you just want to trash the ignored files and nothing else, use the <code>-X</code> option.</p>
<p>So if we wanted to do a major cleanup:</p>
<pre>
$ git clean -n -d -x
Would remove .DS_Store
Would remove _posts/.2009-01-16-cleaning-up-untracked-files.textile.swp
Would remove _posts/2009-01-16-cleaning-up-untracked-files.textile
Would remove _site/
Would remove images/.DS_Store
Would remove images/_site/
</pre>
<p>That command would clean up files listed under the project’s <a href="http://github.com/qrush/gitready/blob/7f51407b796c10beb11fe9e67c0f563d41a92fd8/.gitignore">.gitignore</a> file as well as removing other files and directories that aren’t necessary. As always use precaution when running <code>git clean</code>, and make sure to double check what you’re really deleting.</p>
<p>As always, if you know of other related tricks with <code>git clean</code> let us know in the comments!</p>piecemeal staging2009-01-15T00:00:00+00:00http://gitready.com/advanced/2009/01/15/piecemeal-staging<p>This is a follow up to the comments from yesterday’s article about <a href="http://gitready.com/intermediate/2009/01/14/interactive-adding.html">interactive adding</a>. Readers were begging coverage of powerful <code>git add -p</code>, a shortcut to the patch mode of interactive adding. This command is capable of breaking up changes in files into smaller hunks so you can commit <strong>exactly</strong> what you want, and not just the whole file.</p>
<p>This behavior is very helpful since it allows you to version any “hunk” of text in the file that you’d like. Perhaps that one line of code will break the build on others’ machines or the build server, but just not yours. You get the point.</p>
<p>Let’s go through an example of using it, making changes to our project’s trusty <span class="caps">README</span> file again. Here’s what <code>git diff</code> gives us from the changes that were just made:</p>
<pre>
diff --git a/README.md b/README.md
index 2556dae..45d8b6e 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,14 @@
> There is only one way...
> ~ Henry Van Dyke
+# Project information
+
+Blah blah blah...
+
# Want to contribute?
If you have ideas about...
+
+# About
+
+This blog is just awesome.
</pre>
<p>So as we can see, we’ve made changes in separate parts of the file. However, I want to only commit the lower half. Besides, who really needs documentation anyway? Enter:</p>
<p><code>git add -p</code></p>
<p>Run this and you’ll be greeted with a prompt just like <code>git add -i</code>, but it has quite a few options:</p>
<pre>
Stage this hunk [y/n/a/d/s/e/?]? ?
y - stage this hunk
n - do not stage this hunk
[... removed a few ...]
s - split the current hunk into smaller hunks
e - manually edit the current hunk
? - print help
</pre>
<p>Most are pretty self-explanatory, but let"s go over the really cool ones. What we really want is the <code>s</code> option, which will split the file into two smaller hunks of code, one for the higher “Project Information” block and one for the “About” block. Once it"s split it will prompt you with just the changes for that hunk:</p>
<pre>
Split into 2 hunks.
@@ -1,6 +1,10 @@
> There is only one way...
> ~ Henry Van Dyke
+# Project information
+
+Blah blah blah...
+
# Want to contribute?
If you have ideas about...
Stage this hunk [y/n/a/d/j/J/e/?]? n
</pre>
<p>From here we can ignore it with <code>n</code>, and move on to the next one and add it with <code>y</code>:</p>
<pre>
@@ -4,3 +8,7 @@
# Want to contribute?
If you have ideas about...
+
+# About
+
+This blog is just awesome.
Stage this hunk [y/n/a/d/K/e/?]? y
</pre>
<p>Doing a <code>git status</code> will show changes to be committed and changes to be staged on one file. Strange, but it makes sense: we staged half the changes, and the other half are not yet added to the index.</p>
<p>There’s also the <code>e</code> option, which will let you to manually flip the hunks on and off in your favorite editor. Instructions are included with that option, so go play around with it when you get the chance. (No pun intended.)</p>
<p>If you’ve got any stories as to how <code>git add -p</code> has helped you (or if a neat feature was missed), let us know in the comments!</p>interactive adding2009-01-14T00:00:00+00:00http://gitready.com/intermediate/2009/01/14/interactive-adding<p>Sometimes simple adding with <code>git add .</code> or <code>git commit -am</code> just isn’t enough. You may want to split changes up over several commits, or you’re just not ready to add everything yet. And who wants to add individual files one at a time? That’s just boring. Enter the interactive adder:</p>
<p><code>git add -i</code></p>
<p>Let’s go through an example of using the interactive mode. I made some changes to the <a href="http://github.com/qrush/gitready">gitready</a> project’s readme along with another file. Calling the above command gives us this output, the status of the index:</p>
<pre>
staged unstaged path
1: unchanged +3/-1 README.md
2: unchanged +1/-1 _layouts/default.html
*** Commands ***
1: status 2: update 3: revert 4: add untracked
5: patch 6: diff 7: quit 8: help
What now>
</pre>
<p>As you can see, we have plenty of commands available to us. If we want to see this screen again, using the <code>status</code> command will bring us back. The +3/-1 are the number of lines that have been added/removed, the usual plus and minus symbols that you see when pulling.</p>
<p>Let’s add the changes we made to the readme. Using the <code>update</code> command will allow us to do this. After choosing this command we’ll see this output:</p>
<pre>
staged unstaged path
* 1: unchanged +3/-1 README.md
2: unchanged +1/-1 _layouts/default.html
Update>>
</pre>
<p>And if we select to update 1, will notify us that the file is staged to be committed. Now if we look at the status, you can see that our readme has been staged properly.</p>
<pre>
staged unstaged path
1: +3/-1 nothing README.md
2: unchanged +1/-1 _layouts/default.html
</pre>
<p>Once you’re done, you can dump out using the <code>quit</code> command, and commit your work. If you don’t trust the adder, calling <code>git status</code> will show that only the readme has been staged for the commit:</p>
<pre>
# On branch master
# Changes to be committed:
#
# modified: README.md
#
# Changed but not updated:
#
# modified: _layouts/default.html
</pre>
<p>There’s plenty of other helpful commands that the interactive adding can do, this is just the start. Check out the <code>help</code> command for the rest that’s available to you. We’ll have more tips in the future for the other commands available inside interactive mode.</p>visualizing your repo2009-01-13T00:00:00+00:00http://gitready.com/intermediate/2009/01/13/visualizing-your-repo<p>So, you want to see your repository in a brand new way. You’re sick of the command line, you need to see some graphs! Pixels! Buttons! Graphics! Dialog boxes! Ok, we get the point.</p>
<p>Our first option is viewing your repo in a browser. This functionality is packaged with most git installs:</p>
<p><code>git instaweb</code></p>
<p>This will fire up a server, usually <a href="http://lighttpd.net">lighttpd</a>, to serve a simple web interface for your repository. You can browse commits, trees, view files, what have you.</p>
<p style="text-align:center;"><img src="/images/instaweb.png" alt="" /></p>
<p>This is really useful if you need to dive down and see history but you don’t know the commands yet. (And it’s easier too.) If you don’t have lighttpd installed and don’t want to bother with it, running</p>
<p><code>git instaweb --httpd webrick</code></p>
<p>will force WEBrick to serve the page, which will work just as well if Ruby is installed on your system. It also works with Apache, just check <a href="http://www.kernel.org/pub/software/scm/git/docs/git-instaweb.html">instaweb’s manpage</a> to see the supported server and other goodies.</p>
<p>Webpages are great and all, but what if you want to see your commits in a more…graphical manner? Look no further than gitk or gitx then. These programs give you a more dynamic view of your repository and let you actually see branches and merges take place:</p>
<p style="text-align:center;"><img src="/images/gitk.png" alt="" /></p>
<p>Need some graphical git loving? Use gitk with most git installs by running <code>gitk</code> or <a href="http://gitx.frim.nl/">download gitx for <span class="caps">OSX</span></a>. Windows users, if you know of an equivalent, comment away!</p>
<p>There’s also plenty of git graphical love over at <a href="http://github.com">GitHub</a> for every project, be it visualizing the impact individuals have had on the project, times that people have worked on the project, and even more. Definitely play around with various graphs they have to offer if you haven’t yet.</p>
<p style="text-align:center;"><img src="/images/impact.png" alt="" /></p>
<p style="text-align:center;"><img src="/images/punchcard.png" alt="" /></p>
<p>There’s also plenty of other good visualizers over at the <a href="http://git.or.cz/gitwiki/InterfacesFrontendsAndTools#head-60c66fc11f2aaab74873cbb3c434f2075abd5d87">GitWiki</a>. If you know of any other good ways to see your repository graphically, let us know in the comments. I’ll continue to update the post with more and better knowledge as it becomes available.</p>fixing broken commit messages2009-01-12T00:00:00+00:00http://gitready.com/advanced/2009/01/12/fixing-broken-commit-messages<p>You just committed that awesome feature/test/bug, but something just isn’t right. Either some information isn’t filled out, the commit message is wrong, or something else is just messed up. Let’s go over what can be done to fix the associated data after the fact.</p>
<p>Fixing the previous commit is very simple. Just use</p>
<p><code>git commit --amend</code></p>
<p>And that will fire up the commit patch in $<span class="caps">EDITOR</span> for you to mess with. Simply edit the message right on the top line of the file, save, quit and you’re done.</p>
<p>Now let’s say you’ve got a few commits to fix, or the commit that is broken is a few commits back. This process is a little more complex, but isn’t too bad. (Thanks to <a href="http://blog.fallingsnow.net/">Evan Phoenix</a> for this one.)</p>
<p>Here’s the scenario: the last 3 commits don’t have the right username, email, or perhaps commit message. Let’s start by generating patch files for the commits:</p>
<p><code>git format-patch HEAD^^^</code></p>
<p>That will generate files in the form of 0001-commit-message that contains the commit diff and metadata. One note with the 3 caret symbols: just add one for each commit you need to go back, and be consistent! <strong><span class="caps">EDIT</span>:</strong> You can also refer to past commits with the syntax <span class="caps">HEAD</span>~n, so for this example we’d use <span class="caps">HEAD</span>~3. Go ahead and edit these files so they have the proper information. Once that’s done, we’ll need to reset our repository back a few commits:</p>
<p><code>git reset --hard HEAD^^^</code></p>
<p>Now we can apply each commit to fix the information. Make sure you do it in the right order! (Usually it’s ascending)</p>
<pre>
git am < 0001...
git am < 0002...
git am < 0003...
</pre>
<p>Now if you check <code>git log</code> you should see the right information. If for some reason stuff got messed up, doing a</p>
<p><code>git reset --hard origin/master</code></p>
<p>will bring you back to your original changes. Once you’ve got the information fixed, you’ll need to do a force push on the repo:</p>
<p><code>git push -f</code></p>
<p>If you don’t add the <code>-f</code>, git will complain. <strong><span class="caps">WARNING</span>!</strong> Just be aware that modifying commit messages may muck up other’s repositories and should be used with caution. In fact, other developers may flat out hate you for doing this. If it’s far back enough it’s probably a <a href="http://www.youtube.com/watch?v=BytKSy8M4bk">bad idea to rewrite history anyway.</a></p>
<p>If you know of any unexpected or uncovered consequences please let us know in the comments. Another tip in the future will cover fixing the actual committed files and making sure that all repos are up to date.</p>reverting files2009-01-11T00:00:00+00:00http://gitready.com/beginner/2009/01/11/reverting-files<p>This is a topic that is a constant source of confusion for many git users, basically because there’s more than one way to skin the proverbial cat. Let’s go over some of the basic commands that you’ll need to undo your work.</p>
<p>So, you just want to revert one file back to its original state:</p>
<p><code>git checkout <file></code></p>
<p>One problem with this is that you may have is that a file and branch named the same. Since the checkout command is used for both reverting files and swapping out to a different branch, you’ll need to use this syntax (thanks, <a href="http://norbauer.com/notebooks/code/notes/git-revert-reset-a-single-file">Norbauer</a>)</p>
<p><code>git checkout -- <file></code></p>
<p>If you want to throw out all of the changes you’ve been working on, there’s two ways to do that.</p>
<p><code>git checkout -f</code> or <code>git reset --HARD</code></p>
<p>Once these commands are run you’ll lose all of the work that isn’t committed in your directory, so make sure to take caution when using them.</p>
<p>Also, be aware that <a href="http://bryan-murdock.blogspot.com/2007/07/git-revert-is-not-equivalent-to-svn.html">‘git revert’ is not equivalent to ‘svn revert’!</a> <code>git-revert</code> is used to reverse commits, something another tip will cover in the future.</p>stashing your changes2009-01-10T00:00:00+00:00http://gitready.com/beginner/2009/01/10/stashing-your-changes<p>Stashing is a great way to pause what you’re currently working on and come back to it later. For example, if you working on that awesome, brand new feature but someone just found a bug that you need to fix. Add your changes to the index using</p>
<p><code>git add .</code></p>
<p>Or add individual files to the index, your pick. Stash your changes away with:</p>
<p><code>git stash</code></p>
<p>And boom! You’re back to your original working state. Got that bug fixed? Bring your work back with:</p>
<p><code>git stash apply</code></p>
<p>You can also do multiple layers of stashes, so make sure to use</p>
<p><code>git stash list</code></p>
<p>To check out all of your current ones. If you need to apply a stash from deeper in the stack, that’s easy too. Here’s how to apply the second stash you’ve got:</p>
<p><code>git stash apply stash@{1}</code></p>
<p>You can also easily apply the top stash on the stack by using (<a href="http://jamesgolick.com/">Thanks jamesgolick!</a>):</p>
<p><code>git stash pop</code></p>
<p>A note with this command, it deletes that stash for good, while apply does not. You can manually delete stashes with:</p>
<p><code>git stash drop <id></code></p>
<p>Or delete all of the stored stashes with:</p>
<p><code>git stash clear</code></p>checkout tracked remote branch2009-01-09T00:00:00+00:00http://gitready.com/intermediate/2009/01/09/checkout-remote-tracked-branch<p>I frequently need to do this when setting up or syncing my various machines, and I seem to forget the command all the time. So let’s say you’ve got more than one branch on your remote, and you want to bring it down into your local repository as well:</p>
<p style="text-align:center;"><img src="http://gitready.com/images/branches.png" alt="" /></p>
<p>Viewing information on the remote should look something like this:</p>
<pre>
$ git remote show origin
* remote origin
URL: *************
Remote branch merged with 'git pull'
while on branch master
master
Tracked remote branches
haml master
</pre>
<p>Luckily, the command syntax for this is quite simple:</p>
<pre>
git checkout --track -b
<local branch> <remote>/<tracked branch>
</pre>
<p>So in my case, I used this command:</p>
<p><code>git checkout --track -b haml origin/haml</code></p>
<p>You can also use a simpler version:</p>
<p><code>git checkout -t origin/haml</code></p>