Merge branch 'master' into np/index-pack
* master: (90 commits) gitweb: Better support for non-CSS aware web browsers gitweb: Output also empty patches in "commitdiff" view gitweb: Use git-for-each-ref to generate list of heads and/or tags for-each-ref: "creator" and "creatordate" fields Add --global option to git-repo-config. pack-refs: Store the full name of the ref even when packing only tags. git-clone documentation didn't mention --origin as equivalent of -o Minor grammar fixes for git-diff-index.txt link_temp_to_file: call adjust_shared_perm() only when we created the directory Remove uneccessarily similar printf() from print_ref_list() in builtin-branch pack-objects doesn't create random pack names branch: work in subdirectories. gitweb: Use 's' regexp modifier to secure against filenames with LF gitweb: Secure against commit-ish/tree-ish with the same name as path gitweb: esc_html() author in blame git-svnimport: support for partial imports link_temp_to_file: don't leave the path truncated on adjust_shared_perm failure Move deny_non_fast_forwards handling completely into receive-pack. revision traversal: --unpacked does not limit commit list anymore. Continue traversal when rev-list --unpacked finds a packed commit. ...
This commit is contained in:
commit
407e1d6e12
2
.gitignore
vendored
2
.gitignore
vendored
@ -75,6 +75,7 @@ git-name-rev
|
|||||||
git-mv
|
git-mv
|
||||||
git-pack-redundant
|
git-pack-redundant
|
||||||
git-pack-objects
|
git-pack-objects
|
||||||
|
git-pack-refs
|
||||||
git-parse-remote
|
git-parse-remote
|
||||||
git-patch-id
|
git-patch-id
|
||||||
git-peek-remote
|
git-peek-remote
|
||||||
@ -106,6 +107,7 @@ git-shortlog
|
|||||||
git-show
|
git-show
|
||||||
git-show-branch
|
git-show-branch
|
||||||
git-show-index
|
git-show-index
|
||||||
|
git-show-ref
|
||||||
git-ssh-fetch
|
git-ssh-fetch
|
||||||
git-ssh-pull
|
git-ssh-pull
|
||||||
git-ssh-push
|
git-ssh-push
|
||||||
|
@ -71,12 +71,16 @@ core.preferSymlinkRefs::
|
|||||||
expect HEAD to be a symbolic link.
|
expect HEAD to be a symbolic link.
|
||||||
|
|
||||||
core.logAllRefUpdates::
|
core.logAllRefUpdates::
|
||||||
If true, `git-update-ref` will append a line to
|
Updates to a ref <ref> is logged to the file
|
||||||
"$GIT_DIR/logs/<ref>" listing the new SHA1 and the date/time
|
"$GIT_DIR/logs/<ref>", by appending the new and old
|
||||||
of the update. If the file does not exist it will be
|
SHA1, the date/time and the reason of the update, but
|
||||||
created automatically. This information can be used to
|
only when the file exists. If this configuration
|
||||||
determine what commit was the tip of a branch "2 days ago".
|
variable is set to true, missing "$GIT_DIR/logs/<ref>"
|
||||||
This value is false by default (no logging).
|
file is automatically created for branch heads.
|
||||||
|
|
||||||
|
This information can be used to determine what commit
|
||||||
|
was the tip of a branch "2 days ago". This value is
|
||||||
|
false by default (no automated creation of log files).
|
||||||
|
|
||||||
core.repositoryFormatVersion::
|
core.repositoryFormatVersion::
|
||||||
Internal variable identifying the repository format and layout
|
Internal variable identifying the repository format and layout
|
||||||
|
@ -75,6 +75,7 @@ OPTIONS
|
|||||||
this option is used, neither the `origin` branch nor the
|
this option is used, neither the `origin` branch nor the
|
||||||
default `remotes/origin` file is created.
|
default `remotes/origin` file is created.
|
||||||
|
|
||||||
|
--origin <name>::
|
||||||
-o <name>::
|
-o <name>::
|
||||||
Instead of using the branch name 'origin' to keep track
|
Instead of using the branch name 'origin' to keep track
|
||||||
of the upstream repository, use <name> instead. Note
|
of the upstream repository, use <name> instead. Note
|
||||||
|
@ -54,7 +54,7 @@ If '--cached' is specified, it allows you to ask:
|
|||||||
|
|
||||||
For example, let's say that you have worked on your working directory, updated
|
For example, let's say that you have worked on your working directory, updated
|
||||||
some files in the index and are ready to commit. You want to see exactly
|
some files in the index and are ready to commit. You want to see exactly
|
||||||
*what* you are going to commit is without having to write a new tree
|
*what* you are going to commit, without having to write a new tree
|
||||||
object and compare it that way, and to do that, you just do
|
object and compare it that way, and to do that, you just do
|
||||||
|
|
||||||
git-diff-index --cached HEAD
|
git-diff-index --cached HEAD
|
||||||
@ -68,7 +68,7 @@ matches my working directory. But doing a "git-diff-index" does:
|
|||||||
-100644 blob 4161aecc6700a2eb579e842af0b7f22b98443f74 commit.c
|
-100644 blob 4161aecc6700a2eb579e842af0b7f22b98443f74 commit.c
|
||||||
+100644 blob 4161aecc6700a2eb579e842af0b7f22b98443f74 git-commit.c
|
+100644 blob 4161aecc6700a2eb579e842af0b7f22b98443f74 git-commit.c
|
||||||
|
|
||||||
You can trivially see that the above is a rename.
|
You can see easily that the above is a rename.
|
||||||
|
|
||||||
In fact, "git-diff-index --cached" *should* always be entirely equivalent to
|
In fact, "git-diff-index --cached" *should* always be entirely equivalent to
|
||||||
actually doing a "git-write-tree" and comparing that. Except this one is much
|
actually doing a "git-write-tree" and comparing that. Except this one is much
|
||||||
|
@ -47,9 +47,8 @@ base-name::
|
|||||||
<base-name> to determine the name of the created file.
|
<base-name> to determine the name of the created file.
|
||||||
When this option is used, the two files are written in
|
When this option is used, the two files are written in
|
||||||
<base-name>-<SHA1>.{pack,idx} files. <SHA1> is a hash
|
<base-name>-<SHA1>.{pack,idx} files. <SHA1> is a hash
|
||||||
of object names (currently in random order so it does
|
of the sorted object names to make the resulting filename
|
||||||
not have any useful meaning) to make the resulting
|
based on the pack content, and written to the standard
|
||||||
filename reasonably unique, and written to the standard
|
|
||||||
output of the command.
|
output of the command.
|
||||||
|
|
||||||
--stdout::
|
--stdout::
|
||||||
|
@ -3,19 +3,19 @@ git-repo-config(1)
|
|||||||
|
|
||||||
NAME
|
NAME
|
||||||
----
|
----
|
||||||
git-repo-config - Get and set options in .git/config
|
git-repo-config - Get and set repository or global options.
|
||||||
|
|
||||||
|
|
||||||
SYNOPSIS
|
SYNOPSIS
|
||||||
--------
|
--------
|
||||||
[verse]
|
[verse]
|
||||||
'git-repo-config' [type] name [value [value_regex]]
|
'git-repo-config' [--global] [type] name [value [value_regex]]
|
||||||
'git-repo-config' [type] --replace-all name [value [value_regex]]
|
'git-repo-config' [--global] [type] --replace-all name [value [value_regex]]
|
||||||
'git-repo-config' [type] --get name [value_regex]
|
'git-repo-config' [--global] [type] --get name [value_regex]
|
||||||
'git-repo-config' [type] --get-all name [value_regex]
|
'git-repo-config' [--global] [type] --get-all name [value_regex]
|
||||||
'git-repo-config' [type] --unset name [value_regex]
|
'git-repo-config' [--global] [type] --unset name [value_regex]
|
||||||
'git-repo-config' [type] --unset-all name [value_regex]
|
'git-repo-config' [--global] [type] --unset-all name [value_regex]
|
||||||
'git-repo-config' -l | --list
|
'git-repo-config' [--global] -l | --list
|
||||||
|
|
||||||
DESCRIPTION
|
DESCRIPTION
|
||||||
-----------
|
-----------
|
||||||
@ -41,8 +41,9 @@ This command will fail if:
|
|||||||
. Can not write to .git/config,
|
. Can not write to .git/config,
|
||||||
. no section was provided,
|
. no section was provided,
|
||||||
. the section or key is invalid,
|
. the section or key is invalid,
|
||||||
. you try to unset an option which does not exist, or
|
. you try to unset an option which does not exist,
|
||||||
. you try to unset/set an option for which multiple lines match.
|
. you try to unset/set an option for which multiple lines match, or
|
||||||
|
. you use --global option without $HOME being properly set.
|
||||||
|
|
||||||
|
|
||||||
OPTIONS
|
OPTIONS
|
||||||
@ -64,14 +65,17 @@ OPTIONS
|
|||||||
--get-regexp::
|
--get-regexp::
|
||||||
Like --get-all, but interprets the name as a regular expression.
|
Like --get-all, but interprets the name as a regular expression.
|
||||||
|
|
||||||
|
--global::
|
||||||
|
Use global ~/.gitconfig file rather than the repository .git/config.
|
||||||
|
|
||||||
--unset::
|
--unset::
|
||||||
Remove the line matching the key from .git/config.
|
Remove the line matching the key from config file.
|
||||||
|
|
||||||
--unset-all::
|
--unset-all::
|
||||||
Remove all matching lines from .git/config.
|
Remove all matching lines from config file.
|
||||||
|
|
||||||
-l, --list::
|
-l, --list::
|
||||||
List all variables set in .git/config.
|
List all variables set in config file.
|
||||||
|
|
||||||
|
|
||||||
ENVIRONMENT
|
ENVIRONMENT
|
||||||
@ -79,6 +83,7 @@ ENVIRONMENT
|
|||||||
|
|
||||||
GIT_CONFIG::
|
GIT_CONFIG::
|
||||||
Take the configuration from the given file instead of .git/config.
|
Take the configuration from the given file instead of .git/config.
|
||||||
|
Using the "--global" option forces this to ~/.gitconfig.
|
||||||
|
|
||||||
GIT_CONFIG_LOCAL::
|
GIT_CONFIG_LOCAL::
|
||||||
Currently the same as $GIT_CONFIG; when Git will support global
|
Currently the same as $GIT_CONFIG; when Git will support global
|
||||||
|
156
Documentation/git-show-ref.txt
Normal file
156
Documentation/git-show-ref.txt
Normal file
@ -0,0 +1,156 @@
|
|||||||
|
git-show-ref(1)
|
||||||
|
===============
|
||||||
|
|
||||||
|
NAME
|
||||||
|
----
|
||||||
|
git-show-ref - List references in a local repository
|
||||||
|
|
||||||
|
SYNOPSIS
|
||||||
|
--------
|
||||||
|
[verse]
|
||||||
|
'git-show-ref' [-q|--quiet] [--verify] [-h|--head] [-d|--dereference]
|
||||||
|
[-s|--hash] [--abbrev] [--tags] [--heads] [--] <pattern>...
|
||||||
|
|
||||||
|
DESCRIPTION
|
||||||
|
-----------
|
||||||
|
|
||||||
|
Displays references available in a local repository along with the associated
|
||||||
|
commit IDs. Results can be filtered using a pattern and tags can be
|
||||||
|
dereferenced into object IDs. Additionally, it can be used to test whether a
|
||||||
|
particular ref exists.
|
||||||
|
|
||||||
|
Use of this utility is encouraged in favor of directly accessing files under
|
||||||
|
in the `.git` directory.
|
||||||
|
|
||||||
|
OPTIONS
|
||||||
|
-------
|
||||||
|
|
||||||
|
-h, --head::
|
||||||
|
|
||||||
|
Show the HEAD reference.
|
||||||
|
|
||||||
|
--tags, --heads::
|
||||||
|
|
||||||
|
Limit to only "refs/heads" and "refs/tags", respectively. These
|
||||||
|
options are not mutually exclusive; when given both, references stored
|
||||||
|
in "refs/heads" and "refs/tags" are displayed.
|
||||||
|
|
||||||
|
-d, --dereference::
|
||||||
|
|
||||||
|
Dereference tags into object IDs as well. They will be shown with "^{}"
|
||||||
|
appended.
|
||||||
|
|
||||||
|
-s, --hash::
|
||||||
|
|
||||||
|
Only show the SHA1 hash, not the reference name. When also using
|
||||||
|
--dereference the dereferenced tag will still be shown after the SHA1.
|
||||||
|
|
||||||
|
--verify::
|
||||||
|
|
||||||
|
Enable stricter reference checking by requiring an exact ref path.
|
||||||
|
Aside from returning an error code of 1, it will also print an error
|
||||||
|
message if '--quiet' was not specified.
|
||||||
|
|
||||||
|
--abbrev, --abbrev=len::
|
||||||
|
|
||||||
|
Abbreviate the object name. When using `--hash`, you do
|
||||||
|
not have to say `--hash --abbrev`; `--hash=len` would do.
|
||||||
|
|
||||||
|
-q, --quiet::
|
||||||
|
|
||||||
|
Do not print any results to stdout. When combined with '--verify' this
|
||||||
|
can be used to silently check if a reference exists.
|
||||||
|
|
||||||
|
<pattern>::
|
||||||
|
|
||||||
|
Show references matching one or more patterns.
|
||||||
|
|
||||||
|
OUTPUT
|
||||||
|
------
|
||||||
|
|
||||||
|
The output is in the format: '<SHA-1 ID>' '<space>' '<reference name>'.
|
||||||
|
|
||||||
|
-----------------------------------------------------------------------------
|
||||||
|
$ git show-ref --head --dereference
|
||||||
|
832e76a9899f560a90ffd62ae2ce83bbeff58f54 HEAD
|
||||||
|
832e76a9899f560a90ffd62ae2ce83bbeff58f54 refs/heads/master
|
||||||
|
832e76a9899f560a90ffd62ae2ce83bbeff58f54 refs/heads/origin
|
||||||
|
3521017556c5de4159da4615a39fa4d5d2c279b5 refs/tags/v0.99.9c
|
||||||
|
6ddc0964034342519a87fe013781abf31c6db6ad refs/tags/v0.99.9c^{}
|
||||||
|
055e4ae3ae6eb344cbabf2a5256a49ea66040131 refs/tags/v1.0rc4
|
||||||
|
423325a2d24638ddcc82ce47be5e40be550f4507 refs/tags/v1.0rc4^{}
|
||||||
|
...
|
||||||
|
-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
When using --hash (and not --dereference) the output format is: '<SHA-1 ID>'
|
||||||
|
|
||||||
|
-----------------------------------------------------------------------------
|
||||||
|
$ git show-ref --heads --hash
|
||||||
|
2e3ba0114a1f52b47df29743d6915d056be13278
|
||||||
|
185008ae97960c8d551adcd9e23565194651b5d1
|
||||||
|
03adf42c988195b50e1a1935ba5fcbc39b2b029b
|
||||||
|
...
|
||||||
|
-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
EXAMPLE
|
||||||
|
-------
|
||||||
|
|
||||||
|
To show all references called "master", whether tags or heads or anything
|
||||||
|
else, and regardless of how deep in the reference naming hierarchy they are,
|
||||||
|
use:
|
||||||
|
|
||||||
|
-----------------------------------------------------------------------------
|
||||||
|
git show-ref master
|
||||||
|
-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
This will show "refs/heads/master" but also "refs/remote/other-repo/master",
|
||||||
|
if such references exists.
|
||||||
|
|
||||||
|
When using the '--verify' flag, the command requires an exact path:
|
||||||
|
|
||||||
|
-----------------------------------------------------------------------------
|
||||||
|
git show-ref --verify refs/heads/master
|
||||||
|
-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
will only match the exact branch called "master".
|
||||||
|
|
||||||
|
If nothing matches, gitlink:git-show-ref[1] will return an error code of 1,
|
||||||
|
and in the case of verification, it will show an error message.
|
||||||
|
|
||||||
|
For scripting, you can ask it to be quiet with the "--quiet" flag, which
|
||||||
|
allows you to do things like
|
||||||
|
|
||||||
|
-----------------------------------------------------------------------------
|
||||||
|
git-show-ref --quiet --verify -- "refs/heads/$headname" ||
|
||||||
|
echo "$headname is not a valid branch"
|
||||||
|
-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
to check whether a particular branch exists or not (notice how we don't
|
||||||
|
actually want to show any results, and we want to use the full refname for it
|
||||||
|
in order to not trigger the problem with ambiguous partial matches).
|
||||||
|
|
||||||
|
To show only tags, or only proper branch heads, use "--tags" and/or "--heads"
|
||||||
|
respectively (using both means that it shows tags and heads, but not other
|
||||||
|
random references under the refs/ subdirectory).
|
||||||
|
|
||||||
|
To do automatic tag object dereferencing, use the "-d" or "--dereference"
|
||||||
|
flag, so you can do
|
||||||
|
|
||||||
|
-----------------------------------------------------------------------------
|
||||||
|
git show-ref --tags --dereference
|
||||||
|
-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
to get a listing of all tags together with what they dereference.
|
||||||
|
|
||||||
|
SEE ALSO
|
||||||
|
--------
|
||||||
|
gitlink:git-ls-remote[1], gitlink:git-peek-remote[1]
|
||||||
|
|
||||||
|
AUTHORS
|
||||||
|
-------
|
||||||
|
Written by Linus Torvalds <torvalds@osdl.org>.
|
||||||
|
Man page by Jonas Fonseca <fonseca@diku.dk>.
|
||||||
|
|
||||||
|
GIT
|
||||||
|
---
|
||||||
|
Part of the gitlink:git[7] suite
|
@ -7,7 +7,7 @@ git-update-ref - update the object name stored in a ref safely
|
|||||||
|
|
||||||
SYNOPSIS
|
SYNOPSIS
|
||||||
--------
|
--------
|
||||||
'git-update-ref' [-m <reason>] <ref> <newvalue> [<oldvalue>]
|
'git-update-ref' [-m <reason>] (-d <ref> <oldvalue> | <ref> <newvalue> [<oldvalue>])
|
||||||
|
|
||||||
DESCRIPTION
|
DESCRIPTION
|
||||||
-----------
|
-----------
|
||||||
@ -20,7 +20,9 @@ possibly dereferencing the symbolic refs, after verifying that
|
|||||||
the current value of the <ref> matches <oldvalue>.
|
the current value of the <ref> matches <oldvalue>.
|
||||||
E.g. `git-update-ref refs/heads/master <newvalue> <oldvalue>`
|
E.g. `git-update-ref refs/heads/master <newvalue> <oldvalue>`
|
||||||
updates the master branch head to <newvalue> only if its current
|
updates the master branch head to <newvalue> only if its current
|
||||||
value is <oldvalue>.
|
value is <oldvalue>. You can specify 40 "0" or an empty string
|
||||||
|
as <oldvalue> to make sure that the ref you are creating does
|
||||||
|
not exist.
|
||||||
|
|
||||||
It also allows a "ref" file to be a symbolic pointer to another
|
It also allows a "ref" file to be a symbolic pointer to another
|
||||||
ref file by starting with the four-byte header sequence of
|
ref file by starting with the four-byte header sequence of
|
||||||
@ -49,6 +51,10 @@ for reading but not for writing (so we'll never write through a
|
|||||||
ref symlink to some other tree, if you have copied a whole
|
ref symlink to some other tree, if you have copied a whole
|
||||||
archive by creating a symlink tree).
|
archive by creating a symlink tree).
|
||||||
|
|
||||||
|
With `-d` flag, it deletes the named <ref> after verifying it
|
||||||
|
still contains <oldvalue>.
|
||||||
|
|
||||||
|
|
||||||
Logging Updates
|
Logging Updates
|
||||||
---------------
|
---------------
|
||||||
If config parameter "core.logAllRefUpdates" is true or the file
|
If config parameter "core.logAllRefUpdates" is true or the file
|
||||||
|
11
Makefile
11
Makefile
@ -158,8 +158,8 @@ BASIC_CFLAGS =
|
|||||||
BASIC_LDFLAGS =
|
BASIC_LDFLAGS =
|
||||||
|
|
||||||
SCRIPT_SH = \
|
SCRIPT_SH = \
|
||||||
git-bisect.sh git-branch.sh git-checkout.sh \
|
git-bisect.sh git-checkout.sh \
|
||||||
git-cherry.sh git-clean.sh git-clone.sh git-commit.sh \
|
git-clean.sh git-clone.sh git-commit.sh \
|
||||||
git-fetch.sh \
|
git-fetch.sh \
|
||||||
git-ls-remote.sh \
|
git-ls-remote.sh \
|
||||||
git-merge-one-file.sh git-parse-remote.sh \
|
git-merge-one-file.sh git-parse-remote.sh \
|
||||||
@ -212,7 +212,7 @@ PROGRAMS = \
|
|||||||
EXTRA_PROGRAMS =
|
EXTRA_PROGRAMS =
|
||||||
|
|
||||||
BUILT_INS = \
|
BUILT_INS = \
|
||||||
git-format-patch$X git-show$X git-whatchanged$X \
|
git-format-patch$X git-show$X git-whatchanged$X git-cherry$X \
|
||||||
git-get-tar-commit-id$X \
|
git-get-tar-commit-id$X \
|
||||||
$(patsubst builtin-%.o,git-%$X,$(BUILTIN_OBJS))
|
$(patsubst builtin-%.o,git-%$X,$(BUILTIN_OBJS))
|
||||||
|
|
||||||
@ -270,6 +270,7 @@ BUILTIN_OBJS = \
|
|||||||
builtin-annotate.o \
|
builtin-annotate.o \
|
||||||
builtin-apply.o \
|
builtin-apply.o \
|
||||||
builtin-archive.o \
|
builtin-archive.o \
|
||||||
|
builtin-branch.o \
|
||||||
builtin-cat-file.o \
|
builtin-cat-file.o \
|
||||||
builtin-checkout-index.o \
|
builtin-checkout-index.o \
|
||||||
builtin-check-ref-format.o \
|
builtin-check-ref-format.o \
|
||||||
@ -310,7 +311,9 @@ BUILTIN_OBJS = \
|
|||||||
builtin-update-ref.o \
|
builtin-update-ref.o \
|
||||||
builtin-upload-archive.o \
|
builtin-upload-archive.o \
|
||||||
builtin-verify-pack.o \
|
builtin-verify-pack.o \
|
||||||
builtin-write-tree.o
|
builtin-write-tree.o \
|
||||||
|
builtin-show-ref.o \
|
||||||
|
builtin-pack-refs.o
|
||||||
|
|
||||||
GITLIBS = $(LIB_FILE) $(XDIFF_LIB)
|
GITLIBS = $(LIB_FILE) $(XDIFF_LIB)
|
||||||
EXTLIBS = -lz
|
EXTLIBS = -lz
|
||||||
|
5
blame.c
5
blame.c
@ -19,7 +19,9 @@
|
|||||||
#include "xdiff-interface.h"
|
#include "xdiff-interface.h"
|
||||||
#include "quote.h"
|
#include "quote.h"
|
||||||
|
|
||||||
|
#ifndef DEBUG
|
||||||
#define DEBUG 0
|
#define DEBUG 0
|
||||||
|
#endif
|
||||||
|
|
||||||
static const char blame_usage[] =
|
static const char blame_usage[] =
|
||||||
"git-blame [-c] [-l] [-t] [-f] [-n] [-p] [-S <revs-file>] [--] file [commit]\n"
|
"git-blame [-c] [-l] [-t] [-f] [-n] [-p] [-S <revs-file>] [--] file [commit]\n"
|
||||||
@ -232,6 +234,9 @@ static void print_map(struct commit *cmit, struct commit *other)
|
|||||||
util2->num_lines ? util->num_lines : util2->num_lines;
|
util2->num_lines ? util->num_lines : util2->num_lines;
|
||||||
int num;
|
int num;
|
||||||
|
|
||||||
|
if (print_map == NULL)
|
||||||
|
; /* to avoid "unused function" warning */
|
||||||
|
|
||||||
for (i = 0; i < max; i++) {
|
for (i = 0; i < max; i++) {
|
||||||
printf("i: %d ", i);
|
printf("i: %d ", i);
|
||||||
num = -1;
|
num = -1;
|
||||||
|
221
builtin-branch.c
Normal file
221
builtin-branch.c
Normal file
@ -0,0 +1,221 @@
|
|||||||
|
/*
|
||||||
|
* Builtin "git branch"
|
||||||
|
*
|
||||||
|
* Copyright (c) 2006 Kristian Høgsberg <krh@redhat.com>
|
||||||
|
* Based on git-branch.sh by Junio C Hamano.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "cache.h"
|
||||||
|
#include "refs.h"
|
||||||
|
#include "commit.h"
|
||||||
|
#include "builtin.h"
|
||||||
|
|
||||||
|
static const char builtin_branch_usage[] =
|
||||||
|
"git-branch (-d | -D) <branchname> | [-l] [-f] <branchname> [<start-point>] | [-r]";
|
||||||
|
|
||||||
|
|
||||||
|
static const char *head;
|
||||||
|
static unsigned char head_sha1[20];
|
||||||
|
|
||||||
|
static int in_merge_bases(const unsigned char *sha1,
|
||||||
|
struct commit *rev1,
|
||||||
|
struct commit *rev2)
|
||||||
|
{
|
||||||
|
struct commit_list *bases, *b;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
bases = get_merge_bases(rev1, rev2, 1);
|
||||||
|
for (b = bases; b; b = b->next) {
|
||||||
|
if (!hashcmp(sha1, b->item->object.sha1)) {
|
||||||
|
ret = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
free_commit_list(bases);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void delete_branches(int argc, const char **argv, int force)
|
||||||
|
{
|
||||||
|
struct commit *rev, *head_rev;
|
||||||
|
unsigned char sha1[20];
|
||||||
|
char *name;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
head_rev = lookup_commit_reference(head_sha1);
|
||||||
|
for (i = 0; i < argc; i++) {
|
||||||
|
if (!strcmp(head, argv[i]))
|
||||||
|
die("Cannot delete the branch you are currently on.");
|
||||||
|
|
||||||
|
name = xstrdup(mkpath("refs/heads/%s", argv[i]));
|
||||||
|
if (!resolve_ref(name, sha1, 1, NULL))
|
||||||
|
die("Branch '%s' not found.", argv[i]);
|
||||||
|
|
||||||
|
rev = lookup_commit_reference(sha1);
|
||||||
|
if (!rev || !head_rev)
|
||||||
|
die("Couldn't look up commit objects.");
|
||||||
|
|
||||||
|
/* This checks whether the merge bases of branch and
|
||||||
|
* HEAD contains branch -- which means that the HEAD
|
||||||
|
* contains everything in both.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (!force &&
|
||||||
|
!in_merge_bases(sha1, rev, head_rev)) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"The branch '%s' is not a strict subset of your current HEAD.\n"
|
||||||
|
"If you are sure you want to delete it, run 'git branch -D %s'.\n",
|
||||||
|
argv[i], argv[i]);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (delete_ref(name, sha1))
|
||||||
|
printf("Error deleting branch '%s'\n", argv[i]);
|
||||||
|
else
|
||||||
|
printf("Deleted branch %s.\n", argv[i]);
|
||||||
|
|
||||||
|
free(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ref_index, ref_alloc;
|
||||||
|
static char **ref_list;
|
||||||
|
|
||||||
|
static int append_ref(const char *refname, const unsigned char *sha1, int flags,
|
||||||
|
void *cb_data)
|
||||||
|
{
|
||||||
|
if (ref_index >= ref_alloc) {
|
||||||
|
ref_alloc = alloc_nr(ref_alloc);
|
||||||
|
ref_list = xrealloc(ref_list, ref_alloc * sizeof(char *));
|
||||||
|
}
|
||||||
|
|
||||||
|
ref_list[ref_index++] = xstrdup(refname);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ref_cmp(const void *r1, const void *r2)
|
||||||
|
{
|
||||||
|
return strcmp(*(char **)r1, *(char **)r2);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void print_ref_list(int remote_only)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
char c;
|
||||||
|
|
||||||
|
if (remote_only)
|
||||||
|
for_each_remote_ref(append_ref, NULL);
|
||||||
|
else
|
||||||
|
for_each_branch_ref(append_ref, NULL);
|
||||||
|
|
||||||
|
qsort(ref_list, ref_index, sizeof(char *), ref_cmp);
|
||||||
|
|
||||||
|
for (i = 0; i < ref_index; i++) {
|
||||||
|
c = ' ';
|
||||||
|
if (!strcmp(ref_list[i], head))
|
||||||
|
c = '*';
|
||||||
|
|
||||||
|
printf("%c %s\n", c, ref_list[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void create_branch(const char *name, const char *start,
|
||||||
|
int force, int reflog)
|
||||||
|
{
|
||||||
|
struct ref_lock *lock;
|
||||||
|
struct commit *commit;
|
||||||
|
unsigned char sha1[20];
|
||||||
|
char ref[PATH_MAX], msg[PATH_MAX + 20];
|
||||||
|
|
||||||
|
snprintf(ref, sizeof ref, "refs/heads/%s", name);
|
||||||
|
if (check_ref_format(ref))
|
||||||
|
die("'%s' is not a valid branch name.", name);
|
||||||
|
|
||||||
|
if (resolve_ref(ref, sha1, 1, NULL)) {
|
||||||
|
if (!force)
|
||||||
|
die("A branch named '%s' already exists.", name);
|
||||||
|
else if (!strcmp(head, name))
|
||||||
|
die("Cannot force update the current branch.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (get_sha1(start, sha1) ||
|
||||||
|
(commit = lookup_commit_reference(sha1)) == NULL)
|
||||||
|
die("Not a valid branch point: '%s'.", start);
|
||||||
|
hashcpy(sha1, commit->object.sha1);
|
||||||
|
|
||||||
|
lock = lock_any_ref_for_update(ref, NULL);
|
||||||
|
if (!lock)
|
||||||
|
die("Failed to lock ref for update: %s.", strerror(errno));
|
||||||
|
|
||||||
|
if (reflog) {
|
||||||
|
log_all_ref_updates = 1;
|
||||||
|
snprintf(msg, sizeof msg, "branch: Created from %s", start);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (write_ref_sha1(lock, sha1, msg) < 0)
|
||||||
|
die("Failed to write ref: %s.", strerror(errno));
|
||||||
|
}
|
||||||
|
|
||||||
|
int cmd_branch(int argc, const char **argv, const char *prefix)
|
||||||
|
{
|
||||||
|
int delete = 0, force_delete = 0, force_create = 0, remote_only = 0;
|
||||||
|
int reflog = 0;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
git_config(git_default_config);
|
||||||
|
|
||||||
|
for (i = 1; i < argc; i++) {
|
||||||
|
const char *arg = argv[i];
|
||||||
|
|
||||||
|
if (arg[0] != '-')
|
||||||
|
break;
|
||||||
|
if (!strcmp(arg, "--")) {
|
||||||
|
i++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!strcmp(arg, "-d")) {
|
||||||
|
delete = 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!strcmp(arg, "-D")) {
|
||||||
|
delete = 1;
|
||||||
|
force_delete = 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!strcmp(arg, "-f")) {
|
||||||
|
force_create = 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!strcmp(arg, "-r")) {
|
||||||
|
remote_only = 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!strcmp(arg, "-l")) {
|
||||||
|
reflog = 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
usage(builtin_branch_usage);
|
||||||
|
}
|
||||||
|
|
||||||
|
head = xstrdup(resolve_ref("HEAD", head_sha1, 0, NULL));
|
||||||
|
if (!head)
|
||||||
|
die("Failed to resolve HEAD as a valid ref.");
|
||||||
|
if (strncmp(head, "refs/heads/", 11))
|
||||||
|
die("HEAD not found below refs/heads!");
|
||||||
|
head += 11;
|
||||||
|
|
||||||
|
if (delete)
|
||||||
|
delete_branches(argc - i, argv + i, force_delete);
|
||||||
|
else if (i == argc)
|
||||||
|
print_ref_list(remote_only);
|
||||||
|
else if (i == argc - 1)
|
||||||
|
create_branch(argv[i], head, force_create, reflog);
|
||||||
|
else if (i == argc - 2)
|
||||||
|
create_branch(argv[i], argv[i + 1], force_create, reflog);
|
||||||
|
else
|
||||||
|
usage(builtin_branch_usage);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
@ -249,7 +249,7 @@ int cmd_fmt_merge_msg(int argc, const char **argv, const char *prefix)
|
|||||||
FILE *in = stdin;
|
FILE *in = stdin;
|
||||||
const char *sep = "";
|
const char *sep = "";
|
||||||
unsigned char head_sha1[20];
|
unsigned char head_sha1[20];
|
||||||
const char *head, *current_branch;
|
const char *current_branch;
|
||||||
|
|
||||||
git_config(fmt_merge_msg_config);
|
git_config(fmt_merge_msg_config);
|
||||||
|
|
||||||
@ -277,10 +277,7 @@ int cmd_fmt_merge_msg(int argc, const char **argv, const char *prefix)
|
|||||||
usage(fmt_merge_msg_usage);
|
usage(fmt_merge_msg_usage);
|
||||||
|
|
||||||
/* get current branch */
|
/* get current branch */
|
||||||
head = xstrdup(git_path("HEAD"));
|
current_branch = resolve_ref("HEAD", head_sha1, 1, NULL);
|
||||||
current_branch = resolve_ref(head, head_sha1, 1);
|
|
||||||
current_branch += strlen(head) - 4;
|
|
||||||
free((char *)head);
|
|
||||||
if (!strncmp(current_branch, "refs/heads/", 11))
|
if (!strncmp(current_branch, "refs/heads/", 11))
|
||||||
current_branch += 11;
|
current_branch += 11;
|
||||||
|
|
||||||
|
@ -59,6 +59,8 @@ static struct {
|
|||||||
{ "taggername" },
|
{ "taggername" },
|
||||||
{ "taggeremail" },
|
{ "taggeremail" },
|
||||||
{ "taggerdate", FIELD_TIME },
|
{ "taggerdate", FIELD_TIME },
|
||||||
|
{ "creator" },
|
||||||
|
{ "creatordate", FIELD_TIME },
|
||||||
{ "subject" },
|
{ "subject" },
|
||||||
{ "body" },
|
{ "body" },
|
||||||
{ "contents" },
|
{ "contents" },
|
||||||
@ -401,6 +403,29 @@ static void grab_person(const char *who, struct atom_value *val, int deref, stru
|
|||||||
else if (!strcmp(name + wholen, "date"))
|
else if (!strcmp(name + wholen, "date"))
|
||||||
grab_date(wholine, v);
|
grab_date(wholine, v);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* For a tag or a commit object, if "creator" or "creatordate" is
|
||||||
|
* requested, do something special.
|
||||||
|
*/
|
||||||
|
if (strcmp(who, "tagger") && strcmp(who, "committer"))
|
||||||
|
return; /* "author" for commit object is not wanted */
|
||||||
|
if (!wholine)
|
||||||
|
wholine = find_wholine(who, wholen, buf, sz);
|
||||||
|
if (!wholine)
|
||||||
|
return;
|
||||||
|
for (i = 0; i < used_atom_cnt; i++) {
|
||||||
|
const char *name = used_atom[i];
|
||||||
|
struct atom_value *v = &val[i];
|
||||||
|
if (!!deref != (*name == '*'))
|
||||||
|
continue;
|
||||||
|
if (deref)
|
||||||
|
name++;
|
||||||
|
|
||||||
|
if (!strcmp(name, "creatordate"))
|
||||||
|
grab_date(wholine, v);
|
||||||
|
else if (!strcmp(name, "creator"))
|
||||||
|
v->s = copy_line(wholine);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void find_subpos(const char *buf, unsigned long sz, const char **sub, const char **body)
|
static void find_subpos(const char *buf, unsigned long sz, const char **sub, const char **body)
|
||||||
@ -585,24 +610,27 @@ static void get_value(struct refinfo *ref, int atom, struct atom_value **v)
|
|||||||
*v = &ref->value[atom];
|
*v = &ref->value[atom];
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct refinfo **grab_array;
|
struct grab_ref_cbdata {
|
||||||
static const char **grab_pattern;
|
struct refinfo **grab_array;
|
||||||
static int *grab_cnt;
|
const char **grab_pattern;
|
||||||
|
int grab_cnt;
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* A call-back given to for_each_ref(). It is unfortunate that we
|
* A call-back given to for_each_ref(). It is unfortunate that we
|
||||||
* need to use global variables to pass extra information to this
|
* need to use global variables to pass extra information to this
|
||||||
* function.
|
* function.
|
||||||
*/
|
*/
|
||||||
static int grab_single_ref(const char *refname, const unsigned char *sha1)
|
static int grab_single_ref(const char *refname, const unsigned char *sha1, int flag, void *cb_data)
|
||||||
{
|
{
|
||||||
|
struct grab_ref_cbdata *cb = cb_data;
|
||||||
struct refinfo *ref;
|
struct refinfo *ref;
|
||||||
int cnt;
|
int cnt;
|
||||||
|
|
||||||
if (*grab_pattern) {
|
if (*cb->grab_pattern) {
|
||||||
const char **pattern;
|
const char **pattern;
|
||||||
int namelen = strlen(refname);
|
int namelen = strlen(refname);
|
||||||
for (pattern = grab_pattern; *pattern; pattern++) {
|
for (pattern = cb->grab_pattern; *pattern; pattern++) {
|
||||||
const char *p = *pattern;
|
const char *p = *pattern;
|
||||||
int plen = strlen(p);
|
int plen = strlen(p);
|
||||||
|
|
||||||
@ -626,25 +654,14 @@ static int grab_single_ref(const char *refname, const unsigned char *sha1)
|
|||||||
ref->refname = xstrdup(refname);
|
ref->refname = xstrdup(refname);
|
||||||
hashcpy(ref->objectname, sha1);
|
hashcpy(ref->objectname, sha1);
|
||||||
|
|
||||||
cnt = *grab_cnt;
|
cnt = cb->grab_cnt;
|
||||||
grab_array = xrealloc(grab_array, sizeof(*grab_array) * (cnt + 1));
|
cb->grab_array = xrealloc(cb->grab_array,
|
||||||
grab_array[cnt++] = ref;
|
sizeof(*cb->grab_array) * (cnt + 1));
|
||||||
*grab_cnt = cnt;
|
cb->grab_array[cnt++] = ref;
|
||||||
|
cb->grab_cnt = cnt;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct refinfo **grab_refs(const char **pattern, int *cnt)
|
|
||||||
{
|
|
||||||
/* Sheesh, we really should make for-each-ref to take
|
|
||||||
* callback data.
|
|
||||||
*/
|
|
||||||
*cnt = 0;
|
|
||||||
grab_pattern = pattern;
|
|
||||||
grab_cnt = cnt;
|
|
||||||
for_each_ref(grab_single_ref);
|
|
||||||
return grab_array;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int cmp_ref_sort(struct ref_sort *s, struct refinfo *a, struct refinfo *b)
|
static int cmp_ref_sort(struct ref_sort *s, struct refinfo *a, struct refinfo *b)
|
||||||
{
|
{
|
||||||
struct atom_value *va, *vb;
|
struct atom_value *va, *vb;
|
||||||
@ -784,6 +801,7 @@ int cmd_for_each_ref(int ac, const char **av, char *prefix)
|
|||||||
int maxcount = 0;
|
int maxcount = 0;
|
||||||
int quote_style = -1; /* unspecified yet */
|
int quote_style = -1; /* unspecified yet */
|
||||||
struct refinfo **refs;
|
struct refinfo **refs;
|
||||||
|
struct grab_ref_cbdata cbdata;
|
||||||
|
|
||||||
for (i = 1; i < ac; i++) {
|
for (i = 1; i < ac; i++) {
|
||||||
const char *arg = av[i];
|
const char *arg = av[i];
|
||||||
@ -855,7 +873,11 @@ int cmd_for_each_ref(int ac, const char **av, char *prefix)
|
|||||||
|
|
||||||
verify_format(format);
|
verify_format(format);
|
||||||
|
|
||||||
refs = grab_refs(av + i, &num_refs);
|
memset(&cbdata, 0, sizeof(cbdata));
|
||||||
|
cbdata.grab_pattern = av + i;
|
||||||
|
for_each_ref(grab_single_ref, &cbdata);
|
||||||
|
refs = cbdata.grab_array;
|
||||||
|
num_refs = cbdata.grab_cnt;
|
||||||
|
|
||||||
for (i = 0; i < used_atom_cnt; i++) {
|
for (i = 0; i < used_atom_cnt; i++) {
|
||||||
if (used_atom[i][0] == '*') {
|
if (used_atom[i][0] == '*') {
|
||||||
|
@ -218,8 +218,8 @@ static void create_default_files(const char *git_dir, const char *template_path)
|
|||||||
* branch, if it does not exist yet.
|
* branch, if it does not exist yet.
|
||||||
*/
|
*/
|
||||||
strcpy(path + len, "HEAD");
|
strcpy(path + len, "HEAD");
|
||||||
if (read_ref(path, sha1) < 0) {
|
if (read_ref("HEAD", sha1) < 0) {
|
||||||
if (create_symref(path, "refs/heads/master") < 0)
|
if (create_symref("HEAD", "refs/heads/master") < 0)
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
113
builtin-log.c
113
builtin-log.c
@ -171,8 +171,11 @@ static void reopen_stdout(struct commit *commit, int nr, int keep_subject)
|
|||||||
static int get_patch_id(struct commit *commit, struct diff_options *options,
|
static int get_patch_id(struct commit *commit, struct diff_options *options,
|
||||||
unsigned char *sha1)
|
unsigned char *sha1)
|
||||||
{
|
{
|
||||||
diff_tree_sha1(commit->parents->item->object.sha1, commit->object.sha1,
|
if (commit->parents)
|
||||||
"", options);
|
diff_tree_sha1(commit->parents->item->object.sha1,
|
||||||
|
commit->object.sha1, "", options);
|
||||||
|
else
|
||||||
|
diff_root_tree_sha1(commit->object.sha1, "", options);
|
||||||
diffcore_std(options);
|
diffcore_std(options);
|
||||||
return diff_flush_patch_id(options, sha1);
|
return diff_flush_patch_id(options, sha1);
|
||||||
}
|
}
|
||||||
@ -437,3 +440,109 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int add_pending_commit(const char *arg, struct rev_info *revs, int flags)
|
||||||
|
{
|
||||||
|
unsigned char sha1[20];
|
||||||
|
if (get_sha1(arg, sha1) == 0) {
|
||||||
|
struct commit *commit = lookup_commit_reference(sha1);
|
||||||
|
if (commit) {
|
||||||
|
commit->object.flags |= flags;
|
||||||
|
add_pending_object(revs, &commit->object, arg);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char cherry_usage[] =
|
||||||
|
"git-cherry [-v] <upstream> [<head>] [<limit>]";
|
||||||
|
int cmd_cherry(int argc, const char **argv, const char *prefix)
|
||||||
|
{
|
||||||
|
struct rev_info revs;
|
||||||
|
struct diff_options patch_id_opts;
|
||||||
|
struct commit *commit;
|
||||||
|
struct commit_list *list = NULL;
|
||||||
|
const char *upstream;
|
||||||
|
const char *head = "HEAD";
|
||||||
|
const char *limit = NULL;
|
||||||
|
int verbose = 0;
|
||||||
|
|
||||||
|
if (argc > 1 && !strcmp(argv[1], "-v")) {
|
||||||
|
verbose = 1;
|
||||||
|
argc--;
|
||||||
|
argv++;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (argc) {
|
||||||
|
case 4:
|
||||||
|
limit = argv[3];
|
||||||
|
/* FALLTHROUGH */
|
||||||
|
case 3:
|
||||||
|
head = argv[2];
|
||||||
|
/* FALLTHROUGH */
|
||||||
|
case 2:
|
||||||
|
upstream = argv[1];
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
usage(cherry_usage);
|
||||||
|
}
|
||||||
|
|
||||||
|
init_revisions(&revs, prefix);
|
||||||
|
revs.diff = 1;
|
||||||
|
revs.combine_merges = 0;
|
||||||
|
revs.ignore_merges = 1;
|
||||||
|
revs.diffopt.recursive = 1;
|
||||||
|
|
||||||
|
if (add_pending_commit(head, &revs, 0))
|
||||||
|
die("Unknown commit %s", head);
|
||||||
|
if (add_pending_commit(upstream, &revs, UNINTERESTING))
|
||||||
|
die("Unknown commit %s", upstream);
|
||||||
|
|
||||||
|
/* Don't say anything if head and upstream are the same. */
|
||||||
|
if (revs.pending.nr == 2) {
|
||||||
|
struct object_array_entry *o = revs.pending.objects;
|
||||||
|
if (hashcmp(o[0].item->sha1, o[1].item->sha1) == 0)
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
get_patch_ids(&revs, &patch_id_opts, prefix);
|
||||||
|
|
||||||
|
if (limit && add_pending_commit(limit, &revs, UNINTERESTING))
|
||||||
|
die("Unknown commit %s", limit);
|
||||||
|
|
||||||
|
/* reverse the list of commits */
|
||||||
|
prepare_revision_walk(&revs);
|
||||||
|
while ((commit = get_revision(&revs)) != NULL) {
|
||||||
|
/* ignore merges */
|
||||||
|
if (commit->parents && commit->parents->next)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
commit_list_insert(commit, &list);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (list) {
|
||||||
|
unsigned char sha1[20];
|
||||||
|
char sign = '+';
|
||||||
|
|
||||||
|
commit = list->item;
|
||||||
|
if (!get_patch_id(commit, &patch_id_opts, sha1) &&
|
||||||
|
lookup_object(sha1))
|
||||||
|
sign = '-';
|
||||||
|
|
||||||
|
if (verbose) {
|
||||||
|
static char buf[16384];
|
||||||
|
pretty_print_commit(CMIT_FMT_ONELINE, commit, ~0,
|
||||||
|
buf, sizeof(buf), 0, NULL, NULL, 0);
|
||||||
|
printf("%c %s %s\n", sign,
|
||||||
|
sha1_to_hex(commit->object.sha1), buf);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
printf("%c %s\n", sign,
|
||||||
|
sha1_to_hex(commit->object.sha1));
|
||||||
|
}
|
||||||
|
|
||||||
|
list = list->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
@ -75,11 +75,10 @@ copy_data:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int tags_only;
|
static int name_ref(const char *path, const unsigned char *sha1, int flags, void *cb_data)
|
||||||
|
|
||||||
static int name_ref(const char *path, const unsigned char *sha1)
|
|
||||||
{
|
{
|
||||||
struct object *o = parse_object(sha1);
|
struct object *o = parse_object(sha1);
|
||||||
|
int tags_only = *(int*)cb_data;
|
||||||
int deref = 0;
|
int deref = 0;
|
||||||
|
|
||||||
if (tags_only && strncmp(path, "refs/tags/", 10))
|
if (tags_only && strncmp(path, "refs/tags/", 10))
|
||||||
@ -131,6 +130,7 @@ int cmd_name_rev(int argc, const char **argv, const char *prefix)
|
|||||||
{
|
{
|
||||||
struct object_array revs = { 0, 0, NULL };
|
struct object_array revs = { 0, 0, NULL };
|
||||||
int as_is = 0, all = 0, transform_stdin = 0;
|
int as_is = 0, all = 0, transform_stdin = 0;
|
||||||
|
int tags_only = 0;
|
||||||
|
|
||||||
git_config(git_default_config);
|
git_config(git_default_config);
|
||||||
|
|
||||||
@ -186,7 +186,7 @@ int cmd_name_rev(int argc, const char **argv, const char *prefix)
|
|||||||
add_object_array((struct object *)commit, *argv, &revs);
|
add_object_array((struct object *)commit, *argv, &revs);
|
||||||
}
|
}
|
||||||
|
|
||||||
for_each_ref(name_ref);
|
for_each_ref(name_ref, &tags_only);
|
||||||
|
|
||||||
if (transform_stdin) {
|
if (transform_stdin) {
|
||||||
char buffer[2048];
|
char buffer[2048];
|
||||||
|
107
builtin-pack-refs.c
Normal file
107
builtin-pack-refs.c
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
#include "cache.h"
|
||||||
|
#include "refs.h"
|
||||||
|
|
||||||
|
static const char builtin_pack_refs_usage[] =
|
||||||
|
"git-pack-refs [--all] [--prune]";
|
||||||
|
|
||||||
|
struct ref_to_prune {
|
||||||
|
struct ref_to_prune *next;
|
||||||
|
unsigned char sha1[20];
|
||||||
|
char name[FLEX_ARRAY];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct pack_refs_cb_data {
|
||||||
|
int prune;
|
||||||
|
int all;
|
||||||
|
struct ref_to_prune *ref_to_prune;
|
||||||
|
FILE *refs_file;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int do_not_prune(int flags)
|
||||||
|
{
|
||||||
|
/* If it is already packed or if it is a symref,
|
||||||
|
* do not prune it.
|
||||||
|
*/
|
||||||
|
return (flags & (REF_ISSYMREF|REF_ISPACKED));
|
||||||
|
}
|
||||||
|
|
||||||
|
static int handle_one_ref(const char *path, const unsigned char *sha1,
|
||||||
|
int flags, void *cb_data)
|
||||||
|
{
|
||||||
|
struct pack_refs_cb_data *cb = cb_data;
|
||||||
|
|
||||||
|
if (!cb->all && strncmp(path, "refs/tags/", 10))
|
||||||
|
return 0;
|
||||||
|
/* Do not pack the symbolic refs */
|
||||||
|
if (!(flags & REF_ISSYMREF))
|
||||||
|
fprintf(cb->refs_file, "%s %s\n", sha1_to_hex(sha1), path);
|
||||||
|
if (cb->prune && !do_not_prune(flags)) {
|
||||||
|
int namelen = strlen(path) + 1;
|
||||||
|
struct ref_to_prune *n = xcalloc(1, sizeof(*n) + namelen);
|
||||||
|
hashcpy(n->sha1, sha1);
|
||||||
|
strcpy(n->name, path);
|
||||||
|
n->next = cb->ref_to_prune;
|
||||||
|
cb->ref_to_prune = n;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* make sure nobody touched the ref, and unlink */
|
||||||
|
static void prune_ref(struct ref_to_prune *r)
|
||||||
|
{
|
||||||
|
struct ref_lock *lock = lock_ref_sha1(r->name + 5, r->sha1);
|
||||||
|
|
||||||
|
if (lock) {
|
||||||
|
unlink(git_path("%s", r->name));
|
||||||
|
unlock_ref(lock);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void prune_refs(struct ref_to_prune *r)
|
||||||
|
{
|
||||||
|
while (r) {
|
||||||
|
prune_ref(r);
|
||||||
|
r = r->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct lock_file packed;
|
||||||
|
|
||||||
|
int cmd_pack_refs(int argc, const char **argv, const char *prefix)
|
||||||
|
{
|
||||||
|
int fd, i;
|
||||||
|
struct pack_refs_cb_data cbdata;
|
||||||
|
|
||||||
|
memset(&cbdata, 0, sizeof(cbdata));
|
||||||
|
|
||||||
|
for (i = 1; i < argc; i++) {
|
||||||
|
const char *arg = argv[i];
|
||||||
|
if (!strcmp(arg, "--prune")) {
|
||||||
|
cbdata.prune = 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!strcmp(arg, "--all")) {
|
||||||
|
cbdata.all = 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
/* perhaps other parameters later... */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (i != argc)
|
||||||
|
usage(builtin_pack_refs_usage);
|
||||||
|
|
||||||
|
fd = hold_lock_file_for_update(&packed, git_path("packed-refs"), 1);
|
||||||
|
cbdata.refs_file = fdopen(fd, "w");
|
||||||
|
if (!cbdata.refs_file)
|
||||||
|
die("unable to create ref-pack file structure (%s)",
|
||||||
|
strerror(errno));
|
||||||
|
for_each_ref(handle_one_ref, &cbdata);
|
||||||
|
fflush(cbdata.refs_file);
|
||||||
|
fsync(fd);
|
||||||
|
fclose(cbdata.refs_file);
|
||||||
|
if (commit_lock_file(&packed) < 0)
|
||||||
|
die("unable to overwrite old ref-pack file (%s)", strerror(errno));
|
||||||
|
if (cbdata.prune)
|
||||||
|
prune_refs(cbdata.ref_to_prune);
|
||||||
|
return 0;
|
||||||
|
}
|
@ -174,7 +174,7 @@ static void walk_commit_list(struct rev_info *revs)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int add_one_ref(const char *path, const unsigned char *sha1)
|
static int add_one_ref(const char *path, const unsigned char *sha1, int flag, void *cb_data)
|
||||||
{
|
{
|
||||||
struct object *object = parse_object(sha1);
|
struct object *object = parse_object(sha1);
|
||||||
if (!object)
|
if (!object)
|
||||||
@ -240,7 +240,7 @@ int cmd_prune(int argc, const char **argv, const char *prefix)
|
|||||||
revs.tree_objects = 1;
|
revs.tree_objects = 1;
|
||||||
|
|
||||||
/* Add all external refs */
|
/* Add all external refs */
|
||||||
for_each_ref(add_one_ref);
|
for_each_ref(add_one_ref, NULL);
|
||||||
|
|
||||||
/* Add all refs from the index file */
|
/* Add all refs from the index file */
|
||||||
add_cache_refs();
|
add_cache_refs();
|
||||||
|
@ -27,7 +27,7 @@ static void add_refspec(const char *ref)
|
|||||||
refspec_nr = nr;
|
refspec_nr = nr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int expand_one_ref(const char *ref, const unsigned char *sha1)
|
static int expand_one_ref(const char *ref, const unsigned char *sha1, int flag, void *cb_data)
|
||||||
{
|
{
|
||||||
/* Ignore the "refs/" at the beginning of the refname */
|
/* Ignore the "refs/" at the beginning of the refname */
|
||||||
ref += 5;
|
ref += 5;
|
||||||
@ -51,7 +51,7 @@ static void expand_refspecs(void)
|
|||||||
}
|
}
|
||||||
if (!tags)
|
if (!tags)
|
||||||
return;
|
return;
|
||||||
for_each_ref(expand_one_ref);
|
for_each_ref(expand_one_ref, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void set_refspecs(const char **refs, int nr)
|
static void set_refspecs(const char **refs, int nr)
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
#include <regex.h>
|
#include <regex.h>
|
||||||
|
|
||||||
static const char git_config_set_usage[] =
|
static const char git_config_set_usage[] =
|
||||||
"git-repo-config [ --bool | --int ] [--get | --get-all | --get-regexp | --replace-all | --unset | --unset-all] name [value [value_regex]] | --list";
|
"git-repo-config [ --global ] [ --bool | --int ] [--get | --get-all | --get-regexp | --replace-all | --unset | --unset-all] name [value [value_regex]] | --list";
|
||||||
|
|
||||||
static char *key;
|
static char *key;
|
||||||
static regex_t *key_regexp;
|
static regex_t *key_regexp;
|
||||||
@ -139,7 +139,16 @@ int cmd_repo_config(int argc, const char **argv, const char *prefix)
|
|||||||
type = T_BOOL;
|
type = T_BOOL;
|
||||||
else if (!strcmp(argv[1], "--list") || !strcmp(argv[1], "-l"))
|
else if (!strcmp(argv[1], "--list") || !strcmp(argv[1], "-l"))
|
||||||
return git_config(show_all_config);
|
return git_config(show_all_config);
|
||||||
else
|
else if (!strcmp(argv[1], "--global")) {
|
||||||
|
char *home = getenv("HOME");
|
||||||
|
if (home) {
|
||||||
|
char *user_config = xstrdup(mkpath("%s/.gitconfig", home));
|
||||||
|
setenv("GIT_CONFIG", user_config, 1);
|
||||||
|
free(user_config);
|
||||||
|
} else {
|
||||||
|
die("$HOME not set");
|
||||||
|
}
|
||||||
|
} else
|
||||||
break;
|
break;
|
||||||
argc--;
|
argc--;
|
||||||
argv++;
|
argv++;
|
||||||
|
@ -137,7 +137,7 @@ static void show_default(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int show_reference(const char *refname, const unsigned char *sha1)
|
static int show_reference(const char *refname, const unsigned char *sha1, int flag, void *cb_data)
|
||||||
{
|
{
|
||||||
show_rev(NORMAL, sha1, refname);
|
show_rev(NORMAL, sha1, refname);
|
||||||
return 0;
|
return 0;
|
||||||
@ -299,19 +299,19 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (!strcmp(arg, "--all")) {
|
if (!strcmp(arg, "--all")) {
|
||||||
for_each_ref(show_reference);
|
for_each_ref(show_reference, NULL);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (!strcmp(arg, "--branches")) {
|
if (!strcmp(arg, "--branches")) {
|
||||||
for_each_branch_ref(show_reference);
|
for_each_branch_ref(show_reference, NULL);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (!strcmp(arg, "--tags")) {
|
if (!strcmp(arg, "--tags")) {
|
||||||
for_each_tag_ref(show_reference);
|
for_each_tag_ref(show_reference, NULL);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (!strcmp(arg, "--remotes")) {
|
if (!strcmp(arg, "--remotes")) {
|
||||||
for_each_remote_ref(show_reference);
|
for_each_remote_ref(show_reference, NULL);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (!strcmp(arg, "--show-prefix")) {
|
if (!strcmp(arg, "--show-prefix")) {
|
||||||
|
@ -346,7 +346,7 @@ static void sort_ref_range(int bottom, int top)
|
|||||||
compare_ref_name);
|
compare_ref_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int append_ref(const char *refname, const unsigned char *sha1)
|
static int append_ref(const char *refname, const unsigned char *sha1, int flag, void *cb_data)
|
||||||
{
|
{
|
||||||
struct commit *commit = lookup_commit_reference_gently(sha1, 1);
|
struct commit *commit = lookup_commit_reference_gently(sha1, 1);
|
||||||
int i;
|
int i;
|
||||||
@ -369,7 +369,7 @@ static int append_ref(const char *refname, const unsigned char *sha1)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int append_head_ref(const char *refname, const unsigned char *sha1)
|
static int append_head_ref(const char *refname, const unsigned char *sha1, int flag, void *cb_data)
|
||||||
{
|
{
|
||||||
unsigned char tmp[20];
|
unsigned char tmp[20];
|
||||||
int ofs = 11;
|
int ofs = 11;
|
||||||
@ -380,14 +380,14 @@ static int append_head_ref(const char *refname, const unsigned char *sha1)
|
|||||||
*/
|
*/
|
||||||
if (get_sha1(refname + ofs, tmp) || hashcmp(tmp, sha1))
|
if (get_sha1(refname + ofs, tmp) || hashcmp(tmp, sha1))
|
||||||
ofs = 5;
|
ofs = 5;
|
||||||
return append_ref(refname + ofs, sha1);
|
return append_ref(refname + ofs, sha1, flag, cb_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int append_tag_ref(const char *refname, const unsigned char *sha1)
|
static int append_tag_ref(const char *refname, const unsigned char *sha1, int flag, void *cb_data)
|
||||||
{
|
{
|
||||||
if (strncmp(refname, "refs/tags/", 10))
|
if (strncmp(refname, "refs/tags/", 10))
|
||||||
return 0;
|
return 0;
|
||||||
return append_ref(refname + 5, sha1);
|
return append_ref(refname + 5, sha1, flag, cb_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *match_ref_pattern = NULL;
|
static const char *match_ref_pattern = NULL;
|
||||||
@ -401,7 +401,7 @@ static int count_slash(const char *s)
|
|||||||
return cnt;
|
return cnt;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int append_matching_ref(const char *refname, const unsigned char *sha1)
|
static int append_matching_ref(const char *refname, const unsigned char *sha1, int flag, void *cb_data)
|
||||||
{
|
{
|
||||||
/* we want to allow pattern hold/<asterisk> to show all
|
/* we want to allow pattern hold/<asterisk> to show all
|
||||||
* branches under refs/heads/hold/, and v0.99.9? to show
|
* branches under refs/heads/hold/, and v0.99.9? to show
|
||||||
@ -417,41 +417,39 @@ static int append_matching_ref(const char *refname, const unsigned char *sha1)
|
|||||||
if (fnmatch(match_ref_pattern, tail, 0))
|
if (fnmatch(match_ref_pattern, tail, 0))
|
||||||
return 0;
|
return 0;
|
||||||
if (!strncmp("refs/heads/", refname, 11))
|
if (!strncmp("refs/heads/", refname, 11))
|
||||||
return append_head_ref(refname, sha1);
|
return append_head_ref(refname, sha1, flag, cb_data);
|
||||||
if (!strncmp("refs/tags/", refname, 10))
|
if (!strncmp("refs/tags/", refname, 10))
|
||||||
return append_tag_ref(refname, sha1);
|
return append_tag_ref(refname, sha1, flag, cb_data);
|
||||||
return append_ref(refname, sha1);
|
return append_ref(refname, sha1, flag, cb_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void snarf_refs(int head, int tag)
|
static void snarf_refs(int head, int tag)
|
||||||
{
|
{
|
||||||
if (head) {
|
if (head) {
|
||||||
int orig_cnt = ref_name_cnt;
|
int orig_cnt = ref_name_cnt;
|
||||||
for_each_ref(append_head_ref);
|
for_each_ref(append_head_ref, NULL);
|
||||||
sort_ref_range(orig_cnt, ref_name_cnt);
|
sort_ref_range(orig_cnt, ref_name_cnt);
|
||||||
}
|
}
|
||||||
if (tag) {
|
if (tag) {
|
||||||
int orig_cnt = ref_name_cnt;
|
int orig_cnt = ref_name_cnt;
|
||||||
for_each_ref(append_tag_ref);
|
for_each_ref(append_tag_ref, NULL);
|
||||||
sort_ref_range(orig_cnt, ref_name_cnt);
|
sort_ref_range(orig_cnt, ref_name_cnt);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int rev_is_head(char *head_path, int headlen, char *name,
|
static int rev_is_head(char *head, int headlen, char *name,
|
||||||
unsigned char *head_sha1, unsigned char *sha1)
|
unsigned char *head_sha1, unsigned char *sha1)
|
||||||
{
|
{
|
||||||
int namelen;
|
if ((!head[0]) ||
|
||||||
if ((!head_path[0]) ||
|
|
||||||
(head_sha1 && sha1 && hashcmp(head_sha1, sha1)))
|
(head_sha1 && sha1 && hashcmp(head_sha1, sha1)))
|
||||||
return 0;
|
return 0;
|
||||||
namelen = strlen(name);
|
if (!strncmp(head, "refs/heads/", 11))
|
||||||
if ((headlen < namelen) ||
|
head += 11;
|
||||||
memcmp(head_path + headlen - namelen, name, namelen))
|
if (!strncmp(name, "refs/heads/", 11))
|
||||||
return 0;
|
name += 11;
|
||||||
if (headlen == namelen ||
|
else if (!strncmp(name, "heads/", 6))
|
||||||
head_path[headlen - namelen - 1] == '/')
|
name += 6;
|
||||||
return 1;
|
return !strcmp(head, name);
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int show_merge_base(struct commit_list *seen, int num_rev)
|
static int show_merge_base(struct commit_list *seen, int num_rev)
|
||||||
@ -495,7 +493,7 @@ static void append_one_rev(const char *av)
|
|||||||
{
|
{
|
||||||
unsigned char revkey[20];
|
unsigned char revkey[20];
|
||||||
if (!get_sha1(av, revkey)) {
|
if (!get_sha1(av, revkey)) {
|
||||||
append_ref(av, revkey);
|
append_ref(av, revkey, 0, NULL);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (strchr(av, '*') || strchr(av, '?') || strchr(av, '[')) {
|
if (strchr(av, '*') || strchr(av, '?') || strchr(av, '[')) {
|
||||||
@ -503,7 +501,7 @@ static void append_one_rev(const char *av)
|
|||||||
int saved_matches = ref_name_cnt;
|
int saved_matches = ref_name_cnt;
|
||||||
match_ref_pattern = av;
|
match_ref_pattern = av;
|
||||||
match_ref_slash = count_slash(av);
|
match_ref_slash = count_slash(av);
|
||||||
for_each_ref(append_matching_ref);
|
for_each_ref(append_matching_ref, NULL);
|
||||||
if (saved_matches == ref_name_cnt &&
|
if (saved_matches == ref_name_cnt &&
|
||||||
ref_name_cnt < MAX_REVS)
|
ref_name_cnt < MAX_REVS)
|
||||||
error("no matching refs with %s", av);
|
error("no matching refs with %s", av);
|
||||||
@ -559,9 +557,9 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
|
|||||||
int all_heads = 0, all_tags = 0;
|
int all_heads = 0, all_tags = 0;
|
||||||
int all_mask, all_revs;
|
int all_mask, all_revs;
|
||||||
int lifo = 1;
|
int lifo = 1;
|
||||||
char head_path[128];
|
char head[128];
|
||||||
const char *head_path_p;
|
const char *head_p;
|
||||||
int head_path_len;
|
int head_len;
|
||||||
unsigned char head_sha1[20];
|
unsigned char head_sha1[20];
|
||||||
int merge_base = 0;
|
int merge_base = 0;
|
||||||
int independent = 0;
|
int independent = 0;
|
||||||
@ -638,31 +636,31 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
|
|||||||
ac--; av++;
|
ac--; av++;
|
||||||
}
|
}
|
||||||
|
|
||||||
head_path_p = resolve_ref(git_path("HEAD"), head_sha1, 1);
|
head_p = resolve_ref("HEAD", head_sha1, 1, NULL);
|
||||||
if (head_path_p) {
|
if (head_p) {
|
||||||
head_path_len = strlen(head_path_p);
|
head_len = strlen(head_p);
|
||||||
memcpy(head_path, head_path_p, head_path_len + 1);
|
memcpy(head, head_p, head_len + 1);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
head_path_len = 0;
|
head_len = 0;
|
||||||
head_path[0] = 0;
|
head[0] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (with_current_branch && head_path_p) {
|
if (with_current_branch && head_p) {
|
||||||
int has_head = 0;
|
int has_head = 0;
|
||||||
for (i = 0; !has_head && i < ref_name_cnt; i++) {
|
for (i = 0; !has_head && i < ref_name_cnt; i++) {
|
||||||
/* We are only interested in adding the branch
|
/* We are only interested in adding the branch
|
||||||
* HEAD points at.
|
* HEAD points at.
|
||||||
*/
|
*/
|
||||||
if (rev_is_head(head_path,
|
if (rev_is_head(head,
|
||||||
head_path_len,
|
head_len,
|
||||||
ref_name[i],
|
ref_name[i],
|
||||||
head_sha1, NULL))
|
head_sha1, NULL))
|
||||||
has_head++;
|
has_head++;
|
||||||
}
|
}
|
||||||
if (!has_head) {
|
if (!has_head) {
|
||||||
int pfxlen = strlen(git_path("refs/heads/"));
|
int pfxlen = strlen("refs/heads/");
|
||||||
append_one_rev(head_path + pfxlen);
|
append_one_rev(head + pfxlen);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -713,8 +711,8 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
|
|||||||
if (1 < num_rev || extra < 0) {
|
if (1 < num_rev || extra < 0) {
|
||||||
for (i = 0; i < num_rev; i++) {
|
for (i = 0; i < num_rev; i++) {
|
||||||
int j;
|
int j;
|
||||||
int is_head = rev_is_head(head_path,
|
int is_head = rev_is_head(head,
|
||||||
head_path_len,
|
head_len,
|
||||||
ref_name[i],
|
ref_name[i],
|
||||||
head_sha1,
|
head_sha1,
|
||||||
rev[i]->object.sha1);
|
rev[i]->object.sha1);
|
||||||
|
147
builtin-show-ref.c
Normal file
147
builtin-show-ref.c
Normal file
@ -0,0 +1,147 @@
|
|||||||
|
#include "cache.h"
|
||||||
|
#include "refs.h"
|
||||||
|
#include "object.h"
|
||||||
|
#include "tag.h"
|
||||||
|
|
||||||
|
static const char show_ref_usage[] = "git show-ref [-q|--quiet] [--verify] [-h|--head] [-d|--dereference] [-s|--hash[=<length>]] [--abbrev[=<length>]] [--tags] [--heads] [--] [pattern*]";
|
||||||
|
|
||||||
|
static int deref_tags = 0, show_head = 0, tags_only = 0, heads_only = 0,
|
||||||
|
found_match = 0, verify = 0, quiet = 0, hash_only = 0, abbrev = 0;
|
||||||
|
static const char **pattern;
|
||||||
|
|
||||||
|
static int show_ref(const char *refname, const unsigned char *sha1, int flag, void *cbdata)
|
||||||
|
{
|
||||||
|
struct object *obj;
|
||||||
|
const char *hex;
|
||||||
|
|
||||||
|
if (tags_only || heads_only) {
|
||||||
|
int match;
|
||||||
|
|
||||||
|
match = heads_only && !strncmp(refname, "refs/heads/", 11);
|
||||||
|
match |= tags_only && !strncmp(refname, "refs/tags/", 10);
|
||||||
|
if (!match)
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (pattern) {
|
||||||
|
int reflen = strlen(refname);
|
||||||
|
const char **p = pattern, *m;
|
||||||
|
while ((m = *p++) != NULL) {
|
||||||
|
int len = strlen(m);
|
||||||
|
if (len > reflen)
|
||||||
|
continue;
|
||||||
|
if (memcmp(m, refname + reflen - len, len))
|
||||||
|
continue;
|
||||||
|
if (len == reflen)
|
||||||
|
goto match;
|
||||||
|
/* "--verify" requires an exact match */
|
||||||
|
if (verify)
|
||||||
|
continue;
|
||||||
|
if (refname[reflen - len - 1] == '/')
|
||||||
|
goto match;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
match:
|
||||||
|
found_match++;
|
||||||
|
obj = parse_object(sha1);
|
||||||
|
if (!obj) {
|
||||||
|
if (quiet)
|
||||||
|
return 0;
|
||||||
|
die("git-show-ref: bad ref %s (%s)", refname, sha1_to_hex(sha1));
|
||||||
|
}
|
||||||
|
if (quiet)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
hex = find_unique_abbrev(sha1, abbrev);
|
||||||
|
if (hash_only)
|
||||||
|
printf("%s\n", hex);
|
||||||
|
else
|
||||||
|
printf("%s %s\n", hex, refname);
|
||||||
|
if (deref_tags && obj->type == OBJ_TAG) {
|
||||||
|
obj = deref_tag(obj, refname, 0);
|
||||||
|
hex = find_unique_abbrev(obj->sha1, abbrev);
|
||||||
|
printf("%s %s^{}\n", hex, refname);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int cmd_show_ref(int argc, const char **argv, const char *prefix)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 1; i < argc; i++) {
|
||||||
|
const char *arg = argv[i];
|
||||||
|
if (*arg != '-') {
|
||||||
|
pattern = argv + i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!strcmp(arg, "--")) {
|
||||||
|
pattern = argv + i + 1;
|
||||||
|
if (!*pattern)
|
||||||
|
pattern = NULL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!strcmp(arg, "-q") || !strcmp(arg, "--quiet")) {
|
||||||
|
quiet = 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!strcmp(arg, "-h") || !strcmp(arg, "--head")) {
|
||||||
|
show_head = 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!strcmp(arg, "-d") || !strcmp(arg, "--dereference")) {
|
||||||
|
deref_tags = 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!strcmp(arg, "-s") || !strcmp(arg, "--hash")) {
|
||||||
|
hash_only = 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!strncmp(arg, "--hash=", 7) ||
|
||||||
|
(!strncmp(arg, "--abbrev", 8) &&
|
||||||
|
(arg[8] == '=' || arg[8] == '\0'))) {
|
||||||
|
if (arg[3] != 'h' && !arg[8])
|
||||||
|
/* --abbrev only */
|
||||||
|
abbrev = DEFAULT_ABBREV;
|
||||||
|
else {
|
||||||
|
/* --hash= or --abbrev= */
|
||||||
|
char *end;
|
||||||
|
if (arg[3] == 'h') {
|
||||||
|
hash_only = 1;
|
||||||
|
arg += 7;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
arg += 9;
|
||||||
|
abbrev = strtoul(arg, &end, 10);
|
||||||
|
if (*end || abbrev > 40)
|
||||||
|
usage(show_ref_usage);
|
||||||
|
if (abbrev < MINIMUM_ABBREV)
|
||||||
|
abbrev = MINIMUM_ABBREV;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!strcmp(arg, "--verify")) {
|
||||||
|
verify = 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!strcmp(arg, "--tags")) {
|
||||||
|
tags_only = 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!strcmp(arg, "--heads")) {
|
||||||
|
heads_only = 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
usage(show_ref_usage);
|
||||||
|
}
|
||||||
|
if (show_head)
|
||||||
|
head_ref(show_ref, NULL);
|
||||||
|
for_each_ref(show_ref, NULL);
|
||||||
|
if (!found_match) {
|
||||||
|
if (verify && !quiet)
|
||||||
|
die("No match");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
@ -1,5 +1,6 @@
|
|||||||
#include "builtin.h"
|
#include "builtin.h"
|
||||||
#include "cache.h"
|
#include "cache.h"
|
||||||
|
#include "refs.h"
|
||||||
|
|
||||||
static const char git_symbolic_ref_usage[] =
|
static const char git_symbolic_ref_usage[] =
|
||||||
"git-symbolic-ref name [ref]";
|
"git-symbolic-ref name [ref]";
|
||||||
@ -7,15 +8,14 @@ static const char git_symbolic_ref_usage[] =
|
|||||||
static void check_symref(const char *HEAD)
|
static void check_symref(const char *HEAD)
|
||||||
{
|
{
|
||||||
unsigned char sha1[20];
|
unsigned char sha1[20];
|
||||||
const char *git_HEAD = xstrdup(git_path("%s", HEAD));
|
int flag;
|
||||||
const char *git_refs_heads_master = resolve_ref(git_HEAD, sha1, 0);
|
const char *refs_heads_master = resolve_ref(HEAD, sha1, 0, &flag);
|
||||||
if (git_refs_heads_master) {
|
|
||||||
/* we want to strip the .git/ part */
|
if (!refs_heads_master)
|
||||||
int pfxlen = strlen(git_HEAD) - strlen(HEAD);
|
|
||||||
puts(git_refs_heads_master + pfxlen);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
die("No such ref: %s", HEAD);
|
die("No such ref: %s", HEAD);
|
||||||
|
else if (!(flag & REF_ISSYMREF))
|
||||||
|
die("ref %s is not a symbolic ref", HEAD);
|
||||||
|
puts(refs_heads_master);
|
||||||
}
|
}
|
||||||
|
|
||||||
int cmd_symbolic_ref(int argc, const char **argv, const char *prefix)
|
int cmd_symbolic_ref(int argc, const char **argv, const char *prefix)
|
||||||
@ -26,7 +26,7 @@ int cmd_symbolic_ref(int argc, const char **argv, const char *prefix)
|
|||||||
check_symref(argv[1]);
|
check_symref(argv[1]);
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
create_symref(xstrdup(git_path("%s", argv[1])), argv[2]);
|
create_symref(argv[1], argv[2]);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
usage(git_symbolic_ref_usage);
|
usage(git_symbolic_ref_usage);
|
||||||
|
@ -22,7 +22,7 @@ static SHA_CTX ctx;
|
|||||||
* Make sure at least "min" bytes are available in the buffer, and
|
* Make sure at least "min" bytes are available in the buffer, and
|
||||||
* return the pointer to the buffer.
|
* return the pointer to the buffer.
|
||||||
*/
|
*/
|
||||||
static void * fill(int min)
|
static void *fill(int min)
|
||||||
{
|
{
|
||||||
if (min <= len)
|
if (min <= len)
|
||||||
return buffer + offset;
|
return buffer + offset;
|
||||||
@ -30,7 +30,7 @@ static void * fill(int min)
|
|||||||
die("cannot fill %d bytes", min);
|
die("cannot fill %d bytes", min);
|
||||||
if (offset) {
|
if (offset) {
|
||||||
SHA1_Update(&ctx, buffer, offset);
|
SHA1_Update(&ctx, buffer, offset);
|
||||||
memcpy(buffer, buffer + offset, len);
|
memmove(buffer, buffer + offset, len);
|
||||||
offset = 0;
|
offset = 0;
|
||||||
}
|
}
|
||||||
do {
|
do {
|
||||||
|
@ -406,9 +406,9 @@ static int unresolve_one(const char *path)
|
|||||||
|
|
||||||
static void read_head_pointers(void)
|
static void read_head_pointers(void)
|
||||||
{
|
{
|
||||||
if (read_ref(git_path("HEAD"), head_sha1))
|
if (read_ref("HEAD", head_sha1))
|
||||||
die("No HEAD -- no initial commit yet?\n");
|
die("No HEAD -- no initial commit yet?\n");
|
||||||
if (read_ref(git_path("MERGE_HEAD"), merge_head_sha1)) {
|
if (read_ref("MERGE_HEAD", merge_head_sha1)) {
|
||||||
fprintf(stderr, "Not in the middle of a merge.\n");
|
fprintf(stderr, "Not in the middle of a merge.\n");
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
@ -445,7 +445,7 @@ static int do_reupdate(int ac, const char **av,
|
|||||||
int has_head = 1;
|
int has_head = 1;
|
||||||
const char **pathspec = get_pathspec(prefix, av + 1);
|
const char **pathspec = get_pathspec(prefix, av + 1);
|
||||||
|
|
||||||
if (read_ref(git_path("HEAD"), head_sha1))
|
if (read_ref("HEAD", head_sha1))
|
||||||
/* If there is no HEAD, that means it is an initial
|
/* If there is no HEAD, that means it is an initial
|
||||||
* commit. Update everything in the index.
|
* commit. Update everything in the index.
|
||||||
*/
|
*/
|
||||||
|
@ -3,15 +3,16 @@
|
|||||||
#include "builtin.h"
|
#include "builtin.h"
|
||||||
|
|
||||||
static const char git_update_ref_usage[] =
|
static const char git_update_ref_usage[] =
|
||||||
"git-update-ref <refname> <value> [<oldval>] [-m <reason>]";
|
"git-update-ref [-m <reason>] (-d <refname> <value> | <refname> <value> [<oldval>])";
|
||||||
|
|
||||||
int cmd_update_ref(int argc, const char **argv, const char *prefix)
|
int cmd_update_ref(int argc, const char **argv, const char *prefix)
|
||||||
{
|
{
|
||||||
const char *refname=NULL, *value=NULL, *oldval=NULL, *msg=NULL;
|
const char *refname=NULL, *value=NULL, *oldval=NULL, *msg=NULL;
|
||||||
struct ref_lock *lock;
|
struct ref_lock *lock;
|
||||||
unsigned char sha1[20], oldsha1[20];
|
unsigned char sha1[20], oldsha1[20];
|
||||||
int i;
|
int i, delete;
|
||||||
|
|
||||||
|
delete = 0;
|
||||||
setup_ident();
|
setup_ident();
|
||||||
git_config(git_default_config);
|
git_config(git_default_config);
|
||||||
|
|
||||||
@ -26,6 +27,10 @@ int cmd_update_ref(int argc, const char **argv, const char *prefix)
|
|||||||
die("Refusing to perform update with \\n in message.");
|
die("Refusing to perform update with \\n in message.");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (!strcmp("-d", argv[i])) {
|
||||||
|
delete = 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if (!refname) {
|
if (!refname) {
|
||||||
refname = argv[i];
|
refname = argv[i];
|
||||||
continue;
|
continue;
|
||||||
@ -44,11 +49,18 @@ int cmd_update_ref(int argc, const char **argv, const char *prefix)
|
|||||||
|
|
||||||
if (get_sha1(value, sha1))
|
if (get_sha1(value, sha1))
|
||||||
die("%s: not a valid SHA1", value);
|
die("%s: not a valid SHA1", value);
|
||||||
|
|
||||||
|
if (delete) {
|
||||||
|
if (oldval)
|
||||||
|
usage(git_update_ref_usage);
|
||||||
|
return delete_ref(refname, sha1);
|
||||||
|
}
|
||||||
|
|
||||||
hashclr(oldsha1);
|
hashclr(oldsha1);
|
||||||
if (oldval && get_sha1(oldval, oldsha1))
|
if (oldval && *oldval && get_sha1(oldval, oldsha1))
|
||||||
die("%s: not a valid old SHA1", oldval);
|
die("%s: not a valid old SHA1", oldval);
|
||||||
|
|
||||||
lock = lock_any_ref_for_update(refname, oldval ? oldsha1 : NULL, 0);
|
lock = lock_any_ref_for_update(refname, oldval ? oldsha1 : NULL);
|
||||||
if (!lock)
|
if (!lock)
|
||||||
return 1;
|
return 1;
|
||||||
if (write_ref_sha1(lock, sha1, msg) < 0)
|
if (write_ref_sha1(lock, sha1, msg) < 0)
|
||||||
|
@ -17,9 +17,11 @@ extern int cmd_add(int argc, const char **argv, const char *prefix);
|
|||||||
extern int cmd_annotate(int argc, const char **argv, const char *prefix);
|
extern int cmd_annotate(int argc, const char **argv, const char *prefix);
|
||||||
extern int cmd_apply(int argc, const char **argv, const char *prefix);
|
extern int cmd_apply(int argc, const char **argv, const char *prefix);
|
||||||
extern int cmd_archive(int argc, const char **argv, const char *prefix);
|
extern int cmd_archive(int argc, const char **argv, const char *prefix);
|
||||||
|
extern int cmd_branch(int argc, const char **argv, const char *prefix);
|
||||||
extern int cmd_cat_file(int argc, const char **argv, const char *prefix);
|
extern int cmd_cat_file(int argc, const char **argv, const char *prefix);
|
||||||
extern int cmd_checkout_index(int argc, const char **argv, const char *prefix);
|
extern int cmd_checkout_index(int argc, const char **argv, const char *prefix);
|
||||||
extern int cmd_check_ref_format(int argc, const char **argv, const char *prefix);
|
extern int cmd_check_ref_format(int argc, const char **argv, const char *prefix);
|
||||||
|
extern int cmd_cherry(int argc, const char **argv, const char *prefix);
|
||||||
extern int cmd_commit_tree(int argc, const char **argv, const char *prefix);
|
extern int cmd_commit_tree(int argc, const char **argv, const char *prefix);
|
||||||
extern int cmd_count_objects(int argc, const char **argv, const char *prefix);
|
extern int cmd_count_objects(int argc, const char **argv, const char *prefix);
|
||||||
extern int cmd_diff_files(int argc, const char **argv, const char *prefix);
|
extern int cmd_diff_files(int argc, const char **argv, const char *prefix);
|
||||||
@ -65,5 +67,7 @@ extern int cmd_version(int argc, const char **argv, const char *prefix);
|
|||||||
extern int cmd_whatchanged(int argc, const char **argv, const char *prefix);
|
extern int cmd_whatchanged(int argc, const char **argv, const char *prefix);
|
||||||
extern int cmd_write_tree(int argc, const char **argv, const char *prefix);
|
extern int cmd_write_tree(int argc, const char **argv, const char *prefix);
|
||||||
extern int cmd_verify_pack(int argc, const char **argv, const char *prefix);
|
extern int cmd_verify_pack(int argc, const char **argv, const char *prefix);
|
||||||
|
extern int cmd_show_ref(int argc, const char **argv, const char *prefix);
|
||||||
|
extern int cmd_pack_refs(int argc, const char **argv, const char *prefix);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -2,7 +2,9 @@
|
|||||||
#include "tree.h"
|
#include "tree.h"
|
||||||
#include "cache-tree.h"
|
#include "cache-tree.h"
|
||||||
|
|
||||||
|
#ifndef DEBUG
|
||||||
#define DEBUG 0
|
#define DEBUG 0
|
||||||
|
#endif
|
||||||
|
|
||||||
struct cache_tree *cache_tree(void)
|
struct cache_tree *cache_tree(void)
|
||||||
{
|
{
|
||||||
|
8
cache.h
8
cache.h
@ -179,6 +179,7 @@ struct lock_file {
|
|||||||
extern int hold_lock_file_for_update(struct lock_file *, const char *path, int);
|
extern int hold_lock_file_for_update(struct lock_file *, const char *path, int);
|
||||||
extern int commit_lock_file(struct lock_file *);
|
extern int commit_lock_file(struct lock_file *);
|
||||||
extern void rollback_lock_file(struct lock_file *);
|
extern void rollback_lock_file(struct lock_file *);
|
||||||
|
extern int delete_ref(const char *, unsigned char *sha1);
|
||||||
|
|
||||||
/* Environment bits from configuration mechanism */
|
/* Environment bits from configuration mechanism */
|
||||||
extern int use_legacy_headers;
|
extern int use_legacy_headers;
|
||||||
@ -188,7 +189,6 @@ extern int prefer_symlink_refs;
|
|||||||
extern int log_all_ref_updates;
|
extern int log_all_ref_updates;
|
||||||
extern int warn_ambiguous_refs;
|
extern int warn_ambiguous_refs;
|
||||||
extern int shared_repository;
|
extern int shared_repository;
|
||||||
extern int deny_non_fast_forwards;
|
|
||||||
extern const char *apply_default_whitespace;
|
extern const char *apply_default_whitespace;
|
||||||
extern int zlib_compression_level;
|
extern int zlib_compression_level;
|
||||||
|
|
||||||
@ -289,9 +289,9 @@ extern int get_sha1(const char *str, unsigned char *sha1);
|
|||||||
extern int get_sha1_hex(const char *hex, unsigned char *sha1);
|
extern int get_sha1_hex(const char *hex, unsigned char *sha1);
|
||||||
extern char *sha1_to_hex(const unsigned char *sha1); /* static buffer result! */
|
extern char *sha1_to_hex(const unsigned char *sha1); /* static buffer result! */
|
||||||
extern int read_ref(const char *filename, unsigned char *sha1);
|
extern int read_ref(const char *filename, unsigned char *sha1);
|
||||||
extern const char *resolve_ref(const char *path, unsigned char *sha1, int);
|
extern const char *resolve_ref(const char *path, unsigned char *sha1, int, int *);
|
||||||
extern int create_symref(const char *git_HEAD, const char *refs_heads_master);
|
extern int create_symref(const char *ref, const char *refs_heads_master);
|
||||||
extern int validate_symref(const char *git_HEAD);
|
extern int validate_symref(const char *ref);
|
||||||
|
|
||||||
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);
|
||||||
|
@ -53,7 +53,7 @@ static void add_to_known_names(const char *path,
|
|||||||
names = ++idx;
|
names = ++idx;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int get_name(const char *path, const unsigned char *sha1)
|
static int get_name(const char *path, const unsigned char *sha1, int flag, void *cb_data)
|
||||||
{
|
{
|
||||||
struct commit *commit = lookup_commit_reference_gently(sha1, 1);
|
struct commit *commit = lookup_commit_reference_gently(sha1, 1);
|
||||||
struct object *object;
|
struct object *object;
|
||||||
@ -113,7 +113,7 @@ static void describe(const char *arg, int last_one)
|
|||||||
|
|
||||||
if (!initialized) {
|
if (!initialized) {
|
||||||
initialized = 1;
|
initialized = 1;
|
||||||
for_each_ref(get_name);
|
for_each_ref(get_name, NULL);
|
||||||
qsort(name_array, names, sizeof(*name_array), compare_names);
|
qsort(name_array, names, sizeof(*name_array), compare_names);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
2
diff.h
2
diff.h
@ -102,6 +102,8 @@ extern int diff_tree(struct tree_desc *t1, struct tree_desc *t2,
|
|||||||
const char *base, struct diff_options *opt);
|
const char *base, struct diff_options *opt);
|
||||||
extern int diff_tree_sha1(const unsigned char *old, const unsigned char *new,
|
extern int diff_tree_sha1(const unsigned char *old, const unsigned char *new,
|
||||||
const char *base, struct diff_options *opt);
|
const char *base, struct diff_options *opt);
|
||||||
|
extern int diff_root_tree_sha1(const unsigned char *new, const char *base,
|
||||||
|
struct diff_options *opt);
|
||||||
|
|
||||||
struct combine_diff_path {
|
struct combine_diff_path {
|
||||||
struct combine_diff_path *next;
|
struct combine_diff_path *next;
|
||||||
|
@ -20,7 +20,6 @@ int warn_ambiguous_refs = 1;
|
|||||||
int repository_format_version;
|
int repository_format_version;
|
||||||
char git_commit_encoding[MAX_ENCODING_LENGTH] = "utf-8";
|
char git_commit_encoding[MAX_ENCODING_LENGTH] = "utf-8";
|
||||||
int shared_repository = PERM_UMASK;
|
int shared_repository = PERM_UMASK;
|
||||||
int deny_non_fast_forwards = 0;
|
|
||||||
const char *apply_default_whitespace;
|
const char *apply_default_whitespace;
|
||||||
int zlib_compression_level = Z_DEFAULT_COMPRESSION;
|
int zlib_compression_level = Z_DEFAULT_COMPRESSION;
|
||||||
int pager_in_use;
|
int pager_in_use;
|
||||||
|
@ -42,7 +42,7 @@ static void rev_list_push(struct commit *commit, int mark)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int rev_list_insert_ref(const char *path, const unsigned char *sha1)
|
static int rev_list_insert_ref(const char *path, const unsigned char *sha1, int flag, void *cb_data)
|
||||||
{
|
{
|
||||||
struct object *o = deref_tag(parse_object(sha1), path, 0);
|
struct object *o = deref_tag(parse_object(sha1), path, 0);
|
||||||
|
|
||||||
@ -143,7 +143,7 @@ static int find_common(int fd[2], unsigned char *result_sha1,
|
|||||||
unsigned in_vain = 0;
|
unsigned in_vain = 0;
|
||||||
int got_continue = 0;
|
int got_continue = 0;
|
||||||
|
|
||||||
for_each_ref(rev_list_insert_ref);
|
for_each_ref(rev_list_insert_ref, NULL);
|
||||||
|
|
||||||
fetching = 0;
|
fetching = 0;
|
||||||
for ( ; refs ; refs = refs->next) {
|
for ( ; refs ; refs = refs->next) {
|
||||||
@ -254,7 +254,7 @@ done:
|
|||||||
|
|
||||||
static struct commit_list *complete;
|
static struct commit_list *complete;
|
||||||
|
|
||||||
static int mark_complete(const char *path, const unsigned char *sha1)
|
static int mark_complete(const char *path, const unsigned char *sha1, int flag, void *cb_data)
|
||||||
{
|
{
|
||||||
struct object *o = parse_object(sha1);
|
struct object *o = parse_object(sha1);
|
||||||
|
|
||||||
@ -366,7 +366,7 @@ static int everything_local(struct ref **refs, int nr_match, char **match)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for_each_ref(mark_complete);
|
for_each_ref(mark_complete, NULL);
|
||||||
if (cutoff)
|
if (cutoff)
|
||||||
mark_recent_complete_commits(cutoff);
|
mark_recent_complete_commits(cutoff);
|
||||||
|
|
||||||
|
6
fetch.c
6
fetch.c
@ -201,7 +201,7 @@ static int interpret_target(char *target, unsigned char *sha1)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int mark_complete(const char *path, const unsigned char *sha1)
|
static int mark_complete(const char *path, const unsigned char *sha1, int flag, void *cb_data)
|
||||||
{
|
{
|
||||||
struct commit *commit = lookup_commit_reference_gently(sha1, 1);
|
struct commit *commit = lookup_commit_reference_gently(sha1, 1);
|
||||||
if (commit) {
|
if (commit) {
|
||||||
@ -266,7 +266,7 @@ int pull(int targets, char **target, const char **write_ref,
|
|||||||
if (!write_ref || !write_ref[i])
|
if (!write_ref || !write_ref[i])
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
lock[i] = lock_ref_sha1(write_ref[i], NULL, 0);
|
lock[i] = lock_ref_sha1(write_ref[i], NULL);
|
||||||
if (!lock[i]) {
|
if (!lock[i]) {
|
||||||
error("Can't lock ref %s", write_ref[i]);
|
error("Can't lock ref %s", write_ref[i]);
|
||||||
goto unlock_and_fail;
|
goto unlock_and_fail;
|
||||||
@ -274,7 +274,7 @@ int pull(int targets, char **target, const char **write_ref,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!get_recover)
|
if (!get_recover)
|
||||||
for_each_ref(mark_complete);
|
for_each_ref(mark_complete, NULL);
|
||||||
|
|
||||||
for (i = 0; i < targets; i++) {
|
for (i = 0; i < targets; i++) {
|
||||||
if (interpret_target(target[i], &sha1[20 * i])) {
|
if (interpret_target(target[i], &sha1[20 * i])) {
|
||||||
|
@ -402,7 +402,7 @@ static void fsck_dir(int i, char *path)
|
|||||||
|
|
||||||
static int default_refs;
|
static int default_refs;
|
||||||
|
|
||||||
static int fsck_handle_ref(const char *refname, const unsigned char *sha1)
|
static int fsck_handle_ref(const char *refname, const unsigned char *sha1, int flag, void *cb_data)
|
||||||
{
|
{
|
||||||
struct object *obj;
|
struct object *obj;
|
||||||
|
|
||||||
@ -424,7 +424,7 @@ static int fsck_handle_ref(const char *refname, const unsigned char *sha1)
|
|||||||
|
|
||||||
static void get_default_heads(void)
|
static void get_default_heads(void)
|
||||||
{
|
{
|
||||||
for_each_ref(fsck_handle_ref);
|
for_each_ref(fsck_handle_ref, NULL);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Not having any default heads isn't really fatal, but
|
* Not having any default heads isn't really fatal, but
|
||||||
@ -458,15 +458,14 @@ static void fsck_object_dir(const char *path)
|
|||||||
static int fsck_head_link(void)
|
static int fsck_head_link(void)
|
||||||
{
|
{
|
||||||
unsigned char sha1[20];
|
unsigned char sha1[20];
|
||||||
const char *git_HEAD = xstrdup(git_path("HEAD"));
|
int flag;
|
||||||
const char *git_refs_heads_master = resolve_ref(git_HEAD, sha1, 1);
|
const char *head_points_at = resolve_ref("HEAD", sha1, 1, &flag);
|
||||||
int pfxlen = strlen(git_HEAD) - 4; /* strip .../.git/ part */
|
|
||||||
|
|
||||||
if (!git_refs_heads_master)
|
if (!head_points_at || !(flag & REF_ISSYMREF))
|
||||||
return error("HEAD is not a symbolic ref");
|
return error("HEAD is not a symbolic ref");
|
||||||
if (strncmp(git_refs_heads_master + pfxlen, "refs/heads/", 11))
|
if (strncmp(head_points_at, "refs/heads/", 11))
|
||||||
return error("HEAD points to something strange (%s)",
|
return error("HEAD points to something strange (%s)",
|
||||||
git_refs_heads_master + pfxlen);
|
head_points_at);
|
||||||
if (is_null_sha1(sha1))
|
if (is_null_sha1(sha1))
|
||||||
return error("HEAD: not a valid git pointer");
|
return error("HEAD: not a valid git pointer");
|
||||||
return 0;
|
return 0;
|
||||||
|
140
git-branch.sh
140
git-branch.sh
@ -1,140 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
|
|
||||||
USAGE='[-l] [-f] <branchname> [<start-point>] | (-d | -D) <branchname> | [-r]'
|
|
||||||
LONG_USAGE='If no arguments, show available branches and mark current branch with a star.
|
|
||||||
If one argument, create a new branch <branchname> based off of current HEAD.
|
|
||||||
If two arguments, create a new branch <branchname> based off of <start-point>.'
|
|
||||||
|
|
||||||
SUBDIRECTORY_OK='Yes'
|
|
||||||
. git-sh-setup
|
|
||||||
|
|
||||||
headref=$(git-symbolic-ref HEAD | sed -e 's|^refs/heads/||')
|
|
||||||
|
|
||||||
delete_branch () {
|
|
||||||
option="$1"
|
|
||||||
shift
|
|
||||||
for branch_name
|
|
||||||
do
|
|
||||||
case ",$headref," in
|
|
||||||
",$branch_name,")
|
|
||||||
die "Cannot delete the branch you are on." ;;
|
|
||||||
,,)
|
|
||||||
die "What branch are you on anyway?" ;;
|
|
||||||
esac
|
|
||||||
branch=$(cat "$GIT_DIR/refs/heads/$branch_name") &&
|
|
||||||
branch=$(git-rev-parse --verify "$branch^0") ||
|
|
||||||
die "Seriously, what branch are you talking about?"
|
|
||||||
case "$option" in
|
|
||||||
-D)
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
mbs=$(git-merge-base -a "$branch" HEAD | tr '\012' ' ')
|
|
||||||
case " $mbs " in
|
|
||||||
*' '$branch' '*)
|
|
||||||
# the merge base of branch and HEAD contains branch --
|
|
||||||
# which means that the HEAD contains everything in both.
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
echo >&2 "The branch '$branch_name' is not a strict subset of your current HEAD.
|
|
||||||
If you are sure you want to delete it, run 'git branch -D $branch_name'."
|
|
||||||
exit 1
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
rm -f "$GIT_DIR/logs/refs/heads/$branch_name"
|
|
||||||
rm -f "$GIT_DIR/refs/heads/$branch_name"
|
|
||||||
echo "Deleted branch $branch_name."
|
|
||||||
done
|
|
||||||
exit 0
|
|
||||||
}
|
|
||||||
|
|
||||||
ls_remote_branches () {
|
|
||||||
git-rev-parse --symbolic --all |
|
|
||||||
sed -ne 's|^refs/\(remotes/\)|\1|p' |
|
|
||||||
sort
|
|
||||||
}
|
|
||||||
|
|
||||||
force=
|
|
||||||
create_log=
|
|
||||||
while case "$#,$1" in 0,*) break ;; *,-*) ;; *) break ;; esac
|
|
||||||
do
|
|
||||||
case "$1" in
|
|
||||||
-d | -D)
|
|
||||||
delete_branch "$@"
|
|
||||||
exit
|
|
||||||
;;
|
|
||||||
-r)
|
|
||||||
ls_remote_branches
|
|
||||||
exit
|
|
||||||
;;
|
|
||||||
-f)
|
|
||||||
force="$1"
|
|
||||||
;;
|
|
||||||
-l)
|
|
||||||
create_log="yes"
|
|
||||||
;;
|
|
||||||
--)
|
|
||||||
shift
|
|
||||||
break
|
|
||||||
;;
|
|
||||||
-*)
|
|
||||||
usage
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
shift
|
|
||||||
done
|
|
||||||
|
|
||||||
case "$#" in
|
|
||||||
0)
|
|
||||||
git-rev-parse --symbolic --branches |
|
|
||||||
sort |
|
|
||||||
while read ref
|
|
||||||
do
|
|
||||||
if test "$headref" = "$ref"
|
|
||||||
then
|
|
||||||
pfx='*'
|
|
||||||
else
|
|
||||||
pfx=' '
|
|
||||||
fi
|
|
||||||
echo "$pfx $ref"
|
|
||||||
done
|
|
||||||
exit 0 ;;
|
|
||||||
1)
|
|
||||||
head=HEAD ;;
|
|
||||||
2)
|
|
||||||
head="$2^0" ;;
|
|
||||||
esac
|
|
||||||
branchname="$1"
|
|
||||||
|
|
||||||
rev=$(git-rev-parse --verify "$head") || exit
|
|
||||||
|
|
||||||
git-check-ref-format "heads/$branchname" ||
|
|
||||||
die "we do not like '$branchname' as a branch name."
|
|
||||||
|
|
||||||
if [ -d "$GIT_DIR/refs/heads/$branchname" ]
|
|
||||||
then
|
|
||||||
for refdir in `cd "$GIT_DIR" && \
|
|
||||||
find "refs/heads/$branchname" -type d | sort -r`
|
|
||||||
do
|
|
||||||
rmdir "$GIT_DIR/$refdir" || \
|
|
||||||
die "Could not delete '$refdir', there may still be a ref there."
|
|
||||||
done
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -e "$GIT_DIR/refs/heads/$branchname" ]
|
|
||||||
then
|
|
||||||
if test '' = "$force"
|
|
||||||
then
|
|
||||||
die "$branchname already exists."
|
|
||||||
elif test "$branchname" = "$headref"
|
|
||||||
then
|
|
||||||
die "cannot force-update the current branch."
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
if test "$create_log" = 'yes'
|
|
||||||
then
|
|
||||||
mkdir -p $(dirname "$GIT_DIR/logs/refs/heads/$branchname")
|
|
||||||
touch "$GIT_DIR/logs/refs/heads/$branchname"
|
|
||||||
fi
|
|
||||||
git update-ref -m "branch: Created from $head" "refs/heads/$branchname" $rev
|
|
@ -22,7 +22,7 @@ while [ "$#" != "0" ]; do
|
|||||||
shift
|
shift
|
||||||
[ -z "$newbranch" ] &&
|
[ -z "$newbranch" ] &&
|
||||||
die "git checkout: -b needs a branch name"
|
die "git checkout: -b needs a branch name"
|
||||||
[ -e "$GIT_DIR/refs/heads/$newbranch" ] &&
|
git-show-ref --verify --quiet -- "refs/heads/$newbranch" &&
|
||||||
die "git checkout: branch $newbranch already exists"
|
die "git checkout: branch $newbranch already exists"
|
||||||
git-check-ref-format "heads/$newbranch" ||
|
git-check-ref-format "heads/$newbranch" ||
|
||||||
die "git checkout: we do not like '$newbranch' as a branch name."
|
die "git checkout: we do not like '$newbranch' as a branch name."
|
||||||
@ -51,7 +51,8 @@ while [ "$#" != "0" ]; do
|
|||||||
fi
|
fi
|
||||||
new="$rev"
|
new="$rev"
|
||||||
new_name="$arg^0"
|
new_name="$arg^0"
|
||||||
if [ -f "$GIT_DIR/refs/heads/$arg" ]; then
|
if git-show-ref --verify --quiet -- "refs/heads/$arg"
|
||||||
|
then
|
||||||
branch="$arg"
|
branch="$arg"
|
||||||
fi
|
fi
|
||||||
elif rev=$(git-rev-parse --verify "$arg^{tree}" 2>/dev/null)
|
elif rev=$(git-rev-parse --verify "$arg^{tree}" 2>/dev/null)
|
||||||
|
@ -441,7 +441,7 @@ then
|
|||||||
elif test "$use_commit" != ""
|
elif test "$use_commit" != ""
|
||||||
then
|
then
|
||||||
git-cat-file commit "$use_commit" | sed -e '1,/^$/d'
|
git-cat-file commit "$use_commit" | sed -e '1,/^$/d'
|
||||||
elif test -f "$GIT_DIR/MERGE_HEAD" && test -f "$GIT_DIR/MERGE_MSG"
|
elif test -f "$GIT_DIR/MERGE_MSG"
|
||||||
then
|
then
|
||||||
cat "$GIT_DIR/MERGE_MSG"
|
cat "$GIT_DIR/MERGE_MSG"
|
||||||
elif test -f "$GIT_DIR/SQUASH_MSG"
|
elif test -f "$GIT_DIR/SQUASH_MSG"
|
||||||
@ -522,15 +522,15 @@ then
|
|||||||
PARENTS=$(git-cat-file commit HEAD |
|
PARENTS=$(git-cat-file commit HEAD |
|
||||||
sed -n -e '/^$/q' -e 's/^parent /-p /p')
|
sed -n -e '/^$/q' -e 's/^parent /-p /p')
|
||||||
fi
|
fi
|
||||||
current=$(git-rev-parse --verify HEAD)
|
current="$(git-rev-parse --verify HEAD)"
|
||||||
else
|
else
|
||||||
if [ -z "$(git-ls-files)" ]; then
|
if [ -z "$(git-ls-files)" ]; then
|
||||||
echo >&2 Nothing to commit
|
echo >&2 Nothing to commit
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
PARENTS=""
|
PARENTS=""
|
||||||
current=
|
|
||||||
rloga='commit (initial)'
|
rloga='commit (initial)'
|
||||||
|
current=''
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if test -z "$no_edit"
|
if test -z "$no_edit"
|
||||||
@ -606,8 +606,8 @@ then
|
|||||||
fi &&
|
fi &&
|
||||||
commit=$(cat "$GIT_DIR"/COMMIT_MSG | git-commit-tree $tree $PARENTS) &&
|
commit=$(cat "$GIT_DIR"/COMMIT_MSG | git-commit-tree $tree $PARENTS) &&
|
||||||
rlogm=$(sed -e 1q "$GIT_DIR"/COMMIT_MSG) &&
|
rlogm=$(sed -e 1q "$GIT_DIR"/COMMIT_MSG) &&
|
||||||
git-update-ref -m "$rloga: $rlogm" HEAD $commit $current &&
|
git-update-ref -m "$rloga: $rlogm" HEAD $commit "$current" &&
|
||||||
rm -f -- "$GIT_DIR/MERGE_HEAD" &&
|
rm -f -- "$GIT_DIR/MERGE_HEAD" "$GIT_DIR/MERGE_MSG" &&
|
||||||
if test -f "$NEXT_INDEX"
|
if test -f "$NEXT_INDEX"
|
||||||
then
|
then
|
||||||
mv "$NEXT_INDEX" "$THIS_INDEX"
|
mv "$NEXT_INDEX" "$THIS_INDEX"
|
||||||
|
10
git-fetch.sh
10
git-fetch.sh
@ -147,15 +147,15 @@ update_local_ref () {
|
|||||||
[ "$verbose" ] && echo >&2 " $label_: $newshort_"
|
[ "$verbose" ] && echo >&2 " $label_: $newshort_"
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
oldshort_=$(git-rev-parse --short "$1" 2>/dev/null)
|
oldshort_=$(git show-ref --hash --abbrev "$1" 2>/dev/null)
|
||||||
mkdir -p "$(dirname "$GIT_DIR/$1")"
|
|
||||||
case "$1" in
|
case "$1" in
|
||||||
refs/tags/*)
|
refs/tags/*)
|
||||||
# Tags need not be pointing at commits so there
|
# Tags need not be pointing at commits so there
|
||||||
# is no way to guarantee "fast-forward" anyway.
|
# is no way to guarantee "fast-forward" anyway.
|
||||||
if test -f "$GIT_DIR/$1"
|
if test -n "$oldshort_"
|
||||||
then
|
then
|
||||||
if now_=$(cat "$GIT_DIR/$1") && test "$now_" = "$2"
|
if now_=$(git show-ref --hash "$1") && test "$now_" = "$2"
|
||||||
then
|
then
|
||||||
[ "$verbose" ] && echo >&2 "* $1: same as $3"
|
[ "$verbose" ] && echo >&2 "* $1: same as $3"
|
||||||
[ "$verbose" ] && echo >&2 " $label_: $newshort_" ||:
|
[ "$verbose" ] && echo >&2 " $label_: $newshort_" ||:
|
||||||
@ -427,7 +427,7 @@ case "$no_tags$tags" in
|
|||||||
sed -ne 's|^\([0-9a-f]*\)[ ]\(refs/tags/.*\)^{}$|\1 \2|p' |
|
sed -ne 's|^\([0-9a-f]*\)[ ]\(refs/tags/.*\)^{}$|\1 \2|p' |
|
||||||
while read sha1 name
|
while read sha1 name
|
||||||
do
|
do
|
||||||
test -f "$GIT_DIR/$name" && continue
|
git-show-ref --verify --quiet -- $name && continue
|
||||||
git-check-ref-format "$name" || {
|
git-check-ref-format "$name" || {
|
||||||
echo >&2 "warning: tag ${name} ignored"
|
echo >&2 "warning: tag ${name} ignored"
|
||||||
continue
|
continue
|
||||||
|
@ -145,9 +145,18 @@ git-read-tree -m -u --aggressive $base $head $next &&
|
|||||||
result=$(git-write-tree 2>/dev/null) || {
|
result=$(git-write-tree 2>/dev/null) || {
|
||||||
echo >&2 "Simple $me fails; trying Automatic $me."
|
echo >&2 "Simple $me fails; trying Automatic $me."
|
||||||
git-merge-index -o git-merge-one-file -a || {
|
git-merge-index -o git-merge-one-file -a || {
|
||||||
|
mv -f .msg "$GIT_DIR/MERGE_MSG"
|
||||||
|
{
|
||||||
|
echo '
|
||||||
|
Conflicts:
|
||||||
|
'
|
||||||
|
git ls-files --unmerged |
|
||||||
|
sed -e 's/^[^ ]* / /' |
|
||||||
|
uniq
|
||||||
|
} >>"$GIT_DIR/MERGE_MSG"
|
||||||
echo >&2 "Automatic $me failed. After resolving the conflicts,"
|
echo >&2 "Automatic $me failed. After resolving the conflicts,"
|
||||||
echo >&2 "mark the corrected paths with 'git-update-index <paths>'"
|
echo >&2 "mark the corrected paths with 'git-update-index <paths>'"
|
||||||
echo >&2 "and commit with 'git commit -F .msg'"
|
echo >&2 "and commit the result."
|
||||||
case "$me" in
|
case "$me" in
|
||||||
cherry-pick)
|
cherry-pick)
|
||||||
echo >&2 "You may choose to use the following when making"
|
echo >&2 "You may choose to use the following when making"
|
||||||
|
@ -31,7 +31,7 @@ $SIG{'PIPE'}="IGNORE";
|
|||||||
$ENV{'TZ'}="UTC";
|
$ENV{'TZ'}="UTC";
|
||||||
|
|
||||||
our($opt_h,$opt_o,$opt_v,$opt_u,$opt_C,$opt_i,$opt_m,$opt_M,$opt_t,$opt_T,
|
our($opt_h,$opt_o,$opt_v,$opt_u,$opt_C,$opt_i,$opt_m,$opt_M,$opt_t,$opt_T,
|
||||||
$opt_b,$opt_r,$opt_I,$opt_A,$opt_s,$opt_l,$opt_d,$opt_D,$opt_S,$opt_F);
|
$opt_b,$opt_r,$opt_I,$opt_A,$opt_s,$opt_l,$opt_d,$opt_D,$opt_S,$opt_F,$opt_P);
|
||||||
|
|
||||||
sub usage() {
|
sub usage() {
|
||||||
print STDERR <<END;
|
print STDERR <<END;
|
||||||
@ -39,17 +39,19 @@ Usage: ${\basename $0} # fetch/update GIT from SVN
|
|||||||
[-o branch-for-HEAD] [-h] [-v] [-l max_rev]
|
[-o branch-for-HEAD] [-h] [-v] [-l max_rev]
|
||||||
[-C GIT_repository] [-t tagname] [-T trunkname] [-b branchname]
|
[-C GIT_repository] [-t tagname] [-T trunkname] [-b branchname]
|
||||||
[-d|-D] [-i] [-u] [-r] [-I ignorefilename] [-s start_chg]
|
[-d|-D] [-i] [-u] [-r] [-I ignorefilename] [-s start_chg]
|
||||||
[-m] [-M regex] [-A author_file] [-S] [-F] [SVN_URL]
|
[-m] [-M regex] [-A author_file] [-S] [-F] [-P project_name] [SVN_URL]
|
||||||
END
|
END
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
getopts("A:b:C:dDFhiI:l:mM:o:rs:t:T:Suv") or usage();
|
getopts("A:b:C:dDFhiI:l:mM:o:rs:t:T:SP:uv") or usage();
|
||||||
usage if $opt_h;
|
usage if $opt_h;
|
||||||
|
|
||||||
my $tag_name = $opt_t || "tags";
|
my $tag_name = $opt_t || "tags";
|
||||||
my $trunk_name = $opt_T || "trunk";
|
my $trunk_name = $opt_T || "trunk";
|
||||||
my $branch_name = $opt_b || "branches";
|
my $branch_name = $opt_b || "branches";
|
||||||
|
my $project_name = $opt_P || "";
|
||||||
|
$project_name = "/" . $project_name if ($project_name);
|
||||||
|
|
||||||
@ARGV == 1 or @ARGV == 2 or usage();
|
@ARGV == 1 or @ARGV == 2 or usage();
|
||||||
|
|
||||||
@ -427,6 +429,20 @@ sub get_ignore($$$$$) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub project_path($$)
|
||||||
|
{
|
||||||
|
my ($path, $project) = @_;
|
||||||
|
|
||||||
|
$path = "/".$path unless ($path =~ m#^\/#) ;
|
||||||
|
return $1 if ($path =~ m#^$project\/(.*)$#);
|
||||||
|
|
||||||
|
$path =~ s#\.#\\\.#g;
|
||||||
|
$path =~ s#\+#\\\+#g;
|
||||||
|
return "/" if ($project =~ m#^$path.*$#);
|
||||||
|
|
||||||
|
return undef;
|
||||||
|
}
|
||||||
|
|
||||||
sub split_path($$) {
|
sub split_path($$) {
|
||||||
my($rev,$path) = @_;
|
my($rev,$path) = @_;
|
||||||
my $branch;
|
my $branch;
|
||||||
@ -446,7 +462,11 @@ sub split_path($$) {
|
|||||||
print STDERR "$rev: Unrecognized path: $path\n" unless (defined $no_error{$path});
|
print STDERR "$rev: Unrecognized path: $path\n" unless (defined $no_error{$path});
|
||||||
return ()
|
return ()
|
||||||
}
|
}
|
||||||
$path = "/" if $path eq "";
|
if ($path eq "") {
|
||||||
|
$path = "/";
|
||||||
|
} elsif ($project_name) {
|
||||||
|
$path = project_path($path, $project_name);
|
||||||
|
}
|
||||||
return ($branch,$path);
|
return ($branch,$path);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -898,6 +918,7 @@ sub commit_all {
|
|||||||
while(my($path,$action) = each %$changed_paths) {
|
while(my($path,$action) = each %$changed_paths) {
|
||||||
($branch,$path) = split_path($revision,$path);
|
($branch,$path) = split_path($revision,$path);
|
||||||
next if not defined $branch;
|
next if not defined $branch;
|
||||||
|
next if not defined $path;
|
||||||
$done{$branch}{$path} = $action;
|
$done{$branch}{$path} = $action;
|
||||||
}
|
}
|
||||||
while(($branch,$changed_paths) = each %done) {
|
while(($branch,$changed_paths) = each %done) {
|
||||||
|
18
git-tag.sh
18
git-tag.sh
@ -47,8 +47,10 @@ do
|
|||||||
-d)
|
-d)
|
||||||
shift
|
shift
|
||||||
tag_name="$1"
|
tag_name="$1"
|
||||||
rm "$GIT_DIR/refs/tags/$tag_name" && \
|
tag=$(git-show-ref --verify --hash -- "refs/tags/$tag_name") ||
|
||||||
echo "Deleted tag $tag_name."
|
die "Seriously, what tag are you talking about?"
|
||||||
|
git-update-ref -m 'tag: delete' -d "refs/tags/$tag_name" "$tag" &&
|
||||||
|
echo "Deleted tag $tag_name."
|
||||||
exit $?
|
exit $?
|
||||||
;;
|
;;
|
||||||
-*)
|
-*)
|
||||||
@ -63,8 +65,11 @@ done
|
|||||||
|
|
||||||
name="$1"
|
name="$1"
|
||||||
[ "$name" ] || usage
|
[ "$name" ] || usage
|
||||||
if [ -e "$GIT_DIR/refs/tags/$name" -a -z "$force" ]; then
|
prev=0000000000000000000000000000000000000000
|
||||||
die "tag '$name' already exists"
|
if git-show-ref --verify --quiet -- "refs/tags/$name"
|
||||||
|
then
|
||||||
|
test -n "$force" || die "tag '$name' already exists"
|
||||||
|
prev=`git rev-parse "refs/tags/$name"`
|
||||||
fi
|
fi
|
||||||
shift
|
shift
|
||||||
git-check-ref-format "tags/$name" ||
|
git-check-ref-format "tags/$name" ||
|
||||||
@ -107,6 +112,5 @@ if [ "$annotate" ]; then
|
|||||||
object=$(git-mktag < "$GIT_DIR"/TAG_TMP)
|
object=$(git-mktag < "$GIT_DIR"/TAG_TMP)
|
||||||
fi
|
fi
|
||||||
|
|
||||||
leading=`expr "refs/tags/$name" : '\(.*\)/'` &&
|
git update-ref "refs/tags/$name" "$object" "$prev"
|
||||||
mkdir -p "$GIT_DIR/$leading" &&
|
|
||||||
echo $object > "$GIT_DIR/refs/tags/$name"
|
|
||||||
|
4
git.c
4
git.c
@ -222,9 +222,11 @@ static void handle_internal_command(int argc, const char **argv, char **envp)
|
|||||||
{ "annotate", cmd_annotate, },
|
{ "annotate", cmd_annotate, },
|
||||||
{ "apply", cmd_apply },
|
{ "apply", cmd_apply },
|
||||||
{ "archive", cmd_archive },
|
{ "archive", cmd_archive },
|
||||||
|
{ "branch", cmd_branch, RUN_SETUP },
|
||||||
{ "cat-file", cmd_cat_file, RUN_SETUP },
|
{ "cat-file", cmd_cat_file, RUN_SETUP },
|
||||||
{ "checkout-index", cmd_checkout_index, RUN_SETUP },
|
{ "checkout-index", cmd_checkout_index, RUN_SETUP },
|
||||||
{ "check-ref-format", cmd_check_ref_format },
|
{ "check-ref-format", cmd_check_ref_format },
|
||||||
|
{ "cherry", cmd_cherry, RUN_SETUP },
|
||||||
{ "commit-tree", cmd_commit_tree, RUN_SETUP },
|
{ "commit-tree", cmd_commit_tree, RUN_SETUP },
|
||||||
{ "count-objects", cmd_count_objects, RUN_SETUP },
|
{ "count-objects", cmd_count_objects, RUN_SETUP },
|
||||||
{ "diff", cmd_diff, RUN_SETUP | USE_PAGER },
|
{ "diff", cmd_diff, RUN_SETUP | USE_PAGER },
|
||||||
@ -269,6 +271,8 @@ static void handle_internal_command(int argc, const char **argv, char **envp)
|
|||||||
{ "whatchanged", cmd_whatchanged, RUN_SETUP | USE_PAGER },
|
{ "whatchanged", cmd_whatchanged, RUN_SETUP | USE_PAGER },
|
||||||
{ "write-tree", cmd_write_tree, RUN_SETUP },
|
{ "write-tree", cmd_write_tree, RUN_SETUP },
|
||||||
{ "verify-pack", cmd_verify_pack },
|
{ "verify-pack", cmd_verify_pack },
|
||||||
|
{ "show-ref", cmd_show_ref, RUN_SETUP },
|
||||||
|
{ "pack-refs", cmd_pack_refs, RUN_SETUP },
|
||||||
};
|
};
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
@ -554,12 +554,17 @@ sub esc_url {
|
|||||||
}
|
}
|
||||||
|
|
||||||
# replace invalid utf8 character with SUBSTITUTION sequence
|
# replace invalid utf8 character with SUBSTITUTION sequence
|
||||||
sub esc_html {
|
sub esc_html ($;%) {
|
||||||
my $str = shift;
|
my $str = shift;
|
||||||
|
my %opts = @_;
|
||||||
|
|
||||||
$str = to_utf8($str);
|
$str = to_utf8($str);
|
||||||
$str = escapeHTML($str);
|
$str = escapeHTML($str);
|
||||||
$str =~ s/\014/^L/g; # escape FORM FEED (FF) character (e.g. in COPYING file)
|
$str =~ s/\014/^L/g; # escape FORM FEED (FF) character (e.g. in COPYING file)
|
||||||
$str =~ s/\033/^[/g; # "escape" ESCAPE (\e) character (e.g. commit 20a3847d8a5032ce41f90dcc68abfb36e6fee9b1)
|
$str =~ s/\033/^[/g; # "escape" ESCAPE (\e) character (e.g. commit 20a3847d8a5032ce41f90dcc68abfb36e6fee9b1)
|
||||||
|
if ($opts{'-nbsp'}) {
|
||||||
|
$str =~ s/ / /g;
|
||||||
|
}
|
||||||
return $str;
|
return $str;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -784,7 +789,7 @@ sub format_diff_line {
|
|||||||
$diff_class = " incomplete";
|
$diff_class = " incomplete";
|
||||||
}
|
}
|
||||||
$line = untabify($line);
|
$line = untabify($line);
|
||||||
return "<div class=\"diff$diff_class\">" . esc_html($line) . "</div>\n";
|
return "<div class=\"diff$diff_class\">" . esc_html($line, -nbsp=>1) . "</div>\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
## ----------------------------------------------------------------------
|
## ----------------------------------------------------------------------
|
||||||
@ -860,7 +865,7 @@ sub git_get_hash_by_path {
|
|||||||
close $fd or return undef;
|
close $fd or return undef;
|
||||||
|
|
||||||
#'100644 blob 0fa3f3a66fb6a137f6ec2c19351ed4d807070ffa panic.c'
|
#'100644 blob 0fa3f3a66fb6a137f6ec2c19351ed4d807070ffa panic.c'
|
||||||
$line =~ m/^([0-9]+) (.+) ([0-9a-fA-F]{40})\t(.+)$/;
|
$line =~ m/^([0-9]+) (.+) ([0-9a-fA-F]{40})\t/;
|
||||||
if (defined $type && $type ne $2) {
|
if (defined $type && $type ne $2) {
|
||||||
# type doesn't match
|
# type doesn't match
|
||||||
return undef;
|
return undef;
|
||||||
@ -1111,7 +1116,9 @@ sub parse_commit {
|
|||||||
@commit_lines = @$commit_text;
|
@commit_lines = @$commit_text;
|
||||||
} else {
|
} else {
|
||||||
local $/ = "\0";
|
local $/ = "\0";
|
||||||
open my $fd, "-|", git_cmd(), "rev-list", "--header", "--parents", "--max-count=1", $commit_id
|
open my $fd, "-|", git_cmd(), "rev-list",
|
||||||
|
"--header", "--parents", "--max-count=1",
|
||||||
|
$commit_id, "--"
|
||||||
or return;
|
or return;
|
||||||
@commit_lines = split '\n', <$fd>;
|
@commit_lines = split '\n', <$fd>;
|
||||||
close $fd or return;
|
close $fd or return;
|
||||||
@ -1275,7 +1282,7 @@ sub parse_ls_tree_line ($;%) {
|
|||||||
my %res;
|
my %res;
|
||||||
|
|
||||||
#'100644 blob 0fa3f3a66fb6a137f6ec2c19351ed4d807070ffa panic.c'
|
#'100644 blob 0fa3f3a66fb6a137f6ec2c19351ed4d807070ffa panic.c'
|
||||||
$line =~ m/^([0-9]+) (.+) ([0-9a-fA-F]{40})\t(.+)$/;
|
$line =~ m/^([0-9]+) (.+) ([0-9a-fA-F]{40})\t(.+)$/s;
|
||||||
|
|
||||||
$res{'mode'} = $1;
|
$res{'mode'} = $1;
|
||||||
$res{'type'} = $2;
|
$res{'type'} = $2;
|
||||||
@ -1292,47 +1299,88 @@ sub parse_ls_tree_line ($;%) {
|
|||||||
## ......................................................................
|
## ......................................................................
|
||||||
## parse to array of hashes functions
|
## parse to array of hashes functions
|
||||||
|
|
||||||
sub git_get_refs_list {
|
sub git_get_heads_list {
|
||||||
my $type = shift || "";
|
my $limit = shift;
|
||||||
my %refs;
|
my @headslist;
|
||||||
my @reflist;
|
|
||||||
|
|
||||||
my @refs;
|
open my $fd, '-|', git_cmd(), 'for-each-ref',
|
||||||
open my $fd, "-|", $GIT, "peek-remote", "$projectroot/$project/"
|
($limit ? '--count='.($limit+1) : ()), '--sort=-committerdate',
|
||||||
|
'--format=%(objectname) %(refname) %(subject)%00%(committer)',
|
||||||
|
'refs/heads'
|
||||||
or return;
|
or return;
|
||||||
while (my $line = <$fd>) {
|
while (my $line = <$fd>) {
|
||||||
chomp $line;
|
my %ref_item;
|
||||||
if ($line =~ m/^([0-9a-fA-F]{40})\trefs\/($type\/?([^\^]+))(\^\{\})?$/) {
|
|
||||||
if (defined $refs{$1}) {
|
|
||||||
push @{$refs{$1}}, $2;
|
|
||||||
} else {
|
|
||||||
$refs{$1} = [ $2 ];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (! $4) { # unpeeled, direct reference
|
chomp $line;
|
||||||
push @refs, { hash => $1, name => $3 }; # without type
|
my ($refinfo, $committerinfo) = split(/\0/, $line);
|
||||||
} elsif ($3 eq $refs[-1]{'name'}) {
|
my ($hash, $name, $title) = split(' ', $refinfo, 3);
|
||||||
# most likely a tag is followed by its peeled
|
my ($committer, $epoch, $tz) =
|
||||||
# (deref) one, and when that happens we know the
|
($committerinfo =~ /^(.*) ([0-9]+) (.*)$/);
|
||||||
# previous one was of type 'tag'.
|
$name =~ s!^refs/heads/!!;
|
||||||
$refs[-1]{'type'} = "tag";
|
|
||||||
}
|
$ref_item{'name'} = $name;
|
||||||
|
$ref_item{'id'} = $hash;
|
||||||
|
$ref_item{'title'} = $title || '(no commit message)';
|
||||||
|
$ref_item{'epoch'} = $epoch;
|
||||||
|
if ($epoch) {
|
||||||
|
$ref_item{'age'} = age_string(time - $ref_item{'epoch'});
|
||||||
|
} else {
|
||||||
|
$ref_item{'age'} = "unknown";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
push @headslist, \%ref_item;
|
||||||
}
|
}
|
||||||
close $fd;
|
close $fd;
|
||||||
|
|
||||||
foreach my $ref (@refs) {
|
return wantarray ? @headslist : \@headslist;
|
||||||
my $ref_file = $ref->{'name'};
|
}
|
||||||
my $ref_id = $ref->{'hash'};
|
|
||||||
|
|
||||||
my $type = $ref->{'type'} || git_get_type($ref_id) || next;
|
sub git_get_tags_list {
|
||||||
my %ref_item = parse_ref($ref_file, $ref_id, $type);
|
my $limit = shift;
|
||||||
|
my @tagslist;
|
||||||
|
|
||||||
push @reflist, \%ref_item;
|
open my $fd, '-|', git_cmd(), 'for-each-ref',
|
||||||
|
($limit ? '--count='.($limit+1) : ()), '--sort=-creatordate',
|
||||||
|
'--format=%(objectname) %(objecttype) %(refname) '.
|
||||||
|
'%(*objectname) %(*objecttype) %(subject)%00%(creator)',
|
||||||
|
'refs/tags'
|
||||||
|
or return;
|
||||||
|
while (my $line = <$fd>) {
|
||||||
|
my %ref_item;
|
||||||
|
|
||||||
|
chomp $line;
|
||||||
|
my ($refinfo, $creatorinfo) = split(/\0/, $line);
|
||||||
|
my ($id, $type, $name, $refid, $reftype, $title) = split(' ', $refinfo, 6);
|
||||||
|
my ($creator, $epoch, $tz) =
|
||||||
|
($creatorinfo =~ /^(.*) ([0-9]+) (.*)$/);
|
||||||
|
$name =~ s!^refs/tags/!!;
|
||||||
|
|
||||||
|
$ref_item{'type'} = $type;
|
||||||
|
$ref_item{'id'} = $id;
|
||||||
|
$ref_item{'name'} = $name;
|
||||||
|
if ($type eq "tag") {
|
||||||
|
$ref_item{'subject'} = $title;
|
||||||
|
$ref_item{'reftype'} = $reftype;
|
||||||
|
$ref_item{'refid'} = $refid;
|
||||||
|
} else {
|
||||||
|
$ref_item{'reftype'} = $type;
|
||||||
|
$ref_item{'refid'} = $id;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($type eq "tag" || $type eq "commit") {
|
||||||
|
$ref_item{'epoch'} = $epoch;
|
||||||
|
if ($epoch) {
|
||||||
|
$ref_item{'age'} = age_string(time - $ref_item{'epoch'});
|
||||||
|
} else {
|
||||||
|
$ref_item{'age'} = "unknown";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
push @tagslist, \%ref_item;
|
||||||
}
|
}
|
||||||
# sort refs by age
|
close $fd;
|
||||||
@reflist = sort {$b->{'epoch'} <=> $a->{'epoch'}} @reflist;
|
|
||||||
return (\@reflist, \%refs);
|
return wantarray ? @tagslist : \@tagslist;
|
||||||
}
|
}
|
||||||
|
|
||||||
## ----------------------------------------------------------------------
|
## ----------------------------------------------------------------------
|
||||||
@ -1943,19 +1991,19 @@ sub git_difftree_body {
|
|||||||
print "</td>\n";
|
print "</td>\n";
|
||||||
print "<td>$mode_chnge</td>\n";
|
print "<td>$mode_chnge</td>\n";
|
||||||
print "<td class=\"link\">";
|
print "<td class=\"link\">";
|
||||||
if ($diff{'to_id'} ne $diff{'from_id'}) { # modified
|
if ($action eq 'commitdiff') {
|
||||||
if ($action eq 'commitdiff') {
|
# link to patch
|
||||||
# link to patch
|
$patchno++;
|
||||||
$patchno++;
|
print $cgi->a({-href => "#patch$patchno"}, "patch") .
|
||||||
print $cgi->a({-href => "#patch$patchno"}, "patch");
|
" | ";
|
||||||
} else {
|
} elsif ($diff{'to_id'} ne $diff{'from_id'}) {
|
||||||
print $cgi->a({-href => href(action=>"blobdiff",
|
# "commit" view and modified file (not onlu mode changed)
|
||||||
hash=>$diff{'to_id'}, hash_parent=>$diff{'from_id'},
|
print $cgi->a({-href => href(action=>"blobdiff",
|
||||||
hash_base=>$hash, hash_parent_base=>$parent,
|
hash=>$diff{'to_id'}, hash_parent=>$diff{'from_id'},
|
||||||
file_name=>$diff{'file'})},
|
hash_base=>$hash, hash_parent_base=>$parent,
|
||||||
"diff");
|
file_name=>$diff{'file'})},
|
||||||
}
|
"diff") .
|
||||||
print " | ";
|
" | ";
|
||||||
}
|
}
|
||||||
print $cgi->a({-href => href(action=>"blob", hash=>$diff{'to_id'},
|
print $cgi->a({-href => href(action=>"blob", hash=>$diff{'to_id'},
|
||||||
hash_base=>$hash, file_name=>$diff{'file'})},
|
hash_base=>$hash, file_name=>$diff{'file'})},
|
||||||
@ -1986,19 +2034,19 @@ sub git_difftree_body {
|
|||||||
-class => "list"}, esc_html($diff{'from_file'})) .
|
-class => "list"}, esc_html($diff{'from_file'})) .
|
||||||
" with " . (int $diff{'similarity'}) . "% similarity$mode_chng]</span></td>\n" .
|
" with " . (int $diff{'similarity'}) . "% similarity$mode_chng]</span></td>\n" .
|
||||||
"<td class=\"link\">";
|
"<td class=\"link\">";
|
||||||
if ($diff{'to_id'} ne $diff{'from_id'}) {
|
if ($action eq 'commitdiff') {
|
||||||
if ($action eq 'commitdiff') {
|
# link to patch
|
||||||
# link to patch
|
$patchno++;
|
||||||
$patchno++;
|
print $cgi->a({-href => "#patch$patchno"}, "patch") .
|
||||||
print $cgi->a({-href => "#patch$patchno"}, "patch");
|
" | ";
|
||||||
} else {
|
} elsif ($diff{'to_id'} ne $diff{'from_id'}) {
|
||||||
print $cgi->a({-href => href(action=>"blobdiff",
|
# "commit" view and modified file (not only pure rename or copy)
|
||||||
hash=>$diff{'to_id'}, hash_parent=>$diff{'from_id'},
|
print $cgi->a({-href => href(action=>"blobdiff",
|
||||||
hash_base=>$hash, hash_parent_base=>$parent,
|
hash=>$diff{'to_id'}, hash_parent=>$diff{'from_id'},
|
||||||
file_name=>$diff{'to_file'}, file_parent=>$diff{'from_file'})},
|
hash_base=>$hash, hash_parent_base=>$parent,
|
||||||
"diff");
|
file_name=>$diff{'to_file'}, file_parent=>$diff{'from_file'})},
|
||||||
}
|
"diff") .
|
||||||
print " | ";
|
" | ";
|
||||||
}
|
}
|
||||||
print $cgi->a({-href => href(action=>"blob", hash=>$diff{'from_id'},
|
print $cgi->a({-href => href(action=>"blob", hash=>$diff{'from_id'},
|
||||||
hash_base=>$parent, file_name=>$diff{'from_file'})},
|
hash_base=>$parent, file_name=>$diff{'from_file'})},
|
||||||
@ -2049,13 +2097,6 @@ sub git_patchset_body {
|
|||||||
}
|
}
|
||||||
$patch_idx++;
|
$patch_idx++;
|
||||||
|
|
||||||
# for now, no extended header, hence we skip empty patches
|
|
||||||
# companion to next LINE if $in_header;
|
|
||||||
if ($diffinfo->{'from_id'} eq $diffinfo->{'to_id'}) { # no change
|
|
||||||
$in_header = 1;
|
|
||||||
next LINE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($diffinfo->{'status'} eq "A") { # added
|
if ($diffinfo->{'status'} eq "A") { # added
|
||||||
print "<div class=\"diff_info\">" . file_type($diffinfo->{'to_mode'}) . ":" .
|
print "<div class=\"diff_info\">" . file_type($diffinfo->{'to_mode'}) . ":" .
|
||||||
$cgi->a({-href => href(action=>"blob", hash_base=>$hash,
|
$cgi->a({-href => href(action=>"blob", hash_base=>$hash,
|
||||||
@ -2262,8 +2303,7 @@ sub git_tags_body {
|
|||||||
for (my $i = $from; $i <= $to; $i++) {
|
for (my $i = $from; $i <= $to; $i++) {
|
||||||
my $entry = $taglist->[$i];
|
my $entry = $taglist->[$i];
|
||||||
my %tag = %$entry;
|
my %tag = %$entry;
|
||||||
my $comment_lines = $tag{'comment'};
|
my $comment = $tag{'subject'};
|
||||||
my $comment = shift @$comment_lines;
|
|
||||||
my $comment_short;
|
my $comment_short;
|
||||||
if (defined $comment) {
|
if (defined $comment) {
|
||||||
$comment_short = chop_str($comment, 30, 5);
|
$comment_short = chop_str($comment, 30, 5);
|
||||||
@ -2296,7 +2336,7 @@ sub git_tags_body {
|
|||||||
$cgi->a({-href => href(action=>$tag{'reftype'}, hash=>$tag{'refid'})}, $tag{'reftype'});
|
$cgi->a({-href => href(action=>$tag{'reftype'}, hash=>$tag{'refid'})}, $tag{'reftype'});
|
||||||
if ($tag{'reftype'} eq "commit") {
|
if ($tag{'reftype'} eq "commit") {
|
||||||
print " | " . $cgi->a({-href => href(action=>"shortlog", hash=>$tag{'name'})}, "shortlog") .
|
print " | " . $cgi->a({-href => href(action=>"shortlog", hash=>$tag{'name'})}, "shortlog") .
|
||||||
" | " . $cgi->a({-href => href(action=>"log", hash=>$tag{'refid'})}, "log");
|
" | " . $cgi->a({-href => href(action=>"log", hash=>$tag{'name'})}, "log");
|
||||||
} elsif ($tag{'reftype'} eq "blob") {
|
} elsif ($tag{'reftype'} eq "blob") {
|
||||||
print " | " . $cgi->a({-href => href(action=>"blob_plain", hash=>$tag{'refid'})}, "raw");
|
print " | " . $cgi->a({-href => href(action=>"blob_plain", hash=>$tag{'refid'})}, "raw");
|
||||||
}
|
}
|
||||||
@ -2321,23 +2361,23 @@ sub git_heads_body {
|
|||||||
my $alternate = 1;
|
my $alternate = 1;
|
||||||
for (my $i = $from; $i <= $to; $i++) {
|
for (my $i = $from; $i <= $to; $i++) {
|
||||||
my $entry = $headlist->[$i];
|
my $entry = $headlist->[$i];
|
||||||
my %tag = %$entry;
|
my %ref = %$entry;
|
||||||
my $curr = $tag{'id'} eq $head;
|
my $curr = $ref{'id'} eq $head;
|
||||||
if ($alternate) {
|
if ($alternate) {
|
||||||
print "<tr class=\"dark\">\n";
|
print "<tr class=\"dark\">\n";
|
||||||
} else {
|
} else {
|
||||||
print "<tr class=\"light\">\n";
|
print "<tr class=\"light\">\n";
|
||||||
}
|
}
|
||||||
$alternate ^= 1;
|
$alternate ^= 1;
|
||||||
print "<td><i>$tag{'age'}</i></td>\n" .
|
print "<td><i>$ref{'age'}</i></td>\n" .
|
||||||
($tag{'id'} eq $head ? "<td class=\"current_head\">" : "<td>") .
|
($curr ? "<td class=\"current_head\">" : "<td>") .
|
||||||
$cgi->a({-href => href(action=>"shortlog", hash=>$tag{'name'}),
|
$cgi->a({-href => href(action=>"shortlog", hash=>$ref{'name'}),
|
||||||
-class => "list name"},esc_html($tag{'name'})) .
|
-class => "list name"},esc_html($ref{'name'})) .
|
||||||
"</td>\n" .
|
"</td>\n" .
|
||||||
"<td class=\"link\">" .
|
"<td class=\"link\">" .
|
||||||
$cgi->a({-href => href(action=>"shortlog", hash=>$tag{'name'})}, "shortlog") . " | " .
|
$cgi->a({-href => href(action=>"shortlog", hash=>$ref{'name'})}, "shortlog") . " | " .
|
||||||
$cgi->a({-href => href(action=>"log", hash=>$tag{'name'})}, "log") . " | " .
|
$cgi->a({-href => href(action=>"log", hash=>$ref{'name'})}, "log") . " | " .
|
||||||
$cgi->a({-href => href(action=>"tree", hash=>$tag{'name'}, hash_base=>$tag{'name'})}, "tree") .
|
$cgi->a({-href => href(action=>"tree", hash=>$ref{'name'}, hash_base=>$ref{'name'})}, "tree") .
|
||||||
"</td>\n" .
|
"</td>\n" .
|
||||||
"</tr>";
|
"</tr>";
|
||||||
}
|
}
|
||||||
@ -2487,18 +2527,9 @@ sub git_summary {
|
|||||||
|
|
||||||
my $owner = git_get_project_owner($project);
|
my $owner = git_get_project_owner($project);
|
||||||
|
|
||||||
my ($reflist, $refs) = git_get_refs_list();
|
my $refs = git_get_references();
|
||||||
|
my @taglist = git_get_tags_list(15);
|
||||||
my @taglist;
|
my @headlist = git_get_heads_list(15);
|
||||||
my @headlist;
|
|
||||||
foreach my $ref (@$reflist) {
|
|
||||||
if ($ref->{'name'} =~ s!^heads/!!) {
|
|
||||||
push @headlist, $ref;
|
|
||||||
} else {
|
|
||||||
$ref->{'name'} =~ s!^tags/!!;
|
|
||||||
push @taglist, $ref;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
git_header_html();
|
git_header_html();
|
||||||
git_print_page_nav('summary','', $head);
|
git_print_page_nav('summary','', $head);
|
||||||
@ -2529,7 +2560,7 @@ sub git_summary {
|
|||||||
}
|
}
|
||||||
|
|
||||||
open my $fd, "-|", git_cmd(), "rev-list", "--max-count=17",
|
open my $fd, "-|", git_cmd(), "rev-list", "--max-count=17",
|
||||||
git_get_head_hash($project)
|
git_get_head_hash($project), "--"
|
||||||
or die_error(undef, "Open git-rev-list failed");
|
or die_error(undef, "Open git-rev-list failed");
|
||||||
my @revlist = map { chomp; $_ } <$fd>;
|
my @revlist = map { chomp; $_ } <$fd>;
|
||||||
close $fd;
|
close $fd;
|
||||||
@ -2659,7 +2690,7 @@ HTML
|
|||||||
print "<tr class=\"$rev_color[$current_color]\">\n";
|
print "<tr class=\"$rev_color[$current_color]\">\n";
|
||||||
if ($group_size) {
|
if ($group_size) {
|
||||||
print "<td class=\"sha1\"";
|
print "<td class=\"sha1\"";
|
||||||
print " title=\"$author, $date\"";
|
print " title=\"". esc_html($author) . ", $date\"";
|
||||||
print " rowspan=\"$group_size\"" if ($group_size > 1);
|
print " rowspan=\"$group_size\"" if ($group_size > 1);
|
||||||
print ">";
|
print ">";
|
||||||
print $cgi->a({-href => href(action=>"commit",
|
print $cgi->a({-href => href(action=>"commit",
|
||||||
@ -2790,9 +2821,9 @@ sub git_tags {
|
|||||||
git_print_page_nav('','', $head,undef,$head);
|
git_print_page_nav('','', $head,undef,$head);
|
||||||
git_print_header_div('summary', $project);
|
git_print_header_div('summary', $project);
|
||||||
|
|
||||||
my ($taglist) = git_get_refs_list("tags");
|
my @tagslist = git_get_tags_list();
|
||||||
if (@$taglist) {
|
if (@tagslist) {
|
||||||
git_tags_body($taglist);
|
git_tags_body(\@tagslist);
|
||||||
}
|
}
|
||||||
git_footer_html();
|
git_footer_html();
|
||||||
}
|
}
|
||||||
@ -2803,9 +2834,9 @@ sub git_heads {
|
|||||||
git_print_page_nav('','', $head,undef,$head);
|
git_print_page_nav('','', $head,undef,$head);
|
||||||
git_print_header_div('summary', $project);
|
git_print_header_div('summary', $project);
|
||||||
|
|
||||||
my ($headlist) = git_get_refs_list("heads");
|
my @headslist = git_get_heads_list();
|
||||||
if (@$headlist) {
|
if (@headslist) {
|
||||||
git_heads_body($headlist, $head);
|
git_heads_body(\@headslist, $head);
|
||||||
}
|
}
|
||||||
git_footer_html();
|
git_footer_html();
|
||||||
}
|
}
|
||||||
@ -2918,7 +2949,7 @@ sub git_blob {
|
|||||||
$nr++;
|
$nr++;
|
||||||
$line = untabify($line);
|
$line = untabify($line);
|
||||||
printf "<div class=\"pre\"><a id=\"l%i\" href=\"#l%i\" class=\"linenr\">%4i</a> %s</div>\n",
|
printf "<div class=\"pre\"><a id=\"l%i\" href=\"#l%i\" class=\"linenr\">%4i</a> %s</div>\n",
|
||||||
$nr, $nr, $nr, esc_html($line);
|
$nr, $nr, $nr, esc_html($line, -nbsp=>1);
|
||||||
}
|
}
|
||||||
close $fd
|
close $fd
|
||||||
or print "Reading blob failed.\n";
|
or print "Reading blob failed.\n";
|
||||||
@ -3072,7 +3103,7 @@ sub git_log {
|
|||||||
my $refs = git_get_references();
|
my $refs = git_get_references();
|
||||||
|
|
||||||
my $limit = sprintf("--max-count=%i", (100 * ($page+1)));
|
my $limit = sprintf("--max-count=%i", (100 * ($page+1)));
|
||||||
open my $fd, "-|", git_cmd(), "rev-list", $limit, $hash
|
open my $fd, "-|", git_cmd(), "rev-list", $limit, $hash, "--"
|
||||||
or die_error(undef, "Open git-rev-list failed");
|
or die_error(undef, "Open git-rev-list failed");
|
||||||
my @revlist = map { chomp; $_ } <$fd>;
|
my @revlist = map { chomp; $_ } <$fd>;
|
||||||
close $fd;
|
close $fd;
|
||||||
@ -3130,7 +3161,7 @@ sub git_commit {
|
|||||||
$parent = "--root";
|
$parent = "--root";
|
||||||
}
|
}
|
||||||
open my $fd, "-|", git_cmd(), "diff-tree", '-r', "--no-commit-id",
|
open my $fd, "-|", git_cmd(), "diff-tree", '-r', "--no-commit-id",
|
||||||
@diff_opts, $parent, $hash
|
@diff_opts, $parent, $hash, "--"
|
||||||
or die_error(undef, "Open git-diff-tree failed");
|
or die_error(undef, "Open git-diff-tree failed");
|
||||||
my @difftree = map { chomp; $_ } <$fd>;
|
my @difftree = map { chomp; $_ } <$fd>;
|
||||||
close $fd or die_error(undef, "Reading git-diff-tree failed");
|
close $fd or die_error(undef, "Reading git-diff-tree failed");
|
||||||
@ -3235,7 +3266,8 @@ sub git_blobdiff {
|
|||||||
if (defined $hash_base && defined $hash_parent_base) {
|
if (defined $hash_base && defined $hash_parent_base) {
|
||||||
if (defined $file_name) {
|
if (defined $file_name) {
|
||||||
# read raw output
|
# read raw output
|
||||||
open $fd, "-|", git_cmd(), "diff-tree", '-r', @diff_opts, $hash_parent_base, $hash_base,
|
open $fd, "-|", git_cmd(), "diff-tree", '-r', @diff_opts,
|
||||||
|
$hash_parent_base, $hash_base,
|
||||||
"--", $file_name
|
"--", $file_name
|
||||||
or die_error(undef, "Open git-diff-tree failed");
|
or die_error(undef, "Open git-diff-tree failed");
|
||||||
@difftree = map { chomp; $_ } <$fd>;
|
@difftree = map { chomp; $_ } <$fd>;
|
||||||
@ -3249,7 +3281,8 @@ sub git_blobdiff {
|
|||||||
# try to find filename from $hash
|
# try to find filename from $hash
|
||||||
|
|
||||||
# read filtered raw output
|
# read filtered raw output
|
||||||
open $fd, "-|", git_cmd(), "diff-tree", '-r', @diff_opts, $hash_parent_base, $hash_base
|
open $fd, "-|", git_cmd(), "diff-tree", '-r', @diff_opts,
|
||||||
|
$hash_parent_base, $hash_base, "--"
|
||||||
or die_error(undef, "Open git-diff-tree failed");
|
or die_error(undef, "Open git-diff-tree failed");
|
||||||
@difftree =
|
@difftree =
|
||||||
# ':100644 100644 03b21826... 3b93d5e7... M ls-files.c'
|
# ':100644 100644 03b21826... 3b93d5e7... M ls-files.c'
|
||||||
@ -3319,7 +3352,8 @@ sub git_blobdiff {
|
|||||||
}
|
}
|
||||||
|
|
||||||
# open patch output
|
# open patch output
|
||||||
open $fd, "-|", git_cmd(), "diff", '-p', @diff_opts, $hash_parent, $hash
|
open $fd, "-|", git_cmd(), "diff", '-p', @diff_opts,
|
||||||
|
$hash_parent, $hash, "--"
|
||||||
or die_error(undef, "Open git-diff failed");
|
or die_error(undef, "Open git-diff failed");
|
||||||
} else {
|
} else {
|
||||||
die_error('404 Not Found', "Missing one of the blob diff parameters")
|
die_error('404 Not Found', "Missing one of the blob diff parameters")
|
||||||
@ -3450,8 +3484,8 @@ sub git_commitdiff {
|
|||||||
my @difftree;
|
my @difftree;
|
||||||
if ($format eq 'html') {
|
if ($format eq 'html') {
|
||||||
open $fd, "-|", git_cmd(), "diff-tree", '-r', @diff_opts,
|
open $fd, "-|", git_cmd(), "diff-tree", '-r', @diff_opts,
|
||||||
"--no-commit-id",
|
"--no-commit-id", "--patch-with-raw", "--full-index",
|
||||||
"--patch-with-raw", "--full-index", $hash_parent, $hash
|
$hash_parent, $hash, "--"
|
||||||
or die_error(undef, "Open git-diff-tree failed");
|
or die_error(undef, "Open git-diff-tree failed");
|
||||||
|
|
||||||
while (chomp(my $line = <$fd>)) {
|
while (chomp(my $line = <$fd>)) {
|
||||||
@ -3462,7 +3496,7 @@ sub git_commitdiff {
|
|||||||
|
|
||||||
} elsif ($format eq 'plain') {
|
} elsif ($format eq 'plain') {
|
||||||
open $fd, "-|", git_cmd(), "diff-tree", '-r', @diff_opts,
|
open $fd, "-|", git_cmd(), "diff-tree", '-r', @diff_opts,
|
||||||
'-p', $hash_parent, $hash
|
'-p', $hash_parent, $hash, "--"
|
||||||
or die_error(undef, "Open git-diff-tree failed");
|
or die_error(undef, "Open git-diff-tree failed");
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
@ -3639,7 +3673,9 @@ sub git_search {
|
|||||||
my $alternate = 1;
|
my $alternate = 1;
|
||||||
if ($searchtype eq 'commit' or $searchtype eq 'author' or $searchtype eq 'committer') {
|
if ($searchtype eq 'commit' or $searchtype eq 'author' or $searchtype eq 'committer') {
|
||||||
$/ = "\0";
|
$/ = "\0";
|
||||||
open my $fd, "-|", git_cmd(), "rev-list", "--header", "--parents", $hash or next;
|
open my $fd, "-|", git_cmd(), "rev-list",
|
||||||
|
"--header", "--parents", $hash, "--"
|
||||||
|
or next;
|
||||||
while (my $commit_text = <$fd>) {
|
while (my $commit_text = <$fd>) {
|
||||||
if (!grep m/$searchtext/i, $commit_text) {
|
if (!grep m/$searchtext/i, $commit_text) {
|
||||||
next;
|
next;
|
||||||
@ -3785,7 +3821,7 @@ sub git_shortlog {
|
|||||||
my $refs = git_get_references();
|
my $refs = git_get_references();
|
||||||
|
|
||||||
my $limit = sprintf("--max-count=%i", (100 * ($page+1)));
|
my $limit = sprintf("--max-count=%i", (100 * ($page+1)));
|
||||||
open my $fd, "-|", git_cmd(), "rev-list", $limit, $hash
|
open my $fd, "-|", git_cmd(), "rev-list", $limit, $hash, "--"
|
||||||
or die_error(undef, "Open git-rev-list failed");
|
or die_error(undef, "Open git-rev-list failed");
|
||||||
my @revlist = map { chomp; $_ } <$fd>;
|
my @revlist = map { chomp; $_ } <$fd>;
|
||||||
close $fd;
|
close $fd;
|
||||||
@ -3813,7 +3849,8 @@ sub git_shortlog {
|
|||||||
|
|
||||||
sub git_rss {
|
sub git_rss {
|
||||||
# http://www.notestips.com/80256B3A007F2692/1/NAMO5P9UPQ
|
# http://www.notestips.com/80256B3A007F2692/1/NAMO5P9UPQ
|
||||||
open my $fd, "-|", git_cmd(), "rev-list", "--max-count=150", git_get_head_hash($project)
|
open my $fd, "-|", git_cmd(), "rev-list", "--max-count=150",
|
||||||
|
git_get_head_hash($project), "--"
|
||||||
or die_error(undef, "Open git-rev-list failed");
|
or die_error(undef, "Open git-rev-list failed");
|
||||||
my @revlist = map { chomp; $_ } <$fd>;
|
my @revlist = map { chomp; $_ } <$fd>;
|
||||||
close $fd or die_error(undef, "Reading git-rev-list failed");
|
close $fd or die_error(undef, "Reading git-rev-list failed");
|
||||||
@ -3837,7 +3874,7 @@ XML
|
|||||||
}
|
}
|
||||||
my %cd = parse_date($co{'committer_epoch'});
|
my %cd = parse_date($co{'committer_epoch'});
|
||||||
open $fd, "-|", git_cmd(), "diff-tree", '-r', @diff_opts,
|
open $fd, "-|", git_cmd(), "diff-tree", '-r', @diff_opts,
|
||||||
$co{'parent'}, $co{'id'}
|
$co{'parent'}, $co{'id'}, "--"
|
||||||
or next;
|
or next;
|
||||||
my @difftree = map { chomp; $_ } <$fd>;
|
my @difftree = map { chomp; $_ } <$fd>;
|
||||||
close $fd
|
close $fd
|
||||||
|
@ -1864,7 +1864,7 @@ static int update_remote(unsigned char *sha1, struct remote_lock *lock)
|
|||||||
static struct ref *local_refs, **local_tail;
|
static struct ref *local_refs, **local_tail;
|
||||||
static struct ref *remote_refs, **remote_tail;
|
static struct ref *remote_refs, **remote_tail;
|
||||||
|
|
||||||
static int one_local_ref(const char *refname, const unsigned char *sha1)
|
static int one_local_ref(const char *refname, const unsigned char *sha1, int flag, void *cb_data)
|
||||||
{
|
{
|
||||||
struct ref *ref;
|
struct ref *ref;
|
||||||
int len = strlen(refname) + 1;
|
int len = strlen(refname) + 1;
|
||||||
@ -1913,7 +1913,7 @@ static void one_remote_ref(char *refname)
|
|||||||
static void get_local_heads(void)
|
static void get_local_heads(void)
|
||||||
{
|
{
|
||||||
local_tail = &local_refs;
|
local_tail = &local_refs;
|
||||||
for_each_ref(one_local_ref);
|
for_each_ref(one_local_ref, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void get_dav_remote_heads(void)
|
static void get_dav_remote_heads(void)
|
||||||
|
@ -272,7 +272,7 @@ buffer_gets( buffer_t * b, char **s )
|
|||||||
n = b->bytes - start;
|
n = b->bytes - start;
|
||||||
|
|
||||||
if (n)
|
if (n)
|
||||||
memcpy( b->buf, b->buf + start, n );
|
memmove(b->buf, b->buf + start, n);
|
||||||
b->offset -= start;
|
b->offset -= start;
|
||||||
b->bytes = n;
|
b->bytes = n;
|
||||||
start = 0;
|
start = 0;
|
||||||
|
26
log-tree.c
26
log-tree.c
@ -252,26 +252,6 @@ int log_tree_diff_flush(struct rev_info *opt)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int diff_root_tree(struct rev_info *opt,
|
|
||||||
const unsigned char *new, const char *base)
|
|
||||||
{
|
|
||||||
int retval;
|
|
||||||
void *tree;
|
|
||||||
struct tree_desc empty, real;
|
|
||||||
|
|
||||||
tree = read_object_with_reference(new, tree_type, &real.size, NULL);
|
|
||||||
if (!tree)
|
|
||||||
die("unable to read root tree (%s)", sha1_to_hex(new));
|
|
||||||
real.buf = tree;
|
|
||||||
|
|
||||||
empty.buf = "";
|
|
||||||
empty.size = 0;
|
|
||||||
retval = diff_tree(&empty, &real, base, &opt->diffopt);
|
|
||||||
free(tree);
|
|
||||||
log_tree_diff_flush(opt);
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int do_diff_combined(struct rev_info *opt, struct commit *commit)
|
static int do_diff_combined(struct rev_info *opt, struct commit *commit)
|
||||||
{
|
{
|
||||||
unsigned const char *sha1 = commit->object.sha1;
|
unsigned const char *sha1 = commit->object.sha1;
|
||||||
@ -297,8 +277,10 @@ static int log_tree_diff(struct rev_info *opt, struct commit *commit, struct log
|
|||||||
/* Root commit? */
|
/* Root commit? */
|
||||||
parents = commit->parents;
|
parents = commit->parents;
|
||||||
if (!parents) {
|
if (!parents) {
|
||||||
if (opt->show_root_diff)
|
if (opt->show_root_diff) {
|
||||||
diff_root_tree(opt, sha1, "");
|
diff_root_tree_sha1(sha1, "", &opt->diffopt);
|
||||||
|
log_tree_diff_flush(opt);
|
||||||
|
}
|
||||||
return !opt->loginfo;
|
return !opt->loginfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
2
quote.c
2
quote.c
@ -209,7 +209,7 @@ static int quote_c_style_counted(const char *name, int namelen,
|
|||||||
if (!ch)
|
if (!ch)
|
||||||
break;
|
break;
|
||||||
if ((ch < ' ') || (ch == '"') || (ch == '\\') ||
|
if ((ch < ' ') || (ch == '"') || (ch == '\\') ||
|
||||||
(ch == 0177)) {
|
(ch >= 0177)) {
|
||||||
needquote = 1;
|
needquote = 1;
|
||||||
switch (ch) {
|
switch (ch) {
|
||||||
case '\a': EMITQ(); ch = 'a'; break;
|
case '\a': EMITQ(); ch = 'a'; break;
|
||||||
|
109
receive-pack.c
109
receive-pack.c
@ -9,12 +9,26 @@ static const char receive_pack_usage[] = "git-receive-pack <git-dir>";
|
|||||||
|
|
||||||
static const char *unpacker[] = { "unpack-objects", NULL };
|
static const char *unpacker[] = { "unpack-objects", NULL };
|
||||||
|
|
||||||
|
static int deny_non_fast_forwards = 0;
|
||||||
static int report_status;
|
static int report_status;
|
||||||
|
|
||||||
static char capabilities[] = "report-status";
|
static char capabilities[] = "report-status";
|
||||||
static int capabilities_sent;
|
static int capabilities_sent;
|
||||||
|
|
||||||
static int show_ref(const char *path, const unsigned char *sha1)
|
static int receive_pack_config(const char *var, const char *value)
|
||||||
|
{
|
||||||
|
git_default_config(var, value);
|
||||||
|
|
||||||
|
if (strcmp(var, "receive.denynonfastforwards") == 0)
|
||||||
|
{
|
||||||
|
deny_non_fast_forwards = git_config_bool(var, value);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int show_ref(const char *path, const unsigned char *sha1, int flag, void *cb_data)
|
||||||
{
|
{
|
||||||
if (capabilities_sent)
|
if (capabilities_sent)
|
||||||
packet_write(1, "%s %s\n", sha1_to_hex(sha1), path);
|
packet_write(1, "%s %s\n", sha1_to_hex(sha1), path);
|
||||||
@ -27,9 +41,9 @@ static int show_ref(const char *path, const unsigned char *sha1)
|
|||||||
|
|
||||||
static void write_head_info(void)
|
static void write_head_info(void)
|
||||||
{
|
{
|
||||||
for_each_ref(show_ref);
|
for_each_ref(show_ref, NULL);
|
||||||
if (!capabilities_sent)
|
if (!capabilities_sent)
|
||||||
show_ref("capabilities^{}", null_sha1);
|
show_ref("capabilities^{}", null_sha1, 0, NULL);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -43,34 +57,6 @@ struct command {
|
|||||||
|
|
||||||
static struct command *commands;
|
static struct command *commands;
|
||||||
|
|
||||||
static int is_all_zeroes(const char *hex)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
for (i = 0; i < 40; i++)
|
|
||||||
if (*hex++ != '0')
|
|
||||||
return 0;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int verify_old_ref(const char *name, char *hex_contents)
|
|
||||||
{
|
|
||||||
int fd, ret;
|
|
||||||
char buffer[60];
|
|
||||||
|
|
||||||
if (is_all_zeroes(hex_contents))
|
|
||||||
return 0;
|
|
||||||
fd = open(name, O_RDONLY);
|
|
||||||
if (fd < 0)
|
|
||||||
return -1;
|
|
||||||
ret = read(fd, buffer, 40);
|
|
||||||
close(fd);
|
|
||||||
if (ret != 40)
|
|
||||||
return -1;
|
|
||||||
if (memcmp(buffer, hex_contents, 40))
|
|
||||||
return -1;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static char update_hook[] = "hooks/update";
|
static char update_hook[] = "hooks/update";
|
||||||
|
|
||||||
static int run_update_hook(const char *refname,
|
static int run_update_hook(const char *refname,
|
||||||
@ -107,8 +93,8 @@ static int update(struct command *cmd)
|
|||||||
const char *name = cmd->ref_name;
|
const char *name = cmd->ref_name;
|
||||||
unsigned char *old_sha1 = cmd->old_sha1;
|
unsigned char *old_sha1 = cmd->old_sha1;
|
||||||
unsigned char *new_sha1 = cmd->new_sha1;
|
unsigned char *new_sha1 = cmd->new_sha1;
|
||||||
char new_hex[60], *old_hex, *lock_name;
|
char new_hex[41], old_hex[41];
|
||||||
int newfd, namelen, written;
|
struct ref_lock *lock;
|
||||||
|
|
||||||
cmd->error_string = NULL;
|
cmd->error_string = NULL;
|
||||||
if (!strncmp(name, "refs/", 5) && check_ref_format(name + 5)) {
|
if (!strncmp(name, "refs/", 5) && check_ref_format(name + 5)) {
|
||||||
@ -117,13 +103,8 @@ static int update(struct command *cmd)
|
|||||||
name);
|
name);
|
||||||
}
|
}
|
||||||
|
|
||||||
namelen = strlen(name);
|
|
||||||
lock_name = xmalloc(namelen + 10);
|
|
||||||
memcpy(lock_name, name, namelen);
|
|
||||||
memcpy(lock_name + namelen, ".lock", 6);
|
|
||||||
|
|
||||||
strcpy(new_hex, sha1_to_hex(new_sha1));
|
strcpy(new_hex, sha1_to_hex(new_sha1));
|
||||||
old_hex = sha1_to_hex(old_sha1);
|
strcpy(old_hex, sha1_to_hex(old_sha1));
|
||||||
if (!has_sha1_file(new_sha1)) {
|
if (!has_sha1_file(new_sha1)) {
|
||||||
cmd->error_string = "bad pack";
|
cmd->error_string = "bad pack";
|
||||||
return error("unpack should have generated %s, "
|
return error("unpack should have generated %s, "
|
||||||
@ -144,47 +125,20 @@ static int update(struct command *cmd)
|
|||||||
return error("denying non-fast forward;"
|
return error("denying non-fast forward;"
|
||||||
" you should pull first");
|
" you should pull first");
|
||||||
}
|
}
|
||||||
safe_create_leading_directories(lock_name);
|
|
||||||
|
|
||||||
newfd = open(lock_name, O_CREAT | O_EXCL | O_WRONLY, 0666);
|
|
||||||
if (newfd < 0) {
|
|
||||||
cmd->error_string = "can't lock";
|
|
||||||
return error("unable to create %s (%s)",
|
|
||||||
lock_name, strerror(errno));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Write the ref with an ending '\n' */
|
|
||||||
new_hex[40] = '\n';
|
|
||||||
new_hex[41] = 0;
|
|
||||||
written = write(newfd, new_hex, 41);
|
|
||||||
/* Remove the '\n' again */
|
|
||||||
new_hex[40] = 0;
|
|
||||||
|
|
||||||
close(newfd);
|
|
||||||
if (written != 41) {
|
|
||||||
unlink(lock_name);
|
|
||||||
cmd->error_string = "can't write";
|
|
||||||
return error("unable to write %s", lock_name);
|
|
||||||
}
|
|
||||||
if (verify_old_ref(name, old_hex) < 0) {
|
|
||||||
unlink(lock_name);
|
|
||||||
cmd->error_string = "raced";
|
|
||||||
return error("%s changed during push", name);
|
|
||||||
}
|
|
||||||
if (run_update_hook(name, old_hex, new_hex)) {
|
if (run_update_hook(name, old_hex, new_hex)) {
|
||||||
unlink(lock_name);
|
|
||||||
cmd->error_string = "hook declined";
|
cmd->error_string = "hook declined";
|
||||||
return error("hook declined to update %s", name);
|
return error("hook declined to update %s", name);
|
||||||
}
|
}
|
||||||
else if (rename(lock_name, name) < 0) {
|
|
||||||
unlink(lock_name);
|
lock = lock_any_ref_for_update(name, old_sha1);
|
||||||
cmd->error_string = "can't rename";
|
if (!lock) {
|
||||||
return error("unable to replace %s", name);
|
cmd->error_string = "failed to lock";
|
||||||
}
|
return error("failed to lock %s", name);
|
||||||
else {
|
|
||||||
fprintf(stderr, "%s: %s -> %s\n", name, old_hex, new_hex);
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
write_ref_sha1(lock, new_sha1, "push");
|
||||||
|
|
||||||
|
fprintf(stderr, "%s: %s -> %s\n", name, old_hex, new_hex);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static char update_post_hook[] = "hooks/post-update";
|
static char update_post_hook[] = "hooks/post-update";
|
||||||
@ -333,9 +287,12 @@ int main(int argc, char **argv)
|
|||||||
if (!dir)
|
if (!dir)
|
||||||
usage(receive_pack_usage);
|
usage(receive_pack_usage);
|
||||||
|
|
||||||
if(!enter_repo(dir, 0))
|
if (!enter_repo(dir, 0))
|
||||||
die("'%s': unable to chdir or not a git archive", dir);
|
die("'%s': unable to chdir or not a git archive", dir);
|
||||||
|
|
||||||
|
setup_ident();
|
||||||
|
git_config(receive_pack_config);
|
||||||
|
|
||||||
write_head_info();
|
write_head_info();
|
||||||
|
|
||||||
/* EOF */
|
/* EOF */
|
||||||
|
612
refs.c
612
refs.c
@ -3,15 +3,193 @@
|
|||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
|
||||||
|
struct ref_list {
|
||||||
|
struct ref_list *next;
|
||||||
|
unsigned char flag; /* ISSYMREF? ISPACKED? */
|
||||||
|
unsigned char sha1[20];
|
||||||
|
char name[FLEX_ARRAY];
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char *parse_ref_line(char *line, unsigned char *sha1)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* 42: the answer to everything.
|
||||||
|
*
|
||||||
|
* In this case, it happens to be the answer to
|
||||||
|
* 40 (length of sha1 hex representation)
|
||||||
|
* +1 (space in between hex and name)
|
||||||
|
* +1 (newline at the end of the line)
|
||||||
|
*/
|
||||||
|
int len = strlen(line) - 42;
|
||||||
|
|
||||||
|
if (len <= 0)
|
||||||
|
return NULL;
|
||||||
|
if (get_sha1_hex(line, sha1) < 0)
|
||||||
|
return NULL;
|
||||||
|
if (!isspace(line[40]))
|
||||||
|
return NULL;
|
||||||
|
line += 41;
|
||||||
|
if (isspace(*line))
|
||||||
|
return NULL;
|
||||||
|
if (line[len] != '\n')
|
||||||
|
return NULL;
|
||||||
|
line[len] = 0;
|
||||||
|
return line;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct ref_list *add_ref(const char *name, const unsigned char *sha1,
|
||||||
|
int flag, struct ref_list *list)
|
||||||
|
{
|
||||||
|
int len;
|
||||||
|
struct ref_list **p = &list, *entry;
|
||||||
|
|
||||||
|
/* Find the place to insert the ref into.. */
|
||||||
|
while ((entry = *p) != NULL) {
|
||||||
|
int cmp = strcmp(entry->name, name);
|
||||||
|
if (cmp > 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* Same as existing entry? */
|
||||||
|
if (!cmp)
|
||||||
|
return list;
|
||||||
|
p = &entry->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Allocate it and add it in.. */
|
||||||
|
len = strlen(name) + 1;
|
||||||
|
entry = xmalloc(sizeof(struct ref_list) + len);
|
||||||
|
hashcpy(entry->sha1, sha1);
|
||||||
|
memcpy(entry->name, name, len);
|
||||||
|
entry->flag = flag;
|
||||||
|
entry->next = *p;
|
||||||
|
*p = entry;
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Future: need to be in "struct repository"
|
||||||
|
* when doing a full libification.
|
||||||
|
*/
|
||||||
|
struct cached_refs {
|
||||||
|
char did_loose;
|
||||||
|
char did_packed;
|
||||||
|
struct ref_list *loose;
|
||||||
|
struct ref_list *packed;
|
||||||
|
} cached_refs;
|
||||||
|
|
||||||
|
static void free_ref_list(struct ref_list *list)
|
||||||
|
{
|
||||||
|
struct ref_list *next;
|
||||||
|
for ( ; list; list = next) {
|
||||||
|
next = list->next;
|
||||||
|
free(list);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void invalidate_cached_refs(void)
|
||||||
|
{
|
||||||
|
struct cached_refs *ca = &cached_refs;
|
||||||
|
|
||||||
|
if (ca->did_loose && ca->loose)
|
||||||
|
free_ref_list(ca->loose);
|
||||||
|
if (ca->did_packed && ca->packed)
|
||||||
|
free_ref_list(ca->packed);
|
||||||
|
ca->loose = ca->packed = NULL;
|
||||||
|
ca->did_loose = ca->did_packed = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct ref_list *get_packed_refs(void)
|
||||||
|
{
|
||||||
|
if (!cached_refs.did_packed) {
|
||||||
|
struct ref_list *refs = NULL;
|
||||||
|
FILE *f = fopen(git_path("packed-refs"), "r");
|
||||||
|
if (f) {
|
||||||
|
struct ref_list *list = NULL;
|
||||||
|
char refline[PATH_MAX];
|
||||||
|
while (fgets(refline, sizeof(refline), f)) {
|
||||||
|
unsigned char sha1[20];
|
||||||
|
const char *name = parse_ref_line(refline, sha1);
|
||||||
|
if (!name)
|
||||||
|
continue;
|
||||||
|
list = add_ref(name, sha1, REF_ISPACKED, list);
|
||||||
|
}
|
||||||
|
fclose(f);
|
||||||
|
refs = list;
|
||||||
|
}
|
||||||
|
cached_refs.packed = refs;
|
||||||
|
cached_refs.did_packed = 1;
|
||||||
|
}
|
||||||
|
return cached_refs.packed;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct ref_list *get_ref_dir(const char *base, struct ref_list *list)
|
||||||
|
{
|
||||||
|
DIR *dir = opendir(git_path("%s", base));
|
||||||
|
|
||||||
|
if (dir) {
|
||||||
|
struct dirent *de;
|
||||||
|
int baselen = strlen(base);
|
||||||
|
char *ref = xmalloc(baselen + 257);
|
||||||
|
|
||||||
|
memcpy(ref, base, baselen);
|
||||||
|
if (baselen && base[baselen-1] != '/')
|
||||||
|
ref[baselen++] = '/';
|
||||||
|
|
||||||
|
while ((de = readdir(dir)) != NULL) {
|
||||||
|
unsigned char sha1[20];
|
||||||
|
struct stat st;
|
||||||
|
int flag;
|
||||||
|
int namelen;
|
||||||
|
|
||||||
|
if (de->d_name[0] == '.')
|
||||||
|
continue;
|
||||||
|
namelen = strlen(de->d_name);
|
||||||
|
if (namelen > 255)
|
||||||
|
continue;
|
||||||
|
if (has_extension(de->d_name, ".lock"))
|
||||||
|
continue;
|
||||||
|
memcpy(ref + baselen, de->d_name, namelen+1);
|
||||||
|
if (stat(git_path("%s", ref), &st) < 0)
|
||||||
|
continue;
|
||||||
|
if (S_ISDIR(st.st_mode)) {
|
||||||
|
list = get_ref_dir(ref, list);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!resolve_ref(ref, sha1, 1, &flag)) {
|
||||||
|
error("%s points nowhere!", ref);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
list = add_ref(ref, sha1, flag, list);
|
||||||
|
}
|
||||||
|
free(ref);
|
||||||
|
closedir(dir);
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct ref_list *get_loose_refs(void)
|
||||||
|
{
|
||||||
|
if (!cached_refs.did_loose) {
|
||||||
|
cached_refs.loose = get_ref_dir("refs", NULL);
|
||||||
|
cached_refs.did_loose = 1;
|
||||||
|
}
|
||||||
|
return cached_refs.loose;
|
||||||
|
}
|
||||||
|
|
||||||
/* We allow "recursive" symbolic refs. Only within reason, though */
|
/* We allow "recursive" symbolic refs. Only within reason, though */
|
||||||
#define MAXDEPTH 5
|
#define MAXDEPTH 5
|
||||||
|
|
||||||
const char *resolve_ref(const char *path, unsigned char *sha1, int reading)
|
const char *resolve_ref(const char *ref, unsigned char *sha1, int reading, int *flag)
|
||||||
{
|
{
|
||||||
int depth = MAXDEPTH, len;
|
int depth = MAXDEPTH, len;
|
||||||
char buffer[256];
|
char buffer[256];
|
||||||
|
static char ref_buffer[256];
|
||||||
|
|
||||||
|
if (flag)
|
||||||
|
*flag = 0;
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
|
const char *path = git_path("%s", ref);
|
||||||
struct stat st;
|
struct stat st;
|
||||||
char *buf;
|
char *buf;
|
||||||
int fd;
|
int fd;
|
||||||
@ -27,17 +205,31 @@ const char *resolve_ref(const char *path, unsigned char *sha1, int reading)
|
|||||||
* reading.
|
* reading.
|
||||||
*/
|
*/
|
||||||
if (lstat(path, &st) < 0) {
|
if (lstat(path, &st) < 0) {
|
||||||
|
struct ref_list *list = get_packed_refs();
|
||||||
|
while (list) {
|
||||||
|
if (!strcmp(ref, list->name)) {
|
||||||
|
hashcpy(sha1, list->sha1);
|
||||||
|
if (flag)
|
||||||
|
*flag |= REF_ISPACKED;
|
||||||
|
return ref;
|
||||||
|
}
|
||||||
|
list = list->next;
|
||||||
|
}
|
||||||
if (reading || errno != ENOENT)
|
if (reading || errno != ENOENT)
|
||||||
return NULL;
|
return NULL;
|
||||||
hashclr(sha1);
|
hashclr(sha1);
|
||||||
return path;
|
return ref;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Follow "normalized" - ie "refs/.." symlinks by hand */
|
/* Follow "normalized" - ie "refs/.." symlinks by hand */
|
||||||
if (S_ISLNK(st.st_mode)) {
|
if (S_ISLNK(st.st_mode)) {
|
||||||
len = readlink(path, buffer, sizeof(buffer)-1);
|
len = readlink(path, buffer, sizeof(buffer)-1);
|
||||||
if (len >= 5 && !memcmp("refs/", buffer, 5)) {
|
if (len >= 5 && !memcmp("refs/", buffer, 5)) {
|
||||||
path = git_path("%.*s", len, buffer);
|
buffer[len] = 0;
|
||||||
|
strcpy(ref_buffer, buffer);
|
||||||
|
ref = ref_buffer;
|
||||||
|
if (flag)
|
||||||
|
*flag |= REF_ISSYMREF;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -68,19 +260,24 @@ const char *resolve_ref(const char *path, unsigned char *sha1, int reading)
|
|||||||
while (len && isspace(*buf))
|
while (len && isspace(*buf))
|
||||||
buf++, len--;
|
buf++, len--;
|
||||||
while (len && isspace(buf[len-1]))
|
while (len && isspace(buf[len-1]))
|
||||||
buf[--len] = 0;
|
len--;
|
||||||
path = git_path("%.*s", len, buf);
|
buf[len] = 0;
|
||||||
|
memcpy(ref_buffer, buf, len + 1);
|
||||||
|
ref = ref_buffer;
|
||||||
|
if (flag)
|
||||||
|
*flag |= REF_ISSYMREF;
|
||||||
}
|
}
|
||||||
if (len < 40 || get_sha1_hex(buffer, sha1))
|
if (len < 40 || get_sha1_hex(buffer, sha1))
|
||||||
return NULL;
|
return NULL;
|
||||||
return path;
|
return ref;
|
||||||
}
|
}
|
||||||
|
|
||||||
int create_symref(const char *git_HEAD, const char *refs_heads_master)
|
int create_symref(const char *ref_target, const char *refs_heads_master)
|
||||||
{
|
{
|
||||||
const char *lockpath;
|
const char *lockpath;
|
||||||
char ref[1000];
|
char ref[1000];
|
||||||
int fd, len, written;
|
int fd, len, written;
|
||||||
|
const char *git_HEAD = git_path("%s", ref_target);
|
||||||
|
|
||||||
#ifndef NO_SYMLINK_HEAD
|
#ifndef NO_SYMLINK_HEAD
|
||||||
if (prefer_symlink_refs) {
|
if (prefer_symlink_refs) {
|
||||||
@ -118,104 +315,101 @@ int create_symref(const char *git_HEAD, const char *refs_heads_master)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int read_ref(const char *filename, unsigned char *sha1)
|
int read_ref(const char *ref, unsigned char *sha1)
|
||||||
{
|
{
|
||||||
if (resolve_ref(filename, sha1, 1))
|
if (resolve_ref(ref, sha1, 1, NULL))
|
||||||
return 0;
|
return 0;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int do_for_each_ref(const char *base, int (*fn)(const char *path, const unsigned char *sha1), int trim)
|
static int do_for_each_ref(const char *base, each_ref_fn fn, int trim,
|
||||||
|
void *cb_data)
|
||||||
{
|
{
|
||||||
int retval = 0;
|
int retval;
|
||||||
DIR *dir = opendir(git_path("%s", base));
|
struct ref_list *packed = get_packed_refs();
|
||||||
|
struct ref_list *loose = get_loose_refs();
|
||||||
|
|
||||||
if (dir) {
|
while (packed && loose) {
|
||||||
struct dirent *de;
|
struct ref_list *entry;
|
||||||
int baselen = strlen(base);
|
int cmp = strcmp(packed->name, loose->name);
|
||||||
char *path = xmalloc(baselen + 257);
|
if (!cmp) {
|
||||||
|
packed = packed->next;
|
||||||
if (!strncmp(base, "./", 2)) {
|
continue;
|
||||||
base += 2;
|
|
||||||
baselen -= 2;
|
|
||||||
}
|
}
|
||||||
memcpy(path, base, baselen);
|
if (cmp > 0) {
|
||||||
if (baselen && base[baselen-1] != '/')
|
entry = loose;
|
||||||
path[baselen++] = '/';
|
loose = loose->next;
|
||||||
|
} else {
|
||||||
while ((de = readdir(dir)) != NULL) {
|
entry = packed;
|
||||||
unsigned char sha1[20];
|
packed = packed->next;
|
||||||
struct stat st;
|
|
||||||
int namelen;
|
|
||||||
|
|
||||||
if (de->d_name[0] == '.')
|
|
||||||
continue;
|
|
||||||
namelen = strlen(de->d_name);
|
|
||||||
if (namelen > 255)
|
|
||||||
continue;
|
|
||||||
if (has_extension(de->d_name, ".lock"))
|
|
||||||
continue;
|
|
||||||
memcpy(path + baselen, de->d_name, namelen+1);
|
|
||||||
if (stat(git_path("%s", path), &st) < 0)
|
|
||||||
continue;
|
|
||||||
if (S_ISDIR(st.st_mode)) {
|
|
||||||
retval = do_for_each_ref(path, fn, trim);
|
|
||||||
if (retval)
|
|
||||||
break;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (read_ref(git_path("%s", path), sha1) < 0) {
|
|
||||||
error("%s points nowhere!", path);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (!has_sha1_file(sha1)) {
|
|
||||||
error("%s does not point to a valid "
|
|
||||||
"commit object!", path);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
retval = fn(path + trim, sha1);
|
|
||||||
if (retval)
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
free(path);
|
if (strncmp(base, entry->name, trim))
|
||||||
closedir(dir);
|
continue;
|
||||||
|
if (is_null_sha1(entry->sha1))
|
||||||
|
continue;
|
||||||
|
if (!has_sha1_file(entry->sha1)) {
|
||||||
|
error("%s does not point to a valid object!", entry->name);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
retval = fn(entry->name + trim, entry->sha1,
|
||||||
|
entry->flag, cb_data);
|
||||||
|
if (retval)
|
||||||
|
return retval;
|
||||||
}
|
}
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
int head_ref(int (*fn)(const char *path, const unsigned char *sha1))
|
packed = packed ? packed : loose;
|
||||||
{
|
while (packed) {
|
||||||
unsigned char sha1[20];
|
if (!strncmp(base, packed->name, trim)) {
|
||||||
if (!read_ref(git_path("HEAD"), sha1))
|
retval = fn(packed->name + trim, packed->sha1,
|
||||||
return fn("HEAD", sha1);
|
packed->flag, cb_data);
|
||||||
|
if (retval)
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
packed = packed->next;
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int for_each_ref(int (*fn)(const char *path, const unsigned char *sha1))
|
int head_ref(each_ref_fn fn, void *cb_data)
|
||||||
{
|
{
|
||||||
return do_for_each_ref("refs", fn, 0);
|
unsigned char sha1[20];
|
||||||
|
int flag;
|
||||||
|
|
||||||
|
if (resolve_ref("HEAD", sha1, 1, &flag))
|
||||||
|
return fn("HEAD", sha1, flag, cb_data);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int for_each_tag_ref(int (*fn)(const char *path, const unsigned char *sha1))
|
int for_each_ref(each_ref_fn fn, void *cb_data)
|
||||||
{
|
{
|
||||||
return do_for_each_ref("refs/tags", fn, 10);
|
return do_for_each_ref("refs/", fn, 0, cb_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
int for_each_branch_ref(int (*fn)(const char *path, const unsigned char *sha1))
|
int for_each_tag_ref(each_ref_fn fn, void *cb_data)
|
||||||
{
|
{
|
||||||
return do_for_each_ref("refs/heads", fn, 11);
|
return do_for_each_ref("refs/tags/", fn, 10, cb_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
int for_each_remote_ref(int (*fn)(const char *path, const unsigned char *sha1))
|
int for_each_branch_ref(each_ref_fn fn, void *cb_data)
|
||||||
{
|
{
|
||||||
return do_for_each_ref("refs/remotes", fn, 13);
|
return do_for_each_ref("refs/heads/", fn, 11, cb_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int for_each_remote_ref(each_ref_fn fn, void *cb_data)
|
||||||
|
{
|
||||||
|
return do_for_each_ref("refs/remotes/", fn, 13, cb_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* NEEDSWORK: This is only used by ssh-upload and it should go; the
|
||||||
|
* caller should do resolve_ref or read_ref like everybody else. Or
|
||||||
|
* maybe everybody else should use get_ref_sha1() instead of doing
|
||||||
|
* read_ref().
|
||||||
|
*/
|
||||||
int get_ref_sha1(const char *ref, unsigned char *sha1)
|
int get_ref_sha1(const char *ref, unsigned char *sha1)
|
||||||
{
|
{
|
||||||
if (check_ref_format(ref))
|
if (check_ref_format(ref))
|
||||||
return -1;
|
return -1;
|
||||||
return read_ref(git_path("refs/%s", ref), sha1);
|
return read_ref(mkpath("refs/%s", ref), sha1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -273,22 +467,13 @@ int check_ref_format(const char *ref)
|
|||||||
static struct ref_lock *verify_lock(struct ref_lock *lock,
|
static struct ref_lock *verify_lock(struct ref_lock *lock,
|
||||||
const unsigned char *old_sha1, int mustexist)
|
const unsigned char *old_sha1, int mustexist)
|
||||||
{
|
{
|
||||||
char buf[40];
|
if (!resolve_ref(lock->ref_name, lock->old_sha1, mustexist, NULL)) {
|
||||||
int nr, fd = open(lock->ref_file, O_RDONLY);
|
error("Can't verify ref %s", lock->ref_name);
|
||||||
if (fd < 0 && (mustexist || errno != ENOENT)) {
|
|
||||||
error("Can't verify ref %s", lock->ref_file);
|
|
||||||
unlock_ref(lock);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
nr = read(fd, buf, 40);
|
|
||||||
close(fd);
|
|
||||||
if (nr != 40 || get_sha1_hex(buf, lock->old_sha1) < 0) {
|
|
||||||
error("Can't verify ref %s", lock->ref_file);
|
|
||||||
unlock_ref(lock);
|
unlock_ref(lock);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
if (hashcmp(lock->old_sha1, old_sha1)) {
|
if (hashcmp(lock->old_sha1, old_sha1)) {
|
||||||
error("Ref %s is at %s but expected %s", lock->ref_file,
|
error("Ref %s is at %s but expected %s", lock->ref_name,
|
||||||
sha1_to_hex(lock->old_sha1), sha1_to_hex(old_sha1));
|
sha1_to_hex(lock->old_sha1), sha1_to_hex(old_sha1));
|
||||||
unlock_ref(lock);
|
unlock_ref(lock);
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -296,54 +481,223 @@ static struct ref_lock *verify_lock(struct ref_lock *lock,
|
|||||||
return lock;
|
return lock;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct ref_lock *lock_ref_sha1_basic(const char *path,
|
static int remove_empty_dir_recursive(char *path, int len)
|
||||||
int plen,
|
|
||||||
const unsigned char *old_sha1, int mustexist)
|
|
||||||
{
|
{
|
||||||
const char *orig_path = path;
|
DIR *dir = opendir(path);
|
||||||
|
struct dirent *e;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
if (!dir)
|
||||||
|
return -1;
|
||||||
|
if (path[len-1] != '/')
|
||||||
|
path[len++] = '/';
|
||||||
|
while ((e = readdir(dir)) != NULL) {
|
||||||
|
struct stat st;
|
||||||
|
int namlen;
|
||||||
|
if ((e->d_name[0] == '.') &&
|
||||||
|
((e->d_name[1] == 0) ||
|
||||||
|
((e->d_name[1] == '.') && e->d_name[2] == 0)))
|
||||||
|
continue; /* "." and ".." */
|
||||||
|
|
||||||
|
namlen = strlen(e->d_name);
|
||||||
|
if ((len + namlen < PATH_MAX) &&
|
||||||
|
strcpy(path + len, e->d_name) &&
|
||||||
|
!lstat(path, &st) &&
|
||||||
|
S_ISDIR(st.st_mode) &&
|
||||||
|
!remove_empty_dir_recursive(path, len + namlen))
|
||||||
|
continue; /* happy */
|
||||||
|
|
||||||
|
/* path too long, stat fails, or non-directory still exists */
|
||||||
|
ret = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
closedir(dir);
|
||||||
|
if (!ret) {
|
||||||
|
path[len] = 0;
|
||||||
|
ret = rmdir(path);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int remove_empty_directories(char *file)
|
||||||
|
{
|
||||||
|
/* we want to create a file but there is a directory there;
|
||||||
|
* if that is an empty directory (or a directory that contains
|
||||||
|
* only empty directories), remove them.
|
||||||
|
*/
|
||||||
|
char path[PATH_MAX];
|
||||||
|
int len = strlen(file);
|
||||||
|
|
||||||
|
if (len >= PATH_MAX) /* path too long ;-) */
|
||||||
|
return -1;
|
||||||
|
strcpy(path, file);
|
||||||
|
return remove_empty_dir_recursive(path, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct ref_lock *lock_ref_sha1_basic(const char *ref, const unsigned char *old_sha1, int *flag)
|
||||||
|
{
|
||||||
|
char *ref_file;
|
||||||
|
const char *orig_ref = ref;
|
||||||
struct ref_lock *lock;
|
struct ref_lock *lock;
|
||||||
struct stat st;
|
struct stat st;
|
||||||
|
int last_errno = 0;
|
||||||
|
int mustexist = (old_sha1 && !is_null_sha1(old_sha1));
|
||||||
|
|
||||||
lock = xcalloc(1, sizeof(struct ref_lock));
|
lock = xcalloc(1, sizeof(struct ref_lock));
|
||||||
lock->lock_fd = -1;
|
lock->lock_fd = -1;
|
||||||
|
|
||||||
plen = strlen(path) - plen;
|
ref = resolve_ref(ref, lock->old_sha1, mustexist, flag);
|
||||||
path = resolve_ref(path, lock->old_sha1, mustexist);
|
if (!ref && errno == EISDIR) {
|
||||||
if (!path) {
|
/* we are trying to lock foo but we used to
|
||||||
int last_errno = errno;
|
* have foo/bar which now does not exist;
|
||||||
error("unable to resolve reference %s: %s",
|
* it is normal for the empty directory 'foo'
|
||||||
orig_path, strerror(errno));
|
* to remain.
|
||||||
unlock_ref(lock);
|
*/
|
||||||
errno = last_errno;
|
ref_file = git_path("%s", orig_ref);
|
||||||
return NULL;
|
if (remove_empty_directories(ref_file)) {
|
||||||
|
last_errno = errno;
|
||||||
|
error("there are still refs under '%s'", orig_ref);
|
||||||
|
goto error_return;
|
||||||
|
}
|
||||||
|
ref = resolve_ref(orig_ref, lock->old_sha1, mustexist, flag);
|
||||||
}
|
}
|
||||||
|
if (!ref) {
|
||||||
|
last_errno = errno;
|
||||||
|
error("unable to resolve reference %s: %s",
|
||||||
|
orig_ref, strerror(errno));
|
||||||
|
goto error_return;
|
||||||
|
}
|
||||||
|
if (is_null_sha1(lock->old_sha1)) {
|
||||||
|
/* The ref did not exist and we are creating it.
|
||||||
|
* Make sure there is no existing ref that is packed
|
||||||
|
* whose name begins with our refname, nor a ref whose
|
||||||
|
* name is a proper prefix of our refname.
|
||||||
|
*/
|
||||||
|
int namlen = strlen(ref); /* e.g. 'foo/bar' */
|
||||||
|
struct ref_list *list = get_packed_refs();
|
||||||
|
while (list) {
|
||||||
|
/* list->name could be 'foo' or 'foo/bar/baz' */
|
||||||
|
int len = strlen(list->name);
|
||||||
|
int cmplen = (namlen < len) ? namlen : len;
|
||||||
|
const char *lead = (namlen < len) ? list->name : ref;
|
||||||
|
|
||||||
|
if (!strncmp(ref, list->name, cmplen) &&
|
||||||
|
lead[cmplen] == '/') {
|
||||||
|
error("'%s' exists; cannot create '%s'",
|
||||||
|
list->name, ref);
|
||||||
|
goto error_return;
|
||||||
|
}
|
||||||
|
list = list->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
lock->lk = xcalloc(1, sizeof(struct lock_file));
|
lock->lk = xcalloc(1, sizeof(struct lock_file));
|
||||||
|
|
||||||
lock->ref_file = xstrdup(path);
|
lock->ref_name = xstrdup(ref);
|
||||||
lock->log_file = xstrdup(git_path("logs/%s", lock->ref_file + plen));
|
lock->log_file = xstrdup(git_path("logs/%s", ref));
|
||||||
lock->force_write = lstat(lock->ref_file, &st) && errno == ENOENT;
|
ref_file = git_path("%s", ref);
|
||||||
|
lock->force_write = lstat(ref_file, &st) && errno == ENOENT;
|
||||||
|
|
||||||
if (safe_create_leading_directories(lock->ref_file))
|
if (safe_create_leading_directories(ref_file)) {
|
||||||
die("unable to create directory for %s", lock->ref_file);
|
last_errno = errno;
|
||||||
lock->lock_fd = hold_lock_file_for_update(lock->lk, lock->ref_file, 1);
|
error("unable to create directory for %s", ref_file);
|
||||||
|
goto error_return;
|
||||||
|
}
|
||||||
|
lock->lock_fd = hold_lock_file_for_update(lock->lk, ref_file, 1);
|
||||||
|
|
||||||
return old_sha1 ? verify_lock(lock, old_sha1, mustexist) : lock;
|
return old_sha1 ? verify_lock(lock, old_sha1, mustexist) : lock;
|
||||||
|
|
||||||
|
error_return:
|
||||||
|
unlock_ref(lock);
|
||||||
|
errno = last_errno;
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ref_lock *lock_ref_sha1(const char *ref,
|
struct ref_lock *lock_ref_sha1(const char *ref, const unsigned char *old_sha1)
|
||||||
const unsigned char *old_sha1, int mustexist)
|
|
||||||
{
|
{
|
||||||
|
char refpath[PATH_MAX];
|
||||||
if (check_ref_format(ref))
|
if (check_ref_format(ref))
|
||||||
return NULL;
|
return NULL;
|
||||||
return lock_ref_sha1_basic(git_path("refs/%s", ref),
|
strcpy(refpath, mkpath("refs/%s", ref));
|
||||||
5 + strlen(ref), old_sha1, mustexist);
|
return lock_ref_sha1_basic(refpath, old_sha1, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ref_lock *lock_any_ref_for_update(const char *ref,
|
struct ref_lock *lock_any_ref_for_update(const char *ref, const unsigned char *old_sha1)
|
||||||
const unsigned char *old_sha1, int mustexist)
|
|
||||||
{
|
{
|
||||||
return lock_ref_sha1_basic(git_path("%s", ref),
|
return lock_ref_sha1_basic(ref, old_sha1, NULL);
|
||||||
strlen(ref), old_sha1, mustexist);
|
}
|
||||||
|
|
||||||
|
static struct lock_file packlock;
|
||||||
|
|
||||||
|
static int repack_without_ref(const char *refname)
|
||||||
|
{
|
||||||
|
struct ref_list *list, *packed_ref_list;
|
||||||
|
int fd;
|
||||||
|
int found = 0;
|
||||||
|
|
||||||
|
packed_ref_list = get_packed_refs();
|
||||||
|
for (list = packed_ref_list; list; list = list->next) {
|
||||||
|
if (!strcmp(refname, list->name)) {
|
||||||
|
found = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!found)
|
||||||
|
return 0;
|
||||||
|
memset(&packlock, 0, sizeof(packlock));
|
||||||
|
fd = hold_lock_file_for_update(&packlock, git_path("packed-refs"), 0);
|
||||||
|
if (fd < 0)
|
||||||
|
return error("cannot delete '%s' from packed refs", refname);
|
||||||
|
|
||||||
|
for (list = packed_ref_list; list; list = list->next) {
|
||||||
|
char line[PATH_MAX + 100];
|
||||||
|
int len;
|
||||||
|
|
||||||
|
if (!strcmp(refname, list->name))
|
||||||
|
continue;
|
||||||
|
len = snprintf(line, sizeof(line), "%s %s\n",
|
||||||
|
sha1_to_hex(list->sha1), list->name);
|
||||||
|
/* this should not happen but just being defensive */
|
||||||
|
if (len > sizeof(line))
|
||||||
|
die("too long a refname '%s'", list->name);
|
||||||
|
write_or_die(fd, line, len);
|
||||||
|
}
|
||||||
|
return commit_lock_file(&packlock);
|
||||||
|
}
|
||||||
|
|
||||||
|
int delete_ref(const char *refname, unsigned char *sha1)
|
||||||
|
{
|
||||||
|
struct ref_lock *lock;
|
||||||
|
int err, i, ret = 0, flag = 0;
|
||||||
|
|
||||||
|
lock = lock_ref_sha1_basic(refname, sha1, &flag);
|
||||||
|
if (!lock)
|
||||||
|
return 1;
|
||||||
|
if (!(flag & REF_ISPACKED)) {
|
||||||
|
/* loose */
|
||||||
|
i = strlen(lock->lk->filename) - 5; /* .lock */
|
||||||
|
lock->lk->filename[i] = 0;
|
||||||
|
err = unlink(lock->lk->filename);
|
||||||
|
if (err) {
|
||||||
|
ret = 1;
|
||||||
|
error("unlink(%s) failed: %s",
|
||||||
|
lock->lk->filename, strerror(errno));
|
||||||
|
}
|
||||||
|
lock->lk->filename[i] = '.';
|
||||||
|
}
|
||||||
|
/* removing the loose one could have resurrected an earlier
|
||||||
|
* packed one. Also, if it was not loose we need to repack
|
||||||
|
* without it.
|
||||||
|
*/
|
||||||
|
ret |= repack_without_ref(refname);
|
||||||
|
|
||||||
|
err = unlink(lock->log_file);
|
||||||
|
if (err && errno != ENOENT)
|
||||||
|
fprintf(stderr, "warning: unlink(%s) failed: %s",
|
||||||
|
lock->log_file, strerror(errno));
|
||||||
|
invalidate_cached_refs();
|
||||||
|
unlock_ref(lock);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void unlock_ref(struct ref_lock *lock)
|
void unlock_ref(struct ref_lock *lock)
|
||||||
@ -354,7 +708,7 @@ void unlock_ref(struct ref_lock *lock)
|
|||||||
if (lock->lk)
|
if (lock->lk)
|
||||||
rollback_lock_file(lock->lk);
|
rollback_lock_file(lock->lk);
|
||||||
}
|
}
|
||||||
free(lock->ref_file);
|
free(lock->ref_name);
|
||||||
free(lock->log_file);
|
free(lock->log_file);
|
||||||
free(lock);
|
free(lock);
|
||||||
}
|
}
|
||||||
@ -367,7 +721,8 @@ static int log_ref_write(struct ref_lock *lock,
|
|||||||
char *logrec;
|
char *logrec;
|
||||||
const char *committer;
|
const char *committer;
|
||||||
|
|
||||||
if (log_all_ref_updates) {
|
if (log_all_ref_updates &&
|
||||||
|
!strncmp(lock->ref_name, "refs/heads/", 11)) {
|
||||||
if (safe_create_leading_directories(lock->log_file) < 0)
|
if (safe_create_leading_directories(lock->log_file) < 0)
|
||||||
return error("unable to create directory for %s",
|
return error("unable to create directory for %s",
|
||||||
lock->log_file);
|
lock->log_file);
|
||||||
@ -376,10 +731,20 @@ static int log_ref_write(struct ref_lock *lock,
|
|||||||
|
|
||||||
logfd = open(lock->log_file, oflags, 0666);
|
logfd = open(lock->log_file, oflags, 0666);
|
||||||
if (logfd < 0) {
|
if (logfd < 0) {
|
||||||
if (!log_all_ref_updates && errno == ENOENT)
|
if (!(oflags & O_CREAT) && errno == ENOENT)
|
||||||
return 0;
|
return 0;
|
||||||
return error("Unable to append to %s: %s",
|
|
||||||
lock->log_file, strerror(errno));
|
if ((oflags & O_CREAT) && errno == EISDIR) {
|
||||||
|
if (remove_empty_directories(lock->log_file)) {
|
||||||
|
return error("There are still logs under '%s'",
|
||||||
|
lock->log_file);
|
||||||
|
}
|
||||||
|
logfd = open(lock->log_file, oflags, 0666);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (logfd < 0)
|
||||||
|
return error("Unable to append to %s: %s",
|
||||||
|
lock->log_file, strerror(errno));
|
||||||
}
|
}
|
||||||
|
|
||||||
committer = git_committer_info(1);
|
committer = git_committer_info(1);
|
||||||
@ -426,12 +791,13 @@ int write_ref_sha1(struct ref_lock *lock,
|
|||||||
unlock_ref(lock);
|
unlock_ref(lock);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
invalidate_cached_refs();
|
||||||
if (log_ref_write(lock, sha1, logmsg) < 0) {
|
if (log_ref_write(lock, sha1, logmsg) < 0) {
|
||||||
unlock_ref(lock);
|
unlock_ref(lock);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (commit_lock_file(lock->lk)) {
|
if (commit_lock_file(lock->lk)) {
|
||||||
error("Couldn't set %s", lock->ref_file);
|
error("Couldn't set %s", lock->ref_name);
|
||||||
unlock_ref(lock);
|
unlock_ref(lock);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -440,7 +806,7 @@ int write_ref_sha1(struct ref_lock *lock,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int read_ref_at(const char *ref, unsigned long at_time, unsigned char *sha1)
|
int read_ref_at(const char *ref, unsigned long at_time, int cnt, unsigned char *sha1)
|
||||||
{
|
{
|
||||||
const char *logfile, *logdata, *logend, *rec, *lastgt, *lastrec;
|
const char *logfile, *logdata, *logend, *rec, *lastgt, *lastrec;
|
||||||
char *tz_c;
|
char *tz_c;
|
||||||
@ -473,7 +839,7 @@ int read_ref_at(const char *ref, unsigned long at_time, unsigned char *sha1)
|
|||||||
if (!lastgt)
|
if (!lastgt)
|
||||||
die("Log %s is corrupt.", logfile);
|
die("Log %s is corrupt.", logfile);
|
||||||
date = strtoul(lastgt + 1, &tz_c, 10);
|
date = strtoul(lastgt + 1, &tz_c, 10);
|
||||||
if (date <= at_time) {
|
if (date <= at_time || cnt == 0) {
|
||||||
if (lastrec) {
|
if (lastrec) {
|
||||||
if (get_sha1_hex(lastrec, logged_sha1))
|
if (get_sha1_hex(lastrec, logged_sha1))
|
||||||
die("Log %s is corrupt.", logfile);
|
die("Log %s is corrupt.", logfile);
|
||||||
@ -504,6 +870,8 @@ int read_ref_at(const char *ref, unsigned long at_time, unsigned char *sha1)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
lastrec = rec;
|
lastrec = rec;
|
||||||
|
if (cnt > 0)
|
||||||
|
cnt--;
|
||||||
}
|
}
|
||||||
|
|
||||||
rec = logdata;
|
rec = logdata;
|
||||||
|
21
refs.h
21
refs.h
@ -2,7 +2,7 @@
|
|||||||
#define REFS_H
|
#define REFS_H
|
||||||
|
|
||||||
struct ref_lock {
|
struct ref_lock {
|
||||||
char *ref_file;
|
char *ref_name;
|
||||||
char *log_file;
|
char *log_file;
|
||||||
struct lock_file *lk;
|
struct lock_file *lk;
|
||||||
unsigned char old_sha1[20];
|
unsigned char old_sha1[20];
|
||||||
@ -14,20 +14,23 @@ struct ref_lock {
|
|||||||
* Calls the specified function for each ref file until it returns nonzero,
|
* Calls the specified function for each ref file until it returns nonzero,
|
||||||
* and returns the value
|
* and returns the value
|
||||||
*/
|
*/
|
||||||
extern int head_ref(int (*fn)(const char *path, const unsigned char *sha1));
|
#define REF_ISSYMREF 01
|
||||||
extern int for_each_ref(int (*fn)(const char *path, const unsigned char *sha1));
|
#define REF_ISPACKED 02
|
||||||
extern int for_each_tag_ref(int (*fn)(const char *path, const unsigned char *sha1));
|
typedef int each_ref_fn(const char *refname, const unsigned char *sha1, int flags, void *cb_data);
|
||||||
extern int for_each_branch_ref(int (*fn)(const char *path, const unsigned char *sha1));
|
extern int head_ref(each_ref_fn, void *);
|
||||||
extern int for_each_remote_ref(int (*fn)(const char *path, const unsigned char *sha1));
|
extern int for_each_ref(each_ref_fn, void *);
|
||||||
|
extern int for_each_tag_ref(each_ref_fn, void *);
|
||||||
|
extern int for_each_branch_ref(each_ref_fn, void *);
|
||||||
|
extern int for_each_remote_ref(each_ref_fn, void *);
|
||||||
|
|
||||||
/** Reads the refs file specified into sha1 **/
|
/** Reads the refs file specified into sha1 **/
|
||||||
extern int get_ref_sha1(const char *ref, unsigned char *sha1);
|
extern int get_ref_sha1(const char *ref, unsigned char *sha1);
|
||||||
|
|
||||||
/** Locks a "refs/" ref returning the lock on success and NULL on failure. **/
|
/** Locks a "refs/" ref returning the lock on success and NULL on failure. **/
|
||||||
extern struct ref_lock *lock_ref_sha1(const char *ref, const unsigned char *old_sha1, int mustexist);
|
extern struct ref_lock *lock_ref_sha1(const char *ref, const unsigned char *old_sha1);
|
||||||
|
|
||||||
/** Locks any ref (for 'HEAD' type refs). */
|
/** Locks any ref (for 'HEAD' type refs). */
|
||||||
extern struct ref_lock *lock_any_ref_for_update(const char *ref, const unsigned char *old_sha1, int mustexist);
|
extern struct ref_lock *lock_any_ref_for_update(const char *ref, const unsigned char *old_sha1);
|
||||||
|
|
||||||
/** Release any lock taken but not written. **/
|
/** Release any lock taken but not written. **/
|
||||||
extern void unlock_ref(struct ref_lock *lock);
|
extern void unlock_ref(struct ref_lock *lock);
|
||||||
@ -36,7 +39,7 @@ extern void unlock_ref(struct ref_lock *lock);
|
|||||||
extern int write_ref_sha1(struct ref_lock *lock, const unsigned char *sha1, const char *msg);
|
extern int write_ref_sha1(struct ref_lock *lock, const unsigned char *sha1, const char *msg);
|
||||||
|
|
||||||
/** Reads log for the value of ref during at_time. **/
|
/** Reads log for the value of ref during at_time. **/
|
||||||
extern int read_ref_at(const char *ref, unsigned long at_time, unsigned char *sha1);
|
extern int read_ref_at(const char *ref, unsigned long at_time, int cnt, unsigned char *sha1);
|
||||||
|
|
||||||
/** Returns 0 if target has the right format for a ref. **/
|
/** Returns 0 if target has the right format for a ref. **/
|
||||||
extern int check_ref_format(const char *target);
|
extern int check_ref_format(const char *target);
|
||||||
|
20
revision.c
20
revision.c
@ -418,9 +418,6 @@ static void limit_list(struct rev_info *revs)
|
|||||||
|
|
||||||
if (revs->max_age != -1 && (commit->date < revs->max_age))
|
if (revs->max_age != -1 && (commit->date < revs->max_age))
|
||||||
obj->flags |= UNINTERESTING;
|
obj->flags |= UNINTERESTING;
|
||||||
if (revs->unpacked &&
|
|
||||||
has_sha1_pack(obj->sha1, revs->ignore_packed))
|
|
||||||
obj->flags |= UNINTERESTING;
|
|
||||||
add_parents_to_list(revs, commit, &list);
|
add_parents_to_list(revs, commit, &list);
|
||||||
if (obj->flags & UNINTERESTING) {
|
if (obj->flags & UNINTERESTING) {
|
||||||
mark_parents_uninteresting(commit);
|
mark_parents_uninteresting(commit);
|
||||||
@ -468,7 +465,7 @@ static void limit_list(struct rev_info *revs)
|
|||||||
static int all_flags;
|
static int all_flags;
|
||||||
static struct rev_info *all_revs;
|
static struct rev_info *all_revs;
|
||||||
|
|
||||||
static int handle_one_ref(const char *path, const unsigned char *sha1)
|
static int handle_one_ref(const char *path, const unsigned char *sha1, int flag, void *cb_data)
|
||||||
{
|
{
|
||||||
struct object *object = get_reference(all_revs, path, sha1, all_flags);
|
struct object *object = get_reference(all_revs, path, sha1, all_flags);
|
||||||
add_pending_object(all_revs, object, "");
|
add_pending_object(all_revs, object, "");
|
||||||
@ -479,7 +476,7 @@ static void handle_all(struct rev_info *revs, unsigned flags)
|
|||||||
{
|
{
|
||||||
all_revs = revs;
|
all_revs = revs;
|
||||||
all_flags = flags;
|
all_flags = flags;
|
||||||
for_each_ref(handle_one_ref);
|
for_each_ref(handle_one_ref, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int add_parents_only(struct rev_info *revs, const char *arg, int flags)
|
static int add_parents_only(struct rev_info *revs, const char *arg, int flags)
|
||||||
@ -1015,7 +1012,7 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch
|
|||||||
add_pending_object(revs, object, def);
|
add_pending_object(revs, object, def);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (revs->topo_order || revs->unpacked)
|
if (revs->topo_order)
|
||||||
revs->limited = 1;
|
revs->limited = 1;
|
||||||
|
|
||||||
if (revs->prune_data) {
|
if (revs->prune_data) {
|
||||||
@ -1149,17 +1146,18 @@ struct commit *get_revision(struct rev_info *revs)
|
|||||||
* that we'd otherwise have done in limit_list().
|
* that we'd otherwise have done in limit_list().
|
||||||
*/
|
*/
|
||||||
if (!revs->limited) {
|
if (!revs->limited) {
|
||||||
if ((revs->unpacked &&
|
if (revs->max_age != -1 &&
|
||||||
has_sha1_pack(commit->object.sha1,
|
(commit->date < revs->max_age))
|
||||||
revs->ignore_packed)) ||
|
|
||||||
(revs->max_age != -1 &&
|
|
||||||
(commit->date < revs->max_age)))
|
|
||||||
continue;
|
continue;
|
||||||
add_parents_to_list(revs, commit, &revs->commits);
|
add_parents_to_list(revs, commit, &revs->commits);
|
||||||
}
|
}
|
||||||
if (commit->object.flags & SHOWN)
|
if (commit->object.flags & SHOWN)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
if (revs->unpacked && has_sha1_pack(commit->object.sha1,
|
||||||
|
revs->ignore_packed))
|
||||||
|
continue;
|
||||||
|
|
||||||
/* We want to show boundary commits only when their
|
/* We want to show boundary commits only when their
|
||||||
* children are shown. When path-limiter is in effect,
|
* children are shown. When path-limiter is in effect,
|
||||||
* rewrite_parents() drops some commits from getting shown,
|
* rewrite_parents() drops some commits from getting shown,
|
||||||
|
@ -215,7 +215,7 @@ static int ref_newer(const unsigned char *new_sha1,
|
|||||||
static struct ref *local_refs, **local_tail;
|
static struct ref *local_refs, **local_tail;
|
||||||
static struct ref *remote_refs, **remote_tail;
|
static struct ref *remote_refs, **remote_tail;
|
||||||
|
|
||||||
static int one_local_ref(const char *refname, const unsigned char *sha1)
|
static int one_local_ref(const char *refname, const unsigned char *sha1, int flag, void *cb_data)
|
||||||
{
|
{
|
||||||
struct ref *ref;
|
struct ref *ref;
|
||||||
int len = strlen(refname) + 1;
|
int len = strlen(refname) + 1;
|
||||||
@ -230,7 +230,7 @@ static int one_local_ref(const char *refname, const unsigned char *sha1)
|
|||||||
static void get_local_heads(void)
|
static void get_local_heads(void)
|
||||||
{
|
{
|
||||||
local_tail = &local_refs;
|
local_tail = &local_refs;
|
||||||
for_each_ref(one_local_ref);
|
for_each_ref(one_local_ref, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int receive_status(int in)
|
static int receive_status(int in)
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
/* refs */
|
/* refs */
|
||||||
static FILE *info_ref_fp;
|
static FILE *info_ref_fp;
|
||||||
|
|
||||||
static int add_info_ref(const char *path, const unsigned char *sha1)
|
static int add_info_ref(const char *path, const unsigned char *sha1, int flag, void *cb_data)
|
||||||
{
|
{
|
||||||
struct object *o = parse_object(sha1);
|
struct object *o = parse_object(sha1);
|
||||||
|
|
||||||
@ -34,7 +34,7 @@ static int update_info_refs(int force)
|
|||||||
info_ref_fp = fopen(path1, "w");
|
info_ref_fp = fopen(path1, "w");
|
||||||
if (!info_ref_fp)
|
if (!info_ref_fp)
|
||||||
return error("unable to update %s", path0);
|
return error("unable to update %s", path0);
|
||||||
for_each_ref(add_info_ref);
|
for_each_ref(add_info_ref, NULL);
|
||||||
fclose(info_ref_fp);
|
fclose(info_ref_fp);
|
||||||
rename(path1, path0);
|
rename(path1, path0);
|
||||||
free(path0);
|
free(path0);
|
||||||
|
2
setup.c
2
setup.c
@ -244,8 +244,6 @@ int check_repository_format_version(const char *var, const char *value)
|
|||||||
repository_format_version = git_config_int(var, value);
|
repository_format_version = git_config_int(var, value);
|
||||||
else if (strcmp(var, "core.sharedrepository") == 0)
|
else if (strcmp(var, "core.sharedrepository") == 0)
|
||||||
shared_repository = git_config_perm(var, value);
|
shared_repository = git_config_perm(var, value);
|
||||||
else if (strcmp(var, "receive.denynonfastforwards") == 0)
|
|
||||||
deny_non_fast_forwards = git_config_bool(var, value);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1417,9 +1417,10 @@ static int link_temp_to_file(const char *tmpfile, const char *filename)
|
|||||||
dir = strrchr(filename, '/');
|
dir = strrchr(filename, '/');
|
||||||
if (dir) {
|
if (dir) {
|
||||||
*dir = 0;
|
*dir = 0;
|
||||||
mkdir(filename, 0777);
|
if (!mkdir(filename, 0777) && adjust_shared_perm(filename)) {
|
||||||
if (adjust_shared_perm(filename))
|
*dir = '/';
|
||||||
return -2;
|
return -2;
|
||||||
|
}
|
||||||
*dir = '/';
|
*dir = '/';
|
||||||
if (!link(tmpfile, filename))
|
if (!link(tmpfile, filename))
|
||||||
return 0;
|
return 0;
|
||||||
|
56
sha1_name.c
56
sha1_name.c
@ -247,26 +247,25 @@ static int get_sha1_basic(const char *str, int len, unsigned char *sha1)
|
|||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
static const char *warning = "warning: refname '%.*s' is ambiguous.\n";
|
static const char *warning = "warning: refname '%.*s' is ambiguous.\n";
|
||||||
const char **p, *pathname;
|
const char **p, *ref;
|
||||||
char *real_path = NULL;
|
char *real_ref = NULL;
|
||||||
int refs_found = 0, am;
|
int refs_found = 0;
|
||||||
unsigned long at_time = (unsigned long)-1;
|
int at, reflog_len;
|
||||||
unsigned char *this_result;
|
unsigned char *this_result;
|
||||||
unsigned char sha1_from_ref[20];
|
unsigned char sha1_from_ref[20];
|
||||||
|
|
||||||
if (len == 40 && !get_sha1_hex(str, sha1))
|
if (len == 40 && !get_sha1_hex(str, sha1))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* At a given period of time? "@{2 hours ago}" */
|
/* basic@{time or number} format to query ref-log */
|
||||||
for (am = 1; am < len - 1; am++) {
|
reflog_len = at = 0;
|
||||||
if (str[am] == '@' && str[am+1] == '{' && str[len-1] == '}') {
|
if (str[len-1] == '}') {
|
||||||
int date_len = len - am - 3;
|
for (at = 1; at < len - 1; at++) {
|
||||||
char *date_spec = xmalloc(date_len + 1);
|
if (str[at] == '@' && str[at+1] == '{') {
|
||||||
strlcpy(date_spec, str + am + 2, date_len + 1);
|
reflog_len = (len-1) - (at+2);
|
||||||
at_time = approxidate(date_spec);
|
len = at;
|
||||||
free(date_spec);
|
break;
|
||||||
len = am;
|
}
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -276,10 +275,10 @@ static int get_sha1_basic(const char *str, int len, unsigned char *sha1)
|
|||||||
|
|
||||||
for (p = fmt; *p; p++) {
|
for (p = fmt; *p; p++) {
|
||||||
this_result = refs_found ? sha1_from_ref : sha1;
|
this_result = refs_found ? sha1_from_ref : sha1;
|
||||||
pathname = resolve_ref(git_path(*p, len, str), this_result, 1);
|
ref = resolve_ref(mkpath(*p, len, str), this_result, 1, NULL);
|
||||||
if (pathname) {
|
if (ref) {
|
||||||
if (!refs_found++)
|
if (!refs_found++)
|
||||||
real_path = xstrdup(pathname);
|
real_ref = xstrdup(ref);
|
||||||
if (!warn_ambiguous_refs)
|
if (!warn_ambiguous_refs)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -291,14 +290,25 @@ static int get_sha1_basic(const char *str, int len, unsigned char *sha1)
|
|||||||
if (warn_ambiguous_refs && refs_found > 1)
|
if (warn_ambiguous_refs && refs_found > 1)
|
||||||
fprintf(stderr, warning, len, str);
|
fprintf(stderr, warning, len, str);
|
||||||
|
|
||||||
if (at_time != (unsigned long)-1) {
|
if (reflog_len) {
|
||||||
read_ref_at(
|
/* Is it asking for N-th entry, or approxidate? */
|
||||||
real_path + strlen(git_path(".")) - 1,
|
int nth, i;
|
||||||
at_time,
|
unsigned long at_time;
|
||||||
sha1);
|
for (i = nth = 0; 0 <= nth && i < reflog_len; i++) {
|
||||||
|
char ch = str[at+2+i];
|
||||||
|
if ('0' <= ch && ch <= '9')
|
||||||
|
nth = nth * 10 + ch - '0';
|
||||||
|
else
|
||||||
|
nth = -1;
|
||||||
|
}
|
||||||
|
if (0 <= nth)
|
||||||
|
at_time = 0;
|
||||||
|
else
|
||||||
|
at_time = approxidate(str + at + 2);
|
||||||
|
read_ref_at(real_ref, at_time, nth, sha1);
|
||||||
}
|
}
|
||||||
|
|
||||||
free(real_path);
|
free(real_ref);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,11 +30,8 @@ rm -f .git/$m
|
|||||||
test_expect_success \
|
test_expect_success \
|
||||||
"fail to create $n" \
|
"fail to create $n" \
|
||||||
"touch .git/$n_dir
|
"touch .git/$n_dir
|
||||||
git-update-ref $n $A >out 2>err
|
git-update-ref $n $A >out 2>err"'
|
||||||
test "'$? = 1 &&
|
test $? != 0'
|
||||||
test "" = "$(cat out)" &&
|
|
||||||
grep "error: unable to resolve reference" err &&
|
|
||||||
grep '"$n err"
|
|
||||||
rm -f .git/$n_dir out err
|
rm -f .git/$n_dir out err
|
||||||
|
|
||||||
test_expect_success \
|
test_expect_success \
|
||||||
|
@ -17,13 +17,10 @@ test_expect_success \
|
|||||||
git-commit -m "Initial commit." &&
|
git-commit -m "Initial commit." &&
|
||||||
HEAD=$(git-rev-parse --verify HEAD)'
|
HEAD=$(git-rev-parse --verify HEAD)'
|
||||||
|
|
||||||
test_expect_success \
|
|
||||||
'git branch --help should return success now.' \
|
|
||||||
'git-branch --help'
|
|
||||||
|
|
||||||
test_expect_failure \
|
test_expect_failure \
|
||||||
'git branch --help should not have created a bogus branch' \
|
'git branch --help should not have created a bogus branch' \
|
||||||
'test -f .git/refs/heads/--help'
|
'git-branch --help </dev/null >/dev/null 2>/dev/null || :
|
||||||
|
test -f .git/refs/heads/--help'
|
||||||
|
|
||||||
test_expect_success \
|
test_expect_success \
|
||||||
'git branch abc should create a branch' \
|
'git branch abc should create a branch' \
|
||||||
@ -34,7 +31,7 @@ test_expect_success \
|
|||||||
'git-branch a/b/c && test -f .git/refs/heads/a/b/c'
|
'git-branch a/b/c && test -f .git/refs/heads/a/b/c'
|
||||||
|
|
||||||
cat >expect <<EOF
|
cat >expect <<EOF
|
||||||
0000000000000000000000000000000000000000 $HEAD $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1117150200 +0000 branch: Created from HEAD
|
0000000000000000000000000000000000000000 $HEAD $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1117150200 +0000 branch: Created from master
|
||||||
EOF
|
EOF
|
||||||
test_expect_success \
|
test_expect_success \
|
||||||
'git branch -l d/e/f should create a branch and a log' \
|
'git branch -l d/e/f should create a branch and a log' \
|
||||||
|
99
t/t3210-pack-refs.sh
Executable file
99
t/t3210-pack-refs.sh
Executable file
@ -0,0 +1,99 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
#
|
||||||
|
# Copyright (c) 2005 Amos Waterland
|
||||||
|
# Copyright (c) 2006 Christian Couder
|
||||||
|
#
|
||||||
|
|
||||||
|
test_description='git pack-refs should not change the branch semantic
|
||||||
|
|
||||||
|
This test runs git pack-refs and git show-ref and checks that the branch
|
||||||
|
semantic is still the same.
|
||||||
|
'
|
||||||
|
. ./test-lib.sh
|
||||||
|
|
||||||
|
echo '[core] logallrefupdates = true' >>.git/config
|
||||||
|
|
||||||
|
test_expect_success \
|
||||||
|
'prepare a trivial repository' \
|
||||||
|
'echo Hello > A &&
|
||||||
|
git-update-index --add A &&
|
||||||
|
git-commit -m "Initial commit." &&
|
||||||
|
HEAD=$(git-rev-parse --verify HEAD)'
|
||||||
|
|
||||||
|
SHA1=
|
||||||
|
|
||||||
|
test_expect_success \
|
||||||
|
'see if git show-ref works as expected' \
|
||||||
|
'git-branch a &&
|
||||||
|
SHA1=`cat .git/refs/heads/a` &&
|
||||||
|
echo "$SHA1 refs/heads/a" >expect &&
|
||||||
|
git-show-ref a >result &&
|
||||||
|
diff expect result'
|
||||||
|
|
||||||
|
test_expect_success \
|
||||||
|
'see if a branch still exists when packed' \
|
||||||
|
'git-branch b &&
|
||||||
|
git-pack-refs --all &&
|
||||||
|
rm .git/refs/heads/b &&
|
||||||
|
echo "$SHA1 refs/heads/b" >expect &&
|
||||||
|
git-show-ref b >result &&
|
||||||
|
diff expect result'
|
||||||
|
|
||||||
|
test_expect_failure \
|
||||||
|
'git branch c/d should barf if branch c exists' \
|
||||||
|
'git-branch c &&
|
||||||
|
git-pack-refs --all &&
|
||||||
|
rm .git/refs/heads/c &&
|
||||||
|
git-branch c/d'
|
||||||
|
|
||||||
|
test_expect_success \
|
||||||
|
'see if a branch still exists after git pack-refs --prune' \
|
||||||
|
'git-branch e &&
|
||||||
|
git-pack-refs --all --prune &&
|
||||||
|
echo "$SHA1 refs/heads/e" >expect &&
|
||||||
|
git-show-ref e >result &&
|
||||||
|
diff expect result'
|
||||||
|
|
||||||
|
test_expect_failure \
|
||||||
|
'see if git pack-refs --prune remove ref files' \
|
||||||
|
'git-branch f &&
|
||||||
|
git-pack-refs --all --prune &&
|
||||||
|
ls .git/refs/heads/f'
|
||||||
|
|
||||||
|
test_expect_success \
|
||||||
|
'git branch g should work when git branch g/h has been deleted' \
|
||||||
|
'git-branch g/h &&
|
||||||
|
git-pack-refs --all --prune &&
|
||||||
|
git-branch -d g/h &&
|
||||||
|
git-branch g &&
|
||||||
|
git-pack-refs --all &&
|
||||||
|
git-branch -d g'
|
||||||
|
|
||||||
|
test_expect_failure \
|
||||||
|
'git branch i/j/k should barf if branch i exists' \
|
||||||
|
'git-branch i &&
|
||||||
|
git-pack-refs --all --prune &&
|
||||||
|
git-branch i/j/k'
|
||||||
|
|
||||||
|
test_expect_success \
|
||||||
|
'test git branch k after branch k/l/m and k/lm have been deleted' \
|
||||||
|
'git-branch k/l &&
|
||||||
|
git-branch k/lm &&
|
||||||
|
git-branch -d k/l &&
|
||||||
|
git-branch k/l/m &&
|
||||||
|
git-branch -d k/l/m &&
|
||||||
|
git-branch -d k/lm &&
|
||||||
|
git-branch k'
|
||||||
|
|
||||||
|
test_expect_success \
|
||||||
|
'test git branch n after some branch deletion and pruning' \
|
||||||
|
'git-branch n/o &&
|
||||||
|
git-branch n/op &&
|
||||||
|
git-branch -d n/o &&
|
||||||
|
git-branch n/o/p &&
|
||||||
|
git-branch -d n/op &&
|
||||||
|
git-pack-refs --all --prune &&
|
||||||
|
git-branch -d n/o/p &&
|
||||||
|
git-branch n'
|
||||||
|
|
||||||
|
test_done
|
18
tree-diff.c
18
tree-diff.c
@ -215,6 +215,24 @@ int diff_tree_sha1(const unsigned char *old, const unsigned char *new, const cha
|
|||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int diff_root_tree_sha1(const unsigned char *new, const char *base, struct diff_options *opt)
|
||||||
|
{
|
||||||
|
int retval;
|
||||||
|
void *tree;
|
||||||
|
struct tree_desc empty, real;
|
||||||
|
|
||||||
|
tree = read_object_with_reference(new, tree_type, &real.size, NULL);
|
||||||
|
if (!tree)
|
||||||
|
die("unable to read root tree (%s)", sha1_to_hex(new));
|
||||||
|
real.buf = tree;
|
||||||
|
|
||||||
|
empty.size = 0;
|
||||||
|
empty.buf = "";
|
||||||
|
retval = diff_tree(&empty, &real, base, opt);
|
||||||
|
free(tree);
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
static int count_paths(const char **paths)
|
static int count_paths(const char **paths)
|
||||||
{
|
{
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
@ -420,7 +420,7 @@ static void receive_needs(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int send_ref(const char *refname, const unsigned char *sha1)
|
static int send_ref(const char *refname, const unsigned char *sha1, int flag, void *cb_data)
|
||||||
{
|
{
|
||||||
static const char *capabilities = "multi_ack thin-pack side-band side-band-64k ofs-delta";
|
static const char *capabilities = "multi_ack thin-pack side-band side-band-64k ofs-delta";
|
||||||
struct object *o = parse_object(sha1);
|
struct object *o = parse_object(sha1);
|
||||||
@ -448,8 +448,8 @@ static int send_ref(const char *refname, const unsigned char *sha1)
|
|||||||
static void upload_pack(void)
|
static void upload_pack(void)
|
||||||
{
|
{
|
||||||
reset_timeout();
|
reset_timeout();
|
||||||
head_ref(send_ref);
|
head_ref(send_ref, NULL);
|
||||||
for_each_ref(send_ref);
|
for_each_ref(send_ref, NULL);
|
||||||
packet_flush(1);
|
packet_flush(1);
|
||||||
receive_needs();
|
receive_needs();
|
||||||
if (want_obj.nr) {
|
if (want_obj.nr) {
|
||||||
|
@ -41,10 +41,8 @@ void wt_status_prepare(struct wt_status *s)
|
|||||||
|
|
||||||
s->is_initial = get_sha1("HEAD", sha1) ? 1 : 0;
|
s->is_initial = get_sha1("HEAD", sha1) ? 1 : 0;
|
||||||
|
|
||||||
head = resolve_ref(git_path("HEAD"), sha1, 0);
|
head = resolve_ref("HEAD", sha1, 0, NULL);
|
||||||
s->branch = head ?
|
s->branch = head ? xstrdup(head) : NULL;
|
||||||
strdup(head + strlen(get_git_dir()) + 1) :
|
|
||||||
NULL;
|
|
||||||
|
|
||||||
s->reference = "HEAD";
|
s->reference = "HEAD";
|
||||||
s->amend = 0;
|
s->amend = 0;
|
||||||
|
Loading…
Reference in New Issue
Block a user