GIT 0.99.9m aka 1.0rc5
Signed-off-by: Junio C Hamano <junkio@cox.net>
This commit is contained in:
commit
a9572072f0
@ -9,6 +9,7 @@ ARTICLES += diffcore
|
||||
ARTICLES += howto-index
|
||||
ARTICLES += repository-layout
|
||||
ARTICLES += hooks
|
||||
ARTICLES += everyday
|
||||
# with their own formatting rules.
|
||||
SP_ARTICLES = glossary howto/revert-branch-rebase
|
||||
|
||||
|
@ -187,7 +187,8 @@ you would use git-rev-list and git-diff-tree like this:
|
||||
|
||||
We have already talked about the "\--stdin" form of git-diff-tree
|
||||
command that reads the list of commits and compares each commit
|
||||
with its parents. The git-whatchanged command internally runs
|
||||
with its parents (otherwise you should go back and read the tutorial).
|
||||
The git-whatchanged command internally runs
|
||||
the equivalent of the above command, and can be used like this:
|
||||
|
||||
$ git-whatchanged -p -S'if (frotz) {
|
||||
|
138
Documentation/everyday.txt
Normal file
138
Documentation/everyday.txt
Normal file
@ -0,0 +1,138 @@
|
||||
Everyday GIT With 20 Commands Or So
|
||||
===================================
|
||||
|
||||
GIT suite has over 100 commands, and the manual page for each of
|
||||
them discusses what the command does and how it is used in
|
||||
detail, but until you know what command should be used in order
|
||||
to achieve what you want to do, you cannot tell which manual
|
||||
page to look at, and if you know that already you do not need
|
||||
the manual.
|
||||
|
||||
Does that mean you need to know all of them before you can use
|
||||
git? Not at all. Depending on the role you play, the set of
|
||||
commands you need to know is slightly different, but in any case
|
||||
what you need to learn is far smaller than the full set of
|
||||
commands to carry out your day-to-day work. This document is to
|
||||
serve as a cheat-sheet and a set of pointers for people playing
|
||||
various roles.
|
||||
|
||||
<<Basic Repository>> commands are needed by people who has a
|
||||
repository --- that is everybody, because every working tree of
|
||||
git is a repository.
|
||||
|
||||
In addition, <<Individual Developer (Standalone)>> commands are
|
||||
essential for anybody who makes a commit, even for somebody who
|
||||
works alone.
|
||||
|
||||
If you work with other people, you will need commands listed in
|
||||
<<Individual Developer (Participant)>> section as well.
|
||||
|
||||
People who play <<Integrator>> role need to learn some more
|
||||
commands in addition to the above.
|
||||
|
||||
<<Repository Administration>> commands are for system
|
||||
administrators who are responsible to care and feed git
|
||||
repositories to support developers.
|
||||
|
||||
|
||||
Basic Repository[[Basic Repository]]
|
||||
------------------------------------
|
||||
|
||||
Everybody uses these commands to feed and care git repositories.
|
||||
|
||||
* gitlink:git-init-db[1] or gitlink:git-clone[1] to create a
|
||||
new repository.
|
||||
|
||||
* gitlink:git-fsck-objects[1] to validate the repository.
|
||||
|
||||
* gitlink:git-prune[1] to garbage collect crufts in the
|
||||
repository.
|
||||
|
||||
* gitlink:git-repack[1] to pack loose objects for efficiency.
|
||||
|
||||
Individual Developer (Standalone)[[Individual Developer (Standalone)]]
|
||||
----------------------------------------------------------------------
|
||||
|
||||
A standalone individual developer does not exchange patches with
|
||||
other poeple, and works alone in a single repository, using the
|
||||
following commands.
|
||||
|
||||
* gitlink:git-show-branch[1] to see where you are.
|
||||
|
||||
* gitlink:git-diff[1] and gitlink:git-status[1] to see what
|
||||
you are in the middle of doing.
|
||||
|
||||
* gitlink:git-log[1] to see what happened.
|
||||
|
||||
* gitlink:git-whatchanged[1] to find out where things have
|
||||
come from.
|
||||
|
||||
* gitlink:git-checkout[1] and gitlink:git-branch[1] to switch
|
||||
branches.
|
||||
|
||||
* gitlink:git-update-index[1] to manage the index file.
|
||||
|
||||
* gitlink:git-commit[1] to advance the current branch.
|
||||
|
||||
* gitlink:git-reset[1] and gitlink:git-checkout[1] (with
|
||||
pathname parameters) to undo changes.
|
||||
|
||||
* gitlink:git-pull[1] with "." as the remote to merge between
|
||||
local branches.
|
||||
|
||||
* gitlink:git-rebase[1] to maintain topic branches.
|
||||
|
||||
|
||||
Individual Developer (Participant)[[Individual Developer (Participant)]]
|
||||
------------------------------------------------------------------------
|
||||
|
||||
A developer working as a participant in a group project needs to
|
||||
learn how to communicate with others, and uses these commands in
|
||||
addition to the ones needed by a standalone developer.
|
||||
|
||||
* gitlink:git-pull[1] from "origin" to keep up-to-date with
|
||||
the upstream.
|
||||
|
||||
* gitlink:git-push[1] to shared repository if you adopt CVS
|
||||
style shared repository workflow.
|
||||
|
||||
* gitlink:git-format-patch[1] to prepare e-mail submission, if
|
||||
you adopt Linux kernel-style public forum workflow.
|
||||
|
||||
|
||||
Integrator[[Integrator]]
|
||||
------------------------
|
||||
|
||||
A fairly central person acting as the integrator in a group
|
||||
project receives changes made by others, reviews and integrates
|
||||
them and publishes the result for others to use, using these
|
||||
commands in addition to the ones needed by participants.
|
||||
|
||||
* gitlink:git-am[1] to apply patches e-mailed in from your
|
||||
contributors.
|
||||
|
||||
* gitlink:git-pull[1] to merge from your trusted lieutenants.
|
||||
|
||||
* gitlink:git-format-patch[1] to prepare and send suggested
|
||||
alternative to contributors.
|
||||
|
||||
* gitlink:git-revert[1] to undo botched commits.
|
||||
|
||||
* gitlink:git-push[1] to publish the bleeding edge.
|
||||
|
||||
|
||||
Repository Administration[[Repository Administration]]
|
||||
------------------------------------------------------
|
||||
|
||||
A repository administrator uses the following tools to set up
|
||||
and maintain access to the repository by developers.
|
||||
|
||||
* gitlink:git-daemon[1] to allow anonymous download from
|
||||
repository.
|
||||
|
||||
* gitlink:git-shell[1] can be used as a 'restricted login shell'
|
||||
for shared central repository users.
|
||||
|
||||
* link:howto/update-hook-example.txt[update hook howto] has a
|
||||
good example of managing a shared central repository.
|
||||
|
@ -28,7 +28,7 @@ OPTIONS
|
||||
area to store extracted patches.
|
||||
|
||||
--utf8, --keep::
|
||||
Pass `--utf8` and `--keep` flags to `git-mailinfo` (see
|
||||
Pass `-u` and `-k` flags to `git-mailinfo` (see
|
||||
gitlink:git-mailinfo[1]).
|
||||
|
||||
--binary::
|
||||
|
@ -8,16 +8,21 @@ git-bisect - Find the change that introduced a bug
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
'git bisect' start
|
||||
'git bisect' bad <rev>
|
||||
'git bisect' good <rev>
|
||||
'git bisect' reset [<branch>]
|
||||
'git bisect' visualize
|
||||
'git bisect' replay <logfile>
|
||||
'git bisect' log
|
||||
'git bisect' <subcommand> <options>
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
The command takes various subcommands, and different options
|
||||
depending on the subcommand:
|
||||
|
||||
git bisect start [<paths>...]
|
||||
git bisect bad <rev>
|
||||
git bisect good <rev>
|
||||
git bisect reset [<branch>]
|
||||
git bisect visualize
|
||||
git bisect replay <logfile>
|
||||
git bisect log
|
||||
|
||||
This command uses 'git-rev-list --bisect' option to help drive
|
||||
the binary search process to find which change introduced a bug,
|
||||
given an old "good" commit object name and a later "bad" commit
|
||||
@ -26,10 +31,10 @@ object name.
|
||||
The way you use it is:
|
||||
|
||||
------------------------------------------------
|
||||
git bisect start
|
||||
git bisect bad # Current version is bad
|
||||
git bisect good v2.6.13-rc2 # v2.6.13-rc2 was the last version
|
||||
# tested that was good
|
||||
$ git bisect start
|
||||
$ git bisect bad # Current version is bad
|
||||
$ git bisect good v2.6.13-rc2 # v2.6.13-rc2 was the last version
|
||||
# tested that was good
|
||||
------------------------------------------------
|
||||
|
||||
When you give at least one bad and one good versions, it will
|
||||
@ -43,7 +48,7 @@ and check out the state in the middle. Now, compile that kernel, and boot
|
||||
it. Now, let's say that this booted kernel works fine, then just do
|
||||
|
||||
------------------------------------------------
|
||||
git bisect good # this one is good
|
||||
$ git bisect good # this one is good
|
||||
------------------------------------------------
|
||||
|
||||
which will now say
|
||||
@ -62,7 +67,7 @@ kernel rev in "refs/bisect/bad".
|
||||
Oh, and then after you want to reset to the original head, do a
|
||||
|
||||
------------------------------------------------
|
||||
git bisect reset
|
||||
$ git bisect reset
|
||||
------------------------------------------------
|
||||
|
||||
to get back to the master branch, instead of being in one of the bisection
|
||||
@ -72,7 +77,9 @@ not using some old bisection branch).
|
||||
|
||||
During the bisection process, you can say
|
||||
|
||||
git bisect visualize
|
||||
------------
|
||||
$ git bisect visualize
|
||||
------------
|
||||
|
||||
to see the currently remaining suspects in `gitk`.
|
||||
|
||||
@ -80,11 +87,40 @@ The good/bad input is logged, and `git bisect
|
||||
log` shows what you have done so far. You can truncate its
|
||||
output somewhere and save it in a file, and run
|
||||
|
||||
git bisect replay that-file
|
||||
------------
|
||||
$ git bisect replay that-file
|
||||
------------
|
||||
|
||||
if you find later you made a mistake telling good/bad about a
|
||||
revision.
|
||||
|
||||
If in a middle of bisect session, you know what the bisect
|
||||
suggested to try next is not a good one to test (e.g. the change
|
||||
the commit introduces is known not to work in your environment
|
||||
and you know it does not have anything to do with the bug you
|
||||
are chasing), you may want to find a near-by commit and try that
|
||||
instead. It goes something like this:
|
||||
|
||||
------------
|
||||
$ git bisect good/bad # previous round was good/bad.
|
||||
Bisecting: 337 revisions left to test after this
|
||||
$ git bisect visualize # oops, that is uninteresting.
|
||||
$ git reset --hard HEAD~3 # try 3 revs before what
|
||||
# was suggested
|
||||
------------
|
||||
|
||||
Then compile and test the one you chose to try. After that,
|
||||
tell bisect what the result was as usual.
|
||||
|
||||
You can further cut down the number of trials if you know what
|
||||
part of the tree is involved in the problem you are tracking
|
||||
down, by giving paths parameters when you say `bisect start`,
|
||||
like this:
|
||||
|
||||
------------
|
||||
$ git bisect start arch/i386 include/asm-i386
|
||||
------------
|
||||
|
||||
|
||||
Author
|
||||
------
|
||||
|
@ -9,7 +9,7 @@ git-checkout-index - Copy files from the index to the working directory
|
||||
SYNOPSIS
|
||||
--------
|
||||
'git-checkout-index' [-u] [-q] [-a] [-f] [-n] [--prefix=<string>]
|
||||
[--] <file>...
|
||||
[--stage=<number>] [--] <file>...
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
@ -40,58 +40,80 @@ OPTIONS
|
||||
When creating files, prepend <string> (usually a directory
|
||||
including a trailing /)
|
||||
|
||||
--stage=<number>::
|
||||
Instead of checking out unmerged entries, copy out the
|
||||
files from named stage. <number> must be between 1 and 3.
|
||||
|
||||
--::
|
||||
Do not interpret any more arguments as options.
|
||||
|
||||
The order of the flags used to matter, but not anymore.
|
||||
|
||||
Just doing "git-checkout-index" does nothing. You probably meant
|
||||
"git-checkout-index -a". And if you want to force it, you want
|
||||
"git-checkout-index -f -a".
|
||||
Just doing `git-checkout-index` does nothing. You probably meant
|
||||
`git-checkout-index -a`. And if you want to force it, you want
|
||||
`git-checkout-index -f -a`.
|
||||
|
||||
Intuitiveness is not the goal here. Repeatability is. The reason for
|
||||
the "no arguments means no work" thing is that from scripts you are
|
||||
supposed to be able to do things like:
|
||||
the "no arguments means no work" behavior is that from scripts you are
|
||||
supposed to be able to do:
|
||||
|
||||
find . -name '*.h' -print0 | xargs -0 git-checkout-index -f --
|
||||
----------------
|
||||
$ find . -name '*.h' -print0 | xargs -0 git-checkout-index -f --
|
||||
----------------
|
||||
|
||||
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 index, which was not the point.
|
||||
|
||||
To update and refresh only the files already checked out:
|
||||
The `--` is just a good idea when you know the rest will be filenames;
|
||||
it will prevent problems with a filename of, for example, `-a`.
|
||||
Using `--` is probably a good policy in scripts.
|
||||
|
||||
git-checkout-index -n -f -a && git-update-index --ignore-missing --refresh
|
||||
|
||||
Oh, and the "--" is just a good idea when you know the rest will be
|
||||
filenames. Just so that you wouldn't have a filename of "-a" causing
|
||||
problems (not possible in the above example, but get used to it in
|
||||
scripting!).
|
||||
EXAMPLES
|
||||
--------
|
||||
To update and refresh only the files already checked out::
|
||||
+
|
||||
----------------
|
||||
$ git-checkout-index -n -f -a && git-update-index --ignore-missing --refresh
|
||||
----------------
|
||||
|
||||
The prefix ability basically makes it trivial to use
|
||||
git-checkout-index as an "export as tree" function. Just read the
|
||||
desired tree into the index, and do a
|
||||
|
||||
git-checkout-index --prefix=git-export-dir/ -a
|
||||
|
||||
and git-checkout-index will "export" the index into the specified
|
||||
Using `git-checkout-index` to "export an entire tree"::
|
||||
The prefix ability basically makes it trivial to use
|
||||
`git-checkout-index` as an "export as tree" function.
|
||||
Just read the desired tree into the index, and do:
|
||||
+
|
||||
----------------
|
||||
$ git-checkout-index --prefix=git-export-dir/ -a
|
||||
----------------
|
||||
+
|
||||
`git-checkout-index` will "export" the index into the specified
|
||||
directory.
|
||||
+
|
||||
The final "/" is important. The exported name is literally just
|
||||
prefixed with the specified string. Contrast this with the
|
||||
following example.
|
||||
|
||||
NOTE The final "/" is important. The exported name is literally just
|
||||
prefixed with the specified string, so you can also do something like
|
||||
Export files with a prefix::
|
||||
+
|
||||
----------------
|
||||
$ git-checkout-index --prefix=.merged- Makefile
|
||||
----------------
|
||||
+
|
||||
This will check out the currently cached copy of `Makefile`
|
||||
into the file `.merged-Makefile`.
|
||||
|
||||
git-checkout-index --prefix=.merged- Makefile
|
||||
|
||||
to check out the currently cached copy of `Makefile` into the file
|
||||
`.merged-Makefile`
|
||||
|
||||
Author
|
||||
------
|
||||
Written by Linus Torvalds <torvalds@osdl.org>
|
||||
|
||||
|
||||
Documentation
|
||||
--------------
|
||||
Documentation by David Greaves, Junio C Hamano and the git-list <git@vger.kernel.org>.
|
||||
Documentation by David Greaves,
|
||||
Junio C Hamano and the git-list <git@vger.kernel.org>.
|
||||
|
||||
|
||||
GIT
|
||||
---
|
||||
|
@ -7,7 +7,7 @@ git-cherry-pick - Apply the change introduced by an existing commit.
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
'git-cherry-pick' [-n] [-r] <commit>
|
||||
'git-cherry-pick' [--edit] [-n] [-r] <commit>
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
@ -20,15 +20,19 @@ OPTIONS
|
||||
<commit>::
|
||||
Commit to cherry-pick.
|
||||
|
||||
-r::
|
||||
-e|--edit::
|
||||
With this option, `git-cherry-pick` will let you edit the commit
|
||||
message prior committing.
|
||||
|
||||
-r|--replay::
|
||||
Usually the command appends which commit was
|
||||
cherry-picked after the original commit message when
|
||||
making a commit. This option, '--replay', causes it to
|
||||
use the original commit message intact. This is useful
|
||||
when you are reordering the patches in your private tree
|
||||
before publishing, and is used by 'git rebase'.
|
||||
before publishing.
|
||||
|
||||
-n::
|
||||
-n|--no-commit::
|
||||
Usually the command automatically creates a commit with
|
||||
a commit log message stating which commit was
|
||||
cherry-picked. This flag applies the change necessary
|
||||
|
@ -7,7 +7,7 @@ git-commit - Record your changes
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
'git-commit' [-a] [-s] [-v] [(-c | -C) <commit> | -F <file> | -m <msg>] [-e] <file>...
|
||||
'git-commit' [-a] [-s] [-v] [(-c | -C) <commit> | -F <file> | -m <msg>] [-e] [--] <file>...
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
@ -22,7 +22,7 @@ information.
|
||||
|
||||
OPTIONS
|
||||
-------
|
||||
-a::
|
||||
-a|--all::
|
||||
Update all paths in the index file.
|
||||
|
||||
-c or -C <commit>::
|
||||
@ -39,23 +39,29 @@ OPTIONS
|
||||
-m <msg>::
|
||||
Use the given <msg> as the commit message.
|
||||
|
||||
-s::
|
||||
-s|--signoff::
|
||||
Add Signed-off-by line at the end of the commit message.
|
||||
|
||||
-v::
|
||||
-v|--verify::
|
||||
Look for suspicious lines the commit introduces, and
|
||||
abort committing if there is one. The definition of
|
||||
'suspicious lines' is currently the lines that has
|
||||
trailing whitespaces, and the lines whose indentation
|
||||
has a SP character immediately followed by a TAB
|
||||
character.
|
||||
character. This is the default.
|
||||
|
||||
-e::
|
||||
-n|--no-verify::
|
||||
The opposite of `--verify`.
|
||||
|
||||
-e|--edit::
|
||||
The message taken from file with `-F`, command line with
|
||||
`-m`, and from file with `-C` are usually used as the
|
||||
commit log message unmodified. This option lets you
|
||||
further edit the message taken from these sources.
|
||||
|
||||
--::
|
||||
Do not interpret any more arguments as options.
|
||||
|
||||
<file>...::
|
||||
Update specified paths in the index file before committing.
|
||||
|
||||
|
@ -60,7 +60,7 @@ the old cvs2git tool.
|
||||
+
|
||||
If you need to pass multiple options, separate them with a comma.
|
||||
|
||||
-P:: <cvsps-output-file>
|
||||
-P <cvsps-output-file>::
|
||||
Instead of calling cvsps, read the provided cvsps output file. Useful
|
||||
for debugging or when cvsps is being handled outside cvsimport.
|
||||
|
||||
|
@ -17,14 +17,16 @@ ent and the index file, or the index file and the working tree.
|
||||
The combination of what is compared with what is determined by
|
||||
the number of ents given to the command.
|
||||
|
||||
`----------------`--------`-----------------------------`------------------
|
||||
Number of ents Options What's Compared Underlying command
|
||||
---------------------------------------------------------------------------
|
||||
0 - index file and working tree git-diff-files
|
||||
1 --cached ent and index file git-diff-index
|
||||
1 - ent and working tree git-diff-index
|
||||
2 - two ents git-diff-tree
|
||||
---------------------------------------------------------------------------
|
||||
* When no <ent> is given, the working tree and the index
|
||||
file is compared, using `git-diff-files`.
|
||||
|
||||
* When one <ent> is given, the working tree and the named
|
||||
tree is compared, using `git-diff-index`. The option
|
||||
`--cached` can be given to compare the index file and
|
||||
the named tree.
|
||||
|
||||
* When two <ent>s are given, these two trees are compared
|
||||
using `git-diff-tree`.
|
||||
|
||||
OPTIONS
|
||||
-------
|
||||
|
@ -18,7 +18,7 @@ the objects necessary to complete them.
|
||||
|
||||
The ref names and their object names of fetched refs are stored
|
||||
in `.git/FETCH_HEAD`. This information is left for a later merge
|
||||
operation done by "git resolve" or "git octopus".
|
||||
operation done by "git merge".
|
||||
|
||||
|
||||
OPTIONS
|
||||
|
@ -8,7 +8,7 @@ git-format-patch - Prepare patches for e-mail submission.
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
'git-format-patch' [-n][-o <dir>|--stdout][-k][--mbox][--diff-options] <his> [<mine>]
|
||||
'git-format-patch' [-n | -k] [-o <dir> | --stdout] [-s] [-c] [--mbox] [--diff-options] <his> [<mine>]
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
@ -32,23 +32,34 @@ processing with applymbox.
|
||||
|
||||
OPTIONS
|
||||
-------
|
||||
-o <dir>::
|
||||
-o|--output-directory <dir>::
|
||||
Use <dir> to store the resulting files, instead of the
|
||||
current working directory.
|
||||
|
||||
-n::
|
||||
-n|--numbered::
|
||||
Name output in '[PATCH n/m]' format.
|
||||
|
||||
-k::
|
||||
-k|--keep-subject::
|
||||
Do not strip/add '[PATCH]' from the first line of the
|
||||
commit log message.
|
||||
|
||||
--author, --date::
|
||||
-a|--author, -d|--date::
|
||||
Output From: and Date: headers for commits made by
|
||||
yourself as well. Usually these are output only for
|
||||
commits made by people other than yourself.
|
||||
|
||||
--mbox::
|
||||
-s|--signoff::
|
||||
Add `Signed-off-by:` line to the commit message, using
|
||||
the committer identity of yourself.
|
||||
|
||||
-c|--check::
|
||||
Display suspicious lines in the patch. The definition
|
||||
of 'suspicious lines' is currently the lines that has
|
||||
trailing whitespaces, and the lines whose indentation
|
||||
has a SP character immediately followed by a TAB
|
||||
character.
|
||||
|
||||
-m|--mbox::
|
||||
Format the output files for closer to mbox format by
|
||||
adding a phony Unix "From " line, so they can be
|
||||
concatenated together and fed to `git-applymbox`.
|
||||
|
@ -8,7 +8,7 @@ git-hash-object - Computes object ID and optionally creates a blob from a file.
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
'git-hash-object' [-t <type>] [-w] <any-file-on-the-filesystem>
|
||||
'git-hash-object' [-t <type>] [-w] [--stdin] [--] <file>...
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
@ -29,6 +29,9 @@ OPTIONS
|
||||
-w::
|
||||
Actually write the object into the object database.
|
||||
|
||||
--stdin::
|
||||
Read the object from standard input instead of from a file.
|
||||
|
||||
Author
|
||||
------
|
||||
Written by Junio C Hamano <junkio@cox.net>
|
||||
|
@ -14,6 +14,12 @@ DESCRIPTION
|
||||
-----------
|
||||
Downloads a remote git repository via HTTP.
|
||||
|
||||
OPTIONS
|
||||
-------
|
||||
commit-id::
|
||||
Either the hash or the filename under [URL]/refs/ to
|
||||
pull.
|
||||
|
||||
-c::
|
||||
Get the commit objects.
|
||||
-t::
|
||||
|
@ -8,7 +8,14 @@ git-init-db - Creates an empty git repository
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
'git-init-db'
|
||||
'git-init-db' [--template=<template_directory>]
|
||||
|
||||
|
||||
OPTIONS
|
||||
-------
|
||||
--template=<template_directory>::
|
||||
Provide the directory in from which templates will be used.
|
||||
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
@ -16,14 +23,26 @@ This simply creates an empty git repository - basically a `.git` directory
|
||||
and `.git/object/??/`, `.git/refs/heads` and `.git/refs/tags` directories,
|
||||
and links `.git/HEAD` symbolically to `.git/refs/heads/master`.
|
||||
|
||||
If the 'GIT_DIR' environment variable is set then it specifies a path
|
||||
If the `$GIT_DIR` environment variable is set then it specifies a path
|
||||
to use instead of `./.git` for the base of the repository.
|
||||
|
||||
If the object storage directory is specified via the 'GIT_OBJECT_DIRECTORY'
|
||||
If the object storage directory is specified via the `$GIT_OBJECT_DIRECTORY`
|
||||
environment variable then the sha1 directories are created underneath -
|
||||
otherwise the default `$GIT_DIR/objects` directory is used.
|
||||
|
||||
"git-init-db" won't hurt an existing repository.
|
||||
`git-init-db` won't hurt an existing repository.
|
||||
|
||||
|
||||
EXAMPLES
|
||||
--------
|
||||
|
||||
Start a new git repository for an existing code base::
|
||||
+
|
||||
----------------
|
||||
$ cd /path/to/my/codebase
|
||||
$ git-init-db
|
||||
----------------
|
||||
|
||||
|
||||
|
||||
Author
|
||||
|
@ -17,7 +17,7 @@ Displays the references other repository has.
|
||||
|
||||
OPTIONS
|
||||
-------
|
||||
--heads --tags::
|
||||
-h|--heads, -t|--tags::
|
||||
Limit to only refs/heads and refs/tags, respectively.
|
||||
These options are _not_ mutually exclusive; when given
|
||||
both, references stored in refs/heads and refs/tags are
|
||||
|
@ -8,12 +8,15 @@ git-ls-tree - Lists the contents of a tree object.
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
'git-ls-tree' [-d] [-r] [-z] <tree-ish> [paths...]
|
||||
'git-ls-tree' [-d] [-r] [-t] [-z] [--name-only] [--name-status] <tree-ish> [paths...]
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
Lists the contents of a tree object, like what "/bin/ls -a" does
|
||||
in the current working directory.
|
||||
Lists the contents of a given tree object, like what "/bin/ls -a" does
|
||||
in the current working directory. Note that the usage is subtly different,
|
||||
though - 'paths' denote just a list of patterns to match, e.g. so specifying
|
||||
directory name (without '-r') will behave differently, and order of the
|
||||
arguments does not matter.
|
||||
|
||||
OPTIONS
|
||||
-------
|
||||
@ -21,36 +24,48 @@ OPTIONS
|
||||
Id of a tree-ish.
|
||||
|
||||
-d::
|
||||
show only the named tree entry itself, not its children
|
||||
Show only the named tree entry itself, not its children.
|
||||
|
||||
-r::
|
||||
recurse into sub-trees
|
||||
Recurse into sub-trees.
|
||||
|
||||
-t::
|
||||
Show tree entries even when going to recurse them. Has no effect
|
||||
if '-r' was not passed. '-d' implies '-t'.
|
||||
|
||||
-z::
|
||||
\0 line termination on output
|
||||
\0 line termination on output.
|
||||
|
||||
--name-only::
|
||||
--name-status::
|
||||
List only filenames (instead of the "long" output), one per line.
|
||||
|
||||
paths::
|
||||
When paths are given, show them. Otherwise implicitly
|
||||
uses the root level of the tree as the sole path argument.
|
||||
When paths are given, show them (note that this isn't really raw
|
||||
pathnames, but rather a list of patterns to match). Otherwise
|
||||
implicitly uses the root level of the tree as the sole path argument.
|
||||
|
||||
|
||||
Output Format
|
||||
-------------
|
||||
<mode> SP <type> SP <object> TAB <file>
|
||||
|
||||
When `-z` option is not used, TAB, LF, and backslash characters
|
||||
in pathnames are represented as `\t`, `\n`, and `\\`,
|
||||
respectively.
|
||||
When the `-z` option is not used, TAB, LF, and backslash characters
|
||||
in pathnames are represented as `\t`, `\n`, and `\\`, respectively.
|
||||
|
||||
|
||||
Author
|
||||
------
|
||||
Written by Linus Torvalds <torvalds@osdl.org>
|
||||
Completely rewritten from scratch by Junio C Hamano <junkio@cox.net>
|
||||
Written by Petr Baudis <pasky@suse.cz>
|
||||
Completely rewritten from scratch by Junio C Hamano <junkio@cox.net>,
|
||||
another major rewrite by Linus Torvalds <torvalds@osdl.org>
|
||||
|
||||
Documentation
|
||||
--------------
|
||||
Documentation by David Greaves, Junio C Hamano and the git-list <git@vger.kernel.org>.
|
||||
Documentation by David Greaves, Junio C Hamano and the git-list
|
||||
<git@vger.kernel.org>.
|
||||
|
||||
This manual page is a stub. You can help the git documentation by expanding it.
|
||||
|
||||
GIT
|
||||
---
|
||||
|
@ -20,7 +20,7 @@ files are passed as arguments 5, 6 and 7.
|
||||
OPTIONS
|
||||
-------
|
||||
--::
|
||||
Interpret all following arguments as filenames.
|
||||
Do not interpret any more arguments as options.
|
||||
|
||||
-a::
|
||||
Run merge against all files in the index that need merging.
|
||||
|
@ -8,12 +8,15 @@ git-mv - Script used to move or rename a file, directory or symlink.
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
'git-mv' [-f] [-n] <source> <destination>
|
||||
'git-mv' [-f] [-n] [-k] <source> ... <destination directory>
|
||||
'git-mv' <options>... <args>...
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
This script is used to move or rename a file, directory or symlink.
|
||||
|
||||
git-mv [-f] [-n] <source> <destination>
|
||||
git-mv [-f] [-n] [-k] <source> ... <destination directory>
|
||||
|
||||
In the first form, it renames <source>, which must exist and be either
|
||||
a file, symlink or directory, to <destination>.
|
||||
In the second form, the last argument has to be an existing
|
||||
|
@ -8,7 +8,7 @@ git-pack-objects - Create a packed archive of objects.
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
'git-pack-objects' [--local] [--incremental] [--window=N] [--depth=N] {--stdout | base-name} < object-list
|
||||
'git-pack-objects' [--non-empty] [--local] [--incremental] [--window=N] [--depth=N] {--stdout | base-name} < object-list
|
||||
|
||||
|
||||
DESCRIPTION
|
||||
@ -70,6 +70,10 @@ base-name::
|
||||
that are packed and not in the local object store
|
||||
(i.e. borrowed from an alternate).
|
||||
|
||||
--non-empty::
|
||||
Only create a packed archive if it would contain at
|
||||
least one object.
|
||||
|
||||
Author
|
||||
------
|
||||
Written by Linus Torvalds <torvalds@osdl.org>
|
||||
|
@ -9,19 +9,22 @@ residing in a pack file.
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
'git-prune-packed'
|
||||
'git-prune-packed' [-n]
|
||||
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
This program search the GIT_OBJECT_DIR for all objects that currently exist in
|
||||
a pack file as well as the independent object directories.
|
||||
This program search the `$GIT_OBJECT_DIR` for all objects that currently
|
||||
exist in a pack file as well as the independent object directories.
|
||||
|
||||
All such extra objects are removed.
|
||||
|
||||
A pack is a collection of objects, individually compressed, with delta
|
||||
compression applied, stored in a single file, with an associated index file.
|
||||
|
||||
Packs are used to reduce the load on mirror systems, backup engines, disk storage, etc.
|
||||
Packs are used to reduce the load on mirror systems, backup engines,
|
||||
disk storage, etc.
|
||||
|
||||
|
||||
OPTIONS
|
||||
-------
|
||||
|
@ -8,15 +8,16 @@ git-prune - Prunes all unreachable objects from the object database
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
'git-prune' [-n]
|
||||
'git-prune' [-n] [--] [<head>...]
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
|
||||
This runs `git-fsck-objects --unreachable` using the heads
|
||||
specified on the command line (or `$GIT_DIR/refs/heads/\*` and
|
||||
`$GIT_DIR/refs/tags/\*` if none is specified), and prunes all
|
||||
unreachable objects from the object database. In addition, it
|
||||
This runs `git-fsck-objects --unreachable` using all the refs
|
||||
available in `$GIT_DIR/refs`, optionally with additional set of
|
||||
objects specified on the command line, and prunes all
|
||||
objects unreachable from any of these head objects from the object database.
|
||||
In addition, it
|
||||
prunes the unpacked objects that are also found in packs by
|
||||
running `git prune-packed`.
|
||||
|
||||
@ -27,6 +28,24 @@ OPTIONS
|
||||
Do not remove anything; just report what it would
|
||||
remove.
|
||||
|
||||
--::
|
||||
Do not interpret any more arguments as options.
|
||||
|
||||
<head>...::
|
||||
In addition to objects
|
||||
reachable from any of our references, keep objects
|
||||
reachable from listed <head>s.
|
||||
|
||||
EXAMPLE
|
||||
-------
|
||||
|
||||
To prune objects not used by your repository nor another that
|
||||
borrows from your repository via its
|
||||
`.git/objects/info/alternates`:
|
||||
|
||||
------------
|
||||
$ git prune $(cd ../another && $(git-rev-parse --all))
|
||||
------------
|
||||
|
||||
Author
|
||||
------
|
||||
|
@ -16,6 +16,10 @@ DESCRIPTION
|
||||
Updates remote refs using local refs, while sending objects
|
||||
necessary to complete the given refs.
|
||||
|
||||
You can make "interesting" things to happen on the repository
|
||||
every time you push into it, by setting up 'hooks' there. See
|
||||
documentation for gitlink:git-receive-pack[1].
|
||||
|
||||
|
||||
OPTIONS
|
||||
-------
|
||||
@ -31,6 +35,7 @@ include::pull-fetch-param.txt[]
|
||||
This flag disables the check. What this means is that the
|
||||
local repository can lose commits; use it with care.
|
||||
|
||||
|
||||
Author
|
||||
------
|
||||
Written by Junio C Hamano <junkio@cox.net>
|
||||
|
@ -8,22 +8,22 @@ git-read-tree - Reads tree information into the index
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
'git-read-tree' (<tree-ish> | [-m [-u|-i]] <tree-ish1> [<tree-ish2> [<tree-ish3>]])
|
||||
'git-read-tree' (<tree-ish> | [[-m | --reset] [-u | -i]] <tree-ish1> [<tree-ish2> [<tree-ish3>]])
|
||||
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
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)
|
||||
gitlink:git-checkout-index[1])
|
||||
|
||||
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
|
||||
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.
|
||||
|
||||
Trivial merges are done by "git-read-tree" itself. Only conflicting paths
|
||||
will be in unmerged state when "git-read-tree" returns.
|
||||
Trivial merges are done by `git-read-tree` itself. Only conflicting paths
|
||||
will be in unmerged state when `git-read-tree` returns.
|
||||
|
||||
OPTIONS
|
||||
-------
|
||||
@ -56,7 +56,7 @@ OPTIONS
|
||||
|
||||
Merging
|
||||
-------
|
||||
If '-m' is specified, "git-read-tree" can perform 3 kinds of
|
||||
If `-m` is specified, `git-read-tree` can perform 3 kinds of
|
||||
merge, a single tree merge if only 1 tree is given, a
|
||||
fast-forward merge with 2 trees, or a 3-way merge if 3 trees are
|
||||
provided.
|
||||
@ -65,23 +65,23 @@ 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 index 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 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
|
||||
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
|
||||
the stuff that really changed.
|
||||
|
||||
This is used to avoid unnecessary false hits when "git-diff-files" is
|
||||
run after git-read-tree.
|
||||
This is used to avoid unnecessary false hits when `git-diff-files` is
|
||||
run after `git-read-tree`.
|
||||
|
||||
|
||||
Two Tree Merge
|
||||
~~~~~~~~~~~~~~
|
||||
|
||||
Typically, this is invoked as "git-read-tree -m $H $M", where $H
|
||||
Typically, this is invoked as `git-read-tree -m $H $M`, where $H
|
||||
is the head commit of the current repository, and $M is the head
|
||||
of a foreign tree, which is simply ahead of $H (i.e. we are in a
|
||||
fast forward situation).
|
||||
@ -94,7 +94,7 @@ the following:
|
||||
|
||||
2. The user wants to fast-forward to $M.
|
||||
|
||||
In this case, the "git-read-tree -m $H $M" command makes sure
|
||||
In this case, the `git-read-tree -m $H $M` command makes sure
|
||||
that no local change is lost as the result of this "merge".
|
||||
Here are the "carry forward" rules:
|
||||
|
||||
@ -141,13 +141,13 @@ operating under the -u flag.
|
||||
|
||||
When this form of git-read-tree returns successfully, you can
|
||||
see what "local changes" you made are carried forward by running
|
||||
"git-diff-index --cached $M". Note that this does not
|
||||
necessarily match "git-diff-index --cached $H" would have
|
||||
`git-diff-index --cached $M`. Note that this does not
|
||||
necessarily match `git-diff-index --cached $H` would have
|
||||
produced before such a two tree merge. This is because of cases
|
||||
18 and 19 --- if you already had the changes in $M (e.g. maybe
|
||||
you picked it up via e-mail in a patch form), "git-diff-index
|
||||
--cached $H" would have told you about the change before this
|
||||
merge, but it would not show in "git-diff-index --cached $M"
|
||||
you picked it up via e-mail in a patch form), `git-diff-index
|
||||
--cached $H` would have told you about the change before this
|
||||
merge, but it would not show in `git-diff-index --cached $M`
|
||||
output after two-tree merge.
|
||||
|
||||
|
||||
@ -156,31 +156,39 @@ output after two-tree merge.
|
||||
Each "index" entry has two bits worth of "stage" state. stage 0 is the
|
||||
normal one, and is the only one you'd see in any kind of normal use.
|
||||
|
||||
However, when you do "git-read-tree" with three trees, the "stage"
|
||||
However, when you do `git-read-tree` with three trees, the "stage"
|
||||
starts out at 1.
|
||||
|
||||
This means that you can do
|
||||
|
||||
git-read-tree -m <tree1> <tree2> <tree3>
|
||||
----------------
|
||||
$ git-read-tree -m <tree1> <tree2> <tree3>
|
||||
----------------
|
||||
|
||||
and you will end up with an index with all of the <tree1> entries in
|
||||
"stage1", all of the <tree2> entries in "stage2" and all of the
|
||||
<tree3> entries in "stage3".
|
||||
<tree3> entries in "stage3". When performing a merge of another
|
||||
branch into the current branch, we use the common ancestor tree
|
||||
as <tree1>, the current branch head as <tree2>, and the other
|
||||
branch head as <tree3>.
|
||||
|
||||
Furthermore, "git-read-tree" has special-case logic that says: if you see
|
||||
Furthermore, `git-read-tree` has special-case logic that says: if you see
|
||||
a file that matches in all respects in the following states, it
|
||||
"collapses" back to "stage0":
|
||||
|
||||
- stage 2 and 3 are the same; take one or the other (it makes no
|
||||
difference - the same work has been done on stage 2 and 3)
|
||||
difference - the same work has been done on our branch in
|
||||
stage 2 and their branch in stage 3)
|
||||
|
||||
- stage 1 and stage 2 are the same and stage 3 is different; take
|
||||
stage 3 (some work has been done on stage 3)
|
||||
stage 3 (our branch in stage 2 did not do anything since the
|
||||
ancestor in stage 1 while their branch in stage 3 worked on
|
||||
it)
|
||||
|
||||
- stage 1 and stage 3 are the same and stage 2 is different take
|
||||
stage 2 (some work has been done on stage 2)
|
||||
stage 2 (we did something while they did nothing)
|
||||
|
||||
The "git-write-tree" command refuses to write a nonsensical tree, and it
|
||||
The `git-write-tree` command refuses to write a nonsensical tree, and it
|
||||
will complain about unmerged entries if it sees a single entry that is not
|
||||
stage 0.
|
||||
|
||||
@ -220,12 +228,10 @@ populated. Here is an outline of how the algorithm works:
|
||||
matching "stage1" entry if it exists too. .. all the normal
|
||||
trivial rules ..
|
||||
|
||||
You would normally use "git-merge-index" with supplied
|
||||
"git-merge-one-file" to do this last step. The script
|
||||
does not touch the files in the work tree, and the entire merge
|
||||
happens in the index file. In other words, there is no need to
|
||||
worry about what is in the working directory, since it is never
|
||||
shown and never used.
|
||||
You would normally use `git-merge-index` with supplied
|
||||
`git-merge-one-file` to do this last step. The script updates
|
||||
the files in the working tree as it merges each path and at the
|
||||
end of a successful merge.
|
||||
|
||||
When you start a 3-way merge with an index file that is already
|
||||
populated, it is assumed that it represents the state of the
|
||||
@ -236,33 +242,54 @@ merge refuses to run if it finds an entry in the original index
|
||||
file that does not match stage 2.
|
||||
|
||||
This is done to prevent you from losing your work-in-progress
|
||||
changes. To illustrate, suppose you start from what has been
|
||||
changes, and mixing your random changes in an unrelated merge
|
||||
commit. To illustrate, suppose you start from what has been
|
||||
commited last to your repository:
|
||||
|
||||
$ JC=`git-rev-parse --verify "HEAD^0"`
|
||||
$ git-checkout-index -f -u -a $JC
|
||||
----------------
|
||||
$ JC=`git-rev-parse --verify "HEAD^0"`
|
||||
$ git-checkout-index -f -u -a $JC
|
||||
----------------
|
||||
|
||||
You do random edits, without running git-update-index. And then
|
||||
you notice that the tip of your "upstream" tree has advanced
|
||||
since you pulled from him:
|
||||
|
||||
$ git-fetch rsync://.... linus
|
||||
$ LT=`cat .git/MERGE_HEAD`
|
||||
----------------
|
||||
$ git-fetch git://.... linus
|
||||
$ LT=`cat .git/FETCH_HEAD`
|
||||
----------------
|
||||
|
||||
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 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
|
||||
$ git-merge-index git-merge-one-file -a
|
||||
$ echo "Merge with Linus" | \
|
||||
git-commit-tree `git-write-tree` -p $JC -p $LT
|
||||
----------------
|
||||
$ git-read-tree -m -u `git-merge-base $JC $LT` $JC $LT
|
||||
$ git-merge-index git-merge-one-file -a
|
||||
$ echo "Merge with Linus" | \
|
||||
git-commit-tree `git-write-tree` -p $JC -p $LT
|
||||
----------------
|
||||
|
||||
what you would commit is a pure merge between $JC and LT without
|
||||
what you would commit is a pure merge between $JC and $LT without
|
||||
your work-in-progress changes, and your work tree would be
|
||||
updated to the result of the merge.
|
||||
|
||||
However, if you have local changes in the working tree that
|
||||
would be overwritten by this merge,`git-read-tree` will refuse
|
||||
to run to prevent your changes from being lost.
|
||||
|
||||
In other words, there is no need to worry about what exists only
|
||||
in the working tree. When you have local changes in a part of
|
||||
the project that is not involved in the merge, your changes do
|
||||
not interfere with the merge, and are kept intact. When they
|
||||
*do* interfere, the merge does not even start (`git-read-tree`
|
||||
complains loudly and fails without modifying anything). In such
|
||||
a case, you can simply continue doing what you were in the
|
||||
middle of doing, and when your working tree is ready (i.e. you
|
||||
have finished your work-in-progress), attempt the merge again.
|
||||
|
||||
|
||||
See Also
|
||||
--------
|
||||
|
@ -71,6 +71,10 @@ packed and is served via a dumb transport.
|
||||
#!/bin/sh
|
||||
exec git-update-server-info
|
||||
|
||||
There are other real-world examples of using update and
|
||||
post-update hooks found in the Documentation/howto directory.
|
||||
|
||||
|
||||
OPTIONS
|
||||
-------
|
||||
<directory>::
|
||||
|
@ -9,7 +9,7 @@ objects into pack files.
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
'git-repack' [-a] [-d]
|
||||
'git-repack' [-a] [-d] [-l] [-n]
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
@ -39,6 +39,13 @@ OPTIONS
|
||||
After packing, if the newly created packs make some
|
||||
existing packs redundant, remove the redundant packs.
|
||||
|
||||
-l::
|
||||
Pass the `--local` option to `git pack-objects`, see
|
||||
gitlink:git-pack-objects[1].
|
||||
|
||||
-n::
|
||||
Do not update the server information with
|
||||
`git update-server-info`.
|
||||
|
||||
Author
|
||||
------
|
||||
|
@ -7,7 +7,7 @@ git-revert - Revert an existing commit.
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
'git-revert' [-n] <commit>
|
||||
'git-revert' [--edit | --no-edit] [-n] <commit>
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
@ -20,7 +20,16 @@ OPTIONS
|
||||
<commit>::
|
||||
Commit to revert.
|
||||
|
||||
-n::
|
||||
-e|--edit::
|
||||
With this option, `git-revert` will let you edit the commit
|
||||
message prior committing the revert. This is the default if
|
||||
you run the command from a terminal.
|
||||
|
||||
--no-edit::
|
||||
With this option, `git-revert` will not start the commit
|
||||
message editor.
|
||||
|
||||
-n|--no-commit::
|
||||
Usually the command automatically creates a commit with
|
||||
a commit log message stating which commit was reverted.
|
||||
This flag applies the change necessary to revert the
|
||||
|
@ -7,23 +7,40 @@ git-show-branch - Show branches and their commits.
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
'git-show-branch [--all] [--heads] [--tags] [--more=<n> | --list | --independent | --merge-base] [--no-name | --sha1-name] <reference>...'
|
||||
'git-show-branch [--all] [--heads] [--tags] [--topo-order] [--more=<n> | --list | --independent | --merge-base] [--no-name | --sha1-name] [<rev> | <glob>]...'
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
Shows the head commits from the named <reference> (or all refs under
|
||||
$GIT_DIR/refs/heads), and displays concise list of commit logs
|
||||
to show their relationship semi-visually.
|
||||
|
||||
Shows the commit ancestry graph starting from the commits named
|
||||
with <rev>s or <globs>s (or all refs under $GIT_DIR/refs/heads
|
||||
and/or $GIT_DIR/refs/tags) semi-visually.
|
||||
|
||||
It cannot show more than 29 branches and commits at a time.
|
||||
|
||||
|
||||
OPTIONS
|
||||
-------
|
||||
<reference>::
|
||||
Name of the reference under $GIT_DIR/refs/.
|
||||
<rev>::
|
||||
Arbitrary extended SHA1 expression (see `git-rev-parse`)
|
||||
that typically names a branch HEAD or a tag.
|
||||
|
||||
<glob>::
|
||||
A glob pattern that matches branch or tag names under
|
||||
$GIT_DIR/refs. For example, if you have many topic
|
||||
branches under $GIT_DIR/refs/heads/topic, giving
|
||||
`topic/*` would show all of them.
|
||||
|
||||
--all --heads --tags::
|
||||
Show all refs under $GIT_DIR/refs, $GIT_DIR/refs/heads,
|
||||
and $GIT_DIR/refs/tags, respectively.
|
||||
|
||||
--topo-order::
|
||||
By default, the branches and their commits are shown in
|
||||
reverse chronological order. This option makes them
|
||||
appear in topological order (i.e., descendant commits
|
||||
are shown before their parents).
|
||||
|
||||
--more=<n>::
|
||||
Usually the command stops output upon showing the commit
|
||||
that is the common ancestor of all the branches. This
|
||||
|
@ -10,26 +10,6 @@ SYNOPSIS
|
||||
--------
|
||||
'git-tag' [-a | -s | -u <key-id>] [-f | -d] [-m <msg>] <name> [<head>]
|
||||
|
||||
OPTIONS
|
||||
-------
|
||||
-a::
|
||||
Make an unsigned, annotated tag object
|
||||
|
||||
-s::
|
||||
Make a GPG-signed tag, using the default e-mail address's key
|
||||
|
||||
-u <key-id>::
|
||||
Make a GPG-signed tag, using the given key
|
||||
|
||||
-f::
|
||||
Replace an existing tag with the given name (instead of failing)
|
||||
|
||||
-d::
|
||||
Delete an existing tag with the given name
|
||||
|
||||
-m <msg>::
|
||||
Use the given tag message (instead of prompting)
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
Adds a 'tag' reference in .git/refs/tags/
|
||||
@ -52,6 +32,26 @@ GnuPG key for signing.
|
||||
|
||||
`-d <tag>` deletes the tag.
|
||||
|
||||
OPTIONS
|
||||
-------
|
||||
-a::
|
||||
Make an unsigned, annotated tag object
|
||||
|
||||
-s::
|
||||
Make a GPG-signed tag, using the default e-mail address's key
|
||||
|
||||
-u <key-id>::
|
||||
Make a GPG-signed tag, using the given key
|
||||
|
||||
-f::
|
||||
Replace an existing tag with the given name (instead of failing)
|
||||
|
||||
-d::
|
||||
Delete an existing tag with the given name
|
||||
|
||||
-m <msg>::
|
||||
Use the given tag message (instead of prompting)
|
||||
|
||||
|
||||
Author
|
||||
------
|
||||
|
@ -123,7 +123,9 @@ merging.
|
||||
|
||||
To pretend you have a file with mode and sha1 at path, say:
|
||||
|
||||
$ git-update-index --cacheinfo mode sha1 path
|
||||
----------------
|
||||
$ git-update-index --cacheinfo mode sha1 path
|
||||
----------------
|
||||
|
||||
'--info-only' is used to register files without placing them in the object
|
||||
database. This is useful for status-only repositories.
|
||||
@ -134,11 +136,70 @@ in the database but the file isn't available locally. '--info-only' is
|
||||
useful when the file is available, but you do not wish to update the
|
||||
object database.
|
||||
|
||||
|
||||
Using --index-info
|
||||
------------------
|
||||
|
||||
`--index-info` is a more powerful mechanism that lets you feed
|
||||
multiple entry definitions from the standard input, and designed
|
||||
specifically for scripts. It can take inputs of three formats:
|
||||
|
||||
. mode SP sha1 TAB path
|
||||
+
|
||||
The first format is what "git-apply --index-info"
|
||||
reports, and used to reconstruct a partial tree
|
||||
that is used for phony merge base tree when falling
|
||||
back on 3-way merge.
|
||||
|
||||
. mode SP type SP sha1 TAB path
|
||||
+
|
||||
The second format is to stuff git-ls-tree output
|
||||
into the index file.
|
||||
|
||||
. mode SP sha1 SP stage TAB path
|
||||
+
|
||||
This format is to put higher order stages into the
|
||||
index file and matches git-ls-files --stage output.
|
||||
|
||||
To place a higher stage entry to the index, the path should
|
||||
first be removed by feeding a mode=0 entry for the path, and
|
||||
then feeding necessary input lines in the third format.
|
||||
|
||||
For example, starting with this index:
|
||||
|
||||
------------
|
||||
$ git ls-files -s
|
||||
100644 8a1218a1024a212bb3db30becd860315f9f3ac52 0 frotz
|
||||
------------
|
||||
|
||||
you can feed the following input to `--index-info`:
|
||||
|
||||
------------
|
||||
$ git update-index --index-info
|
||||
0 0000000000000000000000000000000000000000 frotz
|
||||
100644 8a1218a1024a212bb3db30becd860315f9f3ac52 1 frotz
|
||||
100755 8a1218a1024a212bb3db30becd860315f9f3ac52 2 frotz
|
||||
------------
|
||||
|
||||
The first line of the input feeds 0 as the mode to remove the
|
||||
path; the SHA1 does not matter as long as it is well formatted.
|
||||
Then the second and third line feeds stage 1 and stage 2 entries
|
||||
for that path. After the above, we would end up with this:
|
||||
|
||||
------------
|
||||
$ git ls-files -s
|
||||
100644 8a1218a1024a212bb3db30becd860315f9f3ac52 1 frotz
|
||||
100755 8a1218a1024a212bb3db30becd860315f9f3ac52 2 frotz
|
||||
------------
|
||||
|
||||
|
||||
Examples
|
||||
--------
|
||||
To update and refresh only the files already checked out:
|
||||
|
||||
git-checkout-index -n -f -a && git-update-index --ignore-missing --refresh
|
||||
----------------
|
||||
$ git-checkout-index -n -f -a && git-update-index --ignore-missing --refresh
|
||||
----------------
|
||||
|
||||
|
||||
Configuration
|
||||
@ -146,12 +207,18 @@ Configuration
|
||||
|
||||
The command honors `core.filemode` configuration variable. If
|
||||
your repository is on an filesystem whose executable bits are
|
||||
unreliable, this should be set to 'false'. This causes the
|
||||
command to ignore differences in file modes recorded in the
|
||||
index and the file mode on the filesystem if they differ only on
|
||||
unreliable, this should be set to 'false' (see gitlink:git-repo-config[1]).
|
||||
This causes the command to ignore differences in file modes recorded
|
||||
in the index and the file mode on the filesystem if they differ only on
|
||||
executable bit. On such an unfortunate filesystem, you may
|
||||
need to use `git-update-index --chmod=`.
|
||||
|
||||
|
||||
See Also
|
||||
--------
|
||||
gitlink:git-repo-config[1]
|
||||
|
||||
|
||||
Author
|
||||
------
|
||||
Written by Linus Torvalds <torvalds@osdl.org>
|
||||
|
@ -22,7 +22,7 @@ pull decisions. This command generates such auxiliary files.
|
||||
OPTIONS
|
||||
-------
|
||||
|
||||
--force::
|
||||
-f|--force::
|
||||
Update the info files from scratch.
|
||||
|
||||
|
||||
|
@ -8,7 +8,7 @@ git-verify-pack - Validate packed git archive files.
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
'git-verify-pack' [-v] <pack>.idx ...
|
||||
'git-verify-pack' [-v] [--] <pack>.idx ...
|
||||
|
||||
|
||||
DESCRIPTION
|
||||
@ -25,6 +25,8 @@ OPTIONS
|
||||
-v::
|
||||
After verifying the pack, show list of objects contained
|
||||
in the pack.
|
||||
--::
|
||||
Do not interpret any more arguments as options.
|
||||
|
||||
OUTPUT FORMAT
|
||||
-------------
|
||||
|
@ -14,19 +14,21 @@ DESCRIPTION
|
||||
-----------
|
||||
Creates a tree object using the current index.
|
||||
|
||||
The index must be merged.
|
||||
The index must be in a fully merged state.
|
||||
|
||||
Conceptually, "git-write-tree" sync()s the current index 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
|
||||
"git-write-tree".
|
||||
now, you need to have done a `git-update-index` phase before you did the
|
||||
`git-write-tree`.
|
||||
|
||||
|
||||
OPTIONS
|
||||
-------
|
||||
--missing-ok::
|
||||
Normally "git-write-tree" ensures that the objects referenced by the
|
||||
directory exist in the object database. This option disables this check.
|
||||
Normally `git-write-tree` ensures that the objects referenced by the
|
||||
directory exist in the object database. This option disables this
|
||||
check.
|
||||
|
||||
Author
|
||||
------
|
||||
|
@ -36,31 +36,35 @@ OPTIONS
|
||||
CORE GIT COMMANDS
|
||||
-----------------
|
||||
Before reading this cover to cover, you may want to take a look
|
||||
at the link:tutorial.html[tutorial] document.
|
||||
|
||||
The <<Discussion>> section below contains much useful definition and
|
||||
clarification info - read that first. And of the commands, I suggest
|
||||
reading gitlink:git-update-index[1] and
|
||||
gitlink:git-read-tree[1] first - I wish I had!
|
||||
|
||||
If you are migrating from CVS, link:cvs-migration.html[cvs migration]
|
||||
at the link:tutorial.html[tutorial] document. If you are
|
||||
migrating from CVS, link:cvs-migration.html[cvs migration]
|
||||
document may be helpful after you finish the tutorial.
|
||||
|
||||
The <<Discussion>> section below contains much useful definition
|
||||
and clarification info - read that first. After that, if you
|
||||
are interested in using git to manage (version control)
|
||||
projects, use link:everyday.html[Everyday GIT] as a guide to the
|
||||
minimum set of commands you need to know for day-to-day work.
|
||||
|
||||
After you get the general feel from the tutorial and this
|
||||
overview page, you may want to take a look at the
|
||||
link:howto-index.html[howto] documents.
|
||||
|
||||
If you are writing your own Porcelain, you need to be familiar
|
||||
with most of the low level commands --- I suggest starting from
|
||||
gitlink:git-update-index[1] and gitlink:git-read-tree[1].
|
||||
|
||||
|
||||
David Greaves <david@dgreaves.com>
|
||||
08/05/05
|
||||
|
||||
Updated by Junio C Hamano <junkio@cox.net> on 2005-05-05 to
|
||||
reflect recent changes.
|
||||
Updated by Junio C Hamano <junkio@cox.net> on 2005-05-05 and
|
||||
further on 2005-12-07 to reflect recent changes.
|
||||
|
||||
Commands Overview
|
||||
-----------------
|
||||
The git commands can helpfully be split into those that manipulate
|
||||
the repository, the index and the working fileset, those that
|
||||
the repository, the index and the files in the working tree, those that
|
||||
interrogate and compare them, and those that moves objects and
|
||||
references between repositories.
|
||||
|
||||
@ -79,25 +83,26 @@ gitlink:git-apply[1]::
|
||||
applies it to the working tree.
|
||||
|
||||
gitlink:git-checkout-index[1]::
|
||||
Copy files from the index to the working directory
|
||||
Copy files from the index to the working tree.
|
||||
|
||||
gitlink:git-commit-tree[1]::
|
||||
Creates a new commit object
|
||||
Creates a new commit object.
|
||||
|
||||
gitlink:git-hash-object[1]::
|
||||
Computes the object ID from a file.
|
||||
|
||||
gitlink:git-index-pack[1]::
|
||||
Build pack index file for an existing packed archive.
|
||||
Build pack idx file for an existing packed archive.
|
||||
|
||||
gitlink:git-init-db[1]::
|
||||
Creates an empty git object database
|
||||
Creates an empty git object database, or reinitialize an
|
||||
existing one.
|
||||
|
||||
gitlink:git-merge-index[1]::
|
||||
Runs a merge for files needing merging
|
||||
Runs a merge for files needing merging.
|
||||
|
||||
gitlink:git-mktag[1]::
|
||||
Creates a tag object
|
||||
Creates a tag object.
|
||||
|
||||
gitlink:git-pack-objects[1]::
|
||||
Creates a packed archive of objects.
|
||||
@ -106,7 +111,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 index
|
||||
Reads tree information into the index.
|
||||
|
||||
gitlink:git-repo-config[1]::
|
||||
Get and set options in .git/config.
|
||||
@ -115,65 +120,65 @@ gitlink:git-unpack-objects[1]::
|
||||
Unpacks objects out of a packed archive.
|
||||
|
||||
gitlink:git-update-index[1]::
|
||||
Modifies the index or directory cache
|
||||
Registers files in the working tree to the index.
|
||||
|
||||
gitlink:git-write-tree[1]::
|
||||
Creates a tree from the current index
|
||||
Creates a tree from the index.
|
||||
|
||||
|
||||
Interrogation commands
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
gitlink:git-cat-file[1]::
|
||||
Provide content or type information for repository objects
|
||||
Provide content or type/size information for repository objects.
|
||||
|
||||
gitlink:git-diff-index[1]::
|
||||
Compares content and mode of blobs between the index 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 index
|
||||
Compares files in the working tree and the index.
|
||||
|
||||
gitlink:git-diff-stages[1]::
|
||||
Compares two "merge stages" in the index file.
|
||||
Compares two "merge stages" in the index.
|
||||
|
||||
gitlink:git-diff-tree[1]::
|
||||
Compares the content and mode of blobs found via two tree objects
|
||||
Compares the content and mode of blobs found via two tree objects.
|
||||
|
||||
gitlink:git-fsck-objects[1]::
|
||||
Verifies the connectivity and validity of the objects in the database
|
||||
Verifies the connectivity and validity of the objects in the database.
|
||||
|
||||
gitlink:git-ls-files[1]::
|
||||
Information about files in the index/working directory
|
||||
Information about files in the index and the working tree.
|
||||
|
||||
gitlink:git-ls-tree[1]::
|
||||
Displays a tree object in human readable form
|
||||
Displays a tree object in human readable form.
|
||||
|
||||
gitlink:git-merge-base[1]::
|
||||
Finds as good a common ancestor as possible for a merge
|
||||
Finds as good common ancestors as possible for a merge.
|
||||
|
||||
gitlink:git-name-rev[1]::
|
||||
Find symbolic names for given revs
|
||||
Find symbolic names for given revs.
|
||||
|
||||
gitlink:git-rev-list[1]::
|
||||
Lists commit objects in reverse chronological order
|
||||
Lists commit objects in reverse chronological order.
|
||||
|
||||
gitlink:git-show-index[1]::
|
||||
Displays contents of a pack idx file.
|
||||
|
||||
gitlink:git-tar-tree[1]::
|
||||
Creates a tar archive of the files in the named tree
|
||||
Creates a tar archive of the files in the named tree object.
|
||||
|
||||
gitlink:git-unpack-file[1]::
|
||||
Creates a temporary file with a blob's contents
|
||||
Creates a temporary file with a blob's contents.
|
||||
|
||||
gitlink:git-var[1]::
|
||||
Displays a git logical variable
|
||||
Displays a git logical variable.
|
||||
|
||||
gitlink:git-verify-pack[1]::
|
||||
Validates packed git archive files
|
||||
Validates packed git archive files.
|
||||
|
||||
The interrogate commands may create files - and you can force them to
|
||||
touch the working file set - but in general they don't
|
||||
In general, the interrogate commands do not touch the files in
|
||||
the working tree.
|
||||
|
||||
|
||||
Synching repositories
|
||||
@ -181,19 +186,24 @@ Synching repositories
|
||||
|
||||
gitlink:git-clone-pack[1]::
|
||||
Clones a repository into the current repository (engine
|
||||
for ssh and local transport)
|
||||
for ssh and local transport).
|
||||
|
||||
gitlink:git-fetch-pack[1]::
|
||||
Updates from a remote repository.
|
||||
Updates from a remote repository (engine for ssh and
|
||||
local transport).
|
||||
|
||||
gitlink:git-http-fetch[1]::
|
||||
Downloads a remote git repository via HTTP
|
||||
Downloads a remote git repository via HTTP by walking
|
||||
commit chain.
|
||||
|
||||
gitlink:git-local-fetch[1]::
|
||||
Duplicates another git repository on a local system
|
||||
Duplicates another git repository on a local system by
|
||||
walking commit chain.
|
||||
|
||||
gitlink:git-peek-remote[1]::
|
||||
Lists references on a remote repository using upload-pack protocol.
|
||||
Lists references on a remote repository using
|
||||
upload-pack protocol (engine for ssh and local
|
||||
transport).
|
||||
|
||||
gitlink:git-receive-pack[1]::
|
||||
Invoked by 'git-send-pack' to receive what is pushed to it.
|
||||
@ -205,10 +215,11 @@ gitlink:git-shell[1]::
|
||||
Restricted shell for GIT-only SSH access.
|
||||
|
||||
gitlink:git-ssh-fetch[1]::
|
||||
Pulls from a remote repository over ssh connection
|
||||
Pulls from a remote repository over ssh connection by
|
||||
walking commit chain.
|
||||
|
||||
gitlink:git-ssh-upload[1]::
|
||||
Helper "server-side" program used by git-ssh-fetch
|
||||
Helper "server-side" program used by git-ssh-fetch.
|
||||
|
||||
gitlink:git-update-server-info[1]::
|
||||
Updates auxiliary information on a dumb server to help
|
||||
@ -223,16 +234,16 @@ Porcelain-ish Commands
|
||||
----------------------
|
||||
|
||||
gitlink:git-add[1]::
|
||||
Add paths to the index file.
|
||||
Add paths to the index.
|
||||
|
||||
gitlink:git-am[1]::
|
||||
Apply patches from a mailbox, but cooler.
|
||||
|
||||
gitlink:git-applymbox[1]::
|
||||
Apply patches from a mailbox.
|
||||
Apply patches from a mailbox, original version by Linus.
|
||||
|
||||
gitlink:git-bisect[1]::
|
||||
Find the change that introduced a bug.
|
||||
Find the change that introduced a bug by binary search.
|
||||
|
||||
gitlink:git-branch[1]::
|
||||
Create and Show branches.
|
||||
@ -259,7 +270,7 @@ gitlink:git-format-patch[1]::
|
||||
Prepare patches for e-mail submission.
|
||||
|
||||
gitlink:git-grep[1]::
|
||||
Print lines matching a pattern
|
||||
Print lines matching a pattern.
|
||||
|
||||
gitlink:git-log[1]::
|
||||
Shows commit logs.
|
||||
@ -283,7 +294,7 @@ gitlink:git-push[1]::
|
||||
Update remote refs along with associated objects.
|
||||
|
||||
gitlink:git-rebase[1]::
|
||||
Rebase local commits to new upstream head.
|
||||
Rebase local commits to the updated upstream head.
|
||||
|
||||
gitlink:git-repack[1]::
|
||||
Pack unpacked objects in a repository.
|
||||
@ -324,7 +335,7 @@ gitlink:git-archimport[1]::
|
||||
Import an arch repository into git.
|
||||
|
||||
gitlink:git-convert-objects[1]::
|
||||
Converts old-style git repository
|
||||
Converts old-style git repository.
|
||||
|
||||
gitlink:git-cvsimport[1]::
|
||||
Salvage your data out of another SCM people love to hate.
|
||||
@ -333,10 +344,10 @@ 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"
|
||||
The standard helper program to use with `git-merge-index`.
|
||||
|
||||
gitlink:git-prune[1]::
|
||||
Prunes all unreachable objects from the object database
|
||||
Prunes all unreachable objects from the object database.
|
||||
|
||||
gitlink:git-relink[1]::
|
||||
Hardlink common objects in local repositories.
|
||||
@ -348,10 +359,10 @@ gitlink:git-sh-setup[1]::
|
||||
Common git shell script setup code.
|
||||
|
||||
gitlink:git-symbolic-ref[1]::
|
||||
Read and modify symbolic refs
|
||||
Read and modify symbolic refs.
|
||||
|
||||
gitlink:git-tag[1]::
|
||||
An example script to create a tag object signed with GPG
|
||||
An example script to create a tag object signed with GPG.
|
||||
|
||||
gitlink:git-update-ref[1]::
|
||||
Update the object name stored in a ref safely.
|
||||
@ -375,16 +386,19 @@ gitlink:git-get-tar-commit-id[1]::
|
||||
Extract commit ID from an archive created using git-tar-tree.
|
||||
|
||||
gitlink:git-mailinfo[1]::
|
||||
Extracts patch from a single e-mail message.
|
||||
Extracts patch and authorship information from a single
|
||||
e-mail message, optionally transliterating the commit
|
||||
message into utf-8.
|
||||
|
||||
gitlink:git-mailsplit[1]::
|
||||
git-mailsplit.
|
||||
A stupid program to split UNIX mbox format mailbox into
|
||||
individual pieces of e-mail.
|
||||
|
||||
gitlink:git-patch-id[1]::
|
||||
Compute unique ID for a patch.
|
||||
|
||||
gitlink:git-parse-remote[1]::
|
||||
Routines to help parsing $GIT_DIR/remotes/
|
||||
Routines to help parsing `$GIT_DIR/remotes/` files.
|
||||
|
||||
gitlink:git-request-pull[1]::
|
||||
git-request-pull.
|
||||
@ -406,22 +420,20 @@ Commands not yet documented
|
||||
---------------------------
|
||||
|
||||
gitlink:gitk[1]::
|
||||
gitk.
|
||||
The gitk repository browser.
|
||||
|
||||
|
||||
Configuration Mechanism
|
||||
-----------------------
|
||||
|
||||
Starting from 0.99.9 (actually mid 0.99.8.GIT), .git/config file
|
||||
Starting from 0.99.9 (actually mid 0.99.8.GIT), `.git/config` file
|
||||
is used to hold per-repository configuration options. It is a
|
||||
simple text file modelled after `.ini` format familiar to some
|
||||
people. Here is an example:
|
||||
|
||||
------------
|
||||
#
|
||||
# This is the config file, and
|
||||
# a '#' or ';' character indicates
|
||||
# a comment
|
||||
# A '#' or ';' character indicates a comment.
|
||||
#
|
||||
|
||||
; core variables
|
||||
@ -443,30 +455,30 @@ their operation accordingly.
|
||||
Identifier Terminology
|
||||
----------------------
|
||||
<object>::
|
||||
Indicates the sha1 identifier for any type of object
|
||||
Indicates the object name for any type of object.
|
||||
|
||||
<blob>::
|
||||
Indicates a blob object sha1 identifier
|
||||
Indicates a blob object name.
|
||||
|
||||
<tree>::
|
||||
Indicates a tree object sha1 identifier
|
||||
Indicates a tree object name.
|
||||
|
||||
<commit>::
|
||||
Indicates a commit object sha1 identifier
|
||||
Indicates a commit object name.
|
||||
|
||||
<tree-ish>::
|
||||
Indicates a tree, commit or tag object sha1 identifier. A
|
||||
Indicates a tree, commit or tag object name. A
|
||||
command that takes a <tree-ish> argument ultimately wants to
|
||||
operate on a <tree> object but automatically dereferences
|
||||
<commit> and <tag> objects that point at a <tree>.
|
||||
|
||||
<type>::
|
||||
Indicates that an object type is required.
|
||||
Currently one of: blob/tree/commit/tag
|
||||
Currently one of: `blob`, `tree`, `commit`, or `tag`.
|
||||
|
||||
<file>::
|
||||
Indicates a filename - always relative to the root of
|
||||
the tree structure GIT_INDEX_FILE describes.
|
||||
Indicates a filename - almost always relative to the
|
||||
root of the tree structure `GIT_INDEX_FILE` describes.
|
||||
|
||||
Symbolic Identifiers
|
||||
--------------------
|
||||
@ -474,17 +486,20 @@ Any git command accepting any <object> can also use the following
|
||||
symbolic notation:
|
||||
|
||||
HEAD::
|
||||
indicates the head of the repository (ie the contents of
|
||||
`$GIT_DIR/HEAD`)
|
||||
indicates the head of the current branch (i.e. the
|
||||
contents of `$GIT_DIR/HEAD`).
|
||||
|
||||
<tag>::
|
||||
a valid tag 'name'+
|
||||
(ie the contents of `$GIT_DIR/refs/tags/<tag>`)
|
||||
a valid tag 'name'
|
||||
(i.e. the contents of `$GIT_DIR/refs/tags/<tag>`).
|
||||
|
||||
<head>::
|
||||
a valid head 'name'+
|
||||
(ie the contents of `$GIT_DIR/refs/heads/<head>`)
|
||||
a valid head 'name'
|
||||
(i.e. the contents of `$GIT_DIR/refs/heads/<head>`).
|
||||
|
||||
<snap>::
|
||||
a valid snapshot 'name'+
|
||||
(ie the contents of `$GIT_DIR/refs/snap/<snap>`)
|
||||
a valid snapshot 'name'
|
||||
(i.e. the contents of `$GIT_DIR/refs/snap/<snap>`).
|
||||
|
||||
|
||||
File/Directory Structure
|
||||
@ -493,7 +508,7 @@ File/Directory Structure
|
||||
Please see link:repository-layout.html[repository layout] document.
|
||||
|
||||
Higher level SCMs may provide and manage additional information in the
|
||||
GIT_DIR.
|
||||
`$GIT_DIR`.
|
||||
|
||||
|
||||
Terminology
|
||||
@ -509,7 +524,7 @@ The git Repository
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
These environment variables apply to 'all' core git commands. Nb: it
|
||||
is worth noting that they may be used/overridden by SCMS sitting above
|
||||
git so take care if using Cogito etc
|
||||
git so take care if using Cogito etc.
|
||||
|
||||
'GIT_INDEX_FILE'::
|
||||
This environment allows the specification of an alternate
|
||||
@ -530,9 +545,9 @@ git so take care if using Cogito etc
|
||||
written to these directories.
|
||||
|
||||
'GIT_DIR'::
|
||||
If the 'GIT_DIR' environment variable is set then it specifies
|
||||
a path to use instead of `./.git` for the base of the
|
||||
repository.
|
||||
If the 'GIT_DIR' environment variable is set then it
|
||||
specifies a path to use instead of the default `.git`
|
||||
for the base of the repository.
|
||||
|
||||
git Commits
|
||||
~~~~~~~~~~~
|
||||
@ -559,7 +574,7 @@ include::../README[]
|
||||
Authors
|
||||
-------
|
||||
git's founding father is Linus Torvalds <torvalds@osdl.org>.
|
||||
The current git nurse is Junio C. Hamano <junkio@cox.net>.
|
||||
The current git nurse is Junio C Hamano <junkio@cox.net>.
|
||||
The git potty was written by Andres Ericsson <ae@op5.se>.
|
||||
General upbringing is handled by the git-list <git@vger.kernel.org>.
|
||||
|
||||
|
@ -20,7 +20,7 @@ hash::
|
||||
|
||||
object database::
|
||||
Stores a set of "objects", and an individial object is identified
|
||||
by its object name. The object usually live in $GIT_DIR/objects/.
|
||||
by its object name. The objects usually live in `$GIT_DIR/objects/`.
|
||||
|
||||
blob object::
|
||||
Untyped object, e.g. the contents of a file.
|
||||
@ -109,15 +109,15 @@ head::
|
||||
branch::
|
||||
A non-cyclical graph of revisions, i.e. the complete history of
|
||||
a particular revision, which is called the branch head. The
|
||||
branch heads are stored in $GIT_DIR/refs/heads/.
|
||||
branch heads are stored in `$GIT_DIR/refs/heads/`.
|
||||
|
||||
ref::
|
||||
A 40-byte hex representation of a SHA1 pointing to a particular
|
||||
object. These may be stored in $GIT_DIR/refs/.
|
||||
object. These may be stored in `$GIT_DIR/refs/`.
|
||||
|
||||
head ref::
|
||||
A ref pointing to a head. Often, this is abbreviated to "head".
|
||||
Head refs are stored in $GIT_DIR/refs/heads/.
|
||||
Head refs are stored in `$GIT_DIR/refs/heads/`.
|
||||
|
||||
tree-ish::
|
||||
A ref pointing to either a commit object, a tree object, or a
|
||||
@ -125,7 +125,7 @@ tree-ish::
|
||||
|
||||
ent::
|
||||
Favorite synonym to "tree-ish" by some total geeks. See
|
||||
http://en.wikipedia.org/wiki/Ent_(Middle-earth) for an in-depth
|
||||
`http://en.wikipedia.org/wiki/Ent_(Middle-earth)` for an in-depth
|
||||
explanation.
|
||||
|
||||
tag object::
|
||||
@ -137,7 +137,7 @@ tag object::
|
||||
tag::
|
||||
A ref pointing to a tag or commit object. In contrast to a head,
|
||||
a tag is not changed by a commit. Tags (not tag objects) are
|
||||
stored in $GIT_DIR/refs/tags/. A git tag has nothing to do with
|
||||
stored in `$GIT_DIR/refs/tags/`. A git tag has nothing to do with
|
||||
a Lisp tag (which is called object type in git's context).
|
||||
A tag is most typically used to mark a particular point in the
|
||||
commit ancestry chain.
|
||||
|
@ -1,4 +1,4 @@
|
||||
From: Junio C Hamano <junkio@cox.net>
|
||||
From: Junio C Hamano <junkio@cox.net> and Carl Baldwin <cnb@fc.hp.com>
|
||||
Subject: control access to branches.
|
||||
Date: Thu, 17 Nov 2005 23:55:32 -0800
|
||||
Message-ID: <7vfypumlu3.fsf@assigned-by-dhcp.cox.net>
|
||||
@ -26,63 +26,137 @@ section of the documentation:
|
||||
So if your policy is (1) always require fast-forward push
|
||||
(i.e. never allow "git-push repo +branch:branch"), (2) you
|
||||
have a list of users allowed to update each branch, and (3) you
|
||||
do not let tags to be overwritten, then:
|
||||
do not let tags to be overwritten, then you can use something
|
||||
like this as your hooks/update script.
|
||||
|
||||
#!/bin/sh
|
||||
# This is a sample hooks/update script, written by JC
|
||||
# in his e-mail buffer, so naturally it is not tested
|
||||
# but hopefully would convey the idea.
|
||||
[jc: editorial note. This is a much improved version by Carl
|
||||
since I posted the original outline]
|
||||
|
||||
umask 002
|
||||
case "$1" in
|
||||
refs/tags/*)
|
||||
# No overwriting an existing tag
|
||||
if test -f "$GIT_DIR/$1"
|
||||
then
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
refs/heads/*)
|
||||
# No rebasing or rewinding
|
||||
if expr "$2" : '0*$' >/dev/null
|
||||
then
|
||||
# creating a new branch
|
||||
;
|
||||
else
|
||||
# updating -- make sure it is a fast forward
|
||||
mb=`git-merge-base "$2" "$3"`
|
||||
case "$mb,$2" in
|
||||
"$2,$mb")
|
||||
;; # fast forward -- happy
|
||||
*)
|
||||
exit 1 ;; # unhappy
|
||||
esac
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
# No funny refs allowed
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
-- >8 -- beginning of script -- >8 --
|
||||
|
||||
# Is the user allowed to update it?
|
||||
me=`id -u -n` ;# e.g. "junio"
|
||||
while read head_pattern users
|
||||
do
|
||||
if expr "$1" : "$head_pattern" >/dev/null
|
||||
then
|
||||
case " $users " in
|
||||
*" $me "*)
|
||||
exit 0 ;; # happy
|
||||
' * ')
|
||||
exit 0 ;; # anybody
|
||||
esac
|
||||
fi
|
||||
done
|
||||
exit 1
|
||||
#!/bin/bash
|
||||
|
||||
For the sake of simplicity, I assumed that you keep something
|
||||
like this in $GIT_DIR/info/allowed-pushers file:
|
||||
umask 002
|
||||
|
||||
# If you are having trouble with this access control hook script
|
||||
# you can try setting this to true. It will tell you exactly
|
||||
# why a user is being allowed/denied access.
|
||||
|
||||
verbose=false
|
||||
|
||||
# Default shell globbing messes things up downstream
|
||||
GLOBIGNORE=*
|
||||
|
||||
function grant {
|
||||
$verbose && echo >&2 "-Grant- $1"
|
||||
echo grant
|
||||
exit 0
|
||||
}
|
||||
|
||||
function deny {
|
||||
$verbose && echo >&2 "-Deny- $1"
|
||||
echo deny
|
||||
exit 1
|
||||
}
|
||||
|
||||
function info {
|
||||
$verbose && echo >&2 "-Info- $1"
|
||||
}
|
||||
|
||||
# Implement generic branch and tag policies.
|
||||
# - Tags should not be updated once created.
|
||||
# - Branches should only be fast-forwarded.
|
||||
case "$1" in
|
||||
refs/tags/*)
|
||||
[ -f "$GIT_DIR/$1" ] &&
|
||||
deny >/dev/null "You can't overwrite an existing tag"
|
||||
;;
|
||||
refs/heads/*)
|
||||
# No rebasing or rewinding
|
||||
if expr "$2" : '0*$' >/dev/null; then
|
||||
info "The branch '$1' is new..."
|
||||
else
|
||||
# updating -- make sure it is a fast forward
|
||||
mb=$(git-merge-base "$2" "$3")
|
||||
case "$mb,$2" in
|
||||
"$2,$mb") info "Update is fast-forward" ;;
|
||||
*) deny >/dev/null "This is not a fast-forward update." ;;
|
||||
esac
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
deny >/dev/null \
|
||||
"Branch is not under refs/heads or refs/tags. What are you trying to do?"
|
||||
;;
|
||||
esac
|
||||
|
||||
# Implement per-branch controls based on username
|
||||
allowed_users_file=$GIT_DIR/info/allowed-users
|
||||
username=$(id -u -n)
|
||||
info "The user is: '$username'"
|
||||
|
||||
if [ -f "$allowed_users_file" ]; then
|
||||
rc=$(cat $allowed_users_file | grep -v '^#' | grep -v '^$' |
|
||||
while read head_pattern user_patterns; do
|
||||
matchlen=$(expr "$1" : "$head_pattern")
|
||||
if [ "$matchlen" == "${#1}" ]; then
|
||||
info "Found matching head pattern: '$head_pattern'"
|
||||
for user_pattern in $user_patterns; do
|
||||
info "Checking user: '$username' against pattern: '$user_pattern'"
|
||||
matchlen=$(expr "$username" : "$user_pattern")
|
||||
if [ "$matchlen" == "${#username}" ]; then
|
||||
grant "Allowing user: '$username' with pattern: '$user_pattern'"
|
||||
fi
|
||||
done
|
||||
deny "The user is not in the access list for this branch"
|
||||
fi
|
||||
done
|
||||
)
|
||||
case "$rc" in
|
||||
grant) grant >/dev/null "Granting access based on $allowed_users_file" ;;
|
||||
deny) deny >/dev/null "Denying access based on $allowed_users_file" ;;
|
||||
*) ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
allowed_groups_file=$GIT_DIR/info/allowed-groups
|
||||
groups=$(id -G -n)
|
||||
info "The user belongs to the following groups:"
|
||||
info "'$groups'"
|
||||
|
||||
if [ -f "$allowed_groups_file" ]; then
|
||||
rc=$(cat $allowed_groups_file | grep -v '^#' | grep -v '^$' |
|
||||
while read head_pattern group_patterns; do
|
||||
matchlen=$(expr "$1" : "$head_pattern")
|
||||
if [ "$matchlen" == "${#1}" ]; then
|
||||
info "Found matching head pattern: '$head_pattern'"
|
||||
for group_pattern in $group_patterns; do
|
||||
for groupname in $groups; do
|
||||
info "Checking group: '$groupname' against pattern: '$group_pattern'"
|
||||
matchlen=$(expr "$groupname" : "$group_pattern")
|
||||
if [ "$matchlen" == "${#groupname}" ]; then
|
||||
grant "Allowing group: '$groupname' with pattern: '$group_pattern'"
|
||||
fi
|
||||
done
|
||||
done
|
||||
deny "None of the user's groups are in the access list for this branch"
|
||||
fi
|
||||
done
|
||||
)
|
||||
case "$rc" in
|
||||
grant) grant >/dev/null "Granting access based on $allowed_groups_file" ;;
|
||||
deny) deny >/dev/null "Denying access based on $allowed_groups_file" ;;
|
||||
*) ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
deny >/dev/null "There are no more rules to check. Denying access"
|
||||
|
||||
-- >8 -- end of script -- >8 --
|
||||
|
||||
This uses two files, $GIT_DIR/info/allowed-users and
|
||||
allowed-groups, to describe which heads can be pushed into by
|
||||
whom. The format of each file would look like this:
|
||||
|
||||
refs/heads/master junio
|
||||
refs/heads/cogito$ pasky
|
||||
@ -91,15 +165,8 @@ like this in $GIT_DIR/info/allowed-pushers file:
|
||||
refs/tags/v[0-9]* junio
|
||||
|
||||
With this, Linus can push or create "bw/penguin" or "bw/zebra"
|
||||
or "bw/panda" branches, Pasky can do only "cogito", and I can do
|
||||
master branch and make versioned tags. And anybody can do
|
||||
tmp/blah branches. This assumes all the users are in a single
|
||||
group that can write into $GIT_DIR/ and underneath.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
or "bw/panda" branches, Pasky can do only "cogito", and JC can
|
||||
do master branch and make versioned tags. And anybody can do
|
||||
tmp/blah branches.
|
||||
|
||||
------------
|
||||
|
@ -11,6 +11,6 @@
|
||||
Use the given merge strategy; can be supplied more than
|
||||
once to specify them in the order they should be tried.
|
||||
If there is no `-s` option, a built-in list of strategies
|
||||
is used instead (`git-merge-resolve` when merging a single
|
||||
is used instead (`git-merge-recursive` when merging a single
|
||||
head, `git-merge-octopus` otherwise).
|
||||
|
||||
|
@ -6,27 +6,27 @@ resolve::
|
||||
and another branch you pulled from) using 3-way merge
|
||||
algorithm. It tries to carefully detect criss-cross
|
||||
merge ambiguities and is considered generally safe and
|
||||
fast. This is the default merge strategy when pulling
|
||||
one branch.
|
||||
fast.
|
||||
|
||||
recursive::
|
||||
This can only resolve two heads using 3-way merge
|
||||
algorithm. When there are more than one common
|
||||
ancestors that can be used for 3-way merge, it creates a
|
||||
merged tree of the common ancestores and uses that as
|
||||
merged tree of the common ancestors and uses that as
|
||||
the reference tree for the 3-way merge. This has been
|
||||
reported to result in fewer merge conflicts without
|
||||
causing mis-merges by tests done on actual merge commits
|
||||
taken from Linux 2.6 kernel development history.
|
||||
Additionally this can detect and handle merges involving
|
||||
renames.
|
||||
renames. This is the default merge strategy when
|
||||
pulling or merging one branch.
|
||||
|
||||
octopus::
|
||||
This resolves more than two-head case, but refuses to do
|
||||
complex merge that needs manual resolution. It is
|
||||
primarily meant to be used for bundling topic branch
|
||||
heads together. This is the default merge strategy when
|
||||
pulling more than one branch.
|
||||
pulling or merging more than one branches.
|
||||
|
||||
ours::
|
||||
This resolves any number of heads, but the result of the
|
||||
|
@ -42,7 +42,6 @@ sub no_spaces ($) {
|
||||
|
||||
print 'GIT Glossary
|
||||
============
|
||||
Aug 2005
|
||||
|
||||
This list is sorted alphabetically:
|
||||
|
||||
|
@ -1282,26 +1282,27 @@ fatal: merge program failed
|
||||
|
||||
`git-merge-one-file` script is called with parameters to
|
||||
describe those three versions, and is responsible to leave the
|
||||
merge results in the working tree and register it in the index
|
||||
file. It is a fairly straightforward shell script, and
|
||||
eventually calls `merge` program from RCS suite to perform the
|
||||
merge results in the working tree.
|
||||
It is a fairly straightforward shell script, and
|
||||
eventually calls `merge` program from RCS suite to perform a
|
||||
file-level 3-way merge. In this case, `merge` detects
|
||||
conflicts, and the merge result with conflict marks is left in
|
||||
the working tree, while the index file is updated with the
|
||||
version from the current branch (this is to make `git diff`
|
||||
useful after this step). This can be seen if you run `ls-files
|
||||
the working tree.. This can be seen if you run `ls-files
|
||||
--stage` again at this point:
|
||||
|
||||
------------
|
||||
$ git-ls-files --stage
|
||||
100644 7f8b141b65fdcee47321e399a2598a235a032422 0 example
|
||||
100644 06fa6a24256dc7e560efa5687fa84b51f0263c3a 0 hello
|
||||
100644 263414f423d0e4d70dae8fe53fa34614ff3e2860 1 hello
|
||||
100644 06fa6a24256dc7e560efa5687fa84b51f0263c3a 2 hello
|
||||
100644 cc44c73eb783565da5831b4d820c962954019b69 3 hello
|
||||
------------
|
||||
|
||||
As you can see, there is no unmerged paths in the index file.
|
||||
This is the state of the index file and the working file after
|
||||
`git merge` returns control back to you, leaving the conflicting
|
||||
merge for you to resolve.
|
||||
merge for you to resolve. Notice that the path `hello` is still
|
||||
unmerged, and what you see with `git diff` at this point is
|
||||
differences since stage 2 (i.e. your version).
|
||||
|
||||
|
||||
Publishing your work
|
||||
@ -1636,14 +1637,49 @@ fast forward. You need to pull and merge those other changes
|
||||
back before you push your work when it happens.
|
||||
|
||||
|
||||
Advanced Shared Repository Management
|
||||
-------------------------------------
|
||||
|
||||
Being able to push into a shared repository means being able to
|
||||
write into it. If your developers are coming over the network,
|
||||
this means you, as the repository administrator, need to give
|
||||
each of them an SSH access to the shared repository machine.
|
||||
|
||||
In some cases, though, you may not want to give a normal shell
|
||||
account to them, but want to restrict them to be able to only
|
||||
do `git push` into the repository and nothing else.
|
||||
|
||||
You can achieve this by setting the login shell of your
|
||||
developers on the shared repository host to `git-shell` program.
|
||||
|
||||
[NOTE]
|
||||
Most likely you would also need to list `git-shell` program in
|
||||
`/etc/shells` file.
|
||||
|
||||
This restricts the set of commands that can be run from incoming
|
||||
SSH connection for these users to only `receive-pack` and
|
||||
`upload-pack`, so the only thing they can do are `git fetch` and
|
||||
`git push`.
|
||||
|
||||
You still need to create UNIX user accounts for each developer,
|
||||
and put them in the same group. Make sure that the repository
|
||||
shared among these developers is writable by that group.
|
||||
|
||||
You can implement finer grained branch policies using update
|
||||
hooks. There is a document ("control access to branches") in
|
||||
Documentation/howto by Carl Baldwin and JC outlining how to (1)
|
||||
limit access to branch per user, (2) forbid overwriting existing
|
||||
tags.
|
||||
|
||||
|
||||
Bundling your work together
|
||||
---------------------------
|
||||
|
||||
It is likely that you will be working on more than one thing at
|
||||
a time. It is easy to use those more-or-less independent tasks
|
||||
a time. It is easy to manage those more-or-less independent tasks
|
||||
using branches with git.
|
||||
|
||||
We have already seen how branches work in a previous example,
|
||||
We have already seen how branches work previously,
|
||||
with "fun and work" example using two branches. The idea is the
|
||||
same if there are more than two branches. Let's say you started
|
||||
out from "master" head, and have some new code in the "master"
|
||||
|
3
INSTALL
3
INSTALL
@ -87,3 +87,6 @@ Issues of note:
|
||||
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.
|
||||
You can place local settings in config.mak and the Makefile
|
||||
will include them. Note that config.mak is not distributed;
|
||||
the name is reserved for local settings.
|
||||
|
18
Makefile
18
Makefile
@ -55,7 +55,7 @@ all:
|
||||
# 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.9l
|
||||
GIT_VERSION = 0.99.9m
|
||||
|
||||
# CFLAGS and LDFLAGS are for the users to override from the command line.
|
||||
|
||||
@ -162,7 +162,7 @@ LIB_FILE=libgit.a
|
||||
LIB_H = \
|
||||
blob.h cache.h commit.h count-delta.h csum-file.h delta.h \
|
||||
diff.h epoch.h object.h pack.h pkt-line.h quote.h refs.h \
|
||||
run-command.h strbuf.h tag.h tree.h
|
||||
run-command.h strbuf.h tag.h tree.h git-compat-util.h
|
||||
|
||||
DIFF_OBJS = \
|
||||
diff.o diffcore-break.o diffcore-order.o diffcore-pathspec.o \
|
||||
@ -243,6 +243,10 @@ ifeq ($(uname_S),NetBSD)
|
||||
ALL_CFLAGS += -I/usr/pkg/include
|
||||
ALL_LDFLAGS += -L/usr/pkg/lib -Wl,-rpath,/usr/pkg/lib
|
||||
endif
|
||||
ifeq ($(uname_S),AIX)
|
||||
NO_STRCASESTR=YesPlease
|
||||
NEEDS_LIBICONV=YesPlease
|
||||
endif
|
||||
ifneq (,$(findstring arm,$(uname_M)))
|
||||
ARM_SHA1 = YesPlease
|
||||
endif
|
||||
@ -320,15 +324,15 @@ ifdef NEEDS_NSL
|
||||
SIMPLE_LIB += -lnsl
|
||||
endif
|
||||
ifdef NO_STRCASESTR
|
||||
COMPAT_CFLAGS += -Dstrcasestr=gitstrcasestr -DNO_STRCASESTR=1
|
||||
COMPAT_CFLAGS += -DNO_STRCASESTR
|
||||
COMPAT_OBJS += compat/strcasestr.o
|
||||
endif
|
||||
ifdef NO_SETENV
|
||||
COMPAT_CFLAGS += -Dsetenv=gitsetenv -DNO_SETENV=1
|
||||
COMPAT_CFLAGS += -DNO_SETENV
|
||||
COMPAT_OBJS += compat/setenv.o
|
||||
endif
|
||||
ifdef NO_MMAP
|
||||
COMPAT_CFLAGS += -Dmmap=gitfakemmap -Dmunmap=gitfakemunmap -DNO_MMAP
|
||||
COMPAT_CFLAGS += -DNO_MMAP
|
||||
COMPAT_OBJS += compat/mmap.o
|
||||
endif
|
||||
ifdef NO_IPV6
|
||||
@ -363,9 +367,9 @@ all: $(ALL_PROGRAMS)
|
||||
all:
|
||||
$(MAKE) -C templates
|
||||
|
||||
git$(X): git.c $(COMPAT_OBJS) Makefile
|
||||
git$X: git.c $(LIB_FILE) Makefile
|
||||
$(CC) -DGIT_EXEC_PATH='"$(bindir)"' -DGIT_VERSION='"$(GIT_VERSION)"' \
|
||||
$(CFLAGS) $(COMPAT_CFLAGS) -o $@ $(filter %.c,$^) $(filter %.o,$^)
|
||||
$(CFLAGS) $(COMPAT_CFLAGS) -o $@ $(filter %.c,$^) $(LIB_FILE)
|
||||
|
||||
$(patsubst %.sh,%,$(SCRIPT_SH)) : % : %.sh
|
||||
rm -f $@
|
||||
|
17
README
17
README
@ -35,7 +35,7 @@ the object (i.e. how it is used, and how it can refer to other
|
||||
objects). There are currently four different object types: "blob",
|
||||
"tree", "commit" and "tag".
|
||||
|
||||
A "blob" object cannot refer to any other object, and is, like the tag
|
||||
A "blob" object cannot refer to any other object, and is, like the type
|
||||
implies, a pure storage object containing some user data. It is used to
|
||||
actually store the file data, i.e. a blob object is associated with some
|
||||
particular version of some file.
|
||||
@ -64,7 +64,7 @@ symbolic name (of course!) and, optionally, a signature.
|
||||
|
||||
Regardless of object type, all objects share the following
|
||||
characteristics: they are all deflated with zlib, and have a header
|
||||
that not only specifies their tag, but also provides size information
|
||||
that not only specifies their type, but also provides size information
|
||||
about the data in the object. It's worth noting that the SHA1 hash
|
||||
that is used to name the object is the hash of the original data
|
||||
plus this header, so `sha1sum` 'file' does not match the object name
|
||||
@ -76,7 +76,7 @@ As a result, the general consistency of an object can always be tested
|
||||
independently of the contents or the type of the object: all objects can
|
||||
be validated by verifying that (a) their hashes match the content of the
|
||||
file and (b) the object successfully inflates to a stream of bytes that
|
||||
forms a sequence of <ascii tag without space> + <space> + <ascii decimal
|
||||
forms a sequence of <ascii type without space> + <space> + <ascii decimal
|
||||
size> + <byte\0> + <binary object data>.
|
||||
|
||||
The structured objects can further have their structure and
|
||||
@ -297,7 +297,7 @@ will not normally add totally new entries or remove old entries,
|
||||
i.e. it will normally just update existing cache entries.
|
||||
|
||||
To tell git that yes, you really do realize that certain files no
|
||||
longer exist in the archive, or that new files should be added, you
|
||||
longer exist, or that new files should be added, you
|
||||
should use the `--remove` and `--add` flags respectively.
|
||||
|
||||
NOTE! A `--remove` flag does 'not' mean that subsequent filenames will
|
||||
@ -515,8 +515,11 @@ index file, and you can just write the result out with
|
||||
Historical note. We did not have `-u` facility when this
|
||||
section was first written, so we used to warn that
|
||||
the merge is done in the index file, not in your
|
||||
working directory, and your working directory will no longer match your
|
||||
index.
|
||||
working tree, and your working tree will not match your
|
||||
index after this step.
|
||||
This is no longer true. The above command, thanks to `-u`
|
||||
option, updates your working tree with the merge results for
|
||||
paths that have been trivially merged.
|
||||
|
||||
|
||||
8) Merging multiple trees, continued
|
||||
@ -579,7 +582,7 @@ The above is the description of a git merge at the lowest level,
|
||||
to help you understand what conceptually happens under the hood.
|
||||
In practice, nobody, not even git itself, uses three `git-cat-file`
|
||||
for this. There is `git-merge-index` program that extracts the
|
||||
stages to temporary files and calls a `merge` script on it
|
||||
stages to temporary files and calls a "merge" script on it:
|
||||
|
||||
git-merge-index git-merge-one-file hello.c
|
||||
|
||||
|
97
cache.h
97
cache.h
@ -1,23 +1,7 @@
|
||||
#ifndef CACHE_H
|
||||
#define CACHE_H
|
||||
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#ifndef NO_MMAP
|
||||
#include <sys/mman.h>
|
||||
#endif
|
||||
#include <sys/param.h>
|
||||
#include <netinet/in.h>
|
||||
#include <sys/types.h>
|
||||
#include <dirent.h>
|
||||
#include "git-compat-util.h"
|
||||
|
||||
#include SHA1_HEADER
|
||||
#include <zlib.h>
|
||||
@ -36,15 +20,6 @@
|
||||
#define DTYPE(de) DT_UNKNOWN
|
||||
#endif
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define NORETURN __attribute__((__noreturn__))
|
||||
#else
|
||||
#define NORETURN
|
||||
#ifndef __attribute__
|
||||
#define __attribute__(x)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Intensive research over the course of many years has shown that
|
||||
* port 9418 is totally unused by anything else. Or
|
||||
@ -169,6 +144,7 @@ extern int ce_match_stat(struct cache_entry *ce, struct stat *st);
|
||||
extern int ce_modified(struct cache_entry *ce, struct stat *st);
|
||||
extern int ce_path_match(const struct cache_entry *ce, const char **pathspec);
|
||||
extern int index_fd(unsigned char *sha1, int fd, struct stat *st, int write_object, const char *type);
|
||||
extern int index_pipe(unsigned char *sha1, int fd, const char *type, int write_object);
|
||||
extern int index_path(unsigned char *sha1, const char *path, struct stat *st, int write_object);
|
||||
extern void fill_stat_cache_info(struct cache_entry *ce, struct stat *st);
|
||||
|
||||
@ -250,11 +226,6 @@ extern const char *resolve_ref(const char *path, unsigned char *sha1, int);
|
||||
extern int create_symref(const char *git_HEAD, const char *refs_heads_master);
|
||||
extern int validate_symref(const char *git_HEAD);
|
||||
|
||||
/* General helper functions */
|
||||
extern void usage(const char *err) NORETURN;
|
||||
extern void die(const char *err, ...) NORETURN __attribute__((format (printf, 1, 2)));
|
||||
extern int error(const char *err, ...) __attribute__((format (printf, 1, 2)));
|
||||
|
||||
extern int base_name_compare(const char *name1, int len1, int mode1, const char *name2, int len2, int mode2);
|
||||
extern int cache_name_compare(const char *name1, int len1, const char *name2, int len2);
|
||||
|
||||
@ -272,30 +243,6 @@ extern int setup_ident(void);
|
||||
extern const char *git_author_info(void);
|
||||
extern const char *git_committer_info(void);
|
||||
|
||||
static inline void *xmalloc(size_t size)
|
||||
{
|
||||
void *ret = malloc(size);
|
||||
if (!ret)
|
||||
die("Out of memory, malloc failed");
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline void *xrealloc(void *ptr, size_t size)
|
||||
{
|
||||
void *ret = realloc(ptr, size);
|
||||
if (!ret)
|
||||
die("Out of memory, realloc failed");
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline void *xcalloc(size_t nmemb, size_t size)
|
||||
{
|
||||
void *ret = calloc(nmemb, size);
|
||||
if (!ret)
|
||||
die("Out of memory, calloc failed");
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct checkout {
|
||||
const char *base_dir;
|
||||
int base_dir_len;
|
||||
@ -373,20 +320,6 @@ extern void packed_object_info_detail(struct pack_entry *, char *, unsigned long
|
||||
/* Dumb servers support */
|
||||
extern int update_server_info(int);
|
||||
|
||||
#ifdef NO_MMAP
|
||||
|
||||
#ifndef PROT_READ
|
||||
#define PROT_READ 1
|
||||
#define PROT_WRITE 2
|
||||
#define MAP_PRIVATE 1
|
||||
#define MAP_FAILED ((void*)-1)
|
||||
#endif
|
||||
|
||||
extern void *gitfakemmap(void *start, size_t length, int prot , int flags, int fd, off_t offset);
|
||||
extern int gitfakemunmap(void *start, size_t length);
|
||||
|
||||
#endif
|
||||
|
||||
typedef int (*config_fn_t)(const char *, const char *);
|
||||
extern int git_default_config(const char *, const char *);
|
||||
extern int git_config_from_file(config_fn_t fn, const char *);
|
||||
@ -404,31 +337,5 @@ extern char git_default_name[MAX_GITNAME];
|
||||
#define MAX_ENCODING_LENGTH 64
|
||||
extern char git_commit_encoding[MAX_ENCODING_LENGTH];
|
||||
|
||||
/* Sane ctype - no locale, and works with signed chars */
|
||||
#undef isspace
|
||||
#undef isdigit
|
||||
#undef isalpha
|
||||
#undef isalnum
|
||||
#undef tolower
|
||||
#undef toupper
|
||||
extern unsigned char sane_ctype[256];
|
||||
#define GIT_SPACE 0x01
|
||||
#define GIT_DIGIT 0x02
|
||||
#define GIT_ALPHA 0x04
|
||||
#define sane_istest(x,mask) ((sane_ctype[(unsigned char)(x)] & (mask)) != 0)
|
||||
#define isspace(x) sane_istest(x,GIT_SPACE)
|
||||
#define isdigit(x) sane_istest(x,GIT_DIGIT)
|
||||
#define isalpha(x) sane_istest(x,GIT_ALPHA)
|
||||
#define isalnum(x) sane_istest(x,GIT_ALPHA | GIT_DIGIT)
|
||||
#define tolower(x) sane_case((unsigned char)(x), 0x20)
|
||||
#define toupper(x) sane_case((unsigned char)(x), 0)
|
||||
|
||||
static inline int sane_case(int x, int high)
|
||||
{
|
||||
if (sane_istest(x, GIT_ALPHA))
|
||||
x = (x & ~0x20) | high;
|
||||
return x;
|
||||
}
|
||||
|
||||
extern int copy_fd(int ifd, int ofd);
|
||||
#endif /* CACHE_H */
|
||||
|
@ -36,6 +36,7 @@
|
||||
|
||||
static const char *prefix;
|
||||
static int prefix_length;
|
||||
static int checkout_stage; /* default to checkout stage0 */
|
||||
|
||||
static struct checkout state = {
|
||||
.base_dir = "",
|
||||
@ -48,20 +49,36 @@ static struct checkout state = {
|
||||
|
||||
static int checkout_file(const char *name)
|
||||
{
|
||||
int pos = cache_name_pos(name, strlen(name));
|
||||
if (pos < 0) {
|
||||
if (!state.quiet) {
|
||||
pos = -pos - 1;
|
||||
fprintf(stderr,
|
||||
"git-checkout-index: %s is %s.\n",
|
||||
name,
|
||||
(pos < active_nr &&
|
||||
!strcmp(active_cache[pos]->name, name)) ?
|
||||
"unmerged" : "not in the cache");
|
||||
}
|
||||
return -1;
|
||||
int namelen = strlen(name);
|
||||
int pos = cache_name_pos(name, namelen);
|
||||
int has_same_name = 0;
|
||||
|
||||
if (pos < 0)
|
||||
pos = -pos - 1;
|
||||
|
||||
while (pos < active_nr) {
|
||||
struct cache_entry *ce = active_cache[pos];
|
||||
if (ce_namelen(ce) != namelen &&
|
||||
memcmp(ce->name, name, namelen))
|
||||
break;
|
||||
has_same_name = 1;
|
||||
if (checkout_stage == ce_stage(ce))
|
||||
return checkout_entry(ce, &state);
|
||||
pos++;
|
||||
}
|
||||
return checkout_entry(active_cache[pos], &state);
|
||||
|
||||
if (!state.quiet) {
|
||||
fprintf(stderr, "git-checkout-index: %s ", name);
|
||||
if (!has_same_name)
|
||||
fprintf(stderr, "is not in the cache");
|
||||
else if (checkout_stage)
|
||||
fprintf(stderr, "does not exist at stage %d",
|
||||
checkout_stage);
|
||||
else
|
||||
fprintf(stderr, "is unmerged");
|
||||
fputc('\n', stderr);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int checkout_all(void)
|
||||
@ -70,11 +87,11 @@ static int checkout_all(void)
|
||||
|
||||
for (i = 0; i < active_nr ; i++) {
|
||||
struct cache_entry *ce = active_cache[i];
|
||||
if (ce_stage(ce))
|
||||
if (ce_stage(ce) != checkout_stage)
|
||||
continue;
|
||||
if (prefix && *prefix &&
|
||||
( ce_namelen(ce) <= prefix_length ||
|
||||
memcmp(prefix, ce->name, prefix_length) ))
|
||||
(ce_namelen(ce) <= prefix_length ||
|
||||
memcmp(prefix, ce->name, prefix_length)))
|
||||
continue;
|
||||
if (checkout_entry(ce, &state) < 0)
|
||||
errs++;
|
||||
@ -88,7 +105,7 @@ static int checkout_all(void)
|
||||
}
|
||||
|
||||
static const char checkout_cache_usage[] =
|
||||
"git-checkout-index [-u] [-q] [-a] [-f] [-n] [--prefix=<string>] [--] <file>...";
|
||||
"git-checkout-index [-u] [-q] [-a] [-f] [-n] [--stage=[123]] [--prefix=<string>] [--] <file>...";
|
||||
|
||||
static struct cache_file cache_file;
|
||||
|
||||
@ -138,11 +155,19 @@ int main(int argc, char **argv)
|
||||
die("cannot open index.lock file.");
|
||||
continue;
|
||||
}
|
||||
if (!memcmp(arg, "--prefix=", 9)) {
|
||||
if (!strncmp(arg, "--prefix=", 9)) {
|
||||
state.base_dir = arg+9;
|
||||
state.base_dir_len = strlen(state.base_dir);
|
||||
continue;
|
||||
}
|
||||
if (!strncmp(arg, "--stage=", 8)) {
|
||||
int ch = arg[8];
|
||||
if ('1' <= ch && ch <= '3')
|
||||
checkout_stage = arg[8] - '0';
|
||||
else
|
||||
die("stage should be between 1 and 3");
|
||||
continue;
|
||||
}
|
||||
if (arg[0] == '-')
|
||||
usage(checkout_cache_usage);
|
||||
break;
|
||||
|
@ -2,7 +2,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include "../cache.h"
|
||||
#include "../git-compat-util.h"
|
||||
|
||||
void *gitfakemmap(void *start, size_t length, int prot , int flags, int fd, off_t offset)
|
||||
{
|
||||
|
@ -16,7 +16,7 @@ int gitsetenv(const char *name, const char *value, int replace)
|
||||
|
||||
namelen = strlen(name);
|
||||
valuelen = strlen(value);
|
||||
envstr = malloc((namelen + valuelen + 2) * sizeof(char));
|
||||
envstr = malloc((namelen + valuelen + 2));
|
||||
if (!envstr) return -1;
|
||||
|
||||
memcpy(envstr, name, namelen);
|
||||
@ -25,7 +25,11 @@ int gitsetenv(const char *name, const char *value, int replace)
|
||||
envstr[namelen + valuelen + 1] = 0;
|
||||
|
||||
out = putenv(envstr);
|
||||
/* putenv(3) makes the argument string part of the environment,
|
||||
* and changing that string modifies the environment --- which
|
||||
* means we do not own that storage anymore. Do not free
|
||||
* envstr.
|
||||
*/
|
||||
|
||||
free(envstr);
|
||||
return out;
|
||||
}
|
||||
|
@ -1,5 +1,4 @@
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include "../git-compat-util.h"
|
||||
|
||||
char *gitstrcasestr(const char *haystack, const char *needle)
|
||||
{
|
||||
|
8
config.c
8
config.c
@ -458,12 +458,6 @@ int git_config_set_multivar(const char* key, const char* value,
|
||||
* If .git/config does not exist yet, write a minimal version.
|
||||
*/
|
||||
if (stat(config_filename, &st)) {
|
||||
static const char contents[] =
|
||||
"#\n"
|
||||
"# This is the config file\n"
|
||||
"#\n"
|
||||
"\n";
|
||||
|
||||
free(store.key);
|
||||
|
||||
/* if nothing to unset, error out */
|
||||
@ -474,8 +468,6 @@ int git_config_set_multivar(const char* key, const char* value,
|
||||
}
|
||||
|
||||
store.key = (char*)key;
|
||||
|
||||
write(fd, contents, sizeof(contents)-1);
|
||||
store_write_section(fd, key);
|
||||
store_write_pair(fd, key, value);
|
||||
} else{
|
||||
|
@ -1,4 +1,5 @@
|
||||
#define _XOPEN_SOURCE /* glibc2 needs this */
|
||||
#define _XOPEN_SOURCE 500 /* glibc2 and AIX 5.3L need this */
|
||||
#define _XOPEN_SOURCE_EXTENDED 1 /* AIX 5.3L needs this */
|
||||
#include <time.h>
|
||||
#include "cache.h"
|
||||
|
||||
|
6
debian/changelog
vendored
6
debian/changelog
vendored
@ -1,3 +1,9 @@
|
||||
git-core (0.99.9m-0) unstable; urgency=low
|
||||
|
||||
* GIT 0.99.9m aka 1.0rc5
|
||||
|
||||
-- Junio C Hamano <junkio@cox.net> Sun, 11 Dec 2005 16:48:06 -0800
|
||||
|
||||
git-core (0.99.9l-0) unstable; urgency=low
|
||||
|
||||
* GIT 0.99.9l aka 1.0rc4
|
||||
|
@ -312,7 +312,7 @@ do
|
||||
echo "--------------------------"
|
||||
cat "$dotest/final-commit"
|
||||
echo "--------------------------"
|
||||
echo -n "Apply? [y]es/[n]o/[e]dit/[v]iew patch/[a]ccept all "
|
||||
printf "Apply? [y]es/[n]o/[e]dit/[v]iew patch/[a]ccept all "
|
||||
read reply
|
||||
case "$reply" in
|
||||
[yY]*) action=yes ;;
|
||||
|
@ -83,7 +83,7 @@ while [ "$interactive" = yes ]; do
|
||||
echo "--------------------------"
|
||||
cat "$final"
|
||||
echo "--------------------------"
|
||||
echo -n "Apply? [y]es/[n]o/[e]dit/[a]ccept all "
|
||||
printf "Apply? [y]es/[n]o/[e]dit/[a]ccept all "
|
||||
read reply
|
||||
case "$reply" in
|
||||
y|Y) interactive=no;;
|
||||
|
@ -25,6 +25,9 @@ See man (1) git-archimport for more details.
|
||||
- audit shell-escaping of filenames
|
||||
- hide our private tags somewhere smarter
|
||||
- find a way to make "cat *patches | patch" safe even when patchfiles are missing newlines
|
||||
- sort and apply patches by graphing ancestry relations instead of just
|
||||
relying in dates supplied in the changeset itself.
|
||||
tla ancestry-graph -m could be helpful here...
|
||||
|
||||
=head1 Devel tricks
|
||||
|
||||
@ -53,15 +56,9 @@ and can contain multiple, unrelated branches.
|
||||
use strict;
|
||||
use warnings;
|
||||
use Getopt::Std;
|
||||
use File::Spec;
|
||||
use File::Temp qw(tempfile tempdir);
|
||||
use File::Path qw(mkpath);
|
||||
use File::Temp qw(tempdir);
|
||||
use File::Path qw(mkpath rmtree);
|
||||
use File::Basename qw(basename dirname);
|
||||
use String::ShellQuote;
|
||||
use Time::Local;
|
||||
use IO::Socket;
|
||||
use IO::Pipe;
|
||||
use POSIX qw(strftime dup2);
|
||||
use Data::Dumper qw/ Dumper /;
|
||||
use IPC::Open2;
|
||||
|
||||
@ -72,124 +69,150 @@ my $git_dir = $ENV{"GIT_DIR"} || ".git";
|
||||
$ENV{"GIT_DIR"} = $git_dir;
|
||||
my $ptag_dir = "$git_dir/archimport/tags";
|
||||
|
||||
our($opt_h,$opt_v, $opt_T,$opt_t,$opt_o);
|
||||
our($opt_h,$opt_f,$opt_v,$opt_T,$opt_t,$opt_D,$opt_a,$opt_o);
|
||||
|
||||
sub usage() {
|
||||
print STDERR <<END;
|
||||
Usage: ${\basename $0} # fetch/update GIT from Arch
|
||||
[ -o ] [ -h ] [ -v ] [ -T ] [ -t tempdir ]
|
||||
[ -f ] [ -o ] [ -h ] [ -v ] [ -T ] [ -a ] [ -D depth ] [ -t tempdir ]
|
||||
repository/arch-branch [ repository/arch-branch] ...
|
||||
END
|
||||
exit(1);
|
||||
}
|
||||
|
||||
getopts("Thvt:") or usage();
|
||||
getopts("fThvat:D:") or usage();
|
||||
usage if $opt_h;
|
||||
|
||||
@ARGV >= 1 or usage();
|
||||
my @arch_roots = @ARGV;
|
||||
# $arch_branches:
|
||||
# values associated with keys:
|
||||
# =1 - Arch version / git 'branch' detected via abrowse on a limit
|
||||
# >1 - Arch version / git 'branch' of an auxilliary branch we've merged
|
||||
my %arch_branches = map { $_ => 1 } @ARGV;
|
||||
|
||||
my ($tmpdir, $tmpdirname) = tempdir('git-archimport-XXXXXX', TMPDIR => 1, CLEANUP => 1);
|
||||
my $tmp = $opt_t || 1;
|
||||
$tmp = tempdir('git-archimport-XXXXXX', TMPDIR => 1, CLEANUP => 1);
|
||||
$ENV{'TMPDIR'} = $opt_t if $opt_t; # $ENV{TMPDIR} will affect tempdir() calls:
|
||||
my $tmp = tempdir('git-archimport-XXXXXX', TMPDIR => 1, CLEANUP => 1);
|
||||
$opt_v && print "+ Using $tmp as temporary directory\n";
|
||||
|
||||
my %reachable = (); # Arch repositories we can access
|
||||
my %unreachable = (); # Arch repositories we can't access :<
|
||||
my @psets = (); # the collection
|
||||
my %psets = (); # the collection, by name
|
||||
my %stats = ( # Track which strategy we used to import:
|
||||
get_tag => 0, replay => 0, get_new => 0, get_delta => 0,
|
||||
simple_changeset => 0, import_or_tag => 0
|
||||
);
|
||||
|
||||
my %rptags = (); # my reverse private tags
|
||||
# to map a SHA1 to a commitid
|
||||
my $TLA = $ENV{'ARCH_CLIENT'} || 'tla';
|
||||
|
||||
foreach my $root (@arch_roots) {
|
||||
my ($arepo, $abranch) = split(m!/!, $root);
|
||||
open ABROWSE, "tla abrowse -f -A $arepo --desc --merges $abranch |"
|
||||
or die "Problems with tla abrowse: $!";
|
||||
|
||||
my %ps = (); # the current one
|
||||
my $mode = '';
|
||||
my $lastseen = '';
|
||||
|
||||
while (<ABROWSE>) {
|
||||
chomp;
|
||||
sub do_abrowse {
|
||||
my $stage = shift;
|
||||
while (my ($limit, $level) = each %arch_branches) {
|
||||
next unless $level == $stage;
|
||||
|
||||
# first record padded w 8 spaces
|
||||
if (s/^\s{8}\b//) {
|
||||
open ABROWSE, "$TLA abrowse -fkD --merges $limit |"
|
||||
or die "Problems with tla abrowse: $!";
|
||||
|
||||
my %ps = (); # the current one
|
||||
my $lastseen = '';
|
||||
|
||||
while (<ABROWSE>) {
|
||||
chomp;
|
||||
|
||||
# store the record we just captured
|
||||
if (%ps) {
|
||||
my %temp = %ps; # break references
|
||||
push (@psets, \%temp);
|
||||
$psets{$temp{id}} = \%temp;
|
||||
%ps = ();
|
||||
}
|
||||
|
||||
my ($id, $type) = split(m/\s{3}/, $_);
|
||||
$ps{id} = $id;
|
||||
$ps{repo} = $arepo;
|
||||
# first record padded w 8 spaces
|
||||
if (s/^\s{8}\b//) {
|
||||
my ($id, $type) = split(m/\s+/, $_, 2);
|
||||
|
||||
# deal with types
|
||||
if ($type =~ m/^\(simple changeset\)/) {
|
||||
$ps{type} = 's';
|
||||
} elsif ($type eq '(initial import)') {
|
||||
$ps{type} = 'i';
|
||||
} elsif ($type =~ m/^\(tag revision of (.+)\)/) {
|
||||
$ps{type} = 't';
|
||||
$ps{tag} = $1;
|
||||
} else {
|
||||
warn "Unknown type $type";
|
||||
}
|
||||
$lastseen = 'id';
|
||||
}
|
||||
|
||||
if (s/^\s{10}//) {
|
||||
# 10 leading spaces or more
|
||||
# indicate commit metadata
|
||||
|
||||
# date & author
|
||||
if ($lastseen eq 'id' && m/^\d{4}-\d{2}-\d{2}/) {
|
||||
|
||||
my ($date, $authoremail) = split(m/\s{2,}/, $_);
|
||||
$ps{date} = $date;
|
||||
$ps{date} =~ s/\bGMT$//; # strip off trailign GMT
|
||||
if ($ps{date} =~ m/\b\w+$/) {
|
||||
warn 'Arch dates not in GMT?! - imported dates will be wrong';
|
||||
my %last_ps;
|
||||
# store the record we just captured
|
||||
if (%ps && !exists $psets{ $ps{id} }) {
|
||||
%last_ps = %ps; # break references
|
||||
push (@psets, \%last_ps);
|
||||
$psets{ $last_ps{id} } = \%last_ps;
|
||||
}
|
||||
|
||||
$authoremail =~ m/^(.+)\s(\S+)$/;
|
||||
$ps{author} = $1;
|
||||
$ps{email} = $2;
|
||||
|
||||
$lastseen = 'date';
|
||||
|
||||
} elsif ($lastseen eq 'date') {
|
||||
# the only hint is position
|
||||
# subject is after date
|
||||
$ps{subj} = $_;
|
||||
$lastseen = 'subj';
|
||||
|
||||
} elsif ($lastseen eq 'subj' && $_ eq 'merges in:') {
|
||||
$ps{merges} = [];
|
||||
$lastseen = 'merges';
|
||||
|
||||
} elsif ($lastseen eq 'merges' && s/^\s{2}//) {
|
||||
push (@{$ps{merges}}, $_);
|
||||
} else {
|
||||
warn 'more metadata after merges!?';
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
my $branch = extract_versionname($id);
|
||||
%ps = ( id => $id, branch => $branch );
|
||||
if (%last_ps && ($last_ps{branch} eq $branch)) {
|
||||
$ps{parent_id} = $last_ps{id};
|
||||
}
|
||||
|
||||
$arch_branches{$branch} = 1;
|
||||
$lastseen = 'id';
|
||||
|
||||
if (%ps) {
|
||||
my %temp = %ps; # break references
|
||||
push (@psets, \%temp);
|
||||
$psets{ $temp{id} } = \%temp;
|
||||
%ps = ();
|
||||
}
|
||||
close ABROWSE;
|
||||
# deal with types (should work with baz or tla):
|
||||
if ($type =~ m/\(.*changeset\)/) {
|
||||
$ps{type} = 's';
|
||||
} elsif ($type =~ /\(.*import\)/) {
|
||||
$ps{type} = 'i';
|
||||
} elsif ($type =~ m/\(tag.*?(\S+\@\S+).*?\)/) {
|
||||
$ps{type} = 't';
|
||||
# read which revision we've tagged when we parse the log
|
||||
$ps{tag} = $1;
|
||||
} else {
|
||||
warn "Unknown type $type";
|
||||
}
|
||||
|
||||
$arch_branches{$branch} = 1;
|
||||
$lastseen = 'id';
|
||||
} elsif (s/^\s{10}//) {
|
||||
# 10 leading spaces or more
|
||||
# indicate commit metadata
|
||||
|
||||
# date
|
||||
if ($lastseen eq 'id' && m/^(\d{4}-\d\d-\d\d \d\d:\d\d:\d\d)/){
|
||||
$ps{date} = $1;
|
||||
$lastseen = 'date';
|
||||
} elsif ($_ eq 'merges in:') {
|
||||
$ps{merges} = [];
|
||||
$lastseen = 'merges';
|
||||
} elsif ($lastseen eq 'merges' && s/^\s{2}//) {
|
||||
my $id = $_;
|
||||
push (@{$ps{merges}}, $id);
|
||||
|
||||
# aggressive branch finding:
|
||||
if ($opt_D) {
|
||||
my $branch = extract_versionname($id);
|
||||
my $repo = extract_reponame($branch);
|
||||
|
||||
if (archive_reachable($repo) &&
|
||||
!defined $arch_branches{$branch}) {
|
||||
$arch_branches{$branch} = $stage + 1;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
warn "more metadata after merges!?: $_\n" unless /^\s*$/;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (%ps && !exists $psets{ $ps{id} }) {
|
||||
my %temp = %ps; # break references
|
||||
if (@psets && $psets[$#psets]{branch} eq $ps{branch}) {
|
||||
$temp{parent_id} = $psets[$#psets]{id};
|
||||
}
|
||||
push (@psets, \%temp);
|
||||
$psets{ $temp{id} } = \%temp;
|
||||
}
|
||||
|
||||
close ABROWSE or die "$TLA abrowse failed on $limit\n";
|
||||
}
|
||||
} # end foreach $root
|
||||
|
||||
do_abrowse(1);
|
||||
my $depth = 2;
|
||||
$opt_D ||= 0;
|
||||
while ($depth <= $opt_D) {
|
||||
do_abrowse($depth);
|
||||
$depth++;
|
||||
}
|
||||
|
||||
## Order patches by time
|
||||
# FIXME see if we can find a more optimal way to do this by graphing
|
||||
# the ancestry data and walking it, that way we won't have to rely on
|
||||
# client-supplied dates
|
||||
@psets = sort {$a->{date}.$b->{id} cmp $b->{date}.$b->{id}} @psets;
|
||||
|
||||
#print Dumper \@psets;
|
||||
@ -210,7 +233,7 @@ unless (-d $git_dir) { # initial import
|
||||
}
|
||||
} else { # progressing an import
|
||||
# load the rptags
|
||||
opendir(DIR, "$git_dir/archimport/tags")
|
||||
opendir(DIR, $ptag_dir)
|
||||
|| die "can't opendir: $!";
|
||||
while (my $file = readdir(DIR)) {
|
||||
# skip non-interesting-files
|
||||
@ -272,29 +295,69 @@ sub old_style_branchname {
|
||||
|
||||
*git_branchname = $opt_o ? *old_style_branchname : *tree_dirname;
|
||||
|
||||
# process patchsets
|
||||
foreach my $ps (@psets) {
|
||||
$ps->{branch} = git_branchname($ps->{id});
|
||||
sub process_patchset_accurate {
|
||||
my $ps = shift;
|
||||
|
||||
# switch to that branch if we're not already in that branch:
|
||||
if (-e "$git_dir/refs/heads/$ps->{branch}") {
|
||||
system('git-checkout','-f',$ps->{branch}) == 0 or die "$! $?\n";
|
||||
|
||||
#
|
||||
# ensure we have a clean state
|
||||
#
|
||||
if (`git diff-files`) {
|
||||
die "Unclean tree when about to process $ps->{id} " .
|
||||
" - did we fail to commit cleanly before?";
|
||||
# remove any old stuff that got leftover:
|
||||
my $rm = safe_pipe_capture('git-ls-files','--others','-z');
|
||||
rmtree(split(/\0/,$rm)) if $rm;
|
||||
}
|
||||
die $! if $?;
|
||||
|
||||
# Apply the import/changeset/merge into the working tree
|
||||
my $dir = sync_to_ps($ps);
|
||||
# read the new log entry:
|
||||
my @commitlog = safe_pipe_capture($TLA,'cat-log','-d',$dir,$ps->{id});
|
||||
die "Error in cat-log: $!" if $?;
|
||||
chomp @commitlog;
|
||||
|
||||
#
|
||||
# skip commits already in repo
|
||||
#
|
||||
if (ptag($ps->{id})) {
|
||||
$opt_v && print " * Skipping already imported: $ps->{id}\n";
|
||||
next;
|
||||
}
|
||||
# grab variables we want from the log, new fields get added to $ps:
|
||||
# (author, date, email, summary, message body ...)
|
||||
parselog($ps, \@commitlog);
|
||||
|
||||
print " * Starting to work on $ps->{id}\n";
|
||||
if ($ps->{id} =~ /--base-0$/ && $ps->{id} ne $psets[0]{id}) {
|
||||
# this should work when importing continuations
|
||||
if ($ps->{tag} && (my $branchpoint = eval { ptag($ps->{tag}) })) {
|
||||
|
||||
# find where we are supposed to branch from
|
||||
system('git-checkout','-f','-b',$ps->{branch},
|
||||
$branchpoint) == 0 or die "$! $?\n";
|
||||
|
||||
# remove any old stuff that got leftover:
|
||||
my $rm = safe_pipe_capture('git-ls-files','--others','-z');
|
||||
rmtree(split(/\0/,$rm)) if $rm;
|
||||
|
||||
# If we trust Arch with the fact that this is just
|
||||
# a tag, and it does not affect the state of the tree
|
||||
# then we just tag and move on
|
||||
tag($ps->{id}, $branchpoint);
|
||||
ptag($ps->{id}, $branchpoint);
|
||||
print " * Tagged $ps->{id} at $branchpoint\n";
|
||||
return 0;
|
||||
} else {
|
||||
warn "Tagging from unknown id unsupported\n" if $ps->{tag};
|
||||
}
|
||||
# allow multiple bases/imports here since Arch supports cherry-picks
|
||||
# from unrelated trees
|
||||
}
|
||||
|
||||
# update the index with all the changes we got
|
||||
system('git-ls-files --others -z | '.
|
||||
'git-update-index --add -z --stdin') == 0 or die "$! $?\n";
|
||||
system('git-ls-files --deleted -z | '.
|
||||
'git-update-index --remove -z --stdin') == 0 or die "$! $?\n";
|
||||
system('git-ls-files -z | '.
|
||||
'git-update-index -z --stdin') == 0 or die "$! $?\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
# the native changeset processing strategy. This is very fast, but
|
||||
# does not handle permissions or any renames involving directories
|
||||
sub process_patchset_fast {
|
||||
my $ps = shift;
|
||||
#
|
||||
# create the branch if needed
|
||||
#
|
||||
@ -305,7 +368,7 @@ foreach my $ps (@psets) {
|
||||
unless ($import) { # skip for import
|
||||
if ( -e "$git_dir/refs/heads/$ps->{branch}") {
|
||||
# we know about this branch
|
||||
`git checkout $ps->{branch}`;
|
||||
system('git-checkout',$ps->{branch});
|
||||
} else {
|
||||
# new branch! we need to verify a few things
|
||||
die "Branch on a non-tag!" unless $ps->{type} eq 't';
|
||||
@ -314,7 +377,7 @@ foreach my $ps (@psets) {
|
||||
unless $branchpoint;
|
||||
|
||||
# find where we are supposed to branch from
|
||||
`git checkout -b $ps->{branch} $branchpoint`;
|
||||
system('git-checkout','-b',$ps->{branch},$branchpoint);
|
||||
|
||||
# If we trust Arch with the fact that this is just
|
||||
# a tag, and it does not affect the state of the tree
|
||||
@ -322,7 +385,7 @@ foreach my $ps (@psets) {
|
||||
tag($ps->{id}, $branchpoint);
|
||||
ptag($ps->{id}, $branchpoint);
|
||||
print " * Tagged $ps->{id} at $branchpoint\n";
|
||||
next;
|
||||
return 0;
|
||||
}
|
||||
die $! if $?;
|
||||
}
|
||||
@ -332,96 +395,128 @@ foreach my $ps (@psets) {
|
||||
#
|
||||
if ($ps->{type} eq 'i' || $ps->{type} eq 't') {
|
||||
apply_import($ps) or die $!;
|
||||
$stats{import_or_tag}++;
|
||||
$import=0;
|
||||
} elsif ($ps->{type} eq 's') {
|
||||
apply_cset($ps);
|
||||
$stats{simple_changeset}++;
|
||||
}
|
||||
|
||||
#
|
||||
# prepare update git's index, based on what arch knows
|
||||
# about the pset, resolve parents, etc
|
||||
#
|
||||
my $tree;
|
||||
|
||||
my $commitlog = `tla cat-archive-log -A $ps->{repo} $ps->{id}`;
|
||||
my @commitlog = safe_pipe_capture($TLA,'cat-archive-log',$ps->{id});
|
||||
die "Error in cat-archive-log: $!" if $?;
|
||||
|
||||
# parselog will git-add/rm files
|
||||
# and generally prepare things for the commit
|
||||
# NOTE: parselog will shell-quote filenames!
|
||||
my ($sum, $msg, $add, $del, $mod, $ren) = parselog($commitlog);
|
||||
my $logmessage = "$sum\n$msg";
|
||||
|
||||
parselog($ps,\@commitlog);
|
||||
|
||||
# imports don't give us good info
|
||||
# on added files. Shame on them
|
||||
if ($ps->{type} eq 'i' || $ps->{type} eq 't') {
|
||||
`find . -type f -print0 | grep -zv '^./$git_dir' | xargs -0 -l100 git-update-index --add`;
|
||||
`git-ls-files --deleted -z | xargs --no-run-if-empty -0 -l100 git-update-index --remove`;
|
||||
if ($ps->{type} eq 'i' || $ps->{type} eq 't') {
|
||||
system('git-ls-files --others -z | '.
|
||||
'git-update-index --add -z --stdin') == 0 or die "$! $?\n";
|
||||
system('git-ls-files --deleted -z | '.
|
||||
'git-update-index --remove -z --stdin') == 0 or die "$! $?\n";
|
||||
}
|
||||
|
||||
if (@$add) {
|
||||
# TODO: handle removed_directories and renamed_directories:
|
||||
|
||||
if (my $add = $ps->{new_files}) {
|
||||
while (@$add) {
|
||||
my @slice = splice(@$add, 0, 100);
|
||||
my $slice = join(' ', @slice);
|
||||
`git-update-index --add $slice`;
|
||||
die "Error in git-update-index --add: $!" if $?;
|
||||
system('git-update-index','--add','--',@slice) == 0 or
|
||||
die "Error in git-update-index --add: $! $?\n";
|
||||
}
|
||||
}
|
||||
if (@$del) {
|
||||
foreach my $file (@$del) {
|
||||
unlink $file or die "Problems deleting $file : $!";
|
||||
}
|
||||
|
||||
if (my $del = $ps->{removed_files}) {
|
||||
unlink @$del;
|
||||
while (@$del) {
|
||||
my @slice = splice(@$del, 0, 100);
|
||||
my $slice = join(' ', @slice);
|
||||
`git-update-index --remove $slice`;
|
||||
die "Error in git-update-index --remove: $!" if $?;
|
||||
system('git-update-index','--remove','--',@slice) == 0 or
|
||||
die "Error in git-update-index --remove: $! $?\n";
|
||||
}
|
||||
}
|
||||
if (@$ren) { # renamed
|
||||
|
||||
if (my $ren = $ps->{renamed_files}) { # renamed
|
||||
if (@$ren % 2) {
|
||||
die "Odd number of entries in rename!?";
|
||||
}
|
||||
;
|
||||
|
||||
while (@$ren) {
|
||||
my $from = pop @$ren;
|
||||
my $to = pop @$ren;
|
||||
my $from = shift @$ren;
|
||||
my $to = shift @$ren;
|
||||
|
||||
unless (-d dirname($to)) {
|
||||
mkpath(dirname($to)); # will die on err
|
||||
}
|
||||
#print "moving $from $to";
|
||||
`mv $from $to`;
|
||||
die "Error renaming $from $to : $!" if $?;
|
||||
`git-update-index --remove $from`;
|
||||
die "Error in git-update-index --remove: $!" if $?;
|
||||
`git-update-index --add $to`;
|
||||
die "Error in git-update-index --add: $!" if $?;
|
||||
# print "moving $from $to";
|
||||
rename($from, $to) or die "Error renaming '$from' '$to': $!\n";
|
||||
system('git-update-index','--remove','--',$from) == 0 or
|
||||
die "Error in git-update-index --remove: $! $?\n";
|
||||
system('git-update-index','--add','--',$to) == 0 or
|
||||
die "Error in git-update-index --add: $! $?\n";
|
||||
}
|
||||
|
||||
}
|
||||
if (@$mod) { # must be _after_ renames
|
||||
|
||||
if (my $mod = $ps->{modified_files}) {
|
||||
while (@$mod) {
|
||||
my @slice = splice(@$mod, 0, 100);
|
||||
my $slice = join(' ', @slice);
|
||||
`git-update-index $slice`;
|
||||
die "Error in git-update-index: $!" if $?;
|
||||
system('git-update-index','--',@slice) == 0 or
|
||||
die "Error in git-update-index: $! $?\n";
|
||||
}
|
||||
}
|
||||
return 1; # we successfully applied the changeset
|
||||
}
|
||||
|
||||
if ($opt_f) {
|
||||
print "Will import patchsets using the fast strategy\n",
|
||||
"Renamed directories and permission changes will be missed\n";
|
||||
*process_patchset = *process_patchset_fast;
|
||||
} else {
|
||||
print "Using the default (accurate) import strategy.\n",
|
||||
"Things may be a bit slow\n";
|
||||
*process_patchset = *process_patchset_accurate;
|
||||
}
|
||||
|
||||
foreach my $ps (@psets) {
|
||||
# process patchsets
|
||||
$ps->{branch} = git_branchname($ps->{id});
|
||||
|
||||
#
|
||||
# ensure we have a clean state
|
||||
#
|
||||
if (my $dirty = `git-diff-files`) {
|
||||
die "Unclean tree when about to process $ps->{id} " .
|
||||
" - did we fail to commit cleanly before?\n$dirty";
|
||||
}
|
||||
die $! if $?;
|
||||
|
||||
#
|
||||
# skip commits already in repo
|
||||
#
|
||||
if (ptag($ps->{id})) {
|
||||
$opt_v && print " * Skipping already imported: $ps->{id}\n";
|
||||
next;
|
||||
}
|
||||
|
||||
print " * Starting to work on $ps->{id}\n";
|
||||
|
||||
process_patchset($ps) or next;
|
||||
|
||||
# warn "errors when running git-update-index! $!";
|
||||
$tree = `git-write-tree`;
|
||||
my $tree = `git-write-tree`;
|
||||
die "cannot write tree $!" if $?;
|
||||
chomp $tree;
|
||||
|
||||
|
||||
#
|
||||
# Who's your daddy?
|
||||
#
|
||||
my @par;
|
||||
if ( -e "$git_dir/refs/heads/$ps->{branch}") {
|
||||
if (open HEAD, "<$git_dir/refs/heads/$ps->{branch}") {
|
||||
if (open HEAD, "<","$git_dir/refs/heads/$ps->{branch}") {
|
||||
my $p = <HEAD>;
|
||||
close HEAD;
|
||||
chomp $p;
|
||||
@ -436,7 +531,6 @@ foreach my $ps (@psets) {
|
||||
if ($ps->{merges}) {
|
||||
push @par, find_parents($ps);
|
||||
}
|
||||
my $par = join (' ', @par);
|
||||
|
||||
#
|
||||
# Commit, tag and clean state
|
||||
@ -449,13 +543,14 @@ foreach my $ps (@psets) {
|
||||
$ENV{GIT_COMMITTER_EMAIL} = $ps->{email};
|
||||
$ENV{GIT_COMMITTER_DATE} = $ps->{date};
|
||||
|
||||
my ($pid, $commit_rh, $commit_wh);
|
||||
$commit_rh = 'commit_rh';
|
||||
$commit_wh = 'commit_wh';
|
||||
|
||||
$pid = open2(*READER, *WRITER, "git-commit-tree $tree $par")
|
||||
my $pid = open2(*READER, *WRITER,'git-commit-tree',$tree,@par)
|
||||
or die $!;
|
||||
print WRITER $logmessage; # write
|
||||
print WRITER $ps->{summary},"\n";
|
||||
print WRITER $ps->{message},"\n";
|
||||
|
||||
# make it easy to backtrack and figure out which Arch revision this was:
|
||||
print WRITER 'git-archimport-id: ',$ps->{id},"\n";
|
||||
|
||||
close WRITER;
|
||||
my $commitid = <READER>; # read
|
||||
chomp $commitid;
|
||||
@ -468,7 +563,7 @@ foreach my $ps (@psets) {
|
||||
#
|
||||
# Update the branch
|
||||
#
|
||||
open HEAD, ">$git_dir/refs/heads/$ps->{branch}";
|
||||
open HEAD, ">","$git_dir/refs/heads/$ps->{branch}";
|
||||
print HEAD $commitid;
|
||||
close HEAD;
|
||||
system('git-update-ref', 'HEAD', "$ps->{branch}");
|
||||
@ -482,21 +577,78 @@ foreach my $ps (@psets) {
|
||||
print " + tree $tree\n";
|
||||
print " + commit $commitid\n";
|
||||
$opt_v && print " + commit date is $ps->{date} \n";
|
||||
$opt_v && print " + parents: $par \n";
|
||||
$opt_v && print " + parents: ",join(' ',@par),"\n";
|
||||
}
|
||||
|
||||
if ($opt_v) {
|
||||
foreach (sort keys %stats) {
|
||||
print" $_: $stats{$_}\n";
|
||||
}
|
||||
}
|
||||
exit 0;
|
||||
|
||||
# used by the accurate strategy:
|
||||
sub sync_to_ps {
|
||||
my $ps = shift;
|
||||
my $tree_dir = $tmp.'/'.tree_dirname($ps->{id});
|
||||
|
||||
$opt_v && print "sync_to_ps($ps->{id}) method: ";
|
||||
|
||||
if (-d $tree_dir) {
|
||||
if ($ps->{type} eq 't') {
|
||||
$opt_v && print "get (tag)\n";
|
||||
# looks like a tag-only or (worse,) a mixed tags/changeset branch,
|
||||
# can't rely on replay to work correctly on these
|
||||
rmtree($tree_dir);
|
||||
safe_pipe_capture($TLA,'get','--no-pristine',$ps->{id},$tree_dir);
|
||||
$stats{get_tag}++;
|
||||
} else {
|
||||
my $tree_id = arch_tree_id($tree_dir);
|
||||
if ($ps->{parent_id} && ($ps->{parent_id} eq $tree_id)) {
|
||||
# the common case (hopefully)
|
||||
$opt_v && print "replay\n";
|
||||
safe_pipe_capture($TLA,'replay','-d',$tree_dir,$ps->{id});
|
||||
$stats{replay}++;
|
||||
} else {
|
||||
# getting one tree is usually faster than getting two trees
|
||||
# and applying the delta ...
|
||||
rmtree($tree_dir);
|
||||
$opt_v && print "apply-delta\n";
|
||||
safe_pipe_capture($TLA,'get','--no-pristine',
|
||||
$ps->{id},$tree_dir);
|
||||
$stats{get_delta}++;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
# new branch work
|
||||
$opt_v && print "get (new tree)\n";
|
||||
safe_pipe_capture($TLA,'get','--no-pristine',$ps->{id},$tree_dir);
|
||||
$stats{get_new}++;
|
||||
}
|
||||
|
||||
# added -I flag to rsync since we're going to fast! AIEEEEE!!!!
|
||||
system('rsync','-aI','--delete','--exclude',$git_dir,
|
||||
# '--exclude','.arch-inventory',
|
||||
'--exclude','.arch-ids','--exclude','{arch}',
|
||||
'--exclude','+*','--exclude',',*',
|
||||
"$tree_dir/",'./') == 0 or die "Cannot rsync $tree_dir: $! $?";
|
||||
return $tree_dir;
|
||||
}
|
||||
|
||||
sub apply_import {
|
||||
my $ps = shift;
|
||||
my $bname = git_branchname($ps->{id});
|
||||
|
||||
`mkdir -p $tmp`;
|
||||
mkpath($tmp);
|
||||
|
||||
`tla get -s --no-pristine -A $ps->{repo} $ps->{id} $tmp/import`;
|
||||
safe_pipe_capture($TLA,'get','-s','--no-pristine',$ps->{id},"$tmp/import");
|
||||
die "Cannot get import: $!" if $?;
|
||||
`rsync -v --archive --delete --exclude '$git_dir' --exclude '.arch-ids' --exclude '{arch}' $tmp/import/* ./`;
|
||||
system('rsync','-aI','--delete', '--exclude',$git_dir,
|
||||
'--exclude','.arch-ids','--exclude','{arch}',
|
||||
"$tmp/import/", './');
|
||||
die "Cannot rsync import:$!" if $?;
|
||||
|
||||
`rm -fr $tmp/import`;
|
||||
rmtree("$tmp/import");
|
||||
die "Cannot remove tempdir: $!" if $?;
|
||||
|
||||
|
||||
@ -506,10 +658,10 @@ sub apply_import {
|
||||
sub apply_cset {
|
||||
my $ps = shift;
|
||||
|
||||
`mkdir -p $tmp`;
|
||||
mkpath($tmp);
|
||||
|
||||
# get the changeset
|
||||
`tla get-changeset -A $ps->{repo} $ps->{id} $tmp/changeset`;
|
||||
safe_pipe_capture($TLA,'get-changeset',$ps->{id},"$tmp/changeset");
|
||||
die "Cannot get changeset: $!" if $?;
|
||||
|
||||
# apply patches
|
||||
@ -533,22 +685,27 @@ sub apply_cset {
|
||||
$orig =~ s/\.modified$//; # lazy
|
||||
$orig =~ s!^\Q$tmp\E/changeset/patches/!!;
|
||||
#print "rsync -p '$mod' '$orig'";
|
||||
`rsync -p $mod ./$orig`;
|
||||
system('rsync','-p',$mod,"./$orig");
|
||||
die "Problem applying binary changes! $!" if $?;
|
||||
}
|
||||
}
|
||||
|
||||
# bring in new files
|
||||
`rsync --archive --exclude '$git_dir' --exclude '.arch-ids' --exclude '{arch}' $tmp/changeset/new-files-archive/* ./`;
|
||||
system('rsync','-aI','--exclude',$git_dir,
|
||||
'--exclude','.arch-ids',
|
||||
'--exclude', '{arch}',
|
||||
"$tmp/changeset/new-files-archive/",'./');
|
||||
|
||||
# deleted files are hinted from the commitlog processing
|
||||
|
||||
`rm -fr $tmp/changeset`;
|
||||
rmtree("$tmp/changeset");
|
||||
}
|
||||
|
||||
|
||||
# =for reference
|
||||
# A log entry looks like
|
||||
# notes: *-files/-directories keys cannot have spaces, they're always
|
||||
# pika-escaped. Everything after the first newline
|
||||
# A log entry looks like:
|
||||
# Revision: moodle-org--moodle--1.3.3--patch-15
|
||||
# Archive: arch-eduforge@catalyst.net.nz--2004
|
||||
# Creator: Penny Leach <penny@catalyst.net.nz>
|
||||
@ -566,70 +723,85 @@ sub apply_cset {
|
||||
# admin/editor.html backup/lib.php backup/restore.php
|
||||
# New-patches: arch-eduforge@catalyst.net.nz--2004/moodle-org--moodle--1.3.3--patch-15
|
||||
# Summary: Updating to latest from MOODLE_14_STABLE (1.4.5+)
|
||||
# summary can be multiline with a leading space just like the above fields
|
||||
# Keywords:
|
||||
#
|
||||
# Updating yadda tadda tadda madda
|
||||
sub parselog {
|
||||
my $log = shift;
|
||||
#print $log;
|
||||
my ($ps, $log) = @_;
|
||||
my $key = undef;
|
||||
|
||||
my (@add, @del, @mod, @ren, @kw, $sum, $msg );
|
||||
|
||||
if ($log =~ m/(?:\n|^)New-files:(.*?)(?=\n\w)/s ) {
|
||||
my $files = $1;
|
||||
@add = split(m/\s+/s, $files);
|
||||
}
|
||||
|
||||
if ($log =~ m/(?:\n|^)Removed-files:(.*?)(?=\n\w)/s ) {
|
||||
my $files = $1;
|
||||
@del = split(m/\s+/s, $files);
|
||||
}
|
||||
# headers we want that contain filenames:
|
||||
my %want_headers = (
|
||||
new_files => 1,
|
||||
modified_files => 1,
|
||||
renamed_files => 1,
|
||||
renamed_directories => 1,
|
||||
removed_files => 1,
|
||||
removed_directories => 1,
|
||||
);
|
||||
|
||||
if ($log =~ m/(?:\n|^)Modified-files:(.*?)(?=\n\w)/s ) {
|
||||
my $files = $1;
|
||||
@mod = split(m/\s+/s, $files);
|
||||
chomp (@$log);
|
||||
while ($_ = shift @$log) {
|
||||
if (/^Continuation-of:\s*(.*)/) {
|
||||
$ps->{tag} = $1;
|
||||
$key = undef;
|
||||
} elsif (/^Summary:\s*(.*)$/ ) {
|
||||
# summary can be multiline as long as it has a leading space
|
||||
$ps->{summary} = [ $1 ];
|
||||
$key = 'summary';
|
||||
} elsif (/^Creator: (.*)\s*<([^\>]+)>/) {
|
||||
$ps->{author} = $1;
|
||||
$ps->{email} = $2;
|
||||
$key = undef;
|
||||
# any *-files or *-directories can be read here:
|
||||
} elsif (/^([A-Z][a-z\-]+):\s*(.*)$/) {
|
||||
my $val = $2;
|
||||
$key = lc $1;
|
||||
$key =~ tr/-/_/; # too lazy to quote :P
|
||||
if ($want_headers{$key}) {
|
||||
push @{$ps->{$key}}, split(/\s+/, $val);
|
||||
} else {
|
||||
$key = undef;
|
||||
}
|
||||
} elsif (/^$/) {
|
||||
last; # remainder of @$log that didn't get shifted off is message
|
||||
} elsif ($key) {
|
||||
if (/^\s+(.*)$/) {
|
||||
if ($key eq 'summary') {
|
||||
push @{$ps->{$key}}, $1;
|
||||
} else { # files/directories:
|
||||
push @{$ps->{$key}}, split(/\s+/, $1);
|
||||
}
|
||||
} else {
|
||||
$key = undef;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# post-processing:
|
||||
$ps->{summary} = join("\n",@{$ps->{summary}})."\n";
|
||||
$ps->{message} = join("\n",@$log);
|
||||
|
||||
if ($log =~ m/(?:\n|^)Renamed-files:(.*?)(?=\n\w)/s ) {
|
||||
my $files = $1;
|
||||
@ren = split(m/\s+/s, $files);
|
||||
}
|
||||
|
||||
$sum ='';
|
||||
if ($log =~ m/^Summary:(.+?)$/m ) {
|
||||
$sum = $1;
|
||||
$sum =~ s/^\s+//;
|
||||
$sum =~ s/\s+$//;
|
||||
}
|
||||
|
||||
$msg = '';
|
||||
if ($log =~ m/\n\n(.+)$/s) {
|
||||
$msg = $1;
|
||||
$msg =~ s/^\s+//;
|
||||
$msg =~ s/\s+$//;
|
||||
}
|
||||
|
||||
|
||||
# cleanup the arrays
|
||||
foreach my $ref ( (\@add, \@del, \@mod, \@ren) ) {
|
||||
# skip Arch control files, unescape pika-escaped files
|
||||
foreach my $k (keys %want_headers) {
|
||||
next unless (defined $ps->{$k});
|
||||
my @tmp = ();
|
||||
while (my $t = pop @$ref) {
|
||||
next unless length ($t);
|
||||
next if $t =~ m!\{arch\}/!;
|
||||
next if $t =~ m!\.arch-ids/!;
|
||||
next if $t =~ m!\.arch-inventory$!;
|
||||
foreach my $t (@{$ps->{$k}}) {
|
||||
next unless length ($t);
|
||||
next if $t =~ m!\{arch\}/!;
|
||||
next if $t =~ m!\.arch-ids/!;
|
||||
# should we skip this?
|
||||
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'`;
|
||||
if ($t =~ /\\/ ){
|
||||
$t = (safe_pipe_capture($TLA,'escape','--unescaped',$t))[0];
|
||||
}
|
||||
push (@tmp, shell_quote($t));
|
||||
push @tmp, $t;
|
||||
}
|
||||
@$ref = @tmp;
|
||||
$ps->{$k} = \@tmp;
|
||||
}
|
||||
|
||||
#print Dumper [$sum, $msg, \@add, \@del, \@mod, \@ren];
|
||||
return ($sum, $msg, \@add, \@del, \@mod, \@ren);
|
||||
}
|
||||
|
||||
# write/read a tag
|
||||
@ -826,8 +998,11 @@ sub find_parents {
|
||||
}
|
||||
}
|
||||
}
|
||||
@parents = keys %parents;
|
||||
@parents = map { " -p " . ptag($_) } @parents;
|
||||
|
||||
@parents = ();
|
||||
foreach (keys %parents) {
|
||||
push @parents, '-p', ptag($_);
|
||||
}
|
||||
return @parents;
|
||||
}
|
||||
|
||||
@ -850,3 +1025,45 @@ sub commitid2pset {
|
||||
|| (print Dumper(sort keys %psets)) && die "Cannot find patchset for $name";
|
||||
return $ps;
|
||||
}
|
||||
|
||||
|
||||
# an alterative to `command` that allows input to be passed as an array
|
||||
# to work around shell problems with weird characters in arguments
|
||||
sub safe_pipe_capture {
|
||||
my @output;
|
||||
if (my $pid = open my $child, '-|') {
|
||||
@output = (<$child>);
|
||||
close $child or die join(' ',@_).": $! $?";
|
||||
} else {
|
||||
exec(@_) or die "$! $?"; # exec() can fail the executable can't be found
|
||||
}
|
||||
return wantarray ? @output : join('',@output);
|
||||
}
|
||||
|
||||
# `tla logs -rf -d <dir> | head -n1` or `baz tree-id <dir>`
|
||||
sub arch_tree_id {
|
||||
my $dir = shift;
|
||||
chomp( my $ret = (safe_pipe_capture($TLA,'logs','-rf','-d',$dir))[0] );
|
||||
return $ret;
|
||||
}
|
||||
|
||||
sub archive_reachable {
|
||||
my $archive = shift;
|
||||
return 1 if $reachable{$archive};
|
||||
return 0 if $unreachable{$archive};
|
||||
|
||||
if (system "$TLA whereis-archive $archive >/dev/null") {
|
||||
if ($opt_a && (system($TLA,'register-archive',
|
||||
"http://mirrors.sourcecontrol.net/$archive") == 0)) {
|
||||
$reachable{$archive} = 1;
|
||||
return 1;
|
||||
}
|
||||
print STDERR "Archive is unreachable: $archive\n";
|
||||
$unreachable{$archive} = 1;
|
||||
return 0;
|
||||
} else {
|
||||
$reachable{$archive} = 1;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -67,7 +67,7 @@ bisect_start() {
|
||||
rm -rf "$GIT_DIR/refs/bisect/"
|
||||
mkdir "$GIT_DIR/refs/bisect"
|
||||
{
|
||||
echo -n "git-bisect start"
|
||||
printf "git-bisect start"
|
||||
sq "$@"
|
||||
} >"$GIT_DIR/BISECT_LOG"
|
||||
sq "$@" >"$GIT_DIR/BISECT_NAMES"
|
||||
|
113
git-compat-util.h
Normal file
113
git-compat-util.h
Normal file
@ -0,0 +1,113 @@
|
||||
#ifndef GIT_COMPAT_UTIL_H
|
||||
#define GIT_COMPAT_UTIL_H
|
||||
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <sys/param.h>
|
||||
#include <netinet/in.h>
|
||||
#include <sys/types.h>
|
||||
#include <dirent.h>
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define NORETURN __attribute__((__noreturn__))
|
||||
#else
|
||||
#define NORETURN
|
||||
#ifndef __attribute__
|
||||
#define __attribute__(x)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* General helper functions */
|
||||
extern void usage(const char *err) NORETURN;
|
||||
extern void die(const char *err, ...) NORETURN __attribute__((format (printf, 1, 2)));
|
||||
extern int error(const char *err, ...) __attribute__((format (printf, 1, 2)));
|
||||
|
||||
#ifdef NO_MMAP
|
||||
|
||||
#ifndef PROT_READ
|
||||
#define PROT_READ 1
|
||||
#define PROT_WRITE 2
|
||||
#define MAP_PRIVATE 1
|
||||
#define MAP_FAILED ((void*)-1)
|
||||
#endif
|
||||
|
||||
#define mmap gitfakemmap
|
||||
#define munmap gitfakemunmap
|
||||
extern void *gitfakemmap(void *start, size_t length, int prot , int flags, int fd, off_t offset);
|
||||
extern int gitfakemunmap(void *start, size_t length);
|
||||
|
||||
#else /* NO_MMAP */
|
||||
|
||||
#include <sys/mman.h>
|
||||
|
||||
#endif /* NO_MMAP */
|
||||
|
||||
#ifdef NO_SETENV
|
||||
#define setenv gitsetenv
|
||||
extern int gitsetenv(const char *, const char *, int);
|
||||
#endif
|
||||
|
||||
#ifdef NO_STRCASESTR
|
||||
#define strcasestr gitstrcasestr
|
||||
extern char *gitstrcasestr(const char *haystack, const char *needle);
|
||||
#endif
|
||||
|
||||
static inline void *xmalloc(size_t size)
|
||||
{
|
||||
void *ret = malloc(size);
|
||||
if (!ret)
|
||||
die("Out of memory, malloc failed");
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline void *xrealloc(void *ptr, size_t size)
|
||||
{
|
||||
void *ret = realloc(ptr, size);
|
||||
if (!ret)
|
||||
die("Out of memory, realloc failed");
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline void *xcalloc(size_t nmemb, size_t size)
|
||||
{
|
||||
void *ret = calloc(nmemb, size);
|
||||
if (!ret)
|
||||
die("Out of memory, calloc failed");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Sane ctype - no locale, and works with signed chars */
|
||||
#undef isspace
|
||||
#undef isdigit
|
||||
#undef isalpha
|
||||
#undef isalnum
|
||||
#undef tolower
|
||||
#undef toupper
|
||||
extern unsigned char sane_ctype[256];
|
||||
#define GIT_SPACE 0x01
|
||||
#define GIT_DIGIT 0x02
|
||||
#define GIT_ALPHA 0x04
|
||||
#define sane_istest(x,mask) ((sane_ctype[(unsigned char)(x)] & (mask)) != 0)
|
||||
#define isspace(x) sane_istest(x,GIT_SPACE)
|
||||
#define isdigit(x) sane_istest(x,GIT_DIGIT)
|
||||
#define isalpha(x) sane_istest(x,GIT_ALPHA)
|
||||
#define isalnum(x) sane_istest(x,GIT_ALPHA | GIT_DIGIT)
|
||||
#define tolower(x) sane_case((unsigned char)(x), 0x20)
|
||||
#define toupper(x) sane_case((unsigned char)(x), 0)
|
||||
|
||||
static inline int sane_case(int x, int high)
|
||||
{
|
||||
if (sane_istest(x, GIT_ALPHA))
|
||||
x = (x & ~0x20) | high;
|
||||
return x;
|
||||
}
|
||||
|
||||
#endif
|
@ -254,6 +254,15 @@ Date: '"$ad"
|
||||
}
|
||||
|
||||
total=`wc -l <$series | tr -dc "[0-9]"`
|
||||
case "$total,$numbered" in
|
||||
1,*)
|
||||
numfmt='' ;;
|
||||
*,t)
|
||||
numfmt=`echo "$total" | wc -c`
|
||||
numfmt=$(($numfmt-1))
|
||||
numfmt=" %0${numfmt}d/$total"
|
||||
esac
|
||||
|
||||
i=1
|
||||
while read commit
|
||||
do
|
||||
@ -262,10 +271,7 @@ do
|
||||
case "$numbered" in
|
||||
'') num= ;;
|
||||
*)
|
||||
case $total in
|
||||
1) num= ;;
|
||||
*) num=' '`printf "%d/%d" $i $total` ;;
|
||||
esac
|
||||
num=`printf "$numfmt" $i` ;;
|
||||
esac
|
||||
|
||||
file=`printf '%04d-%stxt' $i "$title"`
|
||||
|
@ -87,15 +87,16 @@ case "${1:-.}${2:-.}${3:-.}" in
|
||||
;;
|
||||
esac
|
||||
|
||||
# Create the working tree file, with the correct permission bits.
|
||||
# we can not rely on the fact that our tree has the path, because
|
||||
# we allow the merge to be done in an unchecked-out working tree.
|
||||
rm -f "$4" &&
|
||||
git-cat-file blob "$2" >"$4" &&
|
||||
case "$6" in *7??) chmod +x "$4" ;; esac &&
|
||||
merge "$4" "$orig" "$src2"
|
||||
# Be careful for funny filename such as "-L" in "$4", which
|
||||
# would confuse "merge" greatly.
|
||||
src1=`git-unpack-file $2`
|
||||
merge "$src1" "$orig" "$src2"
|
||||
ret=$?
|
||||
rm -f -- "$orig" "$src2"
|
||||
|
||||
# Create the working tree file, using "our tree" version from the
|
||||
# index, and then store the result of the merge.
|
||||
git-checkout-index -f --stage=2 -- "$4" && cat "$src1" >"$4"
|
||||
rm -f -- "$orig" "$src1" "$src2"
|
||||
|
||||
if [ "$6" != "$7" ]; then
|
||||
echo "ERROR: Permissions conflict: $5->$6,$7."
|
||||
|
@ -280,6 +280,16 @@ def updateFileExt(sha, mode, path, updateCache, updateWd):
|
||||
runProgram(['git-update-index', '--add', '--cacheinfo',
|
||||
'0%o' % mode, sha, path])
|
||||
|
||||
def setIndexStages(path,
|
||||
oSHA1, oMode,
|
||||
aSHA1, aMode,
|
||||
bSHA1, bMode):
|
||||
runProgram(['git-update-index', '-z', '--index-info'],
|
||||
input="0 " + ("0" * 40) + "\t" + path + "\0" + \
|
||||
"%o %s %d\t%s\0" % (oMode, oSHA1, 1, path) + \
|
||||
"%o %s %d\t%s\0" % (aMode, aSHA1, 2, path) + \
|
||||
"%o %s %d\t%s\0" % (bMode, bSHA1, 3, path))
|
||||
|
||||
def removeFile(clean, path):
|
||||
updateCache = cacheOnly or clean
|
||||
updateWd = not cacheOnly
|
||||
@ -590,6 +600,8 @@ def processRenames(renamesA, renamesB, branchNameA, branchNameB):
|
||||
else:
|
||||
dstName2 = ren1.dstName
|
||||
|
||||
# NEEDSWORK: place dstNameA at stage 2 and dstNameB at stage 3
|
||||
# What about other stages???
|
||||
updateFile(False, ren1.dstSha, ren1.dstMode, dstName1)
|
||||
updateFile(False, ren2.dstSha, ren2.dstMode, dstName2)
|
||||
else:
|
||||
@ -611,8 +623,11 @@ def processRenames(renamesA, renamesB, branchNameA, branchNameB):
|
||||
cleanMerge = False
|
||||
|
||||
if not cacheOnly:
|
||||
updateFileExt(ren1.dstSha, ren1.dstMode, ren1.dstName,
|
||||
updateCache=True, updateWd=False)
|
||||
setIndexStages(ren1.dstName,
|
||||
ren1.srcSha, ren1.srcMode,
|
||||
ren1.dstSha, ren1.dstMode,
|
||||
ren2.dstSha, ren2.dstMode)
|
||||
|
||||
updateFile(clean, resSha, resMode, ren1.dstName)
|
||||
else:
|
||||
# Renamed in 1, maybe changed in 2
|
||||
@ -672,11 +687,24 @@ def processRenames(renamesA, renamesB, branchNameA, branchNameB):
|
||||
tryMerge = True
|
||||
|
||||
if tryMerge:
|
||||
|
||||
oName, oSHA1, oMode = ren1.srcName, ren1.srcSha, ren1.srcMode
|
||||
aName, bName = ren1.dstName, ren1.srcName
|
||||
aSHA1, bSHA1 = ren1.dstSha, srcShaOtherBranch
|
||||
aMode, bMode = ren1.dstMode, srcModeOtherBranch
|
||||
aBranch, bBranch = branchName1, branchName2
|
||||
|
||||
if renamesA != renames1:
|
||||
aName, bName = bName, aName
|
||||
aSHA1, bSHA1 = bSHA1, aSHA1
|
||||
aMode, bMode = bMode, aMode
|
||||
aBranch, bBranch = bBranch, aBranch
|
||||
|
||||
[resSha, resMode, clean, merge] = \
|
||||
mergeFile(ren1.srcName, ren1.srcSha, ren1.srcMode,
|
||||
ren1.dstName, ren1.dstSha, ren1.dstMode,
|
||||
ren1.srcName, srcShaOtherBranch, srcModeOtherBranch,
|
||||
branchName1, branchName2)
|
||||
mergeFile(oName, oSHA1, oMode,
|
||||
aName, aSHA1, aMode,
|
||||
bName, bSHA1, bMode,
|
||||
aBranch, bBranch);
|
||||
|
||||
if merge or not clean:
|
||||
output('Renaming', fmtRename(ren1.srcName, ren1.dstName))
|
||||
@ -690,8 +718,11 @@ def processRenames(renamesA, renamesB, branchNameA, branchNameB):
|
||||
cleanMerge = False
|
||||
|
||||
if not cacheOnly:
|
||||
updateFileExt(ren1.dstSha, ren1.dstMode, ren1.dstName,
|
||||
updateCache=True, updateWd=False)
|
||||
setIndexStages(ren1.dstName,
|
||||
oSHA1, oMode,
|
||||
aSHA1, aMode,
|
||||
bSHA1, bMode)
|
||||
|
||||
updateFile(clean, resSha, resMode, ren1.dstName)
|
||||
|
||||
return cleanMerge
|
||||
|
@ -62,7 +62,7 @@ my $safesrc;
|
||||
my (%overwritten, %srcForDst);
|
||||
|
||||
$/ = "\0";
|
||||
open(F,"-|","git-ls-files","-z")
|
||||
open(F, 'git-ls-files -z |')
|
||||
or die "Failed to open pipe from git-ls-files: " . $!;
|
||||
|
||||
@allfiles = map { chomp; $_; } <F>;
|
||||
|
@ -16,7 +16,11 @@ do
|
||||
done
|
||||
|
||||
sync
|
||||
git-fsck-objects --full --cache --unreachable "$@" |
|
||||
case "$#" in
|
||||
0) git-fsck-objects --full --cache --unreachable ;;
|
||||
*) git-fsck-objects --full --cache --unreachable $(git-rev-parse --all) "$@" ;;
|
||||
esac |
|
||||
|
||||
sed -ne '/unreachable /{
|
||||
s/unreachable [^ ][^ ]* //
|
||||
s|\(..\)|\1/|p
|
||||
|
@ -19,10 +19,10 @@ esac
|
||||
usage () {
|
||||
case "$me" in
|
||||
cherry-pick)
|
||||
die "usage git $me [-n] [-r] <commit-ish>"
|
||||
die "usage git $me [--edit] [-n] [-r] <commit-ish>"
|
||||
;;
|
||||
revert)
|
||||
die "usage git $me [-n] <commit-ish>"
|
||||
die "usage git $me [--edit | --no-edit] [-n] <commit-ish>"
|
||||
;;
|
||||
esac
|
||||
}
|
||||
@ -38,7 +38,7 @@ do
|
||||
-e|--e|--ed|--edi|--edit)
|
||||
edit=-e
|
||||
;;
|
||||
-n|--n|--no|--no-|--no-e|--no-ed|--no-edi|--no-edit)
|
||||
--n|--no|--no-|--no-e|--no-ed|--no-edi|--no-edit)
|
||||
edit=
|
||||
;;
|
||||
-r|--r|--re|--rep|--repl|--repla|--replay)
|
||||
|
@ -13,7 +13,7 @@ report () {
|
||||
trailer=""
|
||||
while read status name newname
|
||||
do
|
||||
echo -n "$header"
|
||||
printf '%s' "$header"
|
||||
header=""
|
||||
trailer="#
|
||||
"
|
||||
@ -27,7 +27,7 @@ report () {
|
||||
U ) echo "# unmerged: $name";;
|
||||
esac
|
||||
done
|
||||
echo -n "$trailer"
|
||||
printf '%s' "$trailer"
|
||||
[ "$header" ]
|
||||
}
|
||||
|
||||
|
18
git.c
18
git.c
@ -8,15 +8,12 @@
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <stdarg.h>
|
||||
#include "git-compat-util.h"
|
||||
|
||||
#ifndef PATH_MAX
|
||||
# define PATH_MAX 4096
|
||||
#endif
|
||||
|
||||
#ifdef NO_SETENV
|
||||
extern int gitsetenv(char *name, char *value, int overwrite);
|
||||
#endif
|
||||
|
||||
static const char git_usage[] =
|
||||
"Usage: git [--version] [--exec-path[=GIT_EXEC_PATH]] [--help] COMMAND [ ARGS ]";
|
||||
|
||||
@ -156,10 +153,10 @@ static void list_commands(const char *exec_path, const char *pattern)
|
||||
}
|
||||
|
||||
#ifdef __GNUC__
|
||||
static void usage(const char *exec_path, const char *fmt, ...)
|
||||
static void cmd_usage(const char *exec_path, const char *fmt, ...)
|
||||
__attribute__((__format__(__printf__, 2, 3), __noreturn__));
|
||||
#endif
|
||||
static void usage(const char *exec_path, const char *fmt, ...)
|
||||
static void cmd_usage(const char *exec_path, const char *fmt, ...)
|
||||
{
|
||||
if (fmt) {
|
||||
va_list ap;
|
||||
@ -192,7 +189,6 @@ static void prepend_to_path(const char *dir, int len)
|
||||
path_len = len + strlen(old_path) + 1;
|
||||
|
||||
path = malloc(path_len + 1);
|
||||
path[path_len + 1] = '\0';
|
||||
|
||||
memcpy(path, dir, len);
|
||||
path[len] = ':';
|
||||
@ -255,12 +251,12 @@ int main(int argc, char **argv, char **envp)
|
||||
else if (!strcmp(arg, "help"))
|
||||
show_help = 1;
|
||||
else if (!show_help)
|
||||
usage(NULL, NULL);
|
||||
cmd_usage(NULL, NULL);
|
||||
}
|
||||
|
||||
if (i >= argc || show_help) {
|
||||
if (i >= argc)
|
||||
usage(exec_path, NULL);
|
||||
cmd_usage(exec_path, NULL);
|
||||
|
||||
show_man_page(argv[i]);
|
||||
}
|
||||
@ -290,7 +286,7 @@ int main(int argc, char **argv, char **envp)
|
||||
len += snprintf(git_command + len, sizeof(git_command) - len,
|
||||
"/git-%s", argv[i]);
|
||||
if (sizeof(git_command) <= len) {
|
||||
fprintf(stderr, "git: command name given is too long (%d)\n", len);
|
||||
fprintf(stderr, "git: command name given is too long.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
@ -298,7 +294,7 @@ int main(int argc, char **argv, char **envp)
|
||||
execve(git_command, &argv[i], envp);
|
||||
|
||||
if (errno == ENOENT)
|
||||
usage(exec_path, "'%s' is not a git-command", argv[i]);
|
||||
cmd_usage(exec_path, "'%s' is not a git-command", argv[i]);
|
||||
|
||||
fprintf(stderr, "Failed to run command '%s': %s\n",
|
||||
git_command, strerror(errno));
|
||||
|
538
gitk
538
gitk
@ -16,22 +16,9 @@ proc gitdir {} {
|
||||
}
|
||||
}
|
||||
|
||||
proc getcommits {rargs} {
|
||||
global commits commfd phase canv mainfont env
|
||||
global startmsecs nextupdate ncmupdate
|
||||
global ctext maincursor textcursor leftover gitencoding
|
||||
proc parse_args {rargs} {
|
||||
global parsed_args
|
||||
|
||||
# check that we can find a .git directory somewhere...
|
||||
set gitdir [gitdir]
|
||||
if {![file isdirectory $gitdir]} {
|
||||
error_popup "Cannot find the git directory \"$gitdir\"."
|
||||
exit 1
|
||||
}
|
||||
set commits {}
|
||||
set phase getcommits
|
||||
set startmsecs [clock clicks -milliseconds]
|
||||
set nextupdate [expr {$startmsecs + 100}]
|
||||
set ncmupdate 1
|
||||
if [catch {
|
||||
set parse_args [concat --default HEAD $rargs]
|
||||
set parsed_args [split [eval exec git-rev-parse $parse_args] "\n"]
|
||||
@ -42,26 +29,56 @@ proc getcommits {rargs} {
|
||||
}
|
||||
set parsed_args $rargs
|
||||
}
|
||||
return $parsed_args
|
||||
}
|
||||
|
||||
proc start_rev_list {rlargs} {
|
||||
global startmsecs nextupdate ncmupdate
|
||||
global commfd leftover tclencoding
|
||||
|
||||
set startmsecs [clock clicks -milliseconds]
|
||||
set nextupdate [expr {$startmsecs + 100}]
|
||||
set ncmupdate 1
|
||||
if [catch {
|
||||
set commfd [open "|git-rev-list --header --topo-order --parents $parsed_args" r]
|
||||
set commfd [open [concat | git-rev-list --header --topo-order \
|
||||
--parents $rlargs] r]
|
||||
} err] {
|
||||
puts stderr "Error executing git-rev-list: $err"
|
||||
exit 1
|
||||
}
|
||||
set leftover {}
|
||||
fconfigure $commfd -blocking 0 -translation lf -encoding $gitencoding
|
||||
fconfigure $commfd -blocking 0 -translation lf
|
||||
if {$tclencoding != {}} {
|
||||
fconfigure $commfd -encoding $tclencoding
|
||||
}
|
||||
fileevent $commfd readable [list getcommitlines $commfd]
|
||||
$canv delete all
|
||||
$canv create text 3 3 -anchor nw -text "Reading commits..." \
|
||||
-font $mainfont -tags textitems
|
||||
. config -cursor watch
|
||||
settextcursor watch
|
||||
}
|
||||
|
||||
proc getcommits {rargs} {
|
||||
global oldcommits commits phase canv mainfont env
|
||||
|
||||
# check that we can find a .git directory somewhere...
|
||||
set gitdir [gitdir]
|
||||
if {![file isdirectory $gitdir]} {
|
||||
error_popup "Cannot find the git directory \"$gitdir\"."
|
||||
exit 1
|
||||
}
|
||||
set oldcommits {}
|
||||
set commits {}
|
||||
set phase getcommits
|
||||
start_rev_list [parse_args $rargs]
|
||||
$canv delete all
|
||||
$canv create text 3 3 -anchor nw -text "Reading commits..." \
|
||||
-font $mainfont -tags textitems
|
||||
}
|
||||
|
||||
proc getcommitlines {commfd} {
|
||||
global commits parents cdate children
|
||||
global oldcommits commits parents cdate children nchildren
|
||||
global commitlisted phase nextupdate
|
||||
global stopped redisplaying leftover
|
||||
global canv
|
||||
|
||||
set stuff [read $commfd]
|
||||
if {$stuff == {}} {
|
||||
@ -122,7 +139,7 @@ proc getcommitlines {commfd} {
|
||||
lappend commits $id
|
||||
set commitlisted($id) 1
|
||||
parsecommit $id $cmit 1 [lrange $ids 1 end]
|
||||
drawcommit $id
|
||||
drawcommit $id 1
|
||||
if {[clock clicks -milliseconds] >= $nextupdate} {
|
||||
doupdate 1
|
||||
}
|
||||
@ -132,7 +149,7 @@ proc getcommitlines {commfd} {
|
||||
set stopped 0
|
||||
set phase "getcommits"
|
||||
foreach id $commits {
|
||||
drawcommit $id
|
||||
drawcommit $id 1
|
||||
if {$stopped} break
|
||||
if {[clock clicks -milliseconds] >= $nextupdate} {
|
||||
doupdate 1
|
||||
@ -168,16 +185,99 @@ proc readcommit {id} {
|
||||
parsecommit $id $contents 0 {}
|
||||
}
|
||||
|
||||
proc parsecommit {id contents listed olds} {
|
||||
global commitinfo children nchildren parents nparents cdate ncleft
|
||||
proc updatecommits {rargs} {
|
||||
global commitlisted commfd phase
|
||||
global startmsecs nextupdate ncmupdate
|
||||
global idtags idheads idotherrefs
|
||||
global leftover
|
||||
global parsed_args
|
||||
global canv mainfont
|
||||
global oldcommits commits
|
||||
global parents nchildren children ncleft
|
||||
|
||||
set old_args $parsed_args
|
||||
parse_args $rargs
|
||||
|
||||
if {$phase == "getcommits" || $phase == "incrdraw"} {
|
||||
# havent read all the old commits, just start again from scratch
|
||||
stopfindproc
|
||||
set oldcommits {}
|
||||
set commits {}
|
||||
foreach v {children nchildren parents commitlisted commitinfo
|
||||
selectedline matchinglines treediffs
|
||||
mergefilelist currentid rowtextx} {
|
||||
global $v
|
||||
catch {unset $v}
|
||||
}
|
||||
readrefs
|
||||
if {$phase == "incrdraw"} {
|
||||
allcanvs delete all
|
||||
$canv create text 3 3 -anchor nw -text "Reading commits..." \
|
||||
-font $mainfont -tags textitems
|
||||
set phase getcommits
|
||||
}
|
||||
start_rev_list $parsed_args
|
||||
return
|
||||
}
|
||||
|
||||
foreach id $old_args {
|
||||
if {![regexp {^[0-9a-f]{40}$} $id]} continue
|
||||
if {[info exists oldref($id)]} continue
|
||||
set oldref($id) $id
|
||||
lappend ignoreold "^$id"
|
||||
}
|
||||
foreach id $parsed_args {
|
||||
if {![regexp {^[0-9a-f]{40}$} $id]} continue
|
||||
if {[info exists ref($id)]} continue
|
||||
set ref($id) $id
|
||||
lappend ignorenew "^$id"
|
||||
}
|
||||
|
||||
foreach a $old_args {
|
||||
if {![info exists ref($a)]} {
|
||||
lappend ignorenew $a
|
||||
}
|
||||
}
|
||||
|
||||
set phase updatecommits
|
||||
set oldcommits $commits
|
||||
set commits {}
|
||||
set removed_commits [split [eval exec git-rev-list $ignorenew] "\n" ]
|
||||
if {[llength $removed_commits] > 0} {
|
||||
allcanvs delete all
|
||||
foreach c $removed_commits {
|
||||
set i [lsearch -exact $oldcommits $c]
|
||||
if {$i >= 0} {
|
||||
set oldcommits [lreplace $oldcommits $i $i]
|
||||
unset commitlisted($c)
|
||||
foreach p $parents($c) {
|
||||
if {[info exists nchildren($p)]} {
|
||||
set j [lsearch -exact $children($p) $c]
|
||||
if {$j >= 0} {
|
||||
set children($p) [lreplace $children($p) $j $j]
|
||||
incr nchildren($p) -1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
set phase removecommits
|
||||
}
|
||||
|
||||
set args {}
|
||||
foreach a $parsed_args {
|
||||
if {![info exists oldref($a)]} {
|
||||
lappend args $a
|
||||
}
|
||||
}
|
||||
|
||||
readrefs
|
||||
start_rev_list [concat $ignoreold $args]
|
||||
}
|
||||
|
||||
proc updatechildren {id olds} {
|
||||
global children nchildren parents nparents ncleft
|
||||
|
||||
set inhdr 1
|
||||
set comment {}
|
||||
set headline {}
|
||||
set auname {}
|
||||
set audate {}
|
||||
set comname {}
|
||||
set comdate {}
|
||||
if {![info exists nchildren($id)]} {
|
||||
set children($id) {}
|
||||
set nchildren($id) 0
|
||||
@ -196,6 +296,19 @@ proc parsecommit {id contents listed olds} {
|
||||
incr ncleft($p)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
proc parsecommit {id contents listed olds} {
|
||||
global commitinfo cdate
|
||||
|
||||
set inhdr 1
|
||||
set comment {}
|
||||
set headline {}
|
||||
set auname {}
|
||||
set audate {}
|
||||
set comname {}
|
||||
set comdate {}
|
||||
updatechildren $id $olds
|
||||
set hdrend [string first "\n\n" $contents]
|
||||
if {$hdrend < 0} {
|
||||
# should never happen...
|
||||
@ -243,6 +356,9 @@ proc readrefs {} {
|
||||
global tagids idtags headids idheads tagcontents
|
||||
global otherrefids idotherrefs
|
||||
|
||||
foreach v {tagids idtags headids idheads otherrefids idotherrefs} {
|
||||
catch {unset $v}
|
||||
}
|
||||
set refd [open [list | git-ls-remote [gitdir]] r]
|
||||
while {0 <= [set n [gets $refd line]]} {
|
||||
if {![regexp {^([0-9a-f]{40}) refs/([^^]*)$} $line \
|
||||
@ -292,7 +408,7 @@ proc error_popup msg {
|
||||
tkwait window $w
|
||||
}
|
||||
|
||||
proc makewindow {} {
|
||||
proc makewindow {rargs} {
|
||||
global canv canv2 canv3 linespc charspc ctext cflist textfont
|
||||
global findtype findtypemenu findloc findstring fstring geometry
|
||||
global entries sha1entry sha1string sha1but
|
||||
@ -302,6 +418,7 @@ proc makewindow {} {
|
||||
menu .bar
|
||||
.bar add cascade -label "File" -menu .bar.file
|
||||
menu .bar.file
|
||||
.bar.file add command -label "Update" -command [list updatecommits $rargs]
|
||||
.bar.file add command -label "Reread references" -command rereadrefs
|
||||
.bar.file add command -label "Quit" -command doquit
|
||||
menu .bar.edit
|
||||
@ -719,7 +836,6 @@ proc assigncolor {id} {
|
||||
|
||||
proc initgraph {} {
|
||||
global canvy canvy0 lineno numcommits nextcolor linespc
|
||||
global mainline mainlinearrow sidelines
|
||||
global nchildren ncleft
|
||||
global displist nhyperspace
|
||||
|
||||
@ -728,9 +844,11 @@ proc initgraph {} {
|
||||
set canvy $canvy0
|
||||
set lineno -1
|
||||
set numcommits 0
|
||||
catch {unset mainline}
|
||||
catch {unset mainlinearrow}
|
||||
catch {unset sidelines}
|
||||
foreach v {mainline mainlinearrow sidelines colormap cornercrossings
|
||||
crossings idline lineid} {
|
||||
global $v
|
||||
catch {unset $v}
|
||||
}
|
||||
foreach id [array names nchildren] {
|
||||
set ncleft($id) $nchildren($id)
|
||||
}
|
||||
@ -1399,29 +1517,23 @@ proc decidenext {{noread 0}} {
|
||||
}
|
||||
}
|
||||
}
|
||||
if {$level < 0} {
|
||||
if {$todo != {}} {
|
||||
puts "ERROR: none of the pending commits can be done yet:"
|
||||
foreach p $todo {
|
||||
puts " $p ($ncleft($p))"
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
return $level
|
||||
}
|
||||
|
||||
proc drawcommit {id} {
|
||||
global phase todo nchildren datemode nextupdate revlistorder
|
||||
proc drawcommit {id reading} {
|
||||
global phase todo nchildren datemode nextupdate revlistorder ncleft
|
||||
global numcommits ncmupdate displayorder todo onscreen parents
|
||||
global commitlisted commitordered
|
||||
|
||||
if {$phase != "incrdraw"} {
|
||||
set phase incrdraw
|
||||
set displayorder {}
|
||||
set todo {}
|
||||
initgraph
|
||||
catch {unset commitordered}
|
||||
}
|
||||
set commitordered($id) 1
|
||||
if {$nchildren($id) == 0} {
|
||||
lappend todo $id
|
||||
set onscreen($id) 0
|
||||
@ -1436,35 +1548,44 @@ proc drawcommit {id} {
|
||||
updatetodo $level 0
|
||||
} else {
|
||||
set level [decidenext 1]
|
||||
if {$level == {} || $id != [lindex $todo $level]} {
|
||||
return
|
||||
}
|
||||
if {$level == {} || $level < 0} return
|
||||
while 1 {
|
||||
set id [lindex $todo $level]
|
||||
if {![info exists commitordered($id)]} {
|
||||
break
|
||||
}
|
||||
lappend displayorder [lindex $todo $level]
|
||||
if {[updatetodo $level $datemode]} {
|
||||
set level [decidenext 1]
|
||||
if {$level == {}} break
|
||||
}
|
||||
set id [lindex $todo $level]
|
||||
if {![info exists commitlisted($id)]} {
|
||||
break
|
||||
if {$level == {} || $level < 0} break
|
||||
}
|
||||
}
|
||||
}
|
||||
drawmore 1
|
||||
drawmore $reading
|
||||
}
|
||||
|
||||
proc finishcommits {} {
|
||||
global phase
|
||||
global phase oldcommits commits
|
||||
global canv mainfont ctext maincursor textcursor
|
||||
global parents displayorder todo
|
||||
|
||||
if {$phase != "incrdraw"} {
|
||||
if {$phase == "incrdraw" || $phase == "removecommits"} {
|
||||
foreach id $oldcommits {
|
||||
lappend commits $id
|
||||
drawcommit $id 0
|
||||
}
|
||||
set oldcommits {}
|
||||
drawrest
|
||||
} elseif {$phase == "updatecommits"} {
|
||||
# there were no new commits, in fact
|
||||
set commits $oldcommits
|
||||
set oldcommits {}
|
||||
set phase {}
|
||||
} else {
|
||||
$canv delete all
|
||||
$canv create text 3 3 -anchor nw -text "No commits selected" \
|
||||
-font $mainfont -tags textitems
|
||||
set phase {}
|
||||
} else {
|
||||
drawrest
|
||||
}
|
||||
. config -cursor $maincursor
|
||||
settextcursor $textcursor
|
||||
@ -1498,7 +1619,7 @@ proc drawgraph {} {
|
||||
|
||||
proc drawrest {} {
|
||||
global phase stopped redisplaying selectedline
|
||||
global datemode todo displayorder
|
||||
global datemode todo displayorder ncleft
|
||||
global numcommits ncmupdate
|
||||
global nextupdate startmsecs revlistorder
|
||||
|
||||
@ -1514,6 +1635,13 @@ proc drawrest {} {
|
||||
}
|
||||
}
|
||||
}
|
||||
if {$todo != {}} {
|
||||
puts "ERROR: none of the pending commits can be done yet:"
|
||||
foreach p $todo {
|
||||
puts " $p ($ncleft($p))"
|
||||
}
|
||||
}
|
||||
|
||||
drawmore 0
|
||||
set phase {}
|
||||
set drawmsecs [expr {[clock clicks -milliseconds] - $startmsecs}]
|
||||
@ -3578,9 +3706,6 @@ proc rereadrefs {} {
|
||||
set ref($id) [listrefs $id]
|
||||
}
|
||||
}
|
||||
foreach v {tagids idtags headids idheads otherrefids idotherrefs} {
|
||||
catch {unset $v}
|
||||
}
|
||||
readrefs
|
||||
set refids [lsort -unique [concat $refids [array names idtags] \
|
||||
[array names idheads] [array names idotherrefs]]]
|
||||
@ -3689,17 +3814,294 @@ proc formatdate {d} {
|
||||
return [clock format $d -format "%Y-%m-%d %H:%M:%S"]
|
||||
}
|
||||
|
||||
# This list of encoding names and aliases is distilled from
|
||||
# http://www.iana.org/assignments/character-sets.
|
||||
# Not all of them are supported by Tcl.
|
||||
set encoding_aliases {
|
||||
{ ANSI_X3.4-1968 iso-ir-6 ANSI_X3.4-1986 ISO_646.irv:1991 ASCII
|
||||
ISO646-US US-ASCII us IBM367 cp367 csASCII }
|
||||
{ ISO-10646-UTF-1 csISO10646UTF1 }
|
||||
{ ISO_646.basic:1983 ref csISO646basic1983 }
|
||||
{ INVARIANT csINVARIANT }
|
||||
{ ISO_646.irv:1983 iso-ir-2 irv csISO2IntlRefVersion }
|
||||
{ BS_4730 iso-ir-4 ISO646-GB gb uk csISO4UnitedKingdom }
|
||||
{ NATS-SEFI iso-ir-8-1 csNATSSEFI }
|
||||
{ NATS-SEFI-ADD iso-ir-8-2 csNATSSEFIADD }
|
||||
{ NATS-DANO iso-ir-9-1 csNATSDANO }
|
||||
{ NATS-DANO-ADD iso-ir-9-2 csNATSDANOADD }
|
||||
{ SEN_850200_B iso-ir-10 FI ISO646-FI ISO646-SE se csISO10Swedish }
|
||||
{ SEN_850200_C iso-ir-11 ISO646-SE2 se2 csISO11SwedishForNames }
|
||||
{ KS_C_5601-1987 iso-ir-149 KS_C_5601-1989 KSC_5601 korean csKSC56011987 }
|
||||
{ ISO-2022-KR csISO2022KR }
|
||||
{ EUC-KR csEUCKR }
|
||||
{ ISO-2022-JP csISO2022JP }
|
||||
{ ISO-2022-JP-2 csISO2022JP2 }
|
||||
{ JIS_C6220-1969-jp JIS_C6220-1969 iso-ir-13 katakana x0201-7
|
||||
csISO13JISC6220jp }
|
||||
{ JIS_C6220-1969-ro iso-ir-14 jp ISO646-JP csISO14JISC6220ro }
|
||||
{ IT iso-ir-15 ISO646-IT csISO15Italian }
|
||||
{ PT iso-ir-16 ISO646-PT csISO16Portuguese }
|
||||
{ ES iso-ir-17 ISO646-ES csISO17Spanish }
|
||||
{ greek7-old iso-ir-18 csISO18Greek7Old }
|
||||
{ latin-greek iso-ir-19 csISO19LatinGreek }
|
||||
{ DIN_66003 iso-ir-21 de ISO646-DE csISO21German }
|
||||
{ NF_Z_62-010_(1973) iso-ir-25 ISO646-FR1 csISO25French }
|
||||
{ Latin-greek-1 iso-ir-27 csISO27LatinGreek1 }
|
||||
{ ISO_5427 iso-ir-37 csISO5427Cyrillic }
|
||||
{ JIS_C6226-1978 iso-ir-42 csISO42JISC62261978 }
|
||||
{ BS_viewdata iso-ir-47 csISO47BSViewdata }
|
||||
{ INIS iso-ir-49 csISO49INIS }
|
||||
{ INIS-8 iso-ir-50 csISO50INIS8 }
|
||||
{ INIS-cyrillic iso-ir-51 csISO51INISCyrillic }
|
||||
{ ISO_5427:1981 iso-ir-54 ISO5427Cyrillic1981 }
|
||||
{ ISO_5428:1980 iso-ir-55 csISO5428Greek }
|
||||
{ GB_1988-80 iso-ir-57 cn ISO646-CN csISO57GB1988 }
|
||||
{ GB_2312-80 iso-ir-58 chinese csISO58GB231280 }
|
||||
{ NS_4551-1 iso-ir-60 ISO646-NO no csISO60DanishNorwegian
|
||||
csISO60Norwegian1 }
|
||||
{ NS_4551-2 ISO646-NO2 iso-ir-61 no2 csISO61Norwegian2 }
|
||||
{ NF_Z_62-010 iso-ir-69 ISO646-FR fr csISO69French }
|
||||
{ videotex-suppl iso-ir-70 csISO70VideotexSupp1 }
|
||||
{ PT2 iso-ir-84 ISO646-PT2 csISO84Portuguese2 }
|
||||
{ ES2 iso-ir-85 ISO646-ES2 csISO85Spanish2 }
|
||||
{ MSZ_7795.3 iso-ir-86 ISO646-HU hu csISO86Hungarian }
|
||||
{ JIS_C6226-1983 iso-ir-87 x0208 JIS_X0208-1983 csISO87JISX0208 }
|
||||
{ greek7 iso-ir-88 csISO88Greek7 }
|
||||
{ ASMO_449 ISO_9036 arabic7 iso-ir-89 csISO89ASMO449 }
|
||||
{ iso-ir-90 csISO90 }
|
||||
{ JIS_C6229-1984-a iso-ir-91 jp-ocr-a csISO91JISC62291984a }
|
||||
{ JIS_C6229-1984-b iso-ir-92 ISO646-JP-OCR-B jp-ocr-b
|
||||
csISO92JISC62991984b }
|
||||
{ JIS_C6229-1984-b-add iso-ir-93 jp-ocr-b-add csISO93JIS62291984badd }
|
||||
{ JIS_C6229-1984-hand iso-ir-94 jp-ocr-hand csISO94JIS62291984hand }
|
||||
{ JIS_C6229-1984-hand-add iso-ir-95 jp-ocr-hand-add
|
||||
csISO95JIS62291984handadd }
|
||||
{ JIS_C6229-1984-kana iso-ir-96 csISO96JISC62291984kana }
|
||||
{ ISO_2033-1983 iso-ir-98 e13b csISO2033 }
|
||||
{ ANSI_X3.110-1983 iso-ir-99 CSA_T500-1983 NAPLPS csISO99NAPLPS }
|
||||
{ ISO_8859-1:1987 iso-ir-100 ISO_8859-1 ISO-8859-1 latin1 l1 IBM819
|
||||
CP819 csISOLatin1 }
|
||||
{ ISO_8859-2:1987 iso-ir-101 ISO_8859-2 ISO-8859-2 latin2 l2 csISOLatin2 }
|
||||
{ T.61-7bit iso-ir-102 csISO102T617bit }
|
||||
{ T.61-8bit T.61 iso-ir-103 csISO103T618bit }
|
||||
{ ISO_8859-3:1988 iso-ir-109 ISO_8859-3 ISO-8859-3 latin3 l3 csISOLatin3 }
|
||||
{ ISO_8859-4:1988 iso-ir-110 ISO_8859-4 ISO-8859-4 latin4 l4 csISOLatin4 }
|
||||
{ ECMA-cyrillic iso-ir-111 KOI8-E csISO111ECMACyrillic }
|
||||
{ CSA_Z243.4-1985-1 iso-ir-121 ISO646-CA csa7-1 ca csISO121Canadian1 }
|
||||
{ CSA_Z243.4-1985-2 iso-ir-122 ISO646-CA2 csa7-2 csISO122Canadian2 }
|
||||
{ CSA_Z243.4-1985-gr iso-ir-123 csISO123CSAZ24341985gr }
|
||||
{ ISO_8859-6:1987 iso-ir-127 ISO_8859-6 ISO-8859-6 ECMA-114 ASMO-708
|
||||
arabic csISOLatinArabic }
|
||||
{ ISO_8859-6-E csISO88596E ISO-8859-6-E }
|
||||
{ ISO_8859-6-I csISO88596I ISO-8859-6-I }
|
||||
{ ISO_8859-7:1987 iso-ir-126 ISO_8859-7 ISO-8859-7 ELOT_928 ECMA-118
|
||||
greek greek8 csISOLatinGreek }
|
||||
{ T.101-G2 iso-ir-128 csISO128T101G2 }
|
||||
{ ISO_8859-8:1988 iso-ir-138 ISO_8859-8 ISO-8859-8 hebrew
|
||||
csISOLatinHebrew }
|
||||
{ ISO_8859-8-E csISO88598E ISO-8859-8-E }
|
||||
{ ISO_8859-8-I csISO88598I ISO-8859-8-I }
|
||||
{ CSN_369103 iso-ir-139 csISO139CSN369103 }
|
||||
{ JUS_I.B1.002 iso-ir-141 ISO646-YU js yu csISO141JUSIB1002 }
|
||||
{ ISO_6937-2-add iso-ir-142 csISOTextComm }
|
||||
{ IEC_P27-1 iso-ir-143 csISO143IECP271 }
|
||||
{ ISO_8859-5:1988 iso-ir-144 ISO_8859-5 ISO-8859-5 cyrillic
|
||||
csISOLatinCyrillic }
|
||||
{ JUS_I.B1.003-serb iso-ir-146 serbian csISO146Serbian }
|
||||
{ JUS_I.B1.003-mac macedonian iso-ir-147 csISO147Macedonian }
|
||||
{ ISO_8859-9:1989 iso-ir-148 ISO_8859-9 ISO-8859-9 latin5 l5 csISOLatin5 }
|
||||
{ greek-ccitt iso-ir-150 csISO150 csISO150GreekCCITT }
|
||||
{ NC_NC00-10:81 cuba iso-ir-151 ISO646-CU csISO151Cuba }
|
||||
{ ISO_6937-2-25 iso-ir-152 csISO6937Add }
|
||||
{ GOST_19768-74 ST_SEV_358-88 iso-ir-153 csISO153GOST1976874 }
|
||||
{ ISO_8859-supp iso-ir-154 latin1-2-5 csISO8859Supp }
|
||||
{ ISO_10367-box iso-ir-155 csISO10367Box }
|
||||
{ ISO-8859-10 iso-ir-157 l6 ISO_8859-10:1992 csISOLatin6 latin6 }
|
||||
{ latin-lap lap iso-ir-158 csISO158Lap }
|
||||
{ JIS_X0212-1990 x0212 iso-ir-159 csISO159JISX02121990 }
|
||||
{ DS_2089 DS2089 ISO646-DK dk csISO646Danish }
|
||||
{ us-dk csUSDK }
|
||||
{ dk-us csDKUS }
|
||||
{ JIS_X0201 X0201 csHalfWidthKatakana }
|
||||
{ KSC5636 ISO646-KR csKSC5636 }
|
||||
{ ISO-10646-UCS-2 csUnicode }
|
||||
{ ISO-10646-UCS-4 csUCS4 }
|
||||
{ DEC-MCS dec csDECMCS }
|
||||
{ hp-roman8 roman8 r8 csHPRoman8 }
|
||||
{ macintosh mac csMacintosh }
|
||||
{ IBM037 cp037 ebcdic-cp-us ebcdic-cp-ca ebcdic-cp-wt ebcdic-cp-nl
|
||||
csIBM037 }
|
||||
{ IBM038 EBCDIC-INT cp038 csIBM038 }
|
||||
{ IBM273 CP273 csIBM273 }
|
||||
{ IBM274 EBCDIC-BE CP274 csIBM274 }
|
||||
{ IBM275 EBCDIC-BR cp275 csIBM275 }
|
||||
{ IBM277 EBCDIC-CP-DK EBCDIC-CP-NO csIBM277 }
|
||||
{ IBM278 CP278 ebcdic-cp-fi ebcdic-cp-se csIBM278 }
|
||||
{ IBM280 CP280 ebcdic-cp-it csIBM280 }
|
||||
{ IBM281 EBCDIC-JP-E cp281 csIBM281 }
|
||||
{ IBM284 CP284 ebcdic-cp-es csIBM284 }
|
||||
{ IBM285 CP285 ebcdic-cp-gb csIBM285 }
|
||||
{ IBM290 cp290 EBCDIC-JP-kana csIBM290 }
|
||||
{ IBM297 cp297 ebcdic-cp-fr csIBM297 }
|
||||
{ IBM420 cp420 ebcdic-cp-ar1 csIBM420 }
|
||||
{ IBM423 cp423 ebcdic-cp-gr csIBM423 }
|
||||
{ IBM424 cp424 ebcdic-cp-he csIBM424 }
|
||||
{ IBM437 cp437 437 csPC8CodePage437 }
|
||||
{ IBM500 CP500 ebcdic-cp-be ebcdic-cp-ch csIBM500 }
|
||||
{ IBM775 cp775 csPC775Baltic }
|
||||
{ IBM850 cp850 850 csPC850Multilingual }
|
||||
{ IBM851 cp851 851 csIBM851 }
|
||||
{ IBM852 cp852 852 csPCp852 }
|
||||
{ IBM855 cp855 855 csIBM855 }
|
||||
{ IBM857 cp857 857 csIBM857 }
|
||||
{ IBM860 cp860 860 csIBM860 }
|
||||
{ IBM861 cp861 861 cp-is csIBM861 }
|
||||
{ IBM862 cp862 862 csPC862LatinHebrew }
|
||||
{ IBM863 cp863 863 csIBM863 }
|
||||
{ IBM864 cp864 csIBM864 }
|
||||
{ IBM865 cp865 865 csIBM865 }
|
||||
{ IBM866 cp866 866 csIBM866 }
|
||||
{ IBM868 CP868 cp-ar csIBM868 }
|
||||
{ IBM869 cp869 869 cp-gr csIBM869 }
|
||||
{ IBM870 CP870 ebcdic-cp-roece ebcdic-cp-yu csIBM870 }
|
||||
{ IBM871 CP871 ebcdic-cp-is csIBM871 }
|
||||
{ IBM880 cp880 EBCDIC-Cyrillic csIBM880 }
|
||||
{ IBM891 cp891 csIBM891 }
|
||||
{ IBM903 cp903 csIBM903 }
|
||||
{ IBM904 cp904 904 csIBBM904 }
|
||||
{ IBM905 CP905 ebcdic-cp-tr csIBM905 }
|
||||
{ IBM918 CP918 ebcdic-cp-ar2 csIBM918 }
|
||||
{ IBM1026 CP1026 csIBM1026 }
|
||||
{ EBCDIC-AT-DE csIBMEBCDICATDE }
|
||||
{ EBCDIC-AT-DE-A csEBCDICATDEA }
|
||||
{ EBCDIC-CA-FR csEBCDICCAFR }
|
||||
{ EBCDIC-DK-NO csEBCDICDKNO }
|
||||
{ EBCDIC-DK-NO-A csEBCDICDKNOA }
|
||||
{ EBCDIC-FI-SE csEBCDICFISE }
|
||||
{ EBCDIC-FI-SE-A csEBCDICFISEA }
|
||||
{ EBCDIC-FR csEBCDICFR }
|
||||
{ EBCDIC-IT csEBCDICIT }
|
||||
{ EBCDIC-PT csEBCDICPT }
|
||||
{ EBCDIC-ES csEBCDICES }
|
||||
{ EBCDIC-ES-A csEBCDICESA }
|
||||
{ EBCDIC-ES-S csEBCDICESS }
|
||||
{ EBCDIC-UK csEBCDICUK }
|
||||
{ EBCDIC-US csEBCDICUS }
|
||||
{ UNKNOWN-8BIT csUnknown8BiT }
|
||||
{ MNEMONIC csMnemonic }
|
||||
{ MNEM csMnem }
|
||||
{ VISCII csVISCII }
|
||||
{ VIQR csVIQR }
|
||||
{ KOI8-R csKOI8R }
|
||||
{ IBM00858 CCSID00858 CP00858 PC-Multilingual-850+euro }
|
||||
{ IBM00924 CCSID00924 CP00924 ebcdic-Latin9--euro }
|
||||
{ IBM01140 CCSID01140 CP01140 ebcdic-us-37+euro }
|
||||
{ IBM01141 CCSID01141 CP01141 ebcdic-de-273+euro }
|
||||
{ IBM01142 CCSID01142 CP01142 ebcdic-dk-277+euro ebcdic-no-277+euro }
|
||||
{ IBM01143 CCSID01143 CP01143 ebcdic-fi-278+euro ebcdic-se-278+euro }
|
||||
{ IBM01144 CCSID01144 CP01144 ebcdic-it-280+euro }
|
||||
{ IBM01145 CCSID01145 CP01145 ebcdic-es-284+euro }
|
||||
{ IBM01146 CCSID01146 CP01146 ebcdic-gb-285+euro }
|
||||
{ IBM01147 CCSID01147 CP01147 ebcdic-fr-297+euro }
|
||||
{ IBM01148 CCSID01148 CP01148 ebcdic-international-500+euro }
|
||||
{ IBM01149 CCSID01149 CP01149 ebcdic-is-871+euro }
|
||||
{ IBM1047 IBM-1047 }
|
||||
{ PTCP154 csPTCP154 PT154 CP154 Cyrillic-Asian }
|
||||
{ Amiga-1251 Ami1251 Amiga1251 Ami-1251 }
|
||||
{ UNICODE-1-1 csUnicode11 }
|
||||
{ CESU-8 csCESU-8 }
|
||||
{ BOCU-1 csBOCU-1 }
|
||||
{ UNICODE-1-1-UTF-7 csUnicode11UTF7 }
|
||||
{ ISO-8859-14 iso-ir-199 ISO_8859-14:1998 ISO_8859-14 latin8 iso-celtic
|
||||
l8 }
|
||||
{ ISO-8859-15 ISO_8859-15 Latin-9 }
|
||||
{ ISO-8859-16 iso-ir-226 ISO_8859-16:2001 ISO_8859-16 latin10 l10 }
|
||||
{ GBK CP936 MS936 windows-936 }
|
||||
{ JIS_Encoding csJISEncoding }
|
||||
{ Shift_JIS MS_Kanji csShiftJIS }
|
||||
{ Extended_UNIX_Code_Packed_Format_for_Japanese csEUCPkdFmtJapanese
|
||||
EUC-JP }
|
||||
{ Extended_UNIX_Code_Fixed_Width_for_Japanese csEUCFixWidJapanese }
|
||||
{ ISO-10646-UCS-Basic csUnicodeASCII }
|
||||
{ ISO-10646-Unicode-Latin1 csUnicodeLatin1 ISO-10646 }
|
||||
{ ISO-Unicode-IBM-1261 csUnicodeIBM1261 }
|
||||
{ ISO-Unicode-IBM-1268 csUnicodeIBM1268 }
|
||||
{ ISO-Unicode-IBM-1276 csUnicodeIBM1276 }
|
||||
{ ISO-Unicode-IBM-1264 csUnicodeIBM1264 }
|
||||
{ ISO-Unicode-IBM-1265 csUnicodeIBM1265 }
|
||||
{ ISO-8859-1-Windows-3.0-Latin-1 csWindows30Latin1 }
|
||||
{ ISO-8859-1-Windows-3.1-Latin-1 csWindows31Latin1 }
|
||||
{ ISO-8859-2-Windows-Latin-2 csWindows31Latin2 }
|
||||
{ ISO-8859-9-Windows-Latin-5 csWindows31Latin5 }
|
||||
{ Adobe-Standard-Encoding csAdobeStandardEncoding }
|
||||
{ Ventura-US csVenturaUS }
|
||||
{ Ventura-International csVenturaInternational }
|
||||
{ PC8-Danish-Norwegian csPC8DanishNorwegian }
|
||||
{ PC8-Turkish csPC8Turkish }
|
||||
{ IBM-Symbols csIBMSymbols }
|
||||
{ IBM-Thai csIBMThai }
|
||||
{ HP-Legal csHPLegal }
|
||||
{ HP-Pi-font csHPPiFont }
|
||||
{ HP-Math8 csHPMath8 }
|
||||
{ Adobe-Symbol-Encoding csHPPSMath }
|
||||
{ HP-DeskTop csHPDesktop }
|
||||
{ Ventura-Math csVenturaMath }
|
||||
{ Microsoft-Publishing csMicrosoftPublishing }
|
||||
{ Windows-31J csWindows31J }
|
||||
{ GB2312 csGB2312 }
|
||||
{ Big5 csBig5 }
|
||||
}
|
||||
|
||||
proc tcl_encoding {enc} {
|
||||
global encoding_aliases
|
||||
set names [encoding names]
|
||||
set lcnames [string tolower $names]
|
||||
set enc [string tolower $enc]
|
||||
set i [lsearch -exact $lcnames $enc]
|
||||
if {$i < 0} {
|
||||
# look for "isonnn" instead of "iso-nnn" or "iso_nnn"
|
||||
if {[regsub {^iso[-_]} $enc iso encx]} {
|
||||
set i [lsearch -exact $lcnames $encx]
|
||||
}
|
||||
}
|
||||
if {$i < 0} {
|
||||
foreach l $encoding_aliases {
|
||||
set ll [string tolower $l]
|
||||
if {[lsearch -exact $ll $enc] < 0} continue
|
||||
# look through the aliases for one that tcl knows about
|
||||
foreach e $ll {
|
||||
set i [lsearch -exact $lcnames $e]
|
||||
if {$i < 0} {
|
||||
if {[regsub {^iso[-_]} $e iso ex]} {
|
||||
set i [lsearch -exact $lcnames $ex]
|
||||
}
|
||||
}
|
||||
if {$i >= 0} break
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
if {$i >= 0} {
|
||||
return [lindex $names $i]
|
||||
}
|
||||
return {}
|
||||
}
|
||||
|
||||
# defaults...
|
||||
set datemode 0
|
||||
set diffopts "-U 5 -p"
|
||||
set wrcomcmd "git-diff-tree --stdin -p --pretty"
|
||||
|
||||
set gitencoding ""
|
||||
set gitencoding {}
|
||||
catch {
|
||||
set gitencoding [exec git-repo-config --get i18n.commitencoding]
|
||||
}
|
||||
if {$gitencoding == ""} {
|
||||
set gitencoding "utf-8"
|
||||
set gitencoding "utf-8"
|
||||
}
|
||||
set tclencoding [tcl_encoding $gitencoding]
|
||||
if {$tclencoding == {}} {
|
||||
puts stderr "Warning: encoding $gitencoding is not supported by Tcl/Tk"
|
||||
}
|
||||
|
||||
set mainfont {Helvetica 9}
|
||||
@ -3738,6 +4140,6 @@ set redisplaying 0
|
||||
set stuffsaved 0
|
||||
set patchnum 0
|
||||
setcoords
|
||||
makewindow
|
||||
makewindow $revtreeargs
|
||||
readrefs
|
||||
getcommits $revtreeargs
|
||||
|
@ -21,8 +21,16 @@ static void hash_object(const char *path, const char *type, int write_object)
|
||||
printf("%s\n", sha1_to_hex(sha1));
|
||||
}
|
||||
|
||||
static void hash_stdin(const char *type, int write_object)
|
||||
{
|
||||
unsigned char sha1[20];
|
||||
if (index_pipe(sha1, 0, type, write_object))
|
||||
die("Unable to add stdin to database");
|
||||
printf("%s\n", sha1_to_hex(sha1));
|
||||
}
|
||||
|
||||
static const char hash_object_usage[] =
|
||||
"git-hash-object [-t <type>] [-w] <file>...";
|
||||
"git-hash-object [-t <type>] [-w] [--stdin] <file>...";
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
@ -31,26 +39,41 @@ int main(int argc, char **argv)
|
||||
int write_object = 0;
|
||||
const char *prefix = NULL;
|
||||
int prefix_length = -1;
|
||||
int no_more_flags = 0;
|
||||
|
||||
for (i = 1 ; i < argc; i++) {
|
||||
if (!strcmp(argv[i], "-t")) {
|
||||
if (argc <= ++i)
|
||||
die(hash_object_usage);
|
||||
type = argv[i];
|
||||
}
|
||||
else if (!strcmp(argv[i], "-w")) {
|
||||
if (prefix_length < 0) {
|
||||
prefix = setup_git_directory();
|
||||
prefix_length = prefix ? strlen(prefix) : 0;
|
||||
if (!no_more_flags && argv[i][0] == '-') {
|
||||
if (!strcmp(argv[i], "-t")) {
|
||||
if (argc <= ++i)
|
||||
die(hash_object_usage);
|
||||
type = argv[i];
|
||||
}
|
||||
write_object = 1;
|
||||
}
|
||||
else if (!strcmp(argv[i], "-w")) {
|
||||
if (prefix_length < 0) {
|
||||
prefix = setup_git_directory();
|
||||
prefix_length =
|
||||
prefix ? strlen(prefix) : 0;
|
||||
}
|
||||
write_object = 1;
|
||||
}
|
||||
else if (!strcmp(argv[i], "--")) {
|
||||
no_more_flags = 1;
|
||||
}
|
||||
else if (!strcmp(argv[i], "--help"))
|
||||
usage(hash_object_usage);
|
||||
else if (!strcmp(argv[i], "--stdin")) {
|
||||
hash_stdin(type, write_object);
|
||||
}
|
||||
else
|
||||
die(hash_object_usage);
|
||||
}
|
||||
else {
|
||||
const char *arg = argv[i];
|
||||
if (0 <= prefix_length)
|
||||
arg = prefix_filename(prefix, prefix_length,
|
||||
arg);
|
||||
hash_object(arg, type, write_object);
|
||||
no_more_flags = 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
@ -237,9 +237,7 @@ int main(int argc, char **argv)
|
||||
|
||||
for (i = 1; i < argc; i++, argv++) {
|
||||
char *arg = argv[1];
|
||||
if (arg[0] != '-')
|
||||
break;
|
||||
else if (!strncmp(arg, "--template=", 11))
|
||||
if (!strncmp(arg, "--template=", 11))
|
||||
template_dir = arg+11;
|
||||
else
|
||||
die(init_db_usage);
|
||||
|
@ -8,12 +8,9 @@
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <iconv.h>
|
||||
#include "git-compat-util.h"
|
||||
#include "cache.h"
|
||||
|
||||
#ifdef NO_STRCASESTR
|
||||
extern char *gitstrcasestr(const char *haystack, const char *needle);
|
||||
#endif
|
||||
|
||||
static FILE *cmitmsg, *patchfile;
|
||||
|
||||
static int keep_subject = 0;
|
||||
|
7
object.c
7
object.c
@ -82,7 +82,12 @@ static int compare_object_pointers(const void *a, const void *b)
|
||||
{
|
||||
const struct object * const *pa = a;
|
||||
const struct object * const *pb = b;
|
||||
return *pa - *pb;
|
||||
if (*pa == *pb)
|
||||
return 0;
|
||||
else if (*pa < *pb)
|
||||
return -1;
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
|
||||
void set_object_refs(struct object *obj, struct object_refs *refs)
|
||||
|
@ -4,7 +4,7 @@
|
||||
#include "pack.h"
|
||||
#include "csum-file.h"
|
||||
|
||||
static const char pack_usage[] = "git-pack-objects [--local] [--incremental] [--window=N] [--depth=N] {--stdout | base-name} < object-list";
|
||||
static const char pack_usage[] = "git-pack-objects [--non-empty] [--local] [--incremental] [--window=N] [--depth=N] {--stdout | base-name} < object-list";
|
||||
|
||||
struct object_entry {
|
||||
unsigned char sha1[20];
|
||||
|
@ -173,7 +173,7 @@ static void run_update_post_hook(struct command *cmd)
|
||||
argc++;
|
||||
}
|
||||
argv[argc] = NULL;
|
||||
run_command_v(argc, argv);
|
||||
run_command_v_opt(argc, argv, RUN_COMMAND_NO_STDIO);
|
||||
}
|
||||
|
||||
/*
|
||||
|
4
refs.c
4
refs.c
@ -292,6 +292,8 @@ int write_ref_sha1(const char *ref, int fd, const unsigned char *sha1)
|
||||
return -1;
|
||||
filename = ref_file_name(ref);
|
||||
lock_filename = ref_lock_file_name(ref);
|
||||
if (safe_create_leading_directories(filename))
|
||||
die("unable to create leading directory for %s", filename);
|
||||
retval = write_ref_file(filename, lock_filename, fd, sha1);
|
||||
free(filename);
|
||||
free(lock_filename);
|
||||
@ -358,6 +360,8 @@ int write_ref_sha1_unlocked(const char *ref, const unsigned char *sha1)
|
||||
return -1;
|
||||
filename = ref_file_name(ref);
|
||||
lock_filename = ref_lock_file_name(ref);
|
||||
if (safe_create_leading_directories(filename))
|
||||
die("unable to create leading directory for %s", filename);
|
||||
fd = open(lock_filename, O_WRONLY | O_CREAT | O_EXCL, 0666);
|
||||
if (fd < 0) {
|
||||
error("Writing %s", lock_filename);
|
||||
|
@ -2,13 +2,19 @@
|
||||
#include "run-command.h"
|
||||
#include <sys/wait.h>
|
||||
|
||||
int run_command_v(int argc, char **argv)
|
||||
int run_command_v_opt(int argc, char **argv, int flags)
|
||||
{
|
||||
pid_t pid = fork();
|
||||
|
||||
if (pid < 0)
|
||||
return -ERR_RUN_COMMAND_FORK;
|
||||
if (!pid) {
|
||||
if (flags & RUN_COMMAND_NO_STDIO) {
|
||||
int fd = open("/dev/null", O_RDWR);
|
||||
dup2(fd, 0);
|
||||
dup2(fd, 1);
|
||||
close(fd);
|
||||
}
|
||||
execvp(argv[0], (char *const*) argv);
|
||||
die("exec %s failed.", argv[0]);
|
||||
}
|
||||
@ -36,6 +42,11 @@ int run_command_v(int argc, char **argv)
|
||||
}
|
||||
}
|
||||
|
||||
int run_command_v(int argc, char **argv)
|
||||
{
|
||||
return run_command_v_opt(argc, argv, 0);
|
||||
}
|
||||
|
||||
int run_command(const char *cmd, ...)
|
||||
{
|
||||
int argc;
|
||||
@ -54,5 +65,5 @@ int run_command(const char *cmd, ...)
|
||||
va_end(param);
|
||||
if (MAX_RUN_COMMAND_ARGS <= argc)
|
||||
return error("too many args to run %s", cmd);
|
||||
return run_command_v(argc, argv);
|
||||
return run_command_v_opt(argc, argv, 0);
|
||||
}
|
||||
|
@ -11,6 +11,9 @@ enum {
|
||||
ERR_RUN_COMMAND_WAITPID_NOEXIT,
|
||||
};
|
||||
|
||||
#define RUN_COMMAND_NO_STDIO 1
|
||||
|
||||
int run_command_v_opt(int argc, char **argv, int opt);
|
||||
int run_command_v(int argc, char **argv);
|
||||
int run_command(const char *cmd, ...);
|
||||
|
||||
|
@ -190,6 +190,12 @@ static int send_pack(int in, int out, int nr_refspec, char **refspec)
|
||||
if (match_refs(local_refs, remote_refs, &remote_tail,
|
||||
nr_refspec, refspec, send_all))
|
||||
return -1;
|
||||
|
||||
if (!remote_refs) {
|
||||
fprintf(stderr, "No refs in common and none specified; doing nothing.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Finally, tell the other end!
|
||||
*/
|
||||
|
324
server-info.c
324
server-info.c
@ -44,43 +44,17 @@ static int update_info_refs(int force)
|
||||
|
||||
/* packs */
|
||||
static struct pack_info {
|
||||
unsigned long latest;
|
||||
struct packed_git *p;
|
||||
int old_num;
|
||||
int new_num;
|
||||
int nr_alloc;
|
||||
int nr_heads;
|
||||
unsigned char (*head)[20];
|
||||
char dep[0]; /* more */
|
||||
} **info;
|
||||
static int num_pack;
|
||||
static const char *objdir;
|
||||
static int objdirlen;
|
||||
|
||||
static struct object *parse_object_cheap(const unsigned char *sha1)
|
||||
{
|
||||
struct object *o;
|
||||
|
||||
if ((o = parse_object(sha1)) == NULL)
|
||||
return NULL;
|
||||
if (o->type == commit_type) {
|
||||
struct commit *commit = (struct commit *)o;
|
||||
free(commit->buffer);
|
||||
commit->buffer = NULL;
|
||||
} else if (o->type == tree_type) {
|
||||
struct tree *tree = (struct tree *)o;
|
||||
struct tree_entry_list *e, *n;
|
||||
for (e = tree->entries; e; e = n) {
|
||||
free(e->name);
|
||||
e->name = NULL;
|
||||
n = e->next;
|
||||
free(e);
|
||||
}
|
||||
tree->entries = NULL;
|
||||
}
|
||||
return o;
|
||||
}
|
||||
|
||||
static struct pack_info *find_pack_by_name(const char *name)
|
||||
{
|
||||
int i;
|
||||
@ -93,25 +67,6 @@ static struct pack_info *find_pack_by_name(const char *name)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct pack_info *find_pack_by_old_num(int old_num)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < num_pack; i++)
|
||||
if (info[i]->old_num == old_num)
|
||||
return info[i];
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int add_head_def(struct pack_info *this, unsigned char *sha1)
|
||||
{
|
||||
if (this->nr_alloc <= this->nr_heads) {
|
||||
this->nr_alloc = alloc_nr(this->nr_alloc);
|
||||
this->head = xrealloc(this->head, this->nr_alloc * 20);
|
||||
}
|
||||
memcpy(this->head[this->nr_heads++], sha1, 20);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Returns non-zero when we detect that the info in the
|
||||
* old file is useless.
|
||||
*/
|
||||
@ -123,72 +78,11 @@ static int parse_pack_def(const char *line, int old_cnt)
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
/* The file describes a pack that is no longer here;
|
||||
* dependencies between packs needs to be recalculated.
|
||||
*/
|
||||
/* The file describes a pack that is no longer here */
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Returns non-zero when we detect that the info in the
|
||||
* old file is useless.
|
||||
*/
|
||||
static int parse_depend_def(char *line)
|
||||
{
|
||||
unsigned long num;
|
||||
char *cp, *ep;
|
||||
struct pack_info *this, *that;
|
||||
|
||||
cp = line + 2;
|
||||
num = strtoul(cp, &ep, 10);
|
||||
if (ep == cp)
|
||||
return error("invalid input %s", line);
|
||||
this = find_pack_by_old_num(num);
|
||||
if (!this)
|
||||
return 0;
|
||||
while (ep && *(cp = ep)) {
|
||||
num = strtoul(cp, &ep, 10);
|
||||
if (ep == cp)
|
||||
break;
|
||||
that = find_pack_by_old_num(num);
|
||||
if (!that)
|
||||
/* The pack this one depends on does not
|
||||
* exist; this should not happen because
|
||||
* we write out the list of packs first and
|
||||
* then dependency information, but it means
|
||||
* the file is useless anyway.
|
||||
*/
|
||||
return 1;
|
||||
this->dep[that->new_num] = 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Returns non-zero when we detect that the info in the
|
||||
* old file is useless.
|
||||
*/
|
||||
static int parse_head_def(char *line)
|
||||
{
|
||||
unsigned char sha1[20];
|
||||
unsigned long num;
|
||||
char *cp, *ep;
|
||||
struct pack_info *this;
|
||||
struct object *o;
|
||||
|
||||
cp = line + 2;
|
||||
num = strtoul(cp, &ep, 10);
|
||||
if (ep == cp || *ep++ != ' ')
|
||||
return error("invalid input ix %s", line);
|
||||
this = find_pack_by_old_num(num);
|
||||
if (!this)
|
||||
return 1; /* You know the drill. */
|
||||
if (get_sha1_hex(ep, sha1) || ep[40] != ' ')
|
||||
return error("invalid input sha1 %s (%s)", line, ep);
|
||||
if ((o = parse_object_cheap(sha1)) == NULL)
|
||||
return error("no such object: %s", line);
|
||||
return add_head_def(this, sha1);
|
||||
}
|
||||
|
||||
/* Returns non-zero when we detect that the info in the
|
||||
* old file is useless.
|
||||
*/
|
||||
@ -212,13 +106,11 @@ static int read_pack_info_file(const char *infofile)
|
||||
if (parse_pack_def(line, old_cnt++))
|
||||
goto out_stale;
|
||||
break;
|
||||
case 'D': /* D ix dep-ix1 dep-ix2... */
|
||||
if (parse_depend_def(line))
|
||||
goto out_stale;
|
||||
case 'D': /* we used to emit D but that was misguided. */
|
||||
goto out_stale;
|
||||
break;
|
||||
case 'T': /* T ix sha1 type */
|
||||
if (parse_head_def(line))
|
||||
goto out_stale;
|
||||
case 'T': /* we used to emit T but nobody uses it. */
|
||||
goto out_stale;
|
||||
break;
|
||||
default:
|
||||
error("unrecognized: %s", line);
|
||||
@ -232,32 +124,6 @@ static int read_pack_info_file(const char *infofile)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* We sort the packs according to the date of the latest commit. That
|
||||
* in turn indicates how young the pack is, and in general we would
|
||||
* want to depend on younger packs.
|
||||
*/
|
||||
static unsigned long get_latest_commit_date(struct packed_git *p)
|
||||
{
|
||||
unsigned char sha1[20];
|
||||
struct object *o;
|
||||
int num = num_packed_objects(p);
|
||||
int i;
|
||||
unsigned long latest = 0;
|
||||
|
||||
for (i = 0; i < num; i++) {
|
||||
if (nth_packed_object_sha1(p, i, sha1))
|
||||
die("corrupt pack file %s?", p->pack_name);
|
||||
if ((o = parse_object_cheap(sha1)) == NULL)
|
||||
die("cannot parse %s", sha1_to_hex(sha1));
|
||||
if (o->type == commit_type) {
|
||||
struct commit *commit = (struct commit *)o;
|
||||
if (latest < commit->date)
|
||||
latest = commit->date;
|
||||
}
|
||||
}
|
||||
return latest;
|
||||
}
|
||||
|
||||
static int compare_info(const void *a_, const void *b_)
|
||||
{
|
||||
struct pack_info * const* a = a_;
|
||||
@ -273,10 +139,11 @@ static int compare_info(const void *a_, const void *b_)
|
||||
/* The other way around. */
|
||||
return 1;
|
||||
|
||||
if ((*a)->latest < (*b)->latest)
|
||||
return -1;
|
||||
else if ((*a)->latest == (*b)->latest)
|
||||
/* then it does not matter but at least keep the comparison stable */
|
||||
if ((*a)->p == (*b)->p)
|
||||
return 0;
|
||||
else if ((*a)->p < (*b)->p)
|
||||
return -1;
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
@ -286,7 +153,6 @@ static void init_pack_info(const char *infofile, int force)
|
||||
struct packed_git *p;
|
||||
int stale;
|
||||
int i = 0;
|
||||
char *dep_temp;
|
||||
|
||||
objdir = get_object_directory();
|
||||
objdirlen = strlen(objdir);
|
||||
@ -296,18 +162,16 @@ static void init_pack_info(const char *infofile, int force)
|
||||
/* we ignore things on alternate path since they are
|
||||
* not available to the pullers in general.
|
||||
*/
|
||||
if (strncmp(p->pack_name, objdir, objdirlen) ||
|
||||
strncmp(p->pack_name + objdirlen, "/pack/", 6))
|
||||
if (!p->pack_local)
|
||||
continue;
|
||||
i++;
|
||||
}
|
||||
num_pack = i;
|
||||
info = xcalloc(num_pack, sizeof(struct pack_info *));
|
||||
for (i = 0, p = packed_git; p; p = p->next) {
|
||||
if (strncmp(p->pack_name, objdir, objdirlen) ||
|
||||
p->pack_name[objdirlen] != '/')
|
||||
if (!p->pack_local)
|
||||
continue;
|
||||
info[i] = xcalloc(1, sizeof(struct pack_info) + num_pack);
|
||||
info[i] = xcalloc(1, sizeof(struct pack_info));
|
||||
info[i]->p = p;
|
||||
info[i]->old_num = -1;
|
||||
i++;
|
||||
@ -321,177 +185,21 @@ static void init_pack_info(const char *infofile, int force)
|
||||
for (i = 0; i < num_pack; i++) {
|
||||
if (stale) {
|
||||
info[i]->old_num = -1;
|
||||
memset(info[i]->dep, 0, num_pack);
|
||||
info[i]->nr_heads = 0;
|
||||
}
|
||||
if (info[i]->old_num < 0)
|
||||
info[i]->latest = get_latest_commit_date(info[i]->p);
|
||||
}
|
||||
|
||||
/* renumber them */
|
||||
qsort(info, num_pack, sizeof(info[0]), compare_info);
|
||||
for (i = 0; i < num_pack; i++)
|
||||
info[i]->new_num = i;
|
||||
|
||||
/* we need to fix up the dependency information
|
||||
* for the old ones.
|
||||
*/
|
||||
dep_temp = NULL;
|
||||
for (i = 0; i < num_pack; i++) {
|
||||
int old;
|
||||
|
||||
if (info[i]->old_num < 0)
|
||||
continue;
|
||||
if (! dep_temp)
|
||||
dep_temp = xmalloc(num_pack);
|
||||
memset(dep_temp, 0, num_pack);
|
||||
for (old = 0; old < num_pack; old++) {
|
||||
struct pack_info *base;
|
||||
if (!info[i]->dep[old])
|
||||
continue;
|
||||
base = find_pack_by_old_num(old);
|
||||
if (!base)
|
||||
die("internal error renumbering");
|
||||
dep_temp[base->new_num] = 1;
|
||||
}
|
||||
memcpy(info[i]->dep, dep_temp, num_pack);
|
||||
}
|
||||
free(dep_temp);
|
||||
}
|
||||
|
||||
static void write_pack_info_file(FILE *fp)
|
||||
{
|
||||
int i, j;
|
||||
int i;
|
||||
for (i = 0; i < num_pack; i++)
|
||||
fprintf(fp, "P %s\n", info[i]->p->pack_name + objdirlen + 6);
|
||||
|
||||
for (i = 0; i < num_pack; i++) {
|
||||
fprintf(fp, "D %1d", i);
|
||||
for (j = 0; j < num_pack; j++) {
|
||||
if ((i == j) || !(info[i]->dep[j]))
|
||||
continue;
|
||||
fprintf(fp, " %1d", j);
|
||||
}
|
||||
fputc('\n', fp);
|
||||
}
|
||||
|
||||
for (i = 0; i < num_pack; i++) {
|
||||
struct pack_info *this = info[i];
|
||||
for (j = 0; j < this->nr_heads; j++) {
|
||||
struct object *o = lookup_object(this->head[j]);
|
||||
fprintf(fp, "T %1d %s %s\n",
|
||||
i, sha1_to_hex(this->head[j]), o->type);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#define REFERENCED 01
|
||||
#define INTERNAL 02
|
||||
#define EMITTED 04
|
||||
|
||||
static void show(struct object *o, int pack_ix)
|
||||
{
|
||||
/*
|
||||
* We are interested in objects that are not referenced,
|
||||
* and objects that are referenced but not internal.
|
||||
*/
|
||||
if (o->flags & EMITTED)
|
||||
return;
|
||||
|
||||
if (!(o->flags & REFERENCED))
|
||||
add_head_def(info[pack_ix], o->sha1);
|
||||
else if ((o->flags & REFERENCED) && !(o->flags & INTERNAL)) {
|
||||
int i;
|
||||
|
||||
/* Which pack contains this object? That is what
|
||||
* pack_ix can depend on. We earlier sorted info
|
||||
* array from youngest to oldest, so try newer packs
|
||||
* first to favor them here.
|
||||
*/
|
||||
for (i = num_pack - 1; 0 <= i; i--) {
|
||||
struct packed_git *p = info[i]->p;
|
||||
struct pack_entry ent;
|
||||
if (find_pack_entry_one(o->sha1, &ent, p)) {
|
||||
info[pack_ix]->dep[i] = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
o->flags |= EMITTED;
|
||||
}
|
||||
|
||||
static void find_pack_info_one(int pack_ix)
|
||||
{
|
||||
unsigned char sha1[20];
|
||||
struct object *o;
|
||||
int i;
|
||||
struct packed_git *p = info[pack_ix]->p;
|
||||
int num = num_packed_objects(p);
|
||||
|
||||
/* Scan objects, clear flags from all the edge ones and
|
||||
* internal ones, possibly marked in the previous round.
|
||||
*/
|
||||
for (i = 0; i < num; i++) {
|
||||
if (nth_packed_object_sha1(p, i, sha1))
|
||||
die("corrupt pack file %s?", p->pack_name);
|
||||
if ((o = lookup_object(sha1)) == NULL)
|
||||
die("cannot parse %s", sha1_to_hex(sha1));
|
||||
if (o->refs) {
|
||||
struct object_refs *refs = o->refs;
|
||||
int j;
|
||||
for (j = 0; j < refs->count; j++)
|
||||
refs->ref[j]->flags = 0;
|
||||
}
|
||||
o->flags = 0;
|
||||
}
|
||||
|
||||
/* Mark all the internal ones */
|
||||
for (i = 0; i < num; i++) {
|
||||
if (nth_packed_object_sha1(p, i, sha1))
|
||||
die("corrupt pack file %s?", p->pack_name);
|
||||
if ((o = lookup_object(sha1)) == NULL)
|
||||
die("cannot find %s", sha1_to_hex(sha1));
|
||||
if (o->refs) {
|
||||
struct object_refs *refs = o->refs;
|
||||
int j;
|
||||
for (j = 0; j < refs->count; j++)
|
||||
refs->ref[j]->flags |= REFERENCED;
|
||||
}
|
||||
o->flags |= INTERNAL;
|
||||
}
|
||||
|
||||
for (i = 0; i < num; i++) {
|
||||
if (nth_packed_object_sha1(p, i, sha1))
|
||||
die("corrupt pack file %s?", p->pack_name);
|
||||
if ((o = lookup_object(sha1)) == NULL)
|
||||
die("cannot find %s", sha1_to_hex(sha1));
|
||||
|
||||
show(o, pack_ix);
|
||||
if (o->refs) {
|
||||
struct object_refs *refs = o->refs;
|
||||
int j;
|
||||
for (j = 0; j < refs->count; j++)
|
||||
show(refs->ref[j], pack_ix);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void find_pack_info(void)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < num_pack; i++) {
|
||||
/* The packed objects are cast in stone, and a head
|
||||
* in a pack will stay as head, so is the set of missing
|
||||
* objects. If the repo has been reorganized and we
|
||||
* are missing some packs available back then, we have
|
||||
* already discarded the info read from the file, so
|
||||
* we will find (old_num < 0) in that case.
|
||||
*/
|
||||
if (0 <= info[i]->old_num)
|
||||
continue;
|
||||
find_pack_info_one(i);
|
||||
}
|
||||
}
|
||||
|
||||
static int update_info_packs(int force)
|
||||
@ -506,7 +214,6 @@ static int update_info_packs(int force)
|
||||
strcpy(name + namelen, "+");
|
||||
|
||||
init_pack_info(infofile, force);
|
||||
find_pack_info();
|
||||
|
||||
safe_create_leading_directories(name);
|
||||
fp = fopen(name, "w");
|
||||
@ -530,5 +237,8 @@ int update_server_info(int force)
|
||||
errs = errs | update_info_refs(force);
|
||||
errs = errs | update_info_packs(force);
|
||||
|
||||
/* remove leftover rev-cache file if there is any */
|
||||
unlink(git_path("info/rev-cache"));
|
||||
|
||||
return errs;
|
||||
}
|
||||
|
63
sha1_file.c
63
sha1_file.c
@ -184,8 +184,8 @@ static struct alternate_object_database **alt_odb_tail;
|
||||
* alternate_object_database. The elements on this list come from
|
||||
* non-empty elements from colon separated ALTERNATE_DB_ENVIRONMENT
|
||||
* environment variable, and $GIT_OBJECT_DIRECTORY/info/alternates,
|
||||
* whose contents is exactly in the same format as that environment
|
||||
* variable. Its base points at a statically allocated buffer that
|
||||
* whose contents is similar to that environment variable but can be
|
||||
* LF separated. Its base points at a statically allocated buffer that
|
||||
* contains "/the/directory/corresponding/to/.git/objects/...", while
|
||||
* its name points just after the slash at the end of ".git/objects/"
|
||||
* in the example above, and has enough space to hold 40-byte hex
|
||||
@ -197,6 +197,7 @@ static void link_alt_odb_entries(const char *alt, const char *ep, int sep,
|
||||
{
|
||||
const char *cp, *last;
|
||||
struct alternate_object_database *ent;
|
||||
const char *objdir = get_object_directory();
|
||||
int base_len = -1;
|
||||
|
||||
last = alt;
|
||||
@ -211,6 +212,7 @@ static void link_alt_odb_entries(const char *alt, const char *ep, int sep,
|
||||
for ( ; cp < ep && *cp != sep; cp++)
|
||||
;
|
||||
if (last != cp) {
|
||||
struct alternate_object_database *alt;
|
||||
/* 43 = 40-byte + 2 '/' + terminating NUL */
|
||||
int pfxlen = cp - last;
|
||||
int entlen = pfxlen + 43;
|
||||
@ -223,9 +225,7 @@ static void link_alt_odb_entries(const char *alt, const char *ep, int sep,
|
||||
pfxlen += base_len;
|
||||
}
|
||||
ent = xmalloc(sizeof(*ent) + entlen);
|
||||
*alt_odb_tail = ent;
|
||||
alt_odb_tail = &(ent->next);
|
||||
ent->next = NULL;
|
||||
|
||||
if (*last != '/' && relative_base) {
|
||||
memcpy(ent->base, relative_base, base_len - 1);
|
||||
ent->base[base_len - 1] = '/';
|
||||
@ -237,6 +237,22 @@ static void link_alt_odb_entries(const char *alt, const char *ep, int sep,
|
||||
ent->name = ent->base + pfxlen + 1;
|
||||
ent->base[pfxlen] = ent->base[pfxlen + 3] = '/';
|
||||
ent->base[entlen-1] = 0;
|
||||
|
||||
/* Prevent the common mistake of listing the same
|
||||
* thing twice, or object directory itself.
|
||||
*/
|
||||
for (alt = alt_odb_list; alt; alt = alt->next)
|
||||
if (!memcmp(ent->base, alt->base, pfxlen))
|
||||
goto bad;
|
||||
if (!memcmp(ent->base, objdir, pfxlen)) {
|
||||
bad:
|
||||
free(ent);
|
||||
}
|
||||
else {
|
||||
*alt_odb_tail = ent;
|
||||
alt_odb_tail = &(ent->next);
|
||||
ent->next = NULL;
|
||||
}
|
||||
}
|
||||
while (cp < ep && *cp == sep)
|
||||
cp++;
|
||||
@ -531,8 +547,9 @@ void prepare_packed_git(void)
|
||||
prepare_packed_git_one(get_object_directory(), 1);
|
||||
prepare_alt_odb();
|
||||
for (alt = alt_odb_list; alt; alt = alt->next) {
|
||||
alt->name[0] = 0;
|
||||
alt->name[-1] = 0;
|
||||
prepare_packed_git_one(alt->base, 0);
|
||||
alt->name[-1] = '/';
|
||||
}
|
||||
run_once = 1;
|
||||
}
|
||||
@ -1511,6 +1528,40 @@ int has_sha1_file(const unsigned char *sha1)
|
||||
return find_sha1_file(sha1, &st) ? 1 : 0;
|
||||
}
|
||||
|
||||
int index_pipe(unsigned char *sha1, int fd, const char *type, int write_object)
|
||||
{
|
||||
unsigned long size = 4096;
|
||||
char *buf = malloc(size);
|
||||
int iret, ret;
|
||||
unsigned long off = 0;
|
||||
unsigned char hdr[50];
|
||||
int hdrlen;
|
||||
do {
|
||||
iret = read(fd, buf + off, size - off);
|
||||
if (iret > 0) {
|
||||
off += iret;
|
||||
if (off == size) {
|
||||
size *= 2;
|
||||
buf = realloc(buf, size);
|
||||
}
|
||||
}
|
||||
} while (iret > 0);
|
||||
if (iret < 0) {
|
||||
free(buf);
|
||||
return -1;
|
||||
}
|
||||
if (!type)
|
||||
type = "blob";
|
||||
if (write_object)
|
||||
ret = write_sha1_file(buf, off, type, sha1);
|
||||
else {
|
||||
write_sha1_file_prepare(buf, off, type, sha1, hdr, &hdrlen);
|
||||
ret = 0;
|
||||
}
|
||||
free(buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int index_fd(unsigned char *sha1, int fd, struct stat *st, int write_object, const char *type)
|
||||
{
|
||||
unsigned long size = st->st_size;
|
||||
|
@ -1,10 +1,11 @@
|
||||
#include <stdlib.h>
|
||||
#include <fnmatch.h>
|
||||
#include "cache.h"
|
||||
#include "commit.h"
|
||||
#include "refs.h"
|
||||
|
||||
static const char show_branch_usage[] =
|
||||
"git-show-branch [--all] [--heads] [--tags] [--more=count | --list | --independent | --merge-base ] [<refs>...]";
|
||||
"git-show-branch [--all] [--heads] [--tags] [--topo-order] [--more=count | --list | --independent | --merge-base ] [<refs>...]";
|
||||
|
||||
#define UNINTERESTING 01
|
||||
|
||||
@ -54,7 +55,7 @@ static void name_commit(struct commit *commit, const char *head_name, int nth)
|
||||
|
||||
/* Parent is the first parent of the commit. We may name it
|
||||
* as (n+1)th generation ancestor of the same head_name as
|
||||
* commit is nth generation ancestore of, if that generation
|
||||
* commit is nth generation ancestor of, if that generation
|
||||
* number is better than the name it already has.
|
||||
*/
|
||||
static void name_parent(struct commit *commit, struct commit *parent)
|
||||
@ -332,6 +333,39 @@ static int append_tag_ref(const char *refname, const unsigned char *sha1)
|
||||
return append_ref(refname + 5, sha1);
|
||||
}
|
||||
|
||||
static const char *match_ref_pattern = NULL;
|
||||
static int match_ref_slash = 0;
|
||||
static int count_slash(const char *s)
|
||||
{
|
||||
int cnt = 0;
|
||||
while (*s)
|
||||
if (*s++ == '/')
|
||||
cnt++;
|
||||
return cnt;
|
||||
}
|
||||
|
||||
static int append_matching_ref(const char *refname, const unsigned char *sha1)
|
||||
{
|
||||
/* we want to allow pattern hold/<asterisk> to show all
|
||||
* branches under refs/heads/hold/, and v0.99.9? to show
|
||||
* refs/tags/v0.99.9a and friends.
|
||||
*/
|
||||
const char *tail;
|
||||
int slash = count_slash(refname);
|
||||
for (tail = refname; *tail && match_ref_slash < slash; )
|
||||
if (*tail++ == '/')
|
||||
slash--;
|
||||
if (!*tail)
|
||||
return 0;
|
||||
if (fnmatch(match_ref_pattern, tail, 0))
|
||||
return 0;
|
||||
if (!strncmp("refs/heads/", refname, 11))
|
||||
return append_head_ref(refname, sha1);
|
||||
if (!strncmp("refs/tags/", refname, 10))
|
||||
return append_tag_ref(refname, sha1);
|
||||
return append_ref(refname, sha1);
|
||||
}
|
||||
|
||||
static void snarf_refs(int head, int tag)
|
||||
{
|
||||
if (head) {
|
||||
@ -400,6 +434,27 @@ static int show_independent(struct commit **rev,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void append_one_rev(const char *av)
|
||||
{
|
||||
unsigned char revkey[20];
|
||||
if (!get_sha1(av, revkey)) {
|
||||
append_ref(av, revkey);
|
||||
return;
|
||||
}
|
||||
if (strchr(av, '*') || strchr(av, '?')) {
|
||||
/* glob style match */
|
||||
int saved_matches = ref_name_cnt;
|
||||
match_ref_pattern = av;
|
||||
match_ref_slash = count_slash(av);
|
||||
for_each_ref(append_matching_ref);
|
||||
if (saved_matches == ref_name_cnt &&
|
||||
ref_name_cnt < MAX_REVS)
|
||||
error("no matching refs with %s", av);
|
||||
return;
|
||||
}
|
||||
die("bad sha1 reference %s", av);
|
||||
}
|
||||
|
||||
int main(int ac, char **av)
|
||||
{
|
||||
struct commit *rev[MAX_REVS], *commit;
|
||||
@ -458,17 +513,20 @@ int main(int ac, char **av)
|
||||
if (all_heads + all_tags)
|
||||
snarf_refs(all_heads, all_tags);
|
||||
|
||||
while (0 < ac) {
|
||||
unsigned char revkey[20];
|
||||
if (get_sha1(*av, revkey))
|
||||
die("bad sha1 reference %s", *av);
|
||||
append_ref(*av, revkey);
|
||||
ac--; av++;
|
||||
if (ac) {
|
||||
while (0 < ac) {
|
||||
append_one_rev(*av);
|
||||
ac--; av++;
|
||||
}
|
||||
}
|
||||
|
||||
/* If still no revs, then add heads */
|
||||
if (!ref_name_cnt)
|
||||
else {
|
||||
/* If no revs given, then add heads */
|
||||
snarf_refs(1, 0);
|
||||
}
|
||||
if (!ref_name_cnt) {
|
||||
fprintf(stderr, "No revs to be shown.\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
for (num_rev = 0; ref_name[num_rev]; num_rev++) {
|
||||
unsigned char revkey[20];
|
||||
|
@ -17,8 +17,37 @@ IDs. When object ID computation changes, like in the previous case of
|
||||
swapping compression and hashing order, the person who is making the
|
||||
modification *should* take notice and update the test vectors here.
|
||||
'
|
||||
|
||||
################################################################
|
||||
# It appears that people are getting bitten by not installing
|
||||
# 'merge' (usually part of RCS package in binary distributions)
|
||||
# or have too old python without subprocess. Check them and error
|
||||
# out before running any tests. Also catch the bogosity of trying
|
||||
# to run tests without building while we are at it.
|
||||
|
||||
../git >/dev/null
|
||||
if test $? != 1
|
||||
then
|
||||
echo >&2 'You do not seem to have built git yet.'
|
||||
exit 1
|
||||
fi
|
||||
|
||||
merge >/dev/null 2>/dev/null
|
||||
if test $? == 127
|
||||
then
|
||||
echo >&2 'You do not seem to have "merge" installed.
|
||||
Please check INSTALL document.'
|
||||
exit 1
|
||||
fi
|
||||
|
||||
. ./test-lib.sh
|
||||
|
||||
"$PYTHON" -c 'import subprocess' || {
|
||||
echo >&2 'Your python seem to lack "subprocess" module.
|
||||
Please check INSTALL document.'
|
||||
exit 1
|
||||
}
|
||||
|
||||
################################################################
|
||||
# init-db has been done in an empty repository.
|
||||
# make sure it is empty.
|
||||
|
@ -12,10 +12,6 @@ test -f .git/config && rm .git/config
|
||||
git-repo-config core.penguin "little blue"
|
||||
|
||||
cat > expect << EOF
|
||||
#
|
||||
# This is the config file
|
||||
#
|
||||
|
||||
[core]
|
||||
penguin = little blue
|
||||
EOF
|
||||
@ -25,10 +21,6 @@ test_expect_success 'initial' 'cmp .git/config expect'
|
||||
git-repo-config Core.Movie BadPhysics
|
||||
|
||||
cat > expect << EOF
|
||||
#
|
||||
# This is the config file
|
||||
#
|
||||
|
||||
[core]
|
||||
penguin = little blue
|
||||
Movie = BadPhysics
|
||||
@ -39,10 +31,6 @@ test_expect_success 'mixed case' 'cmp .git/config expect'
|
||||
git-repo-config Cores.WhatEver Second
|
||||
|
||||
cat > expect << EOF
|
||||
#
|
||||
# This is the config file
|
||||
#
|
||||
|
||||
[core]
|
||||
penguin = little blue
|
||||
Movie = BadPhysics
|
||||
@ -55,10 +43,6 @@ test_expect_success 'similar section' 'cmp .git/config expect'
|
||||
git-repo-config CORE.UPPERCASE true
|
||||
|
||||
cat > expect << EOF
|
||||
#
|
||||
# This is the config file
|
||||
#
|
||||
|
||||
[core]
|
||||
penguin = little blue
|
||||
Movie = BadPhysics
|
||||
@ -76,10 +60,6 @@ test_expect_success 'replace with non-match (actually matching)' \
|
||||
'git-repo-config core.penguin "very blue" !kingpin'
|
||||
|
||||
cat > expect << EOF
|
||||
#
|
||||
# This is the config file
|
||||
#
|
||||
|
||||
[core]
|
||||
penguin = very blue
|
||||
Movie = BadPhysics
|
||||
|
@ -15,7 +15,7 @@ test "$(uname -o 2>/dev/null)" = Cygwin && exit 0
|
||||
. ./test-lib.sh
|
||||
|
||||
p0='no-funny'
|
||||
p1='tabs and spaces'
|
||||
p1='tabs ," (dq) and spaces'
|
||||
p2='just space'
|
||||
|
||||
cat >"$p0" <<\EOF
|
||||
@ -39,7 +39,7 @@ echo "$t0" >t0
|
||||
|
||||
echo 'just space
|
||||
no-funny
|
||||
"tabs\tand spaces"' >expected
|
||||
"tabs\t,\" (dq) and spaces"' >expected
|
||||
test_expect_success 'git-ls-files with-funny' \
|
||||
'git-update-index --add "$p1" &&
|
||||
git-ls-files >current &&
|
||||
@ -47,7 +47,7 @@ test_expect_success 'git-ls-files with-funny' \
|
||||
|
||||
echo 'just space
|
||||
no-funny
|
||||
tabs and spaces' >expected
|
||||
tabs ," (dq) and spaces' >expected
|
||||
test_expect_success 'git-ls-files -z with-funny' \
|
||||
'git-ls-files -z | tr \\0 \\012 >current &&
|
||||
diff -u expected current'
|
||||
@ -57,12 +57,12 @@ echo "$t1" >t1
|
||||
|
||||
echo 'just space
|
||||
no-funny
|
||||
"tabs\tand spaces"' >expected
|
||||
"tabs\t,\" (dq) and spaces"' >expected
|
||||
test_expect_success 'git-ls-tree with funny' \
|
||||
'git-ls-tree -r $t1 | sed -e "s/^[^ ]* //" >current &&
|
||||
diff -u expected current'
|
||||
|
||||
echo 'A "tabs\tand spaces"' >expected
|
||||
echo 'A "tabs\t,\" (dq) and spaces"' >expected
|
||||
test_expect_success 'git-diff-index with-funny' \
|
||||
'git-diff-index --name-status $t0 >current &&
|
||||
diff -u expected current'
|
||||
@ -72,7 +72,7 @@ test_expect_success 'git-diff-tree with-funny' \
|
||||
diff -u expected current'
|
||||
|
||||
echo 'A
|
||||
tabs and spaces' >expected
|
||||
tabs ," (dq) and spaces' >expected
|
||||
test_expect_success 'git-diff-index -z with-funny' \
|
||||
'git-diff-index -z --name-status $t0 | tr \\0 \\012 >current &&
|
||||
diff -u expected current'
|
||||
@ -81,23 +81,23 @@ test_expect_success 'git-diff-tree -z with-funny' \
|
||||
'git-diff-tree -z --name-status $t0 $t1 | tr \\0 \\012 >current &&
|
||||
diff -u expected current'
|
||||
|
||||
echo 'CNUM no-funny "tabs\tand spaces"' >expected
|
||||
echo 'CNUM no-funny "tabs\t,\" (dq) and spaces"' >expected
|
||||
test_expect_success 'git-diff-tree -C with-funny' \
|
||||
'git-diff-tree -C --find-copies-harder --name-status \
|
||||
$t0 $t1 | sed -e 's/^C[0-9]*/CNUM/' >current &&
|
||||
diff -u expected current'
|
||||
|
||||
echo 'RNUM no-funny "tabs\tand spaces"' >expected
|
||||
echo 'RNUM no-funny "tabs\t,\" (dq) and spaces"' >expected
|
||||
test_expect_success 'git-diff-tree delete with-funny' \
|
||||
'git-update-index --force-remove "$p0" &&
|
||||
git-diff-index -M --name-status \
|
||||
$t0 | sed -e 's/^R[0-9]*/RNUM/' >current &&
|
||||
diff -u expected current'
|
||||
|
||||
echo 'diff --git a/no-funny "b/tabs\tand spaces"
|
||||
echo 'diff --git a/no-funny "b/tabs\t,\" (dq) and spaces"
|
||||
similarity index NUM%
|
||||
rename from no-funny
|
||||
rename to "tabs\tand spaces"' >expected
|
||||
rename to "tabs\t,\" (dq) and spaces"' >expected
|
||||
|
||||
test_expect_success 'git-diff-tree delete with-funny' \
|
||||
'git-diff-index -M -p $t0 |
|
||||
@ -105,19 +105,19 @@ test_expect_success 'git-diff-tree delete with-funny' \
|
||||
diff -u expected current'
|
||||
|
||||
chmod +x "$p1"
|
||||
echo 'diff --git a/no-funny "b/tabs\tand spaces"
|
||||
echo 'diff --git a/no-funny "b/tabs\t,\" (dq) and spaces"
|
||||
old mode 100644
|
||||
new mode 100755
|
||||
similarity index NUM%
|
||||
rename from no-funny
|
||||
rename to "tabs\tand spaces"' >expected
|
||||
rename to "tabs\t,\" (dq) and spaces"' >expected
|
||||
|
||||
test_expect_success 'git-diff-tree delete with-funny' \
|
||||
'git-diff-index -M -p $t0 |
|
||||
sed -e "s/index [0-9]*%/index NUM%/" >current &&
|
||||
diff -u expected current'
|
||||
|
||||
echo >expected ' "tabs\tand spaces"
|
||||
echo >expected ' "tabs\t,\" (dq) and spaces"
|
||||
1 files changed, 0 insertions(+), 0 deletions(-)'
|
||||
test_expect_success 'git-diff-tree rename with-funny applied' \
|
||||
'git-diff-index -M -p $t0 |
|
||||
@ -125,7 +125,7 @@ test_expect_success 'git-diff-tree rename with-funny applied' \
|
||||
diff -u expected current'
|
||||
|
||||
echo >expected ' no-funny
|
||||
"tabs\tand spaces"
|
||||
"tabs\t,\" (dq) and spaces"
|
||||
2 files changed, 3 insertions(+), 3 deletions(-)'
|
||||
|
||||
test_expect_success 'git-diff-tree delete with-funny applied' \
|
||||
|
@ -7,8 +7,9 @@
|
||||
# an old counterpart
|
||||
|
||||
cd $(dirname $0) || exit 1
|
||||
: ${SHELL_PATH=/bin/sh}
|
||||
|
||||
tmp=$(mktemp /tmp/tmp-XXXXXXXX)
|
||||
tmp=`pwd`/.tmp$$
|
||||
|
||||
retval=0
|
||||
|
||||
@ -25,13 +26,17 @@ for i in $list; do
|
||||
both) pgm="old-git-upload-pack"; replace="old-git-fetch-pack --exec=$pgm";;
|
||||
esac
|
||||
|
||||
if which $pgm 2>/dev/null; then
|
||||
if where=`LANG=C LC_ALL=C which "$pgm" 2>/dev/null` &&
|
||||
case "$where" in
|
||||
"no "*) (exit 1) ;;
|
||||
esac
|
||||
then
|
||||
echo "Testing with $pgm"
|
||||
sed -e "s/git-fetch-pack/$replace/g" \
|
||||
-e "s/# old fails/warn/" < t5500-fetch-pack.sh > $tmp
|
||||
|
||||
sh $tmp || retval=$?
|
||||
rm $tmp
|
||||
"$SHELL_PATH" "$tmp" || retval=$?
|
||||
rm -f "$tmp"
|
||||
|
||||
test $retval != 0 && exit $retval
|
||||
else
|
||||
|
164
t/t6022-merge-rename.sh
Executable file
164
t/t6022-merge-rename.sh
Executable file
@ -0,0 +1,164 @@
|
||||
#!/bin/sh
|
||||
|
||||
test_description='Merge-recursive merging renames'
|
||||
. ./test-lib.sh
|
||||
|
||||
test_expect_success setup \
|
||||
'
|
||||
cat >A <<\EOF &&
|
||||
a aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||
b bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
|
||||
c cccccccccccccccccccccccccccccccccccccccccccccccc
|
||||
d dddddddddddddddddddddddddddddddddddddddddddddddd
|
||||
e eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
|
||||
f ffffffffffffffffffffffffffffffffffffffffffffffff
|
||||
g gggggggggggggggggggggggggggggggggggggggggggggggg
|
||||
h hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh
|
||||
i iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii
|
||||
j jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj
|
||||
k kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
|
||||
l llllllllllllllllllllllllllllllllllllllllllllllll
|
||||
m mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm
|
||||
n nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn
|
||||
o oooooooooooooooooooooooooooooooooooooooooooooooo
|
||||
EOF
|
||||
|
||||
cat >M <<\EOF &&
|
||||
A AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
B BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
|
||||
C CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
|
||||
D DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD
|
||||
E EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
|
||||
F FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
|
||||
G GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG
|
||||
H HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH
|
||||
I IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII
|
||||
J JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ
|
||||
K KKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKK
|
||||
L LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL
|
||||
M MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
|
||||
N NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN
|
||||
O OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO
|
||||
EOF
|
||||
|
||||
git add A M &&
|
||||
git commit -m initial &&
|
||||
git branch white &&
|
||||
git branch red &&
|
||||
git branch blue &&
|
||||
|
||||
sed -e "/^g /s/.*/g : master changes a line/" <A >A+ &&
|
||||
mv A+ A &&
|
||||
git commit -a -m "master updates A" &&
|
||||
|
||||
git checkout white &&
|
||||
sed -e "/^g /s/.*/g : white changes a line/" <A >B &&
|
||||
sed -e "/^G /s/.*/G : colored branch changes a line/" <M >N &&
|
||||
rm -f A M &&
|
||||
git update-index --add --remove A B M N &&
|
||||
git commit -m "white renames A->B, M->N" &&
|
||||
|
||||
git checkout red &&
|
||||
sed -e "/^g /s/.*/g : red changes a line/" <A >B &&
|
||||
sed -e "/^G /s/.*/G : colored branch changes a line/" <M >N &&
|
||||
rm -f A M &&
|
||||
git update-index --add --remove A B M N &&
|
||||
git commit -m "red renames A->B, M->N" &&
|
||||
|
||||
git checkout blue &&
|
||||
sed -e "/^g /s/.*/g : blue changes a line/" <A >C &&
|
||||
sed -e "/^G /s/.*/G : colored branch changes a line/" <M >N &&
|
||||
rm -f A M &&
|
||||
git update-index --add --remove A C M N &&
|
||||
git commit -m "blue renames A->C, M->N" &&
|
||||
|
||||
git checkout master'
|
||||
|
||||
test_expect_success 'pull renaming branch into unrenaming one' \
|
||||
'
|
||||
git show-branch
|
||||
git pull . white && {
|
||||
echo "BAD: should have conflicted"
|
||||
exit 1
|
||||
}
|
||||
git ls-files -s
|
||||
test "$(git ls-files -u B | wc -l)" -eq 3 || {
|
||||
echo "BAD: should have left stages for B"
|
||||
exit 1
|
||||
}
|
||||
test "$(git ls-files -s N | wc -l)" -eq 1 || {
|
||||
echo "BAD: should have merged N"
|
||||
exit 1
|
||||
}
|
||||
sed -ne "/^g/{
|
||||
p
|
||||
q
|
||||
}" B | grep master || {
|
||||
echo "BAD: should have listed our change first"
|
||||
exit 1
|
||||
}
|
||||
test "$(git diff white N | wc -l)" -eq 0 || {
|
||||
echo "BAD: should have taken colored branch"
|
||||
exit 1
|
||||
}
|
||||
'
|
||||
|
||||
test_expect_success 'pull renaming branch into another renaming one' \
|
||||
'
|
||||
git reset --hard
|
||||
git checkout red
|
||||
git pull . white && {
|
||||
echo "BAD: should have conflicted"
|
||||
exit 1
|
||||
}
|
||||
test "$(git ls-files -u B | wc -l)" -eq 3 || {
|
||||
echo "BAD: should have left stages"
|
||||
exit 1
|
||||
}
|
||||
test "$(git ls-files -s N | wc -l)" -eq 1 || {
|
||||
echo "BAD: should have merged N"
|
||||
exit 1
|
||||
}
|
||||
sed -ne "/^g/{
|
||||
p
|
||||
q
|
||||
}" B | grep red || {
|
||||
echo "BAD: should have listed our change first"
|
||||
exit 1
|
||||
}
|
||||
test "$(git diff white N | wc -l)" -eq 0 || {
|
||||
echo "BAD: should have taken colored branch"
|
||||
exit 1
|
||||
}
|
||||
'
|
||||
|
||||
test_expect_success 'pull unrenaming branch into renaming one' \
|
||||
'
|
||||
git reset --hard
|
||||
git show-branch
|
||||
git pull . master && {
|
||||
echo "BAD: should have conflicted"
|
||||
exit 1
|
||||
}
|
||||
test "$(git ls-files -u B | wc -l)" -eq 3 || {
|
||||
echo "BAD: should have left stages"
|
||||
exit 1
|
||||
}
|
||||
test "$(git ls-files -s N | wc -l)" -eq 1 || {
|
||||
echo "BAD: should have merged N"
|
||||
exit 1
|
||||
}
|
||||
sed -ne "/^g/{
|
||||
p
|
||||
q
|
||||
}" B | grep red || {
|
||||
echo "BAD: should have listed our change first"
|
||||
exit 1
|
||||
}
|
||||
test "$(git diff white N | wc -l)" -eq 0 || {
|
||||
echo "BAD: should have taken colored branch"
|
||||
exit 1
|
||||
}
|
||||
'
|
||||
|
||||
test_done
|
@ -149,7 +149,7 @@ test_expect_code () {
|
||||
test_done () {
|
||||
trap - exit
|
||||
case "$test_failure" in
|
||||
0)
|
||||
0)
|
||||
# We could:
|
||||
# cd .. && rm -fr trash
|
||||
# but that means we forbid any tests that use their own
|
||||
@ -172,15 +172,30 @@ test_done () {
|
||||
# t/ subdirectory and are run in trash subdirectory.
|
||||
PATH=$(pwd)/..:$PATH
|
||||
GIT_EXEC_PATH=$(pwd)/..
|
||||
export GIT_EXEC_PATH
|
||||
export PATH GIT_EXEC_PATH
|
||||
|
||||
# Similarly use ../compat/subprocess.py if our python does not
|
||||
# have subprocess.py on its own.
|
||||
PYTHON=`sed -e '1{
|
||||
s/^#!//
|
||||
q
|
||||
}' ../git-merge-recursive` || {
|
||||
error "You haven't built things yet, have you?"
|
||||
}
|
||||
"$PYTHON" -c 'import subprocess' 2>/dev/null || {
|
||||
PYTHONPATH=$(pwd)/../compat
|
||||
export PYTHONPATH
|
||||
}
|
||||
test -d ../templates/blt || {
|
||||
error "You haven't built things yet, have you?"
|
||||
}
|
||||
|
||||
# Test repository
|
||||
test=trash
|
||||
rm -fr "$test"
|
||||
mkdir "$test"
|
||||
cd "$test"
|
||||
git-init-db --template=../../templates/blt/ 2>/dev/null ||
|
||||
error "cannot run git-init-db"
|
||||
"$GIT_EXEC_PATH/git" init-db --template=../../templates/blt/ 2>/dev/null ||
|
||||
error "cannot run git init-db -- have you built things yet?"
|
||||
|
||||
mv .git/hooks .git/hooks-disabled
|
||||
|
||||
|
1
tree.c
1
tree.c
@ -200,7 +200,6 @@ int parse_tree_buffer(struct tree *item, void *buffer, unsigned long size)
|
||||
}
|
||||
if (obj)
|
||||
n_refs++;
|
||||
entry->parent = NULL; /* needs to be filled by the user */
|
||||
*list_p = entry;
|
||||
list_p = &entry->next;
|
||||
}
|
||||
|
1
tree.h
1
tree.h
@ -18,7 +18,6 @@ struct tree_entry_list {
|
||||
struct tree *tree;
|
||||
struct blob *blob;
|
||||
} item;
|
||||
struct tree_entry_list *parent;
|
||||
};
|
||||
|
||||
struct tree {
|
||||
|
@ -256,35 +256,30 @@ inside:
|
||||
}
|
||||
}
|
||||
|
||||
static int add_cacheinfo(const char *arg1, const char *arg2, const char *arg3)
|
||||
static int add_cacheinfo(unsigned int mode, const unsigned char *sha1,
|
||||
const char *path, int stage)
|
||||
{
|
||||
int size, len, option;
|
||||
unsigned int mode;
|
||||
unsigned char sha1[20];
|
||||
struct cache_entry *ce;
|
||||
|
||||
if (sscanf(arg1, "%o", &mode) != 1)
|
||||
return -1;
|
||||
if (get_sha1_hex(arg2, sha1))
|
||||
return -1;
|
||||
if (!verify_path(arg3))
|
||||
if (!verify_path(path))
|
||||
return -1;
|
||||
|
||||
len = strlen(arg3);
|
||||
len = strlen(path);
|
||||
size = cache_entry_size(len);
|
||||
ce = xmalloc(size);
|
||||
memset(ce, 0, size);
|
||||
|
||||
memcpy(ce->sha1, sha1, 20);
|
||||
memcpy(ce->name, arg3, len);
|
||||
ce->ce_flags = htons(len);
|
||||
memcpy(ce->name, path, len);
|
||||
ce->ce_flags = create_ce_flags(len, stage);
|
||||
ce->ce_mode = create_ce_mode(mode);
|
||||
option = allow_add ? ADD_CACHE_OK_TO_ADD : 0;
|
||||
option |= allow_replace ? ADD_CACHE_OK_TO_REPLACE : 0;
|
||||
if (add_cache_entry(ce, option))
|
||||
return error("%s: cannot add to the index - missing --add option?",
|
||||
arg3);
|
||||
report("add '%s'", arg3);
|
||||
path);
|
||||
report("add '%s'", path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -342,7 +337,24 @@ static void read_index_info(int line_termination)
|
||||
char *path_name;
|
||||
unsigned char sha1[20];
|
||||
unsigned int mode;
|
||||
int stage;
|
||||
|
||||
/* This reads lines formatted in one of three formats:
|
||||
*
|
||||
* (1) mode SP sha1 TAB path
|
||||
* The first format is what "git-apply --index-info"
|
||||
* reports, and used to reconstruct a partial tree
|
||||
* that is used for phony merge base tree when falling
|
||||
* back on 3-way merge.
|
||||
*
|
||||
* (2) mode SP type SP sha1 TAB path
|
||||
* The second format is to stuff git-ls-tree output
|
||||
* into the index file.
|
||||
*
|
||||
* (3) mode SP sha1 SP stage TAB path
|
||||
* This format is to put higher order stages into the
|
||||
* index file and matches git-ls-files --stage output.
|
||||
*/
|
||||
read_line(&buf, stdin, line_termination);
|
||||
if (buf.eof)
|
||||
break;
|
||||
@ -354,9 +366,19 @@ static void read_index_info(int line_termination)
|
||||
tab = strchr(ptr, '\t');
|
||||
if (!tab || tab - ptr < 41)
|
||||
goto bad_line;
|
||||
|
||||
if (tab[-2] == ' ' && '1' <= tab[-1] && tab[-1] <= '3') {
|
||||
stage = tab[-1] - '0';
|
||||
ptr = tab + 1; /* point at the head of path */
|
||||
tab = tab - 2; /* point at tail of sha1 */
|
||||
}
|
||||
else {
|
||||
stage = 0;
|
||||
ptr = tab + 1; /* point at the head of path */
|
||||
}
|
||||
|
||||
if (get_sha1_hex(tab - 40, sha1) || tab[-41] != ' ')
|
||||
goto bad_line;
|
||||
ptr = tab + 1;
|
||||
|
||||
if (line_termination && ptr[0] == '"')
|
||||
path_name = unquote_c_style(ptr, NULL);
|
||||
@ -382,7 +404,7 @@ static void read_index_info(int line_termination)
|
||||
* ptr[-41] is at the beginning of sha1
|
||||
*/
|
||||
ptr[-42] = ptr[-1] = 0;
|
||||
if (add_cacheinfo(buf.buf, ptr-41, path_name))
|
||||
if (add_cacheinfo(mode, sha1, path_name, stage))
|
||||
die("git-update-index: unable to update %s",
|
||||
path_name);
|
||||
}
|
||||
@ -449,10 +471,17 @@ int main(int argc, const char **argv)
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(path, "--cacheinfo")) {
|
||||
unsigned char sha1[20];
|
||||
unsigned int mode;
|
||||
|
||||
if (i+3 >= argc)
|
||||
die("git-update-index: --cacheinfo <mode> <sha1> <path>");
|
||||
if (add_cacheinfo(argv[i+1], argv[i+2], argv[i+3]))
|
||||
die("git-update-index: --cacheinfo cannot add %s", argv[i+3]);
|
||||
|
||||
if ((sscanf(argv[i+1], "%o", &mode) != 1) ||
|
||||
get_sha1_hex(argv[i+2], sha1) ||
|
||||
add_cacheinfo(mode, sha1, argv[i+3], 0))
|
||||
die("git-update-index: --cacheinfo"
|
||||
" cannot add %s", argv[i+3]);
|
||||
i += 3;
|
||||
continue;
|
||||
}
|
||||
|
2
usage.c
2
usage.c
@ -3,7 +3,7 @@
|
||||
*
|
||||
* Copyright (C) Linus Torvalds, 2005
|
||||
*/
|
||||
#include "cache.h"
|
||||
#include "git-compat-util.h"
|
||||
|
||||
static void report(const char *prefix, const char *err, va_list params)
|
||||
{
|
||||
|
@ -83,6 +83,8 @@ static int write_tree(struct cache_entry **cachep, int maxentries, const char *b
|
||||
return nr;
|
||||
}
|
||||
|
||||
static const char write_tree_usage[] = "git-write-tree [--missing-ok]";
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int i, funny;
|
||||
@ -96,7 +98,7 @@ int main(int argc, char **argv)
|
||||
if (!strcmp(argv[1], "--missing-ok"))
|
||||
missing_ok = 1;
|
||||
else
|
||||
die("unknown option %s", argv[1]);
|
||||
die(write_tree_usage);
|
||||
}
|
||||
|
||||
if (argc > 2)
|
||||
|
Loading…
Reference in New Issue
Block a user