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-pack-redundant
|
||||
git-pack-objects
|
||||
git-pack-refs
|
||||
git-parse-remote
|
||||
git-patch-id
|
||||
git-peek-remote
|
||||
@ -106,6 +107,7 @@ git-shortlog
|
||||
git-show
|
||||
git-show-branch
|
||||
git-show-index
|
||||
git-show-ref
|
||||
git-ssh-fetch
|
||||
git-ssh-pull
|
||||
git-ssh-push
|
||||
|
@ -71,12 +71,16 @@ core.preferSymlinkRefs::
|
||||
expect HEAD to be a symbolic link.
|
||||
|
||||
core.logAllRefUpdates::
|
||||
If true, `git-update-ref` will append a line to
|
||||
"$GIT_DIR/logs/<ref>" listing the new SHA1 and the date/time
|
||||
of the update. If the file does not exist it will be
|
||||
created automatically. 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 logging).
|
||||
Updates to a ref <ref> is logged to the file
|
||||
"$GIT_DIR/logs/<ref>", by appending the new and old
|
||||
SHA1, the date/time and the reason of the update, but
|
||||
only when the file exists. If this configuration
|
||||
variable is set to true, missing "$GIT_DIR/logs/<ref>"
|
||||
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::
|
||||
Internal variable identifying the repository format and layout
|
||||
|
@ -75,6 +75,7 @@ OPTIONS
|
||||
this option is used, neither the `origin` branch nor the
|
||||
default `remotes/origin` file is created.
|
||||
|
||||
--origin <name>::
|
||||
-o <name>::
|
||||
Instead of using the branch name 'origin' to keep track
|
||||
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
|
||||
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
|
||||
|
||||
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 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
|
||||
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.
|
||||
When this option is used, the two files are written in
|
||||
<base-name>-<SHA1>.{pack,idx} files. <SHA1> is a hash
|
||||
of object names (currently in random order so it does
|
||||
not have any useful meaning) to make the resulting
|
||||
filename reasonably unique, and written to the standard
|
||||
of the sorted object names to make the resulting filename
|
||||
based on the pack content, and written to the standard
|
||||
output of the command.
|
||||
|
||||
--stdout::
|
||||
|
@ -3,19 +3,19 @@ git-repo-config(1)
|
||||
|
||||
NAME
|
||||
----
|
||||
git-repo-config - Get and set options in .git/config
|
||||
git-repo-config - Get and set repository or global options.
|
||||
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
[verse]
|
||||
'git-repo-config' [type] name [value [value_regex]]
|
||||
'git-repo-config' [type] --replace-all name [value [value_regex]]
|
||||
'git-repo-config' [type] --get name [value_regex]
|
||||
'git-repo-config' [type] --get-all name [value_regex]
|
||||
'git-repo-config' [type] --unset name [value_regex]
|
||||
'git-repo-config' [type] --unset-all name [value_regex]
|
||||
'git-repo-config' -l | --list
|
||||
'git-repo-config' [--global] [type] name [value [value_regex]]
|
||||
'git-repo-config' [--global] [type] --replace-all name [value [value_regex]]
|
||||
'git-repo-config' [--global] [type] --get name [value_regex]
|
||||
'git-repo-config' [--global] [type] --get-all name [value_regex]
|
||||
'git-repo-config' [--global] [type] --unset name [value_regex]
|
||||
'git-repo-config' [--global] [type] --unset-all name [value_regex]
|
||||
'git-repo-config' [--global] -l | --list
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
@ -41,8 +41,9 @@ This command will fail if:
|
||||
. Can not write to .git/config,
|
||||
. no section was provided,
|
||||
. the section or key is invalid,
|
||||
. you try to unset an option which does not exist, or
|
||||
. you try to unset/set an option for which multiple lines match.
|
||||
. you try to unset an option which does not exist,
|
||||
. you try to unset/set an option for which multiple lines match, or
|
||||
. you use --global option without $HOME being properly set.
|
||||
|
||||
|
||||
OPTIONS
|
||||
@ -64,14 +65,17 @@ OPTIONS
|
||||
--get-regexp::
|
||||
Like --get-all, but interprets the name as a regular expression.
|
||||
|
||||
--global::
|
||||
Use global ~/.gitconfig file rather than the repository .git/config.
|
||||
|
||||
--unset::
|
||||
Remove the line matching the key from .git/config.
|
||||
Remove the line matching the key from config file.
|
||||
|
||||
--unset-all::
|
||||
Remove all matching lines from .git/config.
|
||||
Remove all matching lines from config file.
|
||||
|
||||
-l, --list::
|
||||
List all variables set in .git/config.
|
||||
List all variables set in config file.
|
||||
|
||||
|
||||
ENVIRONMENT
|
||||
@ -79,6 +83,7 @@ ENVIRONMENT
|
||||
|
||||
GIT_CONFIG::
|
||||
Take the configuration from the given file instead of .git/config.
|
||||
Using the "--global" option forces this to ~/.gitconfig.
|
||||
|
||||
GIT_CONFIG_LOCAL::
|
||||
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
|
||||
--------
|
||||
'git-update-ref' [-m <reason>] <ref> <newvalue> [<oldvalue>]
|
||||
'git-update-ref' [-m <reason>] (-d <ref> <oldvalue> | <ref> <newvalue> [<oldvalue>])
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
@ -20,7 +20,9 @@ possibly dereferencing the symbolic refs, after verifying that
|
||||
the current value of the <ref> matches <oldvalue>.
|
||||
E.g. `git-update-ref refs/heads/master <newvalue> <oldvalue>`
|
||||
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
|
||||
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
|
||||
archive by creating a symlink tree).
|
||||
|
||||
With `-d` flag, it deletes the named <ref> after verifying it
|
||||
still contains <oldvalue>.
|
||||
|
||||
|
||||
Logging Updates
|
||||
---------------
|
||||
If config parameter "core.logAllRefUpdates" is true or the file
|
||||
|
11
Makefile
11
Makefile
@ -158,8 +158,8 @@ BASIC_CFLAGS =
|
||||
BASIC_LDFLAGS =
|
||||
|
||||
SCRIPT_SH = \
|
||||
git-bisect.sh git-branch.sh git-checkout.sh \
|
||||
git-cherry.sh git-clean.sh git-clone.sh git-commit.sh \
|
||||
git-bisect.sh git-checkout.sh \
|
||||
git-clean.sh git-clone.sh git-commit.sh \
|
||||
git-fetch.sh \
|
||||
git-ls-remote.sh \
|
||||
git-merge-one-file.sh git-parse-remote.sh \
|
||||
@ -212,7 +212,7 @@ PROGRAMS = \
|
||||
EXTRA_PROGRAMS =
|
||||
|
||||
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 \
|
||||
$(patsubst builtin-%.o,git-%$X,$(BUILTIN_OBJS))
|
||||
|
||||
@ -270,6 +270,7 @@ BUILTIN_OBJS = \
|
||||
builtin-annotate.o \
|
||||
builtin-apply.o \
|
||||
builtin-archive.o \
|
||||
builtin-branch.o \
|
||||
builtin-cat-file.o \
|
||||
builtin-checkout-index.o \
|
||||
builtin-check-ref-format.o \
|
||||
@ -310,7 +311,9 @@ BUILTIN_OBJS = \
|
||||
builtin-update-ref.o \
|
||||
builtin-upload-archive.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)
|
||||
EXTLIBS = -lz
|
||||
|
5
blame.c
5
blame.c
@ -19,7 +19,9 @@
|
||||
#include "xdiff-interface.h"
|
||||
#include "quote.h"
|
||||
|
||||
#ifndef DEBUG
|
||||
#define DEBUG 0
|
||||
#endif
|
||||
|
||||
static const char blame_usage[] =
|
||||
"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;
|
||||
int num;
|
||||
|
||||
if (print_map == NULL)
|
||||
; /* to avoid "unused function" warning */
|
||||
|
||||
for (i = 0; i < max; i++) {
|
||||
printf("i: %d ", i);
|
||||
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;
|
||||
const char *sep = "";
|
||||
unsigned char head_sha1[20];
|
||||
const char *head, *current_branch;
|
||||
const char *current_branch;
|
||||
|
||||
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);
|
||||
|
||||
/* get current branch */
|
||||
head = xstrdup(git_path("HEAD"));
|
||||
current_branch = resolve_ref(head, head_sha1, 1);
|
||||
current_branch += strlen(head) - 4;
|
||||
free((char *)head);
|
||||
current_branch = resolve_ref("HEAD", head_sha1, 1, NULL);
|
||||
if (!strncmp(current_branch, "refs/heads/", 11))
|
||||
current_branch += 11;
|
||||
|
||||
|
@ -59,6 +59,8 @@ static struct {
|
||||
{ "taggername" },
|
||||
{ "taggeremail" },
|
||||
{ "taggerdate", FIELD_TIME },
|
||||
{ "creator" },
|
||||
{ "creatordate", FIELD_TIME },
|
||||
{ "subject" },
|
||||
{ "body" },
|
||||
{ "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"))
|
||||
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)
|
||||
@ -585,24 +610,27 @@ static void get_value(struct refinfo *ref, int atom, struct atom_value **v)
|
||||
*v = &ref->value[atom];
|
||||
}
|
||||
|
||||
static struct refinfo **grab_array;
|
||||
static const char **grab_pattern;
|
||||
static int *grab_cnt;
|
||||
struct grab_ref_cbdata {
|
||||
struct refinfo **grab_array;
|
||||
const char **grab_pattern;
|
||||
int grab_cnt;
|
||||
};
|
||||
|
||||
/*
|
||||
* A call-back given to for_each_ref(). It is unfortunate that we
|
||||
* need to use global variables to pass extra information to this
|
||||
* 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;
|
||||
int cnt;
|
||||
|
||||
if (*grab_pattern) {
|
||||
if (*cb->grab_pattern) {
|
||||
const char **pattern;
|
||||
int namelen = strlen(refname);
|
||||
for (pattern = grab_pattern; *pattern; pattern++) {
|
||||
for (pattern = cb->grab_pattern; *pattern; pattern++) {
|
||||
const char *p = *pattern;
|
||||
int plen = strlen(p);
|
||||
|
||||
@ -626,25 +654,14 @@ static int grab_single_ref(const char *refname, const unsigned char *sha1)
|
||||
ref->refname = xstrdup(refname);
|
||||
hashcpy(ref->objectname, sha1);
|
||||
|
||||
cnt = *grab_cnt;
|
||||
grab_array = xrealloc(grab_array, sizeof(*grab_array) * (cnt + 1));
|
||||
grab_array[cnt++] = ref;
|
||||
*grab_cnt = cnt;
|
||||
cnt = cb->grab_cnt;
|
||||
cb->grab_array = xrealloc(cb->grab_array,
|
||||
sizeof(*cb->grab_array) * (cnt + 1));
|
||||
cb->grab_array[cnt++] = ref;
|
||||
cb->grab_cnt = cnt;
|
||||
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)
|
||||
{
|
||||
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 quote_style = -1; /* unspecified yet */
|
||||
struct refinfo **refs;
|
||||
struct grab_ref_cbdata cbdata;
|
||||
|
||||
for (i = 1; i < ac; 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);
|
||||
|
||||
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++) {
|
||||
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.
|
||||
*/
|
||||
strcpy(path + len, "HEAD");
|
||||
if (read_ref(path, sha1) < 0) {
|
||||
if (create_symref(path, "refs/heads/master") < 0)
|
||||
if (read_ref("HEAD", sha1) < 0) {
|
||||
if (create_symref("HEAD", "refs/heads/master") < 0)
|
||||
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,
|
||||
unsigned char *sha1)
|
||||
{
|
||||
diff_tree_sha1(commit->parents->item->object.sha1, commit->object.sha1,
|
||||
"", options);
|
||||
if (commit->parents)
|
||||
diff_tree_sha1(commit->parents->item->object.sha1,
|
||||
commit->object.sha1, "", options);
|
||||
else
|
||||
diff_root_tree_sha1(commit->object.sha1, "", options);
|
||||
diffcore_std(options);
|
||||
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;
|
||||
}
|
||||
|
||||
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)
|
||||
static int name_ref(const char *path, const unsigned char *sha1, int flags, void *cb_data)
|
||||
{
|
||||
struct object *o = parse_object(sha1);
|
||||
int tags_only = *(int*)cb_data;
|
||||
int deref = 0;
|
||||
|
||||
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 };
|
||||
int as_is = 0, all = 0, transform_stdin = 0;
|
||||
int tags_only = 0;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
for_each_ref(name_ref);
|
||||
for_each_ref(name_ref, &tags_only);
|
||||
|
||||
if (transform_stdin) {
|
||||
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);
|
||||
if (!object)
|
||||
@ -240,7 +240,7 @@ int cmd_prune(int argc, const char **argv, const char *prefix)
|
||||
revs.tree_objects = 1;
|
||||
|
||||
/* 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_cache_refs();
|
||||
|
@ -27,7 +27,7 @@ static void add_refspec(const char *ref)
|
||||
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 */
|
||||
ref += 5;
|
||||
@ -51,7 +51,7 @@ static void expand_refspecs(void)
|
||||
}
|
||||
if (!tags)
|
||||
return;
|
||||
for_each_ref(expand_one_ref);
|
||||
for_each_ref(expand_one_ref, NULL);
|
||||
}
|
||||
|
||||
static void set_refspecs(const char **refs, int nr)
|
||||
|
@ -3,7 +3,7 @@
|
||||
#include <regex.h>
|
||||
|
||||
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 regex_t *key_regexp;
|
||||
@ -139,7 +139,16 @@ int cmd_repo_config(int argc, const char **argv, const char *prefix)
|
||||
type = T_BOOL;
|
||||
else if (!strcmp(argv[1], "--list") || !strcmp(argv[1], "-l"))
|
||||
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;
|
||||
argc--;
|
||||
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);
|
||||
return 0;
|
||||
@ -299,19 +299,19 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(arg, "--all")) {
|
||||
for_each_ref(show_reference);
|
||||
for_each_ref(show_reference, NULL);
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(arg, "--branches")) {
|
||||
for_each_branch_ref(show_reference);
|
||||
for_each_branch_ref(show_reference, NULL);
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(arg, "--tags")) {
|
||||
for_each_tag_ref(show_reference);
|
||||
for_each_tag_ref(show_reference, NULL);
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(arg, "--remotes")) {
|
||||
for_each_remote_ref(show_reference);
|
||||
for_each_remote_ref(show_reference, NULL);
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(arg, "--show-prefix")) {
|
||||
|
@ -346,7 +346,7 @@ static void sort_ref_range(int bottom, int top)
|
||||
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);
|
||||
int i;
|
||||
@ -369,7 +369,7 @@ static int append_ref(const char *refname, const unsigned char *sha1)
|
||||
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];
|
||||
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))
|
||||
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))
|
||||
return 0;
|
||||
return append_ref(refname + 5, sha1);
|
||||
return append_ref(refname + 5, sha1, flag, cb_data);
|
||||
}
|
||||
|
||||
static const char *match_ref_pattern = NULL;
|
||||
@ -401,7 +401,7 @@ static int count_slash(const char *s)
|
||||
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
|
||||
* 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))
|
||||
return 0;
|
||||
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))
|
||||
return append_tag_ref(refname, sha1);
|
||||
return append_ref(refname, sha1);
|
||||
return append_tag_ref(refname, sha1, flag, cb_data);
|
||||
return append_ref(refname, sha1, flag, cb_data);
|
||||
}
|
||||
|
||||
static void snarf_refs(int head, int tag)
|
||||
{
|
||||
if (head) {
|
||||
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);
|
||||
}
|
||||
if (tag) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
int namelen;
|
||||
if ((!head_path[0]) ||
|
||||
if ((!head[0]) ||
|
||||
(head_sha1 && sha1 && hashcmp(head_sha1, sha1)))
|
||||
return 0;
|
||||
namelen = strlen(name);
|
||||
if ((headlen < namelen) ||
|
||||
memcmp(head_path + headlen - namelen, name, namelen))
|
||||
return 0;
|
||||
if (headlen == namelen ||
|
||||
head_path[headlen - namelen - 1] == '/')
|
||||
return 1;
|
||||
return 0;
|
||||
if (!strncmp(head, "refs/heads/", 11))
|
||||
head += 11;
|
||||
if (!strncmp(name, "refs/heads/", 11))
|
||||
name += 11;
|
||||
else if (!strncmp(name, "heads/", 6))
|
||||
name += 6;
|
||||
return !strcmp(head, name);
|
||||
}
|
||||
|
||||
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];
|
||||
if (!get_sha1(av, revkey)) {
|
||||
append_ref(av, revkey);
|
||||
append_ref(av, revkey, 0, NULL);
|
||||
return;
|
||||
}
|
||||
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;
|
||||
match_ref_pattern = 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 &&
|
||||
ref_name_cnt < MAX_REVS)
|
||||
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_mask, all_revs;
|
||||
int lifo = 1;
|
||||
char head_path[128];
|
||||
const char *head_path_p;
|
||||
int head_path_len;
|
||||
char head[128];
|
||||
const char *head_p;
|
||||
int head_len;
|
||||
unsigned char head_sha1[20];
|
||||
int merge_base = 0;
|
||||
int independent = 0;
|
||||
@ -638,31 +636,31 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
|
||||
ac--; av++;
|
||||
}
|
||||
|
||||
head_path_p = resolve_ref(git_path("HEAD"), head_sha1, 1);
|
||||
if (head_path_p) {
|
||||
head_path_len = strlen(head_path_p);
|
||||
memcpy(head_path, head_path_p, head_path_len + 1);
|
||||
head_p = resolve_ref("HEAD", head_sha1, 1, NULL);
|
||||
if (head_p) {
|
||||
head_len = strlen(head_p);
|
||||
memcpy(head, head_p, head_len + 1);
|
||||
}
|
||||
else {
|
||||
head_path_len = 0;
|
||||
head_path[0] = 0;
|
||||
head_len = 0;
|
||||
head[0] = 0;
|
||||
}
|
||||
|
||||
if (with_current_branch && head_path_p) {
|
||||
if (with_current_branch && head_p) {
|
||||
int has_head = 0;
|
||||
for (i = 0; !has_head && i < ref_name_cnt; i++) {
|
||||
/* We are only interested in adding the branch
|
||||
* HEAD points at.
|
||||
*/
|
||||
if (rev_is_head(head_path,
|
||||
head_path_len,
|
||||
if (rev_is_head(head,
|
||||
head_len,
|
||||
ref_name[i],
|
||||
head_sha1, NULL))
|
||||
has_head++;
|
||||
}
|
||||
if (!has_head) {
|
||||
int pfxlen = strlen(git_path("refs/heads/"));
|
||||
append_one_rev(head_path + pfxlen);
|
||||
int pfxlen = strlen("refs/heads/");
|
||||
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) {
|
||||
for (i = 0; i < num_rev; i++) {
|
||||
int j;
|
||||
int is_head = rev_is_head(head_path,
|
||||
head_path_len,
|
||||
int is_head = rev_is_head(head,
|
||||
head_len,
|
||||
ref_name[i],
|
||||
head_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 "cache.h"
|
||||
#include "refs.h"
|
||||
|
||||
static const char git_symbolic_ref_usage[] =
|
||||
"git-symbolic-ref name [ref]";
|
||||
@ -7,15 +8,14 @@ static const char git_symbolic_ref_usage[] =
|
||||
static void check_symref(const char *HEAD)
|
||||
{
|
||||
unsigned char sha1[20];
|
||||
const char *git_HEAD = xstrdup(git_path("%s", HEAD));
|
||||
const char *git_refs_heads_master = resolve_ref(git_HEAD, sha1, 0);
|
||||
if (git_refs_heads_master) {
|
||||
/* we want to strip the .git/ part */
|
||||
int pfxlen = strlen(git_HEAD) - strlen(HEAD);
|
||||
puts(git_refs_heads_master + pfxlen);
|
||||
}
|
||||
else
|
||||
int flag;
|
||||
const char *refs_heads_master = resolve_ref(HEAD, sha1, 0, &flag);
|
||||
|
||||
if (!refs_heads_master)
|
||||
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)
|
||||
@ -26,7 +26,7 @@ int cmd_symbolic_ref(int argc, const char **argv, const char *prefix)
|
||||
check_symref(argv[1]);
|
||||
break;
|
||||
case 3:
|
||||
create_symref(xstrdup(git_path("%s", argv[1])), argv[2]);
|
||||
create_symref(argv[1], argv[2]);
|
||||
break;
|
||||
default:
|
||||
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
|
||||
* return the pointer to the buffer.
|
||||
*/
|
||||
static void * fill(int min)
|
||||
static void *fill(int min)
|
||||
{
|
||||
if (min <= len)
|
||||
return buffer + offset;
|
||||
@ -30,7 +30,7 @@ static void * fill(int min)
|
||||
die("cannot fill %d bytes", min);
|
||||
if (offset) {
|
||||
SHA1_Update(&ctx, buffer, offset);
|
||||
memcpy(buffer, buffer + offset, len);
|
||||
memmove(buffer, buffer + offset, len);
|
||||
offset = 0;
|
||||
}
|
||||
do {
|
||||
|
@ -406,9 +406,9 @@ static int unresolve_one(const char *path)
|
||||
|
||||
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");
|
||||
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");
|
||||
exit(0);
|
||||
}
|
||||
@ -445,7 +445,7 @@ static int do_reupdate(int ac, const char **av,
|
||||
int has_head = 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
|
||||
* commit. Update everything in the index.
|
||||
*/
|
||||
|
@ -3,15 +3,16 @@
|
||||
#include "builtin.h"
|
||||
|
||||
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)
|
||||
{
|
||||
const char *refname=NULL, *value=NULL, *oldval=NULL, *msg=NULL;
|
||||
struct ref_lock *lock;
|
||||
unsigned char sha1[20], oldsha1[20];
|
||||
int i;
|
||||
int i, delete;
|
||||
|
||||
delete = 0;
|
||||
setup_ident();
|
||||
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.");
|
||||
continue;
|
||||
}
|
||||
if (!strcmp("-d", argv[i])) {
|
||||
delete = 1;
|
||||
continue;
|
||||
}
|
||||
if (!refname) {
|
||||
refname = argv[i];
|
||||
continue;
|
||||
@ -44,11 +49,18 @@ int cmd_update_ref(int argc, const char **argv, const char *prefix)
|
||||
|
||||
if (get_sha1(value, sha1))
|
||||
die("%s: not a valid SHA1", value);
|
||||
|
||||
if (delete) {
|
||||
if (oldval)
|
||||
usage(git_update_ref_usage);
|
||||
return delete_ref(refname, sha1);
|
||||
}
|
||||
|
||||
hashclr(oldsha1);
|
||||
if (oldval && get_sha1(oldval, oldsha1))
|
||||
if (oldval && *oldval && get_sha1(oldval, oldsha1))
|
||||
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)
|
||||
return 1;
|
||||
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_apply(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_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_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_count_objects(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_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_show_ref(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_pack_refs(int argc, const char **argv, const char *prefix);
|
||||
|
||||
#endif
|
||||
|
@ -2,7 +2,9 @@
|
||||
#include "tree.h"
|
||||
#include "cache-tree.h"
|
||||
|
||||
#ifndef DEBUG
|
||||
#define DEBUG 0
|
||||
#endif
|
||||
|
||||
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 commit_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 */
|
||||
extern int use_legacy_headers;
|
||||
@ -188,7 +189,6 @@ extern int prefer_symlink_refs;
|
||||
extern int log_all_ref_updates;
|
||||
extern int warn_ambiguous_refs;
|
||||
extern int shared_repository;
|
||||
extern int deny_non_fast_forwards;
|
||||
extern const char *apply_default_whitespace;
|
||||
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 char *sha1_to_hex(const unsigned char *sha1); /* static buffer result! */
|
||||
extern int read_ref(const char *filename, unsigned char *sha1);
|
||||
extern const char *resolve_ref(const char *path, unsigned char *sha1, int);
|
||||
extern int create_symref(const char *git_HEAD, const char *refs_heads_master);
|
||||
extern int validate_symref(const char *git_HEAD);
|
||||
extern const char *resolve_ref(const char *path, unsigned char *sha1, int, int *);
|
||||
extern int create_symref(const char *ref, const char *refs_heads_master);
|
||||
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 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;
|
||||
}
|
||||
|
||||
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 object *object;
|
||||
@ -113,7 +113,7 @@ static void describe(const char *arg, int last_one)
|
||||
|
||||
if (!initialized) {
|
||||
initialized = 1;
|
||||
for_each_ref(get_name);
|
||||
for_each_ref(get_name, NULL);
|
||||
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);
|
||||
extern int diff_tree_sha1(const unsigned char *old, const unsigned char *new,
|
||||
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 *next;
|
||||
|
@ -20,7 +20,6 @@ int warn_ambiguous_refs = 1;
|
||||
int repository_format_version;
|
||||
char git_commit_encoding[MAX_ENCODING_LENGTH] = "utf-8";
|
||||
int shared_repository = PERM_UMASK;
|
||||
int deny_non_fast_forwards = 0;
|
||||
const char *apply_default_whitespace;
|
||||
int zlib_compression_level = Z_DEFAULT_COMPRESSION;
|
||||
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);
|
||||
|
||||
@ -143,7 +143,7 @@ static int find_common(int fd[2], unsigned char *result_sha1,
|
||||
unsigned in_vain = 0;
|
||||
int got_continue = 0;
|
||||
|
||||
for_each_ref(rev_list_insert_ref);
|
||||
for_each_ref(rev_list_insert_ref, NULL);
|
||||
|
||||
fetching = 0;
|
||||
for ( ; refs ; refs = refs->next) {
|
||||
@ -254,7 +254,7 @@ done:
|
||||
|
||||
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);
|
||||
|
||||
@ -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)
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
if (commit) {
|
||||
@ -266,7 +266,7 @@ int pull(int targets, char **target, const char **write_ref,
|
||||
if (!write_ref || !write_ref[i])
|
||||
continue;
|
||||
|
||||
lock[i] = lock_ref_sha1(write_ref[i], NULL, 0);
|
||||
lock[i] = lock_ref_sha1(write_ref[i], NULL);
|
||||
if (!lock[i]) {
|
||||
error("Can't lock ref %s", write_ref[i]);
|
||||
goto unlock_and_fail;
|
||||
@ -274,7 +274,7 @@ int pull(int targets, char **target, const char **write_ref,
|
||||
}
|
||||
|
||||
if (!get_recover)
|
||||
for_each_ref(mark_complete);
|
||||
for_each_ref(mark_complete, NULL);
|
||||
|
||||
for (i = 0; i < targets; 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 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;
|
||||
|
||||
@ -424,7 +424,7 @@ static int fsck_handle_ref(const char *refname, const unsigned char *sha1)
|
||||
|
||||
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
|
||||
@ -458,15 +458,14 @@ static void fsck_object_dir(const char *path)
|
||||
static int fsck_head_link(void)
|
||||
{
|
||||
unsigned char sha1[20];
|
||||
const char *git_HEAD = xstrdup(git_path("HEAD"));
|
||||
const char *git_refs_heads_master = resolve_ref(git_HEAD, sha1, 1);
|
||||
int pfxlen = strlen(git_HEAD) - 4; /* strip .../.git/ part */
|
||||
int flag;
|
||||
const char *head_points_at = resolve_ref("HEAD", sha1, 1, &flag);
|
||||
|
||||
if (!git_refs_heads_master)
|
||||
if (!head_points_at || !(flag & REF_ISSYMREF))
|
||||
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)",
|
||||
git_refs_heads_master + pfxlen);
|
||||
head_points_at);
|
||||
if (is_null_sha1(sha1))
|
||||
return error("HEAD: not a valid git pointer");
|
||||
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
|
||||
[ -z "$newbranch" ] &&
|
||||
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"
|
||||
git-check-ref-format "heads/$newbranch" ||
|
||||
die "git checkout: we do not like '$newbranch' as a branch name."
|
||||
@ -51,7 +51,8 @@ while [ "$#" != "0" ]; do
|
||||
fi
|
||||
new="$rev"
|
||||
new_name="$arg^0"
|
||||
if [ -f "$GIT_DIR/refs/heads/$arg" ]; then
|
||||
if git-show-ref --verify --quiet -- "refs/heads/$arg"
|
||||
then
|
||||
branch="$arg"
|
||||
fi
|
||||
elif rev=$(git-rev-parse --verify "$arg^{tree}" 2>/dev/null)
|
||||
|
@ -441,7 +441,7 @@ then
|
||||
elif test "$use_commit" != ""
|
||||
then
|
||||
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
|
||||
cat "$GIT_DIR/MERGE_MSG"
|
||||
elif test -f "$GIT_DIR/SQUASH_MSG"
|
||||
@ -522,15 +522,15 @@ then
|
||||
PARENTS=$(git-cat-file commit HEAD |
|
||||
sed -n -e '/^$/q' -e 's/^parent /-p /p')
|
||||
fi
|
||||
current=$(git-rev-parse --verify HEAD)
|
||||
current="$(git-rev-parse --verify HEAD)"
|
||||
else
|
||||
if [ -z "$(git-ls-files)" ]; then
|
||||
echo >&2 Nothing to commit
|
||||
exit 1
|
||||
fi
|
||||
PARENTS=""
|
||||
current=
|
||||
rloga='commit (initial)'
|
||||
current=''
|
||||
fi
|
||||
|
||||
if test -z "$no_edit"
|
||||
@ -606,8 +606,8 @@ then
|
||||
fi &&
|
||||
commit=$(cat "$GIT_DIR"/COMMIT_MSG | git-commit-tree $tree $PARENTS) &&
|
||||
rlogm=$(sed -e 1q "$GIT_DIR"/COMMIT_MSG) &&
|
||||
git-update-ref -m "$rloga: $rlogm" HEAD $commit $current &&
|
||||
rm -f -- "$GIT_DIR/MERGE_HEAD" &&
|
||||
git-update-ref -m "$rloga: $rlogm" HEAD $commit "$current" &&
|
||||
rm -f -- "$GIT_DIR/MERGE_HEAD" "$GIT_DIR/MERGE_MSG" &&
|
||||
if test -f "$NEXT_INDEX"
|
||||
then
|
||||
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_"
|
||||
return 0
|
||||
fi
|
||||
oldshort_=$(git-rev-parse --short "$1" 2>/dev/null)
|
||||
mkdir -p "$(dirname "$GIT_DIR/$1")"
|
||||
oldshort_=$(git show-ref --hash --abbrev "$1" 2>/dev/null)
|
||||
|
||||
case "$1" in
|
||||
refs/tags/*)
|
||||
# Tags need not be pointing at commits so there
|
||||
# is no way to guarantee "fast-forward" anyway.
|
||||
if test -f "$GIT_DIR/$1"
|
||||
if test -n "$oldshort_"
|
||||
then
|
||||
if now_=$(cat "$GIT_DIR/$1") && test "$now_" = "$2"
|
||||
if now_=$(git show-ref --hash "$1") && test "$now_" = "$2"
|
||||
then
|
||||
[ "$verbose" ] && echo >&2 "* $1: same as $3"
|
||||
[ "$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' |
|
||||
while read sha1 name
|
||||
do
|
||||
test -f "$GIT_DIR/$name" && continue
|
||||
git-show-ref --verify --quiet -- $name && continue
|
||||
git-check-ref-format "$name" || {
|
||||
echo >&2 "warning: tag ${name} ignored"
|
||||
continue
|
||||
|
@ -145,9 +145,18 @@ git-read-tree -m -u --aggressive $base $head $next &&
|
||||
result=$(git-write-tree 2>/dev/null) || {
|
||||
echo >&2 "Simple $me fails; trying Automatic $me."
|
||||
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 "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
|
||||
cherry-pick)
|
||||
echo >&2 "You may choose to use the following when making"
|
||||
|
@ -31,7 +31,7 @@ $SIG{'PIPE'}="IGNORE";
|
||||
$ENV{'TZ'}="UTC";
|
||||
|
||||
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() {
|
||||
print STDERR <<END;
|
||||
@ -39,17 +39,19 @@ Usage: ${\basename $0} # fetch/update GIT from SVN
|
||||
[-o branch-for-HEAD] [-h] [-v] [-l max_rev]
|
||||
[-C GIT_repository] [-t tagname] [-T trunkname] [-b branchname]
|
||||
[-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
|
||||
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;
|
||||
|
||||
my $tag_name = $opt_t || "tags";
|
||||
my $trunk_name = $opt_T || "trunk";
|
||||
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();
|
||||
|
||||
@ -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($$) {
|
||||
my($rev,$path) = @_;
|
||||
my $branch;
|
||||
@ -446,7 +462,11 @@ sub split_path($$) {
|
||||
print STDERR "$rev: Unrecognized path: $path\n" unless (defined $no_error{$path});
|
||||
return ()
|
||||
}
|
||||
$path = "/" if $path eq "";
|
||||
if ($path eq "") {
|
||||
$path = "/";
|
||||
} elsif ($project_name) {
|
||||
$path = project_path($path, $project_name);
|
||||
}
|
||||
return ($branch,$path);
|
||||
}
|
||||
|
||||
@ -898,6 +918,7 @@ sub commit_all {
|
||||
while(my($path,$action) = each %$changed_paths) {
|
||||
($branch,$path) = split_path($revision,$path);
|
||||
next if not defined $branch;
|
||||
next if not defined $path;
|
||||
$done{$branch}{$path} = $action;
|
||||
}
|
||||
while(($branch,$changed_paths) = each %done) {
|
||||
|
18
git-tag.sh
18
git-tag.sh
@ -47,8 +47,10 @@ do
|
||||
-d)
|
||||
shift
|
||||
tag_name="$1"
|
||||
rm "$GIT_DIR/refs/tags/$tag_name" && \
|
||||
echo "Deleted tag $tag_name."
|
||||
tag=$(git-show-ref --verify --hash -- "refs/tags/$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 $?
|
||||
;;
|
||||
-*)
|
||||
@ -63,8 +65,11 @@ done
|
||||
|
||||
name="$1"
|
||||
[ "$name" ] || usage
|
||||
if [ -e "$GIT_DIR/refs/tags/$name" -a -z "$force" ]; then
|
||||
die "tag '$name' already exists"
|
||||
prev=0000000000000000000000000000000000000000
|
||||
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
|
||||
shift
|
||||
git-check-ref-format "tags/$name" ||
|
||||
@ -107,6 +112,5 @@ if [ "$annotate" ]; then
|
||||
object=$(git-mktag < "$GIT_DIR"/TAG_TMP)
|
||||
fi
|
||||
|
||||
leading=`expr "refs/tags/$name" : '\(.*\)/'` &&
|
||||
mkdir -p "$GIT_DIR/$leading" &&
|
||||
echo $object > "$GIT_DIR/refs/tags/$name"
|
||||
git update-ref "refs/tags/$name" "$object" "$prev"
|
||||
|
||||
|
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, },
|
||||
{ "apply", cmd_apply },
|
||||
{ "archive", cmd_archive },
|
||||
{ "branch", cmd_branch, RUN_SETUP },
|
||||
{ "cat-file", cmd_cat_file, RUN_SETUP },
|
||||
{ "checkout-index", cmd_checkout_index, RUN_SETUP },
|
||||
{ "check-ref-format", cmd_check_ref_format },
|
||||
{ "cherry", cmd_cherry, RUN_SETUP },
|
||||
{ "commit-tree", cmd_commit_tree, RUN_SETUP },
|
||||
{ "count-objects", cmd_count_objects, RUN_SETUP },
|
||||
{ "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 },
|
||||
{ "write-tree", cmd_write_tree, RUN_SETUP },
|
||||
{ "verify-pack", cmd_verify_pack },
|
||||
{ "show-ref", cmd_show_ref, RUN_SETUP },
|
||||
{ "pack-refs", cmd_pack_refs, RUN_SETUP },
|
||||
};
|
||||
int i;
|
||||
|
||||
|
@ -554,12 +554,17 @@ sub esc_url {
|
||||
}
|
||||
|
||||
# replace invalid utf8 character with SUBSTITUTION sequence
|
||||
sub esc_html {
|
||||
sub esc_html ($;%) {
|
||||
my $str = shift;
|
||||
my %opts = @_;
|
||||
|
||||
$str = to_utf8($str);
|
||||
$str = escapeHTML($str);
|
||||
$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)
|
||||
if ($opts{'-nbsp'}) {
|
||||
$str =~ s/ / /g;
|
||||
}
|
||||
return $str;
|
||||
}
|
||||
|
||||
@ -784,7 +789,7 @@ sub format_diff_line {
|
||||
$diff_class = " incomplete";
|
||||
}
|
||||
$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;
|
||||
|
||||
#'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) {
|
||||
# type doesn't match
|
||||
return undef;
|
||||
@ -1111,7 +1116,9 @@ sub parse_commit {
|
||||
@commit_lines = @$commit_text;
|
||||
} else {
|
||||
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;
|
||||
@commit_lines = split '\n', <$fd>;
|
||||
close $fd or return;
|
||||
@ -1275,7 +1282,7 @@ sub parse_ls_tree_line ($;%) {
|
||||
my %res;
|
||||
|
||||
#'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{'type'} = $2;
|
||||
@ -1292,47 +1299,88 @@ sub parse_ls_tree_line ($;%) {
|
||||
## ......................................................................
|
||||
## parse to array of hashes functions
|
||||
|
||||
sub git_get_refs_list {
|
||||
my $type = shift || "";
|
||||
my %refs;
|
||||
my @reflist;
|
||||
sub git_get_heads_list {
|
||||
my $limit = shift;
|
||||
my @headslist;
|
||||
|
||||
my @refs;
|
||||
open my $fd, "-|", $GIT, "peek-remote", "$projectroot/$project/"
|
||||
open my $fd, '-|', git_cmd(), 'for-each-ref',
|
||||
($limit ? '--count='.($limit+1) : ()), '--sort=-committerdate',
|
||||
'--format=%(objectname) %(refname) %(subject)%00%(committer)',
|
||||
'refs/heads'
|
||||
or return;
|
||||
while (my $line = <$fd>) {
|
||||
chomp $line;
|
||||
if ($line =~ m/^([0-9a-fA-F]{40})\trefs\/($type\/?([^\^]+))(\^\{\})?$/) {
|
||||
if (defined $refs{$1}) {
|
||||
push @{$refs{$1}}, $2;
|
||||
} else {
|
||||
$refs{$1} = [ $2 ];
|
||||
}
|
||||
my %ref_item;
|
||||
|
||||
if (! $4) { # unpeeled, direct reference
|
||||
push @refs, { hash => $1, name => $3 }; # without type
|
||||
} elsif ($3 eq $refs[-1]{'name'}) {
|
||||
# most likely a tag is followed by its peeled
|
||||
# (deref) one, and when that happens we know the
|
||||
# previous one was of type 'tag'.
|
||||
$refs[-1]{'type'} = "tag";
|
||||
}
|
||||
chomp $line;
|
||||
my ($refinfo, $committerinfo) = split(/\0/, $line);
|
||||
my ($hash, $name, $title) = split(' ', $refinfo, 3);
|
||||
my ($committer, $epoch, $tz) =
|
||||
($committerinfo =~ /^(.*) ([0-9]+) (.*)$/);
|
||||
$name =~ s!^refs/heads/!!;
|
||||
|
||||
$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;
|
||||
|
||||
foreach my $ref (@refs) {
|
||||
my $ref_file = $ref->{'name'};
|
||||
my $ref_id = $ref->{'hash'};
|
||||
return wantarray ? @headslist : \@headslist;
|
||||
}
|
||||
|
||||
my $type = $ref->{'type'} || git_get_type($ref_id) || next;
|
||||
my %ref_item = parse_ref($ref_file, $ref_id, $type);
|
||||
sub git_get_tags_list {
|
||||
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
|
||||
@reflist = sort {$b->{'epoch'} <=> $a->{'epoch'}} @reflist;
|
||||
return (\@reflist, \%refs);
|
||||
close $fd;
|
||||
|
||||
return wantarray ? @tagslist : \@tagslist;
|
||||
}
|
||||
|
||||
## ----------------------------------------------------------------------
|
||||
@ -1943,19 +1991,19 @@ sub git_difftree_body {
|
||||
print "</td>\n";
|
||||
print "<td>$mode_chnge</td>\n";
|
||||
print "<td class=\"link\">";
|
||||
if ($diff{'to_id'} ne $diff{'from_id'}) { # modified
|
||||
if ($action eq 'commitdiff') {
|
||||
# link to patch
|
||||
$patchno++;
|
||||
print $cgi->a({-href => "#patch$patchno"}, "patch");
|
||||
} else {
|
||||
print $cgi->a({-href => href(action=>"blobdiff",
|
||||
hash=>$diff{'to_id'}, hash_parent=>$diff{'from_id'},
|
||||
hash_base=>$hash, hash_parent_base=>$parent,
|
||||
file_name=>$diff{'file'})},
|
||||
"diff");
|
||||
}
|
||||
print " | ";
|
||||
if ($action eq 'commitdiff') {
|
||||
# link to patch
|
||||
$patchno++;
|
||||
print $cgi->a({-href => "#patch$patchno"}, "patch") .
|
||||
" | ";
|
||||
} elsif ($diff{'to_id'} ne $diff{'from_id'}) {
|
||||
# "commit" view and modified file (not onlu mode changed)
|
||||
print $cgi->a({-href => href(action=>"blobdiff",
|
||||
hash=>$diff{'to_id'}, hash_parent=>$diff{'from_id'},
|
||||
hash_base=>$hash, hash_parent_base=>$parent,
|
||||
file_name=>$diff{'file'})},
|
||||
"diff") .
|
||||
" | ";
|
||||
}
|
||||
print $cgi->a({-href => href(action=>"blob", hash=>$diff{'to_id'},
|
||||
hash_base=>$hash, file_name=>$diff{'file'})},
|
||||
@ -1986,19 +2034,19 @@ sub git_difftree_body {
|
||||
-class => "list"}, esc_html($diff{'from_file'})) .
|
||||
" with " . (int $diff{'similarity'}) . "% similarity$mode_chng]</span></td>\n" .
|
||||
"<td class=\"link\">";
|
||||
if ($diff{'to_id'} ne $diff{'from_id'}) {
|
||||
if ($action eq 'commitdiff') {
|
||||
# link to patch
|
||||
$patchno++;
|
||||
print $cgi->a({-href => "#patch$patchno"}, "patch");
|
||||
} else {
|
||||
print $cgi->a({-href => href(action=>"blobdiff",
|
||||
hash=>$diff{'to_id'}, hash_parent=>$diff{'from_id'},
|
||||
hash_base=>$hash, hash_parent_base=>$parent,
|
||||
file_name=>$diff{'to_file'}, file_parent=>$diff{'from_file'})},
|
||||
"diff");
|
||||
}
|
||||
print " | ";
|
||||
if ($action eq 'commitdiff') {
|
||||
# link to patch
|
||||
$patchno++;
|
||||
print $cgi->a({-href => "#patch$patchno"}, "patch") .
|
||||
" | ";
|
||||
} elsif ($diff{'to_id'} ne $diff{'from_id'}) {
|
||||
# "commit" view and modified file (not only pure rename or copy)
|
||||
print $cgi->a({-href => href(action=>"blobdiff",
|
||||
hash=>$diff{'to_id'}, hash_parent=>$diff{'from_id'},
|
||||
hash_base=>$hash, hash_parent_base=>$parent,
|
||||
file_name=>$diff{'to_file'}, file_parent=>$diff{'from_file'})},
|
||||
"diff") .
|
||||
" | ";
|
||||
}
|
||||
print $cgi->a({-href => href(action=>"blob", hash=>$diff{'from_id'},
|
||||
hash_base=>$parent, file_name=>$diff{'from_file'})},
|
||||
@ -2049,13 +2097,6 @@ sub git_patchset_body {
|
||||
}
|
||||
$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
|
||||
print "<div class=\"diff_info\">" . file_type($diffinfo->{'to_mode'}) . ":" .
|
||||
$cgi->a({-href => href(action=>"blob", hash_base=>$hash,
|
||||
@ -2262,8 +2303,7 @@ sub git_tags_body {
|
||||
for (my $i = $from; $i <= $to; $i++) {
|
||||
my $entry = $taglist->[$i];
|
||||
my %tag = %$entry;
|
||||
my $comment_lines = $tag{'comment'};
|
||||
my $comment = shift @$comment_lines;
|
||||
my $comment = $tag{'subject'};
|
||||
my $comment_short;
|
||||
if (defined $comment) {
|
||||
$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'});
|
||||
if ($tag{'reftype'} eq "commit") {
|
||||
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") {
|
||||
print " | " . $cgi->a({-href => href(action=>"blob_plain", hash=>$tag{'refid'})}, "raw");
|
||||
}
|
||||
@ -2321,23 +2361,23 @@ sub git_heads_body {
|
||||
my $alternate = 1;
|
||||
for (my $i = $from; $i <= $to; $i++) {
|
||||
my $entry = $headlist->[$i];
|
||||
my %tag = %$entry;
|
||||
my $curr = $tag{'id'} eq $head;
|
||||
my %ref = %$entry;
|
||||
my $curr = $ref{'id'} eq $head;
|
||||
if ($alternate) {
|
||||
print "<tr class=\"dark\">\n";
|
||||
} else {
|
||||
print "<tr class=\"light\">\n";
|
||||
}
|
||||
$alternate ^= 1;
|
||||
print "<td><i>$tag{'age'}</i></td>\n" .
|
||||
($tag{'id'} eq $head ? "<td class=\"current_head\">" : "<td>") .
|
||||
$cgi->a({-href => href(action=>"shortlog", hash=>$tag{'name'}),
|
||||
-class => "list name"},esc_html($tag{'name'})) .
|
||||
print "<td><i>$ref{'age'}</i></td>\n" .
|
||||
($curr ? "<td class=\"current_head\">" : "<td>") .
|
||||
$cgi->a({-href => href(action=>"shortlog", hash=>$ref{'name'}),
|
||||
-class => "list name"},esc_html($ref{'name'})) .
|
||||
"</td>\n" .
|
||||
"<td class=\"link\">" .
|
||||
$cgi->a({-href => href(action=>"shortlog", hash=>$tag{'name'})}, "shortlog") . " | " .
|
||||
$cgi->a({-href => href(action=>"log", hash=>$tag{'name'})}, "log") . " | " .
|
||||
$cgi->a({-href => href(action=>"tree", hash=>$tag{'name'}, hash_base=>$tag{'name'})}, "tree") .
|
||||
$cgi->a({-href => href(action=>"shortlog", hash=>$ref{'name'})}, "shortlog") . " | " .
|
||||
$cgi->a({-href => href(action=>"log", hash=>$ref{'name'})}, "log") . " | " .
|
||||
$cgi->a({-href => href(action=>"tree", hash=>$ref{'name'}, hash_base=>$ref{'name'})}, "tree") .
|
||||
"</td>\n" .
|
||||
"</tr>";
|
||||
}
|
||||
@ -2487,18 +2527,9 @@ sub git_summary {
|
||||
|
||||
my $owner = git_get_project_owner($project);
|
||||
|
||||
my ($reflist, $refs) = git_get_refs_list();
|
||||
|
||||
my @taglist;
|
||||
my @headlist;
|
||||
foreach my $ref (@$reflist) {
|
||||
if ($ref->{'name'} =~ s!^heads/!!) {
|
||||
push @headlist, $ref;
|
||||
} else {
|
||||
$ref->{'name'} =~ s!^tags/!!;
|
||||
push @taglist, $ref;
|
||||
}
|
||||
}
|
||||
my $refs = git_get_references();
|
||||
my @taglist = git_get_tags_list(15);
|
||||
my @headlist = git_get_heads_list(15);
|
||||
|
||||
git_header_html();
|
||||
git_print_page_nav('summary','', $head);
|
||||
@ -2529,7 +2560,7 @@ sub git_summary {
|
||||
}
|
||||
|
||||
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");
|
||||
my @revlist = map { chomp; $_ } <$fd>;
|
||||
close $fd;
|
||||
@ -2659,7 +2690,7 @@ HTML
|
||||
print "<tr class=\"$rev_color[$current_color]\">\n";
|
||||
if ($group_size) {
|
||||
print "<td class=\"sha1\"";
|
||||
print " title=\"$author, $date\"";
|
||||
print " title=\"". esc_html($author) . ", $date\"";
|
||||
print " rowspan=\"$group_size\"" if ($group_size > 1);
|
||||
print ">";
|
||||
print $cgi->a({-href => href(action=>"commit",
|
||||
@ -2790,9 +2821,9 @@ sub git_tags {
|
||||
git_print_page_nav('','', $head,undef,$head);
|
||||
git_print_header_div('summary', $project);
|
||||
|
||||
my ($taglist) = git_get_refs_list("tags");
|
||||
if (@$taglist) {
|
||||
git_tags_body($taglist);
|
||||
my @tagslist = git_get_tags_list();
|
||||
if (@tagslist) {
|
||||
git_tags_body(\@tagslist);
|
||||
}
|
||||
git_footer_html();
|
||||
}
|
||||
@ -2803,9 +2834,9 @@ sub git_heads {
|
||||
git_print_page_nav('','', $head,undef,$head);
|
||||
git_print_header_div('summary', $project);
|
||||
|
||||
my ($headlist) = git_get_refs_list("heads");
|
||||
if (@$headlist) {
|
||||
git_heads_body($headlist, $head);
|
||||
my @headslist = git_get_heads_list();
|
||||
if (@headslist) {
|
||||
git_heads_body(\@headslist, $head);
|
||||
}
|
||||
git_footer_html();
|
||||
}
|
||||
@ -2918,7 +2949,7 @@ sub git_blob {
|
||||
$nr++;
|
||||
$line = untabify($line);
|
||||
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
|
||||
or print "Reading blob failed.\n";
|
||||
@ -3072,7 +3103,7 @@ sub git_log {
|
||||
my $refs = git_get_references();
|
||||
|
||||
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");
|
||||
my @revlist = map { chomp; $_ } <$fd>;
|
||||
close $fd;
|
||||
@ -3130,7 +3161,7 @@ sub git_commit {
|
||||
$parent = "--root";
|
||||
}
|
||||
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");
|
||||
my @difftree = map { chomp; $_ } <$fd>;
|
||||
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 $file_name) {
|
||||
# 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
|
||||
or die_error(undef, "Open git-diff-tree failed");
|
||||
@difftree = map { chomp; $_ } <$fd>;
|
||||
@ -3249,7 +3281,8 @@ sub git_blobdiff {
|
||||
# try to find filename from $hash
|
||||
|
||||
# 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");
|
||||
@difftree =
|
||||
# ':100644 100644 03b21826... 3b93d5e7... M ls-files.c'
|
||||
@ -3319,7 +3352,8 @@ sub git_blobdiff {
|
||||
}
|
||||
|
||||
# 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");
|
||||
} else {
|
||||
die_error('404 Not Found', "Missing one of the blob diff parameters")
|
||||
@ -3450,8 +3484,8 @@ sub git_commitdiff {
|
||||
my @difftree;
|
||||
if ($format eq 'html') {
|
||||
open $fd, "-|", git_cmd(), "diff-tree", '-r', @diff_opts,
|
||||
"--no-commit-id",
|
||||
"--patch-with-raw", "--full-index", $hash_parent, $hash
|
||||
"--no-commit-id", "--patch-with-raw", "--full-index",
|
||||
$hash_parent, $hash, "--"
|
||||
or die_error(undef, "Open git-diff-tree failed");
|
||||
|
||||
while (chomp(my $line = <$fd>)) {
|
||||
@ -3462,7 +3496,7 @@ sub git_commitdiff {
|
||||
|
||||
} elsif ($format eq 'plain') {
|
||||
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");
|
||||
|
||||
} else {
|
||||
@ -3639,7 +3673,9 @@ sub git_search {
|
||||
my $alternate = 1;
|
||||
if ($searchtype eq 'commit' or $searchtype eq 'author' or $searchtype eq 'committer') {
|
||||
$/ = "\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>) {
|
||||
if (!grep m/$searchtext/i, $commit_text) {
|
||||
next;
|
||||
@ -3785,7 +3821,7 @@ sub git_shortlog {
|
||||
my $refs = git_get_references();
|
||||
|
||||
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");
|
||||
my @revlist = map { chomp; $_ } <$fd>;
|
||||
close $fd;
|
||||
@ -3813,7 +3849,8 @@ sub git_shortlog {
|
||||
|
||||
sub git_rss {
|
||||
# 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");
|
||||
my @revlist = map { chomp; $_ } <$fd>;
|
||||
close $fd or die_error(undef, "Reading git-rev-list failed");
|
||||
@ -3837,7 +3874,7 @@ XML
|
||||
}
|
||||
my %cd = parse_date($co{'committer_epoch'});
|
||||
open $fd, "-|", git_cmd(), "diff-tree", '-r', @diff_opts,
|
||||
$co{'parent'}, $co{'id'}
|
||||
$co{'parent'}, $co{'id'}, "--"
|
||||
or next;
|
||||
my @difftree = map { chomp; $_ } <$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 *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;
|
||||
int len = strlen(refname) + 1;
|
||||
@ -1913,7 +1913,7 @@ static void one_remote_ref(char *refname)
|
||||
static void get_local_heads(void)
|
||||
{
|
||||
local_tail = &local_refs;
|
||||
for_each_ref(one_local_ref);
|
||||
for_each_ref(one_local_ref, NULL);
|
||||
}
|
||||
|
||||
static void get_dav_remote_heads(void)
|
||||
|
@ -272,7 +272,7 @@ buffer_gets( buffer_t * b, char **s )
|
||||
n = b->bytes - start;
|
||||
|
||||
if (n)
|
||||
memcpy( b->buf, b->buf + start, n );
|
||||
memmove(b->buf, b->buf + start, n);
|
||||
b->offset -= start;
|
||||
b->bytes = n;
|
||||
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;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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? */
|
||||
parents = commit->parents;
|
||||
if (!parents) {
|
||||
if (opt->show_root_diff)
|
||||
diff_root_tree(opt, sha1, "");
|
||||
if (opt->show_root_diff) {
|
||||
diff_root_tree_sha1(sha1, "", &opt->diffopt);
|
||||
log_tree_diff_flush(opt);
|
||||
}
|
||||
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)
|
||||
break;
|
||||
if ((ch < ' ') || (ch == '"') || (ch == '\\') ||
|
||||
(ch == 0177)) {
|
||||
(ch >= 0177)) {
|
||||
needquote = 1;
|
||||
switch (ch) {
|
||||
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 int deny_non_fast_forwards = 0;
|
||||
static int report_status;
|
||||
|
||||
static char capabilities[] = "report-status";
|
||||
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)
|
||||
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)
|
||||
{
|
||||
for_each_ref(show_ref);
|
||||
for_each_ref(show_ref, NULL);
|
||||
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 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 int run_update_hook(const char *refname,
|
||||
@ -107,8 +93,8 @@ static int update(struct command *cmd)
|
||||
const char *name = cmd->ref_name;
|
||||
unsigned char *old_sha1 = cmd->old_sha1;
|
||||
unsigned char *new_sha1 = cmd->new_sha1;
|
||||
char new_hex[60], *old_hex, *lock_name;
|
||||
int newfd, namelen, written;
|
||||
char new_hex[41], old_hex[41];
|
||||
struct ref_lock *lock;
|
||||
|
||||
cmd->error_string = NULL;
|
||||
if (!strncmp(name, "refs/", 5) && check_ref_format(name + 5)) {
|
||||
@ -117,13 +103,8 @@ static int update(struct command *cmd)
|
||||
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));
|
||||
old_hex = sha1_to_hex(old_sha1);
|
||||
strcpy(old_hex, sha1_to_hex(old_sha1));
|
||||
if (!has_sha1_file(new_sha1)) {
|
||||
cmd->error_string = "bad pack";
|
||||
return error("unpack should have generated %s, "
|
||||
@ -144,47 +125,20 @@ static int update(struct command *cmd)
|
||||
return error("denying non-fast forward;"
|
||||
" 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)) {
|
||||
unlink(lock_name);
|
||||
cmd->error_string = "hook declined";
|
||||
return error("hook declined to update %s", name);
|
||||
}
|
||||
else if (rename(lock_name, name) < 0) {
|
||||
unlink(lock_name);
|
||||
cmd->error_string = "can't rename";
|
||||
return error("unable to replace %s", name);
|
||||
}
|
||||
else {
|
||||
fprintf(stderr, "%s: %s -> %s\n", name, old_hex, new_hex);
|
||||
return 0;
|
||||
|
||||
lock = lock_any_ref_for_update(name, old_sha1);
|
||||
if (!lock) {
|
||||
cmd->error_string = "failed to lock";
|
||||
return error("failed to lock %s", name);
|
||||
}
|
||||
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";
|
||||
@ -333,9 +287,12 @@ int main(int argc, char **argv)
|
||||
if (!dir)
|
||||
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);
|
||||
|
||||
setup_ident();
|
||||
git_config(receive_pack_config);
|
||||
|
||||
write_head_info();
|
||||
|
||||
/* EOF */
|
||||
|
612
refs.c
612
refs.c
@ -3,15 +3,193 @@
|
||||
|
||||
#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 */
|
||||
#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;
|
||||
char buffer[256];
|
||||
static char ref_buffer[256];
|
||||
|
||||
if (flag)
|
||||
*flag = 0;
|
||||
|
||||
for (;;) {
|
||||
const char *path = git_path("%s", ref);
|
||||
struct stat st;
|
||||
char *buf;
|
||||
int fd;
|
||||
@ -27,17 +205,31 @@ const char *resolve_ref(const char *path, unsigned char *sha1, int reading)
|
||||
* reading.
|
||||
*/
|
||||
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)
|
||||
return NULL;
|
||||
hashclr(sha1);
|
||||
return path;
|
||||
return ref;
|
||||
}
|
||||
|
||||
/* Follow "normalized" - ie "refs/.." symlinks by hand */
|
||||
if (S_ISLNK(st.st_mode)) {
|
||||
len = readlink(path, buffer, sizeof(buffer)-1);
|
||||
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;
|
||||
}
|
||||
}
|
||||
@ -68,19 +260,24 @@ const char *resolve_ref(const char *path, unsigned char *sha1, int reading)
|
||||
while (len && isspace(*buf))
|
||||
buf++, len--;
|
||||
while (len && isspace(buf[len-1]))
|
||||
buf[--len] = 0;
|
||||
path = git_path("%.*s", len, buf);
|
||||
len--;
|
||||
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))
|
||||
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;
|
||||
char ref[1000];
|
||||
int fd, len, written;
|
||||
const char *git_HEAD = git_path("%s", ref_target);
|
||||
|
||||
#ifndef NO_SYMLINK_HEAD
|
||||
if (prefer_symlink_refs) {
|
||||
@ -118,104 +315,101 @@ int create_symref(const char *git_HEAD, const char *refs_heads_master)
|
||||
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 -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;
|
||||
DIR *dir = opendir(git_path("%s", base));
|
||||
int retval;
|
||||
struct ref_list *packed = get_packed_refs();
|
||||
struct ref_list *loose = get_loose_refs();
|
||||
|
||||
if (dir) {
|
||||
struct dirent *de;
|
||||
int baselen = strlen(base);
|
||||
char *path = xmalloc(baselen + 257);
|
||||
|
||||
if (!strncmp(base, "./", 2)) {
|
||||
base += 2;
|
||||
baselen -= 2;
|
||||
while (packed && loose) {
|
||||
struct ref_list *entry;
|
||||
int cmp = strcmp(packed->name, loose->name);
|
||||
if (!cmp) {
|
||||
packed = packed->next;
|
||||
continue;
|
||||
}
|
||||
memcpy(path, base, baselen);
|
||||
if (baselen && base[baselen-1] != '/')
|
||||
path[baselen++] = '/';
|
||||
|
||||
while ((de = readdir(dir)) != NULL) {
|
||||
unsigned char sha1[20];
|
||||
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;
|
||||
if (cmp > 0) {
|
||||
entry = loose;
|
||||
loose = loose->next;
|
||||
} else {
|
||||
entry = packed;
|
||||
packed = packed->next;
|
||||
}
|
||||
free(path);
|
||||
closedir(dir);
|
||||
if (strncmp(base, entry->name, trim))
|
||||
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))
|
||||
{
|
||||
unsigned char sha1[20];
|
||||
if (!read_ref(git_path("HEAD"), sha1))
|
||||
return fn("HEAD", sha1);
|
||||
packed = packed ? packed : loose;
|
||||
while (packed) {
|
||||
if (!strncmp(base, packed->name, trim)) {
|
||||
retval = fn(packed->name + trim, packed->sha1,
|
||||
packed->flag, cb_data);
|
||||
if (retval)
|
||||
return retval;
|
||||
}
|
||||
packed = packed->next;
|
||||
}
|
||||
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)
|
||||
{
|
||||
if (check_ref_format(ref))
|
||||
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,
|
||||
const unsigned char *old_sha1, int mustexist)
|
||||
{
|
||||
char buf[40];
|
||||
int nr, fd = open(lock->ref_file, O_RDONLY);
|
||||
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);
|
||||
if (!resolve_ref(lock->ref_name, lock->old_sha1, mustexist, NULL)) {
|
||||
error("Can't verify ref %s", lock->ref_name);
|
||||
unlock_ref(lock);
|
||||
return NULL;
|
||||
}
|
||||
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));
|
||||
unlock_ref(lock);
|
||||
return NULL;
|
||||
@ -296,54 +481,223 @@ static struct ref_lock *verify_lock(struct ref_lock *lock,
|
||||
return lock;
|
||||
}
|
||||
|
||||
static struct ref_lock *lock_ref_sha1_basic(const char *path,
|
||||
int plen,
|
||||
const unsigned char *old_sha1, int mustexist)
|
||||
static int remove_empty_dir_recursive(char *path, int len)
|
||||
{
|
||||
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 stat st;
|
||||
int last_errno = 0;
|
||||
int mustexist = (old_sha1 && !is_null_sha1(old_sha1));
|
||||
|
||||
lock = xcalloc(1, sizeof(struct ref_lock));
|
||||
lock->lock_fd = -1;
|
||||
|
||||
plen = strlen(path) - plen;
|
||||
path = resolve_ref(path, lock->old_sha1, mustexist);
|
||||
if (!path) {
|
||||
int last_errno = errno;
|
||||
error("unable to resolve reference %s: %s",
|
||||
orig_path, strerror(errno));
|
||||
unlock_ref(lock);
|
||||
errno = last_errno;
|
||||
return NULL;
|
||||
ref = resolve_ref(ref, lock->old_sha1, mustexist, flag);
|
||||
if (!ref && errno == EISDIR) {
|
||||
/* we are trying to lock foo but we used to
|
||||
* have foo/bar which now does not exist;
|
||||
* it is normal for the empty directory 'foo'
|
||||
* to remain.
|
||||
*/
|
||||
ref_file = git_path("%s", orig_ref);
|
||||
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->ref_file = xstrdup(path);
|
||||
lock->log_file = xstrdup(git_path("logs/%s", lock->ref_file + plen));
|
||||
lock->force_write = lstat(lock->ref_file, &st) && errno == ENOENT;
|
||||
lock->ref_name = xstrdup(ref);
|
||||
lock->log_file = xstrdup(git_path("logs/%s", ref));
|
||||
ref_file = git_path("%s", ref);
|
||||
lock->force_write = lstat(ref_file, &st) && errno == ENOENT;
|
||||
|
||||
if (safe_create_leading_directories(lock->ref_file))
|
||||
die("unable to create directory for %s", lock->ref_file);
|
||||
lock->lock_fd = hold_lock_file_for_update(lock->lk, lock->ref_file, 1);
|
||||
if (safe_create_leading_directories(ref_file)) {
|
||||
last_errno = errno;
|
||||
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;
|
||||
|
||||
error_return:
|
||||
unlock_ref(lock);
|
||||
errno = last_errno;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct ref_lock *lock_ref_sha1(const char *ref,
|
||||
const unsigned char *old_sha1, int mustexist)
|
||||
struct ref_lock *lock_ref_sha1(const char *ref, const unsigned char *old_sha1)
|
||||
{
|
||||
char refpath[PATH_MAX];
|
||||
if (check_ref_format(ref))
|
||||
return NULL;
|
||||
return lock_ref_sha1_basic(git_path("refs/%s", ref),
|
||||
5 + strlen(ref), old_sha1, mustexist);
|
||||
strcpy(refpath, mkpath("refs/%s", ref));
|
||||
return lock_ref_sha1_basic(refpath, old_sha1, NULL);
|
||||
}
|
||||
|
||||
struct ref_lock *lock_any_ref_for_update(const char *ref,
|
||||
const unsigned char *old_sha1, int mustexist)
|
||||
struct ref_lock *lock_any_ref_for_update(const char *ref, const unsigned char *old_sha1)
|
||||
{
|
||||
return lock_ref_sha1_basic(git_path("%s", ref),
|
||||
strlen(ref), old_sha1, mustexist);
|
||||
return lock_ref_sha1_basic(ref, old_sha1, NULL);
|
||||
}
|
||||
|
||||
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)
|
||||
@ -354,7 +708,7 @@ void unlock_ref(struct ref_lock *lock)
|
||||
if (lock->lk)
|
||||
rollback_lock_file(lock->lk);
|
||||
}
|
||||
free(lock->ref_file);
|
||||
free(lock->ref_name);
|
||||
free(lock->log_file);
|
||||
free(lock);
|
||||
}
|
||||
@ -367,7 +721,8 @@ static int log_ref_write(struct ref_lock *lock,
|
||||
char *logrec;
|
||||
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)
|
||||
return error("unable to create directory for %s",
|
||||
lock->log_file);
|
||||
@ -376,10 +731,20 @@ static int log_ref_write(struct ref_lock *lock,
|
||||
|
||||
logfd = open(lock->log_file, oflags, 0666);
|
||||
if (logfd < 0) {
|
||||
if (!log_all_ref_updates && errno == ENOENT)
|
||||
if (!(oflags & O_CREAT) && errno == ENOENT)
|
||||
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);
|
||||
@ -426,12 +791,13 @@ int write_ref_sha1(struct ref_lock *lock,
|
||||
unlock_ref(lock);
|
||||
return -1;
|
||||
}
|
||||
invalidate_cached_refs();
|
||||
if (log_ref_write(lock, sha1, logmsg) < 0) {
|
||||
unlock_ref(lock);
|
||||
return -1;
|
||||
}
|
||||
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);
|
||||
return -1;
|
||||
}
|
||||
@ -440,7 +806,7 @@ int write_ref_sha1(struct ref_lock *lock,
|
||||
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;
|
||||
char *tz_c;
|
||||
@ -473,7 +839,7 @@ int read_ref_at(const char *ref, unsigned long at_time, unsigned char *sha1)
|
||||
if (!lastgt)
|
||||
die("Log %s is corrupt.", logfile);
|
||||
date = strtoul(lastgt + 1, &tz_c, 10);
|
||||
if (date <= at_time) {
|
||||
if (date <= at_time || cnt == 0) {
|
||||
if (lastrec) {
|
||||
if (get_sha1_hex(lastrec, logged_sha1))
|
||||
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;
|
||||
}
|
||||
lastrec = rec;
|
||||
if (cnt > 0)
|
||||
cnt--;
|
||||
}
|
||||
|
||||
rec = logdata;
|
||||
|
21
refs.h
21
refs.h
@ -2,7 +2,7 @@
|
||||
#define REFS_H
|
||||
|
||||
struct ref_lock {
|
||||
char *ref_file;
|
||||
char *ref_name;
|
||||
char *log_file;
|
||||
struct lock_file *lk;
|
||||
unsigned char old_sha1[20];
|
||||
@ -14,20 +14,23 @@ struct ref_lock {
|
||||
* Calls the specified function for each ref file until it returns nonzero,
|
||||
* and returns the value
|
||||
*/
|
||||
extern int head_ref(int (*fn)(const char *path, const unsigned char *sha1));
|
||||
extern int for_each_ref(int (*fn)(const char *path, const unsigned char *sha1));
|
||||
extern int for_each_tag_ref(int (*fn)(const char *path, const unsigned char *sha1));
|
||||
extern int for_each_branch_ref(int (*fn)(const char *path, const unsigned char *sha1));
|
||||
extern int for_each_remote_ref(int (*fn)(const char *path, const unsigned char *sha1));
|
||||
#define REF_ISSYMREF 01
|
||||
#define REF_ISPACKED 02
|
||||
typedef int each_ref_fn(const char *refname, const unsigned char *sha1, int flags, void *cb_data);
|
||||
extern int head_ref(each_ref_fn, void *);
|
||||
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 **/
|
||||
extern int get_ref_sha1(const char *ref, unsigned char *sha1);
|
||||
|
||||
/** 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). */
|
||||
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. **/
|
||||
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);
|
||||
|
||||
/** 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. **/
|
||||
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))
|
||||
obj->flags |= UNINTERESTING;
|
||||
if (revs->unpacked &&
|
||||
has_sha1_pack(obj->sha1, revs->ignore_packed))
|
||||
obj->flags |= UNINTERESTING;
|
||||
add_parents_to_list(revs, commit, &list);
|
||||
if (obj->flags & UNINTERESTING) {
|
||||
mark_parents_uninteresting(commit);
|
||||
@ -468,7 +465,7 @@ static void limit_list(struct rev_info *revs)
|
||||
static int all_flags;
|
||||
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);
|
||||
add_pending_object(all_revs, object, "");
|
||||
@ -479,7 +476,7 @@ static void handle_all(struct rev_info *revs, unsigned flags)
|
||||
{
|
||||
all_revs = revs;
|
||||
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)
|
||||
@ -1015,7 +1012,7 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch
|
||||
add_pending_object(revs, object, def);
|
||||
}
|
||||
|
||||
if (revs->topo_order || revs->unpacked)
|
||||
if (revs->topo_order)
|
||||
revs->limited = 1;
|
||||
|
||||
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().
|
||||
*/
|
||||
if (!revs->limited) {
|
||||
if ((revs->unpacked &&
|
||||
has_sha1_pack(commit->object.sha1,
|
||||
revs->ignore_packed)) ||
|
||||
(revs->max_age != -1 &&
|
||||
(commit->date < revs->max_age)))
|
||||
if (revs->max_age != -1 &&
|
||||
(commit->date < revs->max_age))
|
||||
continue;
|
||||
add_parents_to_list(revs, commit, &revs->commits);
|
||||
}
|
||||
if (commit->object.flags & SHOWN)
|
||||
continue;
|
||||
|
||||
if (revs->unpacked && has_sha1_pack(commit->object.sha1,
|
||||
revs->ignore_packed))
|
||||
continue;
|
||||
|
||||
/* We want to show boundary commits only when their
|
||||
* children are shown. When path-limiter is in effect,
|
||||
* 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 *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;
|
||||
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)
|
||||
{
|
||||
local_tail = &local_refs;
|
||||
for_each_ref(one_local_ref);
|
||||
for_each_ref(one_local_ref, NULL);
|
||||
}
|
||||
|
||||
static int receive_status(int in)
|
||||
|
@ -7,7 +7,7 @@
|
||||
/* refs */
|
||||
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);
|
||||
|
||||
@ -34,7 +34,7 @@ static int update_info_refs(int force)
|
||||
info_ref_fp = fopen(path1, "w");
|
||||
if (!info_ref_fp)
|
||||
return error("unable to update %s", path0);
|
||||
for_each_ref(add_info_ref);
|
||||
for_each_ref(add_info_ref, NULL);
|
||||
fclose(info_ref_fp);
|
||||
rename(path1, 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);
|
||||
else if (strcmp(var, "core.sharedrepository") == 0)
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -1417,9 +1417,10 @@ static int link_temp_to_file(const char *tmpfile, const char *filename)
|
||||
dir = strrchr(filename, '/');
|
||||
if (dir) {
|
||||
*dir = 0;
|
||||
mkdir(filename, 0777);
|
||||
if (adjust_shared_perm(filename))
|
||||
if (!mkdir(filename, 0777) && adjust_shared_perm(filename)) {
|
||||
*dir = '/';
|
||||
return -2;
|
||||
}
|
||||
*dir = '/';
|
||||
if (!link(tmpfile, filename))
|
||||
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
|
||||
};
|
||||
static const char *warning = "warning: refname '%.*s' is ambiguous.\n";
|
||||
const char **p, *pathname;
|
||||
char *real_path = NULL;
|
||||
int refs_found = 0, am;
|
||||
unsigned long at_time = (unsigned long)-1;
|
||||
const char **p, *ref;
|
||||
char *real_ref = NULL;
|
||||
int refs_found = 0;
|
||||
int at, reflog_len;
|
||||
unsigned char *this_result;
|
||||
unsigned char sha1_from_ref[20];
|
||||
|
||||
if (len == 40 && !get_sha1_hex(str, sha1))
|
||||
return 0;
|
||||
|
||||
/* At a given period of time? "@{2 hours ago}" */
|
||||
for (am = 1; am < len - 1; am++) {
|
||||
if (str[am] == '@' && str[am+1] == '{' && str[len-1] == '}') {
|
||||
int date_len = len - am - 3;
|
||||
char *date_spec = xmalloc(date_len + 1);
|
||||
strlcpy(date_spec, str + am + 2, date_len + 1);
|
||||
at_time = approxidate(date_spec);
|
||||
free(date_spec);
|
||||
len = am;
|
||||
break;
|
||||
/* basic@{time or number} format to query ref-log */
|
||||
reflog_len = at = 0;
|
||||
if (str[len-1] == '}') {
|
||||
for (at = 1; at < len - 1; at++) {
|
||||
if (str[at] == '@' && str[at+1] == '{') {
|
||||
reflog_len = (len-1) - (at+2);
|
||||
len = at;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -276,10 +275,10 @@ static int get_sha1_basic(const char *str, int len, unsigned char *sha1)
|
||||
|
||||
for (p = fmt; *p; p++) {
|
||||
this_result = refs_found ? sha1_from_ref : sha1;
|
||||
pathname = resolve_ref(git_path(*p, len, str), this_result, 1);
|
||||
if (pathname) {
|
||||
ref = resolve_ref(mkpath(*p, len, str), this_result, 1, NULL);
|
||||
if (ref) {
|
||||
if (!refs_found++)
|
||||
real_path = xstrdup(pathname);
|
||||
real_ref = xstrdup(ref);
|
||||
if (!warn_ambiguous_refs)
|
||||
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)
|
||||
fprintf(stderr, warning, len, str);
|
||||
|
||||
if (at_time != (unsigned long)-1) {
|
||||
read_ref_at(
|
||||
real_path + strlen(git_path(".")) - 1,
|
||||
at_time,
|
||||
sha1);
|
||||
if (reflog_len) {
|
||||
/* Is it asking for N-th entry, or approxidate? */
|
||||
int nth, i;
|
||||
unsigned long at_time;
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -30,11 +30,8 @@ rm -f .git/$m
|
||||
test_expect_success \
|
||||
"fail to create $n" \
|
||||
"touch .git/$n_dir
|
||||
git-update-ref $n $A >out 2>err
|
||||
test "'$? = 1 &&
|
||||
test "" = "$(cat out)" &&
|
||||
grep "error: unable to resolve reference" err &&
|
||||
grep '"$n err"
|
||||
git-update-ref $n $A >out 2>err"'
|
||||
test $? != 0'
|
||||
rm -f .git/$n_dir out err
|
||||
|
||||
test_expect_success \
|
||||
|
@ -17,13 +17,10 @@ test_expect_success \
|
||||
git-commit -m "Initial commit." &&
|
||||
HEAD=$(git-rev-parse --verify HEAD)'
|
||||
|
||||
test_expect_success \
|
||||
'git branch --help should return success now.' \
|
||||
'git-branch --help'
|
||||
|
||||
test_expect_failure \
|
||||
'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 \
|
||||
'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'
|
||||
|
||||
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
|
||||
test_expect_success \
|
||||
'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;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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";
|
||||
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)
|
||||
{
|
||||
reset_timeout();
|
||||
head_ref(send_ref);
|
||||
for_each_ref(send_ref);
|
||||
head_ref(send_ref, NULL);
|
||||
for_each_ref(send_ref, NULL);
|
||||
packet_flush(1);
|
||||
receive_needs();
|
||||
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;
|
||||
|
||||
head = resolve_ref(git_path("HEAD"), sha1, 0);
|
||||
s->branch = head ?
|
||||
strdup(head + strlen(get_git_dir()) + 1) :
|
||||
NULL;
|
||||
head = resolve_ref("HEAD", sha1, 0, NULL);
|
||||
s->branch = head ? xstrdup(head) : NULL;
|
||||
|
||||
s->reference = "HEAD";
|
||||
s->amend = 0;
|
||||
|
Loading…
Reference in New Issue
Block a user