提交 58a1e0e8 编写于 作者: J Junio C Hamano

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.
  ...
......@@ -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
......
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
......
......@@ -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
......
/*
* Builtin "git branch"
*
* Copyright (c) 2006 Kristian Hgsberg <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 @@ static void name_rev(struct commit *commit,
}
}
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];
......
#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);
......
#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;
}
#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
......@@ -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 @@ static int find_common(int fd[2], unsigned char *result_sha1,
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);
......
......@@ -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;
......
#!/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"
......
......@@ -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"
......@@ -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();
......
此差异已折叠。
......@@ -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);
......
......@@ -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' \
......
#!/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;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册