[PATCH] Keep committer and committer dates

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi all,

	I hope that you will find this patch useful. Please, CC: me (I'm 
not on git list).

	Full patch is also here:

http://git.alsa-project.org/?p=git.git;a=commit;h=cbf280c58b11c9ea32095ad0e9f8823f29093a87

					Thanks,
						Jaroslav

===========
>From cbf280c58b11c9ea32095ad0e9f8823f29093a87 Mon Sep 17 00:00:00 2001
From: Jaroslav Kysela <perex@xxxxxxxx>
Date: Tue, 3 Jun 2008 16:40:03 +0200
Subject: [PATCH] Keep committer and committer dates - am, rebase, mailinfo, format-patch

Sometimes, it should be avoided to modify committer information when
rebasing or shuffling patches. The --committer parameter was added
to git-am and git-rebase.

It implies next extensions to format-patch and mailinfo to store
and extract X-Git-Committer / X-Git-CommitterDate e-mail headers.

The git-rebase in this patch contains also --signoff for --continue
action extension to allow signing of modified contents of patch.
The git-am accepts --signresolved to pass this information.

Signed-off-by: Jaroslav Kysela <perex@xxxxxxxx>
---
 Documentation/git-am.txt           |   15 +++++++++-
 Documentation/git-format-patch.txt |    5 +++
 Documentation/git-rebase.txt       |   14 ++++++++-
 builtin-log.c                      |    5 +++-
 builtin-mailinfo.c                 |    8 +++++-
 commit.h                           |    1 +
 git-am.sh                          |   51 +++++++++++++++++++++++++++++++++++-
 git-rebase.sh                      |   32 +++++++++++++++++-----
 log-tree.c                         |    3 +-
 pretty.c                           |   31 ++++++++++++++--------
 10 files changed, 138 insertions(+), 27 deletions(-)

diff --git a/Documentation/git-am.txt b/Documentation/git-am.txt
index 2387a8d..cd83c0e 100644
--- a/Documentation/git-am.txt
+++ b/Documentation/git-am.txt
@@ -10,10 +10,11 @@ SYNOPSIS
 --------
 [verse]
 'git-am' [--signoff] [--keep] [--utf8 | --no-utf8]
-         [--3way] [--interactive] [--binary]
+         [--3way] [--interactive] [--binary] [--committer]
          [--whitespace=<option>] [-C<n>] [-p<n>]
          <mbox>|<Maildir>...
-'git-am' [--skip | --resolved]
+'git-am' --skip
+`git-am` [--signresolved] --resolved
 
 DESCRIPTION
 -----------
@@ -59,6 +60,11 @@ default.   You could use `--no-utf8` to override this.
 	Pass `--allow-binary-replacement` flag to `git-apply`
 	(see linkgit:git-apply[1]).
 
+--committer
+	Use committer and committer date extracted from
+	`X-Git-Committer` and `X-Git-CommitterDate` header
+	lines.
+
 --whitespace=<option>::
 	This flag is passed to the `git-apply` (see linkgit:git-apply[1])
 	program that applies
@@ -91,6 +97,11 @@ default.   You could use `--no-utf8` to override this.
 	or `--skip` to handle the failure.  This is solely
 	for internal use between `git-rebase` and `git-am`.
 
+--signresolved
+        Add `Signed-off-by:` line to the commit message, using
+        the committer identity of yourself for resolved merge.
+	Can be used only for `--resolved`.
+
 DISCUSSION
 ----------
 
diff --git a/Documentation/git-format-patch.txt b/Documentation/git-format-patch.txt
index fefcd26..662659f 100644
--- a/Documentation/git-format-patch.txt
+++ b/Documentation/git-format-patch.txt
@@ -19,6 +19,7 @@ SYNOPSIS
 		   [--subject-prefix=Subject-Prefix]
 		   [--cc=<email>]
 		   [--cover-letter]
+		   [--committer]
 		   [ <since> | <revision range> ]
 
 DESCRIPTION
@@ -141,6 +142,10 @@ include::diff-options.txt[]
 	Add a "Cc:" header to the email headers. This is in addition
 	to any configured headers, and may be used multiple times.
 
+--committer::
+	Store original commiter information to `X-Git-Committer` and
+        `X-Git-CommitterDate` headers.
+
 --cover-letter::
 	Generate a cover letter template.  You still have to fill in
 	a description, but the shortlog and the diffstat will be
diff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt
index e0412e0..c64e6b0 100644
--- a/Documentation/git-rebase.txt
+++ b/Documentation/git-rebase.txt
@@ -11,8 +11,9 @@ SYNOPSIS
 'git-rebase' [-i | --interactive] [-v | --verbose] [-m | --merge]
 	[-s <strategy> | --strategy=<strategy>]
 	[-C<n>] [ --whitespace=<option>] [-p | --preserve-merges]
-	[--onto <newbase>] <upstream> [<branch>]
-'git-rebase' --continue | --skip | --abort
+	[--onto <newbase>] [--committer] <upstream> [<branch>]
+'git-rebase' --skip | --abort
+'git-rebase' [--signoff] --continue
 
 DESCRIPTION
 -----------
@@ -247,6 +248,15 @@ OPTIONS
 	Instead of ignoring merges, try to recreate them.  This option
 	only works in interactive mode.
 
+--committer
+	Preserve original commmitter and committer date.
+
+--signoff
+        Add `Signed-off-by:` line to the commit message, using
+        the committer identity of yourself for resolved merge.
+	Can be used only for `--continue`.
+
+
 include::merge-strategies.txt[]
 
 NOTES
diff --git a/builtin-log.c b/builtin-log.c
index 9817d6f..1c51e29 100644
--- a/builtin-log.c
+++ b/builtin-log.c
@@ -882,6 +882,8 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
 			cover_letter = 1;
 		else if (!strcmp(argv[i], "--no-binary"))
 			no_binary_diff = 1;
+		else if (!strcmp(argv[i], "--committer"))
+			rev.commit_format = CMIT_FMT_CEMAIL;
 		else
 			argv[j++] = argv[i];
 	}
@@ -1015,7 +1017,8 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
 	if (cover_letter) {
 		if (thread)
 			gen_message_id(&rev, "cover");
-		make_cover_letter(&rev, use_stdout, numbered, numbered_files,
+		make_cover_letter(&rev, use_stdout,
+				  numbered, numbered_files,
 				  origin, nr, list, head);
 		total++;
 		start_number--;
diff --git a/builtin-mailinfo.c b/builtin-mailinfo.c
index 97c1ff9..9af0d6d 100644
--- a/builtin-mailinfo.c
+++ b/builtin-mailinfo.c
@@ -289,7 +289,7 @@ static void cleanup_space(char *buf)
 
 static void decode_header(char *it, unsigned itsize);
 static const char *header[MAX_HDR_PARSED] = {
-	"From","Subject","Date",
+	"From","Subject","Date","X-Git-Committer","X-Git-CommitterDate"
 };
 
 static int check_header(char *line, unsigned linesize, char **hdr_data, int overwrite)
@@ -911,6 +911,12 @@ static void handle_info(void)
 			handle_from(hdr);
 			fprintf(fout, "Author: %s\n", name);
 			fprintf(fout, "Email: %s\n", email);
+		} else if (!memcmp(header[i], "X-Git-Committer\0", 16)) {
+			handle_from(hdr);
+			fprintf(fout, "Committer: %s\n", name);
+			fprintf(fout, "CommitterEmail: %s\n", email);
+		} else if (!memcmp(header[i], "X-Git-CommitterDate\0", 20)) {
+			fprintf(fout, "CommitterDate: %s\n", hdr);
 		} else {
 			cleanup_space(hdr);
 			fprintf(fout, "%s: %s\n", header[i], hdr);
diff --git a/commit.h b/commit.h
index 2d94d41..f6ec25e 100644
--- a/commit.h
+++ b/commit.h
@@ -57,6 +57,7 @@ enum cmit_fmt {
 	CMIT_FMT_FULLER,
 	CMIT_FMT_ONELINE,
 	CMIT_FMT_EMAIL,
+	CMIT_FMT_CEMAIL,
 	CMIT_FMT_USERFORMAT,
 
 	CMIT_FMT_UNSPECIFIED,
diff --git a/git-am.sh b/git-am.sh
index b48096e..010d13c 100755
--- a/git-am.sh
+++ b/git-am.sh
@@ -14,8 +14,10 @@ i,interactive   run interactively
 b,binary        pass --allow-binary-replacement to git-apply
 3,3way          allow fall back on 3way merging if needed
 s,signoff       add a Signed-off-by line to the commit message
+signresolved    only for --resolved command - sign-off-by the change
 u,utf8          recode into utf8 (default)
 k,keep          pass -k flag to git-mailinfo
+committer       handle committer and committer date
 whitespace=     pass it through git-apply
 C=              pass it through git-apply
 p=              pass it through git-apply
@@ -120,7 +122,7 @@ It does not apply to blobs recorded in its index."
 prec=4
 dotest=".dotest"
 sign= utf8=t keep= skip= interactive= resolved= binary= rebasing=
-resolvemsg= resume=
+resolvemsg= resume= committer= signresolved=
 git_apply_opt=
 
 while test $# != 0
@@ -142,6 +144,8 @@ do
 		keep=t ;;
 	-r|--resolved)
 		resolved=t ;;
+	--signresolved)
+		signresolved=t ;;
 	--skip)
 		skip=t ;;
 	--rebasing)
@@ -155,6 +159,8 @@ do
 		git_apply_opt="$git_apply_opt $1=$2"; shift ;;
 	-C|-p)
 		git_apply_opt="$git_apply_opt $1$2"; shift ;;
+	--committer)
+		committer="--committer"; shift ;;
 	--)
 		shift; break ;;
 	*)
@@ -347,6 +353,17 @@ do
 	GIT_AUTHOR_NAME="$(sed -n '/^Author/ s/Author: //p' "$dotest/info")"
 	GIT_AUTHOR_EMAIL="$(sed -n '/^Email/ s/Email: //p' "$dotest/info")"
 	GIT_AUTHOR_DATE="$(sed -n '/^Date/ s/Date: //p' "$dotest/info")"
+	if test -n "$committer" -a -z "$resume"
+	then
+		GIT_COMMITTER_NAME="$(sed -n '/^Committer/ s/Committer: //p' "$dotest/info")"
+		GIT_COMMITTER_EMAIL="$(sed -n '/^CommitterEmail/ s/CommitterEmail: //p' "$dotest/info")"
+		GIT_COMMITTER_DATE="$(sed -n '/^CommitterDate/ s/CommitterDate: //p' "$dotest/info")"
+		if test -z "$GIT_COMMITTER_EMAIL"
+		then
+			echo "Patch does not have a valid committer e-mail address."
+			stop_here $this
+		fi
+	fi
 
 	if test -z "$GIT_AUTHOR_EMAIL"
 	then
@@ -355,6 +372,10 @@ do
 	fi
 
 	export GIT_AUTHOR_NAME GIT_AUTHOR_EMAIL GIT_AUTHOR_DATE
+	if test -n "$committer" -a -z "$resume"
+	then
+		export GIT_COMMITTER_NAME GIT_COMMITTER_EMAIL GIT_COMMITTER_DATE
+	fi
 
 	case "$resume" in
 	'')
@@ -393,6 +414,34 @@ do
 		esac
 	esac
 
+	if test -n "$signresolved" -a -n "$resume"
+	then
+	    SIGNOFF1=`git-var GIT_COMMITTER_IDENT | sed -e '
+			s/>.*/>/
+			s/^/Signed-off-by: /'
+	    `
+	    LAST_SIGNED_OFF_BY=`
+		    sed -ne '/^Signed-off-by: /p' \
+		    "$dotest/final-commit" |
+		    sed -ne '$p'
+	    `
+	    ADD_SIGNOFF=`
+		    test "$LAST_SIGNED_OFF_BY" = "$SIGNOFF1" || {
+		    test '' = "$LAST_SIGNED_OFF_BY" && echo
+		    echo "$SIGNOFF1"
+	    }`
+	    {
+		if test -s "$dotest/final-commit"
+		then
+			cat "$dotest/final-commit"
+		fi
+		if test '' != "$ADD_SIGNOFF"
+		then
+			echo "$ADD_SIGNOFF"
+		fi
+	    } >"$dotest/final-commit"
+	fi
+
 	resume=
 	if test "$interactive" = t
 	then
diff --git a/git-rebase.sh b/git-rebase.sh
index dd7dfe1..d835f30 100755
--- a/git-rebase.sh
+++ b/git-rebase.sh
@@ -12,9 +12,9 @@ It then attempts to create a new commit for each commit from the original
 
 It is possible that a merge failure will prevent this process from being
 completely automatic.  You will have to resolve any such merge failure
-and run git rebase --continue.  Another option is to bypass the commit
-that caused the merge failure with git rebase --skip.  To restore the
-original <branch> and remove the .dotest working files, use the command
+and run git rebase [--signoff] --continue.  Another option is to bypass
+the commit that caused the merge failure with git rebase --skip.  To restore
+the original <branch> and remove the .dotest working files, use the command
 git rebase --abort instead.
 
 Note that if <branch> is not specified on the command line, the
@@ -46,6 +46,7 @@ dotest=$GIT_DIR/.dotest-merge
 prec=4
 verbose=
 git_am_opt=
+committer=
 
 continue_merge () {
 	test -n "$prev_head" || die "prev_head must be defined"
@@ -170,10 +171,16 @@ do
 			finish_rb_merge
 			exit
 		fi
+		signresolved=
+		if test -n "$signoff"
+		then
+			signresolved="--signresolved"
+		fi
 		head_name=$(cat .dotest/head-name) &&
 		onto=$(cat .dotest/onto) &&
 		orig_head=$(cat .dotest/orig-head) &&
-		git am --resolved --3way --resolvemsg="$RESOLVEMSG" &&
+		committer=$(cat .dotest/committer) &&
+		git am --resolved $signresolved --3way --resolvemsg="$RESOLVEMSG" $committer &&
 		move_to_original_branch
 		exit
 		;;
@@ -198,7 +205,8 @@ do
 		head_name=$(cat .dotest/head-name) &&
 		onto=$(cat .dotest/onto) &&
 		orig_head=$(cat .dotest/orig-head) &&
-		git am -3 --skip --resolvemsg="$RESOLVEMSG" &&
+		committer=$(cat .dotest/committer) &&
+		git am -3 --skip --resolvemsg="$RESOLVEMSG" $committer &&
 		move_to_original_branch
 		exit
 		;;
@@ -249,6 +257,12 @@ do
 	-C*)
 		git_am_opt="$git_am_opt $1"
 		;;
+	--committer)
+		committer="--committer"
+		;;
+	--signoff)
+		signoff=t
+		;;
 	-*)
 		usage
 		;;
@@ -386,14 +400,15 @@ fi
 if test -z "$do_merge"
 then
 	git format-patch -k --stdout --full-index --ignore-if-in-upstream \
-		"$upstream..$orig_head" |
-	git am $git_am_opt --rebasing --resolvemsg="$RESOLVEMSG" &&
+		$committer "$upstream..$orig_head" |
+	git am $git_am_opt --rebasing --resolvemsg="$RESOLVEMSG" $committer &&
 	move_to_original_branch
 	ret=$?
 	test 0 != $ret -a -d .dotest &&
 		echo $head_name > .dotest/head-name &&
 		echo $onto > .dotest/onto &&
-		echo $orig_head > .dotest/orig-head
+		echo $orig_head > .dotest/orig-head &&
+		echo $committer > .dotest/committer
 	exit $ret
 fi
 
@@ -407,6 +422,7 @@ prev_head=$orig_head
 echo "$prev_head" > "$dotest/prev_head"
 echo "$orig_head" > "$dotest/orig-head"
 echo "$head_name" > "$dotest/head-name"
+echo "$committer" > "$dotest/committer"
 
 msgnum=0
 for cmt in `git rev-list --reverse --no-merges "$upstream..$orig_head"`
diff --git a/log-tree.c b/log-tree.c
index 5505606..da319ef 100644
--- a/log-tree.c
+++ b/log-tree.c
@@ -287,7 +287,8 @@ void show_log(struct rev_info *opt)
 	 * Print header line of header..
 	 */
 
-	if (opt->commit_format == CMIT_FMT_EMAIL) {
+	if (opt->commit_format == CMIT_FMT_EMAIL ||
+	    opt->commit_format == CMIT_FMT_CEMAIL) {
 		log_write_email_headers(opt, sha1_to_hex(commit->object.sha1),
 					&subject, &extra_headers,
 					&need_8bit_cte);
diff --git a/pretty.c b/pretty.c
index 8eb39e9..2fb062f 100644
--- a/pretty.c
+++ b/pretty.c
@@ -18,6 +18,7 @@ void get_commit_format(const char *arg, struct rev_info *rev)
 		{ "medium",	1,	CMIT_FMT_MEDIUM },
 		{ "short",	1,	CMIT_FMT_SHORT },
 		{ "email",	1,	CMIT_FMT_EMAIL },
+		{ "cemail",	1,	CMIT_FMT_CEMAIL },
 		{ "full",	5,	CMIT_FMT_FULL },
 		{ "fuller",	5,	CMIT_FMT_FULLER },
 		{ "oneline",	1,	CMIT_FMT_ONELINE },
@@ -135,7 +136,7 @@ void pp_user_info(const char *what, enum cmit_fmt fmt, struct strbuf *sb,
 	time = strtoul(date, &date, 10);
 	tz = strtol(date, NULL, 10);
 
-	if (fmt == CMIT_FMT_EMAIL) {
+	if (fmt == CMIT_FMT_EMAIL || fmt == CMIT_FMT_CEMAIL) {
 		char *name_tail = strchr(line, '<');
 		int display_name_length;
 		if (!name_tail)
@@ -144,7 +145,12 @@ void pp_user_info(const char *what, enum cmit_fmt fmt, struct strbuf *sb,
 			name_tail--;
 		display_name_length = name_tail - line;
 		filler = "";
-		strbuf_addstr(sb, "From: ");
+		if (fmt == CMIT_FMT_CEMAIL) {
+			strbuf_addstr(sb, what);
+			strbuf_addstr(sb, ": ");
+		} else {
+			strbuf_addstr(sb, "From: ");
+		}
 		add_rfc2047(sb, line, display_name_length, encoding);
 		strbuf_add(sb, name_tail, namelen - display_name_length);
 		strbuf_addch(sb, '\n');
@@ -160,6 +166,7 @@ void pp_user_info(const char *what, enum cmit_fmt fmt, struct strbuf *sb,
 	case CMIT_FMT_EMAIL:
 		strbuf_addf(sb, "Date: %s\n", show_date(time, tz, DATE_RFC2822));
 		break;
+	case CMIT_FMT_CEMAIL:
 	case CMIT_FMT_FULLER:
 		strbuf_addf(sb, "%sDate: %s\n", what, show_date(time, tz, dmode));
 		break;
@@ -184,7 +191,7 @@ static void add_merge_info(enum cmit_fmt fmt, struct strbuf *sb,
 	struct commit_list *parent = commit->parents;
 
 	if ((fmt == CMIT_FMT_ONELINE) || (fmt == CMIT_FMT_EMAIL) ||
-	    !parent || !parent->next)
+	    (fmt == CMIT_FMT_CEMAIL) || !parent || !parent->next)
 		return;
 
 	strbuf_addstr(sb, "Merge:");
@@ -638,12 +645,13 @@ static void pp_header(enum cmit_fmt fmt,
 		 */
 		if (!memcmp(line, "author ", 7)) {
 			strbuf_grow(sb, linelen + 80);
-			pp_user_info("Author", fmt, sb, line + 7, dmode, encoding);
+			pp_user_info("Author", fmt == CMIT_FMT_CEMAIL ? CMIT_FMT_EMAIL : fmt, sb, line + 7, dmode, encoding);
 		}
 		if (!memcmp(line, "committer ", 10) &&
-		    (fmt == CMIT_FMT_FULL || fmt == CMIT_FMT_FULLER)) {
+		    (fmt == CMIT_FMT_FULL || fmt == CMIT_FMT_FULLER ||
+		     fmt == CMIT_FMT_CEMAIL)) {
 			strbuf_grow(sb, linelen + 80);
-			pp_user_info("Commit", fmt, sb, line + 10, dmode, encoding);
+			pp_user_info(fmt == CMIT_FMT_CEMAIL ? "X-Git-Committer" : "Commit", fmt, sb, line + 10, dmode, encoding);
 		}
 	}
 }
@@ -742,6 +750,7 @@ void pretty_print_commit(enum cmit_fmt fmt, const struct commit *commit,
 {
 	unsigned long beginning_of_body;
 	int indent = 4;
+	int email = fmt == CMIT_FMT_EMAIL || fmt == CMIT_FMT_CEMAIL;
 	const char *msg = commit->buffer;
 	char *reencoded;
 	const char *encoding;
@@ -761,14 +770,14 @@ void pretty_print_commit(enum cmit_fmt fmt, const struct commit *commit,
 		msg = reencoded;
 	}
 
-	if (fmt == CMIT_FMT_ONELINE || fmt == CMIT_FMT_EMAIL)
+	if (fmt == CMIT_FMT_ONELINE || email)
 		indent = 0;
 
 	/*
 	 * We need to check and emit Content-type: to mark it
 	 * as 8-bit if we haven't done so.
 	 */
-	if (fmt == CMIT_FMT_EMAIL && need_8bit_cte == 0) {
+	if (email && need_8bit_cte == 0) {
 		int i, ch, in_body;
 
 		for (in_body = i = 0; (ch = msg[i]); i++) {
@@ -804,8 +813,8 @@ void pretty_print_commit(enum cmit_fmt fmt, const struct commit *commit,
 	}
 
 	/* These formats treat the title line specially. */
-	if (fmt == CMIT_FMT_ONELINE || fmt == CMIT_FMT_EMAIL)
-		pp_title_line(fmt, &msg, sb, subject,
+	if (fmt == CMIT_FMT_ONELINE || email)
+		pp_title_line(email ? CMIT_FMT_EMAIL : fmt, &msg, sb, subject,
 			      after_subject, encoding, need_8bit_cte);
 
 	beginning_of_body = sb->len;
@@ -822,7 +831,7 @@ void pretty_print_commit(enum cmit_fmt fmt, const struct commit *commit,
 	 * format.  Make sure we did not strip the blank line
 	 * between the header and the body.
 	 */
-	if (fmt == CMIT_FMT_EMAIL && sb->len <= beginning_of_body)
+	if (email && sb->len <= beginning_of_body)
 		strbuf_addch(sb, '\n');
 	free(reencoded);
 }
-- 
1.5.6.rc1.dirty
===========

Jaroslav Kysela <perex@xxxxxxxx>
Linux Kernel Sound Maintainer
ALSA Project, Red Hat, Inc.
--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Kernel Development]     [Gcc Help]     [IETF Annouce]     [DCCP]     [Netdev]     [Networking]     [Security]     [V4L]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]     [Fedora Users]

  Powered by Linux