]> git.ipfire.org Git - thirdparty/git.git/commitdiff
Merge branch 'jc/tartree' into jc/builtin-n-tar-tree
authorJunio C Hamano <junkio@cox.net>
Tue, 23 May 2006 21:44:31 +0000 (14:44 -0700)
committerJunio C Hamano <junkio@cox.net>
Tue, 23 May 2006 21:44:31 +0000 (14:44 -0700)
* jc/tartree:
  built-in tar-tree and remote tar-tree

31 files changed:
.gitignore
Documentation/Makefile
Documentation/git-add.txt
Documentation/git-branch.txt
Documentation/git-check-ref-format.txt
Documentation/git-checkout.txt
Documentation/tutorial-2.txt [new file with mode: 0644]
Documentation/tutorial.txt
GIT-VERSION-GEN
Makefile
builtin-apply.c [moved from apply.c with 99% similarity]
builtin-commit-tree.c [moved from commit-tree.c with 96% similarity]
builtin-diff-files.c [moved from diff-files.c with 94% similarity]
builtin-diff-index.c [moved from diff-index.c with 91% similarity]
builtin-diff-stages.c [moved from diff-stages.c with 96% similarity]
builtin-diff-tree.c [moved from diff-tree.c with 97% similarity]
builtin-grep.c
builtin-ls-files.c [moved from ls-files.c with 99% similarity]
builtin-ls-tree.c [moved from ls-tree.c with 96% similarity]
builtin-read-tree.c [moved from read-tree.c with 99% similarity]
builtin-show-branch.c [moved from show-branch.c with 99% similarity]
builtin-tar-tree.c
builtin.h
compat/inet_ntop.c [new file with mode: 0644]
diff.c
diff.h
generate-cmdlist.sh
git-clone.sh
git-commit.sh
git-cvsimport.perl
git.c

index b5959d63116aa1e3e900f43a137295b47376e1e0..199cc310a25281a1b423be9399fb9633f0d0c066 100644 (file)
@@ -77,6 +77,7 @@ git-prune
 git-prune-packed
 git-pull
 git-push
+git-quiltimport
 git-read-tree
 git-rebase
 git-receive-pack
index c1af22ce04f71fe2d4a49a908e10878f7b5e0bcf..2a08f592d99476ced40153880461559d059c53e3 100644 (file)
@@ -7,6 +7,7 @@ MAN7_TXT=git.txt
 DOC_HTML=$(patsubst %.txt,%.html,$(MAN1_TXT) $(MAN7_TXT))
 
 ARTICLES = tutorial
+ARTICLES += tutorial-2
 ARTICLES += core-tutorial
 ARTICLES += cvs-migration
 ARTICLES += diffcore
index 5e3112943d1947dbd8b58c23dd535eb4d527b80f..6342ea33e4a34f19ca04c79157d80cb230c15f5c 100644 (file)
@@ -14,11 +14,13 @@ DESCRIPTION
 A simple wrapper for git-update-index to add files to the index,
 for people used to do "cvs add".
 
+It only adds non-ignored files, to add ignored files use
+"git update-index --add".
 
 OPTIONS
 -------
 <file>...::
-       Files to add to the index.
+       Files to add to the index (see gitlink:git-ls-files[1]).
 
 -n::
         Don't actually add the file(s), just show if they exist.
@@ -68,6 +70,7 @@ git-add git-*.sh::
 See Also
 --------
 gitlink:git-rm[1]
+gitlink:git-ls-files[1]
 
 Author
 ------
index 72fb2f89b48ea1b80cd6c4a0bd57a9122e59ad79..0b37e2bfc85706ca6d41c1c9e4fedcdce53a7578 100644 (file)
@@ -43,6 +43,9 @@ OPTIONS
 
 <branchname>::
        The name of the branch to create or delete.
+       The new branch name must pass all checks defined by
+       gitlink:git-check-ref-format[1].  Some of these checks
+       may restrict the characters allowed in a branch name.
 
 <start-point>::
        The new branch will be created with a HEAD equal to this.  It may
index 7dc1bdb6ef62f1325f8cf0567aa65c56728522ec..3ea720dd005f7a9b4a66a419cf5438a3a7d0fa8b 100644 (file)
@@ -45,6 +45,8 @@ refname expressions (see gitlink:git-rev-parse[1]).  Namely:
 
 . colon `:` is used as in `srcref:dstref` to mean "use srcref\'s
   value and store it in dstref" in fetch and push operations.
+  It may also be used to select a specific object such as with
+  gitlink:git-cat-file[1] "git-cat-file blob v1.3.3:refs.c".
 
 
 GIT
index 095128906a523cc8ca30639c1d42452a4bcb0050..d82efc00d403dc13ac1e85c53083ccc52a4c79f3 100644 (file)
@@ -35,7 +35,10 @@ OPTIONS
        Force a re-read of everything.
 
 -b::
-       Create a new branch and start it at <branch>.
+       Create a new branch named <new_branch> and start it at
+       <branch>.  The new branch name must pass all checks defined
+       by gitlink:git-check-ref-format[1].  Some of these checks
+       may restrict the characters allowed in a branch name.
 
 -m::
        If you have local modifications to one or more files that
diff --git a/Documentation/tutorial-2.txt b/Documentation/tutorial-2.txt
new file mode 100644 (file)
index 0000000..08d3453
--- /dev/null
@@ -0,0 +1,391 @@
+A tutorial introduction to git: part two
+========================================
+
+You should work through link:tutorial.html[A tutorial introduction to
+git] before reading this tutorial.
+
+The goal of this tutorial is to introduce two fundamental pieces of
+git's architecture--the object database and the index file--and to
+provide the reader with everything necessary to understand the rest
+of the git documentation.
+
+The git object database
+-----------------------
+
+Let's start a new project and create a small amount of history:
+
+------------------------------------------------
+$ mkdir test-project
+$ cd test-project
+$ git init-db
+defaulting to local storage area
+$ echo 'hello world' > file.txt
+$ git add .
+$ git commit -a -m "initial commit"
+Committing initial tree 92b8b694ffb1675e5975148e1121810081dbdffe
+$ echo 'hello world!' >file.txt
+$ git commit -a -m "add emphasis"
+------------------------------------------------
+
+What are the 40 digits of hex that git responded to the first commit
+with?
+
+We saw in part one of the tutorial that commits have names like this.
+It turns out that every object in the git history is stored under
+such a 40-digit hex name.  That name is the SHA1 hash of the object's
+contents; among other things, this ensures that git will never store
+the same data twice (since identical data is given an identical SHA1
+name), and that the contents of a git object will never change (since
+that would change the object's name as well).
+
+We can ask git about this particular object with the cat-file
+command--just cut-and-paste from the reply to the initial commit, to
+save yourself typing all 40 hex digits:
+
+------------------------------------------------
+$ git cat-file -t 92b8b694ffb1675e5975148e1121810081dbdffe
+tree
+------------------------------------------------
+
+A tree can refer to one or more "blob" objects, each corresponding to
+a file.  In addition, a tree can also refer to other tree objects,
+thus creating a directory heirarchy.  You can examine the contents of
+any tree using ls-tree (remember that a long enough initial portion
+of the SHA1 will also work):
+
+------------------------------------------------
+$ git ls-tree 92b8b694
+100644 blob 3b18e512dba79e4c8300dd08aeb37f8e728b8dad    file.txt
+------------------------------------------------
+
+Thus we see that this tree has one file in it.  The SHA1 hash is a
+reference to that file's data:
+
+------------------------------------------------
+$ git cat-file -t 3b18e512
+blob
+------------------------------------------------
+
+A "blob" is just file data, which we can also examine with cat-file:
+
+------------------------------------------------
+$ git cat-file blob 3b18e512
+hello world
+------------------------------------------------
+
+Note that this is the old file data; so the object that git named in
+its response to the initial tree was a tree with a snapshot of the
+directory state that was recorded by the first commit.
+
+All of these objects are stored under their SHA1 names inside the git
+directory:
+
+------------------------------------------------
+$ find .git/objects/
+.git/objects/
+.git/objects/pack
+.git/objects/info
+.git/objects/3b
+.git/objects/3b/18e512dba79e4c8300dd08aeb37f8e728b8dad
+.git/objects/92
+.git/objects/92/b8b694ffb1675e5975148e1121810081dbdffe
+.git/objects/54
+.git/objects/54/196cc2703dc165cbd373a65a4dcf22d50ae7f7
+.git/objects/a0
+.git/objects/a0/423896973644771497bdc03eb99d5281615b51
+.git/objects/d0
+.git/objects/d0/492b368b66bdabf2ac1fd8c92b39d3db916e59
+.git/objects/c4
+.git/objects/c4/d59f390b9cfd4318117afde11d601c1085f241
+------------------------------------------------
+
+and the contents of these files is just the compressed data plus a
+header identifying their length and their type.  The type is either a
+blob, a tree, a commit, or a tag.  We've seen a blob and a tree now,
+so next we should look at a commit.
+
+The simplest commit to find is the HEAD commit, which we can find
+from .git/HEAD:
+
+------------------------------------------------
+$ cat .git/HEAD
+ref: refs/heads/master
+------------------------------------------------
+
+As you can see, this tells us which branch we're currently on, and it
+tells us this by naming a file under the .git directory, which itself
+contains a SHA1 name referring to a commit object, which we can
+examine with cat-file:
+
+------------------------------------------------
+$ cat .git/refs/heads/master
+c4d59f390b9cfd4318117afde11d601c1085f241
+$ git cat-file -t c4d59f39
+commit
+$ git cat-file commit c4d59f39
+tree d0492b368b66bdabf2ac1fd8c92b39d3db916e59
+parent 54196cc2703dc165cbd373a65a4dcf22d50ae7f7
+author J. Bruce Fields <bfields@puzzle.fieldses.org> 1143418702 -0500
+committer J. Bruce Fields <bfields@puzzle.fieldses.org> 1143418702 -0500
+
+add emphasis
+------------------------------------------------
+
+The "tree" object here refers to the new state of the tree:
+
+------------------------------------------------
+$ git ls-tree d0492b36
+100644 blob a0423896973644771497bdc03eb99d5281615b51    file.txt
+$ git cat-file commit a0423896
+hello world!
+------------------------------------------------
+
+and the "parent" object refers to the previous commit:
+
+------------------------------------------------
+$ git-cat-file commit 54196cc2
+tree 92b8b694ffb1675e5975148e1121810081dbdffe
+author J. Bruce Fields <bfields@puzzle.fieldses.org> 1143414668 -0500
+committer J. Bruce Fields <bfields@puzzle.fieldses.org> 1143414668 -0500
+
+initial commit
+------------------------------------------------
+
+The tree object is the tree we examined first, and this commit is
+unusual in that it lacks any parent.
+
+Most commits have only one parent, but it is also common for a commit
+to have multiple parents.   In that case the commit represents a
+merge, with the parent references pointing to the heads of the merged
+branches.
+
+Besides blobs, trees, and commits, the only remaining type of object
+is a "tag", which we won't discuss here; refer to gitlink:git-tag[1]
+for details.
+
+So now we know how git uses the object database to represent a
+project's history:
+
+  * "commit" objects refer to "tree" objects representing the
+    snapshot of a directory tree at a particular point in the
+    history, and refer to "parent" commits to show how they're
+    connected into the project history.
+  * "tree" objects represent the state of a single directory,
+    associating directory names to "blob" objects containing file
+    data and "tree" objects containing subdirectory information.
+  * "blob" objects contain file data without any other structure.
+  * References to commit objects at the head of each branch are
+    stored in files under .git/refs/heads/.
+  * The name of the current branch is stored in .git/HEAD.
+
+Note, by the way, that lots of commands take a tree as an argument.
+But as we can see above, a tree can be referred to in many different
+ways--by the SHA1 name for that tree, by the name of a commit that
+refers to the tree, by the name of a branch whose head refers to that
+tree, etc.--and most such commands can accept any of these names.
+
+In command synopses, the word "tree-ish" is sometimes used to
+designate such an argument.
+
+The index file
+--------------
+
+The primary tool we've been using to create commits is "git commit
+-a", which creates a commit including every change you've made to
+your working tree.  But what if you want to commit changes only to
+certain files?  Or only certain changes to certain files?
+
+If we look at the way commits are created under the cover, we'll see
+that there are more flexible ways creating commits.
+
+Continuing with our test-project, let's modify file.txt again:
+
+------------------------------------------------
+$ echo "hello world, again" >>file.txt
+------------------------------------------------
+
+but this time instead of immediately making the commit, let's take an
+intermediate step, and ask for diffs along the way to keep track of
+what's happening:
+
+------------------------------------------------
+$ git diff
+--- a/file.txt
++++ b/file.txt
+@@ -1 +1,2 @@
+ hello world!
++hello world, again
+$ git update-index file.txt
+$ git diff
+------------------------------------------------
+
+The last diff is empty, but no new commits have been made, and the
+head still doesn't contain the new line:
+
+------------------------------------------------
+$ git-diff HEAD
+diff --git a/file.txt b/file.txt
+index a042389..513feba 100644
+--- a/file.txt
++++ b/file.txt
+@@ -1 +1,2 @@
+ hello world!
++hello world, again
+------------------------------------------------
+
+So "git diff" is comparing against something other than the head.
+The thing that it's comparing against is actually the index file,
+which is stored in .git/index in a binary format, but whose contents
+we can examine with ls-files:
+
+------------------------------------------------
+$ git ls-files --stage
+100644 513feba2e53ebbd2532419ded848ba19de88ba00 0       file.txt
+$ git cat-file -t 513feba2
+blob
+$ git cat-file blob 513feba2
+hello world, again
+------------------------------------------------
+
+So what our "git update-index" did was store a new blob and then put
+a reference to it in the index file.  If we modify the file again,
+we'll see that the new modifications are reflected in the "git-diff"
+output:
+
+------------------------------------------------
+$ echo 'again?' >>file.txt
+$ git diff
+index 513feba..ba3da7b 100644
+--- a/file.txt
++++ b/file.txt
+@@ -1,2 +1,3 @@
+ hello world!
+ hello world, again
++again?
+------------------------------------------------
+
+With the right arguments, git diff can also show us the difference
+between the working directory and the last commit, or between the
+index and the last commit:
+
+------------------------------------------------
+$ git diff HEAD
+diff --git a/file.txt b/file.txt
+index a042389..ba3da7b 100644
+--- a/file.txt
++++ b/file.txt
+@@ -1 +1,3 @@
+ hello world!
++hello world, again
++again?
+$ git diff --cached
+diff --git a/file.txt b/file.txt
+index a042389..513feba 100644
+--- a/file.txt
++++ b/file.txt
+@@ -1 +1,2 @@
+ hello world!
++hello world, again
+------------------------------------------------
+
+At any time, we can create a new commit using "git commit" (without
+the -a option), and verify that the state committed only includes the
+changes stored in the index file, not the additional change that is
+still only in our working tree:
+
+------------------------------------------------
+$ git commit -m "repeat"
+$ git diff HEAD
+diff --git a/file.txt b/file.txt
+index 513feba..ba3da7b 100644
+--- a/file.txt
++++ b/file.txt
+@@ -1,2 +1,3 @@
+ hello world!
+ hello world, again
++again?
+------------------------------------------------
+
+So by default "git commit" uses the index to create the commit, not
+the working tree; the -a option to commit tells it to first update
+the index with all changes in the working tree.
+
+Finally, it's worth looking at the effect of "git add" on the index
+file:
+
+------------------------------------------------
+$ echo "goodbye, world" >closing.txt
+$ git add closing.txt
+------------------------------------------------
+
+The effect of the "git add" was to add one entry to the index file:
+
+------------------------------------------------
+$ git ls-files --stage
+100644 8b9743b20d4b15be3955fc8d5cd2b09cd2336138 0       closing.txt
+100644 513feba2e53ebbd2532419ded848ba19de88ba00 0       file.txt
+------------------------------------------------
+
+And, as you can see with cat-file, this new entry refers to the
+current contents of the file:
+
+------------------------------------------------
+$ git cat-file blob a6b11f7a
+goodbye, word
+------------------------------------------------
+
+The "status" command is a useful way to get a quick summary of the
+situation:
+
+------------------------------------------------
+$ git status
+#
+# Updated but not checked in:
+#   (will commit)
+#
+#       new file: closing.txt
+#
+#
+# Changed but not updated:
+#   (use git-update-index to mark for commit)
+#
+#       modified: file.txt
+#
+------------------------------------------------
+
+Since the current state of closing.txt is cached in the index file,
+it is listed as "updated but not checked in".  Since file.txt has
+changes in the working directory that aren't reflected in the index,
+it is marked "changed but not updated".  At this point, running "git
+commit" would create a commit that added closing.txt (with its new
+contents), but that didn't modify file.txt.
+
+Also, note that a bare "git diff" shows the changes to file.txt, but
+not the addition of closing.txt, because the version of closing.txt
+in the index file is identical to the one in the working directory.
+
+In addition to being the staging area for new commits, the index file
+is also populated from the object database when checking out a
+branch, and is used to hold the trees involved in a merge operation.
+See the link:core-tutorial.txt[core tutorial] and the relevant man
+pages for details.
+
+What next?
+----------
+
+At this point you should know everything necessary to read the man
+pages for any of the git commands; one good place to start would be
+with the commands mentioned in link:everyday.html[Everyday git].  You
+should be able to find any unknown jargon in the
+link:glossary.html[Glosssay].
+
+The link:cvs-migration.html[CVS migration] document explains how to
+import a CVS repository into git, and shows how to use git in a
+CVS-like way.
+
+For some interesting examples of git use, see the
+link:howto-index.html[howtos].
+
+For git developers, the link:core-tutorial.html[Core tutorial] goes
+into detail on the lower-level git mechanisms involved in, for
+example, creating a new commit.
index fa79b016c77a7f37ae1e289eb42bb008174eda81..79781adf4fb554a458d76903c3999d46952b1ae3 100644 (file)
@@ -80,13 +80,13 @@ file; just remove it, then commit.
 At any point you can view the history of your changes using
 
 ------------------------------------------------
-$ git whatchanged
+$ git log
 ------------------------------------------------
 
 If you also want to see complete diffs at each step, use
 
 ------------------------------------------------
-$ git whatchanged -p
+$ git log -p
 ------------------------------------------------
 
 Managing branches
@@ -216,7 +216,7 @@ This actually pulls changes from the branch in Bob's repository named
 "master".  Alice could request a different branch by adding the name
 of the branch to the end of the git pull command line.
 
-This merges Bob's changes into her repository; "git whatchanged" will
+This merges Bob's changes into her repository; "git log" will
 now show the new commits.  If Alice has made her own changes in the
 meantime, then Bob's changes will be merged in, and she will need to
 manually fix any conflicts.
@@ -234,7 +234,7 @@ named bob-incoming.  (Unlike git pull, git fetch just fetches a copy
 of Bob's line of development without doing any merging).  Then
 
 -------------------------------------
-$ git whatchanged -p master..bob-incoming
+$ git log -p master..bob-incoming
 -------------------------------------
 
 shows a list of all the changes that Bob made since he branched from
@@ -288,102 +288,179 @@ Git can also be used in a CVS-like mode, with a central repository
 that various users push changes to; see gitlink:git-push[1] and
 link:cvs-migration.html[git for CVS users].
 
-Keeping track of history
-------------------------
+Exploring history
+-----------------
 
-Git history is represented as a series of interrelated commits.  The
-most recent commit in the currently checked-out branch can always be
-referred to as HEAD, and the "parent" of any commit can always be
-referred to by appending a caret, "^", to the end of the name of the
-commit.  So, for example,
+Git history is represented as a series of interrelated commits.  We
+have already seen that the git log command can list those commits.
+Note that first line of each git log entry also gives a name for the
+commit:
 
 -------------------------------------
-git diff HEAD^ HEAD
+$ git log
+commit c82a22c39cbc32576f64f5c6b3f24b99ea8149c7
+Author: Junio C Hamano <junkio@cox.net>
+Date:   Tue May 16 17:18:22 2006 -0700
+
+    merge-base: Clarify the comments on post processing.
 -------------------------------------
 
-shows the difference between the most-recently checked-in state of
-the tree and the previous state, and
+We can give this name to git show to see the details about this
+commit.
 
 -------------------------------------
-git diff HEAD^^ HEAD^
+$ git show c82a22c39cbc32576f64f5c6b3f24b99ea8149c7
 -------------------------------------
 
-shows the difference between that previous state and the state two
-commits ago.  Also, HEAD~5 can be used as a shorthand for HEAD{caret}{caret}{caret}{caret}{caret},
-and more generally HEAD~n can refer to the nth previous commit.
-Commits representing merges have more than one parent, and you can
-specify which parent to follow in that case; see
-gitlink:git-rev-parse[1].
+But there other ways to refer to commits.  You can use any initial
+part of the name that is long enough to uniquely identify the commit:
+
+-------------------------------------
+$ git show c82a22c39c  # the first few characters of the name are
+                       # usually enough
+$ git show HEAD                # the tip of the current branch
+$ git show experimental        # the tip of the "experimental" branch
+-------------------------------------
 
-The name of a branch can also be used to refer to the most recent
-commit on that branch; so you can also say things like
+Every commit has at least one "parent" commit, which points to the
+previous state of the project:
 
 -------------------------------------
-git diff HEAD experimental
+$ git show HEAD^  # to see the parent of HEAD
+$ git show HEAD^^ # to see the grandparent of HEAD
+$ git show HEAD~4 # to see the great-great grandparent of HEAD
 -------------------------------------
 
-to see the difference between the most-recently committed tree in
-the current branch and the most-recently committed tree in the
-experimental branch.
+Note that merge commits may have more than one parent:
 
-But you may find it more useful to see the list of commits made in
-the experimental branch but not in the current branch, and
+-------------------------------------
+$ git show HEAD^1 # show the first parent of HEAD (same as HEAD^)
+$ git show HEAD^2 # show the second parent of HEAD
+-------------------------------------
+
+You can also give commits names of your own; after running
 
 -------------------------------------
-git whatchanged HEAD..experimental
+$ git-tag v2.5 1b2e1d63ff
 -------------------------------------
 
-will do that, just as
+you can refer to 1b2e1d63ff by the name "v2.5".  If you intend to
+share this name with other people (for example, to identify a release
+version), you should create a "tag" object, and perhaps sign it; see
+gitlink:git-tag[1] for details.
+
+Any git command that needs to know a commit can take any of these
+names.  For example:
 
 -------------------------------------
-git whatchanged experimental..HEAD
+$ git diff v2.5 HEAD    # compare the current HEAD to v2.5
+$ git branch stable v2.5 # start a new branch named "stable" based
+                        # at v2.5
+$ git reset --hard HEAD^ # reset your current branch and working
+                        # directory its state at HEAD^
 -------------------------------------
 
-will show the list of commits made on the HEAD but not included in
-experimental.
+Be careful with that last command: in addition to losing any changes
+in the working directory, it will also remove all later commits from
+this branch.  If this branch is the only branch containing those
+commits, they will be lost.  (Also, don't use "git reset" on a
+publicly-visible branch that other developers pull from, as git will
+be confused by history that disappears in this way.)
 
-You can also give commits convenient names of your own: after running
+The git grep command can search for strings in any version of your
+project, so
 
 -------------------------------------
-$ git-tag v2.5 HEAD^^
+$ git grep "hello" v2.5
 -------------------------------------
 
-you can refer to HEAD^^ by the name "v2.5".  If you intend to share
-this name with other people (for example, to identify a release
-version), you should create a "tag" object, and perhaps sign it; see
-gitlink:git-tag[1] for details.
+searches for all occurences of "hello" in v2.5.
 
-You can revisit the old state of a tree, and make further
-modifications if you wish, using git branch: the command
+If you leave out the commit name, git grep will search any of the
+files it manages in your current directory.  So
 
 -------------------------------------
-$ git branch stable-release v2.5
+$ git grep "hello"
 -------------------------------------
 
-will create a new branch named "stable-release" starting from the
-commit which you tagged with the name v2.5.
+is a quick way to search just the files that are tracked by git.
 
-You can reset the state of any branch to an earlier commit at any
-time with
+Many git commands also take sets of commits, which can be specified
+in a number of ways.  Here are some examples with git log:
 
 -------------------------------------
-$ git reset --hard v2.5
+$ git log v2.5..v2.6            # commits between v2.5 and v2.6
+$ git log v2.5..                # commits since v2.5
+$ git log --since="2 weeks ago" # commits from the last 2 weeks
+$ git log v2.5.. Makefile       # commits since v2.5 which modify
+                               # Makefile
 -------------------------------------
 
-This will remove all later commits from this branch and reset the
-working tree to the state it had when the given commit was made.  If
-this branch is the only branch containing the later commits, those
-later changes will be lost.  Don't use "git reset" on a
-publicly-visible branch that other developers pull from, as git will
-be confused by history that disappears in this way.
+You can also give git log a "range" of commits where the first is not
+necessarily an ancestor of the second; for example, if the tips of
+the branches "stable-release" and "master" diverged from a common
+commit some time ago, then
+
+-------------------------------------
+$ git log stable..experimental
+-------------------------------------
+
+will list commits made in the experimental branch but not in the
+stable branch, while
+
+-------------------------------------
+$ git log experimental..stable
+-------------------------------------
+
+will show the list of commits made on the stable branch but not
+the experimental branch.
+
+The "git log" command has a weakness: it must present commits in a
+list.  When the history has lines of development that diverged and
+then merged back together, the order in which "git log" presents
+those commits is meaningless.
+
+Most projects with multiple contributors (such as the linux kernel,
+or git itself) have frequent merges, and gitk does a better job of
+visualizing their history.  For example,
+
+-------------------------------------
+$ gitk --since="2 weeks ago" drivers/
+-------------------------------------
+
+allows you to browse any commits from the last 2 weeks of commits
+that modified files under the "drivers" directory.
+
+Finally, most commands that take filenames will optionally allow you
+to precede any filename by a commit, to specify a particular version
+fo the file:
+
+-------------------------------------
+$ git diff v2.5:Makefile HEAD:Makefile.in
+-------------------------------------
 
 Next Steps
 ----------
 
-Some good commands to explore next:
+This tutorial should be enough to perform basic distributed revision
+control for your projects.  However, to fully understand the depth
+and power of git you need to understand two simple ideas on which it
+is based:
 
-  * gitlink:git-diff[1]: This flexible command does much more than
-    we've seen in the few examples above.
+  * The object database is the rather elegant system used to
+    store the history of your project--files, directories, and
+    commits.
+
+  * The index file is a cache of the state of a directory tree,
+    used to create commits, check out working directories, and
+    hold the various trees involved in a merge.
+
+link:tutorial-2.html[Part two of this tutorial] explains the object
+database, the index file, and a few other odds and ends that you'll
+need to make the most of git.
+
+If you don't want to consider with that right away, a few other
+digressions that may be interesting at this point are:
 
   * gitlink:git-format-patch[1], gitlink:git-am[1]: These convert
     series of git commits into emailed patches, and vice versa,
@@ -397,8 +474,6 @@ Some good commands to explore next:
     smart enough to perform a close-to-optimal search even in the
     case of complex non-linear history with lots of merged branches.
 
-Other good starting points include link:everyday.html[Everday GIT
-with 20 Commands Or So] and link:cvs-migration.html[git for CVS
-users].  Also, link:core-tutorial.html[A short git tutorial] gives an
-introduction to lower-level git commands for advanced users and
-developers.
+  * link:everyday.html[Everday GIT with 20 Commands Or So]
+
+  * link:cvs-migration.html[git for CVS users].
index 7fcefcd7c45084d005e8fd677cdf72921864f4a2..a461518cdee5074899f04156c457a3dd78ea23ec 100755 (executable)
@@ -5,7 +5,7 @@ DEF_VER=v1.3.GIT
 
 # First try git-describe, then see if there is a version file
 # (included in release tarballs), then default
-if VN=$(git-describe --abbrev=4 HEAD 2>/dev/null); then
+if VN=$(git describe --abbrev=4 HEAD 2>/dev/null); then
        VN=$(echo "$VN" | sed -e 's/-/./g');
 elif test -f version
 then
@@ -16,7 +16,7 @@ fi
 
 VN=$(expr "$VN" : v*'\(.*\)')
 
-dirty=$(sh -c 'git-diff-index --name-only HEAD' 2>/dev/null) || dirty=
+dirty=$(sh -c 'git diff-index --name-only HEAD' 2>/dev/null) || dirty=
 case "$dirty" in
 '')
        ;;
index f4bcec496a616d111bad42b70b8289a9cde74d7c..14873fa3591516d9aa2a8e3a4bf43341deaa8da0 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -149,17 +149,15 @@ SIMPLE_PROGRAMS = \
 
 # ... and all the rest that could be moved out of bindir to gitexecdir
 PROGRAMS = \
-       git-apply$X git-cat-file$X \
-       git-checkout-index$X git-clone-pack$X git-commit-tree$X \
-       git-convert-objects$X git-diff-files$X \
-       git-diff-index$X git-diff-stages$X \
-       git-diff-tree$X git-fetch-pack$X git-fsck-objects$X \
+       git-cat-file$X \
+       git-checkout-index$X git-clone-pack$X \
+       git-convert-objects$X git-fetch-pack$X git-fsck-objects$X \
        git-hash-object$X git-index-pack$X git-local-fetch$X \
-       git-ls-files$X git-ls-tree$X git-mailinfo$X git-merge-base$X \
+       git-mailinfo$X git-merge-base$X \
        git-merge-index$X git-mktag$X git-mktree$X git-pack-objects$X git-patch-id$X \
-       git-peek-remote$X git-prune-packed$X git-read-tree$X \
+       git-peek-remote$X git-prune-packed$X \
        git-receive-pack$X git-rev-parse$X \
-       git-send-pack$X git-show-branch$X git-shell$X \
+       git-send-pack$X git-shell$X \
        git-show-index$X git-ssh-fetch$X \
        git-ssh-upload$X git-unpack-file$X \
        git-unpack-objects$X git-update-index$X git-update-server-info$X \
@@ -171,7 +169,11 @@ PROGRAMS = \
 BUILT_INS = git-log$X git-whatchanged$X git-show$X \
        git-count-objects$X git-diff$X git-push$X \
        git-grep$X git-rev-list$X git-check-ref-format$X \
-       git-init-db$X git-tar-tree$X git-upload-tar$X
+       git-init-db$X git-ls-files$X git-ls-tree$X \
+       git-read-tree$X git-commit-tree$X \
+       git-apply$X git-show-branch$X git-diff-files$X \
+       git-diff-index$X git-diff-stages$X git-diff-tree$X \
+       git-tar-tree$X git-upload-tar$X
 
 # what 'all' will build and 'install' will install, in gitexecdir
 ALL_PROGRAMS = $(PROGRAMS) $(SIMPLE_PROGRAMS) $(SCRIPTS)
@@ -220,7 +222,11 @@ LIB_OBJS = \
 BUILTIN_OBJS = \
        builtin-log.o builtin-help.o builtin-count.o builtin-diff.o builtin-push.o \
        builtin-grep.o builtin-rev-list.o builtin-check-ref-format.o \
-       builtin-init-db.o builtin-tar-tree.o builtin-upload-tar.o
+       builtin-init-db.o builtin-ls-files.o builtin-ls-tree.o \
+       builtin-read-tree.o builtin-commit-tree.o \
+       builtin-apply.o builtin-show-branch.o builtin-diff-files.o \
+       builtin-diff-index.o builtin-diff-stages.o builtin-diff-tree.o \
+       builtin-tar-tree.o builtin-upload-tar.o
 
 GITLIBS = $(LIB_FILE) $(XDIFF_LIB)
 LIBS = $(GITLIBS) -lz
@@ -420,6 +426,9 @@ else
        ALL_CFLAGS += -Dsockaddr_storage=sockaddr_in6
 endif
 endif
+ifdef NO_INET_NTOP
+       LIB_OBJS += compat/inet_ntop.o
+endif
 
 ifdef NO_ICONV
        ALL_CFLAGS += -DNO_ICONV
@@ -624,7 +633,14 @@ install: all
        $(MAKE) -C templates install
        $(INSTALL) -d -m755 '$(DESTDIR_SQ)$(GIT_PYTHON_DIR_SQ)'
        $(INSTALL) $(PYMODULES) '$(DESTDIR_SQ)$(GIT_PYTHON_DIR_SQ)'
-       $(foreach p,$(BUILT_INS), rm -f '$(DESTDIR_SQ)$(bindir_SQ)/$p' && ln '$(DESTDIR_SQ)$(bindir_SQ)/git$X' '$(DESTDIR_SQ)$(bindir_SQ)/$p' ;)
+       if test 'z$(bindir_SQ)' != 'z$(gitexecdir_SQ)'; \
+       then \
+               ln -f '$(DESTDIR_SQ)$(bindir_SQ)/git$X' \
+                       '$(DESTDIR_SQ)$(gitexecdir_SQ)/git$X' || \
+               cp '$(DESTDIR_SQ)$(bindir_SQ)/git$X' \
+                       '$(DESTDIR_SQ)$(gitexecdir_SQ)/git$X'; \
+       fi
+       $(foreach p,$(BUILT_INS), rm -f '$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' && ln '$(DESTDIR_SQ)$(gitexecdir_SQ)/git$X' '$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' ;)
 
 install-doc:
        $(MAKE) -C Documentation install
similarity index 99%
rename from apply.c
rename to builtin-apply.c
index 0ed9d132e88f52c678a4a64caf3b49d5bc04ee2e..4056b9d67bc1c4e50563ceaa0ee68e94873a8e65 100644 (file)
--- a/apply.c
@@ -11,6 +11,7 @@
 #include "quote.h"
 #include "blob.h"
 #include "delta.h"
+#include "builtin.h"
 
 //  --check turns on checking that the working tree matches the
 //    files that are being modified, but doesn't apply the patch
@@ -2151,7 +2152,7 @@ static int git_apply_config(const char *var, const char *value)
 }
 
 
-int main(int argc, char **argv)
+int cmd_apply(int argc, const char **argv, char **envp)
 {
        int i;
        int read_stdin = 1;
similarity index 96%
rename from commit-tree.c
rename to builtin-commit-tree.c
index 0320036e802f820760dd197f745698acb5531bbb..ec082bf754a0ce5ae1615c41ba32c4515a927361 100644 (file)
@@ -6,6 +6,7 @@
 #include "cache.h"
 #include "commit.h"
 #include "tree.h"
+#include "builtin.h"
 
 #define BLOCKING (1ul << 14)
 
@@ -76,7 +77,7 @@ static int new_parent(int idx)
        return 1;
 }
 
-int main(int argc, char **argv)
+int cmd_commit_tree(int argc, const char **argv, char **envp)
 {
        int i;
        int parents = 0;
@@ -98,7 +99,7 @@ int main(int argc, char **argv)
 
        check_valid(tree_sha1, tree_type);
        for (i = 2; i < argc; i += 2) {
-               char *a, *b;
+               const char *a, *b;
                a = argv[i]; b = argv[i+1];
                if (!b || strcmp(a, "-p"))
                        usage(commit_tree_usage);
similarity index 94%
rename from diff-files.c
rename to builtin-diff-files.c
index b9d193d506d9e67eb5f0c24905aa6d691ccff301..cebda828eec4e90f3d0af050e07a53071b39d5b7 100644 (file)
@@ -7,12 +7,13 @@
 #include "diff.h"
 #include "commit.h"
 #include "revision.h"
+#include "builtin.h"
 
 static const char diff_files_usage[] =
 "git-diff-files [-q] [-0/-1/2/3 |-c|--cc] [<common diff options>] [<path>...]"
 COMMON_DIFF_OPTIONS_HELP;
 
-int main(int argc, const char **argv)
+int cmd_diff_files(int argc, const char **argv, char **envp)
 {
        struct rev_info rev;
        int silent = 0;
similarity index 91%
rename from diff-index.c
rename to builtin-diff-index.c
index 8c9f60173b18a68f6ea224b2e6fc9c0eab4b9d0f..1958580d82e54ab5a5b1e054263eab7264c4bcb2 100644 (file)
@@ -2,13 +2,14 @@
 #include "diff.h"
 #include "commit.h"
 #include "revision.h"
+#include "builtin.h"
 
 static const char diff_cache_usage[] =
 "git-diff-index [-m] [--cached] "
 "[<common diff options>] <tree-ish> [<path>...]"
 COMMON_DIFF_OPTIONS_HELP;
 
-int main(int argc, const char **argv)
+int cmd_diff_index(int argc, const char **argv, char **envp)
 {
        struct rev_info rev;
        int cached = 0;
similarity index 96%
rename from diff-stages.c
rename to builtin-diff-stages.c
index dcd20e79e4fb67cdf6ed577a42277ad00b087c68..7c157ca889eaf85b38be2764fca83814bb83a3f4 100644 (file)
@@ -4,6 +4,7 @@
 
 #include "cache.h"
 #include "diff.h"
+#include "builtin.h"
 
 static struct diff_options diff_options;
 
@@ -54,7 +55,7 @@ static void diff_stages(int stage1, int stage2, const char **pathspec)
        }
 }
 
-int main(int ac, const char **av)
+int cmd_diff_stages(int ac, const char **av, char **envp)
 {
        int stage1, stage2;
        const char *prefix = setup_git_directory();
similarity index 97%
rename from diff-tree.c
rename to builtin-diff-tree.c
index 69bb74b3100d598c938fa01f1111deb85abcfac0..cc53b81ac427f27522130e741350b955f4b1f653 100644 (file)
@@ -2,6 +2,7 @@
 #include "diff.h"
 #include "commit.h"
 #include "log-tree.h"
+#include "builtin.h"
 
 static struct rev_info log_tree_opt;
 
@@ -58,7 +59,7 @@ static const char diff_tree_usage[] =
 "  --root        include the initial commit as diff against /dev/null\n"
 COMMON_DIFF_OPTIONS_HELP;
 
-int main(int argc, const char **argv)
+int cmd_diff_tree(int argc, const char **argv, char **envp)
 {
        int nr_sha1;
        char line[1000];
index d09ddf04850baa17842975ff54063f5acfce8cfe..53de8a883607157c88d02a30f0320aa9e5c0581a 100644 (file)
@@ -518,7 +518,7 @@ static int external_grep(struct grep_opt *opt, const char **paths, int cached)
        argc = nr;
        for (i = 0; i < active_nr; i++) {
                struct cache_entry *ce = active_cache[i];
-               const char *name;
+               char *name;
                if (ce_stage(ce) || !S_ISREG(ntohl(ce->ce_mode)))
                        continue;
                if (!pathspec_matches(paths, ce->name))
similarity index 99%
rename from ls-files.c
rename to builtin-ls-files.c
index 4a4af1ca3b3cc11e2996c2889cb8ea16bbb0dded..3a0c5f215003bda5cfa2109953cd556765f6ea2c 100644 (file)
@@ -10,6 +10,7 @@
 
 #include "cache.h"
 #include "quote.h"
+#include "builtin.h"
 
 static int abbrev = 0;
 static int show_deleted = 0;
@@ -648,7 +649,7 @@ static const char ls_files_usage[] =
        "[ --exclude-per-directory=<filename> ] [--full-name] [--abbrev] "
        "[--] [<file>]*";
 
-int main(int argc, const char **argv)
+int cmd_ls_files(int argc, const char **argv, char** envp)
 {
        int i;
        int exc_given = 0;
similarity index 96%
rename from ls-tree.c
rename to builtin-ls-tree.c
index f2b3bc1231b7fdfd7277974fc5a5708ceef9cbaf..48385d59f6097258b83ebbf0156e1913043b6928 100644 (file)
--- a/ls-tree.c
@@ -7,6 +7,7 @@
 #include "blob.h"
 #include "tree.h"
 #include "quote.h"
+#include "builtin.h"
 
 static int line_termination = '\n';
 #define LS_RECURSIVE 1
@@ -15,7 +16,7 @@ static int line_termination = '\n';
 #define LS_NAME_ONLY 8
 static int abbrev = 0;
 static int ls_options = 0;
-const char **pathspec;
+static const char **pathspec;
 static int chomp_prefix = 0;
 static const char *prefix;
 
@@ -84,7 +85,7 @@ static int show_tree(unsigned char *sha1, const char *base, int baselen,
        return retval;
 }
 
-int main(int argc, const char **argv)
+int cmd_ls_tree(int argc, const char **argv, char **envp)
 {
        unsigned char sha1[20];
        struct tree *tree;
similarity index 99%
rename from read-tree.c
rename to builtin-read-tree.c
index 82e2a9a4d3663fad513f607e25fe84a8ccbf5460..ec40d013c4d8508bfd10d75e2dab3090dea64a45 100644 (file)
@@ -11,6 +11,7 @@
 #include "tree.h"
 #include <sys/time.h>
 #include <signal.h>
+#include "builtin.h"
 
 static int reset = 0;
 static int merge = 0;
@@ -763,7 +764,7 @@ static const char read_tree_usage[] = "git-read-tree (<sha> | -m [--aggressive]
 
 static struct cache_file cache_file;
 
-int main(int argc, char **argv)
+int cmd_read_tree(int argc, const char **argv, char **envp)
 {
        int i, newfd, stage = 0;
        unsigned char sha1[20];
similarity index 99%
rename from show-branch.c
rename to builtin-show-branch.c
index 268c57b180627f7d8ba3a3a754210a37d420fb0d..3af24e767baae390484d2c5acec9aa25e09d9a91 100644 (file)
@@ -3,13 +3,14 @@
 #include "cache.h"
 #include "commit.h"
 #include "refs.h"
+#include "builtin.h"
 
 static const char show_branch_usage[] =
 "git-show-branch [--dense] [--current] [--all] [--heads] [--tags] [--topo-order] [--more=count | --list | --independent | --merge-base ] [--topics] [<refs>...]";
 
 static int default_num = 0;
 static int default_alloc = 0;
-static char **default_arg = NULL;
+static const char **default_arg = NULL;
 
 #define UNINTERESTING  01
 
@@ -548,7 +549,7 @@ static int omit_in_dense(struct commit *commit, struct commit **rev, int n)
        return 0;
 }
 
-int main(int ac, char **av)
+int cmd_show_branch(int ac, const char **av, char **envp)
 {
        struct commit *rev[MAX_REVS], *commit;
        struct commit_list *list = NULL, *seen = NULL;
@@ -581,7 +582,7 @@ int main(int ac, char **av)
        }
 
        while (1 < ac && av[1][0] == '-') {
-               char *arg = av[1];
+               const char *arg = av[1];
                if (!strcmp(arg, "--")) {
                        ac--; av++;
                        break;
index e97e0af985515df14b37a6f0e5cc84b2c943f8c6..2d5e06fb692968829df00e7166eaaeb9d5902119 100644 (file)
@@ -304,7 +304,7 @@ static void traverse_tree(struct tree_desc *tree, struct strbuf *path)
        }
 }
 
-int generate_tar(int argc, const char **argv)
+static int generate_tar(int argc, const char **argv, char** envp)
 {
        unsigned char sha1[20], tree_sha1[20];
        struct commit *commit;
@@ -404,5 +404,5 @@ int cmd_tar_tree(int argc, const char **argv, char **envp)
                usage(tar_tree_usage);
        if (!strncmp("--remote=", argv[1], 9))
                return remote_tar(argc, argv);
-       return generate_tar(argc, argv);
+       return generate_tar(argc, argv, envp);
 }
index f22783c499a94c3953d098d6edf04984cb25711a..2249c5fae0f8f9134d2328d2835743a8f5d89d46 100644 (file)
--- a/builtin.h
+++ b/builtin.h
@@ -29,5 +29,15 @@ extern int cmd_check_ref_format(int argc, const char **argv, char **envp);
 extern int cmd_init_db(int argc, const char **argv, char **envp);
 extern int cmd_tar_tree(int argc, const char **argv, char **envp);
 extern int cmd_upload_tar(int argc, const char **argv, char **envp);
+extern int cmd_ls_files(int argc, const char **argv, char **envp);
+extern int cmd_ls_tree(int argc, const char **argv, char **envp);
+extern int cmd_read_tree(int argc, const char **argv, char **envp);
+extern int cmd_commit_tree(int argc, const char **argv, char **envp);
+extern int cmd_apply(int argc, const char **argv, char **envp);
+extern int cmd_show_branch(int argc, const char **argv, char **envp);
+extern int cmd_diff_files(int argc, const char **argv, char **envp);
+extern int cmd_diff_index(int argc, const char **argv, char **envp);
+extern int cmd_diff_stages(int argc, const char **argv, char **envp);
+extern int cmd_diff_tree(int argc, const char **argv, char **envp);
 
 #endif
diff --git a/compat/inet_ntop.c b/compat/inet_ntop.c
new file mode 100644 (file)
index 0000000..ec8c1bf
--- /dev/null
@@ -0,0 +1,200 @@
+/*
+ * Copyright (c) 1996-1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <stdio.h>
+#include <string.h>
+
+#ifndef NS_INADDRSZ
+#define NS_INADDRSZ    4
+#endif
+#ifndef NS_IN6ADDRSZ
+#define NS_IN6ADDRSZ   16
+#endif
+#ifndef NS_INT16SZ
+#define NS_INT16SZ     2
+#endif
+
+/*
+ * WARNING: Don't even consider trying to compile this on a system where
+ * sizeof(int) < 4.  sizeof(int) > 4 is fine; all the world's not a VAX.
+ */
+
+/* const char *
+ * inet_ntop4(src, dst, size)
+ *     format an IPv4 address
+ * return:
+ *     `dst' (as a const)
+ * notes:
+ *     (1) uses no statics
+ *     (2) takes a u_char* not an in_addr as input
+ * author:
+ *     Paul Vixie, 1996.
+ */
+static const char *
+inet_ntop4(src, dst, size)
+       const u_char *src;
+       char *dst;
+       size_t size;
+{
+       static const char fmt[] = "%u.%u.%u.%u";
+       char tmp[sizeof "255.255.255.255"];
+       int nprinted;
+
+       nprinted = snprintf(tmp, sizeof(tmp), fmt, src[0], src[1], src[2], src[3]);
+       if (nprinted < 0)
+               return (NULL);  /* we assume "errno" was set by "snprintf()" */
+       if ((size_t)nprinted > size) {
+               errno = ENOSPC;
+               return (NULL);
+       }
+       strcpy(dst, tmp);
+       return (dst);
+}
+
+#ifndef NO_IPV6
+/* const char *
+ * inet_ntop6(src, dst, size)
+ *     convert IPv6 binary address into presentation (printable) format
+ * author:
+ *     Paul Vixie, 1996.
+ */
+static const char *
+inet_ntop6(src, dst, size)
+       const u_char *src;
+       char *dst;
+       size_t size;
+{
+       /*
+        * Note that int32_t and int16_t need only be "at least" large enough
+        * to contain a value of the specified size.  On some systems, like
+        * Crays, there is no such thing as an integer variable with 16 bits.
+        * Keep this in mind if you think this function should have been coded
+        * to use pointer overlays.  All the world's not a VAX.
+        */
+       char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"], *tp;
+       struct { int base, len; } best, cur;
+       u_int words[NS_IN6ADDRSZ / NS_INT16SZ];
+       int i;
+
+       /*
+        * Preprocess:
+        *      Copy the input (bytewise) array into a wordwise array.
+        *      Find the longest run of 0x00's in src[] for :: shorthanding.
+        */
+       memset(words, '\0', sizeof words);
+       for (i = 0; i < NS_IN6ADDRSZ; i++)
+               words[i / 2] |= (src[i] << ((1 - (i % 2)) << 3));
+       best.base = -1;
+       cur.base = -1;
+       for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) {
+               if (words[i] == 0) {
+                       if (cur.base == -1)
+                               cur.base = i, cur.len = 1;
+                       else
+                               cur.len++;
+               } else {
+                       if (cur.base != -1) {
+                               if (best.base == -1 || cur.len > best.len)
+                                       best = cur;
+                               cur.base = -1;
+                       }
+               }
+       }
+       if (cur.base != -1) {
+               if (best.base == -1 || cur.len > best.len)
+                       best = cur;
+       }
+       if (best.base != -1 && best.len < 2)
+               best.base = -1;
+
+       /*
+        * Format the result.
+        */
+       tp = tmp;
+       for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) {
+               /* Are we inside the best run of 0x00's? */
+               if (best.base != -1 && i >= best.base &&
+                   i < (best.base + best.len)) {
+                       if (i == best.base)
+                               *tp++ = ':';
+                       continue;
+               }
+               /* Are we following an initial run of 0x00s or any real hex? */
+               if (i != 0)
+                       *tp++ = ':';
+               /* Is this address an encapsulated IPv4? */
+               if (i == 6 && best.base == 0 &&
+                   (best.len == 6 || (best.len == 5 && words[5] == 0xffff))) {
+                       if (!inet_ntop4(src+12, tp, sizeof tmp - (tp - tmp)))
+                               return (NULL);
+                       tp += strlen(tp);
+                       break;
+               }
+               tp += snprintf(tp, sizeof tmp - (tp - tmp), "%x", words[i]);
+       }
+       /* Was it a trailing run of 0x00's? */
+       if (best.base != -1 && (best.base + best.len) ==
+           (NS_IN6ADDRSZ / NS_INT16SZ))
+               *tp++ = ':';
+       *tp++ = '\0';
+
+       /*
+        * Check for overflow, copy, and we're done.
+        */
+       if ((size_t)(tp - tmp) > size) {
+               errno = ENOSPC;
+               return (NULL);
+       }
+       strcpy(dst, tmp);
+       return (dst);
+}
+#endif
+
+/* char *
+ * inet_ntop(af, src, dst, size)
+ *     convert a network format address to presentation format.
+ * return:
+ *     pointer to presentation format address (`dst'), or NULL (see errno).
+ * author:
+ *     Paul Vixie, 1996.
+ */
+const char *
+inet_ntop(af, src, dst, size)
+       int af;
+       const void *src;
+       char *dst;
+       size_t size;
+{
+       switch (af) {
+       case AF_INET:
+               return (inet_ntop4(src, dst, size));
+#ifndef NO_IPV6
+       case AF_INET6:
+               return (inet_ntop6(src, dst, size));
+#endif
+       default:
+               errno = EAFNOSUPPORT;
+               return (NULL);
+       }
+       /* NOTREACHED */
+}
diff --git a/diff.c b/diff.c
index e16e0bfc0a8999477f2c1d68a6b82cbc3867e8e5..3a2a175c7ec34d5524f8e664c4dd3f05c24f4d4a 100644 (file)
--- a/diff.c
+++ b/diff.c
@@ -237,7 +237,7 @@ static char *pprint_rename(const char *a, const char *b)
                if (a_midlen < 0) a_midlen = 0;
                if (b_midlen < 0) b_midlen = 0;
 
-               name = xmalloc(len_a + len_b - pfx_length - sfx_length + 7);
+               name = xmalloc(pfx_length + a_midlen + b_midlen + sfx_length + 7);
                sprintf(name, "%.*s{%.*s => %.*s}%s",
                        pfx_length, a,
                        a_midlen, a + pfx_length,
@@ -397,6 +397,46 @@ static void show_stats(struct diffstat_t* data)
                        total_files, adds, dels);
 }
 
+struct checkdiff_t {
+       struct xdiff_emit_state xm;
+       const char *filename;
+       int lineno;
+};
+
+static void checkdiff_consume(void *priv, char *line, unsigned long len)
+{
+       struct checkdiff_t *data = priv;
+
+       if (line[0] == '+') {
+               int i, spaces = 0;
+
+               data->lineno++;
+
+               /* check space before tab */
+               for (i = 1; i < len && (line[i] == ' ' || line[i] == '\t'); i++)
+                       if (line[i] == ' ')
+                               spaces++;
+               if (line[i - 1] == '\t' && spaces)
+                       printf("%s:%d: space before tab:%.*s\n",
+                               data->filename, data->lineno, (int)len, line);
+
+               /* check white space at line end */
+               if (line[len - 1] == '\n')
+                       len--;
+               if (isspace(line[len - 1]))
+                       printf("%s:%d: white space at end: %.*s\n",
+                               data->filename, data->lineno, (int)len, line);
+       } else if (line[0] == ' ')
+               data->lineno++;
+       else if (line[0] == '@') {
+               char *plus = strchr(line, '+');
+               if (plus)
+                       data->lineno = strtol(plus, NULL, 10);
+               else
+                       die("invalid diff");
+       }
+}
+
 static unsigned char *deflate_it(char *data,
                                 unsigned long size,
                                 unsigned long *result_size)
@@ -624,6 +664,41 @@ static void builtin_diffstat(const char *name_a, const char *name_b,
        }
 }
 
+static void builtin_checkdiff(const char *name_a, const char *name_b,
+                            struct diff_filespec *one,
+                            struct diff_filespec *two)
+{
+       mmfile_t mf1, mf2;
+       struct checkdiff_t data;
+
+       if (!two)
+               return;
+
+       memset(&data, 0, sizeof(data));
+       data.xm.consume = checkdiff_consume;
+       data.filename = name_b ? name_b : name_a;
+       data.lineno = 0;
+
+       if (fill_mmfile(&mf1, one) < 0 || fill_mmfile(&mf2, two) < 0)
+               die("unable to read files to diff");
+
+       if (mmfile_is_binary(&mf2))
+               return;
+       else {
+               /* Crazy xdl interfaces.. */
+               xpparam_t xpp;
+               xdemitconf_t xecfg;
+               xdemitcb_t ecb;
+
+               xpp.flags = XDF_NEED_MINIMAL;
+               xecfg.ctxlen = 0;
+               xecfg.flags = 0;
+               ecb.outf = xdiff_outf;
+               ecb.priv = &data;
+               xdl_diff(&mf1, &mf2, &xpp, &xecfg, &ecb);
+       }
+}
+
 struct diff_filespec *alloc_filespec(const char *path)
 {
        int namelen = strlen(path);
@@ -1180,6 +1255,25 @@ static void run_diffstat(struct diff_filepair *p, struct diff_options *o,
        builtin_diffstat(name, other, p->one, p->two, diffstat, complete_rewrite);
 }
 
+static void run_checkdiff(struct diff_filepair *p, struct diff_options *o)
+{
+       const char *name;
+       const char *other;
+
+       if (DIFF_PAIR_UNMERGED(p)) {
+               /* unmerged */
+               return;
+       }
+
+       name = p->one->path;
+       other = (strcmp(name, p->two->path) ? p->two->path : NULL);
+
+       diff_fill_sha1_info(p->one);
+       diff_fill_sha1_info(p->two);
+
+       builtin_checkdiff(name, other, p->one, p->two);
+}
+
 void diff_setup(struct diff_options *options)
 {
        memset(options, 0, sizeof(*options));
@@ -1205,9 +1299,18 @@ int diff_setup_done(struct diff_options *options)
         * recursive bits for other formats here.
         */
        if ((options->output_format == DIFF_FORMAT_PATCH) ||
-           (options->output_format == DIFF_FORMAT_DIFFSTAT))
+           (options->output_format == DIFF_FORMAT_DIFFSTAT) ||
+           (options->output_format == DIFF_FORMAT_CHECKDIFF))
                options->recursive = 1;
 
+       /*
+        * These combinations do not make sense.
+        */
+       if (options->output_format == DIFF_FORMAT_RAW)
+               options->with_raw = 0;
+       if (options->output_format == DIFF_FORMAT_DIFFSTAT)
+               options->with_stat  = 0;
+
        if (options->detect_rename && options->rename_limit < 0)
                options->rename_limit = diff_rename_limit_default;
        if (options->setup & DIFF_SETUP_USE_CACHE) {
@@ -1288,6 +1391,8 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac)
        }
        else if (!strcmp(arg, "--stat"))
                options->output_format = DIFF_FORMAT_DIFFSTAT;
+       else if (!strcmp(arg, "--check"))
+               options->output_format = DIFF_FORMAT_CHECKDIFF;
        else if (!strcmp(arg, "--summary"))
                options->summary = 1;
        else if (!strcmp(arg, "--patch-with-stat")) {
@@ -1610,6 +1715,19 @@ static void diff_flush_stat(struct diff_filepair *p, struct diff_options *o,
        run_diffstat(p, o, diffstat);
 }
 
+static void diff_flush_checkdiff(struct diff_filepair *p,
+               struct diff_options *o)
+{
+       if (diff_unmodified_pair(p))
+               return;
+
+       if ((DIFF_FILE_VALID(p->one) && S_ISDIR(p->one->mode)) ||
+           (DIFF_FILE_VALID(p->two) && S_ISDIR(p->two->mode)))
+               return; /* no tree diffs in patch format */
+
+       run_checkdiff(p, o);
+}
+
 int diff_queue_is_empty(void)
 {
        struct diff_queue_struct *q = &diff_queued_diff;
@@ -1740,6 +1858,9 @@ static void flush_one_pair(struct diff_filepair *p,
                case DIFF_FORMAT_DIFFSTAT:
                        diff_flush_stat(p, options, diffstat);
                        break;
+               case DIFF_FORMAT_CHECKDIFF:
+                       diff_flush_checkdiff(p, options);
+                       break;
                case DIFF_FORMAT_PATCH:
                        diff_flush_patch(p, options);
                        break;
diff --git a/diff.h b/diff.h
index 3027974c1ec74217a58345b4ab48e673ee3db710..c672277df25a6855e09e642cdf6341841b4dd5a3 100644 (file)
--- a/diff.h
+++ b/diff.h
@@ -153,6 +153,7 @@ extern int diff_queue_is_empty(void);
 #define DIFF_FORMAT_NAME       4
 #define DIFF_FORMAT_NAME_STATUS        5
 #define DIFF_FORMAT_DIFFSTAT   6
+#define DIFF_FORMAT_CHECKDIFF  7
 
 extern void diff_flush(struct diff_options*);
 
index 6c59dbd68fc15ddd392086d375c8ecfc35e30c1a..ec1eda20de8d510a9acfd981150a5f1a438a0fe4 100755 (executable)
@@ -37,7 +37,6 @@ show-branch
 status
 tag
 verify-tag
-whatchanged
 EOF
 while read cmd
 do
index 227245c865e3f33e3b795868c484a41d590c553a..d96894d4c2aa6e6c0aa38ca0755ffa16ace2161c 100755 (executable)
@@ -199,7 +199,7 @@ dir="$2"
 [ -e "$dir" ] && echo "$dir already exists." && usage
 mkdir -p "$dir" &&
 D=$(cd "$dir" && pwd) &&
-trap 'err=$?; cd ..; rm -r "$D"; exit $err' exit
+trap 'err=$?; cd ..; rm -r "$D"; exit $err' 0
 case "$bare" in
 yes) GIT_DIR="$D" ;;
 *) GIT_DIR="$D/.git" ;;
@@ -407,5 +407,5 @@ Pull: refs/heads/$head_points_at:$origin_track" &&
 fi
 rm -f "$GIT_DIR/CLONE_HEAD" "$GIT_DIR/REMOTE_HEAD"
 
-trap - exit
+trap - 0
 
index 6ef1a9dedc89af10865ed114458df88617bb5ca9..6785826fef91d35277107ae15a96619d2f5113c6 100755 (executable)
@@ -3,7 +3,7 @@
 # Copyright (c) 2005 Linus Torvalds
 # Copyright (c) 2006 Junio C Hamano
 
-USAGE='[-a] [-s] [-v] [--no-verify] [-m <message> | -F <logfile> | (-C|-c) <commit>) [--amend] [-e] [--author <author>] [[-i | -o] <path>...]'
+USAGE='[-a] [-s] [-v] [--no-verify] [-m <message> | -F <logfile> | (-C|-c) <commit>] [-u] [--amend] [-e] [--author <author>] [[-i | -o] <path>...]'
 SUBDIRECTORY_OK=Yes
 . git-sh-setup
 
@@ -134,13 +134,17 @@ run_status () {
        report "Changed but not updated" \
            "use git-update-index to mark for commit"
 
+        option=""
+        if test -z "$untracked_files"; then
+            option="--directory --no-empty-directory"
+        fi
        if test -f "$GIT_DIR/info/exclude"
        then
-           git-ls-files -z --others --directory \
+           git-ls-files -z --others $option \
                --exclude-from="$GIT_DIR/info/exclude" \
                --exclude-per-directory=.gitignore
        else
-           git-ls-files -z --others --directory \
+           git-ls-files -z --others $option \
                --exclude-per-directory=.gitignore
        fi |
        perl -e '$/ = "\0";
@@ -203,6 +207,7 @@ verbose=
 signoff=
 force_author=
 only_include_assumed=
+untracked_files=
 while case "$#" in 0) break;; esac
 do
   case "$1" in
@@ -340,6 +345,12 @@ do
       verbose=t
       shift
       ;;
+  -u|--u|--un|--unt|--untr|--untra|--untrac|--untrack|--untracke|--untracked|\
+  --untracked-|--untracked-f|--untracked-fi|--untracked-fil|--untracked-file|\
+  --untracked-files)
+      untracked_files=t
+      shift
+      ;;
   --)
       shift
       break
index 8c707f2c664ccfc9cad4fca443a5dee1d75604ba..41ee9a608d762718c33594374dfa4cb3205dd4f9 100755 (executable)
@@ -23,13 +23,13 @@ use File::Basename qw(basename dirname);
 use Time::Local;
 use IO::Socket;
 use IO::Pipe;
-use POSIX qw(strftime dup2);
+use POSIX qw(strftime dup2 :errno_h);
 use IPC::Open2;
 
 $SIG{'PIPE'}="IGNORE";
 $ENV{'TZ'}="UTC";
 
-our($opt_h,$opt_o,$opt_v,$opt_k,$opt_u,$opt_d,$opt_p,$opt_C,$opt_z,$opt_i,$opt_P, $opt_s,$opt_m,$opt_M,$opt_A,$opt_S);
+our($opt_h,$opt_o,$opt_v,$opt_k,$opt_u,$opt_d,$opt_p,$opt_C,$opt_z,$opt_i,$opt_P, $opt_s,$opt_m,$opt_M,$opt_A,$opt_S,$opt_L);
 my (%conv_author_name, %conv_author_email);
 
 sub usage() {
@@ -85,7 +85,7 @@ sub write_author_info($) {
        close ($f);
 }
 
-getopts("hivmkuo:d:p:C:z:s:M:P:A:S:") or usage();
+getopts("hivmkuo:d:p:C:z:s:M:P:A:S:L:") or usage();
 usage if $opt_h;
 
 @ARGV <= 1 or usage();
@@ -315,15 +315,7 @@ sub _line {
                        chomp $cnt;
                        die "Duh: Filesize $cnt" if $cnt !~ /^\d+$/;
                        $line="";
-                       $res=0;
-                       while($cnt) {
-                               my $buf;
-                               my $num = $self->{'socketi'}->read($buf,$cnt);
-                               die "Server: Filesize $cnt: $num: $!\n" if not defined $num or $num<=0;
-                               print $fh $buf;
-                               $res += $num;
-                               $cnt -= $num;
-                       }
+                       $res = $self->_fetchfile($fh, $cnt);
                } elsif($line =~ s/^ //) {
                        print $fh $line;
                        $res += length($line);
@@ -335,14 +327,7 @@ sub _line {
                        chomp $cnt;
                        die "Duh: Mbinary $cnt" if $cnt !~ /^\d+$/ or $cnt<1;
                        $line="";
-                       while($cnt) {
-                               my $buf;
-                               my $num = $self->{'socketi'}->read($buf,$cnt);
-                               die "S: Mbinary $cnt: $num: $!\n" if not defined $num or $num<=0;
-                               print $fh $buf;
-                               $res += $num;
-                               $cnt -= $num;
-                       }
+                       $res += $self->_fetchfile($fh, $cnt);
                } else {
                        chomp $line;
                        if($line eq "ok") {
@@ -384,6 +369,23 @@ sub file {
 
        return ($name, $res);
 }
+sub _fetchfile {
+       my ($self, $fh, $cnt) = @_;
+       my $res;
+       my $bufsize = 1024 * 1024;
+       while($cnt) {
+           if ($bufsize > $cnt) {
+               $bufsize = $cnt;
+           }
+           my $buf;
+           my $num = $self->{'socketi'}->read($buf,$bufsize);
+           die "Server: Filesize $cnt: $num: $!\n" if not defined $num or $num<=0;
+           print $fh $buf;
+           $res += $num;
+           $cnt -= $num;
+       }
+       return $res;
+}
 
 
 package main;
@@ -429,22 +431,25 @@ sub getwd() {
        return $pwd;
 }
 
+sub is_sha1 {
+       my $s = shift;
+       return $s =~ /^[a-f0-9]{40}$/;
+}
 
-sub get_headref($$) {
+sub get_headref ($$) {
     my $name    = shift;
     my $git_dir = shift; 
-    my $sha;
     
-    if (open(C,"$git_dir/refs/heads/$name")) {
-       chomp($sha = <C>);
-       close(C);
-       length($sha) == 40
-           or die "Cannot get head id for $name ($sha): $!\n";
+    my $f = "$git_dir/refs/heads/$name";
+    if(open(my $fh, $f)) {
+           chomp(my $r = <$fh>);
+           is_sha1($r) or die "Cannot get head id for $name ($r): $!";
+           return $r;
     }
-    return $sha;
+    die "unable to open $f: $!" unless $! == POSIX::ENOENT;
+    return undef;
 }
 
-
 -d $git_tree
        or mkdir($git_tree,0777)
        or die "Could not create $git_tree: $!";
@@ -561,98 +566,67 @@ unless($pid) {
 
 my $state = 0;
 
-my($patchset,$date,$author_name,$author_email,$branch,$ancestor,$tag,$logmsg);
-my(@old,@new,@skipped);
-my $commit = sub {
-       my $pid;
-       while(@old) {
-               my @o2;
-               if(@old > 55) {
-                       @o2 = splice(@old,0,50);
-               } else {
-                       @o2 = @old;
-                       @old = ();
-               }
-               system("git-update-index","--force-remove","--",@o2);
-               die "Cannot remove files: $?\n" if $?;
-       }
-       while(@new) {
-               my @n2;
-               if(@new > 12) {
-                       @n2 = splice(@new,0,10);
-               } else {
-                       @n2 = @new;
-                       @new = ();
-               }
-               system("git-update-index","--add",
-                       (map { ('--cacheinfo', @$_) } @n2));
-               die "Cannot add files: $?\n" if $?;
-       }
+sub update_index (\@\@) {
+       my $old = shift;
+       my $new = shift;
+       open(my $fh, '|-', qw(git-update-index -z --index-info))
+               or die "unable to open git-update-index: $!";
+       print $fh
+               (map { "0 0000000000000000000000000000000000000000\t$_\0" }
+                       @$old),
+               (map { '100' . sprintf('%o', $_->[0]) . " $_->[1]\t$_->[2]\0" }
+                       @$new)
+               or die "unable to write to git-update-index: $!";
+       close $fh
+               or die "unable to write to git-update-index: $!";
+       $? and die "git-update-index reported error: $?";
+}
 
-       $pid = open(C,"-|");
-       die "Cannot fork: $!" unless defined $pid;
-       unless($pid) {
-               exec("git-write-tree");
-               die "Cannot exec git-write-tree: $!\n";
-       }
-       chomp(my $tree = <C>);
-       length($tree) == 40
-               or die "Cannot get tree id ($tree): $!\n";
-       close(C)
+sub write_tree () {
+       open(my $fh, '-|', qw(git-write-tree))
+               or die "unable to open git-write-tree: $!";
+       chomp(my $tree = <$fh>);
+       is_sha1($tree)
+               or die "Cannot get tree id ($tree): $!";
+       close($fh)
                or die "Error running git-write-tree: $?\n";
        print "Tree ID $tree\n" if $opt_v;
+       return $tree;
+}
 
-       my $parent = "";
-       if(open(C,"$git_dir/refs/heads/$last_branch")) {
-               chomp($parent = <C>);
-               close(C);
-               length($parent) == 40
-                       or die "Cannot get parent id ($parent): $!\n";
-               print "Parent ID $parent\n" if $opt_v;
-       }
-
-       my $pr = IO::Pipe->new() or die "Cannot open pipe: $!\n";
-       my $pw = IO::Pipe->new() or die "Cannot open pipe: $!\n";
-       $pid = fork();
-       die "Fork: $!\n" unless defined $pid;
-       unless($pid) {
-               $pr->writer();
-               $pw->reader();
-               open(OUT,">&STDOUT");
-               dup2($pw->fileno(),0);
-               dup2($pr->fileno(),1);
-               $pr->close();
-               $pw->close();
-
-               my @par = ();
-               @par = ("-p",$parent) if $parent;
-
-               # loose detection of merges
-               # based on the commit msg
-               foreach my $rx (@mergerx) {
-                       if ($logmsg =~ $rx) {
-                               my $mparent = $1;
-                               if ($mparent eq 'HEAD') { $mparent = $opt_o };
-                               if ( -e "$git_dir/refs/heads/$mparent") {
-                                       $mparent = get_headref($mparent, $git_dir);
-                                       push @par, '-p', $mparent;
-                                       print OUT "Merge parent branch: $mparent\n" if $opt_v;
-                               }
-                       }
+my($patchset,$date,$author_name,$author_email,$branch,$ancestor,$tag,$logmsg);
+my(@old,@new,@skipped);
+sub commit {
+       update_index(@old, @new);
+       @old = @new = ();
+       my $tree = write_tree();
+       my $parent = get_headref($last_branch, $git_dir);
+       print "Parent ID " . ($parent ? $parent : "(empty)") . "\n" if $opt_v;
+
+       my @commit_args;
+       push @commit_args, ("-p", $parent) if $parent;
+
+       # loose detection of merges
+       # based on the commit msg
+       foreach my $rx (@mergerx) {
+               next unless $logmsg =~ $rx && $1;
+               my $mparent = $1 eq 'HEAD' ? $opt_o : $1;
+               if(my $sha1 = get_headref($mparent, $git_dir)) {
+                       push @commit_args, '-p', $mparent;
+                       print "Merge parent branch: $mparent\n" if $opt_v;
                }
-
-               exec("env",
-                       "GIT_AUTHOR_NAME=$author_name",
-                       "GIT_AUTHOR_EMAIL=$author_email",
-                       "GIT_AUTHOR_DATE=".strftime("+0000 %Y-%m-%d %H:%M:%S",gmtime($date)),
-                       "GIT_COMMITTER_NAME=$author_name",
-                       "GIT_COMMITTER_EMAIL=$author_email",
-                       "GIT_COMMITTER_DATE=".strftime("+0000 %Y-%m-%d %H:%M:%S",gmtime($date)),
-                       "git-commit-tree", $tree,@par);
-               die "Cannot exec git-commit-tree: $!\n";
        }
-       $pw->writer();
-       $pr->reader();
+
+       my $commit_date = strftime("+0000 %Y-%m-%d %H:%M:%S",gmtime($date));
+       my $pid = open2(my $commit_read, my $commit_write,
+               'env',
+               "GIT_AUTHOR_NAME=$author_name",
+               "GIT_AUTHOR_EMAIL=$author_email",
+               "GIT_AUTHOR_DATE=$commit_date",
+               "GIT_COMMITTER_NAME=$author_name",
+               "GIT_COMMITTER_EMAIL=$author_email",
+               "GIT_COMMITTER_DATE=$commit_date",
+               'git-commit-tree', $tree, @commit_args);
 
        # compatibility with git2cvs
        substr($logmsg,32767) = "" if length($logmsg) > 32767;
@@ -661,18 +635,17 @@ my $commit = sub {
        if (@skipped) {
            $logmsg .= "\n\n\nSKIPPED:\n\t";
            $logmsg .= join("\n\t", @skipped) . "\n";
+           @skipped = ();
        }
 
-       print $pw "$logmsg\n"
+       print($commit_write "$logmsg\n") && close($commit_write)
                or die "Error writing to git-commit-tree: $!\n";
-       $pw->close();
 
-       print "Committed patch $patchset ($branch ".strftime("%Y-%m-%d %H:%M:%S",gmtime($date)).")\n" if $opt_v;
-       chomp(my $cid = <$pr>);
-       length($cid) == 40
-               or die "Cannot get commit id ($cid): $!\n";
+       print "Committed patch $patchset ($branch $commit_date)\n" if $opt_v;
+       chomp(my $cid = <$commit_read>);
+       is_sha1($cid) or die "Cannot get commit id ($cid): $!\n";
        print "Commit ID $cid\n" if $opt_v;
-       $pr->close();
+       close($commit_read);
 
        waitpid($pid,0);
        die "Error running git-commit-tree: $?\n" if $?;
@@ -716,6 +689,7 @@ my $commit = sub {
        }
 };
 
+my $commitcount = 1;
 while(<CVS>) {
        chomp;
        if($state == 0 and /^-+$/) {
@@ -849,7 +823,14 @@ while(<CVS>) {
        } elsif($state == 9 and /^\s*$/) {
                $state = 10;
        } elsif(($state == 9 or $state == 10) and /^-+$/) {
-               &$commit();
+               $commitcount++;
+               if ($opt_L && $commitcount > $opt_L) {
+                       last;
+               }
+               commit();
+               if (($commitcount & 1023) == 0) {
+                       system("git repack -a -d");
+               }
                $state = 1;
        } elsif($state == 11 and /^-+$/) {
                $state = 1;
@@ -859,7 +840,7 @@ while(<CVS>) {
                print "* UNKNOWN LINE * $_\n";
        }
 }
-&$commit() if $branch and $state != 11;
+commit() if $branch and $state != 11;
 
 unlink($git_index);
 
diff --git a/git.c b/git.c
index fd8e9bf7f2b2f7c26984248d0afe2d2143c82cf8..38e84618dcfdc4bd91a5aec6155696416bace6bd 100644 (file)
--- a/git.c
+++ b/git.c
@@ -50,11 +50,22 @@ static void handle_internal_command(int argc, const char **argv, char **envp)
                { "count-objects", cmd_count_objects },
                { "diff", cmd_diff },
                { "grep", cmd_grep },
+               { "rev-list", cmd_rev_list },
                { "init-db", cmd_init_db },
                { "tar-tree", cmd_tar_tree },
                { "upload-tar", cmd_upload_tar },
-               { "rev-list", cmd_rev_list },
-               { "check-ref-format", cmd_check_ref_format }
+               { "check-ref-format", cmd_check_ref_format },
+               { "ls-files", cmd_ls_files },
+               { "ls-tree", cmd_ls_tree },
+               { "tar-tree", cmd_tar_tree },
+               { "read-tree", cmd_read_tree },
+               { "commit-tree", cmd_commit_tree },
+               { "apply", cmd_apply },
+               { "show-branch", cmd_show_branch },
+               { "diff-files", cmd_diff_files },
+               { "diff-index", cmd_diff_index },
+               { "diff-stages", cmd_diff_stages },
+               { "diff-tree", cmd_diff_tree }
        };
        int i;