diff --git a/Documentation/SubmittingPatches b/Documentation/SubmittingPatches index 41b76d8a4a..ce85d06c62 100644 --- a/Documentation/SubmittingPatches +++ b/Documentation/SubmittingPatches @@ -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. diff --git a/Documentation/config.txt b/Documentation/config.txt index 3f2fa09a87..6ea7c76a6a 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -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]. diff --git a/Documentation/diff-options.txt b/Documentation/diff-options.txt index da1cc60e97..019a39f2bf 100644 --- a/Documentation/diff-options.txt +++ b/Documentation/diff-options.txt @@ -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" diff --git a/Documentation/git-describe.txt b/Documentation/git-describe.txt index b87783cf09..47a583d3a6 100644 --- a/Documentation/git-describe.txt +++ b/Documentation/git-describe.txt @@ -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 , but somewhat -butchered by Junio C Hamano +butchered by Junio C Hamano . Later significantly +updated by Shawn Pearce . Documentation -------------- diff --git a/Documentation/git-symbolic-ref.txt b/Documentation/git-symbolic-ref.txt index f93b79a85e..a88f722860 100644 --- a/Documentation/git-symbolic-ref.txt +++ b/Documentation/git-symbolic-ref.txt @@ -7,7 +7,7 @@ git-symbolic-ref - Read and modify symbolic refs SYNOPSIS -------- -'git-symbolic-ref' [-q] [] +'git-symbolic-ref' [-q] [-m ] [] DESCRIPTION ----------- @@ -31,6 +31,10 @@ OPTIONS symbolic ref but a detached HEAD; instead exit with non-zero status silently. +-m:: + Update the reflog for with . This is valid only + when creating or updating a symbolic ref. + NOTES ----- In the past, `.git/HEAD` was a symbolic link pointing at diff --git a/Documentation/git-tag.txt b/Documentation/git-tag.txt index 13c7aefbf3..3f01e0bfc5 100644 --- a/Documentation/git-tag.txt +++ b/Documentation/git-tag.txt @@ -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 ") 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 = + Author ------ Written by Linus Torvalds , diff --git a/builtin-blame.c b/builtin-blame.c index 4a1accf13c..7a58ee303f 100644 --- a/builtin-blame.c +++ b/builtin-blame.c @@ -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)) diff --git a/builtin-branch.c b/builtin-branch.c index 8cac2deaca..869e753a71 100644 --- a/builtin-branch.c +++ b/builtin-branch.c @@ -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++) { diff --git a/builtin-commit-tree.c b/builtin-commit-tree.c index 0651e5927e..2a818a0a2c 100644 --- a/builtin-commit-tree.c +++ b/builtin-commit-tree.c @@ -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) diff --git a/builtin-describe.c b/builtin-describe.c index f3ac2d5f89..bcc645622a 100644 --- a/builtin-describe.c +++ b/builtin-describe.c @@ -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); diff --git a/builtin-init-db.c b/builtin-init-db.c index 1865489381..12e43d0db4 100644 --- a/builtin-init-db.c +++ b/builtin-init-db.c @@ -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); } diff --git a/builtin-log.c b/builtin-log.c index 56acc137f0..982d871887 100644 --- a/builtin-log.c +++ b/builtin-log.c @@ -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; diff --git a/builtin-reflog.c b/builtin-reflog.c index ebe3070e55..7c2443a1db 100644 --- a/builtin-reflog.c +++ b/builtin-reflog.c @@ -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; } diff --git a/builtin-symbolic-ref.c b/builtin-symbolic-ref.c index 227c9d4a62..d41b40640b 100644 --- a/builtin-symbolic-ref.c +++ b/builtin-symbolic-ref.c @@ -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 ] 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); diff --git a/builtin-update-ref.c b/builtin-update-ref.c index b34e5987dd..1461937cb9 100644 --- a/builtin-update-ref.c +++ b/builtin-update-ref.c @@ -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++) { diff --git a/cache.h b/cache.h index 9486132ac5..201704bacf 100644 --- a/cache.h +++ b/cache.h @@ -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); diff --git a/fetch-pack.c b/fetch-pack.c index 83a1d7b319..c787106764 100644 --- a/fetch-pack.c +++ b/fetch-pack.c @@ -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) diff --git a/git-checkout.sh b/git-checkout.sh index 8ce48c3b4d..fb40cba275 100755 --- a/git-checkout.sh +++ b/git-checkout.sh @@ -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 diff --git a/git-tag.sh b/git-tag.sh index 94499c9b36..988bf4c6a6 100755 --- a/git-tag.sh +++ b/git-tag.sh @@ -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 diff --git a/http-fetch.c b/http-fetch.c index 67dfb0a033..efd494a47f 100644 --- a/http-fetch.c +++ b/http-fetch.c @@ -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); diff --git a/http-push.c b/http-push.c index 0a15f53782..b128c0146c 100644 --- a/http-push.c +++ b/http-push.c @@ -2299,7 +2299,6 @@ int main(int argc, char **argv) struct ref *ref; setup_git_directory(); - setup_ident(); remote = xcalloc(sizeof(*remote), 1); diff --git a/ident.c b/ident.c index f9677905e5..6de7eeae4d 100644 --- a/ident.c +++ b/ident.c @@ -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) diff --git a/local-fetch.c b/local-fetch.c index cf99cb72dd..7cfe8b3587 100644 --- a/local-fetch.c +++ b/local-fetch.c @@ -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); diff --git a/log-tree.c b/log-tree.c index c0fa096327..d8ca36bbdd 100644 --- a/log-tree.c +++ b/log-tree.c @@ -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; + } + } } /* diff --git a/receive-pack.c b/receive-pack.c index c4a475762d..c51f417aed 100644 --- a/receive-pack.c +++ b/receive-pack.c @@ -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) diff --git a/reflog-walk.c b/reflog-walk.c index 8e2cd2fcf6..82621601d6 100644 --- a/reflog-walk.c +++ b/reflog-walk.c @@ -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); diff --git a/refs.c b/refs.c index 12e46b8bbe..4a523086e3 100644 --- a/refs.c +++ b/refs.c @@ -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; diff --git a/refs.h b/refs.h index 33450f13e7..94a58b41fb 100644 --- a/refs.h +++ b/refs.h @@ -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; diff --git a/ssh-fetch.c b/ssh-fetch.c index 4c172b6824..bdf51a7a14 100644 --- a/ssh-fetch.c +++ b/ssh-fetch.c @@ -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); diff --git a/var.c b/var.c index 39977b949a..e585e59d31 100644 --- a/var.c +++ b/var.c @@ -56,7 +56,6 @@ int main(int argc, char **argv) } setup_git_directory(); - setup_ident(); val = NULL; if (strcmp(argv[1], "-l") == 0) {