gitscm-old/views/svn.erb

530 строки
21 KiB
Plaintext
Исходник Обычный вид История

2011-09-21 22:08:34 +04:00
<div class="doc-section">
<h1>Git - SVN Crash Course</h1>
<p>Welcome to the Git version control system! Here we will briefly
introduce you to Git usage based on your current Subversion knowledge. You will
need the latest <a href="http://git.or.cz/">Git</a> installed;
There is also a potentially useful
<a href="http://www.kernel.org/pub/software/scm/git/docs/gittutorial.html">
tutorial</a> in the Git documentation.</p>
<div class="doc-toc">
<ul>
<li><a href="#read">How to Read Me</a></li>
<li><a href="#know">Things To Know</a></li>
<li><a href="#commit">Commiting</a></li>
<li><a href="#browse">Browsing</a></li>
<li><a href="#branch">Tagging and Branching</a></li>
<li><a href="#merge">Merging</a></li>
<li><a href="#remote">Going Remote</a></li>
<li><a href="#share">Sharing the Work</a></li>
</ul>
</div>
<div style="text-align:center;"><table class="relnotes" style="margin-left: auto; margin-right: auto; border: 1px">
<tr><td style="text-align:center;">
<p style="margin: 0em 0.4em">If you are just after tracking someone else's project,
this get you started quickly:</p>
<p/>
<table class="ccmd" style="margin:0em; margin-left: auto; margin-right: auto;"><tr>
<td class="g">git clone <em>url</em><br />git pull</td>
<td>svn&nbsp;checkout&nbsp;<em>url</em><br />svn update</td>
</tr></table>
</td></tr>
</table></div>
<hr />
<h2 id="read">How to Read Me</h2>
<p>In those small tables, at the left we always list the Git commands
for the task, while at the right the corresponding Subversion commands you would use
for the job are listed. If you are in hurry, just skimming over them should
give you a good idea about the Git usage basics.</p>
<p>Before running any command the first time, it's recommended that you
at least quickly skim through its manual page. Many of the commands have
very useful and interesting features (that we won't list here) and sometimes
there are some extra notes you might want to know. There's a quick usage
help available for the Git commands if you pass them the <code>-h</code>
switch.</p>
<h2 id="know">Things You Should Know</h2>
<p>There are couple important concepts it is good to know when
starting with Git. If you are in hurry though, you can skip this
section and only get back to it when you get seriously confused;
it should be possible to pick up with just using your intuition.</p>
<ul>
<li>
<b>Repositories.</b>
With Subversion, for each project there is a single repository at some
detached central place where all the history is and which you checkout
and commit into. Git works differently, each copy of the project tree
(we call that the <em>working copy</em>) carries its own repository
around (in the <code>.git</code> subdirectory in the project tree root).
So you can have local and remote branches.
You can also have a so-called <em>bare repository</em> which is not
attached to a working copy; that is useful especially when you want
to publish your repository. We will get to that.
</li>
<li>
<b>URL.</b>
In Subversion the <em>URL</em> identifies the location of the repository
and the path inside the repository, so you organize the layout of the
repository and its meaning. Normally you would have <code>trunk/</code>,
<code>branches/</code> and <code>tags/</code> directories. In Git
the <em>URL</em> is just the location of the repository, and it always
contains branches and tags. One of the branches is the default (normally named
master).
</li>
<li>
<b>Revisions.</b>
Subversion identifies revisions with ids of decimal numbers growing
monotonically which are typically small (although they can get quickly
to hundreds of thousands for large projects). That is impractical in distributed systems like Git. Git
identifies revisions with SHA1 ids, which are long 160-bit numbers
written in hexadecimal. It may look scary at first, but in practice it is
not a big hurdle - you can refer to the latest revision by <code>HEAD</code>,
its parent as <code>HEAD^</code> and its parent as <code>HEAD^^ = HEAD~2</code>
(you can go on adding carrets),
cut'n'paste helps a lot and you can write only the few leading digits
of a revision - as long as it is unique, Git will guess the rest.
(You can do even more advanced stuff with revision specifiers, see the
<a href="http://www.kernel.org/pub/software/scm/git/docs/git-rev-parse.html">git-rev-parse manpage</a> for details.)
</li>
<li>
<b>Commits.</b>
Each commit has an <em>author</em> and a <em>committer</em> field,
which record who and when <em>created</em> the change and who <em>committed</em> it
(Git is designed to work well with patches coming by mail - in that case,
the author and the committer will be different). Git will try to guess
your realname and email, but especially with email it is likely to get it wrong.
You can check it using <code class="g">git config -l</code> and set them with:
<pre>
git config --global user.name "Your Name Comes Here"
git config --global user.email you@yourdomain.example.com
</pre>
</li>
<li>
<b>Commands.</b>
The Git commands are in the form <code>git command</code>.
You can interchangeably use the <code>git-command</code>
form as well.
</li>
<li>
<b>Colors.</b>
Git can produce colorful output with some commands; since
some people hate colors way more than the rest likes them, by default
the colors are turned off. If you would like to have colors in your
output:
<pre>
git config --global color.diff auto
git config --global color.status auto
git config --global color.branch auto
</pre>
</li>
<li>
<b>Visualize.</b>
You may find it convenient to watch your repository using
the <code class="g">gitk</code> repository as you go.
</li>
</ul>
<h2 id="commit">Commiting</h2>
<p>For the first introduction, let's make your project tracked by Git
and see how we get around to do daily development in it. Let's
<code>cd</code> to the directory with your project and initialize
a brand new Git repository with it:</p>
<table class="ccmd">
<tr><td class="g">git init<br/>git add .<br/>git commit</td>
<td>svnadmin create <em>repo</em><br/>svn import <em>file://repo</em></td></tr></table>
<p><code>git init</code> will initialize the repository,
<code>git add .</code> will add all the files under the current directory
and <code>git commit</code> will create the
initial import, given that repositories are coupled with working copies.</p>
<p>Now your tree is officially tracked by Git. You can explore the
<code class="g">.git</code> subdirectory a bit if you want, or don't if you
don't care. Do some random changes to your tree now - poke into few
files or such. Let's check what we've done:</p>
<table class="ccmd"><tr>
<td class="g">git diff</td>
<td>svn diff | less</td>
</tr></table>
<p>That's it. This is one of the more powerful commands. To get a diff with an
specific revision and path do:</p>
<table class="ccmd"><tr>
<td class="g">git diff <em>rev</em> <em>path</em></td>
<td>svn diff -r<em>rev</em> <em>path</em></td>
</tr></table>
<p>Git embeds special information in
the diffs about adds, removals and mode changes:</p>
<table class="ccmd"><tr>
<td class="g">git apply</td>
<td>patch -p0</td>
</tr></table>
<p>That will apply the patch while telling Git about and performing
those "meta-changes".</p>
<p>There is a more concise representation of changes available:</p>
<table class="ccmd"><tr>
<td class="g">git status</td>
<td>svn status</td>
</tr></table>
<p>This will show the concise changes summary as well as list any files
that you haven't either ignored or told Git about. In addition,
it will also show at the top which branch you are in.</p>
<p>While we are at the status command, over time plenty of the
"Untracked files" will get in there, denoting files not tracked by Git.
Wait a moment if you want to add them, run <code class="g">git clean</code>
if you want to get rid of all of them, or add them to the <code class="g">.gitignore</code>
file if you want to keep them around untracked (works the same as the <code>svn:ignore</code>
property in SVN).</p>
<p>To restore a file from the last revision:</p>
<table class="ccmd"><tr>
<td class="g">git checkout <em>path</em></td>
<td>svn revert <em>path</em></td>
</tr></table>
<p>You can restore everything or just specified files.</p>
<p>So, just like in SVN, you need to tell Git when you add, move or
remove any files:</p>
<table class="ccmd"><tr>
<td class="g">git add <em>file</em>
<br />git rm <em>file</em>
<br />git mv <em>file</em></td>
<td>svn add <em>file</em><br />svn rm <em>file</em><br />svn mv <em>file</em></td></tr></table>
<p>You can also recursively add/remove whole directories and so on;
Git's cool!</p>
<p>So, it's about time we commit our changes. Big surprise
about the command:</p>
<table class="ccmd"><tr>
<td class="g">git commit -a</td>
<td>svn commit</td>
</tr></table>
<p>to commit all the changes or, as with Subversion,
you can limit the commit only to specified files
and so on. A few words on the commit message: it is <em>customary</em>
to have a short commit summary as the first line of the message,
because various tools listing commits frequently show only the
first line of the message. You can specify the commit message
using the <code>-m</code> parameter as you are used, but
you can pass several <code>-m</code> arguments and they will create
separate paragraphs in the commit message:</p>
<p>If you don't pass any <code>-m</code> parameter or pass
the <code>-e</code> parameter, your favorite <code>$EDITOR</code>
will get run and you can compose your commit message there,
just as with Subversion. In addition, the list of files to be committed
is shown.</p>
<p>And as a bonus, if you pass it the <code>-v</code> parameter
it will show the whole patch being committed in the editor
so that you can do a quick last-time review.</p>
<p>By the way, if you screwed up committing, there's not much you
can do with Subversion, except using some enigmatic <code>svnadmin</code>
subcommands. Git does it better - you can amend your latest commit
(re-edit the metadata as well as update the tree) using
<code class="g">git commit --amend</code>, or toss your latest
commit away completely using <code class="g">git reset HEAD^</code>,
this will not change the working tree.</p>
<h2 id="browse">Browsing</h2>
<p>Now that we have committed some stuff, you might want to review
your history:</p>
<table class="ccmd"><tr>
<td class="g">git log<br />git blame <em>file</em></td>
<td>svn log | less<br />svn blame <em>file</em></td>
</tr></table>
<p>The log command works quite similar in SVN and Git; again,
<code>git log</code> is quite powerful, please look through
its options to see some of the stuff it can do.</p>
<p>The blame command is more powerful as it can detect the movement of lines,
even with file copies and renames. But there is a
big chance that you probably want to do something different! Usually,
when using annotate you are looking for the origin of some piece of
code, and the so-called <em>pickaxe</em> of Git is much more comfortable
tool for that job (<code>git log -S<em>string</em></code> shows the
commits which add or remove any file data matching <em>string</em>).</p>
<p>You can see the contents of a file, the listing of a directory or
a commit with:</p>
<table class="ccmd"><tr>
<td class="g">git show <em>rev</em>:<em>path/to/file</em>
<br />git&nbsp;show&nbsp;<em>rev</em>:<em>path/to/directory</em>
<br />git show <em>rev</em></td>
<td>svn cat <em>url</em>
<br />svn list <em>url</em>
<br />svn log -r<em>rev</em> <em>url</em>
<br />svn diff -c<em>rev</em> <em>url</em></td>
</tr></table>
<h2 id="branch">Tagging and branching</h2>
<p>Subversion marks certain checkpoints in history through copies, the copy is
usually placed in a directory named tags. Git tags are much more powerful.
The Git tag can have an arbitrary description attached (the first
line is special as in the commit case), some people actually store
the whole release announcements in the tag descriptions. The identity
of the person who tagged is stored (again following the same rules
as identity of the committer). You can tag other objects than commits (but
that is conceptually rather low-level operation).
And the tag can be cryptographically PGP signed to verify the identity
(by Git's nature of working, that signature also confirms the validity
of the associated revision, its history and tree). So, let's do it:</p>
<table class="ccmd"><tr>
<td class="g">git tag -a <em>name</em></td>
<td>svn copy http://example.com/svn/trunk
http://example.com/svn/tags/<em>name</em></td>
</tr></table>
<p>To list tags and to show the tag message:</p>
<table class="ccmd"><tr>
<td class="g">git tag -l<br />git show <em>tag</em></td>
<td>svn&nbsp;list&nbsp;http://example.com/svn/<em>tags/</em>
<br />svn&nbsp;log --limit&nbsp;1&nbsp;http://example.com/svn/tags/<em>tag</em></td>
</tr></table>
<p>Like Subversion, Git can do branches (surprise surprise!). In Subversion,
you basically copy your project to a subdirectory. In Git, you tell it,
well, to create a branch.</p>
<table class="ccmd"><tr>
<td class="g">git branch <em>branch</em>
<br />git&nbsp;checkout&nbsp;<em>branch</em></td>
<td>svn copy http://example.com/svn/trunk
http://example.com/svn/branches/<em>branch</em>
<br />svn switch
http://example.com/svn/branches/<em>branch</em></td>
</tr></table>
<p>The first command creates a branch, the second command switches
your tree to a certain branch. You can pass an extra argument to
<code>git branch</code> to base your new branch on a different
revision than the latest one.</p>
<p>You can list your branches conveniently using the aforementioned
<code>git-branch</code> command without arguments the listing of branches.
The current one is denoted by an "*".</p>
<table class="ccmd"><tr>
<td class="g">git branch</td>
<td>svn list http://example.com/svn/branches/</td>
</tr></table>
<p>To move your tree to some older revision, use:</p>
<table class="ccmd"><tr>
<td class="g">git checkout <em>rev</em>
<br />git checkout <em>prevbranch</em></td>
<td>svn update -r <em>rev</em><br />svn update</td>
</tr></table>
<p>or you could create a temporary branch. In Git you can make commits on
top of the older revision and use it as another branch.</p>
<h2 id="merge">Merging</h2>
<p>Git supports merging between branches much better than Subversion - history
of both branches is preserved over the merges and repeated merges
of the same branches are supported out-of-the-box. Make sure you are on
one of the to-be-merged branches and merge the other one now:</p>
<table class="ccmd"><tr>
<td class="g">git merge <em>branch</em></td>
<td>
svn merge -r 20:HEAD
http://example.com/svn/branches/<em>branch</em>
<br /><em>(assuming the branch was created in revision 20 and
you are inside a working copy of trunk)</em>
</td>
</tr></table>
<p>If changes were made on only one of the branches since the last merge,
they are simply replayed on your other branch (so-called <em>fast-forward merge</em>).
If changes were made on both branches, they are merged intelligently
(so-called <em>three-way merge</em>): if any changes conflicted, <code>git merge</code>
will report them and let you resolve them, updating the rest of the tree
already to the result state; you can <code>git commit</code> when you resolve
the conflicts. If no changes conflicted, a commit is made automatically with
a convenient log message (or you can do
<code class="g">git merge --no-commit <em>branch</em></code> to review the merge
result and then do the commit yourself).</p>
<p>Aside from merging, sometimes you want to just pick one commit from
a different branch. To apply the changes in revision <em>rev</em> and commit
them to the current branch use:</p>
<table class="ccmd"><tr>
<td class="g">git cherry-pick <em>rev</em></td>
<td>svn merge -c <em>rev</em> <em>url</em></td>
</tr></table>
<h2 id="remote">Going Remote</h2>
<p>So far, we have neglected that Git is a <em>distributed</em> version
control system. It is time for us to set the record straight - let's grab
some stuff from remote sites.</p>
<p>If you are working on someone else's project, you usually want to <em>clone</em>
its repository instead of starting your own. We've already mentioned that at the top
of this document:</p>
<table class="ccmd"><tr>
<td class="g">git clone <em>url</em></td>
<td>svn&nbsp;checkout&nbsp;<em>url</em></td>
</tr></table>
<p>Now you have the default branch (normally <code>master</code>),
but in addition you got all the remote branches and tags.
In clone's default setup, the default local branch tracks
the <em>origin</em> remote, which represents the default branch in the
remote repository.</p>
<p><em>Remote branch</em>, you ask? Well, so far we have worked
only with local branches. Remote branches are a mirror image of branches
in remote repositories and you don't ever switch to them directly or write
to them. Let me repeat - you never mess with remote branches. If you want
to switch to a remote branch, you need to create a corresponding local
branch which will "track" the remote branch:</p>
<table class="ccmd"><tr>
<td class="g">
git checkout -b <em>branch</em> origin/<em>branch</em></td>
<td>svn&nbsp;switch&nbsp;<em>url</em></td></tr></table>
<p>You can add more remote branches to a cloned repository, as well as just
an initialized one, using <code class="g">git remote add <em>remote</em> <em>url</em></code>.
The command <code class="g">git remote</code> lists all the remotes
repositories and <code class="g">git remote show <em>remote</em></code> shows
the branches in a remote repository.</p>
<p>Now, how do you get any new changes from a remote repository?
You fetch them: <code class="g">git fetch</code>.
At this point they are in your repository and you can examine them using
<code>git log <em>origin</em></code> (<code>git log HEAD..<em>origin</em></code>
to see just the changes you don't have in your branch), diff them, and obviously, merge them - just do
<code>git merge <em>origin</em></code>. Note that if you don't specify a branch
to fetch, it will conveniently default to the tracking remote.</p>
<p>Since you frequently just fetch + merge the tracking remote branch,
there is a command to automate that:</p>
<table class="ccmd"><tr>
<td class="g">git pull</td>
<td>svn update</td>
</tr></table>
<h2 id="share">Sharing the Work</h2>
<p>Your local repository can be used by others to <em>pull</em> changes, but
normally you would have a private repository and a public repository.
The public repository is where everybody pulls and you... do the
opposite? <em>Push</em> your changes? Yes!
We do <code class="g">git push <em>remote</em></code> which will push
all the local branches with a corresponding remote branch - note that this works
generally only over SSH (or HTTP but with special webserver setup).
It is highly recommended to setup a SSH key and an SSH agent mechanism
so that you don't have to type in a password all the time.</p>
<p>One important thing is that you should push only to remote branches
that are not currently checked out on the other side (for the same
reasons you never switch to a remote branch locally)! Otherwise the
working copy at the remote branch will get out of date and confusion
will ensue. The best way to avoid that is to push only to remote
repositories with no working copy at all - so called <em>bare</em>
repositories which are commonly used for public access or developers'
meeting point - just for exchange of history where a checked out copy
would be a waste of space anyway. You can create such a repository.
See <a href="http://www.kernel.org/pub/software/scm/git/docs/user-manual.html#setting-up-a-public-repository">Setting up a public repository</a> for details.</p>
<p>Git can work with the same workflow as Subversion, with a group of developers
using a single repository for exchange of their work. The only change
is that their changes aren't submitted automatically but they have
to push (however, you can setup a post-commit hook that will push for you
every time you commit; that loses the flexibility to fix up a screwed
commit, though). The developers must have either an entry in htaccess
(for HTTP DAV) or a UNIX account (for SSH). You can restrict their
shell account only to Git pushing/fetching by using the
<code class="g">git-shell</code> login shell.</p>
<p>You can also exchange patches by mail. Git has very good support
for patches incoming by mail. You can apply them by feeding mailboxes
with patch mails to <code class="g">git am</code>. If you
want to <em>send</em> patches use <code class="g">git format-patch</code> and
possibly <code class="g">git send-email</code>.
To maintain a set of patches it is best to use
the <strong>StGIT</strong> tool (see
the <a href="stgit.html">StGIT Crash Course</a>).</p>
<p>If you have any questions or problems which are not obvious from
the documentation, please contact us at the <strong>Git mailing list</strong>
at <a href="mailto:git@vger.kernel.org">git@vger.kernel.org</a>.
We hope you enjoy using Git!</p>
</div>