Modernized command invocations a bit.
[gitmagic/dustin.git] / grandmaster.txt
blobdbcfc630d2283184a3bed27239fa28b408d10d48
1 == Git Grandmastery ==
3 This pretentiously named page is my dumping ground for uncategorized Git tricks.
5 === Source Releases ===
7 For my projects, Git tracks exactly the files I'd like to archive and release to users. So to create a tarball of the source code, I run:
9  $ git archive --format==tar --prefix==proj-1.2.3/ HEAD
11 === Changelog Generation ===
13 It's good practice to keep a http://en.wikipedia.org/wiki/Changelog[changelog], and some projects even require it. If you've been committing frequently, which you should, generate a Changelog by typing
15  $ git log > ChangeLog
17 === Git Over SSH, HTTP ===
19 Suppose you have ssh access to your web server, but it does not have Git installed. Then download, compile and install Git in your account.
21 Create a repository in your web directory:
23  $ GIT_DIR==proj.git git init
25 and in the "proj.git" directory, run
27  $ git --bare update-server-info
28  $ chmod a+x hooks/post-update
30 From your computer, you can push via ssh:
32  $ git push web.server:/path/to/proj.git master
34 and people can get your project via
36  $ git clone http://web.server/proj.git
38 === Commit What Changed ===
40 Telling Git when you've added, deleted and renamed files gets tedious. Instead, try:
42  $ git ls-files -d -m -o -z | xargs -0 git update-index --add --remove
44 and Git will look at the files in the current directory and work everything out for itself. The *-z* and *-0* options prevent ill side-effects from filenames containing strange characters.
46 You might want it to ignore particular files:
48  $ git ls-files -d -m -o -z -x *.tmp | xargs -0 git update-index --add --remove
50 If you have a big list of directories and files that should never be version controlled, type them into a separate file named ".gitignore" and run:
52  $ git ls-files -d -m -o -z -X .gitignore | xargs -0 git update-index --add --remove
54 You can also exclude files on a per-directory basis. See the help page.
56 === I Stand Corrected ===
58 Did you just commit, but wish you had typed a different message? Realized you forgot to add a file? Then:
60  $ git commit --amend
62 can help you out.
64 Since this changes the history, only do this if you have yet to push your changes, otherwise your tree will diverge from other trees. Of course, if you control all the other trees too, then there is no problem since you can always overwrite them.
66 === ... And Then Some ===
68 Let's suppose the previous problem is ten times worse. After a lengthy session you've made a bunch of commits. But you're not quite happy with the way they're organized, and some of those commit messages could use rewording. This is quite likely if you've been saving early and saving often. Then type
70  $ git rebase -i HEAD~10
72 and the last 10 commits will appear in your favourite $EDITOR. A sample excerpt:
74     pick 5c6eb73 Added repo.or.cz link
75     pick a311a64 Reordered analogies in "Work How You Want"
76     pick 100834f Added push target to Makefile
78 Then:
80 - Remove commits by deleting lines.
81 - Reorder commits by reordering lines.
82 - Replace "pick" with "edit" to mark a commit for amending.
83 - Replace "pick" with "squash" to merge a commit with the previous one.
85 Next run *git commit --amend* if you marked a commit for editing. Otherwise, run:
87  $ git rebase --continue
89 Again, only do this if no one else has a clone of your tree.
91 === Local Changes Last ===
93 You're working on an active project. You make some local commits over time, and
94 then you sync with the official tree with a merge. This cycle repeats itself a few times before you're ready to push to the central tree.
96 But now the history in your local Git clone is a messy jumble of your changes and the official changes. You'd prefer to see all your changes in one contiguous section, and after all the official changes.
98 This is a job for *git rebase* as described above. In many cases you can use
99 the *--onto* flag and avoid interaction.
101 Also see the manpage for other amazing uses of this command, which really deserves a chapter of its own. You can split commits. You can even rearrange branches of a tree!
103 === My Commit Is Too Big! ===
105 Have you neglected to commit for too long? Been coding furiously and forgotten
106 about source control until now? Made a series of unrelated changes, because
107 that's your style?
109 No worries, use *git add -i* or *git commit -i* to interactively choose which
110 edits should belong to the next commit.
112 === Don't Lose Your HEAD ===
114 The HEAD tag is like a cursor that normally points at the latest commit, advancing with each new commit. Some Git commands let you move it. For example:
116  $ git reset HEAD~3
118 will move the HEAD three commits backwards in time. Thus all Git commands now act as if you hadn't made those last three commits, while your files remain in the present. See the git reset man page for some applications.
120 But how can you go back to the future? The past commits do not know anything of the future.
122 If you have the SHA1 of the original HEAD then:
124  $ git reset SHA1
126 But suppose you never took it down? Don't worry, for commands like these, Git saves the original HEAD as a tag called ORIG_HEAD, and you can return safe and sound with:
128  $ git reset ORIG_HEAD
130 === HEAD-hunting ===
132 Perhaps ORIG_HEAD isn't enough. Perhaps you've just realized you made a monumental mistake last month and you need to go back to an ancient commit in a long-forgotten branch.
134 It's hard to lose Git commits permanently, even after deleting branches. As long as you never run git gc, your commits are preserved forever and can be restored at any time.
136 The trouble is finding the appropriate hash. You could look at all the hash values in `.git/objects` and use trial and error to find the one you want. But there's a much easier way.
138 Git records every hash of a commit it computes in `.git/logs`. The subdirectory `refs` contains the history of all activity on all branches, while the file `HEAD` shows every hash value it has ever taken. The latter can be used to find hashes of commits on branches that have been accidentally lopped off.
140 Eventually, you may want to run git gc to recover space. Be aware that doing so prevents you from recovering lost HEADs.
142 === Building On Git ===
144 In true UNIX fashion, Git's design allows it to be easily used as a low-level component of other programs. There are GUI interfaces, web interfaces, alternative command-line interfaces, and perhaps soon you will have a script or two of your own that calls Git.
146 One easy trick is to use built-in git aliases shorten your most frequently used
147 commands:
149   $ git config --global alias.co checkout
150   $ git config --global --get-regexp alias  # display current aliases
151   alias.co checkout
152   $ git co foo                              # same as 'git checkout foo'
154 Another is to print the current branch in the prompt, or window title.
155 Invoking
157   $ git symbolic-ref HEAD
159 shows the current branch name. In practice, you most likely want to remove
160 the "refs/heads/" and ignore errors:
162   $ git symbolic-ref HEAD 2> /dev/null | cut -b 12-
164 See http://git.or.cz/[the Git homepage] for more examples.