зеркало из https://github.com/git/gitscm-old.git
530 строки
21 KiB
Plaintext
530 строки
21 KiB
Plaintext
<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 checkout <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 show <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 list http://example.com/svn/<em>tags/</em>
|
|
|
|
<br />svn log --limit 1 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 checkout <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 checkout <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 switch <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> |