GIT 0.99.9h

This is GIT 1.0-rc1 in disguise.  It is plausible that
relatively new parts of the system still need tweaking and
fixing, but that is why it is not 1.0 but rc ;-).

Signed-off-by: Junio C Hamano <junkio@cox.net>
This commit is contained in:
Junio C Hamano 2005-11-11 22:37:38 -08:00
commit f7a2eb7359
53 changed files with 1348 additions and 221 deletions

2
.gitignore vendored
View File

@ -42,6 +42,7 @@ git-index-pack
git-init-db
git-local-fetch
git-log
git-lost+found
git-ls-files
git-ls-remote
git-ls-tree
@ -60,6 +61,7 @@ git-mktag
git-name-rev
git-mv
git-octopus
git-pack-redundant
git-pack-objects
git-parse-remote
git-patch-id

View File

@ -8,13 +8,13 @@ git-diff-index <tree-ish>::
compares the <tree-ish> and the files on the filesystem.
git-diff-index --cached <tree-ish>::
compares the <tree-ish> and the cache.
compares the <tree-ish> and the index.
git-diff-tree [-r] <tree-ish-1> <tree-ish-2> [<pattern>...]::
compares the trees named by the two arguments.
git-diff-files [<pattern>...]::
compares the cache and the files on the filesystem.
compares the index and the files on the filesystem.
An output line is formatted this way:
@ -47,7 +47,7 @@ That is, from the left to the right:
. an LF or a NUL when '-z' option is used, to terminate the record.
<sha1> is shown as all 0's if a file is new on the filesystem
and it is out of sync with the cache.
and it is out of sync with the index.
Example:
@ -104,7 +104,7 @@ where:
The file parameters can point at the user's working file
(e.g. `new-file` in "git-diff-files"), `/dev/null` (e.g. `old-file`
when a new file is added), or a temporary file (e.g. `old-file` in the
cache). 'GIT_EXTERNAL_DIFF' should not worry about unlinking the
index). 'GIT_EXTERNAL_DIFF' should not worry about unlinking the
temporary file --- it is removed when 'GIT_EXTERNAL_DIFF' exits.
For a path that is unmerged, 'GIT_EXTERNAL_DIFF' is called with 1

View File

@ -50,7 +50,7 @@
<orderfile>, which has one shell glob pattern per line.
-R::
Swap two inputs; that is, show differences from cache or
Swap two inputs; that is, show differences from index or
on-disk file to tree contents.
For more detailed explanation on these common options, see also

View File

@ -8,7 +8,7 @@ git-apply - Apply patch on a git index file and a work tree
SYNOPSIS
--------
'git-apply' [--stat] [--numstat] [--summary] [--check] [--index] [--apply] [--index-info] [-z] [<patch>...]
'git-apply' [--stat] [--numstat] [--summary] [--check] [--index] [--apply] [--no-add] [--index-info] [-z] [<patch>...]
DESCRIPTION
-----------
@ -72,6 +72,12 @@ OPTIONS
patch. Give this flag after those flags to also apply
the patch.
--no-add::
When applying a patch, ignore additions made by the
patch. This can be used to extract common part between
two files by first running `diff` on them and applying
the result with this option, which would apply the
deletion part but not addition part.
Author
------

View File

@ -3,7 +3,7 @@ git-checkout-index(1)
NAME
----
git-checkout-index - Copy files from the cache to the working directory
git-checkout-index - Copy files from the index to the working directory
SYNOPSIS
@ -13,23 +13,23 @@ SYNOPSIS
DESCRIPTION
-----------
Will copy all files listed from the cache to the working directory
Will copy all files listed from the index to the working directory
(not overwriting existing files).
OPTIONS
-------
-u::
update stat information for the checked out entries in
the cache file.
the index file.
-q::
be quiet if files exist or are not in the cache
be quiet if files exist or are not in the index
-f::
forces overwrite of existing files
-a::
checks out all files in the cache. Cannot be used
checks out all files in the index. Cannot be used
together with explicit filenames.
-n::
@ -57,7 +57,7 @@ supposed to be able to do things like:
which will force all existing `*.h` files to be replaced with their
cached copies. If an empty command line implied "all", then this would
force-refresh everything in the cache, which was not the point.
force-refresh everything in the index, which was not the point.
To update and refresh only the files already checked out:
@ -74,7 +74,7 @@ desired tree into the index, and do a
git-checkout-index --prefix=git-export-dir/ -a
and git-checkout-index will "export" the cache into the specified
and git-checkout-index will "export" the index into the specified
directory.
NOTE The final "/" is important. The exported name is literally just

View File

@ -8,7 +8,7 @@ git-clone - Clones a repository.
SYNOPSIS
--------
'git-clone' [-l [-s]] [-q] [-n] [-u <upload-pack>] <repository> <directory>
'git-clone' [-l [-s]] [-q] [-n] [-u <upload-pack>] <repository> [<directory>]
DESCRIPTION
-----------
@ -68,9 +68,11 @@ OPTIONS
be any URL git-fetch supports.
<directory>::
The name of a new directory to be cloned into. It is an
error to specify an existing directory.
The name of a new directory to clone into. The "humanish"
part of the source repository is used if no directory is
explicitly given ("repo" for "/path/to/repo.git" and "foo"
for "host.xz:foo/.git"). Cloning into an existing directory
is not allowed.
Author
------
@ -78,7 +80,7 @@ Written by Linus Torvalds <torvalds@osdl.org>
Documentation
--------------
Documentation by Junio C Hamano.
Documentation by Junio C Hamano and the git-list <git@vger.kernel.org>.
GIT

View File

@ -35,7 +35,7 @@ OPTIONS
-i::
Import-only: don't perform a checkout after importing. This option
ensures the working directory and cache remain untouched and will
ensures the working directory and index remain untouched and will
not create them if they do not exist.
-k::

View File

@ -3,7 +3,7 @@ git-diff-files(1)
NAME
----
git-diff-files - Compares files in the working tree and the cache
git-diff-files - Compares files in the working tree and the index
SYNOPSIS
@ -12,9 +12,9 @@ SYNOPSIS
DESCRIPTION
-----------
Compares the files in the working tree and the cache. When paths
Compares the files in the working tree and the index. When paths
are specified, compares only those named paths. Otherwise all
entries in the cache are compared. The output format is the
entries in the index are compared. The output format is the
same as "git-diff-index" and "git-diff-tree".
OPTIONS

View File

@ -3,7 +3,7 @@ git-diff-index(1)
NAME
----
git-diff-index - Compares content and mode of blobs between the cache and repository
git-diff-index - Compares content and mode of blobs between the index and repository
SYNOPSIS
@ -13,10 +13,10 @@ SYNOPSIS
DESCRIPTION
-----------
Compares the content and mode of the blobs found via a tree
object with the content of the current cache and, optionally
object with the content of the current index and, optionally
ignoring the stat state of the file on disk. When paths are
specified, compares only those named paths. Otherwise all
entries in the cache are compared.
entries in the index are compared.
OPTIONS
-------
@ -49,11 +49,11 @@ Cached Mode
-----------
If '--cached' is specified, it allows you to ask:
show me the differences between HEAD and the current cache
show me the differences between HEAD and the current index
contents (the ones I'd write with a "git-write-tree")
For example, let's say that you have worked on your working directory, updated
some files in the cache and are ready to commit. You want to see eactly
some files in the index and are ready to commit. You want to see eactly
*what* you are going to commit is without having to write a new tree
object and compare it that way, and to do that, you just do
@ -92,7 +92,7 @@ which is obviously a very useful question too, since that tells you what
you *could* commit. Again, the output matches the "git-diff-tree -r"
output to a tee, but with a twist.
The twist is that if some file doesn't match the cache, we don't have
The twist is that if some file doesn't match the index, we don't have
a backing store thing for it, and we use the magic "all-zero" sha1 to
show that. So let's say that you have edited `kernel/sched.c`, but
have not actually done a "git-update-index" on it yet - there is no
@ -110,7 +110,7 @@ NOTE: As with other commands of this type, "git-diff-index" does not
actually look at the contents of the file at all. So maybe
`kernel/sched.c` hasn't actually changed, and it's just that you
touched it. In either case, it's a note that you need to
"git-upate-cache" it to make the cache be in sync.
"git-upate-index" it to make the index be in sync.
NOTE: You can have a mixture of files show up as "has been updated"
and "is still dirty in the working directory" together. You can always

View File

@ -8,7 +8,7 @@ git-diff-tree - Compares the content and mode of blobs found via two tree object
SYNOPSIS
--------
'git-diff-tree' [--stdin] [-m] [-s] [-v] [--pretty] [-t] [-r] [--root] [<common diff options>] <tree-ish> [<tree-ish>] [<path>...]
'git-diff-tree' [--stdin] [-m] [-s] [-v] [--no-commit-id] [--pretty] [-t] [-r] [--root] [<common diff options>] <tree-ish> [<tree-ish>] [<path>...]
DESCRIPTION
-----------
@ -74,6 +74,10 @@ separated with a single space are given.
commit message. Without "=<style>", it defaults to
medium.
--no-commit-id::
git-diff-tree outputs a line with the commit ID when
applicable. This flag suppressed the commit ID output.
Limiting Output
---------------

View File

@ -33,7 +33,7 @@ index file and all SHA1 references in .git/refs/* as heads.
Report tags.
--cache::
Consider any object recorded in the cache also as a head node for
Consider any object recorded in the index also as a head node for
an unreachability trace.
--standalone::
@ -125,7 +125,7 @@ GIT_OBJECT_DIRECTORY::
used to specify the object database root (usually $GIT_DIR/objects)
GIT_INDEX_FILE::
used to specify the index file of the cache
used to specify the index file of the index
GIT_ALTERNATE_OBJECT_DIRECTORIES::
used to specify additional object database roots (usually unset)

View File

@ -16,7 +16,7 @@ Computes the object ID value for an object with specified type
with the contents of the named file (which can be outside of the
work tree), and optionally writes the resulting object into the
object database. Reports its object ID to its standard output.
This is used by "git-cvsimport" to update the cache
This is used by "git-cvsimport" to update the index
without modifying files in the work tree. When <type> is not
specified, it defaults to "blob".

View File

@ -0,0 +1,78 @@
git-lost+found(1)
=================
NAME
----
git-lost+found - Recover lost refs that luckily have not yet been pruned.
SYNOPSIS
--------
'git-lost+found'
DESCRIPTION
-----------
Finds dangling commits and tags from the object database, and
creates refs to them in .git/lost-found/ directory. Commits and
tags that dereference to commits go to .git/lost-found/commit
and others are stored in .git/lost-found/other directory.
OUTPUT
------
One line description from the commit and tag found along with
their object name are printed on the standard output.
EXAMPLE
-------
Suppose you run 'git tag -f' and mistyped the tag to overwrite.
The ref to your tag is overwritten, but until you run 'git
prune', it is still there.
------------
$ git lost+found
[1ef2b196d909eed523d4f3c9bf54b78cdd6843c6] GIT 0.99.9c
...
------------
Also you can use gitk to browse how they relate to each other
and existing (probably old) tags.
------------
$ gitk $(cd .git/lost-found/commit && echo ??*)
------------
After making sure that it is the object you are looking for, you
can reconnect it to your regular .git/refs hierarchy.
------------
$ git cat-file -t 1ef2b196
tag
$ git cat-file tag 1ef2b196
object fa41bbce8e38c67a218415de6cfa510c7e50032a
type commit
tag v0.99.9c
tagger Junio C Hamano <junkio@cox.net> 1131059594 -0800
GIT 0.99.9c
This contains the following changes from the "master" branch, since
...
$ git update-ref refs/tags/not-lost-anymore 1ef2b196
$ git rev-parse not-lost-anymore
1ef2b196d909eed523d4f3c9bf54b78cdd6843c6
------------
Author
------
Written by Junio C Hamano 濱野 純 <junkio@cox.net>
Documentation
--------------
Documentation by Junio C Hamano and the git-list <git@vger.kernel.org>.
GIT
---
Part of the gitlink:git[7] suite

View File

@ -3,7 +3,7 @@ git-ls-files(1)
NAME
----
git-ls-files - Information about files in the cache/working directory
git-ls-files - Information about files in the index/working directory
SYNOPSIS

View File

@ -12,7 +12,7 @@ SYNOPSIS
DESCRIPTION
-----------
This looks up the <file>(s) in the cache and, if there are any merge
This looks up the <file>(s) in the index and, if there are any merge
entries, passes the SHA1 hash for those files as arguments 1, 2, 3 (empty
argument if no file), and <file> as argument 4. File modes for the three
files are passed as arguments 5, 6 and 7.
@ -23,7 +23,7 @@ OPTIONS
Interpret all following arguments as filenames.
-a::
Run merge against all files in the cache that need merging.
Run merge against all files in the index that need merging.
-o::
Instead of stopping at the first failed merge, do all of them

View File

@ -0,0 +1,50 @@
git-pack-redundant(1)
=====================
NAME
----
git-pack-redundant - Program used to find redundant pack files.
SYNOPSIS
--------
'git-pack-redundant [ --verbose ] [ --alt-odb ] < --all | .pack filename ... >'
DESCRIPTION
-----------
This program computes which packs in your repository
are redundant. The output is suitable for piping to
'xargs rm' if you are in the root of the repository.
OPTIONS
-------
--all::
Processes all packs. Any filenames on the commandline are ignored.
--alt-odb::
Don't require objects present in packs from alternate object
directories to be present in local packs.
--verbose::
Outputs some statistics to stderr. Has a small performance penalty.
Author
------
Written by Lukas Sandström <lukass@etek.chalmers.se>
Documentation
--------------
Documentation by Lukas Sandström <lukass@etek.chalmers.se>
See-Also
--------
gitlink:git-pack-objects[1]
gitlink:git-repack[1]
gitlink:git-prune-packed[1]
GIT
---
Part of the gitlink:git[7] suite

View File

@ -3,7 +3,7 @@ git-read-tree(1)
NAME
----
git-read-tree - Reads tree information into the directory cache
git-read-tree - Reads tree information into the index
SYNOPSIS
@ -13,11 +13,11 @@ SYNOPSIS
DESCRIPTION
-----------
Reads the tree information given by <tree-ish> into the directory cache,
Reads the tree information given by <tree-ish> into the index,
but does not actually *update* any of the files it "caches". (see:
git-checkout-index)
Optionally, it can merge a tree into the cache, perform a
Optionally, it can merge a tree into the index, perform a
fast-forward (i.e. 2-way) merge, or a 3-way merge, with the -m
flag. When used with -m, the -u flag causes it to also update
the files in the work tree with the result of the merge.
@ -59,10 +59,10 @@ provided.
Single Tree Merge
~~~~~~~~~~~~~~~~~
If only 1 tree is specified, git-read-tree operates as if the user did not
specify '-m', except that if the original cache has an entry for a
specify '-m', except that if the original index has an entry for a
given pathname, and the contents of the path matches with the tree
being read, the stat info from the cache is used. (In other words, the
cache's stat()s take precedence over the merged tree's).
being read, the stat info from the index is used. (In other words, the
index's stat()s take precedence over the merged tree's).
That means that if you do a "git-read-tree -m <newtree>" followed by a
"git-checkout-index -f -u -a", the "git-checkout-index" only checks out
@ -96,7 +96,7 @@ Here are the "carry forward" rules:
-------------------------------------------------------
0 nothing nothing nothing (does not happen)
1 nothing nothing exists use M
2 nothing exists nothing remove path from cache
2 nothing exists nothing remove path from index
3 nothing exists exists use M
clean I==H I==M
@ -109,7 +109,7 @@ Here are the "carry forward" rules:
8 yes N/A no nothing exists fail
9 no N/A no nothing exists fail
10 yes yes N/A exists nothing remove path from cache
10 yes yes N/A exists nothing remove path from index
11 no yes N/A exists nothing fail
12 yes no N/A exists nothing fail
13 no no N/A exists nothing fail
@ -128,7 +128,7 @@ Here are the "carry forward" rules:
20 yes yes no exists exists use M
21 no yes no exists exists fail
In all "keep index" cases, the cache entry stays as in the
In all "keep index" cases, the index entry stays as in the
original index file. If the entry were not up to date,
git-read-tree keeps the copy in the work tree intact when
operating under the -u flag.
@ -245,7 +245,7 @@ since you pulled from him:
Your work tree is still based on your HEAD ($JC), but you have
some edits since. Three-way merge makes sure that you have not
added or modified cache entries since $JC, and if you haven't,
added or modified index entries since $JC, and if you haven't,
then does the right thing. So with the following sequence:
$ git-read-tree -m -u `git-merge-base $JC $LT` $JC $LT

View File

@ -44,7 +44,7 @@ When importing incementally, you might need to edit the .git/svn2git file.
-i::
Import-only: don't perform a checkout after importing. This option
ensures the working directory and cache remain untouched and will
ensures the working directory and index remain untouched and will
not create them if they do not exist.
-t <trunk_subdir>::

View File

@ -21,7 +21,7 @@ SYNOPSIS
DESCRIPTION
-----------
Modifies the index or directory cache. Each file mentioned is updated
into the cache and any 'unmerged' or 'needs updating' state is
into the index and any 'unmerged' or 'needs updating' state is
cleared.
The way "git-update-index" handles files it is told about can be modified
@ -30,26 +30,26 @@ using the various options:
OPTIONS
-------
--add::
If a specified file isn't in the cache already then it's
If a specified file isn't in the index already then it's
added.
Default behaviour is to ignore new files.
--remove::
If a specified file is in the cache but is missing then it's
If a specified file is in the index but is missing then it's
removed.
Default behaviour is to ignore removed file.
--refresh::
Looks at the current cache and checks to see if merges or
Looks at the current index and checks to see if merges or
updates are needed by checking stat() information.
-q::
Quiet. If --refresh finds that the cache needs an update, the
Quiet. If --refresh finds that the index needs an update, the
default behavior is to error out. This option makes
git-update-index continue anyway.
--unmerged::
If --refresh finds unmerged changes in the cache, the default
If --refresh finds unmerged changes in the index, the default
behavior is to error out. This option makes git-update-index
continue anyway.
@ -57,7 +57,7 @@ OPTIONS
Ignores missing files during a --refresh
--cacheinfo <mode> <object> <path>::
Directly insert the specified info into the cache.
Directly insert the specified info into the index.
--index-info::
Read index info from stdin.
@ -68,7 +68,7 @@ OPTIONS
--info-only::
Do not create objects in the object database for all
<file> arguments that follow this flag; just insert
their object IDs into the cache.
their object IDs into the index.
--force-remove::
Remove the file from the index even when the working directory
@ -106,14 +106,14 @@ OPTIONS
Using --refresh
---------------
'--refresh' does not calculate a new sha1 file or bring the cache
'--refresh' does not calculate a new sha1 file or bring the index
up-to-date for mode/content changes. But what it *does* do is to
"re-match" the stat information of a file with the cache, so that you
can refresh the cache for a file that hasn't been changed but where
"re-match" the stat information of a file with the index, so that you
can refresh the index for a file that hasn't been changed but where
the stat entry is out of date.
For example, you'd want to do this after doing a "git-read-tree", to link
up the stat cache details with the proper files.
up the stat index details with the proper files.
Using --cacheinfo or --info-only
--------------------------------

View File

@ -3,7 +3,7 @@ git-write-tree(1)
NAME
----
git-write-tree - Creates a tree object from the current cache
git-write-tree - Creates a tree object from the current index
SYNOPSIS
@ -12,11 +12,11 @@ SYNOPSIS
DESCRIPTION
-----------
Creates a tree object using the current cache.
Creates a tree object using the current index.
The cache must be merged.
The index must be merged.
Conceptually, "git-write-tree" sync()s the current directory cache contents
Conceptually, "git-write-tree" sync()s the current index contents
into a set of tree files.
In order to have that match what is actually in your directory right
now, you need to have done a "git-update-index" phase before you did the

View File

@ -40,7 +40,7 @@ reflect recent changes.
Commands Overview
-----------------
The git commands can helpfully be split into those that manipulate
the repository, the cache and the working fileset, those that
the repository, the index and the working fileset, those that
interrogate and compare them, and those that moves objects and
references between repositories.
@ -59,7 +59,7 @@ gitlink:git-apply[1]::
applies it to the working tree.
gitlink:git-checkout-index[1]::
Copy files from the cache to the working directory
Copy files from the index to the working directory
gitlink:git-commit-tree[1]::
Creates a new commit object
@ -86,7 +86,7 @@ gitlink:git-prune-packed[1]::
Remove extra objects that are already in pack files.
gitlink:git-read-tree[1]::
Reads tree information into the directory cache
Reads tree information into the directory index
gitlink:git-unpack-objects[1]::
Unpacks objects out of a packed archive.
@ -95,7 +95,7 @@ gitlink:git-update-index[1]::
Modifies the index or directory cache
gitlink:git-write-tree[1]::
Creates a tree from the current cache
Creates a tree from the current index
Interrogation commands
@ -105,10 +105,10 @@ gitlink:git-cat-file[1]::
Provide content or type information for repository objects
gitlink:git-diff-index[1]::
Compares content and mode of blobs between the cache and repository
Compares content and mode of blobs between the index and repository
gitlink:git-diff-files[1]::
Compares files in the working tree and the cache
Compares files in the working tree and the index
gitlink:git-diff-stages[1]::
Compares two "merge stages" in the index file.
@ -120,7 +120,7 @@ gitlink:git-fsck-objects[1]::
Verifies the connectivity and validity of the objects in the database
gitlink:git-ls-files[1]::
Information about files in the cache/working directory
Information about files in the index/working directory
gitlink:git-ls-tree[1]::
Displays a tree object in human readable form
@ -309,6 +309,9 @@ gitlink:git-convert-objects[1]::
gitlink:git-cvsimport[1]::
Salvage your data out of another SCM people love to hate.
gitlink:git-lost+found[1]::
Recover lost refs that luckily have not yet been pruned.
gitlink:git-merge-one-file[1]::
The standard helper program to use with "git-merge-index"
@ -490,8 +493,8 @@ git so take care if using Cogito etc
'GIT_INDEX_FILE'::
This environment allows the specification of an alternate
cache/index file. If not specified, the default of
`$GIT_DIR/index` is used.
index file. If not specified, the default of `$GIT_DIR/index`
is used.
'GIT_OBJECT_DIRECTORY'::
If the object storage directory is specified via this

View File

@ -43,14 +43,14 @@ DAG::
index::
A collection of files with stat information, whose contents are
stored as objects. The cache is a stored version of your working
stored as objects. The index is a stored version of your working
tree. Truth be told, it can also contain a second, and even a third
version of a working tree, which are used when merging.
index entry::
The information regarding a particular file, stored in the index.
An index entry can be unmerged, if a merge was started, but not
yet finished (i.e. if the cache contains multiple versions of
yet finished (i.e. if the index contains multiple versions of
that file).
unmerged index:
@ -75,7 +75,7 @@ checkout::
stored in the object database.
commit::
As a verb: The action of storing the current state of the cache in the
As a verb: The action of storing the current state of the index in the
object database. The result is a revision.
As a noun: Short hand for commit object.

View File

@ -8,7 +8,7 @@
- Rsync URL: rsync://remote.machine/path/to/repo.git/
- HTTP(s) URL: http://remote.machine/path/to/repo.git/
- git URL: git://remote.machine/path/to/repo.git/
or remote.machine:/path/to/repo.git/
- ssh URL: remote.machine:/path/to/repo.git/
- Local directory: /path/to/repo.git/
===============================================================
+

View File

@ -131,7 +131,7 @@ actually check in your hard work, you will have to go through two steps:
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.
@ -199,7 +199,7 @@ was just to show that `git-update-index` did something magical, and
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
@ -440,7 +440,7 @@ a bit about what you have done.
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.

12
INSTALL
View File

@ -75,3 +75,15 @@ Issues of note:
history graphically
- "ssh" is used to push and pull over the net
- "perl" and POSIX-compliant shells are needed to use most of
the barebone Porcelainish scripts.
- "python" 2.3 or more recent; if you have 2.3, you may need
to build with "make WITH_OWN_SUBPROCESS_PY=YesPlease".
- Some platform specific issues are dealt with Makefile rules,
but depending on your specific installation, you may not
have all the libraries/tools needed, or you may have
necessary libraries at unusual locations. Please look at the
top of the Makefile to see what can be adjusted for your needs.

View File

@ -50,7 +50,7 @@
# Define USE_STDEV below if you want git to care about the underlying device
# change being considered an inode change from the update-cache perspective.
GIT_VERSION = 0.99.9g
GIT_VERSION = 0.99.9h
# CFLAGS is for the users to override from the command line.
@ -89,7 +89,8 @@ SCRIPT_SH = \
git-tag.sh git-verify-tag.sh git-whatchanged.sh git.sh \
git-applymbox.sh git-applypatch.sh git-am.sh \
git-merge.sh git-merge-stupid.sh git-merge-octopus.sh \
git-merge-resolve.sh git-merge-ours.sh git-grep.sh
git-merge-resolve.sh git-merge-ours.sh git-grep.sh \
git-lost+found.sh
SCRIPT_PERL = \
git-archimport.perl git-cvsimport.perl git-relink.perl \
@ -122,7 +123,7 @@ PROGRAMS = \
git-unpack-objects$X git-update-index$X git-update-server-info$X \
git-upload-pack$X git-verify-pack$X git-write-tree$X \
git-update-ref$X git-symbolic-ref$X git-check-ref-format$X \
git-name-rev$X $(SIMPLE_PROGRAMS)
git-name-rev$X git-pack-redundant$X $(SIMPLE_PROGRAMS)
# Backward compatibility -- to be removed after 1.0
PROGRAMS += git-ssh-pull$X git-ssh-push$X

13
apply.c
View File

@ -23,10 +23,11 @@ static int numstat = 0;
static int summary = 0;
static int check = 0;
static int apply = 1;
static int no_add = 0;
static int show_index_info = 0;
static int line_termination = '\n';
static const char apply_usage[] =
"git-apply [--stat] [--numstat] [--summary] [--check] [--index] [--apply] [--index-info] [-z] <patch>...";
"git-apply [--stat] [--numstat] [--summary] [--check] [--index] [--apply] [--no-add] [--index-info] [-z] <patch>...";
/*
* For "diff-stat" like behaviour, we keep track of the biggest change
@ -1112,8 +1113,10 @@ static int apply_one_fragment(struct buffer_desc *desc, struct fragment *frag)
break;
/* Fall-through for ' ' */
case '+':
memcpy(new + newsize, patch + 1, plen);
newsize += plen;
if (*patch != '+' || !no_add) {
memcpy(new + newsize, patch + 1, plen);
newsize += plen;
}
break;
case '@': case '\\':
/* Ignore it, we already handled it */
@ -1710,6 +1713,10 @@ int main(int argc, char **argv)
excludes = x;
continue;
}
if (!strcmp(arg, "--no-add")) {
no_add = 1;
continue;
}
if (!strcmp(arg, "--stat")) {
apply = 0;
diffstat = 1;

View File

@ -34,6 +34,8 @@ enum cmit_fmt get_commit_format(const char *arg)
return CMIT_FMT_SHORT;
if (!strcmp(arg, "=full"))
return CMIT_FMT_FULL;
if (!strcmp(arg, "=fuller"))
return CMIT_FMT_FULLER;
if (!strcmp(arg, "=oneline"))
return CMIT_FMT_ONELINE;
die("invalid --pretty format");
@ -361,6 +363,7 @@ static int add_user_info(const char *what, enum cmit_fmt fmt, char *buf, const c
int namelen;
unsigned long time;
int tz, ret;
const char *filler = " ";
if (fmt == CMIT_FMT_ONELINE)
return 0;
@ -371,9 +374,20 @@ static int add_user_info(const char *what, enum cmit_fmt fmt, char *buf, const c
time = strtoul(date, &date, 10);
tz = strtol(date, NULL, 10);
ret = sprintf(buf, "%s: %.*s\n", what, namelen, line);
if (fmt == CMIT_FMT_MEDIUM)
ret = sprintf(buf, "%s: %.*s%.*s\n", what,
(fmt == CMIT_FMT_FULLER) ? 4 : 0,
filler, namelen, line);
switch (fmt) {
case CMIT_FMT_MEDIUM:
ret += sprintf(buf + ret, "Date: %s\n", show_date(time, tz));
break;
case CMIT_FMT_FULLER:
ret += sprintf(buf + ret, "%sDate: %s\n", what, show_date(time, tz));
break;
default:
/* notin' */
break;
}
return ret;
}
@ -448,12 +462,21 @@ unsigned long pretty_print_commit(enum cmit_fmt fmt, const char *msg, unsigned l
die("bad parent line in commit");
offset += add_parent_info(fmt, buf + offset, line, ++parents);
}
/*
* MEDIUM == DEFAULT shows only author with dates.
* FULL shows both authors but not dates.
* FULLER shows both authors and dates.
*/
if (!memcmp(line, "author ", 7))
offset += add_user_info("Author", fmt, buf + offset, line + 7);
if (fmt == CMIT_FMT_FULL) {
if (!memcmp(line, "committer ", 10))
offset += add_user_info("Commit", fmt, buf + offset, line + 10);
}
offset += add_user_info("Author", fmt,
buf + offset,
line + 7);
if (!memcmp(line, "committer ", 10) &&
(fmt == CMIT_FMT_FULL || fmt == CMIT_FMT_FULLER))
offset += add_user_info("Commit", fmt,
buf + offset,
line + 10);
continue;
}

View File

@ -43,6 +43,7 @@ enum cmit_fmt {
CMIT_FMT_DEFAULT = CMIT_FMT_MEDIUM,
CMIT_FMT_SHORT,
CMIT_FMT_FULL,
CMIT_FMT_FULLER,
CMIT_FMT_ONELINE,
};

6
debian/changelog vendored
View File

@ -1,3 +1,9 @@
git-core (0.99.9h-0) unstable; urgency=low
* GIT 0.99.9h
-- Junio C Hamano <junkio@cox.net> Fri, 11 Nov 2005 22:33:18 -0800
git-core (0.99.9g-0) unstable; urgency=low
* GIT 0.99.9g

View File

@ -3,6 +3,7 @@
#include "commit.h"
static int show_root_diff = 0;
static int no_commit_id = 0;
static int verbose_header = 0;
static int ignore_merges = 1;
static int read_stdin = 0;
@ -29,7 +30,8 @@ static int call_diff_flush(void)
return 0;
}
if (header) {
printf("%s%c", header, diff_options.line_termination);
if (!no_commit_id)
printf("%s%c", header, diff_options.line_termination);
header = NULL;
}
diff_flush(&diff_options);
@ -231,6 +233,10 @@ int main(int argc, const char **argv)
show_root_diff = 1;
continue;
}
if (!strcmp(arg, "--no-commit-id")) {
no_commit_id = 1;
continue;
}
usage(diff_tree_usage);
}
if (diff_options.output_format == DIFF_FORMAT_PATCH)

View File

@ -565,6 +565,11 @@ sub parselog {
next if $t =~ m!\{arch\}/!;
next if $t =~ m!\.arch-ids/!;
next if $t =~ m!\.arch-inventory$!;
# tla cat-archive-log will give us filenames with spaces as file\(sp)name - why?
# we can assume that any filename with \ indicates some pika escaping that we want to get rid of.
if ($t =~ /\\/ ){
$t = `tla escape --unescaped '$t'`;
}
push (@tmp, shell_quote($t));
}
@$ref = @tmp;

View File

@ -23,7 +23,7 @@ fi
http_fetch () {
# $1 = Remote, $2 = Local
curl -nsf $curl_extra_args "$1" >"$2"
curl -nsfL $curl_extra_args "$1" >"$2"
}
clone_dumb_http () {
@ -96,7 +96,10 @@ if base=$(get_repo_base "$repo"); then
fi
dir="$2"
mkdir "$dir" &&
# Try using "humanish" part of source repo if user didn't specify one
[ -z "$dir" ] && dir=$(echo "$repo" | sed -e 's|/$||' -e 's|:*/*\.git$||' -e 's|.*/||g')
[ -e "$dir" ] && $(echo "$dir already exists."; usage)
mkdir -p "$dir" &&
D=$(
(cd "$dir" && git-init-db && pwd)
) &&
@ -163,7 +166,7 @@ yes,yes)
rm -f "$D/.git/TMP_ALT"
if test -f "$D/.git/TMP_ALT"
then
( cd $D &&
( cd "$D" &&
. git-parse-remote &&
resolve_alternates "$repo" <"./.git/TMP_ALT" ) |
while read alt
@ -191,7 +194,7 @@ yes,yes)
;;
esac
cd $D || exit
cd "$D" || exit
if test -f ".git/HEAD"
then

View File

@ -184,7 +184,7 @@ then
}
'
set_author_env=`git-cat-file commit "$use_commit" |
sed -ne "$pick_author_script"`
LANG=C LC_ALL=C sed -ne "$pick_author_script"`
eval "$set_author_env"
export GIT_AUTHOR_NAME
export GIT_AUTHOR_EMAIL

View File

@ -1,4 +1,4 @@
# Pass --without docs to rpmbuild if you don't want the documetnation
# Pass --without docs to rpmbuild if you don't want the documentation
Name: git-core
Version: @@VERSION@@
Release: 1%{?dist}
@ -7,7 +7,7 @@ License: GPL
Group: Development/Tools
URL: http://kernel.org/pub/software/scm/git/
Source: http://kernel.org/pub/software/scm/git/%{name}-%{version}.tar.gz
BuildRequires: zlib-devel, openssl-devel, curl-devel %{!?_without_docs:, xmlto, asciidoc > 6.0.3}
BuildRequires: zlib-devel >= 1.2, openssl-devel, curl-devel %{!?_without_docs:, xmlto, asciidoc > 6.0.3}
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
Requires: zlib >= 1.2, rsync, rcs, curl, less, openssh-clients, python >= 2.3, tk >= 8.4
@ -20,22 +20,30 @@ rudimentary tools that can be used as a SCM, but you should look
elsewhere for tools for ordinary humans layered on top of this.
%package svn
Summary: Git tools for importing Subversion repositories.
Summary: Git tools for importing Subversion repositories
Group: Development/Tools
Requires: subversion
Requires: git-core = %{version}-%{release}, subversion
%description svn
Git tools for importing Subversion repositories.
%package cvs
Summary: Git tools for importing CVS repositories.
Summary: Git tools for importing CVS repositories
Group: Development/Tools
Requires: cvs
Requires: git-core = %{version}-%{release}, cvs, cvsps
%description cvs
Git tools for importing CVS repositories.
%package email
Summary: Git tools for sending email.
%package arch
Summary: Git tools for importing Arch repositories
Group: Development/Tools
Requires: git-core = %{version}-%{release}, tla
%description arch
Git tools for importing Arch repositories.
%package email
Summary: Git tools for sending email
Group: Development/Tools
Requires: git-core = %{version}-%{release}
%description email
Git tools for sending email.
@ -52,33 +60,54 @@ make %{_smp_mflags} DESTDIR=$RPM_BUILD_ROOT WITH_OWN_SUBPROCESS_PY=YesPlease WIT
prefix=%{_prefix} mandir=%{_mandir} \
install %{!?_without_docs: install-doc}
(find $RPM_BUILD_ROOT%{_bindir} -type f | grep -vE "svn|cvs|email" | sed -e s@^$RPM_BUILD_ROOT@@) > bin-man-files
(find $RPM_BUILD_ROOT%{_bindir} -type f | grep -vE "arch|svn|cvs|email" | sed -e s@^$RPM_BUILD_ROOT@@) > bin-man-doc-files
%if %{!?_without_docs:1}0
(find $RPM_BUILD_ROOT%{_mandir} -type f | grep -vE "svn|cvs|email" | sed -e s@^$RPM_BUILD_ROOT@@ -e 's/$/*/' ) >> bin-man-files
(find $RPM_BUILD_ROOT%{_mandir} $RPM_BUILD_ROOT/Documentation -type f | grep -vE "arch|svn|git-cvs|email" | sed -e s@^$RPM_BUILD_ROOT@@ -e 's/$/*/' ) >> bin-man-doc-files
%endif
%clean
rm -rf $RPM_BUILD_ROOT
%files svn
%defattr(-,root,root)
%{_bindir}/*svn*
%doc Documentation/*svn*.txt
%{!?_without_docs: %{_mandir}/man1/*svn*.1*}
%{!?_without_docs: %doc Documentation/*svn*.html }
%files cvs
%defattr(-,root,root)
%doc Documentation/*git-cvs*.txt
%{_bindir}/*cvs*
%{!?_without_docs: %{_mandir}/man1/*cvs*.1*}
%{!?_without_docs: %doc Documentation/*git-cvs*.html }
%files arch
%defattr(-,root,root)
%doc Documentation/*arch*.txt
%{_bindir}/*arch*
%{!?_without_docs: %{_mandir}/man1/*arch*.1*}
%{!?_without_docs: %doc Documentation/*arch*.html }
%files email
%defattr(-,root,root)
%doc Documentation/*email*.txt
%{_bindir}/*email*
%{!?_without_docs: %{_mandir}/man1/*email*.1*}
%{!?_without_docs: %doc Documentation/*email*.html }
%files -f bin-man-files
%files -f bin-man-doc-files
%defattr(-,root,root)
%{_datadir}/git-core/
%doc README COPYING Documentation/*.txt
%{!?_without_docs: %doc Documentation/*.html }
%changelog
* Thu Nov 10 2005 Chris Wright <chrisw@osdl.org> 0.99.9g-1
- zlib dependency fix
- Minor cleanups from split
- Move arch import to separate package as well
* Tue Sep 27 2005 Jim Radford <radford@blackbean.org>
- Move programs with non-standard dependencies (svn, cvs, email)
into separate packages

View File

@ -230,7 +230,7 @@ do
$u =~ s{([^-a-zA-Z0-9/.])}{sprintf"%%%02x",ord($1)}eg;
print "$u";
' "$remote_name")
head=$(curl -nsf $curl_extra_args "$remote/$remote_name_quoted") &&
head=$(curl -nsfL $curl_extra_args "$remote/$remote_name_quoted") &&
expr "$head" : "$_x40\$" >/dev/null ||
die "Failed to fetch $remote_name from $remote"
echo >&2 Fetching "$remote_name from $remote" using http

View File

@ -201,7 +201,7 @@ process_one () {
;;
esac
eval "$(sed -ne "$whosepatchScript" $commsg)"
eval "$(LANG=C LC_ALL=C sed -ne "$whosepatchScript" $commsg)"
test "$author,$au" = ",$me" || {
mailScript="$mailScript"'
a\

23
git-lost+found.sh Executable file
View File

@ -0,0 +1,23 @@
#!/bin/sh
. git-sh-setup || die "Not a git archive."
laf="$GIT_DIR/lost-found"
rm -fr "$laf" && mkdir -p "$laf/commit" "$laf/other" || exit
git fsck-objects |
while read dangling type sha1
do
case "$dangling" in
dangling)
if git-rev-parse --verify "$sha1^0" >/dev/null 2>/dev/null
then
dir="$laf/commit"
git-show-branch "$sha1"
else
dir="$laf/other"
fi
echo "$sha1" >"$dir/$sha1"
;;
esac
done

View File

@ -5,6 +5,9 @@
# Resolve two or more trees.
#
LF='
'
# The first parameters up to -- are merge bases; the rest are heads.
bases= head= remotes= sep_seen=
for arg
@ -42,14 +45,18 @@ CNT=1 ;# counting our head
NON_FF_MERGE=0
for SHA1 in $remotes
do
common=$(git-merge-base $MRC $SHA1) ||
common=$(git-merge-base --all $MRC $SHA1) ||
die "Unable to find common commit with $SHA1"
if test "$common" = $SHA1
then
case "$common" in
?*"$LF"?*)
die "Not trivially mergeable."
;;
$SHA1)
echo "Already up-to-date with $SHA1"
continue
fi
;;
esac
CNT=`expr $CNT + 1`
PARENT="$PARENT -p $SHA1"
@ -79,7 +86,15 @@ do
exit 2 ; # Automatic merge failed; should not be doing Octopus
next=$(git-write-tree 2>/dev/null)
fi
MRC=$common
# We have merged the other branch successfully. Ideally
# we could implement OR'ed heads in merge-base, and keep
# a list of commits we have merged so far in MRC to feed
# them to merge-base, but we approximate it by keep using
# the current MRC. We used to update it to $common, which
# was incorrectly doing AND'ed merge-base here, which was
# unneeded.
MRT=$next
done

View File

@ -40,7 +40,7 @@ case "${1:-.}${2:-.}${3:-.}" in
;;
#
# Added in both (check for same permissions).
# Added in both, identically (check for same permissions).
#
".$3$2")
if [ "$6" != "$7" ]; then
@ -56,10 +56,27 @@ case "${1:-.}${2:-.}${3:-.}" in
#
# Modified in both, but differently.
#
"$1$2$3")
echo "Auto-merging $4."
orig=`git-unpack-file $1`
"$1$2$3" | ".$2$3")
src2=`git-unpack-file $3`
case "$1" in
'')
echo "Added $4 in both, but differently."
# This extracts OUR file in $orig, and uses git-apply to
# remove lines that are unique to ours.
orig=`git-unpack-file $2`
sz0=`wc -c <"$orig"`
diff -u -La/$orig -Lb/$orig $orig $src2 | git-apply --no-add
sz1=`wc -c <"$orig"`
# If we do not have enough common material, it is not
# worth trying two-file merge using common subsections.
expr "$sz0" \< "$sz1" \* 2 >/dev/null || : >$orig
;;
*)
echo "Auto-merging $4."
orig=`git-unpack-file $1`
;;
esac
# We reset the index to the first branch, making
# git-diff-file useful
@ -73,6 +90,9 @@ case "${1:-.}${2:-.}${3:-.}" in
echo "ERROR: Permissions conflict: $5->$6,$7."
ret=1
fi
if [ "$1" = '' ]; then
ret=1
fi
if [ $ret -ne 0 ]; then
echo "ERROR: Merge conflict in $4."

View File

@ -1,4 +1,7 @@
#!/usr/bin/python
#
# Copyright (C) 2005 Fredrik Kuivinen
#
import sys, math, random, os, re, signal, tempfile, stat, errno, traceback
from heapq import heappush, heappop
@ -7,6 +10,11 @@ from sets import Set
sys.path.append('''@@GIT_PYTHON_PATH@@''')
from gitMergeCommon import *
outputIndent = 0
def output(*args):
sys.stdout.write(' '*outputIndent)
printList(args)
originalIndexFile = os.environ.get('GIT_INDEX_FILE',
os.environ.get('GIT_DIR', '.git') + '/index')
temporaryIndexFile = os.environ.get('GIT_DIR', '.git') + \
@ -41,27 +49,27 @@ def merge(h1, h2, branch1Name, branch2Name, graph, callDepth=0):
assert(isinstance(h1, Commit) and isinstance(h2, Commit))
assert(isinstance(graph, Graph))
def infoMsg(*args):
sys.stdout.write(' '*callDepth)
printList(args)
global outputIndent
infoMsg('Merging:')
infoMsg(h1)
infoMsg(h2)
output('Merging:')
output(h1)
output(h2)
sys.stdout.flush()
ca = getCommonAncestors(graph, h1, h2)
infoMsg('found', len(ca), 'common ancestor(s):')
output('found', len(ca), 'common ancestor(s):')
for x in ca:
infoMsg(x)
output(x)
sys.stdout.flush()
mergedCA = ca[0]
for h in ca[1:]:
outputIndent = callDepth+1
[mergedCA, dummy] = merge(mergedCA, h,
'Temporary shared merge branch 1',
'Temporary shared merge branch 2',
'Temporary merge branch 1',
'Temporary merge branch 2',
graph, callDepth+1)
outputIndent = callDepth
assert(isinstance(mergedCA, Commit))
global cacheOnly
@ -116,7 +124,7 @@ def mergeTrees(head, merge, common, branch1Name, branch2Name):
assert(isSha(head) and isSha(merge) and isSha(common))
if common == merge:
print 'Already uptodate!'
output('Already uptodate!')
return [head, True]
if cacheOnly:
@ -296,13 +304,13 @@ def uniquePath(path, branch):
raise
branch = branch.replace('/', '_')
newPath = path + '_' + branch
newPath = path + '~' + branch
suffix = 0
while newPath in currentFileSet or \
newPath in currentDirectorySet or \
fileExists(newPath):
suffix += 1
newPath = path + '_' + branch + '_' + str(suffix)
newPath = path + '~' + branch + '_' + str(suffix)
currentFileSet.add(newPath)
return newPath
@ -554,23 +562,24 @@ def processRenames(renamesA, renamesB, branchNameA, branchNameB):
ren2.processed = True
if ren1.dstName != ren2.dstName:
print 'CONFLICT (rename/rename): Rename', \
fmtRename(path, ren1.dstName), 'in branch', branchName1, \
'rename', fmtRename(path, ren2.dstName), 'in', branchName2
output('CONFLICT (rename/rename): Rename',
fmtRename(path, ren1.dstName), 'in branch', branchName1,
'rename', fmtRename(path, ren2.dstName), 'in',
branchName2)
cleanMerge = False
if ren1.dstName in currentDirectorySet:
dstName1 = uniquePath(ren1.dstName, branchName1)
print ren1.dstName, 'is a directory in', branchName2, \
'adding as', dstName1, 'instead.'
output(ren1.dstName, 'is a directory in', branchName2,
'adding as', dstName1, 'instead.')
removeFile(False, ren1.dstName)
else:
dstName1 = ren1.dstName
if ren2.dstName in currentDirectorySet:
dstName2 = uniquePath(ren2.dstName, branchName2)
print ren2.dstName, 'is a directory in', branchName1, \
'adding as', dstName2, 'instead.'
output(ren2.dstName, 'is a directory in', branchName1,
'adding as', dstName2, 'instead.')
removeFile(False, ren2.dstName)
else:
dstName2 = ren1.dstName
@ -585,13 +594,14 @@ def processRenames(renamesA, renamesB, branchNameA, branchNameB):
branchName1, branchName2)
if merge or not clean:
print 'Renaming', fmtRename(path, ren1.dstName)
output('Renaming', fmtRename(path, ren1.dstName))
if merge:
print 'Auto-merging', ren1.dstName
output('Auto-merging', ren1.dstName)
if not clean:
print 'CONFLICT (content): merge conflict in', ren1.dstName
output('CONFLICT (content): merge conflict in',
ren1.dstName)
cleanMerge = False
if not cacheOnly:
@ -615,25 +625,25 @@ def processRenames(renamesA, renamesB, branchNameA, branchNameB):
if ren1.dstName in currentDirectorySet:
newPath = uniquePath(ren1.dstName, branchName1)
print 'CONFLICT (rename/directory): Rename', \
fmtRename(ren1.srcName, ren1.dstName), 'in', branchName1,\
'directory', ren1.dstName, 'added in', branchName2
print 'Renaming', ren1.srcName, 'to', newPath, 'instead'
output('CONFLICT (rename/directory): Rename',
fmtRename(ren1.srcName, ren1.dstName), 'in', branchName1,
'directory', ren1.dstName, 'added in', branchName2)
output('Renaming', ren1.srcName, 'to', newPath, 'instead')
cleanMerge = False
removeFile(False, ren1.dstName)
updateFile(False, ren1.dstSha, ren1.dstMode, newPath)
elif srcShaOtherBranch == None:
print 'CONFLICT (rename/delete): Rename', \
fmtRename(ren1.srcName, ren1.dstName), 'in', \
branchName1, 'and deleted in', branchName2
output('CONFLICT (rename/delete): Rename',
fmtRename(ren1.srcName, ren1.dstName), 'in',
branchName1, 'and deleted in', branchName2)
cleanMerge = False
updateFile(False, ren1.dstSha, ren1.dstMode, ren1.dstName)
elif dstShaOtherBranch:
newPath = uniquePath(ren1.dstName, branchName2)
print 'CONFLICT (rename/add): Rename', \
fmtRename(ren1.srcName, ren1.dstName), 'in', \
branchName1 + '.', ren1.dstName, 'added in', branchName2
print 'Adding as', newPath, 'instead'
output('CONFLICT (rename/add): Rename',
fmtRename(ren1.srcName, ren1.dstName), 'in',
branchName1 + '.', ren1.dstName, 'added in', branchName2)
output('Adding as', newPath, 'instead')
updateFile(False, dstShaOtherBranch, dstModeOtherBranch, newPath)
cleanMerge = False
tryMerge = True
@ -641,12 +651,12 @@ def processRenames(renamesA, renamesB, branchNameA, branchNameB):
dst2 = renames2.getDst(ren1.dstName)
newPath1 = uniquePath(ren1.dstName, branchName1)
newPath2 = uniquePath(dst2.dstName, branchName2)
print 'CONFLICT (rename/rename): Rename', \
fmtRename(ren1.srcName, ren1.dstName), 'in', \
branchName1+'. Rename', \
fmtRename(dst2.srcName, dst2.dstName), 'in', branchName2
print 'Renaming', ren1.srcName, 'to', newPath1, 'and', \
dst2.srcName, 'to', newPath2, 'instead'
output('CONFLICT (rename/rename): Rename',
fmtRename(ren1.srcName, ren1.dstName), 'in',
branchName1+'. Rename',
fmtRename(dst2.srcName, dst2.dstName), 'in', branchName2)
output('Renaming', ren1.srcName, 'to', newPath1, 'and',
dst2.srcName, 'to', newPath2, 'instead')
removeFile(False, ren1.dstName)
updateFile(False, ren1.dstSha, ren1.dstMode, newPath1)
updateFile(False, dst2.dstSha, dst2.dstMode, newPath2)
@ -663,13 +673,14 @@ def processRenames(renamesA, renamesB, branchNameA, branchNameB):
branchName1, branchName2)
if merge or not clean:
print 'Renaming', fmtRename(ren1.srcName, ren1.dstName)
output('Renaming', fmtRename(ren1.srcName, ren1.dstName))
if merge:
print 'Auto-merging', ren1.dstName
output('Auto-merging', ren1.dstName)
if not clean:
print 'CONFLICT (rename/modify): Merge conflict in', ren1.dstName
output('CONFLICT (rename/modify): Merge conflict in',
ren1.dstName)
cleanMerge = False
if not cacheOnly:
@ -714,21 +725,21 @@ def processEntry(entry, branch1Name, branch2Name):
(not aSha and bSha == oSha):
# Deleted in both or deleted in one and unchanged in the other
if aSha:
print 'Removing', path
output('Removing', path)
removeFile(True, path)
else:
# Deleted in one and changed in the other
cleanMerge = False
if not aSha:
print 'CONFLICT (delete/modify):', path, 'deleted in', \
branch1Name, 'and modified in', branch2Name + '.', \
'Version', branch2Name, 'of', path, 'left in tree.'
output('CONFLICT (delete/modify):', path, 'deleted in',
branch1Name, 'and modified in', branch2Name + '.',
'Version', branch2Name, 'of', path, 'left in tree.')
mode = bMode
sha = bSha
else:
print 'CONFLICT (modify/delete):', path, 'deleted in', \
branch2Name, 'and modified in', branch1Name + '.', \
'Version', branch1Name, 'of', path, 'left in tree.'
output('CONFLICT (modify/delete):', path, 'deleted in',
branch2Name, 'and modified in', branch1Name + '.',
'Version', branch1Name, 'of', path, 'left in tree.')
mode = aMode
sha = aSha
@ -755,14 +766,14 @@ def processEntry(entry, branch1Name, branch2Name):
if path in currentDirectorySet:
cleanMerge = False
newPath = uniquePath(path, addBranch)
print 'CONFLICT (' + conf + '):', \
'There is a directory with name', path, 'in', \
otherBranch + '. Adding', path, 'as', newPath
output('CONFLICT (' + conf + '):',
'There is a directory with name', path, 'in',
otherBranch + '. Adding', path, 'as', newPath)
removeFile(False, path)
updateFile(False, sha, mode, newPath)
else:
print 'Adding', path
output('Adding', path)
updateFile(True, sha, mode, path)
elif not oSha and aSha and bSha:
@ -772,10 +783,10 @@ def processEntry(entry, branch1Name, branch2Name):
if aSha == bSha:
if aMode != bMode:
cleanMerge = False
print 'CONFLICT: File', path, \
'added identically in both branches, but permissions', \
'conflict', '0%o' % aMode, '->', '0%o' % bMode
print 'CONFLICT: adding with permission:', '0%o' % aMode
output('CONFLICT: File', path,
'added identically in both branches, but permissions',
'conflict', '0%o' % aMode, '->', '0%o' % bMode)
output('CONFLICT: adding with permission:', '0%o' % aMode)
updateFile(False, aSha, aMode, path)
else:
@ -785,9 +796,9 @@ def processEntry(entry, branch1Name, branch2Name):
cleanMerge = False
newPath1 = uniquePath(path, branch1Name)
newPath2 = uniquePath(path, branch2Name)
print 'CONFLICT (add/add): File', path, \
'added non-identically in both branches. Adding as', \
newPath1, 'and', newPath2, 'instead.'
output('CONFLICT (add/add): File', path,
'added non-identically in both branches. Adding as',
newPath1, 'and', newPath2, 'instead.')
removeFile(False, path)
updateFile(False, aSha, aMode, newPath1)
updateFile(False, bSha, bMode, newPath2)
@ -796,7 +807,7 @@ def processEntry(entry, branch1Name, branch2Name):
#
# case D: Modified in both, but differently.
#
print 'Auto-merging', path
output('Auto-merging', path)
[sha, mode, clean, dummy] = \
mergeFile(path, oSha, oMode,
path, aSha, aMode,
@ -806,7 +817,7 @@ def processEntry(entry, branch1Name, branch2Name):
updateFile(True, sha, mode, path)
else:
cleanMerge = False
print 'CONFLICT (content): Merge conflict in', path
output('CONFLICT (content): Merge conflict in', path)
if cacheOnly:
updateFile(False, sha, mode, path)

View File

@ -27,3 +27,14 @@ sed -ne '/unreachable /{
}
git-prune-packed $dryrun
redundant=$(git-pack-redundant --all)
if test "" != "$redundant"
then
if test "" = $dryrun
then
echo "$redundant" | xargs rm -f
else
echo rm -f "$redundant"
fi
fi

View File

@ -32,10 +32,6 @@ case ",$all_into_one," in
rev_list=
rev_parse='--all'
pack_objects=
# This part is a stop-gap until we have proper pack redundancy
# checker.
existing=`cd "$PACKDIR" && \
find . -type f \( -name '*.pack' -o -name '*.idx' \) -print`
;;
esac
if [ "$local" ]; then
@ -46,6 +42,14 @@ name=$(git-rev-list --objects $rev_list $(git-rev-parse $rev_parse) |
exit 1
if [ -z "$name" ]; then
echo Nothing new to pack.
if test "$remove_redandant" = t ; then
echo "Removing redundant packs."
sync
redundant=$(git-pack-redundant --all)
if test "$redundant" != "" ; then
echo $redundant | xargs rm
fi
fi
exit 0
fi
echo "Pack pack-$name created."
@ -58,20 +62,10 @@ exit
if test "$remove_redandant" = t
then
# We know $existing are all redandant only when
# all-into-one is used.
if test "$all_into_one" != '' && test "$existing" != ''
then
sync
( cd "$PACKDIR" &&
for e in $existing
do
case "$e" in
./pack-$name.pack | ./pack-$name.idx) ;;
*) rm -f $e ;;
esac
done
)
sync
redundant=$(git-pack-redundant --all)
if test "$redundant" != "" ; then
echo $redundant | xargs rm
fi
fi

View File

@ -112,7 +112,7 @@ cherry-pick)
q
}'
set_author_env=`git-cat-file commit "$commit" |
sed -ne "$pick_author_script"`
LANG=C LC_ALL=C sed -ne "$pick_author_script"`
eval "$set_author_env"
export GIT_AUTHOR_NAME
export GIT_AUTHOR_EMAIL

View File

@ -1,3 +1,7 @@
#
# Copyright (C) 2005 Fredrik Kuivinen
#
import sys, re, os, traceback
from sets import Set

View File

@ -269,6 +269,8 @@ static CURL* get_curl_handle(void)
curl_low_speed_time);
}
curl_easy_setopt(result, CURLOPT_FOLLOWLOCATION, 1);
return result;
}
@ -786,7 +788,7 @@ static int fetch_alternates(char *base)
buffer.buffer = data;
if (get_verbosely)
fprintf(stderr, "Getting alternates list\n");
fprintf(stderr, "Getting alternates list for %s\n", base);
url = xmalloc(strlen(base) + 31);
sprintf(url, "%s/objects/info/http-alternates", base);
@ -909,7 +911,7 @@ static int fetch_indices(struct alt_base *repo)
buffer.buffer = data;
if (get_verbosely)
fprintf(stderr, "Getting pack list\n");
fprintf(stderr, "Getting pack list for %s\n", repo->base);
url = xmalloc(strlen(repo->base) + 21);
sprintf(url, "%s/objects/info/packs", repo->base);

View File

@ -80,14 +80,95 @@ static struct commit *interesting(struct commit_list *list)
* Now, list does not have any interesting commit. So we find the newest
* commit from the result list that is not marked uninteresting. Which is
* commit B.
*
*
* Another pathological example how this thing can fail to mark an ancestor
* of a merge base as UNINTERESTING without the postprocessing phase.
*
* 2
* H
* 1 / \
* G A \
* |\ / \
* | B \
* | \ \
* \ C F
* \ \ /
* \ D /
* \ | /
* \| /
* E
*
* list A B C D E F G H
* G1 H2 - - - - - - 1 2
* H2 E1 B1 - 1 - - 1 - 1 2
* F2 E1 B1 A2 2 1 - - 1 2 1 2
* E3 B1 A2 2 1 - - 3 2 1 2
* B1 A2 2 1 - - 3 2 1 2
* C1 A2 2 1 1 - 3 2 1 2
* D1 A2 2 1 1 1 3 2 1 2
* A2 2 1 1 1 3 2 1 2
* B3 2 3 1 1 3 2 1 2
* C7 2 3 7 1 3 2 1 2
*
* At this point, unfortunately, everybody in the list is
* uninteresting, so we fail to complete the following two
* steps to fully marking uninteresting commits.
*
* D7 2 3 7 7 3 2 1 2
* E7 2 3 7 7 7 2 1 2
*
* and we end up showing E as an interesting merge base.
*/
static int show_all = 0;
static void mark_reachable_commits(struct commit_list *result,
struct commit_list *list)
{
struct commit_list *tmp;
/*
* Postprocess to fully contaminate the well.
*/
for (tmp = result; tmp; tmp = tmp->next) {
struct commit *c = tmp->item;
/* Reinject uninteresting ones to list,
* so we can scan their parents.
*/
if (c->object.flags & UNINTERESTING)
commit_list_insert(c, &list);
}
while (list) {
struct commit *c = list->item;
struct commit_list *parents;
tmp = list;
list = list->next;
free(tmp);
/* Anything taken out of the list is uninteresting, so
* mark all its parents uninteresting. We do not
* parse new ones (we already parsed all the relevant
* ones).
*/
parents = c->parents;
while (parents) {
struct commit *p = parents->item;
parents = parents->next;
if (!(p->object.flags & UNINTERESTING)) {
p->object.flags |= UNINTERESTING;
commit_list_insert(p, &list);
}
}
}
}
static int merge_base(struct commit *rev1, struct commit *rev2)
{
struct commit_list *list = NULL;
struct commit_list *result = NULL;
struct commit_list *tmp = NULL;
if (rev1 == rev2) {
printf("%s\n", sha1_to_hex(rev1->object.sha1));
@ -104,9 +185,10 @@ static int merge_base(struct commit *rev1, struct commit *rev2)
while (interesting(list)) {
struct commit *commit = list->item;
struct commit_list *tmp = list, *parents;
struct commit_list *parents;
int flags = commit->object.flags & 7;
tmp = list;
list = list->next;
free(tmp);
if (flags == 3) {
@ -130,6 +212,9 @@ static int merge_base(struct commit *rev1, struct commit *rev2)
if (!result)
return 1;
if (result->next && list)
mark_reachable_commits(result, list);
while (result) {
struct commit *commit = result->item;
result = result->next;

620
pack-redundant.c Normal file
View File

@ -0,0 +1,620 @@
/*
*
* Copyright 2005, Lukas Sandstrom <lukass@etek.chalmers.se>
*
* This file is licensed under the GPL v2.
*
*/
#include "cache.h"
static const char pack_redundant_usage[] =
"git-pack-redundant [ --verbose ] [ --alt-odb ] < --all | <.pack filename> ...>";
int load_all_packs = 0, verbose = 0, alt_odb = 0;
struct llist_item {
struct llist_item *next;
char *sha1;
};
struct llist {
struct llist_item *front;
struct llist_item *back;
size_t size;
} *all_objects; /* all objects which must be present in local packfiles */
struct pack_list {
struct pack_list *next;
struct packed_git *pack;
struct llist *unique_objects;
struct llist *all_objects;
} *local_packs = NULL, *altodb_packs = NULL;
struct pll {
struct pll *next;
struct pack_list *pl;
};
inline void llist_free(struct llist *list)
{
while((list->back = list->front)) {
list->front = list->front->next;
free(list->back);
}
free(list);
}
inline void llist_init(struct llist **list)
{
*list = xmalloc(sizeof(struct llist));
(*list)->front = (*list)->back = NULL;
(*list)->size = 0;
}
struct llist * llist_copy(struct llist *list)
{
struct llist *ret;
struct llist_item *new, *old, *prev;
llist_init(&ret);
if ((ret->size = list->size) == 0)
return ret;
new = ret->front = xmalloc(sizeof(struct llist_item));
new->sha1 = list->front->sha1;
old = list->front->next;
while (old) {
prev = new;
new = xmalloc(sizeof(struct llist_item));
prev->next = new;
new->sha1 = old->sha1;
old = old->next;
}
new->next = NULL;
ret->back = new;
return ret;
}
inline struct llist_item * llist_insert(struct llist *list,
struct llist_item *after, char *sha1)
{
struct llist_item *new = xmalloc(sizeof(struct llist_item));
new->sha1 = sha1;
new->next = NULL;
if (after != NULL) {
new->next = after->next;
after->next = new;
if (after == list->back)
list->back = new;
} else {/* insert in front */
if (list->size == 0)
list->back = new;
else
new->next = list->front;
list->front = new;
}
list->size++;
return new;
}
inline struct llist_item * llist_insert_back(struct llist *list, char *sha1)
{
return llist_insert(list, list->back, sha1);
}
inline struct llist_item * llist_insert_sorted_unique(struct llist *list,
char *sha1, struct llist_item *hint)
{
struct llist_item *prev = NULL, *l;
l = (hint == NULL) ? list->front : hint;
while (l) {
int cmp = memcmp(l->sha1, sha1, 20);
if (cmp > 0) { /* we insert before this entry */
return llist_insert(list, prev, sha1);
}
if(!cmp) { /* already exists */
return l;
}
prev = l;
l = l->next;
}
/* insert at the end */
return llist_insert_back(list, sha1);
}
/* computes A\B */
void llist_sorted_difference_inplace(struct llist *A,
struct llist *B)
{
struct llist_item *prev, *a, *b, *x;
prev = a = A->front;
b = B->front;
while (a != NULL && b != NULL) {
int cmp = memcmp(a->sha1, b->sha1, 20);
if (!cmp) {
x = a;
if (a == A->front)
A->front = a->next;
a = prev->next = a->next;
if (a == NULL) /* end of list */
A->back = prev;
A->size--;
free(x);
b = b->next;
} else
if (cmp > 0)
b = b->next;
else {
prev = a;
a = a->next;
}
}
}
/* returns a pointer to an item in front of sha1 */
inline struct llist_item * llist_sorted_remove(struct llist *list, char *sha1,
struct llist_item *hint)
{
struct llist_item *prev, *l;
redo_from_start:
l = (hint == NULL) ? list->front : hint;
prev = NULL;
while (l) {
int cmp = memcmp(l->sha1, sha1, 20);
if (cmp > 0) /* not in list, since sorted */
return prev;
if(!cmp) { /* found */
if (prev == NULL) {
if (hint != NULL && hint != list->front) {
/* we don't know the previous element */
hint = NULL;
goto redo_from_start;
}
list->front = l->next;
} else
prev->next = l->next;
if (l == list->back)
list->back = prev;
free(l);
list->size--;
return prev;
}
prev = l;
l = l->next;
}
return prev;
}
inline struct pack_list * pack_list_insert(struct pack_list **pl,
struct pack_list *entry)
{
struct pack_list *p = xmalloc(sizeof(struct pack_list));
memcpy(p, entry, sizeof(struct pack_list));
p->next = *pl;
*pl = p;
return p;
}
inline size_t pack_list_size(struct pack_list *pl)
{
size_t ret = 0;
while(pl) {
ret++;
pl = pl->next;
}
return ret;
}
struct pack_list * pack_list_difference(struct pack_list *A,
struct pack_list *B)
{
struct pack_list *ret, *pl;
if (A == NULL)
return NULL;
pl = B;
while (pl != NULL) {
if (A->pack == pl->pack)
return pack_list_difference(A->next, B);
pl = pl->next;
}
ret = xmalloc(sizeof(struct pack_list));
memcpy(ret, A, sizeof(struct pack_list));
ret->next = pack_list_difference(A->next, B);
return ret;
}
void cmp_two_packs(struct pack_list *p1, struct pack_list *p2)
{
int p1_off, p2_off;
void *p1_base, *p2_base;
struct llist_item *p1_hint = NULL, *p2_hint = NULL;
p1_off = p2_off = 256 * 4 + 4;
p1_base = (void *)p1->pack->index_base;
p2_base = (void *)p2->pack->index_base;
while (p1_off <= p1->pack->index_size - 3 * 20 &&
p2_off <= p2->pack->index_size - 3 * 20)
{
int cmp = memcmp(p1_base + p1_off, p2_base + p2_off, 20);
/* cmp ~ p1 - p2 */
if (cmp == 0) {
p1_hint = llist_sorted_remove(p1->unique_objects,
p1_base + p1_off, p1_hint);
p2_hint = llist_sorted_remove(p2->unique_objects,
p1_base + p1_off, p2_hint);
p1_off+=24;
p2_off+=24;
continue;
}
if (cmp < 0) { /* p1 has the object, p2 doesn't */
p1_off+=24;
} else { /* p2 has the object, p1 doesn't */
p2_off+=24;
}
}
}
/* all the permutations have to be free()d at the same time,
* since they refer to each other
*/
struct pll * get_all_permutations(struct pack_list *list)
{
struct pll *subset, *pll, *new_pll = NULL; /*silence warning*/
if (list == NULL)
return NULL;
if (list->next == NULL) {
new_pll = xmalloc(sizeof(struct pll));
new_pll->next = NULL;
new_pll->pl = list;
return new_pll;
}
pll = subset = get_all_permutations(list->next);
while (pll) {
new_pll = xmalloc(sizeof(struct pll));
new_pll->next = pll->next;
pll->next = new_pll;
new_pll->pl = xmalloc(sizeof(struct pack_list));
memcpy(new_pll->pl, list, sizeof(struct pack_list));
new_pll->pl->next = pll->pl;
pll = new_pll->next;
}
/* add ourself to the end */
new_pll->next = xmalloc(sizeof(struct pll));
new_pll->next->pl = xmalloc(sizeof(struct pack_list));
new_pll->next->next = NULL;
memcpy(new_pll->next->pl, list, sizeof(struct pack_list));
new_pll->next->pl->next = NULL;
return subset;
}
int is_superset(struct pack_list *pl, struct llist *list)
{
struct llist *diff;
diff = llist_copy(list);
while (pl) {
llist_sorted_difference_inplace(diff,
pl->all_objects);
if (diff->size == 0) { /* we're done */
llist_free(diff);
return 1;
}
pl = pl->next;
}
llist_free(diff);
return 0;
}
size_t sizeof_union(struct packed_git *p1, struct packed_git *p2)
{
size_t ret = 0;
int p1_off, p2_off;
void *p1_base, *p2_base;
p1_off = p2_off = 256 * 4 + 4;
p1_base = (void *)p1->index_base;
p2_base = (void *)p2->index_base;
while (p1_off <= p1->index_size - 3 * 20 &&
p2_off <= p2->index_size - 3 * 20)
{
int cmp = memcmp(p1_base + p1_off, p2_base + p2_off, 20);
/* cmp ~ p1 - p2 */
if (cmp == 0) {
ret++;
p1_off+=24;
p2_off+=24;
continue;
}
if (cmp < 0) { /* p1 has the object, p2 doesn't */
p1_off+=24;
} else { /* p2 has the object, p1 doesn't */
p2_off+=24;
}
}
return ret;
}
/* another O(n^2) function ... */
size_t get_pack_redundancy(struct pack_list *pl)
{
struct pack_list *subset;
if (pl == NULL)
return 0;
size_t ret = 0;
while ((subset = pl->next)) {
while(subset) {
ret += sizeof_union(pl->pack, subset->pack);
subset = subset->next;
}
pl = pl->next;
}
return ret;
}
inline size_t pack_set_bytecount(struct pack_list *pl)
{
size_t ret = 0;
while (pl) {
ret += pl->pack->pack_size;
ret += pl->pack->index_size;
pl = pl->next;
}
return ret;
}
void minimize(struct pack_list **min)
{
struct pack_list *pl, *unique = NULL,
*non_unique = NULL, *min_perm = NULL;
struct pll *perm, *perm_all, *perm_ok = NULL, *new_perm;
struct llist *missing;
size_t min_perm_size = (size_t)-1, perm_size;
pl = local_packs;
while (pl) {
if(pl->unique_objects->size)
pack_list_insert(&unique, pl);
else
pack_list_insert(&non_unique, pl);
pl = pl->next;
}
/* find out which objects are missing from the set of unique packs */
missing = llist_copy(all_objects);
pl = unique;
while (pl) {
llist_sorted_difference_inplace(missing,
pl->all_objects);
pl = pl->next;
}
/* return if there are no objects missing from the unique set */
if (missing->size == 0) {
*min = unique;
return;
}
/* find the permutations which contain all missing objects */
perm_all = perm = get_all_permutations(non_unique);
while (perm) {
if (is_superset(perm->pl, missing)) {
new_perm = xmalloc(sizeof(struct pll));
new_perm->pl = perm->pl;
new_perm->next = perm_ok;
perm_ok = new_perm;
}
perm = perm->next;
}
if (perm_ok == NULL)
die("Internal error: No complete sets found!\n");
/* find the permutation with the smallest size */
perm = perm_ok;
while (perm) {
perm_size = pack_set_bytecount(perm->pl);
if (min_perm_size > perm_size) {
min_perm_size = perm_size;
min_perm = perm->pl;
}
perm = perm->next;
}
*min = min_perm;
/* add the unique packs to the list */
pl = unique;
while(pl) {
pack_list_insert(min, pl);
pl = pl->next;
}
}
void load_all_objects()
{
struct pack_list *pl = local_packs;
struct llist_item *hint, *l;
int i;
llist_init(&all_objects);
while (pl) {
i = 0;
hint = NULL;
l = pl->all_objects->front;
while (l) {
hint = llist_insert_sorted_unique(all_objects,
l->sha1, hint);
l = l->next;
}
pl = pl->next;
}
/* remove objects present in remote packs */
pl = altodb_packs;
while (pl) {
llist_sorted_difference_inplace(all_objects, pl->all_objects);
pl = pl->next;
}
}
/* this scales like O(n^2) */
void cmp_packs()
{
struct pack_list *subset, *pl = local_packs;
while ((subset = pl)) {
while((subset = subset->next))
cmp_two_packs(pl, subset);
pl = pl->next;
}
pl = altodb_packs;
while (pl) {
subset = local_packs;
while (subset) {
llist_sorted_difference_inplace(subset->unique_objects,
pl->all_objects);
subset = subset->next;
}
pl = pl->next;
}
}
struct pack_list * add_pack(struct packed_git *p)
{
struct pack_list l;
size_t off;
void *base;
l.pack = p;
llist_init(&l.all_objects);
off = 256 * 4 + 4;
base = (void *)p->index_base;
while (off <= p->index_size - 3 * 20) {
llist_insert_back(l.all_objects, base + off);
off+=24;
}
/* this list will be pruned in cmp_two_packs later */
l.unique_objects = llist_copy(l.all_objects);
if (p->pack_local)
return pack_list_insert(&local_packs, &l);
else
return alt_odb ? pack_list_insert(&altodb_packs, &l) : NULL;
}
struct pack_list * add_pack_file(char *filename)
{
struct packed_git *p = packed_git;
if (strlen(filename) < 40)
die("Bad pack filename: %s\n", filename);
while (p) {
if (strstr(p->pack_name, filename))
return add_pack(p);
p = p->next;
}
die("Filename %s not found in packed_git\n", filename);
}
void load_all()
{
struct packed_git *p = packed_git;
while (p) {
add_pack(p);
p = p->next;
}
}
int main(int argc, char **argv)
{
int i;
struct pack_list *min, *red, *pl;
for (i = 1; i < argc; i++) {
const char *arg = argv[i];
if(!strcmp(arg, "--")) {
i++;
break;
}
if(!strcmp(arg, "--all")) {
load_all_packs = 1;
continue;
}
if(!strcmp(arg, "--verbose")) {
verbose = 1;
continue;
}
if(!strcmp(arg, "--alt-odb")) {
alt_odb = 1;
continue;
}
if(*arg == '-')
usage(pack_redundant_usage);
else
break;
}
prepare_packed_git();
if (load_all_packs)
load_all();
else
while (*(argv + i) != NULL)
add_pack_file(*(argv + i++));
if (local_packs == NULL)
die("Zero packs found!\n");
cmp_packs();
load_all_objects();
minimize(&min);
if (verbose) {
fprintf(stderr, "There are %ld packs available in alt-odbs.\n",
pack_list_size(altodb_packs));
fprintf(stderr, "The smallest (bytewise) set of packs is:\n");
pl = min;
while (pl) {
fprintf(stderr, "\t%s\n", pl->pack->pack_name);
pl = pl->next;
}
fprintf(stderr, "containing %ld duplicate objects "
"with a total size of %ldkb.\n",
get_pack_redundancy(min), pack_set_bytecount(min)/1024);
fprintf(stderr, "A total of %ld unique objects were considered.\n",
all_objects->size);
fprintf(stderr, "Redundant packs (with indexes):\n");
}
pl = red = pack_list_difference(local_packs, min);
while (pl) {
printf("%s\n%s\n",
sha1_pack_index_name(pl->pack->sha1),
pl->pack->pack_name);
pl = pl->next;
}
return 0;
}

View File

@ -424,6 +424,7 @@ struct packed_git *add_packed_git(char *path, int path_len, int local)
struct packed_git *p;
unsigned long idx_size;
void *idx_map;
char sha1[20];
if (check_packed_git_idx(path, &idx_size, &idx_map))
return NULL;
@ -447,6 +448,8 @@ struct packed_git *add_packed_git(char *path, int path_len, int local)
p->pack_last_used = 0;
p->pack_use_cnt = 0;
p->pack_local = local;
if (!get_sha1_hex(path + path_len - 40 - 4, sha1))
memcpy(p->sha1, sha1, 20);
return p;
}

View File

@ -181,11 +181,11 @@ static void join_revs(struct commit_list **list_p,
while (*list_p) {
struct commit_list *parents;
int still_interesting = !!interesting(*list_p);
struct commit *commit = pop_one_commit(list_p);
int flags = commit->object.flags & all_mask;
int still_interesting = !!interesting(*list_p);
if (!still_interesting && extra < 0)
if (!still_interesting && extra <= 0)
break;
mark_seen(commit, seen_p);
@ -199,18 +199,58 @@ static void join_revs(struct commit_list **list_p,
parents = parents->next;
if ((this_flag & flags) == flags)
continue;
parse_commit(p);
if (!p->object.parsed)
parse_commit(p);
if (mark_seen(p, seen_p) && !still_interesting)
extra--;
p->object.flags |= flags;
insert_by_date(p, list_p);
}
}
/*
* Postprocess to complete well-poisoning.
*
* At this point we have all the commits we have seen in
* seen_p list (which happens to be sorted chronologically but
* it does not really matter). Mark anything that can be
* reached from uninteresting commits not interesting.
*/
for (;;) {
int changed = 0;
struct commit_list *s;
for (s = *seen_p; s; s = s->next) {
struct commit *c = s->item;
struct commit_list *parents;
if (((c->object.flags & all_revs) != all_revs) &&
!(c->object.flags & UNINTERESTING))
continue;
/* The current commit is either a merge base or
* already uninteresting one. Mark its parents
* as uninteresting commits _only_ if they are
* already parsed. No reason to find new ones
* here.
*/
parents = c->parents;
while (parents) {
struct commit *p = parents->item;
parents = parents->next;
if (!(p->object.flags & UNINTERESTING)) {
p->object.flags |= UNINTERESTING;
changed = 1;
}
}
}
if (!changed)
break;
}
}
static void show_one_commit(struct commit *commit, int no_name)
{
char pretty[128], *cp;
char pretty[256], *cp;
struct commit_name *name = commit->object.util;
if (commit->object.parsed)
pretty_print_commit(CMIT_FMT_ONELINE, commit->buffer, ~0,
@ -360,7 +400,7 @@ int main(int ac, char **av)
unsigned int rev_mask[MAX_REVS];
int num_rev, i, extra = 0;
int all_heads = 0, all_tags = 0;
int all_mask, all_revs, shown_merge_point;
int all_mask, all_revs;
char head_path[128];
const char *head_path_p;
int head_path_len;
@ -369,6 +409,8 @@ int main(int ac, char **av)
int independent = 0;
int no_name = 0;
int sha1_name = 0;
int shown_merge_point = 0;
int topo_order = 0;
setup_git_directory();
@ -394,6 +436,8 @@ int main(int ac, char **av)
merge_base = 1;
else if (!strcmp(arg, "--independent"))
independent = 1;
else if (!strcmp(arg, "--topo-order"))
topo_order = 1;
else
usage(show_branch_usage);
ac--; av++;
@ -496,7 +540,8 @@ int main(int ac, char **av)
exit(0);
/* Sort topologically */
sort_in_topological_order(&seen);
if (topo_order)
sort_in_topological_order(&seen);
/* Give names to commits */
if (!sha1_name && !no_name)
@ -504,15 +549,12 @@ int main(int ac, char **av)
all_mask = ((1u << (REV_SHIFT + num_rev)) - 1);
all_revs = all_mask & ~((1u << REV_SHIFT) - 1);
shown_merge_point = 0;
while (seen) {
struct commit *commit = pop_one_commit(&seen);
int this_flag = commit->object.flags;
int is_merge_point = (this_flag & all_revs) == all_revs;
if (is_merge_point)
shown_merge_point = 1;
shown_merge_point |= ((this_flag & all_revs) == all_revs);
if (1 < num_rev) {
for (i = 0; i < num_rev; i++)
@ -521,9 +563,9 @@ int main(int ac, char **av)
putchar(' ');
}
show_one_commit(commit, no_name);
if (shown_merge_point && is_merge_point)
if (--extra < 0)
break;
if (shown_merge_point && --extra < 0)
break;
}
return 0;
}

View File

@ -122,7 +122,7 @@ cat > show-branch.expect << EOF
++ [mybranch] Some work.
EOF
git show-branch master mybranch > show-branch.output
git show-branch --topo-order master mybranch > show-branch.output
test_expect_success 'git show-branch' 'cmp show-branch.expect show-branch.output'
git checkout mybranch
@ -145,7 +145,7 @@ cat > show-branch2.expect << EOF
++ [master] Merged "mybranch" changes.
EOF
git show-branch master mybranch > show-branch2.output
git show-branch --topo-order master mybranch > show-branch2.output
test_expect_success 'git show-branch' 'cmp show-branch2.expect show-branch2.output'
# TODO: test git fetch

59
t/t6010-merge-base.sh Executable file
View File

@ -0,0 +1,59 @@
#!/bin/sh
#
# Copyright (c) 2005 Junio C Hamano
#
test_description='Merge base computation.
'
. ./test-lib.sh
T=$(git-write-tree)
M=1130000000
Z=+0000
export GIT_COMMITTER_EMAIL=git@comm.iter.xz
export GIT_COMMITTER_NAME='C O Mmiter'
export GIT_AUTHOR_NAME='A U Thor'
export GIT_AUTHOR_EMAIL=git@au.thor.xz
doit() {
OFFSET=$1; shift
NAME=$1; shift
PARENTS=
for P
do
PARENTS="${PARENTS}-p $P "
done
GIT_COMMITTER_DATE="$(($M + $OFFSET)) $Z"
GIT_AUTHOR_DATE=$GIT_COMMITTER_DATE
export GIT_COMMITTER_DATE GIT_AUTHOR_DATE
commit=$(echo $NAME | git-commit-tree $T $PARENTS)
echo $commit >.git/refs/tags/$NAME
echo $commit
}
# Setup...
E=$(doit 5 E)
D=$(doit 4 D $E)
F=$(doit 6 F $E)
C=$(doit 3 C $D)
B=$(doit 2 B $C)
A=$(doit 1 A $B)
G=$(doit 7 G $B $E)
H=$(doit 8 H $A $F)
test_expect_success 'compute merge-base (single)' \
'MB=$(git-merge-base G H) &&
expr "$(git-name-rev "$MB")" : "[0-9a-f]* B"'
test_expect_success 'compute merge-base (all)' \
'MB=$(git-merge-base --all G H) &&
expr "$(git-name-rev "$MB")" : "[0-9a-f]* B"'
test_expect_success 'compute merge-base with show-branch' \
'MB=$(git-show-branch --merge-base G H) &&
expr "$(git-name-rev "$MB")" : "[0-9a-f]* B"'
test_done

View File

@ -42,7 +42,7 @@ int main(int argc, char **argv)
if (oldval) {
if (memcmp(currsha1, oldsha1, 20))
die("Ref %s changed to %s", refname, sha1_to_hex(currsha1));
die("Ref %s is at %s but expected %s", refname, sha1_to_hex(currsha1), sha1_to_hex(oldsha1));
/* Nothing to do? */
if (!memcmp(oldsha1, sha1, 20))
exit(0);