Refactor "tracking statistics" code used by "git checkout"
People seem to like "Your branch is ahead by N commit" report made by "git checkout", but the interface into the statistics function was a bit clunky. This splits the function into three parts: * The core "commit counting" function that takes "struct branch" and returns number of commits to show if we are ahead, behind or forked; * Convenience "stat formating" function that takes "struct branch" and formats the report into a given strbuf, using the above function; * "checkout" specific function that takes "branch_info" (type that is internal to checkout implementation), calls the above function and print the formatted result. in the hope that the former two can be more easily reusable. Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
parent
6cbf8b00fb
commit
6d21bf96b5
@ -305,97 +305,15 @@ static int merge_working_tree(struct checkout_opts *opts,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void report_tracking(struct branch_info *new, struct checkout_opts *opts)
|
static void report_tracking(struct branch_info *new)
|
||||||
{
|
{
|
||||||
/*
|
struct strbuf sb = STRBUF_INIT;
|
||||||
* We have switched to a new branch; is it building on
|
|
||||||
* top of another branch, and if so does that other branch
|
|
||||||
* have changes we do not have yet?
|
|
||||||
*/
|
|
||||||
char *base;
|
|
||||||
unsigned char sha1[20];
|
|
||||||
struct commit *ours, *theirs;
|
|
||||||
char symmetric[84];
|
|
||||||
struct rev_info revs;
|
|
||||||
const char *rev_argv[10];
|
|
||||||
int rev_argc;
|
|
||||||
int num_ours, num_theirs;
|
|
||||||
const char *remote_msg;
|
|
||||||
struct branch *branch = branch_get(new->name);
|
struct branch *branch = branch_get(new->name);
|
||||||
|
|
||||||
/*
|
if (!format_tracking_info(branch, &sb))
|
||||||
* Nothing to report unless we are marked to build on top of
|
|
||||||
* somebody else.
|
|
||||||
*/
|
|
||||||
if (!branch || !branch->merge || !branch->merge[0] || !branch->merge[0]->dst)
|
|
||||||
return;
|
return;
|
||||||
|
fputs(sb.buf, stdout);
|
||||||
/*
|
strbuf_release(&sb);
|
||||||
* If what we used to build on no longer exists, there is
|
|
||||||
* nothing to report.
|
|
||||||
*/
|
|
||||||
base = branch->merge[0]->dst;
|
|
||||||
if (!resolve_ref(base, sha1, 1, NULL))
|
|
||||||
return;
|
|
||||||
|
|
||||||
theirs = lookup_commit(sha1);
|
|
||||||
ours = new->commit;
|
|
||||||
if (!hashcmp(sha1, ours->object.sha1))
|
|
||||||
return; /* we are the same */
|
|
||||||
|
|
||||||
/* Run "rev-list --left-right ours...theirs" internally... */
|
|
||||||
rev_argc = 0;
|
|
||||||
rev_argv[rev_argc++] = NULL;
|
|
||||||
rev_argv[rev_argc++] = "--left-right";
|
|
||||||
rev_argv[rev_argc++] = symmetric;
|
|
||||||
rev_argv[rev_argc++] = "--";
|
|
||||||
rev_argv[rev_argc] = NULL;
|
|
||||||
|
|
||||||
strcpy(symmetric, sha1_to_hex(ours->object.sha1));
|
|
||||||
strcpy(symmetric + 40, "...");
|
|
||||||
strcpy(symmetric + 43, sha1_to_hex(theirs->object.sha1));
|
|
||||||
|
|
||||||
init_revisions(&revs, NULL);
|
|
||||||
setup_revisions(rev_argc, rev_argv, &revs, NULL);
|
|
||||||
prepare_revision_walk(&revs);
|
|
||||||
|
|
||||||
/* ... and count the commits on each side. */
|
|
||||||
num_ours = 0;
|
|
||||||
num_theirs = 0;
|
|
||||||
while (1) {
|
|
||||||
struct commit *c = get_revision(&revs);
|
|
||||||
if (!c)
|
|
||||||
break;
|
|
||||||
if (c->object.flags & SYMMETRIC_LEFT)
|
|
||||||
num_ours++;
|
|
||||||
else
|
|
||||||
num_theirs++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!prefixcmp(base, "refs/remotes/")) {
|
|
||||||
remote_msg = " remote";
|
|
||||||
base += strlen("refs/remotes/");
|
|
||||||
} else {
|
|
||||||
remote_msg = "";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!num_theirs)
|
|
||||||
printf("Your branch is ahead of the tracked%s branch '%s' "
|
|
||||||
"by %d commit%s.\n",
|
|
||||||
remote_msg, base,
|
|
||||||
num_ours, (num_ours == 1) ? "" : "s");
|
|
||||||
else if (!num_ours)
|
|
||||||
printf("Your branch is behind the tracked%s branch '%s' "
|
|
||||||
"by %d commit%s,\n"
|
|
||||||
"and can be fast-forwarded.\n",
|
|
||||||
remote_msg, base,
|
|
||||||
num_theirs, (num_theirs == 1) ? "" : "s");
|
|
||||||
else
|
|
||||||
printf("Your branch and the tracked%s branch '%s' "
|
|
||||||
"have diverged,\nand respectively "
|
|
||||||
"have %d and %d different commit(s) each.\n",
|
|
||||||
remote_msg, base,
|
|
||||||
num_ours, num_theirs);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void update_refs_for_switch(struct checkout_opts *opts,
|
static void update_refs_for_switch(struct checkout_opts *opts,
|
||||||
@ -441,7 +359,7 @@ static void update_refs_for_switch(struct checkout_opts *opts,
|
|||||||
remove_branch_state();
|
remove_branch_state();
|
||||||
strbuf_release(&msg);
|
strbuf_release(&msg);
|
||||||
if (!opts->quiet && (new->path || !strcmp(new->name, "HEAD")))
|
if (!opts->quiet && (new->path || !strcmp(new->name, "HEAD")))
|
||||||
report_tracking(new, opts);
|
report_tracking(new);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int switch_branches(struct checkout_opts *opts, struct branch_info *new)
|
static int switch_branches(struct checkout_opts *opts, struct branch_info *new)
|
||||||
|
113
remote.c
113
remote.c
@ -1,6 +1,9 @@
|
|||||||
#include "cache.h"
|
#include "cache.h"
|
||||||
#include "remote.h"
|
#include "remote.h"
|
||||||
#include "refs.h"
|
#include "refs.h"
|
||||||
|
#include "commit.h"
|
||||||
|
#include "diff.h"
|
||||||
|
#include "revision.h"
|
||||||
|
|
||||||
static struct refspec s_tag_refspec = {
|
static struct refspec s_tag_refspec = {
|
||||||
0,
|
0,
|
||||||
@ -1222,3 +1225,113 @@ int resolve_remote_symref(struct ref *ref, struct ref *list)
|
|||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return true if there is anything to report, otherwise false.
|
||||||
|
*/
|
||||||
|
int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs)
|
||||||
|
{
|
||||||
|
unsigned char sha1[20];
|
||||||
|
struct commit *ours, *theirs;
|
||||||
|
char symmetric[84];
|
||||||
|
struct rev_info revs;
|
||||||
|
const char *rev_argv[10], *base;
|
||||||
|
int rev_argc;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Nothing to report unless we are marked to build on top of
|
||||||
|
* somebody else.
|
||||||
|
*/
|
||||||
|
if (!branch ||
|
||||||
|
!branch->merge || !branch->merge[0] || !branch->merge[0]->dst)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If what we used to build on no longer exists, there is
|
||||||
|
* nothing to report.
|
||||||
|
*/
|
||||||
|
base = branch->merge[0]->dst;
|
||||||
|
if (!resolve_ref(base, sha1, 1, NULL))
|
||||||
|
return 0;
|
||||||
|
theirs = lookup_commit(sha1);
|
||||||
|
if (!theirs)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (!resolve_ref(branch->refname, sha1, 1, NULL))
|
||||||
|
return 0;
|
||||||
|
ours = lookup_commit(sha1);
|
||||||
|
if (!ours)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* are we the same? */
|
||||||
|
if (theirs == ours)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* Run "rev-list --left-right ours...theirs" internally... */
|
||||||
|
rev_argc = 0;
|
||||||
|
rev_argv[rev_argc++] = NULL;
|
||||||
|
rev_argv[rev_argc++] = "--left-right";
|
||||||
|
rev_argv[rev_argc++] = symmetric;
|
||||||
|
rev_argv[rev_argc++] = "--";
|
||||||
|
rev_argv[rev_argc] = NULL;
|
||||||
|
|
||||||
|
strcpy(symmetric, sha1_to_hex(ours->object.sha1));
|
||||||
|
strcpy(symmetric + 40, "...");
|
||||||
|
strcpy(symmetric + 43, sha1_to_hex(theirs->object.sha1));
|
||||||
|
|
||||||
|
init_revisions(&revs, NULL);
|
||||||
|
setup_revisions(rev_argc, rev_argv, &revs, NULL);
|
||||||
|
prepare_revision_walk(&revs);
|
||||||
|
|
||||||
|
/* ... and count the commits on each side. */
|
||||||
|
*num_ours = 0;
|
||||||
|
*num_theirs = 0;
|
||||||
|
while (1) {
|
||||||
|
struct commit *c = get_revision(&revs);
|
||||||
|
if (!c)
|
||||||
|
break;
|
||||||
|
if (c->object.flags & SYMMETRIC_LEFT)
|
||||||
|
(*num_ours)++;
|
||||||
|
else
|
||||||
|
(*num_theirs)++;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return true when there is anything to report, otherwise false.
|
||||||
|
*/
|
||||||
|
int format_tracking_info(struct branch *branch, struct strbuf *sb)
|
||||||
|
{
|
||||||
|
int num_ours, num_theirs;
|
||||||
|
const char *base, *remote_msg;
|
||||||
|
|
||||||
|
if (!stat_tracking_info(branch, &num_ours, &num_theirs))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
base = branch->merge[0]->dst;
|
||||||
|
if (!prefixcmp(base, "refs/remotes/")) {
|
||||||
|
remote_msg = " remote";
|
||||||
|
base += strlen("refs/remotes/");
|
||||||
|
} else {
|
||||||
|
remote_msg = "";
|
||||||
|
}
|
||||||
|
if (!num_theirs)
|
||||||
|
strbuf_addf(sb, "Your branch is ahead of the tracked%s branch '%s' "
|
||||||
|
"by %d commit%s.\n",
|
||||||
|
remote_msg, base,
|
||||||
|
num_ours, (num_ours == 1) ? "" : "s");
|
||||||
|
else if (!num_ours)
|
||||||
|
strbuf_addf(sb, "Your branch is behind the tracked%s branch '%s' "
|
||||||
|
"by %d commit%s,\n"
|
||||||
|
"and can be fast-forwarded.\n",
|
||||||
|
remote_msg, base,
|
||||||
|
num_theirs, (num_theirs == 1) ? "" : "s");
|
||||||
|
else
|
||||||
|
strbuf_addf(sb, "Your branch and the tracked%s branch '%s' "
|
||||||
|
"have diverged,\nand respectively "
|
||||||
|
"have %d and %d different commit(s) each.\n",
|
||||||
|
remote_msg, base,
|
||||||
|
num_ours, num_theirs);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
4
remote.h
4
remote.h
@ -129,4 +129,8 @@ enum match_refs_flags {
|
|||||||
MATCH_REFS_MIRROR = (1 << 1),
|
MATCH_REFS_MIRROR = (1 << 1),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Reporting of tracking info */
|
||||||
|
int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs);
|
||||||
|
int format_tracking_info(struct branch *branch, struct strbuf *sb);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
Reference in New Issue
Block a user