copy_file('+', temp[1].name);
}
-static void builtin_diff(const char *name_a,
+static const char *builtin_diff(const char *name_a,
const char *name_b,
struct diff_tempfile *temp,
const char *xfrm_msg,
- int complete_rewrite)
+ int complete_rewrite,
+ const char **args)
{
int i, next_at, cmd_size;
const char *const diff_cmd = "diff -L%s -L%s";
}
if (xfrm_msg && xfrm_msg[0])
puts(xfrm_msg);
+ /*
+ * we do not run diff between different kind
+ * of objects.
+ */
if (strncmp(temp[0].mode, temp[1].mode, 3))
- /* we do not run diff between different kind
- * of objects.
- */
- exit(0);
+ return NULL;
if (complete_rewrite) {
- fflush(NULL);
emit_rewrite_diff(name_a, name_b, temp);
- exit(0);
+ return NULL;
}
}
- fflush(NULL);
- execlp("/bin/sh","sh", "-c", cmd, NULL);
+
+ /* This is disgusting */
+ *args++ = "sh";
+ *args++ = "-c";
+ *args++ = cmd;
+ *args = NULL;
+ return "/bin/sh";
}
struct diff_filespec *alloc_filespec(const char *path)
ce = active_cache[pos];
if ((lstat(name, &st) < 0) ||
!S_ISREG(st.st_mode) || /* careful! */
- ce_match_stat(ce, &st) ||
+ ce_match_stat(ce, &st, 0) ||
memcmp(sha1, ce->sha1, 20))
return 0;
/* we return 1 only when we can stat, it is a regular file,
static void remove_tempfile_on_signal(int signo)
{
remove_tempfile();
+ signal(SIGINT, SIG_DFL);
+ raise(signo);
+}
+
+static int spawn_prog(const char *pgm, const char **arg)
+{
+ pid_t pid;
+ int status;
+
+ fflush(NULL);
+ pid = fork();
+ if (pid < 0)
+ die("unable to fork");
+ if (!pid) {
+ execvp(pgm, (char *const*) arg);
+ exit(255);
+ }
+
+ while (waitpid(pid, &status, 0) < 0) {
+ if (errno == EINTR)
+ continue;
+ return -1;
+ }
+
+ /* Earlier we did not check the exit status because
+ * diff exits non-zero if files are different, and
+ * we are not interested in knowing that. It was a
+ * mistake which made it harder to quit a diff-*
+ * session that uses the git-apply-patch-script as
+ * the GIT_EXTERNAL_DIFF. A custom GIT_EXTERNAL_DIFF
+ * should also exit non-zero only when it wants to
+ * abort the entire diff-* session.
+ */
+ if (WIFEXITED(status) && !WEXITSTATUS(status))
+ return 0;
+ return -1;
}
/* An external diff command takes:
const char *xfrm_msg,
int complete_rewrite)
{
+ const char *spawn_arg[10];
struct diff_tempfile *temp = diff_temp;
- pid_t pid;
- int status;
+ int retval;
static int atexit_asked = 0;
const char *othername;
signal(SIGINT, remove_tempfile_on_signal);
}
- fflush(NULL);
- pid = fork();
- if (pid < 0)
- die("unable to fork");
- if (!pid) {
- if (pgm) {
- if (one && two) {
- const char *exec_arg[10];
- const char **arg = &exec_arg[0];
- *arg++ = pgm;
- *arg++ = name;
- *arg++ = temp[0].name;
- *arg++ = temp[0].hex;
- *arg++ = temp[0].mode;
- *arg++ = temp[1].name;
- *arg++ = temp[1].hex;
- *arg++ = temp[1].mode;
- if (other) {
- *arg++ = other;
- *arg++ = xfrm_msg;
- }
- *arg = NULL;
- execvp(pgm, (char *const*) exec_arg);
+ if (pgm) {
+ const char **arg = &spawn_arg[0];
+ if (one && two) {
+ *arg++ = pgm;
+ *arg++ = name;
+ *arg++ = temp[0].name;
+ *arg++ = temp[0].hex;
+ *arg++ = temp[0].mode;
+ *arg++ = temp[1].name;
+ *arg++ = temp[1].hex;
+ *arg++ = temp[1].mode;
+ if (other) {
+ *arg++ = other;
+ *arg++ = xfrm_msg;
}
- else
- execlp(pgm, pgm, name, NULL);
+ } else {
+ *arg++ = pgm;
+ *arg++ = name;
}
- /*
- * otherwise we use the built-in one.
- */
- if (one && two)
- builtin_diff(name, othername, temp, xfrm_msg,
- complete_rewrite);
- else
+ *arg = NULL;
+ } else {
+ if (one && two) {
+ pgm = builtin_diff(name, othername, temp, xfrm_msg, complete_rewrite, spawn_arg);
+ } else
printf("* Unmerged path %s\n", name);
- exit(0);
}
- if (waitpid(pid, &status, 0) < 0 ||
- !WIFEXITED(status) || WEXITSTATUS(status)) {
- /* Earlier we did not check the exit status because
- * diff exits non-zero if files are different, and
- * we are not interested in knowing that. It was a
- * mistake which made it harder to quit a diff-*
- * session that uses the git-apply-patch-script as
- * the GIT_EXTERNAL_DIFF. A custom GIT_EXTERNAL_DIFF
- * should also exit non-zero only when it wants to
- * abort the entire diff-* session.
- */
- remove_tempfile();
+
+ retval = 0;
+ if (pgm)
+ retval = spawn_prog(pgm, spawn_arg);
+ remove_tempfile();
+ if (retval) {
fprintf(stderr, "external diff died, stopping at %s.\n", name);
exit(1);
}
- remove_tempfile();
}
static void diff_fill_sha1_info(struct diff_filespec *one)
if (memcmp(one->sha1, two->sha1, 20)) {
char one_sha1[41];
- int abbrev = o->full_index ? 40 : DIFF_DEFAULT_INDEX_ABBREV;
+ int abbrev = o->full_index ? 40 : DEFAULT_ABBREV;
memcpy(one_sha1, sha1_to_hex(one->sha1), 41);
len += snprintf(msg + len, sizeof(msg) - len,
* so it is safe for us to do this here. Also
* it does not smudge active_cache or active_nr
* when it fails, so we do not have to worry about
- * cleaning it up oufselves either.
+ * cleaning it up ourselves either.
*/
read_cache();
}
else if (!strcmp(arg, "--find-copies-harder"))
options->find_copies_harder = 1;
else if (!strcmp(arg, "--abbrev"))
- options->abbrev = DIFF_DEFAULT_ABBREV;
- else if (!strncmp(arg, "--abbrev=", 9))
+ options->abbrev = DEFAULT_ABBREV;
+ else if (!strncmp(arg, "--abbrev=", 9)) {
options->abbrev = strtoul(arg + 9, NULL, 10);
+ if (options->abbrev < MINIMUM_ABBREV)
+ options->abbrev = MINIMUM_ABBREV;
+ else if (40 < options->abbrev)
+ options->abbrev = 40;
+ }
else
return 0;
return 1;
}
/* This is different from find_unique_abbrev() in that
- * it needs to deal with 0{40} SHA1.
+ * it stuffs the result with dots for alignment.
*/
const char *diff_unique_abbrev(const unsigned char *sha1, int len)
{
return sha1_to_hex(sha1);
abbrev = find_unique_abbrev(sha1, len);
- if (!abbrev) {
- if (!memcmp(sha1, null_sha1, 20)) {
- char *buf = sha1_to_hex(null_sha1);
- if (len < 37)
- strcpy(buf + len, "...");
- return buf;
- }
- else
- return sha1_to_hex(sha1);
- }
+ if (!abbrev)
+ return sha1_to_hex(sha1);
abblen = strlen(abbrev);
if (abblen < 37) {
static char hex[41];