Merge branch 'np/dreflog' into next

* np/dreflog:
  add reflog when moving HEAD to a new branch
  create_symref(): do not assume pathname from git_path() persists long enough
  add logref support to git-symbolic-ref
  move create_symref() past log_ref_write()
  add reflog entries for HEAD when detached
  enable separate reflog for HEAD
  lock_ref_sha1_basic(): remember the original name of a ref when resolving it
  make reflog filename independent from struct ref_lock
  Compute accurate distances in git-describe before output.
  Update describe documentation.
  Teach git-describe to display distances from tags.
  git-blame --porcelain: quote filename in c-style when needed.
  git-blame --incremental
  Don't force everybody to call setup_ident().
  git-log -g --pretty=oneline should display the reflog message
  Document --check option to git diff.
  Allow the tag signing key to be specified in the config file
This commit is contained in:
Junio C Hamano
2007-01-28 02:17:31 -08:00
30 changed files with 367 additions and 194 deletions

View File

@@ -23,7 +23,8 @@ probably need to split up your commit to finer grained pieces.
Oh, another thing. I am picky about whitespaces. Make sure your
changes do not trigger errors with the sample pre-commit hook shipped
in templates/hooks--pre-commit.
in templates/hooks--pre-commit. To help ensure this does not happen,
run git diff --check on your changes before you commit.
(2) Generate your patch using git tools out of your commits.

View File

@@ -469,6 +469,13 @@ user.name::
Can be overridden by the 'GIT_AUTHOR_NAME' and 'GIT_COMMITTER_NAME'
environment variables. See gitlink:git-commit-tree[1].
user.signingkey::
If gitlink:git-tag[1] is not selecting the key you want it to
automatically when creating a signed tag, you can override the
default selection with this variable. This option is passed
unchanged to gpg's --local-user parameter, so you may specify a key
using any method that gpg supports.
whatchanged.difftree::
The default gitlink:git-diff-tree[1] arguments to be used
for gitlink:git-whatchanged[1].

View File

@@ -58,6 +58,10 @@
Turn off rename detection, even when the configuration
file gives the default to do so.
--check::
Warn if changes introduce trailing whitespace
or an indent that uses a space before a tab.
--full-index::
Instead of the first handful characters, show full
object name of pre- and post-image blob on the "index"

View File

@@ -14,8 +14,8 @@ DESCRIPTION
-----------
The command finds the most recent tag that is reachable from a
commit, and if the commit itself is pointed at by the tag, shows
the tag. Otherwise, it suffixes the tag name with abbreviated
object name of the commit.
the tag. Otherwise, it suffixes the tag name with the number of
additional commits and the abbreviated object name of the commit.
OPTIONS
@@ -52,12 +52,18 @@ EXAMPLES
With something like git.git current tree, I get:
[torvalds@g5 git]$ git-describe parent
v1.0.4-g2414721b
v1.0.4-14-g2414721
i.e. the current head of my "parent" branch is based on v1.0.4,
but since it has a few commits on top of that, it has added the
git hash of the thing to the end: "-g" + 8-char shorthand for
the commit `2414721b194453f058079d897d13c4e377f92dc6`.
but since it has a handful commits on top of that,
describe has added the number of additional commits ("14") and
an abbreviated object name for the commit itself ("2414721")
at the end.
The number of additional commits is the number
of commits which would be displayed by "git log v1.0.4..parent".
The hash suffix is "-g" + 7-char abbreviation for the tip commit
of parent (which was `2414721b194453f058079d897d13c4e377f92dc6`).
Doing a "git-describe" on a tag-name will just show the tag name:
@@ -68,10 +74,16 @@ With --all, the command can use branch heads as references, so
the output shows the reference path as well:
[torvalds@g5 git]$ git describe --all --abbrev=4 v1.0.5^2
tags/v1.0.0-g975b
tags/v1.0.0-21-g975b
[torvalds@g5 git]$ git describe --all HEAD^
heads/lt/describe-g975b
heads/lt/describe-7-g975b
With --abbrev set to 0, the command can be used to find the
closest tagname without any suffix:
[torvalds@g5 git]$ git describe --abbrev=0 v1.0.5^2
tags/v1.0.0
SEARCH STRATEGY
---------------
@@ -97,7 +109,8 @@ will be the smallest number of commits possible.
Author
------
Written by Linus Torvalds <torvalds@osdl.org>, but somewhat
butchered by Junio C Hamano <junkio@cox.net>
butchered by Junio C Hamano <junkio@cox.net>. Later significantly
updated by Shawn Pearce <spearce@spearce.org>.
Documentation
--------------

View File

@@ -7,7 +7,7 @@ git-symbolic-ref - Read and modify symbolic refs
SYNOPSIS
--------
'git-symbolic-ref' [-q] <name> [<ref>]
'git-symbolic-ref' [-q] [-m <reason>] <name> [<ref>]
DESCRIPTION
-----------
@@ -31,6 +31,10 @@ OPTIONS
symbolic ref but a detached HEAD; instead exit with
non-zero status silently.
-m::
Update the reflog for <name> with <reason>. This is valid only
when creating or updating a symbolic ref.
NOTES
-----
In the past, `.git/HEAD` was a symbolic link pointing at

View File

@@ -70,6 +70,16 @@ OPTIONS
Take the tag message from the given file. Use '-' to
read the message from the standard input.
CONFIGURATION
-------------
By default, git-tag in sign-with-default mode (-s) will use your
committer identity (of the form "Your Name <your@email.address>") to
find a key. If you want to use a different default key, you can specify
it in the repository configuration as follows:
[user]
signingkey = <gpg-key-id>
Author
------
Written by Linus Torvalds <torvalds@osdl.org>,

View File

@@ -13,6 +13,7 @@
#include "diff.h"
#include "diffcore.h"
#include "revision.h"
#include "quote.h"
#include "xdiff-interface.h"
static char blame_usage[] =
@@ -27,6 +28,7 @@ static char blame_usage[] =
" -p, --porcelain Show in a format designed for machine consumption\n"
" -L n,m Process only line range n,m, counting from 1\n"
" -M, -C Find line movements within and across files\n"
" --incremental Show blame entries as we find them, incrementally\n"
" -S revs-file Use revisions from revs-file instead of calling git-rev-list\n";
static int longest_file;
@@ -36,6 +38,7 @@ static int max_digits;
static int max_score_digits;
static int show_root;
static int blank_boundary;
static int incremental;
#ifndef DEBUG
#define DEBUG 0
@@ -1069,72 +1072,6 @@ static void pass_blame(struct scoreboard *sb, struct origin *origin, int opt)
origin_decref(parent_origin[i]);
}
static void assign_blame(struct scoreboard *sb, struct rev_info *revs, int opt)
{
while (1) {
struct blame_entry *ent;
struct commit *commit;
struct origin *suspect = NULL;
/* find one suspect to break down */
for (ent = sb->ent; !suspect && ent; ent = ent->next)
if (!ent->guilty)
suspect = ent->suspect;
if (!suspect)
return; /* all done */
origin_incref(suspect);
commit = suspect->commit;
if (!commit->object.parsed)
parse_commit(commit);
if (!(commit->object.flags & UNINTERESTING) &&
!(revs->max_age != -1 && commit->date < revs->max_age))
pass_blame(sb, suspect, opt);
else {
commit->object.flags |= UNINTERESTING;
if (commit->object.parsed)
mark_parents_uninteresting(commit);
}
/* treat root commit as boundary */
if (!commit->parents && !show_root)
commit->object.flags |= UNINTERESTING;
/* Take responsibility for the remaining entries */
for (ent = sb->ent; ent; ent = ent->next)
if (!cmp_suspect(ent->suspect, suspect))
ent->guilty = 1;
origin_decref(suspect);
if (DEBUG) /* sanity */
sanity_check_refcnt(sb);
}
}
static const char *format_time(unsigned long time, const char *tz_str,
int show_raw_time)
{
static char time_buf[128];
time_t t = time;
int minutes, tz;
struct tm *tm;
if (show_raw_time) {
sprintf(time_buf, "%lu %s", time, tz_str);
return time_buf;
}
tz = atoi(tz_str);
minutes = tz < 0 ? -tz : tz;
minutes = (minutes / 100)*60 + (minutes % 100);
minutes = tz < 0 ? -minutes : minutes;
t = time + minutes * 60;
tm = gmtime(&t);
strftime(time_buf, sizeof(time_buf), "%Y-%m-%d %H:%M:%S ", tm);
strcat(time_buf, tz_str);
return time_buf;
}
struct commit_info
{
char *author;
@@ -1245,6 +1182,110 @@ static void get_commit_info(struct commit *commit,
summary_buf[len] = 0;
}
static void write_filename_info(const char *path)
{
printf("filename ");
write_name_quoted(NULL, 0, path, 1, stdout);
putchar('\n');
}
static void found_guilty_entry(struct blame_entry *ent)
{
if (ent->guilty)
return;
ent->guilty = 1;
if (incremental) {
struct origin *suspect = ent->suspect;
printf("%s %d %d %d\n",
sha1_to_hex(suspect->commit->object.sha1),
ent->s_lno + 1, ent->lno + 1, ent->num_lines);
if (!(suspect->commit->object.flags & METAINFO_SHOWN)) {
struct commit_info ci;
suspect->commit->object.flags |= METAINFO_SHOWN;
get_commit_info(suspect->commit, &ci, 1);
printf("author %s\n", ci.author);
printf("author-mail %s\n", ci.author_mail);
printf("author-time %lu\n", ci.author_time);
printf("author-tz %s\n", ci.author_tz);
printf("committer %s\n", ci.committer);
printf("committer-mail %s\n", ci.committer_mail);
printf("committer-time %lu\n", ci.committer_time);
printf("committer-tz %s\n", ci.committer_tz);
printf("summary %s\n", ci.summary);
if (suspect->commit->object.flags & UNINTERESTING)
printf("boundary\n");
}
write_filename_info(suspect->path);
}
}
static void assign_blame(struct scoreboard *sb, struct rev_info *revs, int opt)
{
while (1) {
struct blame_entry *ent;
struct commit *commit;
struct origin *suspect = NULL;
/* find one suspect to break down */
for (ent = sb->ent; !suspect && ent; ent = ent->next)
if (!ent->guilty)
suspect = ent->suspect;
if (!suspect)
return; /* all done */
origin_incref(suspect);
commit = suspect->commit;
if (!commit->object.parsed)
parse_commit(commit);
if (!(commit->object.flags & UNINTERESTING) &&
!(revs->max_age != -1 && commit->date < revs->max_age))
pass_blame(sb, suspect, opt);
else {
commit->object.flags |= UNINTERESTING;
if (commit->object.parsed)
mark_parents_uninteresting(commit);
}
/* treat root commit as boundary */
if (!commit->parents && !show_root)
commit->object.flags |= UNINTERESTING;
/* Take responsibility for the remaining entries */
for (ent = sb->ent; ent; ent = ent->next)
if (!cmp_suspect(ent->suspect, suspect))
found_guilty_entry(ent);
origin_decref(suspect);
if (DEBUG) /* sanity */
sanity_check_refcnt(sb);
}
}
static const char *format_time(unsigned long time, const char *tz_str,
int show_raw_time)
{
static char time_buf[128];
time_t t = time;
int minutes, tz;
struct tm *tm;
if (show_raw_time) {
sprintf(time_buf, "%lu %s", time, tz_str);
return time_buf;
}
tz = atoi(tz_str);
minutes = tz < 0 ? -tz : tz;
minutes = (minutes / 100)*60 + (minutes % 100);
minutes = tz < 0 ? -minutes : minutes;
t = time + minutes * 60;
tm = gmtime(&t);
strftime(time_buf, sizeof(time_buf), "%Y-%m-%d %H:%M:%S ", tm);
strcat(time_buf, tz_str);
return time_buf;
}
#define OUTPUT_ANNOTATE_COMPAT 001
#define OUTPUT_LONG_OBJECT_NAME 002
#define OUTPUT_RAW_TIMESTAMP 004
@@ -1279,13 +1320,13 @@ static void emit_porcelain(struct scoreboard *sb, struct blame_entry *ent)
printf("committer-mail %s\n", ci.committer_mail);
printf("committer-time %lu\n", ci.committer_time);
printf("committer-tz %s\n", ci.committer_tz);
printf("filename %s\n", suspect->path);
write_filename_info(suspect->path);
printf("summary %s\n", ci.summary);
if (suspect->commit->object.flags & UNINTERESTING)
printf("boundary\n");
}
else if (suspect->commit->object.flags & MORE_THAN_ONE_PATH)
printf("filename %s\n", suspect->path);
write_filename_info(suspect->path);
cp = nth_line(sb, ent->lno);
for (cnt = 0; cnt < ent->num_lines; cnt++) {
@@ -1717,6 +1758,8 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
die("More than one '-L n,m' option given");
bottomtop = arg;
}
else if (!strcmp("--incremental", arg))
incremental = 1;
else if (!strcmp("--score-debug", arg))
output_option |= OUTPUT_SHOW_SCORE;
else if (!strcmp("-f", arg) ||
@@ -1907,6 +1950,9 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
assign_blame(&sb, &revs, opt);
if (incremental)
return 0;
coalesce(&sb);
if (!(output_option & OUTPUT_PORCELAIN))

View File

@@ -381,7 +381,8 @@ static void rename_branch(const char *oldname, const char *newname, int force)
if (rename_ref(oldref, newref, logmsg))
die("Branch rename failed");
if (!strcmp(oldname, head) && create_symref("HEAD", newref))
/* no need to pass logmsg here as HEAD didn't really move */
if (!strcmp(oldname, head) && create_symref("HEAD", newref, NULL))
die("Branch renamed to %s, but HEAD is not updated!", newname);
}
@@ -394,7 +395,6 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
int kinds = REF_LOCAL_BRANCH;
int i;
setup_ident();
git_config(git_branch_config);
for (i = 1; i < argc; i++) {

View File

@@ -94,7 +94,6 @@ int cmd_commit_tree(int argc, const char **argv, const char *prefix)
unsigned int size;
int encoding_is_utf8;
setup_ident();
git_config(git_default_config);
if (argc < 2)

View File

@@ -91,6 +91,39 @@ static int compare_pt(const void *a_, const void *b_)
return 0;
}
static unsigned long finish_depth_computation(
struct commit_list **list,
struct possible_tag *best)
{
unsigned long seen_commits = 0;
while (*list) {
struct commit *c = pop_commit(list);
struct commit_list *parents = c->parents;
seen_commits++;
if (c->object.flags & best->flag_within) {
struct commit_list *a = *list;
while (a) {
struct commit *i = a->item;
if (!(i->object.flags & best->flag_within))
break;
a = a->next;
}
if (!a)
break;
} else
best->depth++;
while (parents) {
struct commit *p = parents->item;
parse_commit(p);
if (!(p->object.flags & SEEN))
insert_by_date(p, list);
p->object.flags |= c->object.flags;
parents = parents->next;
}
}
return seen_commits;
}
static void describe(const char *arg, int last_one)
{
unsigned char sha1[20];
@@ -166,12 +199,19 @@ static void describe(const char *arg, int last_one)
parents = parents->next;
}
}
free_commit_list(list);
if (!match_cnt)
die("cannot describe '%s'", sha1_to_hex(cmit->object.sha1));
qsort(all_matches, match_cnt, sizeof(all_matches[0]), compare_pt);
if (gave_up_on) {
insert_by_date(gave_up_on, &list);
seen_commits--;
}
seen_commits += finish_depth_computation(&list, &all_matches[0]);
free_commit_list(list);
if (debug) {
for (cur_match = 0; cur_match < match_cnt; cur_match++) {
struct possible_tag *t = &all_matches[cur_match];
@@ -191,8 +231,9 @@ static void describe(const char *arg, int last_one)
if (abbrev == 0)
printf("%s\n", all_matches[0].name->path );
else
printf("%s-g%s\n", all_matches[0].name->path,
find_unique_abbrev(cmit->object.sha1, abbrev));
printf("%s-%d-g%s\n", all_matches[0].name->path,
all_matches[0].depth,
find_unique_abbrev(cmit->object.sha1, abbrev));
if (!last_one)
clear_commit_marks(cmit, -1);

View File

@@ -231,7 +231,7 @@ static int create_default_files(const char *git_dir, const char *template_path)
strcpy(path + len, "HEAD");
reinit = !read_ref("HEAD", sha1);
if (!reinit) {
if (create_symref("HEAD", "refs/heads/master") < 0)
if (create_symref("HEAD", "refs/heads/master", NULL) < 0)
exit(1);
}

View File

@@ -380,7 +380,6 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
char message_id[1024];
char ref_message_id[1024];
setup_ident();
git_config(git_format_config);
init_revisions(&rev, prefix);
rev.commit_format = CMIT_FMT_EMAIL;

View File

@@ -242,7 +242,7 @@ static int expire_reflog(const char *ref, const unsigned char *sha1, int unused,
struct cmd_reflog_expire_cb *cmd = cb_data;
struct expire_reflog_cb cb;
struct ref_lock *lock;
char *newlog_path = NULL;
char *log_file, *newlog_path = NULL;
int status = 0;
if (strncmp(ref, "refs/", 5))
@@ -255,7 +255,8 @@ static int expire_reflog(const char *ref, const unsigned char *sha1, int unused,
lock = lock_ref_sha1(ref + 5, sha1);
if (!lock)
return error("cannot lock ref '%s'", ref);
if (!file_exists(lock->log_file))
log_file = xstrdup(git_path("logs/%s", ref));
if (!file_exists(log_file))
goto finish;
if (!cmd->dry_run) {
newlog_path = xstrdup(git_path("logs/%s.lock", ref));
@@ -271,13 +272,14 @@ static int expire_reflog(const char *ref, const unsigned char *sha1, int unused,
if (fclose(cb.newlog))
status |= error("%s: %s", strerror(errno),
newlog_path);
if (rename(newlog_path, lock->log_file)) {
if (rename(newlog_path, log_file)) {
status |= error("cannot rename %s to %s",
newlog_path, lock->log_file);
newlog_path, log_file);
unlink(newlog_path);
}
}
free(newlog_path);
free(log_file);
unlock_ref(lock);
return status;
}

View File

@@ -3,7 +3,7 @@
#include "refs.h"
static const char git_symbolic_ref_usage[] =
"git-symbolic-ref [-q] name [ref]";
"git-symbolic-ref [-q] [-m <reason>] name [ref]";
static void check_symref(const char *HEAD, int quiet)
{
@@ -25,6 +25,7 @@ static void check_symref(const char *HEAD, int quiet)
int cmd_symbolic_ref(int argc, const char **argv, const char *prefix)
{
int quiet = 0;
const char *msg = NULL;
git_config(git_default_config);
@@ -34,6 +35,17 @@ int cmd_symbolic_ref(int argc, const char **argv, const char *prefix)
break;
else if (!strcmp("-q", arg))
quiet = 1;
else if (!strcmp("-m", arg)) {
argc--;
argv++;
if (argc <= 1)
break;
msg = argv[1];
if (!*msg)
die("Refusing to perform update with empty message");
if (strchr(msg, '\n'))
die("Refusing to perform update with \\n in message");
}
else if (!strcmp("--", arg)) {
argc--;
argv++;
@@ -50,7 +62,7 @@ int cmd_symbolic_ref(int argc, const char **argv, const char *prefix)
check_symref(argv[1], quiet);
break;
case 3:
create_symref(argv[1], argv[2]);
create_symref(argv[1], argv[2], msg);
break;
default:
usage(git_symbolic_ref_usage);

View File

@@ -13,7 +13,6 @@ int cmd_update_ref(int argc, const char **argv, const char *prefix)
int i, delete;
delete = 0;
setup_ident();
git_config(git_default_config);
for (i = 1; i < argc; i++) {

View File

@@ -302,7 +302,7 @@ extern int read_ref(const char *filename, unsigned char *sha1);
extern const char *resolve_ref(const char *path, unsigned char *sha1, int, int *);
extern int dwim_ref(const char *str, int len, unsigned char *sha1, char **ref);
extern int create_symref(const char *ref, const char *refs_heads_master);
extern int create_symref(const char *ref, const char *refs_heads_master, const char *logmsg);
extern int validate_headref(const char *ref);
extern int base_name_compare(const char *name1, int len1, int mode1, const char *name2, int len2, int mode2);
@@ -319,7 +319,6 @@ int parse_date(const char *date, char *buf, int bufsize);
void datestamp(char *buf, int bufsize);
unsigned long approxidate(const char *);
extern int setup_ident(void);
extern const char *git_author_info(int);
extern const char *git_committer_info(int);

View File

@@ -670,7 +670,6 @@ int main(int argc, char **argv)
struct stat st;
setup_git_directory();
setup_ident();
git_config(fetch_pack_config);
if (0 <= transfer_unpack_limit)

View File

@@ -257,7 +257,7 @@ if [ "$?" -eq 0 ]; then
fi
if test -n "$branch"
then
GIT_DIR="$GIT_DIR" git-symbolic-ref HEAD "refs/heads/$branch"
GIT_DIR="$GIT_DIR" git-symbolic-ref -m "checkout: moving to $branch" HEAD "refs/heads/$branch"
elif test -n "$detached"
then
# NEEDSWORK: we would want a command to detach the HEAD
@@ -266,8 +266,9 @@ if [ "$?" -eq 0 ]; then
# git update-ref --detach HEAD $new
# or something like that...
#
echo "$detached" >"$GIT_DIR/HEAD.new" &&
mv "$GIT_DIR/HEAD.new" "$GIT_DIR/HEAD" ||
git-rev-parse HEAD >"$GIT_DIR/HEAD.new" &&
mv "$GIT_DIR/HEAD.new" "$GIT_DIR/HEAD" &&
git-update-ref -m "checkout: moving to $arg" HEAD "$detached" ||
die "Cannot detach HEAD"
if test -n "$detach_warn"
then

View File

@@ -112,7 +112,9 @@ git-check-ref-format "tags/$name" ||
object=$(git-rev-parse --verify --default HEAD "$@") || exit 1
type=$(git-cat-file -t $object) || exit 1
tagger=$(git-var GIT_COMMITTER_IDENT) || exit 1
: ${username:=$(expr "z$tagger" : 'z\(.*>\)')}
keyid=$(git-repo-config user.signingkey) ||
keyid=$(expr "z$tagger" : 'z\(.*>\)')
trap 'rm -f "$GIT_DIR"/TAG_TMP* "$GIT_DIR"/TAG_FINALMSG "$GIT_DIR"/TAG_EDITMSG' 0
@@ -139,7 +141,7 @@ if [ "$annotate" ]; then
cat "$GIT_DIR"/TAG_FINALMSG ) >"$GIT_DIR"/TAG_TMP
rm -f "$GIT_DIR"/TAG_TMP.asc "$GIT_DIR"/TAG_FINALMSG
if [ "$signed" ]; then
gpg -bsa -u "$username" "$GIT_DIR"/TAG_TMP &&
gpg -bsa -u "$keyid" "$GIT_DIR"/TAG_TMP &&
cat "$GIT_DIR"/TAG_TMP.asc >>"$GIT_DIR"/TAG_TMP ||
die "failed to sign the tag with GPG."
fi

View File

@@ -1003,7 +1003,6 @@ int main(int argc, const char **argv)
int arg = 1;
int rc = 0;
setup_ident();
setup_git_directory();
git_config(git_default_config);

View File

@@ -2299,7 +2299,6 @@ int main(int argc, char **argv)
struct ref *ref;
setup_git_directory();
setup_ident();
remote = xcalloc(sizeof(*remote), 1);

51
ident.c
View File

@@ -43,19 +43,13 @@ static void copy_gecos(struct passwd *w, char *name, int sz)
}
int setup_ident(void)
static void copy_email(struct passwd *pw)
{
int len;
struct passwd *pw = getpwuid(getuid());
if (!pw)
die("You don't exist. Go away!");
/* Get the name ("gecos") */
copy_gecos(pw, git_default_name, sizeof(git_default_name));
/* Make up a fake email address (name + '@' + hostname [+ '.' + domainname]) */
len = strlen(pw->pw_name);
/*
* Make up a fake email address
* (name + '@' + hostname [+ '.' + domainname])
*/
int len = strlen(pw->pw_name);
if (len > sizeof(git_default_email)/2)
die("Your sysadmin must hate you!");
memcpy(git_default_email, pw->pw_name, len);
@@ -68,13 +62,37 @@ int setup_ident(void)
len = strlen(git_default_email);
git_default_email[len++] = '.';
if (he && (domainname = strchr(he->h_name, '.')))
strlcpy(git_default_email + len, domainname + 1, sizeof(git_default_email) - len);
strlcpy(git_default_email + len, domainname + 1,
sizeof(git_default_email) - len);
else
strlcpy(git_default_email + len, "(none)", sizeof(git_default_email) - len);
strlcpy(git_default_email + len, "(none)",
sizeof(git_default_email) - len);
}
}
static void setup_ident(void)
{
struct passwd *pw = NULL;
/* Get the name ("gecos") */
if (!git_default_name[0]) {
pw = getpwuid(getuid());
if (!pw)
die("You don't exist. Go away!");
copy_gecos(pw, git_default_name, sizeof(git_default_name));
}
if (!git_default_email[0]) {
if (!pw)
pw = getpwuid(getuid());
if (!pw)
die("You don't exist. Go away!");
copy_email(pw);
}
/* And set the default date */
datestamp(git_default_date, sizeof(git_default_date));
return 0;
if (!git_default_date[0])
datestamp(git_default_date, sizeof(git_default_date));
}
static int add_raw(char *buf, int size, int offset, const char *str)
@@ -174,6 +192,7 @@ static const char *get_ident(const char *name, const char *email,
char date[50];
int i;
setup_ident();
if (!name)
name = git_default_name;
if (!email)

View File

@@ -210,7 +210,6 @@ int main(int argc, const char **argv)
char **commit_id;
int arg = 1;
setup_ident();
setup_git_directory();
git_config(git_default_config);

View File

@@ -224,9 +224,14 @@ void show_log(struct rev_info *opt, const char *sep)
printf("%s",
diff_get_color(opt->diffopt.color_diff, DIFF_RESET));
putchar(opt->commit_format == CMIT_FMT_ONELINE ? ' ' : '\n');
if (opt->reflog_info)
if (opt->reflog_info) {
show_reflog_message(opt->reflog_info,
opt->commit_format == CMIT_FMT_ONELINE);;
if (opt->commit_format == CMIT_FMT_ONELINE) {
printf("%s", sep);
return;
}
}
}
/*

View File

@@ -429,7 +429,6 @@ int main(int argc, char **argv)
if (is_repository_shallow())
die("attempt to push into a shallow repository");
setup_ident();
git_config(receive_pack_config);
if (0 <= transfer_unpack_limit)

View File

@@ -233,7 +233,7 @@ void show_reflog_message(struct reflog_walk_info* info, int oneline)
else
printf("%d", commit_reflog->reflogs->nr
- 2 - commit_reflog->recno);
printf("}: ");
printf("}: %s", info->message);
}
else {
printf("Reflog: %s@{", commit_reflog->reflogs->ref);

151
refs.c
View File

@@ -309,53 +309,6 @@ const char *resolve_ref(const char *ref, unsigned char *sha1, int reading, int *
return ref;
}
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) {
unlink(git_HEAD);
if (!symlink(refs_heads_master, git_HEAD))
return 0;
fprintf(stderr, "no symlink - falling back to symbolic ref\n");
}
#endif
len = snprintf(ref, sizeof(ref), "ref: %s\n", refs_heads_master);
if (sizeof(ref) <= len) {
error("refname too long: %s", refs_heads_master);
return -1;
}
lockpath = mkpath("%s.lock", git_HEAD);
fd = open(lockpath, O_CREAT | O_EXCL | O_WRONLY, 0666);
if (fd < 0) {
error("Unable to open %s for writing", lockpath);
return -5;
}
written = write_in_full(fd, ref, len);
close(fd);
if (written != len) {
unlink(lockpath);
error("Unable to write to %s", lockpath);
return -2;
}
if (rename(lockpath, git_HEAD) < 0) {
unlink(lockpath);
error("Unable to create %s", git_HEAD);
return -3;
}
if (adjust_shared_perm(git_HEAD)) {
unlink(lockpath);
error("Unable to fix permissions on %s", lockpath);
return -4;
}
return 0;
}
int read_ref(const char *ref, unsigned char *sha1)
{
if (resolve_ref(ref, sha1, 1, NULL))
@@ -680,7 +633,7 @@ static struct ref_lock *lock_ref_sha1_basic(const char *ref, const unsigned char
lock->lk = xcalloc(1, sizeof(struct lock_file));
lock->ref_name = xstrdup(ref);
lock->log_file = xstrdup(git_path("logs/%s", ref));
lock->orig_ref_name = xstrdup(orig_ref);
ref_file = git_path("%s", ref);
lock->force_write = lstat(ref_file, &st) && errno == ENOENT;
@@ -776,10 +729,10 @@ int delete_ref(const char *refname, unsigned char *sha1)
*/
ret |= repack_without_ref(refname);
err = unlink(lock->log_file);
err = unlink(git_path("logs/%s", lock->ref_name));
if (err && errno != ENOENT)
fprintf(stderr, "warning: unlink(%s) failed: %s",
lock->log_file, strerror(errno));
git_path("logs/%s", lock->ref_name), strerror(errno));
invalidate_cached_refs();
unlock_ref(lock);
return ret;
@@ -920,47 +873,50 @@ void unlock_ref(struct ref_lock *lock)
rollback_lock_file(lock->lk);
}
free(lock->ref_name);
free(lock->log_file);
free(lock->orig_ref_name);
free(lock);
}
static int log_ref_write(struct ref_lock *lock,
const unsigned char *sha1, const char *msg)
static int log_ref_write(const char *ref_name, const unsigned char *old_sha1,
const unsigned char *new_sha1, const char *msg)
{
int logfd, written, oflags = O_APPEND | O_WRONLY;
unsigned maxlen, len;
int msglen;
char *logrec;
char *log_file, *logrec;
const char *committer;
if (log_all_ref_updates < 0)
log_all_ref_updates = !is_bare_repository();
log_file = git_path("logs/%s", ref_name);
if (log_all_ref_updates &&
(!strncmp(lock->ref_name, "refs/heads/", 11) ||
!strncmp(lock->ref_name, "refs/remotes/", 13))) {
if (safe_create_leading_directories(lock->log_file) < 0)
(!strncmp(ref_name, "refs/heads/", 11) ||
!strncmp(ref_name, "refs/remotes/", 13) ||
!strcmp(ref_name, "HEAD"))) {
if (safe_create_leading_directories(log_file) < 0)
return error("unable to create directory for %s",
lock->log_file);
log_file);
oflags |= O_CREAT;
}
logfd = open(lock->log_file, oflags, 0666);
logfd = open(log_file, oflags, 0666);
if (logfd < 0) {
if (!(oflags & O_CREAT) && errno == ENOENT)
return 0;
if ((oflags & O_CREAT) && errno == EISDIR) {
if (remove_empty_directories(lock->log_file)) {
if (remove_empty_directories(log_file)) {
return error("There are still logs under '%s'",
lock->log_file);
log_file);
}
logfd = open(lock->log_file, oflags, 0666);
logfd = open(log_file, oflags, 0666);
}
if (logfd < 0)
return error("Unable to append to %s: %s",
lock->log_file, strerror(errno));
log_file, strerror(errno));
}
msglen = 0;
@@ -982,8 +938,8 @@ static int log_ref_write(struct ref_lock *lock,
maxlen = strlen(committer) + msglen + 100;
logrec = xmalloc(maxlen);
len = sprintf(logrec, "%s %s %s\n",
sha1_to_hex(lock->old_sha1),
sha1_to_hex(sha1),
sha1_to_hex(old_sha1),
sha1_to_hex(new_sha1),
committer);
if (msglen)
len += sprintf(logrec + len - 1, "\t%.*s\n", msglen, msg) - 1;
@@ -991,7 +947,7 @@ static int log_ref_write(struct ref_lock *lock,
free(logrec);
close(logfd);
if (written != len)
return error("Unable to append to %s", lock->log_file);
return error("Unable to append to %s", log_file);
return 0;
}
@@ -1014,7 +970,9 @@ int write_ref_sha1(struct ref_lock *lock,
return -1;
}
invalidate_cached_refs();
if (log_ref_write(lock, sha1, logmsg) < 0) {
if (log_ref_write(lock->ref_name, lock->old_sha1, sha1, logmsg) < 0 ||
(strcmp(lock->ref_name, lock->orig_ref_name) &&
log_ref_write(lock->orig_ref_name, lock->old_sha1, sha1, logmsg) < 0)) {
unlock_ref(lock);
return -1;
}
@@ -1028,6 +986,65 @@ int write_ref_sha1(struct ref_lock *lock,
return 0;
}
int create_symref(const char *ref_target, const char *refs_heads_master,
const char *logmsg)
{
const char *lockpath;
char ref[1000];
int fd, len, written;
char *git_HEAD = xstrdup(git_path("%s", ref_target));
unsigned char old_sha1[20], new_sha1[20];
if (logmsg && read_ref(ref_target, old_sha1))
hashclr(old_sha1);
#ifndef NO_SYMLINK_HEAD
if (prefer_symlink_refs) {
unlink(git_HEAD);
if (!symlink(refs_heads_master, git_HEAD))
goto done;
fprintf(stderr, "no symlink - falling back to symbolic ref\n");
}
#endif
len = snprintf(ref, sizeof(ref), "ref: %s\n", refs_heads_master);
if (sizeof(ref) <= len) {
error("refname too long: %s", refs_heads_master);
goto error_free_return;
}
lockpath = mkpath("%s.lock", git_HEAD);
fd = open(lockpath, O_CREAT | O_EXCL | O_WRONLY, 0666);
if (fd < 0) {
error("Unable to open %s for writing", lockpath);
goto error_free_return;
}
written = write_in_full(fd, ref, len);
close(fd);
if (written != len) {
error("Unable to write to %s", lockpath);
goto error_unlink_return;
}
if (rename(lockpath, git_HEAD) < 0) {
error("Unable to create %s", git_HEAD);
goto error_unlink_return;
}
if (adjust_shared_perm(git_HEAD)) {
error("Unable to fix permissions on %s", lockpath);
error_unlink_return:
unlink(lockpath);
error_free_return:
free(git_HEAD);
return -1;
}
done:
if (logmsg && !read_ref(refs_heads_master, new_sha1))
log_ref_write(ref_target, old_sha1, new_sha1, logmsg);
free(git_HEAD);
return 0;
}
static char *ref_msg(const char *line, const char *endp)
{
const char *ep;

2
refs.h
View File

@@ -3,7 +3,7 @@
struct ref_lock {
char *ref_name;
char *log_file;
char *orig_ref_name;
struct lock_file *lk;
unsigned char old_sha1[20];
int lock_fd;

View File

@@ -124,7 +124,6 @@ int main(int argc, char **argv)
prog = getenv("GIT_SSH_PUSH");
if (!prog) prog = "git-ssh-upload";
setup_ident();
setup_git_directory();
git_config(git_default_config);

1
var.c
View File

@@ -56,7 +56,6 @@ int main(int argc, char **argv)
}
setup_git_directory();
setup_ident();
val = NULL;
if (strcmp(argv[1], "-l") == 0) {