Merge branch 'jc/conflict-hint' into cc/interpret-trailers-more
* jc/conflict-hint: merge & sequencer: turn "Conflicts:" hint into a comment builtin/commit.c: extract ignore_non_trailer() helper function merge & sequencer: unify codepaths that write "Conflicts:" hint builtin/merge.c: drop a parameter that is never used git-tag.txt: Add a missing hyphen to `-s`
This commit is contained in:
commit
216d29ef25
@ -42,7 +42,7 @@ committer identity for the current user is used to find the
|
||||
GnuPG key for signing. The configuration variable `gpg.program`
|
||||
is used to specify custom GnuPG binary.
|
||||
|
||||
Tag objects (created with `-a`, `s`, or `-u`) are called "annotated"
|
||||
Tag objects (created with `-a`, `-s`, or `-u`) are called "annotated"
|
||||
tags; they contain a creation date, the tagger name and e-mail, a
|
||||
tagging message, and an optional GnuPG signature. Whereas a
|
||||
"lightweight" tag is simply a name for an object (usually a commit
|
||||
|
@ -669,6 +669,52 @@ static void adjust_comment_line_char(const struct strbuf *sb)
|
||||
comment_line_char = *p;
|
||||
}
|
||||
|
||||
/*
|
||||
* Inspect sb and determine the true "end" of the log message, in
|
||||
* order to find where to put a new Signed-off-by: line. Ignored are
|
||||
* trailing comment lines and blank lines, and also the traditional
|
||||
* "Conflicts:" block that is not commented out, so that we can use
|
||||
* "git commit -s --amend" on an existing commit that forgot to remove
|
||||
* it.
|
||||
*
|
||||
* Returns the number of bytes from the tail to ignore, to be fed as
|
||||
* the second parameter to append_signoff().
|
||||
*/
|
||||
static int ignore_non_trailer(struct strbuf *sb)
|
||||
{
|
||||
int boc = 0;
|
||||
int bol = 0;
|
||||
int in_old_conflicts_block = 0;
|
||||
|
||||
while (bol < sb->len) {
|
||||
char *next_line;
|
||||
|
||||
if (!(next_line = memchr(sb->buf + bol, '\n', sb->len - bol)))
|
||||
next_line = sb->buf + sb->len;
|
||||
else
|
||||
next_line++;
|
||||
|
||||
if (sb->buf[bol] == comment_line_char || sb->buf[bol] == '\n') {
|
||||
/* is this the first of the run of comments? */
|
||||
if (!boc)
|
||||
boc = bol;
|
||||
/* otherwise, it is just continuing */
|
||||
} else if (starts_with(sb->buf + bol, "Conflicts:\n")) {
|
||||
in_old_conflicts_block = 1;
|
||||
if (!boc)
|
||||
boc = bol;
|
||||
} else if (in_old_conflicts_block && sb->buf[bol] == '\t') {
|
||||
; /* a pathname in the conflicts block */
|
||||
} else if (boc) {
|
||||
/* the previous was not trailing comment */
|
||||
boc = 0;
|
||||
in_old_conflicts_block = 0;
|
||||
}
|
||||
bol = next_line - sb->buf;
|
||||
}
|
||||
return boc ? sb->len - boc : 0;
|
||||
}
|
||||
|
||||
static int prepare_to_commit(const char *index_file, const char *prefix,
|
||||
struct commit *current_head,
|
||||
struct wt_status *s,
|
||||
@ -792,32 +838,8 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
|
||||
if (clean_message_contents)
|
||||
stripspace(&sb, 0);
|
||||
|
||||
if (signoff) {
|
||||
/*
|
||||
* See if we have a Conflicts: block at the end. If yes, count
|
||||
* its size, so we can ignore it.
|
||||
*/
|
||||
int ignore_footer = 0;
|
||||
int i, eol, previous = 0;
|
||||
const char *nl;
|
||||
|
||||
for (i = 0; i < sb.len; i++) {
|
||||
nl = memchr(sb.buf + i, '\n', sb.len - i);
|
||||
if (nl)
|
||||
eol = nl - sb.buf;
|
||||
else
|
||||
eol = sb.len;
|
||||
if (starts_with(sb.buf + previous, "\nConflicts:\n")) {
|
||||
ignore_footer = sb.len - previous;
|
||||
break;
|
||||
}
|
||||
while (i < eol)
|
||||
i++;
|
||||
previous = eol;
|
||||
}
|
||||
|
||||
append_signoff(&sb, ignore_footer, 0);
|
||||
}
|
||||
if (signoff)
|
||||
append_signoff(&sb, ignore_non_trailer(&sb), 0);
|
||||
|
||||
if (fwrite(sb.buf, 1, sb.len, s->fp) < sb.len)
|
||||
die_errno(_("could not write commit template"));
|
||||
|
@ -28,6 +28,7 @@
|
||||
#include "remote.h"
|
||||
#include "fmt-merge-msg.h"
|
||||
#include "gpg-interface.h"
|
||||
#include "sequencer.h"
|
||||
|
||||
#define DEFAULT_TWOHEAD (1<<0)
|
||||
#define DEFAULT_OCTOPUS (1<<1)
|
||||
@ -880,28 +881,19 @@ static int finish_automerge(struct commit *head,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int suggest_conflicts(int renormalizing)
|
||||
static int suggest_conflicts(void)
|
||||
{
|
||||
const char *filename;
|
||||
FILE *fp;
|
||||
int pos;
|
||||
struct strbuf msgbuf = STRBUF_INIT;
|
||||
|
||||
filename = git_path("MERGE_MSG");
|
||||
fp = fopen(filename, "a");
|
||||
if (!fp)
|
||||
die_errno(_("Could not open '%s' for writing"), filename);
|
||||
fprintf(fp, "\nConflicts:\n");
|
||||
for (pos = 0; pos < active_nr; pos++) {
|
||||
const struct cache_entry *ce = active_cache[pos];
|
||||
|
||||
if (ce_stage(ce)) {
|
||||
fprintf(fp, "\t%s\n", ce->name);
|
||||
while (pos + 1 < active_nr &&
|
||||
!strcmp(ce->name,
|
||||
active_cache[pos + 1]->name))
|
||||
pos++;
|
||||
}
|
||||
}
|
||||
append_conflicts_hint(&msgbuf);
|
||||
fputs(msgbuf.buf, fp);
|
||||
fclose(fp);
|
||||
rerere(allow_rerere_auto);
|
||||
printf(_("Automatic merge failed; "
|
||||
@ -1550,7 +1542,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
|
||||
fprintf(stderr, _("Automatic merge went well; "
|
||||
"stopped before committing as requested\n"));
|
||||
else
|
||||
ret = suggest_conflicts(option_renormalize);
|
||||
ret = suggest_conflicts();
|
||||
|
||||
done:
|
||||
free(branch_to_free);
|
||||
|
34
sequencer.c
34
sequencer.c
@ -266,6 +266,23 @@ static int fast_forward_to(const unsigned char *to, const unsigned char *from,
|
||||
return 0;
|
||||
}
|
||||
|
||||
void append_conflicts_hint(struct strbuf *msgbuf)
|
||||
{
|
||||
int i;
|
||||
|
||||
strbuf_addch(msgbuf, '\n');
|
||||
strbuf_commented_addf(msgbuf, "Conflicts:\n");
|
||||
for (i = 0; i < active_nr;) {
|
||||
const struct cache_entry *ce = active_cache[i++];
|
||||
if (ce_stage(ce)) {
|
||||
strbuf_commented_addf(msgbuf, "\t%s\n", ce->name);
|
||||
while (i < active_nr && !strcmp(ce->name,
|
||||
active_cache[i]->name))
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int do_recursive_merge(struct commit *base, struct commit *next,
|
||||
const char *base_label, const char *next_label,
|
||||
unsigned char *head, struct strbuf *msgbuf,
|
||||
@ -306,21 +323,8 @@ static int do_recursive_merge(struct commit *base, struct commit *next,
|
||||
if (opts->signoff)
|
||||
append_signoff(msgbuf, 0, 0);
|
||||
|
||||
if (!clean) {
|
||||
int i;
|
||||
strbuf_addstr(msgbuf, "\nConflicts:\n");
|
||||
for (i = 0; i < active_nr;) {
|
||||
const struct cache_entry *ce = active_cache[i++];
|
||||
if (ce_stage(ce)) {
|
||||
strbuf_addch(msgbuf, '\t');
|
||||
strbuf_addstr(msgbuf, ce->name);
|
||||
strbuf_addch(msgbuf, '\n');
|
||||
while (i < active_nr && !strcmp(ce->name,
|
||||
active_cache[i]->name))
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!clean)
|
||||
append_conflicts_hint(msgbuf);
|
||||
|
||||
return !clean;
|
||||
}
|
||||
|
@ -53,5 +53,6 @@ int sequencer_pick_revisions(struct replay_opts *opts);
|
||||
extern const char sign_off_header[];
|
||||
|
||||
void append_signoff(struct strbuf *msgbuf, int ignore_footer, unsigned flag);
|
||||
void append_conflicts_hint(struct strbuf *msgbuf);
|
||||
|
||||
#endif
|
||||
|
@ -351,19 +351,45 @@ test_expect_success 'commit after failed cherry-pick does not add duplicated -s'
|
||||
test_expect_success 'commit after failed cherry-pick adds -s at the right place' '
|
||||
pristine_detach initial &&
|
||||
test_must_fail git cherry-pick picked &&
|
||||
|
||||
git commit -a -s &&
|
||||
pwd &&
|
||||
cat <<EOF > expected &&
|
||||
picked
|
||||
|
||||
Signed-off-by: C O Mitter <committer@example.com>
|
||||
# Do S-o-b and Conflicts appear in the right order?
|
||||
cat <<-\EOF >expect &&
|
||||
Signed-off-by: C O Mitter <committer@example.com>
|
||||
# Conflicts:
|
||||
EOF
|
||||
grep -e "^# Conflicts:" -e '^Signed-off-by' <.git/COMMIT_EDITMSG >actual &&
|
||||
test_cmp expect actual &&
|
||||
|
||||
Conflicts:
|
||||
foo
|
||||
EOF
|
||||
cat <<-\EOF >expected &&
|
||||
picked
|
||||
|
||||
git show -s --pretty=format:%B > actual &&
|
||||
Signed-off-by: C O Mitter <committer@example.com>
|
||||
EOF
|
||||
|
||||
git show -s --pretty=format:%B >actual &&
|
||||
test_cmp expected actual
|
||||
'
|
||||
|
||||
test_expect_success 'commit --amend -s places the sign-off at the right place' '
|
||||
pristine_detach initial &&
|
||||
test_must_fail git cherry-pick picked &&
|
||||
|
||||
# emulate old-style conflicts block
|
||||
mv .git/MERGE_MSG .git/MERGE_MSG+ &&
|
||||
sed -e "/^# Conflicts:/,\$s/^# *//" <.git/MERGE_MSG+ >.git/MERGE_MSG &&
|
||||
|
||||
git commit -a &&
|
||||
git commit --amend -s &&
|
||||
|
||||
# Do S-o-b and Conflicts appear in the right order?
|
||||
cat <<-\EOF >expect &&
|
||||
Signed-off-by: C O Mitter <committer@example.com>
|
||||
Conflicts:
|
||||
EOF
|
||||
grep -e "^Conflicts:" -e '^Signed-off-by' <.git/COMMIT_EDITMSG >actual &&
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_done
|
||||
|
Loading…
Reference in New Issue
Block a user