зеркало из https://github.com/microsoft/git.git
Merge branch 'lj/refs'
* lj/refs: (63 commits) Fix show-ref usagestring t3200: git-branch testsuite update sha1_name.c: avoid compilation warnings. Make git-branch a builtin ref-log: fix D/F conflict coming from deleted refs. git-revert with conflicts to behave as git-merge with conflicts core.logallrefupdates thinko-fix git-pack-refs --all core.logallrefupdates create new log file only for branch heads. Remove bashism from t3210-pack-refs.sh ref-log: allow ref@{count} syntax. pack-refs: call fflush before fsync. pack-refs: use lockfile as everybody else does. git-fetch: do not look into $GIT_DIR/refs to see if a tag exists. lock_ref_sha1_basic does not remove empty directories on BSD Do not create tag leading directories since git update-ref does it. Check that a tag exists using show-ref instead of looking for the ref file. Use git-update-ref to delete a tag instead of rm()ing the ref file. Fix refs.c;:repack_without_ref() clean-up path Clean up "git-branch.sh" and add remove recursive dir test cases. ...
This commit is contained in:
Коммит
58a1e0e83b
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
7
Makefile
7
Makefile
|
@ -158,7 +158,7 @@ BASIC_CFLAGS =
|
|||
BASIC_LDFLAGS =
|
||||
|
||||
SCRIPT_SH = \
|
||||
git-bisect.sh git-branch.sh git-checkout.sh \
|
||||
git-bisect.sh git-checkout.sh \
|
||||
git-cherry.sh git-clean.sh git-clone.sh git-commit.sh \
|
||||
git-fetch.sh \
|
||||
git-ls-remote.sh \
|
||||
|
@ -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
|
||||
|
|
|
@ -0,0 +1,219 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
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++) {
|
||||
if (!strcmp(ref_list[i], head))
|
||||
printf("* %s\n", ref_list[i]);
|
||||
else
|
||||
printf(" %s\n", 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;
|
||||
|
||||
|
|
|
@ -585,24 +585,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 +629,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 +776,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 +848,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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -0,0 +1,105 @@
|
|||
#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;
|
||||
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;
|
||||
|
||||
/* 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;
|
||||
int (*iterate_ref)(each_ref_fn, void *) = for_each_tag_ref;
|
||||
|
||||
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")) {
|
||||
iterate_ref = for_each_ref;
|
||||
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));
|
||||
iterate_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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,6 +17,7 @@ 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);
|
||||
|
@ -65,5 +66,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
|
||||
|
|
7
cache.h
7
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;
|
||||
|
@ -288,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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
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"
|
||||
|
||||
|
|
3
git.c
3
git.c
|
@ -222,6 +222,7 @@ static void handle_internal_command(int argc, const char **argv, char **envp)
|
|||
{ "annotate", cmd_annotate, },
|
||||
{ "apply", cmd_apply },
|
||||
{ "archive", cmd_archive },
|
||||
{ "branch", cmd_branch },
|
||||
{ "cat-file", cmd_cat_file, RUN_SETUP },
|
||||
{ "checkout-index", cmd_checkout_index, RUN_SETUP },
|
||||
{ "check-ref-format", cmd_check_ref_format },
|
||||
|
@ -269,6 +270,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;
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -28,7 +28,7 @@ static int receive_pack_config(const char *var, const char *value)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int show_ref(const char *path, const unsigned char *sha1)
|
||||
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);
|
||||
|
@ -41,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);
|
||||
|
||||
}
|
||||
|
||||
|
@ -57,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,
|
||||
|
@ -121,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)) {
|
||||
|
@ -131,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, "
|
||||
|
@ -158,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";
|
||||
|
@ -349,9 +289,10 @@ 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();
|
||||
|
|
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);
|
||||
|
|
|
@ -465,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, "");
|
||||
|
@ -476,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)
|
||||
|
|
|
@ -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);
|
||||
|
|
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' \
|
||||
|
|
|
@ -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
|
|
@ -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;
|
||||
|
|
Загрузка…
Ссылка в новой задаче