12
#include "branch.h"
13
#include "diff.h"
14
#include "revision.h"
15
+#include "remote.h"
16
17
static const char * const checkout_usage[] = {
18
"git checkout [options] <branch>",
291
return 0;
292
}
293
294
+/*
295
+ * We really should allow cb_data... Yuck
296
+ */
297
+static const char *branch_name;
298
+static int branch_name_len;
299
+static char *found_remote;
300
+static char *found_merge;
301
+static int read_branch_config(const char *var, const char *value)
302
+{
303
+ const char *name;
304
+ if (prefixcmp(var, "branch."))
305
+ return 0; /* not ours */
306
+ name = var + strlen("branch.");
307
+ if (strncmp(name, branch_name, branch_name_len) ||
308
+ name[branch_name_len] != '.')
309
+ return 0; /* not ours either */
310
+ if (!strcmp(name + branch_name_len, ".remote")) {
311
+ /*
312
+ * Yeah, I know Christian's clean-up should
313
+ * be used here, but the topic is based on an
314
+ * older fork point.
315
+ */
316
+ if (!value)
317
+ return error("'%s' not string", var);
318
+ found_remote = xstrdup(value);
319
+ return 0;
320
+ }
321
+ if (!strcmp(name + branch_name_len, ".merge")) {
322
+ if (!value)
323
+ return error("'%s' not string", var);
324
+ found_merge = xstrdup(value);
325
+ return 0;
326
+ }
327
+ return 0; /* not ours */
328
+}
329
+
330
+static int find_build_base(const char *ours, char **base)
331
+{
332
+ struct remote *remote;
333
+ struct refspec spec;
334
+
335
+ *base = NULL;
336
+
337
+ branch_name = ours + strlen("refs/heads/");
338
+ branch_name_len = strlen(branch_name);
339
+ found_remote = NULL;
340
+ found_merge = NULL;
341
+ git_config(read_branch_config);
342
+
343
+ if (!found_remote || !found_merge) {
344
+ cleanup:
345
+ free(found_remote);
346
+ free(found_merge);
347
+ return 0;
348
+ }
349
+
350
+ remote = remote_get(found_remote);
351
+ memset(&spec, 0, sizeof(spec));
352
+ spec.src = found_merge;
353
+ if (remote_find_tracking(remote, &spec))
354
+ goto cleanup;
355
+ *base = spec.dst;
356
+ return 1;
357
+}
358
+
359
+static void adjust_to_tracking(struct branch_info *new, struct checkout_opts *opts)
360
+{
361
+ /*
362
+ * We have switched to a new branch; is it building on
363
+ * top of another branch, and if so does that other branch
364
+ * have changes we do not have yet?
365
+ */
366
+ char *base;
367
+ unsigned char sha1[20];
368
+ struct commit *ours, *theirs;
369
+ const char *msgfmt;
370
+ char symmetric[84];
371
+ int show_log;
372
+
373
+ if (!resolve_ref(new->path, sha1, 1, NULL))
374
+ return;
375
+ ours = lookup_commit(sha1);
376
+
377
+ if (!find_build_base(new->path, &base))
378
+ return;
379
+
380
+ sprintf(symmetric, "%s", sha1_to_hex(sha1));
381
+
382
+ /*
383
+ * Ok, it is tracking base; is it ahead of us?
384
+ */
385
+ if (!resolve_ref(base, sha1, 1, NULL))
386
+ return;
387
+ theirs = lookup_commit(sha1);
388
+
389
+ sprintf(symmetric + 40, "...%s", sha1_to_hex(sha1));
390
+
391
+ if (!hashcmp(sha1, ours->object.sha1))
392
+ return; /* we are the same */
393
+
394
+ show_log = 1;
395
+ if (in_merge_bases(theirs, &ours, 1)) {
396
+ msgfmt = "You are ahead of the tracked branch '%s'\n";
397
+ show_log = 0;
398
+ }
399
+ else if (in_merge_bases(ours, &theirs, 1))
400
+ msgfmt = "Your branch can be fast-forwarded to the tracked branch '%s'\n";
401
+ else
402
+ msgfmt = "Both your branch and the tracked branch '%s' have own changes, you would eventually need to merge\n";
403
+
404
+ if (!prefixcmp(base, "refs/remotes/"))
405
+ base += strlen("refs/remotes/");
406
+ fprintf(stderr, msgfmt, base);
407
+
408
+ if (show_log) {
409
+ const char *args[32];
410
+ int ac;
411
+
412
+ ac = 0;
413
+ args[ac++] = "log";
414
+ args[ac++] = "--pretty=oneline";
415
+ args[ac++] = "--abbrev-commit";
416
+ args[ac++] = "--left-right";
417
+ args[ac++] = "--boundary";
418
+ args[ac++] = symmetric;
419
+ args[ac++] = "--";
420
+ args[ac] = NULL;
421
+
422
+ run_command_v_opt(args, RUN_GIT_CMD);
423
+ }
424
+}
425
+
426
+
427
static void update_refs_for_switch(struct checkout_opts *opts,
428
struct branch_info *old,
429
struct branch_info *new)
466
}
467
remove_branch_state();
468
strbuf_release(&msg);
469
+ if (new->path)
470
+ adjust_to_tracking(new, opts);
471
}
472
473
static int switch_branches(struct checkout_opts *opts,