The core git is often called "plumbing", with the prettier user
interfaces on top of it called "porcelain". You may not want to use the
plumbing directly very often, but it can be good to know what the
-plumbing does for when the porcelain isn't flushing...
+plumbing does for when the porcelain isn't flushing.
+
+The material presented here often goes deep describing how things
+work internally. If you are mostly interested in using git as a
+SCM, you can skip them during your first pass.
+
+[NOTE]
+And those "too deep" descriptions are often marked as Note.
+
+[NOTE]
+If you are already familiar with another version control system,
+like CVS, you may want to take a look at
+link:everyday.html[Everyday GIT in 20 commands or so] first
+before reading this.
Creating a git repository
The first step is trivial: when you want to tell git about any changes
to your working tree, you use the `git-update-index` program. That
program normally just takes a list of filenames you want to update, but
-to avoid trivial mistakes, it refuses to add new entries to the cache
+to avoid trivial mistakes, it refuses to add new entries to the index
(or remove existing ones) unless you explicitly tell it that you're
adding a new entry with the `\--add` flag (or removing an entry with the
`\--remove`) flag.
actually saved away the contents of your files into the git object
database.
-Updating the cache did something else too: it created a `.git/index`
+Updating the index did something else too: it created a `.git/index`
file. This is the index that describes your current working tree, and
something you should be very aware of. Again, you normally never worry
about the index file itself, but you should be aware of the fact that
A common shorthand for `git-diff-files -p` is to just write `git
diff`, which will do the same thing.
+------------
+$ git diff
+diff --git a/hello b/hello
+index 557db03..263414f 100644
+--- a/hello
++++ b/hello
+@@ -1 +1,2 @@
+ Hello World
++It's a new day for git
+------------
+
Committing git state
--------------------
Write whatever message you want, and all the lines that start with '#'
will be pruned out, and the rest will be used as the commit message for
the change. If you decide you don't want to commit anything after all at
-this point (you can continue to edit things and update the cache), you
+this point (you can continue to edit things and update the index), you
can just leave an empty message. Otherwise `git commit` will commit
the change for you.
fatal: Merge requires file-level merging
Nope.
...
- merge: warning: conflicts during merge
- ERROR: Merge conflict in hello.
- fatal: merge program failed
+ Auto-merging hello
+ CONFLICT (content): Merge conflict in hello
Automatic merge failed/prevented; fix up by hand
----------------
------------------------------------------------
$ git show-branch master mybranch
-* [master] Merged "mybranch" changes.
+* [master] Merge work in mybranch
! [mybranch] Some work.
--
-+ [master] Merged "mybranch" changes.
++ [master] Merge work in mybranch
++ [mybranch] Some work.
------------------------------------------------
------------------------------------------------
$ git show-branch master mybranch
-! [master] Merged "mybranch" changes.
- * [mybranch] Merged "mybranch" changes.
+! [master] Merge work in mybranch
+ * [mybranch] Merge work in mybranch
--
-++ [master] Merged "mybranch" changes.
+++ [master] Merge work in mybranch
------------------------------------------------
HTTP(S)::
`http://remote.machine/path/to/repo.git/`
+
-HTTP and HTTPS transport are used only for downloading. They
-first obtain the topmost commit object name from the remote site
-by looking at `repo.git/info/refs` file, tries to obtain the
+Downloader from http and https URL
+first obtains the topmost commit object name from the remote site
+by looking at the specified refname under `repo.git/refs/` directory,
+and then tries to obtain the
commit object by downloading from `repo.git/objects/xx/xxx\...`
using the object name of that commit object. Then it reads the
commit object to find out its parent commits and the associate
The 'commit walkers' are sometimes also called 'dumb
transports', because they do not require any git aware smart
server like git Native transport does. Any stock HTTP server
-would suffice.
+that does not even support directory index would suffice. But
+you must prepare your repository with `git-update-server-info`
+to help dumb transport downloaders.
+
There are (confusingly enough) `git-ssh-fetch` and `git-ssh-upload`
programs, which are 'commit walkers'; they outlived their
`git-merge-one-file` script is called with parameters to
describe those three versions, and is responsible to leave the
-merge results in the working tree and register it in the index
-file. It is a fairly straightforward shell script, and
-eventually calls `merge` program from RCS suite to perform the
+merge results in the working tree.
+It is a fairly straightforward shell script, and
+eventually calls `merge` program from RCS suite to perform a
file-level 3-way merge. In this case, `merge` detects
conflicts, and the merge result with conflict marks is left in
-the working tree, while the index file is updated with the
-version from the current branch (this is to make `git diff`
-useful after this step). This can be seen if you run `ls-files
+the working tree.. This can be seen if you run `ls-files
--stage` again at this point:
------------
$ git-ls-files --stage
100644 7f8b141b65fdcee47321e399a2598a235a032422 0 example
-100644 06fa6a24256dc7e560efa5687fa84b51f0263c3a 0 hello
+100644 263414f423d0e4d70dae8fe53fa34614ff3e2860 1 hello
+100644 06fa6a24256dc7e560efa5687fa84b51f0263c3a 2 hello
+100644 cc44c73eb783565da5831b4d820c962954019b69 3 hello
------------
-As you can see, there is no unmerged paths in the index file.
This is the state of the index file and the working file after
`git merge` returns control back to you, leaving the conflicting
-merge for you to resolve.
+merge for you to resolve. Notice that the path `hello` is still
+unmerged, and what you see with `git diff` at this point is
+differences since stage 2 (i.e. your version).
Publishing your work
2. Prepare a public repository accessible to others.
+
If other people are pulling from your repository over dumb
-transport protocols, you need to keep this repository 'dumb
-transport friendly'. After `git init-db`,
+transport protocols (HTTP), you need to keep this repository
+'dumb transport friendly'. After `git init-db`,
`$GIT_DIR/hooks/post-update` copied from the standard templates
would contain a call to `git-update-server-info` but the
`post-update` hook itself is disabled by default -- enable it
-with `chmod +x post-update`.
+with `chmod +x post-update`. This makes sure `git-update-server-info`
+keeps the necessary files up-to-date.
3. Push into the public repository from your primary
repository.
the "project lead" person does.
3. Copy over the packed files from "project lead" public
- repository to your public repository.
+ repository to your public repository, unless the "project
+ lead" repository lives on the same machine as yours. In the
+ latter case, you can use `objects/info/alternates` file to
+ point at the repository you are borrowing from.
4. Push into the public repository from your primary
repository. Run `git repack`, and possibly `git prune` if the
For this, set up a public repository on a machine that is
reachable via SSH by people with "commit privileges". Put the
committers in the same user group and make the repository
-writable by that group.
+writable by that group. Make sure their umasks are set up to
+allow group members to write into directories other members
+have created.
You, as an individual committer, then:
back before you push your work when it happens.
+Advanced Shared Repository Management
+-------------------------------------
+
+Being able to push into a shared repository means being able to
+write into it. If your developers are coming over the network,
+this means you, as the repository administrator, need to give
+each of them an SSH access to the shared repository machine.
+
+In some cases, though, you may not want to give a normal shell
+account to them, but want to restrict them to be able to only
+do `git push` into the repository and nothing else.
+
+You can achieve this by setting the login shell of your
+developers on the shared repository host to `git-shell` program.
+
+[NOTE]
+Most likely you would also need to list `git-shell` program in
+`/etc/shells` file.
+
+This restricts the set of commands that can be run from incoming
+SSH connection for these users to only `receive-pack` and
+`upload-pack`, so the only thing they can do are `git fetch` and
+`git push`.
+
+You still need to create UNIX user accounts for each developer,
+and put them in the same group. Make sure that the repository
+shared among these developers is writable by that group.
+
+You can implement finer grained branch policies using update
+hooks. There is a document ("control access to branches") in
+Documentation/howto by Carl Baldwin and JC outlining how to (1)
+limit access to branch per user, (2) forbid overwriting existing
+tags.
+
+
Bundling your work together
---------------------------
It is likely that you will be working on more than one thing at
-a time. It is easy to use those more-or-less independent tasks
+a time. It is easy to manage those more-or-less independent tasks
using branches with git.
-We have already seen how branches work in a previous example,
+We have already seen how branches work previously,
with "fun and work" example using two branches. The idea is the
same if there are more than two branches. Let's say you started
out from "master" head, and have some new code in the "master"