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:
commit
f7a2eb7359
2
.gitignore
vendored
2
.gitignore
vendored
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
------
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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::
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
---------------
|
||||
|
@ -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)
|
||||
|
@ -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".
|
||||
|
||||
|
78
Documentation/git-lost+found.txt
Normal file
78
Documentation/git-lost+found.txt
Normal 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
|
@ -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
|
||||
|
@ -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
|
||||
|
50
Documentation/git-pack-redundant.txt
Normal file
50
Documentation/git-pack-redundant.txt
Normal 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
|
||||
|
@ -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
|
||||
|
@ -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>::
|
||||
|
@ -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
|
||||
--------------------------------
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
||||
|
@ -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/
|
||||
===============================================================
|
||||
+
|
||||
|
@ -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
12
INSTALL
@ -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.
|
||||
|
7
Makefile
7
Makefile
@ -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
13
apply.c
@ -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;
|
||||
|
37
commit.c
37
commit.c
@ -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;
|
||||
}
|
||||
|
||||
|
1
commit.h
1
commit.h
@ -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
6
debian/changelog
vendored
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
11
git-clone.sh
11
git-clone.sh
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
23
git-lost+found.sh
Executable 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
|
@ -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
|
||||
|
||||
|
@ -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."
|
||||
|
@ -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)
|
||||
|
11
git-prune.sh
11
git-prune.sh
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -1,3 +1,7 @@
|
||||
#
|
||||
# Copyright (C) 2005 Fredrik Kuivinen
|
||||
#
|
||||
|
||||
import sys, re, os, traceback
|
||||
from sets import Set
|
||||
|
||||
|
@ -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);
|
||||
|
87
merge-base.c
87
merge-base.c
@ -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
620
pack-redundant.c
Normal 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;
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
59
t/t6010-merge-base.sh
Executable 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
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user