mirror of
https://github.com/git/git.git
synced 2026-03-13 18:33:25 +01:00
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:
@@ -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.
|
||||
|
||||
@@ -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].
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
--------------
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>,
|
||||
|
||||
182
builtin-blame.c
182
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))
|
||||
|
||||
@@ -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++) {
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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++) {
|
||||
|
||||
3
cache.h
3
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);
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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
51
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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
151
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;
|
||||
|
||||
2
refs.h
2
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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user