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 += howto-index
|
||||||
ARTICLES += repository-layout
|
ARTICLES += repository-layout
|
||||||
ARTICLES += hooks
|
ARTICLES += hooks
|
||||||
|
ARTICLES += everyday
|
||||||
# with their own formatting rules.
|
# with their own formatting rules.
|
||||||
SP_ARTICLES = glossary howto/revert-branch-rebase
|
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
|
We have already talked about the "\--stdin" form of git-diff-tree
|
||||||
command that reads the list of commits and compares each commit
|
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:
|
the equivalent of the above command, and can be used like this:
|
||||||
|
|
||||||
$ git-whatchanged -p -S'if (frotz) {
|
$ 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.
|
area to store extracted patches.
|
||||||
|
|
||||||
--utf8, --keep::
|
--utf8, --keep::
|
||||||
Pass `--utf8` and `--keep` flags to `git-mailinfo` (see
|
Pass `-u` and `-k` flags to `git-mailinfo` (see
|
||||||
gitlink:git-mailinfo[1]).
|
gitlink:git-mailinfo[1]).
|
||||||
|
|
||||||
--binary::
|
--binary::
|
||||||
|
@ -8,16 +8,21 @@ git-bisect - Find the change that introduced a bug
|
|||||||
|
|
||||||
SYNOPSIS
|
SYNOPSIS
|
||||||
--------
|
--------
|
||||||
'git bisect' start
|
'git bisect' <subcommand> <options>
|
||||||
'git bisect' bad <rev>
|
|
||||||
'git bisect' good <rev>
|
|
||||||
'git bisect' reset [<branch>]
|
|
||||||
'git bisect' visualize
|
|
||||||
'git bisect' replay <logfile>
|
|
||||||
'git bisect' log
|
|
||||||
|
|
||||||
DESCRIPTION
|
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
|
This command uses 'git-rev-list --bisect' option to help drive
|
||||||
the binary search process to find which change introduced a bug,
|
the binary search process to find which change introduced a bug,
|
||||||
given an old "good" commit object name and a later "bad" commit
|
given an old "good" commit object name and a later "bad" commit
|
||||||
@ -26,10 +31,10 @@ object name.
|
|||||||
The way you use it is:
|
The way you use it is:
|
||||||
|
|
||||||
------------------------------------------------
|
------------------------------------------------
|
||||||
git bisect start
|
$ git bisect start
|
||||||
git bisect bad # Current version is bad
|
$ git bisect bad # Current version is bad
|
||||||
git bisect good v2.6.13-rc2 # v2.6.13-rc2 was the last version
|
$ git bisect good v2.6.13-rc2 # v2.6.13-rc2 was the last version
|
||||||
# tested that was good
|
# tested that was good
|
||||||
------------------------------------------------
|
------------------------------------------------
|
||||||
|
|
||||||
When you give at least one bad and one good versions, it will
|
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
|
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
|
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
|
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
|
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
|
During the bisection process, you can say
|
||||||
|
|
||||||
git bisect visualize
|
------------
|
||||||
|
$ git bisect visualize
|
||||||
|
------------
|
||||||
|
|
||||||
to see the currently remaining suspects in `gitk`.
|
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
|
log` shows what you have done so far. You can truncate its
|
||||||
output somewhere and save it in a file, and run
|
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
|
if you find later you made a mistake telling good/bad about a
|
||||||
revision.
|
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
|
Author
|
||||||
------
|
------
|
||||||
|
@ -9,7 +9,7 @@ git-checkout-index - Copy files from the index to the working directory
|
|||||||
SYNOPSIS
|
SYNOPSIS
|
||||||
--------
|
--------
|
||||||
'git-checkout-index' [-u] [-q] [-a] [-f] [-n] [--prefix=<string>]
|
'git-checkout-index' [-u] [-q] [-a] [-f] [-n] [--prefix=<string>]
|
||||||
[--] <file>...
|
[--stage=<number>] [--] <file>...
|
||||||
|
|
||||||
DESCRIPTION
|
DESCRIPTION
|
||||||
-----------
|
-----------
|
||||||
@ -40,58 +40,80 @@ OPTIONS
|
|||||||
When creating files, prepend <string> (usually a directory
|
When creating files, prepend <string> (usually a directory
|
||||||
including a trailing /)
|
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.
|
Do not interpret any more arguments as options.
|
||||||
|
|
||||||
The order of the flags used to matter, but not anymore.
|
The order of the flags used to matter, but not anymore.
|
||||||
|
|
||||||
Just doing "git-checkout-index" does nothing. You probably meant
|
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 -a`. And if you want to force it, you want
|
||||||
"git-checkout-index -f -a".
|
`git-checkout-index -f -a`.
|
||||||
|
|
||||||
Intuitiveness is not the goal here. Repeatability is. The reason for
|
Intuitiveness is not the goal here. Repeatability is. The reason for
|
||||||
the "no arguments means no work" thing is that from scripts you are
|
the "no arguments means no work" behavior is that from scripts you are
|
||||||
supposed to be able to do things like:
|
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
|
which will force all existing `*.h` files to be replaced with their
|
||||||
cached copies. If an empty command line implied "all", then this would
|
cached copies. If an empty command line implied "all", then this would
|
||||||
force-refresh everything in the index, which was not the point.
|
force-refresh everything in the index, which was not the point.
|
||||||
|
|
||||||
To update and refresh only the files already checked out:
|
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
|
EXAMPLES
|
||||||
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
|
To update and refresh only the files already checked out::
|
||||||
scripting!).
|
+
|
||||||
|
----------------
|
||||||
|
$ git-checkout-index -n -f -a && git-update-index --ignore-missing --refresh
|
||||||
|
----------------
|
||||||
|
|
||||||
The prefix ability basically makes it trivial to use
|
Using `git-checkout-index` to "export an entire tree"::
|
||||||
git-checkout-index as an "export as tree" function. Just read the
|
The prefix ability basically makes it trivial to use
|
||||||
desired tree into the index, and do a
|
`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
|
+
|
||||||
|
----------------
|
||||||
and git-checkout-index will "export" the index into the specified
|
$ git-checkout-index --prefix=git-export-dir/ -a
|
||||||
|
----------------
|
||||||
|
+
|
||||||
|
`git-checkout-index` will "export" the index into the specified
|
||||||
directory.
|
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
|
Export files with a prefix::
|
||||||
prefixed with the specified string, so you can also do something like
|
+
|
||||||
|
----------------
|
||||||
|
$ 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
|
Author
|
||||||
------
|
------
|
||||||
Written by Linus Torvalds <torvalds@osdl.org>
|
Written by Linus Torvalds <torvalds@osdl.org>
|
||||||
|
|
||||||
|
|
||||||
Documentation
|
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
|
GIT
|
||||||
---
|
---
|
||||||
|
@ -7,7 +7,7 @@ git-cherry-pick - Apply the change introduced by an existing commit.
|
|||||||
|
|
||||||
SYNOPSIS
|
SYNOPSIS
|
||||||
--------
|
--------
|
||||||
'git-cherry-pick' [-n] [-r] <commit>
|
'git-cherry-pick' [--edit] [-n] [-r] <commit>
|
||||||
|
|
||||||
DESCRIPTION
|
DESCRIPTION
|
||||||
-----------
|
-----------
|
||||||
@ -20,15 +20,19 @@ OPTIONS
|
|||||||
<commit>::
|
<commit>::
|
||||||
Commit to cherry-pick.
|
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
|
Usually the command appends which commit was
|
||||||
cherry-picked after the original commit message when
|
cherry-picked after the original commit message when
|
||||||
making a commit. This option, '--replay', causes it to
|
making a commit. This option, '--replay', causes it to
|
||||||
use the original commit message intact. This is useful
|
use the original commit message intact. This is useful
|
||||||
when you are reordering the patches in your private tree
|
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
|
Usually the command automatically creates a commit with
|
||||||
a commit log message stating which commit was
|
a commit log message stating which commit was
|
||||||
cherry-picked. This flag applies the change necessary
|
cherry-picked. This flag applies the change necessary
|
||||||
|
@ -7,7 +7,7 @@ git-commit - Record your changes
|
|||||||
|
|
||||||
SYNOPSIS
|
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
|
DESCRIPTION
|
||||||
-----------
|
-----------
|
||||||
@ -22,7 +22,7 @@ information.
|
|||||||
|
|
||||||
OPTIONS
|
OPTIONS
|
||||||
-------
|
-------
|
||||||
-a::
|
-a|--all::
|
||||||
Update all paths in the index file.
|
Update all paths in the index file.
|
||||||
|
|
||||||
-c or -C <commit>::
|
-c or -C <commit>::
|
||||||
@ -39,23 +39,29 @@ OPTIONS
|
|||||||
-m <msg>::
|
-m <msg>::
|
||||||
Use the given <msg> as the commit message.
|
Use the given <msg> as the commit message.
|
||||||
|
|
||||||
-s::
|
-s|--signoff::
|
||||||
Add Signed-off-by line at the end of the commit message.
|
Add Signed-off-by line at the end of the commit message.
|
||||||
|
|
||||||
-v::
|
-v|--verify::
|
||||||
Look for suspicious lines the commit introduces, and
|
Look for suspicious lines the commit introduces, and
|
||||||
abort committing if there is one. The definition of
|
abort committing if there is one. The definition of
|
||||||
'suspicious lines' is currently the lines that has
|
'suspicious lines' is currently the lines that has
|
||||||
trailing whitespaces, and the lines whose indentation
|
trailing whitespaces, and the lines whose indentation
|
||||||
has a SP character immediately followed by a TAB
|
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
|
The message taken from file with `-F`, command line with
|
||||||
`-m`, and from file with `-C` are usually used as the
|
`-m`, and from file with `-C` are usually used as the
|
||||||
commit log message unmodified. This option lets you
|
commit log message unmodified. This option lets you
|
||||||
further edit the message taken from these sources.
|
further edit the message taken from these sources.
|
||||||
|
|
||||||
|
--::
|
||||||
|
Do not interpret any more arguments as options.
|
||||||
|
|
||||||
<file>...::
|
<file>...::
|
||||||
Update specified paths in the index file before committing.
|
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.
|
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
|
Instead of calling cvsps, read the provided cvsps output file. Useful
|
||||||
for debugging or when cvsps is being handled outside cvsimport.
|
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 combination of what is compared with what is determined by
|
||||||
the number of ents given to the command.
|
the number of ents given to the command.
|
||||||
|
|
||||||
`----------------`--------`-----------------------------`------------------
|
* When no <ent> is given, the working tree and the index
|
||||||
Number of ents Options What's Compared Underlying command
|
file is compared, using `git-diff-files`.
|
||||||
---------------------------------------------------------------------------
|
|
||||||
0 - index file and working tree git-diff-files
|
* When one <ent> is given, the working tree and the named
|
||||||
1 --cached ent and index file git-diff-index
|
tree is compared, using `git-diff-index`. The option
|
||||||
1 - ent and working tree git-diff-index
|
`--cached` can be given to compare the index file and
|
||||||
2 - two ents git-diff-tree
|
the named tree.
|
||||||
---------------------------------------------------------------------------
|
|
||||||
|
* When two <ent>s are given, these two trees are compared
|
||||||
|
using `git-diff-tree`.
|
||||||
|
|
||||||
OPTIONS
|
OPTIONS
|
||||||
-------
|
-------
|
||||||
|
@ -18,7 +18,7 @@ the objects necessary to complete them.
|
|||||||
|
|
||||||
The ref names and their object names of fetched refs are stored
|
The ref names and their object names of fetched refs are stored
|
||||||
in `.git/FETCH_HEAD`. This information is left for a later merge
|
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
|
OPTIONS
|
||||||
|
@ -8,7 +8,7 @@ git-format-patch - Prepare patches for e-mail submission.
|
|||||||
|
|
||||||
SYNOPSIS
|
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
|
DESCRIPTION
|
||||||
-----------
|
-----------
|
||||||
@ -32,23 +32,34 @@ processing with applymbox.
|
|||||||
|
|
||||||
OPTIONS
|
OPTIONS
|
||||||
-------
|
-------
|
||||||
-o <dir>::
|
-o|--output-directory <dir>::
|
||||||
Use <dir> to store the resulting files, instead of the
|
Use <dir> to store the resulting files, instead of the
|
||||||
current working directory.
|
current working directory.
|
||||||
|
|
||||||
-n::
|
-n|--numbered::
|
||||||
Name output in '[PATCH n/m]' format.
|
Name output in '[PATCH n/m]' format.
|
||||||
|
|
||||||
-k::
|
-k|--keep-subject::
|
||||||
Do not strip/add '[PATCH]' from the first line of the
|
Do not strip/add '[PATCH]' from the first line of the
|
||||||
commit log message.
|
commit log message.
|
||||||
|
|
||||||
--author, --date::
|
-a|--author, -d|--date::
|
||||||
Output From: and Date: headers for commits made by
|
Output From: and Date: headers for commits made by
|
||||||
yourself as well. Usually these are output only for
|
yourself as well. Usually these are output only for
|
||||||
commits made by people other than yourself.
|
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
|
Format the output files for closer to mbox format by
|
||||||
adding a phony Unix "From " line, so they can be
|
adding a phony Unix "From " line, so they can be
|
||||||
concatenated together and fed to `git-applymbox`.
|
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
|
SYNOPSIS
|
||||||
--------
|
--------
|
||||||
'git-hash-object' [-t <type>] [-w] <any-file-on-the-filesystem>
|
'git-hash-object' [-t <type>] [-w] [--stdin] [--] <file>...
|
||||||
|
|
||||||
DESCRIPTION
|
DESCRIPTION
|
||||||
-----------
|
-----------
|
||||||
@ -29,6 +29,9 @@ OPTIONS
|
|||||||
-w::
|
-w::
|
||||||
Actually write the object into the object database.
|
Actually write the object into the object database.
|
||||||
|
|
||||||
|
--stdin::
|
||||||
|
Read the object from standard input instead of from a file.
|
||||||
|
|
||||||
Author
|
Author
|
||||||
------
|
------
|
||||||
Written by Junio C Hamano <junkio@cox.net>
|
Written by Junio C Hamano <junkio@cox.net>
|
||||||
|
@ -14,6 +14,12 @@ DESCRIPTION
|
|||||||
-----------
|
-----------
|
||||||
Downloads a remote git repository via HTTP.
|
Downloads a remote git repository via HTTP.
|
||||||
|
|
||||||
|
OPTIONS
|
||||||
|
-------
|
||||||
|
commit-id::
|
||||||
|
Either the hash or the filename under [URL]/refs/ to
|
||||||
|
pull.
|
||||||
|
|
||||||
-c::
|
-c::
|
||||||
Get the commit objects.
|
Get the commit objects.
|
||||||
-t::
|
-t::
|
||||||
|
@ -8,7 +8,14 @@ git-init-db - Creates an empty git repository
|
|||||||
|
|
||||||
SYNOPSIS
|
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
|
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 `.git/object/??/`, `.git/refs/heads` and `.git/refs/tags` directories,
|
||||||
and links `.git/HEAD` symbolically to `.git/refs/heads/master`.
|
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.
|
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 -
|
environment variable then the sha1 directories are created underneath -
|
||||||
otherwise the default `$GIT_DIR/objects` directory is used.
|
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
|
Author
|
||||||
|
@ -17,7 +17,7 @@ Displays the references other repository has.
|
|||||||
|
|
||||||
OPTIONS
|
OPTIONS
|
||||||
-------
|
-------
|
||||||
--heads --tags::
|
-h|--heads, -t|--tags::
|
||||||
Limit to only refs/heads and refs/tags, respectively.
|
Limit to only refs/heads and refs/tags, respectively.
|
||||||
These options are _not_ mutually exclusive; when given
|
These options are _not_ mutually exclusive; when given
|
||||||
both, references stored in refs/heads and refs/tags are
|
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
|
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
|
DESCRIPTION
|
||||||
-----------
|
-----------
|
||||||
Lists the contents of a tree object, like what "/bin/ls -a" does
|
Lists the contents of a given tree object, like what "/bin/ls -a" does
|
||||||
in the current working directory.
|
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
|
OPTIONS
|
||||||
-------
|
-------
|
||||||
@ -21,36 +24,48 @@ OPTIONS
|
|||||||
Id of a tree-ish.
|
Id of a tree-ish.
|
||||||
|
|
||||||
-d::
|
-d::
|
||||||
show only the named tree entry itself, not its children
|
Show only the named tree entry itself, not its children.
|
||||||
|
|
||||||
-r::
|
-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::
|
-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::
|
paths::
|
||||||
When paths are given, show them. Otherwise implicitly
|
When paths are given, show them (note that this isn't really raw
|
||||||
uses the root level of the tree as the sole path argument.
|
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
|
Output Format
|
||||||
-------------
|
-------------
|
||||||
<mode> SP <type> SP <object> TAB <file>
|
<mode> SP <type> SP <object> TAB <file>
|
||||||
|
|
||||||
When `-z` option is not used, TAB, LF, and backslash characters
|
When the `-z` option is not used, TAB, LF, and backslash characters
|
||||||
in pathnames are represented as `\t`, `\n`, and `\\`,
|
in pathnames are represented as `\t`, `\n`, and `\\`, respectively.
|
||||||
respectively.
|
|
||||||
|
|
||||||
|
|
||||||
Author
|
Author
|
||||||
------
|
------
|
||||||
Written by Linus Torvalds <torvalds@osdl.org>
|
Written by Petr Baudis <pasky@suse.cz>
|
||||||
Completely rewritten from scratch by Junio C Hamano <junkio@cox.net>
|
Completely rewritten from scratch by Junio C Hamano <junkio@cox.net>,
|
||||||
|
another major rewrite by Linus Torvalds <torvalds@osdl.org>
|
||||||
|
|
||||||
Documentation
|
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
|
GIT
|
||||||
---
|
---
|
||||||
|
@ -20,7 +20,7 @@ files are passed as arguments 5, 6 and 7.
|
|||||||
OPTIONS
|
OPTIONS
|
||||||
-------
|
-------
|
||||||
--::
|
--::
|
||||||
Interpret all following arguments as filenames.
|
Do not interpret any more arguments as options.
|
||||||
|
|
||||||
-a::
|
-a::
|
||||||
Run merge against all files in the index that need merging.
|
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
|
SYNOPSIS
|
||||||
--------
|
--------
|
||||||
'git-mv' [-f] [-n] <source> <destination>
|
'git-mv' <options>... <args>...
|
||||||
'git-mv' [-f] [-n] [-k] <source> ... <destination directory>
|
|
||||||
|
|
||||||
DESCRIPTION
|
DESCRIPTION
|
||||||
-----------
|
-----------
|
||||||
This script is used to move or rename a file, directory or symlink.
|
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
|
In the first form, it renames <source>, which must exist and be either
|
||||||
a file, symlink or directory, to <destination>.
|
a file, symlink or directory, to <destination>.
|
||||||
In the second form, the last argument has to be an existing
|
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
|
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
|
DESCRIPTION
|
||||||
@ -70,6 +70,10 @@ base-name::
|
|||||||
that are packed and not in the local object store
|
that are packed and not in the local object store
|
||||||
(i.e. borrowed from an alternate).
|
(i.e. borrowed from an alternate).
|
||||||
|
|
||||||
|
--non-empty::
|
||||||
|
Only create a packed archive if it would contain at
|
||||||
|
least one object.
|
||||||
|
|
||||||
Author
|
Author
|
||||||
------
|
------
|
||||||
Written by Linus Torvalds <torvalds@osdl.org>
|
Written by Linus Torvalds <torvalds@osdl.org>
|
||||||
|
@ -9,19 +9,22 @@ residing in a pack file.
|
|||||||
|
|
||||||
SYNOPSIS
|
SYNOPSIS
|
||||||
--------
|
--------
|
||||||
'git-prune-packed'
|
'git-prune-packed' [-n]
|
||||||
|
|
||||||
|
|
||||||
DESCRIPTION
|
DESCRIPTION
|
||||||
-----------
|
-----------
|
||||||
This program search the GIT_OBJECT_DIR for all objects that currently exist in
|
This program search the `$GIT_OBJECT_DIR` for all objects that currently
|
||||||
a pack file as well as the independent object directories.
|
exist in a pack file as well as the independent object directories.
|
||||||
|
|
||||||
All such extra objects are removed.
|
All such extra objects are removed.
|
||||||
|
|
||||||
A pack is a collection of objects, individually compressed, with delta
|
A pack is a collection of objects, individually compressed, with delta
|
||||||
compression applied, stored in a single file, with an associated index file.
|
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
|
OPTIONS
|
||||||
-------
|
-------
|
||||||
|
@ -8,15 +8,16 @@ git-prune - Prunes all unreachable objects from the object database
|
|||||||
|
|
||||||
SYNOPSIS
|
SYNOPSIS
|
||||||
--------
|
--------
|
||||||
'git-prune' [-n]
|
'git-prune' [-n] [--] [<head>...]
|
||||||
|
|
||||||
DESCRIPTION
|
DESCRIPTION
|
||||||
-----------
|
-----------
|
||||||
|
|
||||||
This runs `git-fsck-objects --unreachable` using the heads
|
This runs `git-fsck-objects --unreachable` using all the refs
|
||||||
specified on the command line (or `$GIT_DIR/refs/heads/\*` and
|
available in `$GIT_DIR/refs`, optionally with additional set of
|
||||||
`$GIT_DIR/refs/tags/\*` if none is specified), and prunes all
|
objects specified on the command line, and prunes all
|
||||||
unreachable objects from the object database. In addition, it
|
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
|
prunes the unpacked objects that are also found in packs by
|
||||||
running `git prune-packed`.
|
running `git prune-packed`.
|
||||||
|
|
||||||
@ -27,6 +28,24 @@ OPTIONS
|
|||||||
Do not remove anything; just report what it would
|
Do not remove anything; just report what it would
|
||||||
remove.
|
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
|
Author
|
||||||
------
|
------
|
||||||
|
@ -16,6 +16,10 @@ DESCRIPTION
|
|||||||
Updates remote refs using local refs, while sending objects
|
Updates remote refs using local refs, while sending objects
|
||||||
necessary to complete the given refs.
|
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
|
OPTIONS
|
||||||
-------
|
-------
|
||||||
@ -31,6 +35,7 @@ include::pull-fetch-param.txt[]
|
|||||||
This flag disables the check. What this means is that the
|
This flag disables the check. What this means is that the
|
||||||
local repository can lose commits; use it with care.
|
local repository can lose commits; use it with care.
|
||||||
|
|
||||||
|
|
||||||
Author
|
Author
|
||||||
------
|
------
|
||||||
Written by Junio C Hamano <junkio@cox.net>
|
Written by Junio C Hamano <junkio@cox.net>
|
||||||
|
@ -8,22 +8,22 @@ git-read-tree - Reads tree information into the index
|
|||||||
|
|
||||||
SYNOPSIS
|
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
|
DESCRIPTION
|
||||||
-----------
|
-----------
|
||||||
Reads the tree information given by <tree-ish> into the index,
|
Reads the tree information given by <tree-ish> into the index,
|
||||||
but does not actually *update* any of the files it "caches". (see:
|
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
|
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
|
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
|
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.
|
the files in the work tree with the result of the merge.
|
||||||
|
|
||||||
Trivial merges are done by "git-read-tree" itself. Only conflicting paths
|
Trivial merges are done by `git-read-tree` itself. Only conflicting paths
|
||||||
will be in unmerged state when "git-read-tree" returns.
|
will be in unmerged state when `git-read-tree` returns.
|
||||||
|
|
||||||
OPTIONS
|
OPTIONS
|
||||||
-------
|
-------
|
||||||
@ -56,7 +56,7 @@ OPTIONS
|
|||||||
|
|
||||||
Merging
|
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
|
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
|
fast-forward merge with 2 trees, or a 3-way merge if 3 trees are
|
||||||
provided.
|
provided.
|
||||||
@ -65,23 +65,23 @@ provided.
|
|||||||
Single Tree Merge
|
Single Tree Merge
|
||||||
~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~
|
||||||
If only 1 tree is specified, git-read-tree operates as if the user did not
|
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
|
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
|
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).
|
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
|
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
|
`git-checkout-index -f -u -a`, the `git-checkout-index` only checks out
|
||||||
the stuff that really changed.
|
the stuff that really changed.
|
||||||
|
|
||||||
This is used to avoid unnecessary false hits when "git-diff-files" is
|
This is used to avoid unnecessary false hits when `git-diff-files` is
|
||||||
run after git-read-tree.
|
run after `git-read-tree`.
|
||||||
|
|
||||||
|
|
||||||
Two Tree Merge
|
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
|
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
|
of a foreign tree, which is simply ahead of $H (i.e. we are in a
|
||||||
fast forward situation).
|
fast forward situation).
|
||||||
@ -94,7 +94,7 @@ the following:
|
|||||||
|
|
||||||
2. The user wants to fast-forward to $M.
|
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".
|
that no local change is lost as the result of this "merge".
|
||||||
Here are the "carry forward" rules:
|
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
|
When this form of git-read-tree returns successfully, you can
|
||||||
see what "local changes" you made are carried forward by running
|
see what "local changes" you made are carried forward by running
|
||||||
"git-diff-index --cached $M". Note that this does not
|
`git-diff-index --cached $M`. Note that this does not
|
||||||
necessarily match "git-diff-index --cached $H" would have
|
necessarily match `git-diff-index --cached $H` would have
|
||||||
produced before such a two tree merge. This is because of cases
|
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
|
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
|
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
|
--cached $H` would have told you about the change before this
|
||||||
merge, but it would not show in "git-diff-index --cached $M"
|
merge, but it would not show in `git-diff-index --cached $M`
|
||||||
output after two-tree merge.
|
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
|
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.
|
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.
|
starts out at 1.
|
||||||
|
|
||||||
This means that you can do
|
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
|
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
|
"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
|
a file that matches in all respects in the following states, it
|
||||||
"collapses" back to "stage0":
|
"collapses" back to "stage0":
|
||||||
|
|
||||||
- stage 2 and 3 are the same; take one or the other (it makes no
|
- 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 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 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
|
will complain about unmerged entries if it sees a single entry that is not
|
||||||
stage 0.
|
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
|
matching "stage1" entry if it exists too. .. all the normal
|
||||||
trivial rules ..
|
trivial rules ..
|
||||||
|
|
||||||
You would normally use "git-merge-index" with supplied
|
You would normally use `git-merge-index` with supplied
|
||||||
"git-merge-one-file" to do this last step. The script
|
`git-merge-one-file` to do this last step. The script updates
|
||||||
does not touch the files in the work tree, and the entire merge
|
the files in the working tree as it merges each path and at the
|
||||||
happens in the index file. In other words, there is no need to
|
end of a successful merge.
|
||||||
worry about what is in the working directory, since it is never
|
|
||||||
shown and never used.
|
|
||||||
|
|
||||||
When you start a 3-way merge with an index file that is already
|
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
|
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.
|
file that does not match stage 2.
|
||||||
|
|
||||||
This is done to prevent you from losing your work-in-progress
|
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:
|
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 do random edits, without running git-update-index. And then
|
||||||
you notice that the tip of your "upstream" tree has advanced
|
you notice that the tip of your "upstream" tree has advanced
|
||||||
since you pulled from him:
|
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
|
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
|
some edits since. Three-way merge makes sure that you have not
|
||||||
added or modified index entries since $JC, and if you haven't,
|
added or modified index entries since $JC, and if you haven't,
|
||||||
then does the right thing. So with the following sequence:
|
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
|
$ git-read-tree -m -u `git-merge-base $JC $LT` $JC $LT
|
||||||
$ echo "Merge with Linus" | \
|
$ git-merge-index git-merge-one-file -a
|
||||||
git-commit-tree `git-write-tree` -p $JC -p $LT
|
$ 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
|
your work-in-progress changes, and your work tree would be
|
||||||
updated to the result of the merge.
|
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
|
See Also
|
||||||
--------
|
--------
|
||||||
|
@ -71,6 +71,10 @@ packed and is served via a dumb transport.
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
exec git-update-server-info
|
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
|
OPTIONS
|
||||||
-------
|
-------
|
||||||
<directory>::
|
<directory>::
|
||||||
|
@ -9,7 +9,7 @@ objects into pack files.
|
|||||||
|
|
||||||
SYNOPSIS
|
SYNOPSIS
|
||||||
--------
|
--------
|
||||||
'git-repack' [-a] [-d]
|
'git-repack' [-a] [-d] [-l] [-n]
|
||||||
|
|
||||||
DESCRIPTION
|
DESCRIPTION
|
||||||
-----------
|
-----------
|
||||||
@ -39,6 +39,13 @@ OPTIONS
|
|||||||
After packing, if the newly created packs make some
|
After packing, if the newly created packs make some
|
||||||
existing packs redundant, remove the redundant packs.
|
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
|
Author
|
||||||
------
|
------
|
||||||
|
@ -7,7 +7,7 @@ git-revert - Revert an existing commit.
|
|||||||
|
|
||||||
SYNOPSIS
|
SYNOPSIS
|
||||||
--------
|
--------
|
||||||
'git-revert' [-n] <commit>
|
'git-revert' [--edit | --no-edit] [-n] <commit>
|
||||||
|
|
||||||
DESCRIPTION
|
DESCRIPTION
|
||||||
-----------
|
-----------
|
||||||
@ -20,7 +20,16 @@ OPTIONS
|
|||||||
<commit>::
|
<commit>::
|
||||||
Commit to revert.
|
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
|
Usually the command automatically creates a commit with
|
||||||
a commit log message stating which commit was reverted.
|
a commit log message stating which commit was reverted.
|
||||||
This flag applies the change necessary to revert the
|
This flag applies the change necessary to revert the
|
||||||
|
@ -7,23 +7,40 @@ git-show-branch - Show branches and their commits.
|
|||||||
|
|
||||||
SYNOPSIS
|
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
|
DESCRIPTION
|
||||||
-----------
|
-----------
|
||||||
Shows the head commits from the named <reference> (or all refs under
|
|
||||||
$GIT_DIR/refs/heads), and displays concise list of commit logs
|
Shows the commit ancestry graph starting from the commits named
|
||||||
to show their relationship semi-visually.
|
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
|
OPTIONS
|
||||||
-------
|
-------
|
||||||
<reference>::
|
<rev>::
|
||||||
Name of the reference under $GIT_DIR/refs/.
|
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::
|
--all --heads --tags::
|
||||||
Show all refs under $GIT_DIR/refs, $GIT_DIR/refs/heads,
|
Show all refs under $GIT_DIR/refs, $GIT_DIR/refs/heads,
|
||||||
and $GIT_DIR/refs/tags, respectively.
|
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>::
|
--more=<n>::
|
||||||
Usually the command stops output upon showing the commit
|
Usually the command stops output upon showing the commit
|
||||||
that is the common ancestor of all the branches. This
|
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>]
|
'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
|
DESCRIPTION
|
||||||
-----------
|
-----------
|
||||||
Adds a 'tag' reference in .git/refs/tags/
|
Adds a 'tag' reference in .git/refs/tags/
|
||||||
@ -52,6 +32,26 @@ GnuPG key for signing.
|
|||||||
|
|
||||||
`-d <tag>` deletes the tag.
|
`-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
|
Author
|
||||||
------
|
------
|
||||||
|
@ -123,7 +123,9 @@ merging.
|
|||||||
|
|
||||||
To pretend you have a file with mode and sha1 at path, say:
|
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
|
'--info-only' is used to register files without placing them in the object
|
||||||
database. This is useful for status-only repositories.
|
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
|
useful when the file is available, but you do not wish to update the
|
||||||
object database.
|
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
|
Examples
|
||||||
--------
|
--------
|
||||||
To update and refresh only the files already checked out:
|
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
|
Configuration
|
||||||
@ -146,12 +207,18 @@ Configuration
|
|||||||
|
|
||||||
The command honors `core.filemode` configuration variable. If
|
The command honors `core.filemode` configuration variable. If
|
||||||
your repository is on an filesystem whose executable bits are
|
your repository is on an filesystem whose executable bits are
|
||||||
unreliable, this should be set to 'false'. This causes the
|
unreliable, this should be set to 'false' (see gitlink:git-repo-config[1]).
|
||||||
command to ignore differences in file modes recorded in the
|
This causes the command to ignore differences in file modes recorded
|
||||||
index and the file mode on the filesystem if they differ only on
|
in the index and the file mode on the filesystem if they differ only on
|
||||||
executable bit. On such an unfortunate filesystem, you may
|
executable bit. On such an unfortunate filesystem, you may
|
||||||
need to use `git-update-index --chmod=`.
|
need to use `git-update-index --chmod=`.
|
||||||
|
|
||||||
|
|
||||||
|
See Also
|
||||||
|
--------
|
||||||
|
gitlink:git-repo-config[1]
|
||||||
|
|
||||||
|
|
||||||
Author
|
Author
|
||||||
------
|
------
|
||||||
Written by Linus Torvalds <torvalds@osdl.org>
|
Written by Linus Torvalds <torvalds@osdl.org>
|
||||||
|
@ -22,7 +22,7 @@ pull decisions. This command generates such auxiliary files.
|
|||||||
OPTIONS
|
OPTIONS
|
||||||
-------
|
-------
|
||||||
|
|
||||||
--force::
|
-f|--force::
|
||||||
Update the info files from scratch.
|
Update the info files from scratch.
|
||||||
|
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@ git-verify-pack - Validate packed git archive files.
|
|||||||
|
|
||||||
SYNOPSIS
|
SYNOPSIS
|
||||||
--------
|
--------
|
||||||
'git-verify-pack' [-v] <pack>.idx ...
|
'git-verify-pack' [-v] [--] <pack>.idx ...
|
||||||
|
|
||||||
|
|
||||||
DESCRIPTION
|
DESCRIPTION
|
||||||
@ -25,6 +25,8 @@ OPTIONS
|
|||||||
-v::
|
-v::
|
||||||
After verifying the pack, show list of objects contained
|
After verifying the pack, show list of objects contained
|
||||||
in the pack.
|
in the pack.
|
||||||
|
--::
|
||||||
|
Do not interpret any more arguments as options.
|
||||||
|
|
||||||
OUTPUT FORMAT
|
OUTPUT FORMAT
|
||||||
-------------
|
-------------
|
||||||
|
@ -14,19 +14,21 @@ DESCRIPTION
|
|||||||
-----------
|
-----------
|
||||||
Creates a tree object using the current index.
|
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.
|
into a set of tree files.
|
||||||
In order to have that match what is actually in your directory right
|
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
|
now, you need to have done a `git-update-index` phase before you did the
|
||||||
"git-write-tree".
|
`git-write-tree`.
|
||||||
|
|
||||||
|
|
||||||
OPTIONS
|
OPTIONS
|
||||||
-------
|
-------
|
||||||
--missing-ok::
|
--missing-ok::
|
||||||
Normally "git-write-tree" ensures that the objects referenced by the
|
Normally `git-write-tree` ensures that the objects referenced by the
|
||||||
directory exist in the object database. This option disables this check.
|
directory exist in the object database. This option disables this
|
||||||
|
check.
|
||||||
|
|
||||||
Author
|
Author
|
||||||
------
|
------
|
||||||
|
@ -36,31 +36,35 @@ OPTIONS
|
|||||||
CORE GIT COMMANDS
|
CORE GIT COMMANDS
|
||||||
-----------------
|
-----------------
|
||||||
Before reading this cover to cover, you may want to take a look
|
Before reading this cover to cover, you may want to take a look
|
||||||
at the link:tutorial.html[tutorial] document.
|
at the link:tutorial.html[tutorial] document. If you are
|
||||||
|
migrating from CVS, link:cvs-migration.html[cvs migration]
|
||||||
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]
|
|
||||||
document may be helpful after you finish the tutorial.
|
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
|
After you get the general feel from the tutorial and this
|
||||||
overview page, you may want to take a look at the
|
overview page, you may want to take a look at the
|
||||||
link:howto-index.html[howto] documents.
|
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>
|
David Greaves <david@dgreaves.com>
|
||||||
08/05/05
|
08/05/05
|
||||||
|
|
||||||
Updated by Junio C Hamano <junkio@cox.net> on 2005-05-05 to
|
Updated by Junio C Hamano <junkio@cox.net> on 2005-05-05 and
|
||||||
reflect recent changes.
|
further on 2005-12-07 to reflect recent changes.
|
||||||
|
|
||||||
Commands Overview
|
Commands Overview
|
||||||
-----------------
|
-----------------
|
||||||
The git commands can helpfully be split into those that manipulate
|
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
|
interrogate and compare them, and those that moves objects and
|
||||||
references between repositories.
|
references between repositories.
|
||||||
|
|
||||||
@ -79,25 +83,26 @@ gitlink:git-apply[1]::
|
|||||||
applies it to the working tree.
|
applies it to the working tree.
|
||||||
|
|
||||||
gitlink:git-checkout-index[1]::
|
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]::
|
gitlink:git-commit-tree[1]::
|
||||||
Creates a new commit object
|
Creates a new commit object.
|
||||||
|
|
||||||
gitlink:git-hash-object[1]::
|
gitlink:git-hash-object[1]::
|
||||||
Computes the object ID from a file.
|
Computes the object ID from a file.
|
||||||
|
|
||||||
gitlink:git-index-pack[1]::
|
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]::
|
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]::
|
gitlink:git-merge-index[1]::
|
||||||
Runs a merge for files needing merging
|
Runs a merge for files needing merging.
|
||||||
|
|
||||||
gitlink:git-mktag[1]::
|
gitlink:git-mktag[1]::
|
||||||
Creates a tag object
|
Creates a tag object.
|
||||||
|
|
||||||
gitlink:git-pack-objects[1]::
|
gitlink:git-pack-objects[1]::
|
||||||
Creates a packed archive of objects.
|
Creates a packed archive of objects.
|
||||||
@ -106,7 +111,7 @@ gitlink:git-prune-packed[1]::
|
|||||||
Remove extra objects that are already in pack files.
|
Remove extra objects that are already in pack files.
|
||||||
|
|
||||||
gitlink:git-read-tree[1]::
|
gitlink:git-read-tree[1]::
|
||||||
Reads tree information into the directory index
|
Reads tree information into the index.
|
||||||
|
|
||||||
gitlink:git-repo-config[1]::
|
gitlink:git-repo-config[1]::
|
||||||
Get and set options in .git/config.
|
Get and set options in .git/config.
|
||||||
@ -115,65 +120,65 @@ gitlink:git-unpack-objects[1]::
|
|||||||
Unpacks objects out of a packed archive.
|
Unpacks objects out of a packed archive.
|
||||||
|
|
||||||
gitlink:git-update-index[1]::
|
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]::
|
gitlink:git-write-tree[1]::
|
||||||
Creates a tree from the current index
|
Creates a tree from the index.
|
||||||
|
|
||||||
|
|
||||||
Interrogation commands
|
Interrogation commands
|
||||||
~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
gitlink:git-cat-file[1]::
|
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]::
|
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]::
|
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]::
|
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]::
|
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]::
|
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]::
|
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]::
|
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]::
|
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]::
|
gitlink:git-name-rev[1]::
|
||||||
Find symbolic names for given revs
|
Find symbolic names for given revs.
|
||||||
|
|
||||||
gitlink:git-rev-list[1]::
|
gitlink:git-rev-list[1]::
|
||||||
Lists commit objects in reverse chronological order
|
Lists commit objects in reverse chronological order.
|
||||||
|
|
||||||
gitlink:git-show-index[1]::
|
gitlink:git-show-index[1]::
|
||||||
Displays contents of a pack idx file.
|
Displays contents of a pack idx file.
|
||||||
|
|
||||||
gitlink:git-tar-tree[1]::
|
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]::
|
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]::
|
gitlink:git-var[1]::
|
||||||
Displays a git logical variable
|
Displays a git logical variable.
|
||||||
|
|
||||||
gitlink:git-verify-pack[1]::
|
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
|
In general, the interrogate commands do not touch the files in
|
||||||
touch the working file set - but in general they don't
|
the working tree.
|
||||||
|
|
||||||
|
|
||||||
Synching repositories
|
Synching repositories
|
||||||
@ -181,19 +186,24 @@ Synching repositories
|
|||||||
|
|
||||||
gitlink:git-clone-pack[1]::
|
gitlink:git-clone-pack[1]::
|
||||||
Clones a repository into the current repository (engine
|
Clones a repository into the current repository (engine
|
||||||
for ssh and local transport)
|
for ssh and local transport).
|
||||||
|
|
||||||
gitlink:git-fetch-pack[1]::
|
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]::
|
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]::
|
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]::
|
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]::
|
gitlink:git-receive-pack[1]::
|
||||||
Invoked by 'git-send-pack' to receive what is pushed to it.
|
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.
|
Restricted shell for GIT-only SSH access.
|
||||||
|
|
||||||
gitlink:git-ssh-fetch[1]::
|
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]::
|
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]::
|
gitlink:git-update-server-info[1]::
|
||||||
Updates auxiliary information on a dumb server to help
|
Updates auxiliary information on a dumb server to help
|
||||||
@ -223,16 +234,16 @@ Porcelain-ish Commands
|
|||||||
----------------------
|
----------------------
|
||||||
|
|
||||||
gitlink:git-add[1]::
|
gitlink:git-add[1]::
|
||||||
Add paths to the index file.
|
Add paths to the index.
|
||||||
|
|
||||||
gitlink:git-am[1]::
|
gitlink:git-am[1]::
|
||||||
Apply patches from a mailbox, but cooler.
|
Apply patches from a mailbox, but cooler.
|
||||||
|
|
||||||
gitlink:git-applymbox[1]::
|
gitlink:git-applymbox[1]::
|
||||||
Apply patches from a mailbox.
|
Apply patches from a mailbox, original version by Linus.
|
||||||
|
|
||||||
gitlink:git-bisect[1]::
|
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]::
|
gitlink:git-branch[1]::
|
||||||
Create and Show branches.
|
Create and Show branches.
|
||||||
@ -259,7 +270,7 @@ gitlink:git-format-patch[1]::
|
|||||||
Prepare patches for e-mail submission.
|
Prepare patches for e-mail submission.
|
||||||
|
|
||||||
gitlink:git-grep[1]::
|
gitlink:git-grep[1]::
|
||||||
Print lines matching a pattern
|
Print lines matching a pattern.
|
||||||
|
|
||||||
gitlink:git-log[1]::
|
gitlink:git-log[1]::
|
||||||
Shows commit logs.
|
Shows commit logs.
|
||||||
@ -283,7 +294,7 @@ gitlink:git-push[1]::
|
|||||||
Update remote refs along with associated objects.
|
Update remote refs along with associated objects.
|
||||||
|
|
||||||
gitlink:git-rebase[1]::
|
gitlink:git-rebase[1]::
|
||||||
Rebase local commits to new upstream head.
|
Rebase local commits to the updated upstream head.
|
||||||
|
|
||||||
gitlink:git-repack[1]::
|
gitlink:git-repack[1]::
|
||||||
Pack unpacked objects in a repository.
|
Pack unpacked objects in a repository.
|
||||||
@ -324,7 +335,7 @@ gitlink:git-archimport[1]::
|
|||||||
Import an arch repository into git.
|
Import an arch repository into git.
|
||||||
|
|
||||||
gitlink:git-convert-objects[1]::
|
gitlink:git-convert-objects[1]::
|
||||||
Converts old-style git repository
|
Converts old-style git repository.
|
||||||
|
|
||||||
gitlink:git-cvsimport[1]::
|
gitlink:git-cvsimport[1]::
|
||||||
Salvage your data out of another SCM people love to hate.
|
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.
|
Recover lost refs that luckily have not yet been pruned.
|
||||||
|
|
||||||
gitlink:git-merge-one-file[1]::
|
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]::
|
gitlink:git-prune[1]::
|
||||||
Prunes all unreachable objects from the object database
|
Prunes all unreachable objects from the object database.
|
||||||
|
|
||||||
gitlink:git-relink[1]::
|
gitlink:git-relink[1]::
|
||||||
Hardlink common objects in local repositories.
|
Hardlink common objects in local repositories.
|
||||||
@ -348,10 +359,10 @@ gitlink:git-sh-setup[1]::
|
|||||||
Common git shell script setup code.
|
Common git shell script setup code.
|
||||||
|
|
||||||
gitlink:git-symbolic-ref[1]::
|
gitlink:git-symbolic-ref[1]::
|
||||||
Read and modify symbolic refs
|
Read and modify symbolic refs.
|
||||||
|
|
||||||
gitlink:git-tag[1]::
|
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]::
|
gitlink:git-update-ref[1]::
|
||||||
Update the object name stored in a ref safely.
|
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.
|
Extract commit ID from an archive created using git-tar-tree.
|
||||||
|
|
||||||
gitlink:git-mailinfo[1]::
|
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]::
|
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]::
|
gitlink:git-patch-id[1]::
|
||||||
Compute unique ID for a patch.
|
Compute unique ID for a patch.
|
||||||
|
|
||||||
gitlink:git-parse-remote[1]::
|
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]::
|
gitlink:git-request-pull[1]::
|
||||||
git-request-pull.
|
git-request-pull.
|
||||||
@ -406,22 +420,20 @@ Commands not yet documented
|
|||||||
---------------------------
|
---------------------------
|
||||||
|
|
||||||
gitlink:gitk[1]::
|
gitlink:gitk[1]::
|
||||||
gitk.
|
The gitk repository browser.
|
||||||
|
|
||||||
|
|
||||||
Configuration Mechanism
|
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
|
is used to hold per-repository configuration options. It is a
|
||||||
simple text file modelled after `.ini` format familiar to some
|
simple text file modelled after `.ini` format familiar to some
|
||||||
people. Here is an example:
|
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
|
; core variables
|
||||||
@ -443,30 +455,30 @@ their operation accordingly.
|
|||||||
Identifier Terminology
|
Identifier Terminology
|
||||||
----------------------
|
----------------------
|
||||||
<object>::
|
<object>::
|
||||||
Indicates the sha1 identifier for any type of object
|
Indicates the object name for any type of object.
|
||||||
|
|
||||||
<blob>::
|
<blob>::
|
||||||
Indicates a blob object sha1 identifier
|
Indicates a blob object name.
|
||||||
|
|
||||||
<tree>::
|
<tree>::
|
||||||
Indicates a tree object sha1 identifier
|
Indicates a tree object name.
|
||||||
|
|
||||||
<commit>::
|
<commit>::
|
||||||
Indicates a commit object sha1 identifier
|
Indicates a commit object name.
|
||||||
|
|
||||||
<tree-ish>::
|
<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
|
command that takes a <tree-ish> argument ultimately wants to
|
||||||
operate on a <tree> object but automatically dereferences
|
operate on a <tree> object but automatically dereferences
|
||||||
<commit> and <tag> objects that point at a <tree>.
|
<commit> and <tag> objects that point at a <tree>.
|
||||||
|
|
||||||
<type>::
|
<type>::
|
||||||
Indicates that an object type is required.
|
Indicates that an object type is required.
|
||||||
Currently one of: blob/tree/commit/tag
|
Currently one of: `blob`, `tree`, `commit`, or `tag`.
|
||||||
|
|
||||||
<file>::
|
<file>::
|
||||||
Indicates a filename - always relative to the root of
|
Indicates a filename - almost always relative to the
|
||||||
the tree structure GIT_INDEX_FILE describes.
|
root of the tree structure `GIT_INDEX_FILE` describes.
|
||||||
|
|
||||||
Symbolic Identifiers
|
Symbolic Identifiers
|
||||||
--------------------
|
--------------------
|
||||||
@ -474,17 +486,20 @@ Any git command accepting any <object> can also use the following
|
|||||||
symbolic notation:
|
symbolic notation:
|
||||||
|
|
||||||
HEAD::
|
HEAD::
|
||||||
indicates the head of the repository (ie the contents of
|
indicates the head of the current branch (i.e. the
|
||||||
`$GIT_DIR/HEAD`)
|
contents of `$GIT_DIR/HEAD`).
|
||||||
|
|
||||||
<tag>::
|
<tag>::
|
||||||
a valid tag 'name'+
|
a valid tag 'name'
|
||||||
(ie the contents of `$GIT_DIR/refs/tags/<tag>`)
|
(i.e. the contents of `$GIT_DIR/refs/tags/<tag>`).
|
||||||
|
|
||||||
<head>::
|
<head>::
|
||||||
a valid head 'name'+
|
a valid head 'name'
|
||||||
(ie the contents of `$GIT_DIR/refs/heads/<head>`)
|
(i.e. the contents of `$GIT_DIR/refs/heads/<head>`).
|
||||||
|
|
||||||
<snap>::
|
<snap>::
|
||||||
a valid snapshot 'name'+
|
a valid snapshot 'name'
|
||||||
(ie the contents of `$GIT_DIR/refs/snap/<snap>`)
|
(i.e. the contents of `$GIT_DIR/refs/snap/<snap>`).
|
||||||
|
|
||||||
|
|
||||||
File/Directory Structure
|
File/Directory Structure
|
||||||
@ -493,7 +508,7 @@ File/Directory Structure
|
|||||||
Please see link:repository-layout.html[repository layout] document.
|
Please see link:repository-layout.html[repository layout] document.
|
||||||
|
|
||||||
Higher level SCMs may provide and manage additional information in the
|
Higher level SCMs may provide and manage additional information in the
|
||||||
GIT_DIR.
|
`$GIT_DIR`.
|
||||||
|
|
||||||
|
|
||||||
Terminology
|
Terminology
|
||||||
@ -509,7 +524,7 @@ The git Repository
|
|||||||
~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~
|
||||||
These environment variables apply to 'all' core git commands. Nb: it
|
These environment variables apply to 'all' core git commands. Nb: it
|
||||||
is worth noting that they may be used/overridden by SCMS sitting above
|
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'::
|
'GIT_INDEX_FILE'::
|
||||||
This environment allows the specification of an alternate
|
This environment allows the specification of an alternate
|
||||||
@ -530,9 +545,9 @@ git so take care if using Cogito etc
|
|||||||
written to these directories.
|
written to these directories.
|
||||||
|
|
||||||
'GIT_DIR'::
|
'GIT_DIR'::
|
||||||
If the 'GIT_DIR' environment variable is set then it specifies
|
If the 'GIT_DIR' environment variable is set then it
|
||||||
a path to use instead of `./.git` for the base of the
|
specifies a path to use instead of the default `.git`
|
||||||
repository.
|
for the base of the repository.
|
||||||
|
|
||||||
git Commits
|
git Commits
|
||||||
~~~~~~~~~~~
|
~~~~~~~~~~~
|
||||||
@ -559,7 +574,7 @@ include::../README[]
|
|||||||
Authors
|
Authors
|
||||||
-------
|
-------
|
||||||
git's founding father is Linus Torvalds <torvalds@osdl.org>.
|
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>.
|
The git potty was written by Andres Ericsson <ae@op5.se>.
|
||||||
General upbringing is handled by the git-list <git@vger.kernel.org>.
|
General upbringing is handled by the git-list <git@vger.kernel.org>.
|
||||||
|
|
||||||
|
@ -20,7 +20,7 @@ hash::
|
|||||||
|
|
||||||
object database::
|
object database::
|
||||||
Stores a set of "objects", and an individial object is identified
|
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::
|
blob object::
|
||||||
Untyped object, e.g. the contents of a file.
|
Untyped object, e.g. the contents of a file.
|
||||||
@ -109,15 +109,15 @@ head::
|
|||||||
branch::
|
branch::
|
||||||
A non-cyclical graph of revisions, i.e. the complete history of
|
A non-cyclical graph of revisions, i.e. the complete history of
|
||||||
a particular revision, which is called the branch head. The
|
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::
|
ref::
|
||||||
A 40-byte hex representation of a SHA1 pointing to a particular
|
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::
|
head ref::
|
||||||
A ref pointing to a head. Often, this is abbreviated to "head".
|
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::
|
tree-ish::
|
||||||
A ref pointing to either a commit object, a tree object, or a
|
A ref pointing to either a commit object, a tree object, or a
|
||||||
@ -125,7 +125,7 @@ tree-ish::
|
|||||||
|
|
||||||
ent::
|
ent::
|
||||||
Favorite synonym to "tree-ish" by some total geeks. See
|
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.
|
explanation.
|
||||||
|
|
||||||
tag object::
|
tag object::
|
||||||
@ -137,7 +137,7 @@ tag object::
|
|||||||
tag::
|
tag::
|
||||||
A ref pointing to a tag or commit object. In contrast to a head,
|
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
|
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 Lisp tag (which is called object type in git's context).
|
||||||
A tag is most typically used to mark a particular point in the
|
A tag is most typically used to mark a particular point in the
|
||||||
commit ancestry chain.
|
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.
|
Subject: control access to branches.
|
||||||
Date: Thu, 17 Nov 2005 23:55:32 -0800
|
Date: Thu, 17 Nov 2005 23:55:32 -0800
|
||||||
Message-ID: <7vfypumlu3.fsf@assigned-by-dhcp.cox.net>
|
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
|
So if your policy is (1) always require fast-forward push
|
||||||
(i.e. never allow "git-push repo +branch:branch"), (2) you
|
(i.e. never allow "git-push repo +branch:branch"), (2) you
|
||||||
have a list of users allowed to update each branch, and (3) 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
|
[jc: editorial note. This is a much improved version by Carl
|
||||||
# This is a sample hooks/update script, written by JC
|
since I posted the original outline]
|
||||||
# in his e-mail buffer, so naturally it is not tested
|
|
||||||
# but hopefully would convey the idea.
|
|
||||||
|
|
||||||
umask 002
|
-- >8 -- beginning of script -- >8 --
|
||||||
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
|
|
||||||
|
|
||||||
# Is the user allowed to update it?
|
#!/bin/bash
|
||||||
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
|
|
||||||
|
|
||||||
For the sake of simplicity, I assumed that you keep something
|
umask 002
|
||||||
like this in $GIT_DIR/info/allowed-pushers file:
|
|
||||||
|
# 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/master junio
|
||||||
refs/heads/cogito$ pasky
|
refs/heads/cogito$ pasky
|
||||||
@ -91,15 +165,8 @@ like this in $GIT_DIR/info/allowed-pushers file:
|
|||||||
refs/tags/v[0-9]* junio
|
refs/tags/v[0-9]* junio
|
||||||
|
|
||||||
With this, Linus can push or create "bw/penguin" or "bw/zebra"
|
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
|
or "bw/panda" branches, Pasky can do only "cogito", and JC can
|
||||||
master branch and make versioned tags. And anybody can do
|
do master branch and make versioned tags. And anybody can do
|
||||||
tmp/blah branches. This assumes all the users are in a single
|
tmp/blah branches.
|
||||||
group that can write into $GIT_DIR/ and underneath.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
------------
|
||||||
|
@ -11,6 +11,6 @@
|
|||||||
Use the given merge strategy; can be supplied more than
|
Use the given merge strategy; can be supplied more than
|
||||||
once to specify them in the order they should be tried.
|
once to specify them in the order they should be tried.
|
||||||
If there is no `-s` option, a built-in list of strategies
|
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).
|
head, `git-merge-octopus` otherwise).
|
||||||
|
|
||||||
|
@ -6,27 +6,27 @@ resolve::
|
|||||||
and another branch you pulled from) using 3-way merge
|
and another branch you pulled from) using 3-way merge
|
||||||
algorithm. It tries to carefully detect criss-cross
|
algorithm. It tries to carefully detect criss-cross
|
||||||
merge ambiguities and is considered generally safe and
|
merge ambiguities and is considered generally safe and
|
||||||
fast. This is the default merge strategy when pulling
|
fast.
|
||||||
one branch.
|
|
||||||
|
|
||||||
recursive::
|
recursive::
|
||||||
This can only resolve two heads using 3-way merge
|
This can only resolve two heads using 3-way merge
|
||||||
algorithm. When there are more than one common
|
algorithm. When there are more than one common
|
||||||
ancestors that can be used for 3-way merge, it creates a
|
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
|
the reference tree for the 3-way merge. This has been
|
||||||
reported to result in fewer merge conflicts without
|
reported to result in fewer merge conflicts without
|
||||||
causing mis-merges by tests done on actual merge commits
|
causing mis-merges by tests done on actual merge commits
|
||||||
taken from Linux 2.6 kernel development history.
|
taken from Linux 2.6 kernel development history.
|
||||||
Additionally this can detect and handle merges involving
|
Additionally this can detect and handle merges involving
|
||||||
renames.
|
renames. This is the default merge strategy when
|
||||||
|
pulling or merging one branch.
|
||||||
|
|
||||||
octopus::
|
octopus::
|
||||||
This resolves more than two-head case, but refuses to do
|
This resolves more than two-head case, but refuses to do
|
||||||
complex merge that needs manual resolution. It is
|
complex merge that needs manual resolution. It is
|
||||||
primarily meant to be used for bundling topic branch
|
primarily meant to be used for bundling topic branch
|
||||||
heads together. This is the default merge strategy when
|
heads together. This is the default merge strategy when
|
||||||
pulling more than one branch.
|
pulling or merging more than one branches.
|
||||||
|
|
||||||
ours::
|
ours::
|
||||||
This resolves any number of heads, but the result of the
|
This resolves any number of heads, but the result of the
|
||||||
|
@ -42,7 +42,6 @@ sub no_spaces ($) {
|
|||||||
|
|
||||||
print 'GIT Glossary
|
print 'GIT Glossary
|
||||||
============
|
============
|
||||||
Aug 2005
|
|
||||||
|
|
||||||
This list is sorted alphabetically:
|
This list is sorted alphabetically:
|
||||||
|
|
||||||
|
@ -1282,26 +1282,27 @@ fatal: merge program failed
|
|||||||
|
|
||||||
`git-merge-one-file` script is called with parameters to
|
`git-merge-one-file` script is called with parameters to
|
||||||
describe those three versions, and is responsible to leave the
|
describe those three versions, and is responsible to leave the
|
||||||
merge results in the working tree and register it in the index
|
merge results in the working tree.
|
||||||
file. It is a fairly straightforward shell script, and
|
It is a fairly straightforward shell script, and
|
||||||
eventually calls `merge` program from RCS suite to perform the
|
eventually calls `merge` program from RCS suite to perform a
|
||||||
file-level 3-way merge. In this case, `merge` detects
|
file-level 3-way merge. In this case, `merge` detects
|
||||||
conflicts, and the merge result with conflict marks is left in
|
conflicts, and the merge result with conflict marks is left in
|
||||||
the working tree, while the index file is updated with the
|
the working tree.. This can be seen if you run `ls-files
|
||||||
version from the current branch (this is to make `git diff`
|
|
||||||
useful after this step). This can be seen if you run `ls-files
|
|
||||||
--stage` again at this point:
|
--stage` again at this point:
|
||||||
|
|
||||||
------------
|
------------
|
||||||
$ git-ls-files --stage
|
$ git-ls-files --stage
|
||||||
100644 7f8b141b65fdcee47321e399a2598a235a032422 0 example
|
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
|
This is the state of the index file and the working file after
|
||||||
`git merge` returns control back to you, leaving the conflicting
|
`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
|
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.
|
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
|
Bundling your work together
|
||||||
---------------------------
|
---------------------------
|
||||||
|
|
||||||
It is likely that you will be working on more than one thing at
|
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.
|
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
|
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
|
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"
|
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
|
have all the libraries/tools needed, or you may have
|
||||||
necessary libraries at unusual locations. Please look at the
|
necessary libraries at unusual locations. Please look at the
|
||||||
top of the Makefile to see what can be adjusted for your needs.
|
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
|
# 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.
|
# 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.
|
# CFLAGS and LDFLAGS are for the users to override from the command line.
|
||||||
|
|
||||||
@ -162,7 +162,7 @@ LIB_FILE=libgit.a
|
|||||||
LIB_H = \
|
LIB_H = \
|
||||||
blob.h cache.h commit.h count-delta.h csum-file.h delta.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 \
|
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_OBJS = \
|
||||||
diff.o diffcore-break.o diffcore-order.o diffcore-pathspec.o \
|
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_CFLAGS += -I/usr/pkg/include
|
||||||
ALL_LDFLAGS += -L/usr/pkg/lib -Wl,-rpath,/usr/pkg/lib
|
ALL_LDFLAGS += -L/usr/pkg/lib -Wl,-rpath,/usr/pkg/lib
|
||||||
endif
|
endif
|
||||||
|
ifeq ($(uname_S),AIX)
|
||||||
|
NO_STRCASESTR=YesPlease
|
||||||
|
NEEDS_LIBICONV=YesPlease
|
||||||
|
endif
|
||||||
ifneq (,$(findstring arm,$(uname_M)))
|
ifneq (,$(findstring arm,$(uname_M)))
|
||||||
ARM_SHA1 = YesPlease
|
ARM_SHA1 = YesPlease
|
||||||
endif
|
endif
|
||||||
@ -320,15 +324,15 @@ ifdef NEEDS_NSL
|
|||||||
SIMPLE_LIB += -lnsl
|
SIMPLE_LIB += -lnsl
|
||||||
endif
|
endif
|
||||||
ifdef NO_STRCASESTR
|
ifdef NO_STRCASESTR
|
||||||
COMPAT_CFLAGS += -Dstrcasestr=gitstrcasestr -DNO_STRCASESTR=1
|
COMPAT_CFLAGS += -DNO_STRCASESTR
|
||||||
COMPAT_OBJS += compat/strcasestr.o
|
COMPAT_OBJS += compat/strcasestr.o
|
||||||
endif
|
endif
|
||||||
ifdef NO_SETENV
|
ifdef NO_SETENV
|
||||||
COMPAT_CFLAGS += -Dsetenv=gitsetenv -DNO_SETENV=1
|
COMPAT_CFLAGS += -DNO_SETENV
|
||||||
COMPAT_OBJS += compat/setenv.o
|
COMPAT_OBJS += compat/setenv.o
|
||||||
endif
|
endif
|
||||||
ifdef NO_MMAP
|
ifdef NO_MMAP
|
||||||
COMPAT_CFLAGS += -Dmmap=gitfakemmap -Dmunmap=gitfakemunmap -DNO_MMAP
|
COMPAT_CFLAGS += -DNO_MMAP
|
||||||
COMPAT_OBJS += compat/mmap.o
|
COMPAT_OBJS += compat/mmap.o
|
||||||
endif
|
endif
|
||||||
ifdef NO_IPV6
|
ifdef NO_IPV6
|
||||||
@ -363,9 +367,9 @@ all: $(ALL_PROGRAMS)
|
|||||||
all:
|
all:
|
||||||
$(MAKE) -C templates
|
$(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)"' \
|
$(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
|
$(patsubst %.sh,%,$(SCRIPT_SH)) : % : %.sh
|
||||||
rm -f $@
|
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",
|
objects). There are currently four different object types: "blob",
|
||||||
"tree", "commit" and "tag".
|
"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
|
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
|
actually store the file data, i.e. a blob object is associated with some
|
||||||
particular version of some file.
|
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
|
Regardless of object type, all objects share the following
|
||||||
characteristics: they are all deflated with zlib, and have a header
|
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
|
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
|
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
|
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
|
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
|
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
|
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>.
|
size> + <byte\0> + <binary object data>.
|
||||||
|
|
||||||
The structured objects can further have their structure and
|
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.
|
i.e. it will normally just update existing cache entries.
|
||||||
|
|
||||||
To tell git that yes, you really do realize that certain files no
|
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.
|
should use the `--remove` and `--add` flags respectively.
|
||||||
|
|
||||||
NOTE! A `--remove` flag does 'not' mean that subsequent filenames will
|
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
|
Historical note. We did not have `-u` facility when this
|
||||||
section was first written, so we used to warn that
|
section was first written, so we used to warn that
|
||||||
the merge is done in the index file, not in your
|
the merge is done in the index file, not in your
|
||||||
working directory, and your working directory will no longer match your
|
working tree, and your working tree will not match your
|
||||||
index.
|
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
|
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.
|
to help you understand what conceptually happens under the hood.
|
||||||
In practice, nobody, not even git itself, uses three `git-cat-file`
|
In practice, nobody, not even git itself, uses three `git-cat-file`
|
||||||
for this. There is `git-merge-index` program that extracts the
|
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
|
git-merge-index git-merge-one-file hello.c
|
||||||
|
|
||||||
|
97
cache.h
97
cache.h
@ -1,23 +1,7 @@
|
|||||||
#ifndef CACHE_H
|
#ifndef CACHE_H
|
||||||
#define CACHE_H
|
#define CACHE_H
|
||||||
|
|
||||||
#include <unistd.h>
|
#include "git-compat-util.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 SHA1_HEADER
|
#include SHA1_HEADER
|
||||||
#include <zlib.h>
|
#include <zlib.h>
|
||||||
@ -36,15 +20,6 @@
|
|||||||
#define DTYPE(de) DT_UNKNOWN
|
#define DTYPE(de) DT_UNKNOWN
|
||||||
#endif
|
#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
|
* Intensive research over the course of many years has shown that
|
||||||
* port 9418 is totally unused by anything else. Or
|
* 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_modified(struct cache_entry *ce, struct stat *st);
|
||||||
extern int ce_path_match(const struct cache_entry *ce, const char **pathspec);
|
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_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 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);
|
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 create_symref(const char *git_HEAD, const char *refs_heads_master);
|
||||||
extern int validate_symref(const char *git_HEAD);
|
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 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);
|
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_author_info(void);
|
||||||
extern const char *git_committer_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 {
|
struct checkout {
|
||||||
const char *base_dir;
|
const char *base_dir;
|
||||||
int base_dir_len;
|
int base_dir_len;
|
||||||
@ -373,20 +320,6 @@ extern void packed_object_info_detail(struct pack_entry *, char *, unsigned long
|
|||||||
/* Dumb servers support */
|
/* Dumb servers support */
|
||||||
extern int update_server_info(int);
|
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 *);
|
typedef int (*config_fn_t)(const char *, const char *);
|
||||||
extern int git_default_config(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 *);
|
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
|
#define MAX_ENCODING_LENGTH 64
|
||||||
extern char git_commit_encoding[MAX_ENCODING_LENGTH];
|
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);
|
extern int copy_fd(int ifd, int ofd);
|
||||||
#endif /* CACHE_H */
|
#endif /* CACHE_H */
|
||||||
|
@ -36,6 +36,7 @@
|
|||||||
|
|
||||||
static const char *prefix;
|
static const char *prefix;
|
||||||
static int prefix_length;
|
static int prefix_length;
|
||||||
|
static int checkout_stage; /* default to checkout stage0 */
|
||||||
|
|
||||||
static struct checkout state = {
|
static struct checkout state = {
|
||||||
.base_dir = "",
|
.base_dir = "",
|
||||||
@ -48,20 +49,36 @@ static struct checkout state = {
|
|||||||
|
|
||||||
static int checkout_file(const char *name)
|
static int checkout_file(const char *name)
|
||||||
{
|
{
|
||||||
int pos = cache_name_pos(name, strlen(name));
|
int namelen = strlen(name);
|
||||||
if (pos < 0) {
|
int pos = cache_name_pos(name, namelen);
|
||||||
if (!state.quiet) {
|
int has_same_name = 0;
|
||||||
pos = -pos - 1;
|
|
||||||
fprintf(stderr,
|
if (pos < 0)
|
||||||
"git-checkout-index: %s is %s.\n",
|
pos = -pos - 1;
|
||||||
name,
|
|
||||||
(pos < active_nr &&
|
while (pos < active_nr) {
|
||||||
!strcmp(active_cache[pos]->name, name)) ?
|
struct cache_entry *ce = active_cache[pos];
|
||||||
"unmerged" : "not in the cache");
|
if (ce_namelen(ce) != namelen &&
|
||||||
}
|
memcmp(ce->name, name, namelen))
|
||||||
return -1;
|
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)
|
static int checkout_all(void)
|
||||||
@ -70,11 +87,11 @@ static int checkout_all(void)
|
|||||||
|
|
||||||
for (i = 0; i < active_nr ; i++) {
|
for (i = 0; i < active_nr ; i++) {
|
||||||
struct cache_entry *ce = active_cache[i];
|
struct cache_entry *ce = active_cache[i];
|
||||||
if (ce_stage(ce))
|
if (ce_stage(ce) != checkout_stage)
|
||||||
continue;
|
continue;
|
||||||
if (prefix && *prefix &&
|
if (prefix && *prefix &&
|
||||||
( ce_namelen(ce) <= prefix_length ||
|
(ce_namelen(ce) <= prefix_length ||
|
||||||
memcmp(prefix, ce->name, prefix_length) ))
|
memcmp(prefix, ce->name, prefix_length)))
|
||||||
continue;
|
continue;
|
||||||
if (checkout_entry(ce, &state) < 0)
|
if (checkout_entry(ce, &state) < 0)
|
||||||
errs++;
|
errs++;
|
||||||
@ -88,7 +105,7 @@ static int checkout_all(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static const char checkout_cache_usage[] =
|
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;
|
static struct cache_file cache_file;
|
||||||
|
|
||||||
@ -138,11 +155,19 @@ int main(int argc, char **argv)
|
|||||||
die("cannot open index.lock file.");
|
die("cannot open index.lock file.");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (!memcmp(arg, "--prefix=", 9)) {
|
if (!strncmp(arg, "--prefix=", 9)) {
|
||||||
state.base_dir = arg+9;
|
state.base_dir = arg+9;
|
||||||
state.base_dir_len = strlen(state.base_dir);
|
state.base_dir_len = strlen(state.base_dir);
|
||||||
continue;
|
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] == '-')
|
if (arg[0] == '-')
|
||||||
usage(checkout_cache_usage);
|
usage(checkout_cache_usage);
|
||||||
break;
|
break;
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <errno.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)
|
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);
|
namelen = strlen(name);
|
||||||
valuelen = strlen(value);
|
valuelen = strlen(value);
|
||||||
envstr = malloc((namelen + valuelen + 2) * sizeof(char));
|
envstr = malloc((namelen + valuelen + 2));
|
||||||
if (!envstr) return -1;
|
if (!envstr) return -1;
|
||||||
|
|
||||||
memcpy(envstr, name, namelen);
|
memcpy(envstr, name, namelen);
|
||||||
@ -25,7 +25,11 @@ int gitsetenv(const char *name, const char *value, int replace)
|
|||||||
envstr[namelen + valuelen + 1] = 0;
|
envstr[namelen + valuelen + 1] = 0;
|
||||||
|
|
||||||
out = putenv(envstr);
|
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;
|
return out;
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
#include <string.h>
|
#include "../git-compat-util.h"
|
||||||
#include <ctype.h>
|
|
||||||
|
|
||||||
char *gitstrcasestr(const char *haystack, const char *needle)
|
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 .git/config does not exist yet, write a minimal version.
|
||||||
*/
|
*/
|
||||||
if (stat(config_filename, &st)) {
|
if (stat(config_filename, &st)) {
|
||||||
static const char contents[] =
|
|
||||||
"#\n"
|
|
||||||
"# This is the config file\n"
|
|
||||||
"#\n"
|
|
||||||
"\n";
|
|
||||||
|
|
||||||
free(store.key);
|
free(store.key);
|
||||||
|
|
||||||
/* if nothing to unset, error out */
|
/* 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;
|
store.key = (char*)key;
|
||||||
|
|
||||||
write(fd, contents, sizeof(contents)-1);
|
|
||||||
store_write_section(fd, key);
|
store_write_section(fd, key);
|
||||||
store_write_pair(fd, key, value);
|
store_write_pair(fd, key, value);
|
||||||
} else{
|
} 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 <time.h>
|
||||||
#include "cache.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-core (0.99.9l-0) unstable; urgency=low
|
||||||
|
|
||||||
* GIT 0.99.9l aka 1.0rc4
|
* GIT 0.99.9l aka 1.0rc4
|
||||||
|
@ -312,7 +312,7 @@ do
|
|||||||
echo "--------------------------"
|
echo "--------------------------"
|
||||||
cat "$dotest/final-commit"
|
cat "$dotest/final-commit"
|
||||||
echo "--------------------------"
|
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
|
read reply
|
||||||
case "$reply" in
|
case "$reply" in
|
||||||
[yY]*) action=yes ;;
|
[yY]*) action=yes ;;
|
||||||
|
@ -83,7 +83,7 @@ while [ "$interactive" = yes ]; do
|
|||||||
echo "--------------------------"
|
echo "--------------------------"
|
||||||
cat "$final"
|
cat "$final"
|
||||||
echo "--------------------------"
|
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
|
read reply
|
||||||
case "$reply" in
|
case "$reply" in
|
||||||
y|Y) interactive=no;;
|
y|Y) interactive=no;;
|
||||||
|
@ -25,6 +25,9 @@ See man (1) git-archimport for more details.
|
|||||||
- audit shell-escaping of filenames
|
- audit shell-escaping of filenames
|
||||||
- hide our private tags somewhere smarter
|
- hide our private tags somewhere smarter
|
||||||
- find a way to make "cat *patches | patch" safe even when patchfiles are missing newlines
|
- 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
|
=head1 Devel tricks
|
||||||
|
|
||||||
@ -53,15 +56,9 @@ and can contain multiple, unrelated branches.
|
|||||||
use strict;
|
use strict;
|
||||||
use warnings;
|
use warnings;
|
||||||
use Getopt::Std;
|
use Getopt::Std;
|
||||||
use File::Spec;
|
use File::Temp qw(tempdir);
|
||||||
use File::Temp qw(tempfile tempdir);
|
use File::Path qw(mkpath rmtree);
|
||||||
use File::Path qw(mkpath);
|
|
||||||
use File::Basename qw(basename dirname);
|
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 Data::Dumper qw/ Dumper /;
|
||||||
use IPC::Open2;
|
use IPC::Open2;
|
||||||
|
|
||||||
@ -72,124 +69,150 @@ my $git_dir = $ENV{"GIT_DIR"} || ".git";
|
|||||||
$ENV{"GIT_DIR"} = $git_dir;
|
$ENV{"GIT_DIR"} = $git_dir;
|
||||||
my $ptag_dir = "$git_dir/archimport/tags";
|
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() {
|
sub usage() {
|
||||||
print STDERR <<END;
|
print STDERR <<END;
|
||||||
Usage: ${\basename $0} # fetch/update GIT from Arch
|
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] ...
|
repository/arch-branch [ repository/arch-branch] ...
|
||||||
END
|
END
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
getopts("Thvt:") or usage();
|
getopts("fThvat:D:") or usage();
|
||||||
usage if $opt_h;
|
usage if $opt_h;
|
||||||
|
|
||||||
@ARGV >= 1 or usage();
|
@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);
|
$ENV{'TMPDIR'} = $opt_t if $opt_t; # $ENV{TMPDIR} will affect tempdir() calls:
|
||||||
my $tmp = $opt_t || 1;
|
my $tmp = tempdir('git-archimport-XXXXXX', TMPDIR => 1, CLEANUP => 1);
|
||||||
$tmp = tempdir('git-archimport-XXXXXX', TMPDIR => 1, CLEANUP => 1);
|
|
||||||
$opt_v && print "+ Using $tmp as temporary directory\n";
|
$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
|
||||||
my %psets = (); # the collection, by name
|
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
|
my %rptags = (); # my reverse private tags
|
||||||
# to map a SHA1 to a commitid
|
# to map a SHA1 to a commitid
|
||||||
|
my $TLA = $ENV{'ARCH_CLIENT'} || 'tla';
|
||||||
|
|
||||||
foreach my $root (@arch_roots) {
|
sub do_abrowse {
|
||||||
my ($arepo, $abranch) = split(m!/!, $root);
|
my $stage = shift;
|
||||||
open ABROWSE, "tla abrowse -f -A $arepo --desc --merges $abranch |"
|
while (my ($limit, $level) = each %arch_branches) {
|
||||||
or die "Problems with tla abrowse: $!";
|
next unless $level == $stage;
|
||||||
|
|
||||||
my %ps = (); # the current one
|
|
||||||
my $mode = '';
|
|
||||||
my $lastseen = '';
|
|
||||||
|
|
||||||
while (<ABROWSE>) {
|
|
||||||
chomp;
|
|
||||||
|
|
||||||
# first record padded w 8 spaces
|
open ABROWSE, "$TLA abrowse -fkD --merges $limit |"
|
||||||
if (s/^\s{8}\b//) {
|
or die "Problems with tla abrowse: $!";
|
||||||
|
|
||||||
|
my %ps = (); # the current one
|
||||||
|
my $lastseen = '';
|
||||||
|
|
||||||
|
while (<ABROWSE>) {
|
||||||
|
chomp;
|
||||||
|
|
||||||
# store the record we just captured
|
# first record padded w 8 spaces
|
||||||
if (%ps) {
|
if (s/^\s{8}\b//) {
|
||||||
my %temp = %ps; # break references
|
my ($id, $type) = split(m/\s+/, $_, 2);
|
||||||
push (@psets, \%temp);
|
|
||||||
$psets{$temp{id}} = \%temp;
|
|
||||||
%ps = ();
|
|
||||||
}
|
|
||||||
|
|
||||||
my ($id, $type) = split(m/\s{3}/, $_);
|
|
||||||
$ps{id} = $id;
|
|
||||||
$ps{repo} = $arepo;
|
|
||||||
|
|
||||||
# deal with types
|
my %last_ps;
|
||||||
if ($type =~ m/^\(simple changeset\)/) {
|
# store the record we just captured
|
||||||
$ps{type} = 's';
|
if (%ps && !exists $psets{ $ps{id} }) {
|
||||||
} elsif ($type eq '(initial import)') {
|
%last_ps = %ps; # break references
|
||||||
$ps{type} = 'i';
|
push (@psets, \%last_ps);
|
||||||
} elsif ($type =~ m/^\(tag revision of (.+)\)/) {
|
$psets{ $last_ps{id} } = \%last_ps;
|
||||||
$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';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$authoremail =~ m/^(.+)\s(\S+)$/;
|
my $branch = extract_versionname($id);
|
||||||
$ps{author} = $1;
|
%ps = ( id => $id, branch => $branch );
|
||||||
$ps{email} = $2;
|
if (%last_ps && ($last_ps{branch} eq $branch)) {
|
||||||
|
$ps{parent_id} = $last_ps{id};
|
||||||
$lastseen = 'date';
|
}
|
||||||
|
|
||||||
} elsif ($lastseen eq 'date') {
|
$arch_branches{$branch} = 1;
|
||||||
# the only hint is position
|
$lastseen = 'id';
|
||||||
# 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!?';
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (%ps) {
|
# deal with types (should work with baz or tla):
|
||||||
my %temp = %ps; # break references
|
if ($type =~ m/\(.*changeset\)/) {
|
||||||
push (@psets, \%temp);
|
$ps{type} = 's';
|
||||||
$psets{ $temp{id} } = \%temp;
|
} elsif ($type =~ /\(.*import\)/) {
|
||||||
%ps = ();
|
$ps{type} = 'i';
|
||||||
}
|
} elsif ($type =~ m/\(tag.*?(\S+\@\S+).*?\)/) {
|
||||||
close ABROWSE;
|
$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
|
} # end foreach $root
|
||||||
|
|
||||||
|
do_abrowse(1);
|
||||||
|
my $depth = 2;
|
||||||
|
$opt_D ||= 0;
|
||||||
|
while ($depth <= $opt_D) {
|
||||||
|
do_abrowse($depth);
|
||||||
|
$depth++;
|
||||||
|
}
|
||||||
|
|
||||||
## Order patches by time
|
## 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;
|
@psets = sort {$a->{date}.$b->{id} cmp $b->{date}.$b->{id}} @psets;
|
||||||
|
|
||||||
#print Dumper \@psets;
|
#print Dumper \@psets;
|
||||||
@ -210,7 +233,7 @@ unless (-d $git_dir) { # initial import
|
|||||||
}
|
}
|
||||||
} else { # progressing an import
|
} else { # progressing an import
|
||||||
# load the rptags
|
# load the rptags
|
||||||
opendir(DIR, "$git_dir/archimport/tags")
|
opendir(DIR, $ptag_dir)
|
||||||
|| die "can't opendir: $!";
|
|| die "can't opendir: $!";
|
||||||
while (my $file = readdir(DIR)) {
|
while (my $file = readdir(DIR)) {
|
||||||
# skip non-interesting-files
|
# skip non-interesting-files
|
||||||
@ -272,29 +295,69 @@ sub old_style_branchname {
|
|||||||
|
|
||||||
*git_branchname = $opt_o ? *old_style_branchname : *tree_dirname;
|
*git_branchname = $opt_o ? *old_style_branchname : *tree_dirname;
|
||||||
|
|
||||||
# process patchsets
|
sub process_patchset_accurate {
|
||||||
foreach my $ps (@psets) {
|
my $ps = shift;
|
||||||
$ps->{branch} = git_branchname($ps->{id});
|
|
||||||
|
# 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";
|
||||||
|
|
||||||
#
|
# remove any old stuff that got leftover:
|
||||||
# ensure we have a clean state
|
my $rm = safe_pipe_capture('git-ls-files','--others','-z');
|
||||||
#
|
rmtree(split(/\0/,$rm)) if $rm;
|
||||||
if (`git diff-files`) {
|
|
||||||
die "Unclean tree when about to process $ps->{id} " .
|
|
||||||
" - did we fail to commit cleanly before?";
|
|
||||||
}
|
}
|
||||||
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;
|
||||||
|
|
||||||
#
|
# grab variables we want from the log, new fields get added to $ps:
|
||||||
# skip commits already in repo
|
# (author, date, email, summary, message body ...)
|
||||||
#
|
parselog($ps, \@commitlog);
|
||||||
if (ptag($ps->{id})) {
|
|
||||||
$opt_v && print " * Skipping already imported: $ps->{id}\n";
|
|
||||||
next;
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
# create the branch if needed
|
||||||
#
|
#
|
||||||
@ -305,7 +368,7 @@ foreach my $ps (@psets) {
|
|||||||
unless ($import) { # skip for import
|
unless ($import) { # skip for import
|
||||||
if ( -e "$git_dir/refs/heads/$ps->{branch}") {
|
if ( -e "$git_dir/refs/heads/$ps->{branch}") {
|
||||||
# we know about this branch
|
# we know about this branch
|
||||||
`git checkout $ps->{branch}`;
|
system('git-checkout',$ps->{branch});
|
||||||
} else {
|
} else {
|
||||||
# new branch! we need to verify a few things
|
# new branch! we need to verify a few things
|
||||||
die "Branch on a non-tag!" unless $ps->{type} eq 't';
|
die "Branch on a non-tag!" unless $ps->{type} eq 't';
|
||||||
@ -314,7 +377,7 @@ foreach my $ps (@psets) {
|
|||||||
unless $branchpoint;
|
unless $branchpoint;
|
||||||
|
|
||||||
# find where we are supposed to branch from
|
# 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
|
# If we trust Arch with the fact that this is just
|
||||||
# a tag, and it does not affect the state of the tree
|
# a tag, and it does not affect the state of the tree
|
||||||
@ -322,7 +385,7 @@ foreach my $ps (@psets) {
|
|||||||
tag($ps->{id}, $branchpoint);
|
tag($ps->{id}, $branchpoint);
|
||||||
ptag($ps->{id}, $branchpoint);
|
ptag($ps->{id}, $branchpoint);
|
||||||
print " * Tagged $ps->{id} at $branchpoint\n";
|
print " * Tagged $ps->{id} at $branchpoint\n";
|
||||||
next;
|
return 0;
|
||||||
}
|
}
|
||||||
die $! if $?;
|
die $! if $?;
|
||||||
}
|
}
|
||||||
@ -332,96 +395,128 @@ foreach my $ps (@psets) {
|
|||||||
#
|
#
|
||||||
if ($ps->{type} eq 'i' || $ps->{type} eq 't') {
|
if ($ps->{type} eq 'i' || $ps->{type} eq 't') {
|
||||||
apply_import($ps) or die $!;
|
apply_import($ps) or die $!;
|
||||||
|
$stats{import_or_tag}++;
|
||||||
$import=0;
|
$import=0;
|
||||||
} elsif ($ps->{type} eq 's') {
|
} elsif ($ps->{type} eq 's') {
|
||||||
apply_cset($ps);
|
apply_cset($ps);
|
||||||
|
$stats{simple_changeset}++;
|
||||||
}
|
}
|
||||||
|
|
||||||
#
|
#
|
||||||
# prepare update git's index, based on what arch knows
|
# prepare update git's index, based on what arch knows
|
||||||
# about the pset, resolve parents, etc
|
# 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 $?;
|
die "Error in cat-archive-log: $!" if $?;
|
||||||
|
|
||||||
# parselog will git-add/rm files
|
parselog($ps,\@commitlog);
|
||||||
# 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";
|
|
||||||
|
|
||||||
|
|
||||||
# imports don't give us good info
|
# imports don't give us good info
|
||||||
# on added files. Shame on them
|
# on added files. Shame on them
|
||||||
if ($ps->{type} eq 'i' || $ps->{type} eq 't') {
|
if ($ps->{type} eq 'i' || $ps->{type} eq 't') {
|
||||||
`find . -type f -print0 | grep -zv '^./$git_dir' | xargs -0 -l100 git-update-index --add`;
|
system('git-ls-files --others -z | '.
|
||||||
`git-ls-files --deleted -z | xargs --no-run-if-empty -0 -l100 git-update-index --remove`;
|
'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) {
|
while (@$add) {
|
||||||
my @slice = splice(@$add, 0, 100);
|
my @slice = splice(@$add, 0, 100);
|
||||||
my $slice = join(' ', @slice);
|
system('git-update-index','--add','--',@slice) == 0 or
|
||||||
`git-update-index --add $slice`;
|
die "Error in git-update-index --add: $! $?\n";
|
||||||
die "Error in git-update-index --add: $!" if $?;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (@$del) {
|
|
||||||
foreach my $file (@$del) {
|
if (my $del = $ps->{removed_files}) {
|
||||||
unlink $file or die "Problems deleting $file : $!";
|
unlink @$del;
|
||||||
}
|
|
||||||
while (@$del) {
|
while (@$del) {
|
||||||
my @slice = splice(@$del, 0, 100);
|
my @slice = splice(@$del, 0, 100);
|
||||||
my $slice = join(' ', @slice);
|
system('git-update-index','--remove','--',@slice) == 0 or
|
||||||
`git-update-index --remove $slice`;
|
die "Error in git-update-index --remove: $! $?\n";
|
||||||
die "Error in git-update-index --remove: $!" if $?;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (@$ren) { # renamed
|
|
||||||
|
if (my $ren = $ps->{renamed_files}) { # renamed
|
||||||
if (@$ren % 2) {
|
if (@$ren % 2) {
|
||||||
die "Odd number of entries in rename!?";
|
die "Odd number of entries in rename!?";
|
||||||
}
|
}
|
||||||
;
|
|
||||||
while (@$ren) {
|
while (@$ren) {
|
||||||
my $from = pop @$ren;
|
my $from = shift @$ren;
|
||||||
my $to = pop @$ren;
|
my $to = shift @$ren;
|
||||||
|
|
||||||
unless (-d dirname($to)) {
|
unless (-d dirname($to)) {
|
||||||
mkpath(dirname($to)); # will die on err
|
mkpath(dirname($to)); # will die on err
|
||||||
}
|
}
|
||||||
#print "moving $from $to";
|
# print "moving $from $to";
|
||||||
`mv $from $to`;
|
rename($from, $to) or die "Error renaming '$from' '$to': $!\n";
|
||||||
die "Error renaming $from $to : $!" if $?;
|
system('git-update-index','--remove','--',$from) == 0 or
|
||||||
`git-update-index --remove $from`;
|
die "Error in git-update-index --remove: $! $?\n";
|
||||||
die "Error in git-update-index --remove: $!" if $?;
|
system('git-update-index','--add','--',$to) == 0 or
|
||||||
`git-update-index --add $to`;
|
die "Error in git-update-index --add: $! $?\n";
|
||||||
die "Error in git-update-index --add: $!" if $?;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
if (@$mod) { # must be _after_ renames
|
|
||||||
|
if (my $mod = $ps->{modified_files}) {
|
||||||
while (@$mod) {
|
while (@$mod) {
|
||||||
my @slice = splice(@$mod, 0, 100);
|
my @slice = splice(@$mod, 0, 100);
|
||||||
my $slice = join(' ', @slice);
|
system('git-update-index','--',@slice) == 0 or
|
||||||
`git-update-index $slice`;
|
die "Error in git-update-index: $! $?\n";
|
||||||
die "Error in git-update-index: $!" if $?;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
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! $!";
|
# warn "errors when running git-update-index! $!";
|
||||||
$tree = `git-write-tree`;
|
my $tree = `git-write-tree`;
|
||||||
die "cannot write tree $!" if $?;
|
die "cannot write tree $!" if $?;
|
||||||
chomp $tree;
|
chomp $tree;
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Who's your daddy?
|
# Who's your daddy?
|
||||||
#
|
#
|
||||||
my @par;
|
my @par;
|
||||||
if ( -e "$git_dir/refs/heads/$ps->{branch}") {
|
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>;
|
my $p = <HEAD>;
|
||||||
close HEAD;
|
close HEAD;
|
||||||
chomp $p;
|
chomp $p;
|
||||||
@ -436,7 +531,6 @@ foreach my $ps (@psets) {
|
|||||||
if ($ps->{merges}) {
|
if ($ps->{merges}) {
|
||||||
push @par, find_parents($ps);
|
push @par, find_parents($ps);
|
||||||
}
|
}
|
||||||
my $par = join (' ', @par);
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Commit, tag and clean state
|
# Commit, tag and clean state
|
||||||
@ -449,13 +543,14 @@ foreach my $ps (@psets) {
|
|||||||
$ENV{GIT_COMMITTER_EMAIL} = $ps->{email};
|
$ENV{GIT_COMMITTER_EMAIL} = $ps->{email};
|
||||||
$ENV{GIT_COMMITTER_DATE} = $ps->{date};
|
$ENV{GIT_COMMITTER_DATE} = $ps->{date};
|
||||||
|
|
||||||
my ($pid, $commit_rh, $commit_wh);
|
my $pid = open2(*READER, *WRITER,'git-commit-tree',$tree,@par)
|
||||||
$commit_rh = 'commit_rh';
|
|
||||||
$commit_wh = 'commit_wh';
|
|
||||||
|
|
||||||
$pid = open2(*READER, *WRITER, "git-commit-tree $tree $par")
|
|
||||||
or die $!;
|
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;
|
close WRITER;
|
||||||
my $commitid = <READER>; # read
|
my $commitid = <READER>; # read
|
||||||
chomp $commitid;
|
chomp $commitid;
|
||||||
@ -468,7 +563,7 @@ foreach my $ps (@psets) {
|
|||||||
#
|
#
|
||||||
# Update the branch
|
# Update the branch
|
||||||
#
|
#
|
||||||
open HEAD, ">$git_dir/refs/heads/$ps->{branch}";
|
open HEAD, ">","$git_dir/refs/heads/$ps->{branch}";
|
||||||
print HEAD $commitid;
|
print HEAD $commitid;
|
||||||
close HEAD;
|
close HEAD;
|
||||||
system('git-update-ref', 'HEAD', "$ps->{branch}");
|
system('git-update-ref', 'HEAD', "$ps->{branch}");
|
||||||
@ -482,21 +577,78 @@ foreach my $ps (@psets) {
|
|||||||
print " + tree $tree\n";
|
print " + tree $tree\n";
|
||||||
print " + commit $commitid\n";
|
print " + commit $commitid\n";
|
||||||
$opt_v && print " + commit date is $ps->{date} \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 {
|
sub apply_import {
|
||||||
my $ps = shift;
|
my $ps = shift;
|
||||||
my $bname = git_branchname($ps->{id});
|
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 $?;
|
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 $?;
|
die "Cannot rsync import:$!" if $?;
|
||||||
|
|
||||||
`rm -fr $tmp/import`;
|
rmtree("$tmp/import");
|
||||||
die "Cannot remove tempdir: $!" if $?;
|
die "Cannot remove tempdir: $!" if $?;
|
||||||
|
|
||||||
|
|
||||||
@ -506,10 +658,10 @@ sub apply_import {
|
|||||||
sub apply_cset {
|
sub apply_cset {
|
||||||
my $ps = shift;
|
my $ps = shift;
|
||||||
|
|
||||||
`mkdir -p $tmp`;
|
mkpath($tmp);
|
||||||
|
|
||||||
# get the changeset
|
# 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 $?;
|
die "Cannot get changeset: $!" if $?;
|
||||||
|
|
||||||
# apply patches
|
# apply patches
|
||||||
@ -533,22 +685,27 @@ sub apply_cset {
|
|||||||
$orig =~ s/\.modified$//; # lazy
|
$orig =~ s/\.modified$//; # lazy
|
||||||
$orig =~ s!^\Q$tmp\E/changeset/patches/!!;
|
$orig =~ s!^\Q$tmp\E/changeset/patches/!!;
|
||||||
#print "rsync -p '$mod' '$orig'";
|
#print "rsync -p '$mod' '$orig'";
|
||||||
`rsync -p $mod ./$orig`;
|
system('rsync','-p',$mod,"./$orig");
|
||||||
die "Problem applying binary changes! $!" if $?;
|
die "Problem applying binary changes! $!" if $?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
# bring in new files
|
# 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
|
# deleted files are hinted from the commitlog processing
|
||||||
|
|
||||||
`rm -fr $tmp/changeset`;
|
rmtree("$tmp/changeset");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
# =for reference
|
# =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
|
# Revision: moodle-org--moodle--1.3.3--patch-15
|
||||||
# Archive: arch-eduforge@catalyst.net.nz--2004
|
# Archive: arch-eduforge@catalyst.net.nz--2004
|
||||||
# Creator: Penny Leach <penny@catalyst.net.nz>
|
# Creator: Penny Leach <penny@catalyst.net.nz>
|
||||||
@ -566,70 +723,85 @@ sub apply_cset {
|
|||||||
# admin/editor.html backup/lib.php backup/restore.php
|
# 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
|
# 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: Updating to latest from MOODLE_14_STABLE (1.4.5+)
|
||||||
|
# summary can be multiline with a leading space just like the above fields
|
||||||
# Keywords:
|
# Keywords:
|
||||||
#
|
#
|
||||||
# Updating yadda tadda tadda madda
|
# Updating yadda tadda tadda madda
|
||||||
sub parselog {
|
sub parselog {
|
||||||
my $log = shift;
|
my ($ps, $log) = @_;
|
||||||
#print $log;
|
my $key = undef;
|
||||||
|
|
||||||
my (@add, @del, @mod, @ren, @kw, $sum, $msg );
|
# headers we want that contain filenames:
|
||||||
|
my %want_headers = (
|
||||||
if ($log =~ m/(?:\n|^)New-files:(.*?)(?=\n\w)/s ) {
|
new_files => 1,
|
||||||
my $files = $1;
|
modified_files => 1,
|
||||||
@add = split(m/\s+/s, $files);
|
renamed_files => 1,
|
||||||
}
|
renamed_directories => 1,
|
||||||
|
removed_files => 1,
|
||||||
if ($log =~ m/(?:\n|^)Removed-files:(.*?)(?=\n\w)/s ) {
|
removed_directories => 1,
|
||||||
my $files = $1;
|
);
|
||||||
@del = split(m/\s+/s, $files);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($log =~ m/(?:\n|^)Modified-files:(.*?)(?=\n\w)/s ) {
|
chomp (@$log);
|
||||||
my $files = $1;
|
while ($_ = shift @$log) {
|
||||||
@mod = split(m/\s+/s, $files);
|
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 ) {
|
# skip Arch control files, unescape pika-escaped files
|
||||||
my $files = $1;
|
foreach my $k (keys %want_headers) {
|
||||||
@ren = split(m/\s+/s, $files);
|
next unless (defined $ps->{$k});
|
||||||
}
|
|
||||||
|
|
||||||
$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) ) {
|
|
||||||
my @tmp = ();
|
my @tmp = ();
|
||||||
while (my $t = pop @$ref) {
|
foreach my $t (@{$ps->{$k}}) {
|
||||||
next unless length ($t);
|
next unless length ($t);
|
||||||
next if $t =~ m!\{arch\}/!;
|
next if $t =~ m!\{arch\}/!;
|
||||||
next if $t =~ m!\.arch-ids/!;
|
next if $t =~ m!\.arch-ids/!;
|
||||||
next if $t =~ m!\.arch-inventory$!;
|
# 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?
|
# 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.
|
# we can assume that any filename with \ indicates some pika escaping that we want to get rid of.
|
||||||
if ($t =~ /\\/ ){
|
if ($t =~ /\\/ ){
|
||||||
$t = `tla escape --unescaped '$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
|
# 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;
|
return @parents;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -850,3 +1025,45 @@ sub commitid2pset {
|
|||||||
|| (print Dumper(sort keys %psets)) && die "Cannot find patchset for $name";
|
|| (print Dumper(sort keys %psets)) && die "Cannot find patchset for $name";
|
||||||
return $ps;
|
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/"
|
rm -rf "$GIT_DIR/refs/bisect/"
|
||||||
mkdir "$GIT_DIR/refs/bisect"
|
mkdir "$GIT_DIR/refs/bisect"
|
||||||
{
|
{
|
||||||
echo -n "git-bisect start"
|
printf "git-bisect start"
|
||||||
sq "$@"
|
sq "$@"
|
||||||
} >"$GIT_DIR/BISECT_LOG"
|
} >"$GIT_DIR/BISECT_LOG"
|
||||||
sq "$@" >"$GIT_DIR/BISECT_NAMES"
|
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]"`
|
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
|
i=1
|
||||||
while read commit
|
while read commit
|
||||||
do
|
do
|
||||||
@ -262,10 +271,7 @@ do
|
|||||||
case "$numbered" in
|
case "$numbered" in
|
||||||
'') num= ;;
|
'') num= ;;
|
||||||
*)
|
*)
|
||||||
case $total in
|
num=`printf "$numfmt" $i` ;;
|
||||||
1) num= ;;
|
|
||||||
*) num=' '`printf "%d/%d" $i $total` ;;
|
|
||||||
esac
|
|
||||||
esac
|
esac
|
||||||
|
|
||||||
file=`printf '%04d-%stxt' $i "$title"`
|
file=`printf '%04d-%stxt' $i "$title"`
|
||||||
|
@ -87,15 +87,16 @@ case "${1:-.}${2:-.}${3:-.}" in
|
|||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
# Create the working tree file, with the correct permission bits.
|
# Be careful for funny filename such as "-L" in "$4", which
|
||||||
# we can not rely on the fact that our tree has the path, because
|
# would confuse "merge" greatly.
|
||||||
# we allow the merge to be done in an unchecked-out working tree.
|
src1=`git-unpack-file $2`
|
||||||
rm -f "$4" &&
|
merge "$src1" "$orig" "$src2"
|
||||||
git-cat-file blob "$2" >"$4" &&
|
|
||||||
case "$6" in *7??) chmod +x "$4" ;; esac &&
|
|
||||||
merge "$4" "$orig" "$src2"
|
|
||||||
ret=$?
|
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
|
if [ "$6" != "$7" ]; then
|
||||||
echo "ERROR: Permissions conflict: $5->$6,$7."
|
echo "ERROR: Permissions conflict: $5->$6,$7."
|
||||||
|
@ -280,6 +280,16 @@ def updateFileExt(sha, mode, path, updateCache, updateWd):
|
|||||||
runProgram(['git-update-index', '--add', '--cacheinfo',
|
runProgram(['git-update-index', '--add', '--cacheinfo',
|
||||||
'0%o' % mode, sha, path])
|
'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):
|
def removeFile(clean, path):
|
||||||
updateCache = cacheOnly or clean
|
updateCache = cacheOnly or clean
|
||||||
updateWd = not cacheOnly
|
updateWd = not cacheOnly
|
||||||
@ -590,6 +600,8 @@ def processRenames(renamesA, renamesB, branchNameA, branchNameB):
|
|||||||
else:
|
else:
|
||||||
dstName2 = ren1.dstName
|
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, ren1.dstSha, ren1.dstMode, dstName1)
|
||||||
updateFile(False, ren2.dstSha, ren2.dstMode, dstName2)
|
updateFile(False, ren2.dstSha, ren2.dstMode, dstName2)
|
||||||
else:
|
else:
|
||||||
@ -611,8 +623,11 @@ def processRenames(renamesA, renamesB, branchNameA, branchNameB):
|
|||||||
cleanMerge = False
|
cleanMerge = False
|
||||||
|
|
||||||
if not cacheOnly:
|
if not cacheOnly:
|
||||||
updateFileExt(ren1.dstSha, ren1.dstMode, ren1.dstName,
|
setIndexStages(ren1.dstName,
|
||||||
updateCache=True, updateWd=False)
|
ren1.srcSha, ren1.srcMode,
|
||||||
|
ren1.dstSha, ren1.dstMode,
|
||||||
|
ren2.dstSha, ren2.dstMode)
|
||||||
|
|
||||||
updateFile(clean, resSha, resMode, ren1.dstName)
|
updateFile(clean, resSha, resMode, ren1.dstName)
|
||||||
else:
|
else:
|
||||||
# Renamed in 1, maybe changed in 2
|
# Renamed in 1, maybe changed in 2
|
||||||
@ -672,11 +687,24 @@ def processRenames(renamesA, renamesB, branchNameA, branchNameB):
|
|||||||
tryMerge = True
|
tryMerge = True
|
||||||
|
|
||||||
if tryMerge:
|
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] = \
|
[resSha, resMode, clean, merge] = \
|
||||||
mergeFile(ren1.srcName, ren1.srcSha, ren1.srcMode,
|
mergeFile(oName, oSHA1, oMode,
|
||||||
ren1.dstName, ren1.dstSha, ren1.dstMode,
|
aName, aSHA1, aMode,
|
||||||
ren1.srcName, srcShaOtherBranch, srcModeOtherBranch,
|
bName, bSHA1, bMode,
|
||||||
branchName1, branchName2)
|
aBranch, bBranch);
|
||||||
|
|
||||||
if merge or not clean:
|
if merge or not clean:
|
||||||
output('Renaming', fmtRename(ren1.srcName, ren1.dstName))
|
output('Renaming', fmtRename(ren1.srcName, ren1.dstName))
|
||||||
@ -690,8 +718,11 @@ def processRenames(renamesA, renamesB, branchNameA, branchNameB):
|
|||||||
cleanMerge = False
|
cleanMerge = False
|
||||||
|
|
||||||
if not cacheOnly:
|
if not cacheOnly:
|
||||||
updateFileExt(ren1.dstSha, ren1.dstMode, ren1.dstName,
|
setIndexStages(ren1.dstName,
|
||||||
updateCache=True, updateWd=False)
|
oSHA1, oMode,
|
||||||
|
aSHA1, aMode,
|
||||||
|
bSHA1, bMode)
|
||||||
|
|
||||||
updateFile(clean, resSha, resMode, ren1.dstName)
|
updateFile(clean, resSha, resMode, ren1.dstName)
|
||||||
|
|
||||||
return cleanMerge
|
return cleanMerge
|
||||||
|
@ -62,7 +62,7 @@ my $safesrc;
|
|||||||
my (%overwritten, %srcForDst);
|
my (%overwritten, %srcForDst);
|
||||||
|
|
||||||
$/ = "\0";
|
$/ = "\0";
|
||||||
open(F,"-|","git-ls-files","-z")
|
open(F, 'git-ls-files -z |')
|
||||||
or die "Failed to open pipe from git-ls-files: " . $!;
|
or die "Failed to open pipe from git-ls-files: " . $!;
|
||||||
|
|
||||||
@allfiles = map { chomp; $_; } <F>;
|
@allfiles = map { chomp; $_; } <F>;
|
||||||
|
@ -16,7 +16,11 @@ do
|
|||||||
done
|
done
|
||||||
|
|
||||||
sync
|
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 /{
|
sed -ne '/unreachable /{
|
||||||
s/unreachable [^ ][^ ]* //
|
s/unreachable [^ ][^ ]* //
|
||||||
s|\(..\)|\1/|p
|
s|\(..\)|\1/|p
|
||||||
|
@ -19,10 +19,10 @@ esac
|
|||||||
usage () {
|
usage () {
|
||||||
case "$me" in
|
case "$me" in
|
||||||
cherry-pick)
|
cherry-pick)
|
||||||
die "usage git $me [-n] [-r] <commit-ish>"
|
die "usage git $me [--edit] [-n] [-r] <commit-ish>"
|
||||||
;;
|
;;
|
||||||
revert)
|
revert)
|
||||||
die "usage git $me [-n] <commit-ish>"
|
die "usage git $me [--edit | --no-edit] [-n] <commit-ish>"
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
}
|
}
|
||||||
@ -38,7 +38,7 @@ do
|
|||||||
-e|--e|--ed|--edi|--edit)
|
-e|--e|--ed|--edi|--edit)
|
||||||
edit=-e
|
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=
|
edit=
|
||||||
;;
|
;;
|
||||||
-r|--r|--re|--rep|--repl|--repla|--replay)
|
-r|--r|--re|--rep|--repl|--repla|--replay)
|
||||||
|
@ -13,7 +13,7 @@ report () {
|
|||||||
trailer=""
|
trailer=""
|
||||||
while read status name newname
|
while read status name newname
|
||||||
do
|
do
|
||||||
echo -n "$header"
|
printf '%s' "$header"
|
||||||
header=""
|
header=""
|
||||||
trailer="#
|
trailer="#
|
||||||
"
|
"
|
||||||
@ -27,7 +27,7 @@ report () {
|
|||||||
U ) echo "# unmerged: $name";;
|
U ) echo "# unmerged: $name";;
|
||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
echo -n "$trailer"
|
printf '%s' "$trailer"
|
||||||
[ "$header" ]
|
[ "$header" ]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
18
git.c
18
git.c
@ -8,15 +8,12 @@
|
|||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
#include "git-compat-util.h"
|
||||||
|
|
||||||
#ifndef PATH_MAX
|
#ifndef PATH_MAX
|
||||||
# define PATH_MAX 4096
|
# define PATH_MAX 4096
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef NO_SETENV
|
|
||||||
extern int gitsetenv(char *name, char *value, int overwrite);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static const char git_usage[] =
|
static const char git_usage[] =
|
||||||
"Usage: git [--version] [--exec-path[=GIT_EXEC_PATH]] [--help] COMMAND [ ARGS ]";
|
"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__
|
#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__));
|
__attribute__((__format__(__printf__, 2, 3), __noreturn__));
|
||||||
#endif
|
#endif
|
||||||
static void usage(const char *exec_path, const char *fmt, ...)
|
static void cmd_usage(const char *exec_path, const char *fmt, ...)
|
||||||
{
|
{
|
||||||
if (fmt) {
|
if (fmt) {
|
||||||
va_list ap;
|
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_len = len + strlen(old_path) + 1;
|
||||||
|
|
||||||
path = malloc(path_len + 1);
|
path = malloc(path_len + 1);
|
||||||
path[path_len + 1] = '\0';
|
|
||||||
|
|
||||||
memcpy(path, dir, len);
|
memcpy(path, dir, len);
|
||||||
path[len] = ':';
|
path[len] = ':';
|
||||||
@ -255,12 +251,12 @@ int main(int argc, char **argv, char **envp)
|
|||||||
else if (!strcmp(arg, "help"))
|
else if (!strcmp(arg, "help"))
|
||||||
show_help = 1;
|
show_help = 1;
|
||||||
else if (!show_help)
|
else if (!show_help)
|
||||||
usage(NULL, NULL);
|
cmd_usage(NULL, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (i >= argc || show_help) {
|
if (i >= argc || show_help) {
|
||||||
if (i >= argc)
|
if (i >= argc)
|
||||||
usage(exec_path, NULL);
|
cmd_usage(exec_path, NULL);
|
||||||
|
|
||||||
show_man_page(argv[i]);
|
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,
|
len += snprintf(git_command + len, sizeof(git_command) - len,
|
||||||
"/git-%s", argv[i]);
|
"/git-%s", argv[i]);
|
||||||
if (sizeof(git_command) <= len) {
|
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);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -298,7 +294,7 @@ int main(int argc, char **argv, char **envp)
|
|||||||
execve(git_command, &argv[i], envp);
|
execve(git_command, &argv[i], envp);
|
||||||
|
|
||||||
if (errno == ENOENT)
|
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",
|
fprintf(stderr, "Failed to run command '%s': %s\n",
|
||||||
git_command, strerror(errno));
|
git_command, strerror(errno));
|
||||||
|
538
gitk
538
gitk
@ -16,22 +16,9 @@ proc gitdir {} {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
proc getcommits {rargs} {
|
proc parse_args {rargs} {
|
||||||
global commits commfd phase canv mainfont env
|
global parsed_args
|
||||||
global startmsecs nextupdate ncmupdate
|
|
||||||
global ctext maincursor textcursor leftover gitencoding
|
|
||||||
|
|
||||||
# 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 {
|
if [catch {
|
||||||
set parse_args [concat --default HEAD $rargs]
|
set parse_args [concat --default HEAD $rargs]
|
||||||
set parsed_args [split [eval exec git-rev-parse $parse_args] "\n"]
|
set parsed_args [split [eval exec git-rev-parse $parse_args] "\n"]
|
||||||
@ -42,26 +29,56 @@ proc getcommits {rargs} {
|
|||||||
}
|
}
|
||||||
set parsed_args $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 {
|
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] {
|
} err] {
|
||||||
puts stderr "Error executing git-rev-list: $err"
|
puts stderr "Error executing git-rev-list: $err"
|
||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
set leftover {}
|
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]
|
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
|
. config -cursor watch
|
||||||
settextcursor 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} {
|
proc getcommitlines {commfd} {
|
||||||
global commits parents cdate children
|
global oldcommits commits parents cdate children nchildren
|
||||||
global commitlisted phase nextupdate
|
global commitlisted phase nextupdate
|
||||||
global stopped redisplaying leftover
|
global stopped redisplaying leftover
|
||||||
|
global canv
|
||||||
|
|
||||||
set stuff [read $commfd]
|
set stuff [read $commfd]
|
||||||
if {$stuff == {}} {
|
if {$stuff == {}} {
|
||||||
@ -122,7 +139,7 @@ proc getcommitlines {commfd} {
|
|||||||
lappend commits $id
|
lappend commits $id
|
||||||
set commitlisted($id) 1
|
set commitlisted($id) 1
|
||||||
parsecommit $id $cmit 1 [lrange $ids 1 end]
|
parsecommit $id $cmit 1 [lrange $ids 1 end]
|
||||||
drawcommit $id
|
drawcommit $id 1
|
||||||
if {[clock clicks -milliseconds] >= $nextupdate} {
|
if {[clock clicks -milliseconds] >= $nextupdate} {
|
||||||
doupdate 1
|
doupdate 1
|
||||||
}
|
}
|
||||||
@ -132,7 +149,7 @@ proc getcommitlines {commfd} {
|
|||||||
set stopped 0
|
set stopped 0
|
||||||
set phase "getcommits"
|
set phase "getcommits"
|
||||||
foreach id $commits {
|
foreach id $commits {
|
||||||
drawcommit $id
|
drawcommit $id 1
|
||||||
if {$stopped} break
|
if {$stopped} break
|
||||||
if {[clock clicks -milliseconds] >= $nextupdate} {
|
if {[clock clicks -milliseconds] >= $nextupdate} {
|
||||||
doupdate 1
|
doupdate 1
|
||||||
@ -168,16 +185,99 @@ proc readcommit {id} {
|
|||||||
parsecommit $id $contents 0 {}
|
parsecommit $id $contents 0 {}
|
||||||
}
|
}
|
||||||
|
|
||||||
proc parsecommit {id contents listed olds} {
|
proc updatecommits {rargs} {
|
||||||
global commitinfo children nchildren parents nparents cdate ncleft
|
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)]} {
|
if {![info exists nchildren($id)]} {
|
||||||
set children($id) {}
|
set children($id) {}
|
||||||
set nchildren($id) 0
|
set nchildren($id) 0
|
||||||
@ -196,6 +296,19 @@ proc parsecommit {id contents listed olds} {
|
|||||||
incr ncleft($p)
|
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]
|
set hdrend [string first "\n\n" $contents]
|
||||||
if {$hdrend < 0} {
|
if {$hdrend < 0} {
|
||||||
# should never happen...
|
# should never happen...
|
||||||
@ -243,6 +356,9 @@ proc readrefs {} {
|
|||||||
global tagids idtags headids idheads tagcontents
|
global tagids idtags headids idheads tagcontents
|
||||||
global otherrefids idotherrefs
|
global otherrefids idotherrefs
|
||||||
|
|
||||||
|
foreach v {tagids idtags headids idheads otherrefids idotherrefs} {
|
||||||
|
catch {unset $v}
|
||||||
|
}
|
||||||
set refd [open [list | git-ls-remote [gitdir]] r]
|
set refd [open [list | git-ls-remote [gitdir]] r]
|
||||||
while {0 <= [set n [gets $refd line]]} {
|
while {0 <= [set n [gets $refd line]]} {
|
||||||
if {![regexp {^([0-9a-f]{40}) refs/([^^]*)$} $line \
|
if {![regexp {^([0-9a-f]{40}) refs/([^^]*)$} $line \
|
||||||
@ -292,7 +408,7 @@ proc error_popup msg {
|
|||||||
tkwait window $w
|
tkwait window $w
|
||||||
}
|
}
|
||||||
|
|
||||||
proc makewindow {} {
|
proc makewindow {rargs} {
|
||||||
global canv canv2 canv3 linespc charspc ctext cflist textfont
|
global canv canv2 canv3 linespc charspc ctext cflist textfont
|
||||||
global findtype findtypemenu findloc findstring fstring geometry
|
global findtype findtypemenu findloc findstring fstring geometry
|
||||||
global entries sha1entry sha1string sha1but
|
global entries sha1entry sha1string sha1but
|
||||||
@ -302,6 +418,7 @@ proc makewindow {} {
|
|||||||
menu .bar
|
menu .bar
|
||||||
.bar add cascade -label "File" -menu .bar.file
|
.bar add cascade -label "File" -menu .bar.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 "Reread references" -command rereadrefs
|
||||||
.bar.file add command -label "Quit" -command doquit
|
.bar.file add command -label "Quit" -command doquit
|
||||||
menu .bar.edit
|
menu .bar.edit
|
||||||
@ -719,7 +836,6 @@ proc assigncolor {id} {
|
|||||||
|
|
||||||
proc initgraph {} {
|
proc initgraph {} {
|
||||||
global canvy canvy0 lineno numcommits nextcolor linespc
|
global canvy canvy0 lineno numcommits nextcolor linespc
|
||||||
global mainline mainlinearrow sidelines
|
|
||||||
global nchildren ncleft
|
global nchildren ncleft
|
||||||
global displist nhyperspace
|
global displist nhyperspace
|
||||||
|
|
||||||
@ -728,9 +844,11 @@ proc initgraph {} {
|
|||||||
set canvy $canvy0
|
set canvy $canvy0
|
||||||
set lineno -1
|
set lineno -1
|
||||||
set numcommits 0
|
set numcommits 0
|
||||||
catch {unset mainline}
|
foreach v {mainline mainlinearrow sidelines colormap cornercrossings
|
||||||
catch {unset mainlinearrow}
|
crossings idline lineid} {
|
||||||
catch {unset sidelines}
|
global $v
|
||||||
|
catch {unset $v}
|
||||||
|
}
|
||||||
foreach id [array names nchildren] {
|
foreach id [array names nchildren] {
|
||||||
set ncleft($id) $nchildren($id)
|
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
|
return $level
|
||||||
}
|
}
|
||||||
|
|
||||||
proc drawcommit {id} {
|
proc drawcommit {id reading} {
|
||||||
global phase todo nchildren datemode nextupdate revlistorder
|
global phase todo nchildren datemode nextupdate revlistorder ncleft
|
||||||
global numcommits ncmupdate displayorder todo onscreen parents
|
global numcommits ncmupdate displayorder todo onscreen parents
|
||||||
|
global commitlisted commitordered
|
||||||
|
|
||||||
if {$phase != "incrdraw"} {
|
if {$phase != "incrdraw"} {
|
||||||
set phase incrdraw
|
set phase incrdraw
|
||||||
set displayorder {}
|
set displayorder {}
|
||||||
set todo {}
|
set todo {}
|
||||||
initgraph
|
initgraph
|
||||||
|
catch {unset commitordered}
|
||||||
}
|
}
|
||||||
|
set commitordered($id) 1
|
||||||
if {$nchildren($id) == 0} {
|
if {$nchildren($id) == 0} {
|
||||||
lappend todo $id
|
lappend todo $id
|
||||||
set onscreen($id) 0
|
set onscreen($id) 0
|
||||||
@ -1436,35 +1548,44 @@ proc drawcommit {id} {
|
|||||||
updatetodo $level 0
|
updatetodo $level 0
|
||||||
} else {
|
} else {
|
||||||
set level [decidenext 1]
|
set level [decidenext 1]
|
||||||
if {$level == {} || $id != [lindex $todo $level]} {
|
if {$level == {} || $level < 0} return
|
||||||
return
|
|
||||||
}
|
|
||||||
while 1 {
|
while 1 {
|
||||||
|
set id [lindex $todo $level]
|
||||||
|
if {![info exists commitordered($id)]} {
|
||||||
|
break
|
||||||
|
}
|
||||||
lappend displayorder [lindex $todo $level]
|
lappend displayorder [lindex $todo $level]
|
||||||
if {[updatetodo $level $datemode]} {
|
if {[updatetodo $level $datemode]} {
|
||||||
set level [decidenext 1]
|
set level [decidenext 1]
|
||||||
if {$level == {}} break
|
if {$level == {} || $level < 0} break
|
||||||
}
|
|
||||||
set id [lindex $todo $level]
|
|
||||||
if {![info exists commitlisted($id)]} {
|
|
||||||
break
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
drawmore 1
|
drawmore $reading
|
||||||
}
|
}
|
||||||
|
|
||||||
proc finishcommits {} {
|
proc finishcommits {} {
|
||||||
global phase
|
global phase oldcommits commits
|
||||||
global canv mainfont ctext maincursor textcursor
|
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 delete all
|
||||||
$canv create text 3 3 -anchor nw -text "No commits selected" \
|
$canv create text 3 3 -anchor nw -text "No commits selected" \
|
||||||
-font $mainfont -tags textitems
|
-font $mainfont -tags textitems
|
||||||
set phase {}
|
set phase {}
|
||||||
} else {
|
|
||||||
drawrest
|
|
||||||
}
|
}
|
||||||
. config -cursor $maincursor
|
. config -cursor $maincursor
|
||||||
settextcursor $textcursor
|
settextcursor $textcursor
|
||||||
@ -1498,7 +1619,7 @@ proc drawgraph {} {
|
|||||||
|
|
||||||
proc drawrest {} {
|
proc drawrest {} {
|
||||||
global phase stopped redisplaying selectedline
|
global phase stopped redisplaying selectedline
|
||||||
global datemode todo displayorder
|
global datemode todo displayorder ncleft
|
||||||
global numcommits ncmupdate
|
global numcommits ncmupdate
|
||||||
global nextupdate startmsecs revlistorder
|
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
|
drawmore 0
|
||||||
set phase {}
|
set phase {}
|
||||||
set drawmsecs [expr {[clock clicks -milliseconds] - $startmsecs}]
|
set drawmsecs [expr {[clock clicks -milliseconds] - $startmsecs}]
|
||||||
@ -3578,9 +3706,6 @@ proc rereadrefs {} {
|
|||||||
set ref($id) [listrefs $id]
|
set ref($id) [listrefs $id]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
foreach v {tagids idtags headids idheads otherrefids idotherrefs} {
|
|
||||||
catch {unset $v}
|
|
||||||
}
|
|
||||||
readrefs
|
readrefs
|
||||||
set refids [lsort -unique [concat $refids [array names idtags] \
|
set refids [lsort -unique [concat $refids [array names idtags] \
|
||||||
[array names idheads] [array names idotherrefs]]]
|
[array names idheads] [array names idotherrefs]]]
|
||||||
@ -3689,17 +3814,294 @@ proc formatdate {d} {
|
|||||||
return [clock format $d -format "%Y-%m-%d %H:%M:%S"]
|
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...
|
# defaults...
|
||||||
set datemode 0
|
set datemode 0
|
||||||
set diffopts "-U 5 -p"
|
set diffopts "-U 5 -p"
|
||||||
set wrcomcmd "git-diff-tree --stdin -p --pretty"
|
set wrcomcmd "git-diff-tree --stdin -p --pretty"
|
||||||
|
|
||||||
set gitencoding ""
|
set gitencoding {}
|
||||||
catch {
|
catch {
|
||||||
set gitencoding [exec git-repo-config --get i18n.commitencoding]
|
set gitencoding [exec git-repo-config --get i18n.commitencoding]
|
||||||
}
|
}
|
||||||
if {$gitencoding == ""} {
|
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}
|
set mainfont {Helvetica 9}
|
||||||
@ -3738,6 +4140,6 @@ set redisplaying 0
|
|||||||
set stuffsaved 0
|
set stuffsaved 0
|
||||||
set patchnum 0
|
set patchnum 0
|
||||||
setcoords
|
setcoords
|
||||||
makewindow
|
makewindow $revtreeargs
|
||||||
readrefs
|
readrefs
|
||||||
getcommits $revtreeargs
|
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));
|
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[] =
|
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)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
@ -31,26 +39,41 @@ int main(int argc, char **argv)
|
|||||||
int write_object = 0;
|
int write_object = 0;
|
||||||
const char *prefix = NULL;
|
const char *prefix = NULL;
|
||||||
int prefix_length = -1;
|
int prefix_length = -1;
|
||||||
|
int no_more_flags = 0;
|
||||||
|
|
||||||
for (i = 1 ; i < argc; i++) {
|
for (i = 1 ; i < argc; i++) {
|
||||||
if (!strcmp(argv[i], "-t")) {
|
if (!no_more_flags && argv[i][0] == '-') {
|
||||||
if (argc <= ++i)
|
if (!strcmp(argv[i], "-t")) {
|
||||||
die(hash_object_usage);
|
if (argc <= ++i)
|
||||||
type = argv[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;
|
|
||||||
}
|
}
|
||||||
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 {
|
else {
|
||||||
const char *arg = argv[i];
|
const char *arg = argv[i];
|
||||||
if (0 <= prefix_length)
|
if (0 <= prefix_length)
|
||||||
arg = prefix_filename(prefix, prefix_length,
|
arg = prefix_filename(prefix, prefix_length,
|
||||||
arg);
|
arg);
|
||||||
hash_object(arg, type, write_object);
|
hash_object(arg, type, write_object);
|
||||||
|
no_more_flags = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -237,9 +237,7 @@ int main(int argc, char **argv)
|
|||||||
|
|
||||||
for (i = 1; i < argc; i++, argv++) {
|
for (i = 1; i < argc; i++, argv++) {
|
||||||
char *arg = argv[1];
|
char *arg = argv[1];
|
||||||
if (arg[0] != '-')
|
if (!strncmp(arg, "--template=", 11))
|
||||||
break;
|
|
||||||
else if (!strncmp(arg, "--template=", 11))
|
|
||||||
template_dir = arg+11;
|
template_dir = arg+11;
|
||||||
else
|
else
|
||||||
die(init_db_usage);
|
die(init_db_usage);
|
||||||
|
@ -8,12 +8,9 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <iconv.h>
|
#include <iconv.h>
|
||||||
|
#include "git-compat-util.h"
|
||||||
#include "cache.h"
|
#include "cache.h"
|
||||||
|
|
||||||
#ifdef NO_STRCASESTR
|
|
||||||
extern char *gitstrcasestr(const char *haystack, const char *needle);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static FILE *cmitmsg, *patchfile;
|
static FILE *cmitmsg, *patchfile;
|
||||||
|
|
||||||
static int keep_subject = 0;
|
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 *pa = a;
|
||||||
const struct object * const *pb = b;
|
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)
|
void set_object_refs(struct object *obj, struct object_refs *refs)
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
#include "pack.h"
|
#include "pack.h"
|
||||||
#include "csum-file.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 {
|
struct object_entry {
|
||||||
unsigned char sha1[20];
|
unsigned char sha1[20];
|
||||||
|
@ -173,7 +173,7 @@ static void run_update_post_hook(struct command *cmd)
|
|||||||
argc++;
|
argc++;
|
||||||
}
|
}
|
||||||
argv[argc] = NULL;
|
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;
|
return -1;
|
||||||
filename = ref_file_name(ref);
|
filename = ref_file_name(ref);
|
||||||
lock_filename = ref_lock_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);
|
retval = write_ref_file(filename, lock_filename, fd, sha1);
|
||||||
free(filename);
|
free(filename);
|
||||||
free(lock_filename);
|
free(lock_filename);
|
||||||
@ -358,6 +360,8 @@ int write_ref_sha1_unlocked(const char *ref, const unsigned char *sha1)
|
|||||||
return -1;
|
return -1;
|
||||||
filename = ref_file_name(ref);
|
filename = ref_file_name(ref);
|
||||||
lock_filename = ref_lock_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);
|
fd = open(lock_filename, O_WRONLY | O_CREAT | O_EXCL, 0666);
|
||||||
if (fd < 0) {
|
if (fd < 0) {
|
||||||
error("Writing %s", lock_filename);
|
error("Writing %s", lock_filename);
|
||||||
|
@ -2,13 +2,19 @@
|
|||||||
#include "run-command.h"
|
#include "run-command.h"
|
||||||
#include <sys/wait.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();
|
pid_t pid = fork();
|
||||||
|
|
||||||
if (pid < 0)
|
if (pid < 0)
|
||||||
return -ERR_RUN_COMMAND_FORK;
|
return -ERR_RUN_COMMAND_FORK;
|
||||||
if (!pid) {
|
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);
|
execvp(argv[0], (char *const*) argv);
|
||||||
die("exec %s failed.", argv[0]);
|
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 run_command(const char *cmd, ...)
|
||||||
{
|
{
|
||||||
int argc;
|
int argc;
|
||||||
@ -54,5 +65,5 @@ int run_command(const char *cmd, ...)
|
|||||||
va_end(param);
|
va_end(param);
|
||||||
if (MAX_RUN_COMMAND_ARGS <= argc)
|
if (MAX_RUN_COMMAND_ARGS <= argc)
|
||||||
return error("too many args to run %s", cmd);
|
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,
|
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_v(int argc, char **argv);
|
||||||
int run_command(const char *cmd, ...);
|
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,
|
if (match_refs(local_refs, remote_refs, &remote_tail,
|
||||||
nr_refspec, refspec, send_all))
|
nr_refspec, refspec, send_all))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
if (!remote_refs) {
|
||||||
|
fprintf(stderr, "No refs in common and none specified; doing nothing.\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Finally, tell the other end!
|
* 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 */
|
/* packs */
|
||||||
static struct pack_info {
|
static struct pack_info {
|
||||||
unsigned long latest;
|
|
||||||
struct packed_git *p;
|
struct packed_git *p;
|
||||||
int old_num;
|
int old_num;
|
||||||
int new_num;
|
int new_num;
|
||||||
int nr_alloc;
|
int nr_alloc;
|
||||||
int nr_heads;
|
int nr_heads;
|
||||||
unsigned char (*head)[20];
|
unsigned char (*head)[20];
|
||||||
char dep[0]; /* more */
|
|
||||||
} **info;
|
} **info;
|
||||||
static int num_pack;
|
static int num_pack;
|
||||||
static const char *objdir;
|
static const char *objdir;
|
||||||
static int objdirlen;
|
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)
|
static struct pack_info *find_pack_by_name(const char *name)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
@ -93,25 +67,6 @@ static struct pack_info *find_pack_by_name(const char *name)
|
|||||||
return NULL;
|
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
|
/* Returns non-zero when we detect that the info in the
|
||||||
* old file is useless.
|
* old file is useless.
|
||||||
*/
|
*/
|
||||||
@ -123,72 +78,11 @@ static int parse_pack_def(const char *line, int old_cnt)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
/* The file describes a pack that is no longer here;
|
/* The file describes a pack that is no longer here */
|
||||||
* dependencies between packs needs to be recalculated.
|
|
||||||
*/
|
|
||||||
return 1;
|
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
|
/* Returns non-zero when we detect that the info in the
|
||||||
* old file is useless.
|
* old file is useless.
|
||||||
*/
|
*/
|
||||||
@ -212,13 +106,11 @@ static int read_pack_info_file(const char *infofile)
|
|||||||
if (parse_pack_def(line, old_cnt++))
|
if (parse_pack_def(line, old_cnt++))
|
||||||
goto out_stale;
|
goto out_stale;
|
||||||
break;
|
break;
|
||||||
case 'D': /* D ix dep-ix1 dep-ix2... */
|
case 'D': /* we used to emit D but that was misguided. */
|
||||||
if (parse_depend_def(line))
|
goto out_stale;
|
||||||
goto out_stale;
|
|
||||||
break;
|
break;
|
||||||
case 'T': /* T ix sha1 type */
|
case 'T': /* we used to emit T but nobody uses it. */
|
||||||
if (parse_head_def(line))
|
goto out_stale;
|
||||||
goto out_stale;
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
error("unrecognized: %s", line);
|
error("unrecognized: %s", line);
|
||||||
@ -232,32 +124,6 @@ static int read_pack_info_file(const char *infofile)
|
|||||||
return 1;
|
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_)
|
static int compare_info(const void *a_, const void *b_)
|
||||||
{
|
{
|
||||||
struct pack_info * const* a = a_;
|
struct pack_info * const* a = a_;
|
||||||
@ -273,10 +139,11 @@ static int compare_info(const void *a_, const void *b_)
|
|||||||
/* The other way around. */
|
/* The other way around. */
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
if ((*a)->latest < (*b)->latest)
|
/* then it does not matter but at least keep the comparison stable */
|
||||||
return -1;
|
if ((*a)->p == (*b)->p)
|
||||||
else if ((*a)->latest == (*b)->latest)
|
|
||||||
return 0;
|
return 0;
|
||||||
|
else if ((*a)->p < (*b)->p)
|
||||||
|
return -1;
|
||||||
else
|
else
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@ -286,7 +153,6 @@ static void init_pack_info(const char *infofile, int force)
|
|||||||
struct packed_git *p;
|
struct packed_git *p;
|
||||||
int stale;
|
int stale;
|
||||||
int i = 0;
|
int i = 0;
|
||||||
char *dep_temp;
|
|
||||||
|
|
||||||
objdir = get_object_directory();
|
objdir = get_object_directory();
|
||||||
objdirlen = strlen(objdir);
|
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
|
/* we ignore things on alternate path since they are
|
||||||
* not available to the pullers in general.
|
* not available to the pullers in general.
|
||||||
*/
|
*/
|
||||||
if (strncmp(p->pack_name, objdir, objdirlen) ||
|
if (!p->pack_local)
|
||||||
strncmp(p->pack_name + objdirlen, "/pack/", 6))
|
|
||||||
continue;
|
continue;
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
num_pack = i;
|
num_pack = i;
|
||||||
info = xcalloc(num_pack, sizeof(struct pack_info *));
|
info = xcalloc(num_pack, sizeof(struct pack_info *));
|
||||||
for (i = 0, p = packed_git; p; p = p->next) {
|
for (i = 0, p = packed_git; p; p = p->next) {
|
||||||
if (strncmp(p->pack_name, objdir, objdirlen) ||
|
if (!p->pack_local)
|
||||||
p->pack_name[objdirlen] != '/')
|
|
||||||
continue;
|
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]->p = p;
|
||||||
info[i]->old_num = -1;
|
info[i]->old_num = -1;
|
||||||
i++;
|
i++;
|
||||||
@ -321,177 +185,21 @@ static void init_pack_info(const char *infofile, int force)
|
|||||||
for (i = 0; i < num_pack; i++) {
|
for (i = 0; i < num_pack; i++) {
|
||||||
if (stale) {
|
if (stale) {
|
||||||
info[i]->old_num = -1;
|
info[i]->old_num = -1;
|
||||||
memset(info[i]->dep, 0, num_pack);
|
|
||||||
info[i]->nr_heads = 0;
|
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);
|
qsort(info, num_pack, sizeof(info[0]), compare_info);
|
||||||
for (i = 0; i < num_pack; i++)
|
for (i = 0; i < num_pack; i++)
|
||||||
info[i]->new_num = 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)
|
static void write_pack_info_file(FILE *fp)
|
||||||
{
|
{
|
||||||
int i, j;
|
int i;
|
||||||
for (i = 0; i < num_pack; i++)
|
for (i = 0; i < num_pack; i++)
|
||||||
fprintf(fp, "P %s\n", info[i]->p->pack_name + objdirlen + 6);
|
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)
|
static int update_info_packs(int force)
|
||||||
@ -506,7 +214,6 @@ static int update_info_packs(int force)
|
|||||||
strcpy(name + namelen, "+");
|
strcpy(name + namelen, "+");
|
||||||
|
|
||||||
init_pack_info(infofile, force);
|
init_pack_info(infofile, force);
|
||||||
find_pack_info();
|
|
||||||
|
|
||||||
safe_create_leading_directories(name);
|
safe_create_leading_directories(name);
|
||||||
fp = fopen(name, "w");
|
fp = fopen(name, "w");
|
||||||
@ -530,5 +237,8 @@ int update_server_info(int force)
|
|||||||
errs = errs | update_info_refs(force);
|
errs = errs | update_info_refs(force);
|
||||||
errs = errs | update_info_packs(force);
|
errs = errs | update_info_packs(force);
|
||||||
|
|
||||||
|
/* remove leftover rev-cache file if there is any */
|
||||||
|
unlink(git_path("info/rev-cache"));
|
||||||
|
|
||||||
return errs;
|
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
|
* alternate_object_database. The elements on this list come from
|
||||||
* non-empty elements from colon separated ALTERNATE_DB_ENVIRONMENT
|
* non-empty elements from colon separated ALTERNATE_DB_ENVIRONMENT
|
||||||
* environment variable, and $GIT_OBJECT_DIRECTORY/info/alternates,
|
* environment variable, and $GIT_OBJECT_DIRECTORY/info/alternates,
|
||||||
* whose contents is exactly in the same format as that environment
|
* whose contents is similar to that environment variable but can be
|
||||||
* variable. Its base points at a statically allocated buffer that
|
* LF separated. Its base points at a statically allocated buffer that
|
||||||
* contains "/the/directory/corresponding/to/.git/objects/...", while
|
* contains "/the/directory/corresponding/to/.git/objects/...", while
|
||||||
* its name points just after the slash at the end of ".git/objects/"
|
* 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
|
* 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;
|
const char *cp, *last;
|
||||||
struct alternate_object_database *ent;
|
struct alternate_object_database *ent;
|
||||||
|
const char *objdir = get_object_directory();
|
||||||
int base_len = -1;
|
int base_len = -1;
|
||||||
|
|
||||||
last = alt;
|
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++)
|
for ( ; cp < ep && *cp != sep; cp++)
|
||||||
;
|
;
|
||||||
if (last != cp) {
|
if (last != cp) {
|
||||||
|
struct alternate_object_database *alt;
|
||||||
/* 43 = 40-byte + 2 '/' + terminating NUL */
|
/* 43 = 40-byte + 2 '/' + terminating NUL */
|
||||||
int pfxlen = cp - last;
|
int pfxlen = cp - last;
|
||||||
int entlen = pfxlen + 43;
|
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;
|
pfxlen += base_len;
|
||||||
}
|
}
|
||||||
ent = xmalloc(sizeof(*ent) + entlen);
|
ent = xmalloc(sizeof(*ent) + entlen);
|
||||||
*alt_odb_tail = ent;
|
|
||||||
alt_odb_tail = &(ent->next);
|
|
||||||
ent->next = NULL;
|
|
||||||
if (*last != '/' && relative_base) {
|
if (*last != '/' && relative_base) {
|
||||||
memcpy(ent->base, relative_base, base_len - 1);
|
memcpy(ent->base, relative_base, base_len - 1);
|
||||||
ent->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->name = ent->base + pfxlen + 1;
|
||||||
ent->base[pfxlen] = ent->base[pfxlen + 3] = '/';
|
ent->base[pfxlen] = ent->base[pfxlen + 3] = '/';
|
||||||
ent->base[entlen-1] = 0;
|
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)
|
while (cp < ep && *cp == sep)
|
||||||
cp++;
|
cp++;
|
||||||
@ -531,8 +547,9 @@ void prepare_packed_git(void)
|
|||||||
prepare_packed_git_one(get_object_directory(), 1);
|
prepare_packed_git_one(get_object_directory(), 1);
|
||||||
prepare_alt_odb();
|
prepare_alt_odb();
|
||||||
for (alt = alt_odb_list; alt; alt = alt->next) {
|
for (alt = alt_odb_list; alt; alt = alt->next) {
|
||||||
alt->name[0] = 0;
|
alt->name[-1] = 0;
|
||||||
prepare_packed_git_one(alt->base, 0);
|
prepare_packed_git_one(alt->base, 0);
|
||||||
|
alt->name[-1] = '/';
|
||||||
}
|
}
|
||||||
run_once = 1;
|
run_once = 1;
|
||||||
}
|
}
|
||||||
@ -1511,6 +1528,40 @@ int has_sha1_file(const unsigned char *sha1)
|
|||||||
return find_sha1_file(sha1, &st) ? 1 : 0;
|
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)
|
int index_fd(unsigned char *sha1, int fd, struct stat *st, int write_object, const char *type)
|
||||||
{
|
{
|
||||||
unsigned long size = st->st_size;
|
unsigned long size = st->st_size;
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <fnmatch.h>
|
||||||
#include "cache.h"
|
#include "cache.h"
|
||||||
#include "commit.h"
|
#include "commit.h"
|
||||||
#include "refs.h"
|
#include "refs.h"
|
||||||
|
|
||||||
static const char show_branch_usage[] =
|
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
|
#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
|
/* Parent is the first parent of the commit. We may name it
|
||||||
* as (n+1)th generation ancestor of the same head_name as
|
* 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.
|
* number is better than the name it already has.
|
||||||
*/
|
*/
|
||||||
static void name_parent(struct commit *commit, struct commit *parent)
|
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);
|
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)
|
static void snarf_refs(int head, int tag)
|
||||||
{
|
{
|
||||||
if (head) {
|
if (head) {
|
||||||
@ -400,6 +434,27 @@ static int show_independent(struct commit **rev,
|
|||||||
return 0;
|
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)
|
int main(int ac, char **av)
|
||||||
{
|
{
|
||||||
struct commit *rev[MAX_REVS], *commit;
|
struct commit *rev[MAX_REVS], *commit;
|
||||||
@ -458,17 +513,20 @@ int main(int ac, char **av)
|
|||||||
if (all_heads + all_tags)
|
if (all_heads + all_tags)
|
||||||
snarf_refs(all_heads, all_tags);
|
snarf_refs(all_heads, all_tags);
|
||||||
|
|
||||||
while (0 < ac) {
|
if (ac) {
|
||||||
unsigned char revkey[20];
|
while (0 < ac) {
|
||||||
if (get_sha1(*av, revkey))
|
append_one_rev(*av);
|
||||||
die("bad sha1 reference %s", *av);
|
ac--; av++;
|
||||||
append_ref(*av, revkey);
|
}
|
||||||
ac--; av++;
|
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
/* If still no revs, then add heads */
|
/* If no revs given, then add heads */
|
||||||
if (!ref_name_cnt)
|
|
||||||
snarf_refs(1, 0);
|
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++) {
|
for (num_rev = 0; ref_name[num_rev]; num_rev++) {
|
||||||
unsigned char revkey[20];
|
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
|
swapping compression and hashing order, the person who is making the
|
||||||
modification *should* take notice and update the test vectors here.
|
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
|
. ./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.
|
# init-db has been done in an empty repository.
|
||||||
# make sure it is empty.
|
# make sure it is empty.
|
||||||
|
@ -12,10 +12,6 @@ test -f .git/config && rm .git/config
|
|||||||
git-repo-config core.penguin "little blue"
|
git-repo-config core.penguin "little blue"
|
||||||
|
|
||||||
cat > expect << EOF
|
cat > expect << EOF
|
||||||
#
|
|
||||||
# This is the config file
|
|
||||||
#
|
|
||||||
|
|
||||||
[core]
|
[core]
|
||||||
penguin = little blue
|
penguin = little blue
|
||||||
EOF
|
EOF
|
||||||
@ -25,10 +21,6 @@ test_expect_success 'initial' 'cmp .git/config expect'
|
|||||||
git-repo-config Core.Movie BadPhysics
|
git-repo-config Core.Movie BadPhysics
|
||||||
|
|
||||||
cat > expect << EOF
|
cat > expect << EOF
|
||||||
#
|
|
||||||
# This is the config file
|
|
||||||
#
|
|
||||||
|
|
||||||
[core]
|
[core]
|
||||||
penguin = little blue
|
penguin = little blue
|
||||||
Movie = BadPhysics
|
Movie = BadPhysics
|
||||||
@ -39,10 +31,6 @@ test_expect_success 'mixed case' 'cmp .git/config expect'
|
|||||||
git-repo-config Cores.WhatEver Second
|
git-repo-config Cores.WhatEver Second
|
||||||
|
|
||||||
cat > expect << EOF
|
cat > expect << EOF
|
||||||
#
|
|
||||||
# This is the config file
|
|
||||||
#
|
|
||||||
|
|
||||||
[core]
|
[core]
|
||||||
penguin = little blue
|
penguin = little blue
|
||||||
Movie = BadPhysics
|
Movie = BadPhysics
|
||||||
@ -55,10 +43,6 @@ test_expect_success 'similar section' 'cmp .git/config expect'
|
|||||||
git-repo-config CORE.UPPERCASE true
|
git-repo-config CORE.UPPERCASE true
|
||||||
|
|
||||||
cat > expect << EOF
|
cat > expect << EOF
|
||||||
#
|
|
||||||
# This is the config file
|
|
||||||
#
|
|
||||||
|
|
||||||
[core]
|
[core]
|
||||||
penguin = little blue
|
penguin = little blue
|
||||||
Movie = BadPhysics
|
Movie = BadPhysics
|
||||||
@ -76,10 +60,6 @@ test_expect_success 'replace with non-match (actually matching)' \
|
|||||||
'git-repo-config core.penguin "very blue" !kingpin'
|
'git-repo-config core.penguin "very blue" !kingpin'
|
||||||
|
|
||||||
cat > expect << EOF
|
cat > expect << EOF
|
||||||
#
|
|
||||||
# This is the config file
|
|
||||||
#
|
|
||||||
|
|
||||||
[core]
|
[core]
|
||||||
penguin = very blue
|
penguin = very blue
|
||||||
Movie = BadPhysics
|
Movie = BadPhysics
|
||||||
|
@ -15,7 +15,7 @@ test "$(uname -o 2>/dev/null)" = Cygwin && exit 0
|
|||||||
. ./test-lib.sh
|
. ./test-lib.sh
|
||||||
|
|
||||||
p0='no-funny'
|
p0='no-funny'
|
||||||
p1='tabs and spaces'
|
p1='tabs ," (dq) and spaces'
|
||||||
p2='just space'
|
p2='just space'
|
||||||
|
|
||||||
cat >"$p0" <<\EOF
|
cat >"$p0" <<\EOF
|
||||||
@ -39,7 +39,7 @@ echo "$t0" >t0
|
|||||||
|
|
||||||
echo 'just space
|
echo 'just space
|
||||||
no-funny
|
no-funny
|
||||||
"tabs\tand spaces"' >expected
|
"tabs\t,\" (dq) and spaces"' >expected
|
||||||
test_expect_success 'git-ls-files with-funny' \
|
test_expect_success 'git-ls-files with-funny' \
|
||||||
'git-update-index --add "$p1" &&
|
'git-update-index --add "$p1" &&
|
||||||
git-ls-files >current &&
|
git-ls-files >current &&
|
||||||
@ -47,7 +47,7 @@ test_expect_success 'git-ls-files with-funny' \
|
|||||||
|
|
||||||
echo 'just space
|
echo 'just space
|
||||||
no-funny
|
no-funny
|
||||||
tabs and spaces' >expected
|
tabs ," (dq) and spaces' >expected
|
||||||
test_expect_success 'git-ls-files -z with-funny' \
|
test_expect_success 'git-ls-files -z with-funny' \
|
||||||
'git-ls-files -z | tr \\0 \\012 >current &&
|
'git-ls-files -z | tr \\0 \\012 >current &&
|
||||||
diff -u expected current'
|
diff -u expected current'
|
||||||
@ -57,12 +57,12 @@ echo "$t1" >t1
|
|||||||
|
|
||||||
echo 'just space
|
echo 'just space
|
||||||
no-funny
|
no-funny
|
||||||
"tabs\tand spaces"' >expected
|
"tabs\t,\" (dq) and spaces"' >expected
|
||||||
test_expect_success 'git-ls-tree with funny' \
|
test_expect_success 'git-ls-tree with funny' \
|
||||||
'git-ls-tree -r $t1 | sed -e "s/^[^ ]* //" >current &&
|
'git-ls-tree -r $t1 | sed -e "s/^[^ ]* //" >current &&
|
||||||
diff -u expected 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' \
|
test_expect_success 'git-diff-index with-funny' \
|
||||||
'git-diff-index --name-status $t0 >current &&
|
'git-diff-index --name-status $t0 >current &&
|
||||||
diff -u expected current'
|
diff -u expected current'
|
||||||
@ -72,7 +72,7 @@ test_expect_success 'git-diff-tree with-funny' \
|
|||||||
diff -u expected current'
|
diff -u expected current'
|
||||||
|
|
||||||
echo 'A
|
echo 'A
|
||||||
tabs and spaces' >expected
|
tabs ," (dq) and spaces' >expected
|
||||||
test_expect_success 'git-diff-index -z with-funny' \
|
test_expect_success 'git-diff-index -z with-funny' \
|
||||||
'git-diff-index -z --name-status $t0 | tr \\0 \\012 >current &&
|
'git-diff-index -z --name-status $t0 | tr \\0 \\012 >current &&
|
||||||
diff -u expected 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 &&
|
'git-diff-tree -z --name-status $t0 $t1 | tr \\0 \\012 >current &&
|
||||||
diff -u expected 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' \
|
test_expect_success 'git-diff-tree -C with-funny' \
|
||||||
'git-diff-tree -C --find-copies-harder --name-status \
|
'git-diff-tree -C --find-copies-harder --name-status \
|
||||||
$t0 $t1 | sed -e 's/^C[0-9]*/CNUM/' >current &&
|
$t0 $t1 | sed -e 's/^C[0-9]*/CNUM/' >current &&
|
||||||
diff -u expected 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' \
|
test_expect_success 'git-diff-tree delete with-funny' \
|
||||||
'git-update-index --force-remove "$p0" &&
|
'git-update-index --force-remove "$p0" &&
|
||||||
git-diff-index -M --name-status \
|
git-diff-index -M --name-status \
|
||||||
$t0 | sed -e 's/^R[0-9]*/RNUM/' >current &&
|
$t0 | sed -e 's/^R[0-9]*/RNUM/' >current &&
|
||||||
diff -u expected 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%
|
similarity index NUM%
|
||||||
rename from no-funny
|
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' \
|
test_expect_success 'git-diff-tree delete with-funny' \
|
||||||
'git-diff-index -M -p $t0 |
|
'git-diff-index -M -p $t0 |
|
||||||
@ -105,19 +105,19 @@ test_expect_success 'git-diff-tree delete with-funny' \
|
|||||||
diff -u expected current'
|
diff -u expected current'
|
||||||
|
|
||||||
chmod +x "$p1"
|
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
|
old mode 100644
|
||||||
new mode 100755
|
new mode 100755
|
||||||
similarity index NUM%
|
similarity index NUM%
|
||||||
rename from no-funny
|
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' \
|
test_expect_success 'git-diff-tree delete with-funny' \
|
||||||
'git-diff-index -M -p $t0 |
|
'git-diff-index -M -p $t0 |
|
||||||
sed -e "s/index [0-9]*%/index NUM%/" >current &&
|
sed -e "s/index [0-9]*%/index NUM%/" >current &&
|
||||||
diff -u expected current'
|
diff -u expected current'
|
||||||
|
|
||||||
echo >expected ' "tabs\tand spaces"
|
echo >expected ' "tabs\t,\" (dq) and spaces"
|
||||||
1 files changed, 0 insertions(+), 0 deletions(-)'
|
1 files changed, 0 insertions(+), 0 deletions(-)'
|
||||||
test_expect_success 'git-diff-tree rename with-funny applied' \
|
test_expect_success 'git-diff-tree rename with-funny applied' \
|
||||||
'git-diff-index -M -p $t0 |
|
'git-diff-index -M -p $t0 |
|
||||||
@ -125,7 +125,7 @@ test_expect_success 'git-diff-tree rename with-funny applied' \
|
|||||||
diff -u expected current'
|
diff -u expected current'
|
||||||
|
|
||||||
echo >expected ' no-funny
|
echo >expected ' no-funny
|
||||||
"tabs\tand spaces"
|
"tabs\t,\" (dq) and spaces"
|
||||||
2 files changed, 3 insertions(+), 3 deletions(-)'
|
2 files changed, 3 insertions(+), 3 deletions(-)'
|
||||||
|
|
||||||
test_expect_success 'git-diff-tree delete with-funny applied' \
|
test_expect_success 'git-diff-tree delete with-funny applied' \
|
||||||
|
@ -7,8 +7,9 @@
|
|||||||
# an old counterpart
|
# an old counterpart
|
||||||
|
|
||||||
cd $(dirname $0) || exit 1
|
cd $(dirname $0) || exit 1
|
||||||
|
: ${SHELL_PATH=/bin/sh}
|
||||||
|
|
||||||
tmp=$(mktemp /tmp/tmp-XXXXXXXX)
|
tmp=`pwd`/.tmp$$
|
||||||
|
|
||||||
retval=0
|
retval=0
|
||||||
|
|
||||||
@ -25,13 +26,17 @@ for i in $list; do
|
|||||||
both) pgm="old-git-upload-pack"; replace="old-git-fetch-pack --exec=$pgm";;
|
both) pgm="old-git-upload-pack"; replace="old-git-fetch-pack --exec=$pgm";;
|
||||||
esac
|
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"
|
echo "Testing with $pgm"
|
||||||
sed -e "s/git-fetch-pack/$replace/g" \
|
sed -e "s/git-fetch-pack/$replace/g" \
|
||||||
-e "s/# old fails/warn/" < t5500-fetch-pack.sh > $tmp
|
-e "s/# old fails/warn/" < t5500-fetch-pack.sh > $tmp
|
||||||
|
|
||||||
sh $tmp || retval=$?
|
"$SHELL_PATH" "$tmp" || retval=$?
|
||||||
rm $tmp
|
rm -f "$tmp"
|
||||||
|
|
||||||
test $retval != 0 && exit $retval
|
test $retval != 0 && exit $retval
|
||||||
else
|
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 () {
|
test_done () {
|
||||||
trap - exit
|
trap - exit
|
||||||
case "$test_failure" in
|
case "$test_failure" in
|
||||||
0)
|
0)
|
||||||
# We could:
|
# We could:
|
||||||
# cd .. && rm -fr trash
|
# cd .. && rm -fr trash
|
||||||
# but that means we forbid any tests that use their own
|
# 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.
|
# t/ subdirectory and are run in trash subdirectory.
|
||||||
PATH=$(pwd)/..:$PATH
|
PATH=$(pwd)/..:$PATH
|
||||||
GIT_EXEC_PATH=$(pwd)/..
|
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 repository
|
||||||
test=trash
|
test=trash
|
||||||
rm -fr "$test"
|
rm -fr "$test"
|
||||||
mkdir "$test"
|
mkdir "$test"
|
||||||
cd "$test"
|
cd "$test"
|
||||||
git-init-db --template=../../templates/blt/ 2>/dev/null ||
|
"$GIT_EXEC_PATH/git" init-db --template=../../templates/blt/ 2>/dev/null ||
|
||||||
error "cannot run git-init-db"
|
error "cannot run git init-db -- have you built things yet?"
|
||||||
|
|
||||||
mv .git/hooks .git/hooks-disabled
|
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)
|
if (obj)
|
||||||
n_refs++;
|
n_refs++;
|
||||||
entry->parent = NULL; /* needs to be filled by the user */
|
|
||||||
*list_p = entry;
|
*list_p = entry;
|
||||||
list_p = &entry->next;
|
list_p = &entry->next;
|
||||||
}
|
}
|
||||||
|
1
tree.h
1
tree.h
@ -18,7 +18,6 @@ struct tree_entry_list {
|
|||||||
struct tree *tree;
|
struct tree *tree;
|
||||||
struct blob *blob;
|
struct blob *blob;
|
||||||
} item;
|
} item;
|
||||||
struct tree_entry_list *parent;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct tree {
|
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;
|
int size, len, option;
|
||||||
unsigned int mode;
|
|
||||||
unsigned char sha1[20];
|
|
||||||
struct cache_entry *ce;
|
struct cache_entry *ce;
|
||||||
|
|
||||||
if (sscanf(arg1, "%o", &mode) != 1)
|
if (!verify_path(path))
|
||||||
return -1;
|
|
||||||
if (get_sha1_hex(arg2, sha1))
|
|
||||||
return -1;
|
|
||||||
if (!verify_path(arg3))
|
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
len = strlen(arg3);
|
len = strlen(path);
|
||||||
size = cache_entry_size(len);
|
size = cache_entry_size(len);
|
||||||
ce = xmalloc(size);
|
ce = xmalloc(size);
|
||||||
memset(ce, 0, size);
|
memset(ce, 0, size);
|
||||||
|
|
||||||
memcpy(ce->sha1, sha1, 20);
|
memcpy(ce->sha1, sha1, 20);
|
||||||
memcpy(ce->name, arg3, len);
|
memcpy(ce->name, path, len);
|
||||||
ce->ce_flags = htons(len);
|
ce->ce_flags = create_ce_flags(len, stage);
|
||||||
ce->ce_mode = create_ce_mode(mode);
|
ce->ce_mode = create_ce_mode(mode);
|
||||||
option = allow_add ? ADD_CACHE_OK_TO_ADD : 0;
|
option = allow_add ? ADD_CACHE_OK_TO_ADD : 0;
|
||||||
option |= allow_replace ? ADD_CACHE_OK_TO_REPLACE : 0;
|
option |= allow_replace ? ADD_CACHE_OK_TO_REPLACE : 0;
|
||||||
if (add_cache_entry(ce, option))
|
if (add_cache_entry(ce, option))
|
||||||
return error("%s: cannot add to the index - missing --add option?",
|
return error("%s: cannot add to the index - missing --add option?",
|
||||||
arg3);
|
path);
|
||||||
report("add '%s'", arg3);
|
report("add '%s'", path);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -342,7 +337,24 @@ static void read_index_info(int line_termination)
|
|||||||
char *path_name;
|
char *path_name;
|
||||||
unsigned char sha1[20];
|
unsigned char sha1[20];
|
||||||
unsigned int mode;
|
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);
|
read_line(&buf, stdin, line_termination);
|
||||||
if (buf.eof)
|
if (buf.eof)
|
||||||
break;
|
break;
|
||||||
@ -354,9 +366,19 @@ static void read_index_info(int line_termination)
|
|||||||
tab = strchr(ptr, '\t');
|
tab = strchr(ptr, '\t');
|
||||||
if (!tab || tab - ptr < 41)
|
if (!tab || tab - ptr < 41)
|
||||||
goto bad_line;
|
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] != ' ')
|
if (get_sha1_hex(tab - 40, sha1) || tab[-41] != ' ')
|
||||||
goto bad_line;
|
goto bad_line;
|
||||||
ptr = tab + 1;
|
|
||||||
|
|
||||||
if (line_termination && ptr[0] == '"')
|
if (line_termination && ptr[0] == '"')
|
||||||
path_name = unquote_c_style(ptr, NULL);
|
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[-41] is at the beginning of sha1
|
||||||
*/
|
*/
|
||||||
ptr[-42] = ptr[-1] = 0;
|
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",
|
die("git-update-index: unable to update %s",
|
||||||
path_name);
|
path_name);
|
||||||
}
|
}
|
||||||
@ -449,10 +471,17 @@ int main(int argc, const char **argv)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (!strcmp(path, "--cacheinfo")) {
|
if (!strcmp(path, "--cacheinfo")) {
|
||||||
|
unsigned char sha1[20];
|
||||||
|
unsigned int mode;
|
||||||
|
|
||||||
if (i+3 >= argc)
|
if (i+3 >= argc)
|
||||||
die("git-update-index: --cacheinfo <mode> <sha1> <path>");
|
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;
|
i += 3;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
2
usage.c
2
usage.c
@ -3,7 +3,7 @@
|
|||||||
*
|
*
|
||||||
* Copyright (C) Linus Torvalds, 2005
|
* 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)
|
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;
|
return nr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const char write_tree_usage[] = "git-write-tree [--missing-ok]";
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
int i, funny;
|
int i, funny;
|
||||||
@ -96,7 +98,7 @@ int main(int argc, char **argv)
|
|||||||
if (!strcmp(argv[1], "--missing-ok"))
|
if (!strcmp(argv[1], "--missing-ok"))
|
||||||
missing_ok = 1;
|
missing_ok = 1;
|
||||||
else
|
else
|
||||||
die("unknown option %s", argv[1]);
|
die(write_tree_usage);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (argc > 2)
|
if (argc > 2)
|
||||||
|
Loading…
Reference in New Issue
Block a user