rebase-merges: try and use branch names for labels
cover rebase-merges: try and use branch names for labels
When interactively rebasing merge commits, the commit message is parsed to extract a probably meaningful label name. For instance if the merge commit is “Merge branch 'feature0'”, then the rebase script will have thes lines:
label feature0 merge -C $sha feature0 # “Merge branch 'feature0'
This heuristic fails in the case of octopus merges or when the merge commit message is actually unrelated to the parent commits.
An example that combines both is: *---. 967bfa4 (HEAD -> integration) Integration |\ \
| | | * 2135be1 (feature2, feat2) Feature 2 | |_|/ |/| | | | * c88b01a Feature 1 | |/ |/| | * 75f3139 (feat0) Feature 0 |/ * 25c86d0 (main) Initial
commit which yields the labels Integration, Integration-2 and Integration-3.
Fix this by using a branch name for each merge commit's parent that is the tip of at least one branch, and falling back to a label derived from the merge commit message otherwise. In the example above, the labels become feat0, Integration and feature2.
Nicolas Guichard (2):
sequencer.c: extract load_branch_decorations
rebase-merges: try and use branch names as labels
sequencer.c | 50 ++++++++++++++++++++++------------- t/t3404-rebase-interactive.sh | 4 +-- t/t3430-rebase-merges.sh | 12 ++++----- 3 files changed, 40 insertions(+), 26 deletions(-)
base-commit: 94b60adee30619a05296cf5ed6addb0e6d4e25dc
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-git-1784%2Fnicolas-guichard%2Fuse-branch-names-for-rebase-merges-labels-v1
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-git-1784/nicolas-guichard/use-branch-names-for-rebase-merges-labels-v1
Pull-Request: https://github.com/git/git/pull/1784
Signature · 1 line
gitgitgadget
PATCH 1/2 sequencer.c: extract load_branch_decorations
From: Nicolas Guichard <[email protected]>
Extract load_branch_decorations from todo_list_add_update_ref_commands so it can be re-used in make_script_with_merges.
--- sequencer.c | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-)
sequencer.c +15 -10
@@ -5810,6 +5810,20 @@ static const char *label_oid(struct object_id *oid, const char *label,return string_entry->string; } +static void load_branch_decorations (void ) +{ +static struct string_list decorate_refs_exclude =STRING_LIST_INIT_NODUP ; +static struct string_list decorate_refs_exclude_config =STRING_LIST_INIT_NODUP ; +static struct string_list decorate_refs_include =STRING_LIST_INIT_NODUP ; +struct decoration_filter decoration_filter = { + .include_ref_pattern = &decorate_refs_include, + .exclude_ref_pattern = &decorate_refs_exclude, + .exclude_ref_config_pattern = &decorate_refs_exclude_config, + }; +string_list_append (&decorate_refs_include,"refs/heads/" ); +load_ref_decorations (&decoration_filter,0 ); +} +static int make_script_with_merges (struct pretty_print_context *pp,struct rev_info *revs,struct strbuf *out,unsigned flags)
@@ -6403,14 +6417,6 @@ static int add_decorations_to_list(const struct commit *commit,static int todo_list_add_update_ref_commands (struct todo_list *todo_list) {int i, res; -static struct string_list decorate_refs_exclude =STRING_LIST_INIT_NODUP ; -static struct string_list decorate_refs_exclude_config =STRING_LIST_INIT_NODUP ; -static struct string_list decorate_refs_include =STRING_LIST_INIT_NODUP ; -struct decoration_filter decoration_filter = { - .include_ref_pattern = &decorate_refs_include, - .exclude_ref_pattern = &decorate_refs_exclude, - .exclude_ref_config_pattern = &decorate_refs_exclude_config, - };struct todo_add_branch_context ctx = { .buf = &todo_list->buf, .refs_to_oids =STRING_LIST_INIT_DUP ,
@@ -6419,8 +6425,7 @@ static int todo_list_add_update_ref_commands(struct todo_list *todo_list) ctx.items_alloc =2 * todo_list->nr +1 ;ALLOC_ARRAY (ctx.items, ctx.items_alloc); -string_list_append (&decorate_refs_include,"refs/heads/" ); -load_ref_decorations (&decoration_filter,0 ); +load_branch_decorations ();for (i =0 ; i < todo_list->nr; ) {struct todo_item *item = &todo_list->items[i];
Signature · 1 line
gitgitgadget
Re: [PATCH 1/2] sequencer.c: extract load_branch_decorations
Quoted 9 lines · Nicolas Guichard via GitGitGadget
From: Nicolas Guichard <[email protected]>
Extract
load_branch_decorationsfromtodo_list_add_update_ref_commandsso it can be re-used inmake_script_with_merges.Signed-off-by Nicolas Guichard <[email protected]>--- sequencer.c | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-)
This intends no behaviour change, and it indeed does not make any behaviour change. Good.
Quoted 11 lines
sequencer.c +3
-0@@ -5810,6 +5810,20 @@ static const char *label_oid(struct object_id *oid, const char *label,return string_entry->string; } +static void load_branch_decorations (void ) +{ +static struct string_list decorate_refs_exclude =STRING_LIST_INIT_NODUP ;
sequencer.c static const char *label_oid(struct object_id *oid, const char *label, · line 5825
Quoted 10 lines
sequencer.c +10
-0+static struct string_list decorate_refs_exclude_config =STRING_LIST_INIT_NODUP ; +static struct string_list decorate_refs_include =STRING_LIST_INIT_NODUP ; +struct decoration_filter decoration_filter = { + .include_ref_pattern = &decorate_refs_include, + .exclude_ref_pattern = &decorate_refs_exclude, + .exclude_ref_config_pattern = &decorate_refs_exclude_config, + }; +string_list_append (&decorate_refs_include,"refs/heads/" ); +load_ref_decorations (&decoration_filter,0 ); +}
The load_ref_decorations() function can be called only once per process, so it does not matter whatever garbage your second and later invocations throw at it.
But if this function is ever called N times, you'll add N copies of "refs/heads/" in the _include list, and because the variable is static, it is not reported as a leak.
It may have been OK back when this implementation was inside todo_list_add_update_ref_commands(), which was called by complete_action() only once before the process exited.
But now you made it a "reusable" function, we should clean up after ourselves, perhaps by dropping "static" from these three string_list instances and clearing them after calling load_ref_decorations().
PATCH 2/2 rebase-merges: try and use branch names as labels
In reply to Nicolas Guichard via GitGitGadgetFrom: Nicolas Guichard <[email protected]>
When interactively rebasing merge commits, the commit message is parsed to extract a probably meaningful label name. For instance if the merge commit is “Merge branch 'feature0'”, then the rebase script will have thes lines:
``` label feature0 merge -C $sha feature0 # “Merge branch 'feature0' ```
This heuristic fails in the case of octopus merges or when the merge commit message is actually unrelated to the parent commits.
An example that combines both is:
``` *---. 967bfa4 (HEAD -> integration) Integration |\ \ \ | | | * 2135be1 (feature2, feat2) Feature 2 | |_|/ |/| | | | * c88b01a Feature 1 | |/ |/| | * 75f3139 (feat0) Feature 0 |/ * 25c86d0 (main) Initial commit ```
yields the labels Integration, Integration-2 and Integration-3.
Fix this by using a branch name for each merge commit's parent that is the tip of at least one branch, and falling back to a label derived from the merge commit message otherwise.
In the example above, the labels become feat0, Integration and feature2.
--- sequencer.c | 25 +++++++++++++++++-------- t/t3404-rebase-interactive.sh | 4 ++-- t/t3430-rebase-merges.sh | 12 ++++++------ 3 files changed, 25 insertions(+), 16 deletions(-)
sequencer.c +17 -8
@@ -5833,7 +5833,7 @@ static int make_script_with_merges(struct pretty_print_context *pp,int root_with_onto = flags &TODO_LIST_ROOT_WITH_ONTO ;int skipped_commit =0 ;struct strbuf buf =STRBUF_INIT , oneline =STRBUF_INIT ; -struct strbuf label =STRBUF_INIT ; +struct strbuf label_from_message =STRBUF_INIT ;struct commit_list *commits =NULL , **tail = &commits, *iter;struct commit_list *tips =NULL , **tips_tail = &tips;struct commit *commit;
@@ -5856,6 +5856,7 @@ static int make_script_with_merges(struct pretty_print_context *pp,oidmap_init (&state.commit2label,0 );hashmap_init (&state.labels, labels_cmp,NULL ,0 );strbuf_init (&state.buf,32 ); +load_branch_decorations ();if (revs->cmdline.nr && (revs->cmdline.rev[0 ].flags &BOTTOM )) {struct labels_entry *onto_label_entry;
@@ -5916,18 +5917,18 @@ static int make_script_with_merges(struct pretty_print_context *pp,continue ; } -/* Create a label */ -strbuf_reset (&label); +/* Create a label from the commit message */ +strbuf_reset (&label_from_message);if (skip_prefix (oneline.buf,"Merge " , &p1) && (p1 =strchr (p1,'\'' )) && (p2 =strchr (++p1,'\'' ))) -strbuf_add (&label, p1, p2 - p1); +strbuf_add (&label_from_message, p1, p2 - p1);else if (skip_prefix (oneline.buf,"Merge pull request " , &p1) && (p1 =strstr (p1," from " ))) -strbuf_addstr (&label, p1 +strlen (" from " )); +strbuf_addstr (&label_from_message, p1 +strlen (" from " ));else -strbuf_addbuf (&label, &oneline); +strbuf_addbuf (&label_from_message, &oneline);strbuf_reset (&buf); strbuf_addf(&buf, "%s -C %s",
@@ -5935,6 +5936,14 @@ static int make_script_with_merges(struct pretty_print_context *pp,/* label the tips of merged branches */ for (; to_merge; to_merge = to_merge->next) { +const char *label = label_from_message.buf; +const struct name_decoration *decoration = +get_name_decoration (&to_merge->item->object); + +if (decoration) +skip_prefix (decoration->name,"refs/heads/" , + &label); + oid = &to_merge->item->object.oid;strbuf_addch (&buf,' ' );
@@ -5947,7 +5956,7 @@ static int make_script_with_merges(struct pretty_print_context *pp, tips_tail = &commit_list_insert (to_merge->item, tips_tail)->next; -strbuf_addstr (&buf,label_oid (oid, label.buf, &state)); +strbuf_addstr (&buf,label_oid (oid, label, &state)); }strbuf_addf (&buf," # %s" , oneline.buf);
@@ -6055,7 +6064,7 @@ static int make_script_with_merges(struct pretty_print_context *pp,free_commit_list (commits);free_commit_list (tips); -strbuf_release (&label); +strbuf_release (&label_from_message);strbuf_release (&oneline);strbuf_release (&buf);
t/t3404-rebase-interactive.sh +2 -2
@@ -1870,7 +1870,7 @@ test_expect_success '--update-refs adds commands with --rebase-merges' ' pick $(git log -1 --format=%h branch2~1) F pick $(git log -1 --format=%h branch2) I update-ref refs/heads/branch2 - label merge + label branch2 reset onto pick $(git log -1 --format=%h refs/heads/second) J update-ref refs/heads/second
@@ -1881,7 +1881,7 @@ test_expect_success '--update-refs adds commands with --rebase-merges' ' update-ref refs/heads/third pick $(git log -1 --format=%h HEAD~2) M update-ref refs/heads/no-conflict-branch - merge -C $(git log -1 --format=%h HEAD~1) merge # merge + merge -C $(git log -1 --format=%h HEAD~1) branch2 # merge update-ref refs/heads/merge-branch EOF
t/t3430-rebase-merges.sh +6 -6
@@ -108,19 +108,19 @@ test_expect_success 'generate correct todo list' ' reset onto pick $b B - label E + label first reset onto pick $c C label branch-point pick $f F pick $g G - label H + label second reset branch-point # C pick $d D - merge -C $e E # E - merge -C $h H # H + merge -C $e first # E + merge -C $h second # H EOF
@@ -462,11 +462,11 @@ test_expect_success 'A root commit can be a cousin, treat it that way' ' ' test_expect_success 'labels that are object IDs are rewritten' ' - git checkout -b third B && + git checkout --detach B && test_commit I && third=$(git rev-parse HEAD) && git checkout -b labels main && - git merge --no-commit third && + git merge --no-commit $third && test_tick && git commit -m "Merge commit '\''$third'\'' into labels" && echo noop >script-from-scratch &&
Signature · 1 line
gitgitgadget
Re: [PATCH 2/2] rebase-merges: try and use branch names as labels
Running
git blame -L'/^static int make_script_with_merges/,/^}/' sequencer.c
tells me that the code range this patch touches and the function whose feature this patch extends was mostly introduced in 1644c73c (rebase-helper --make-script: introduce a flag to rebase merges, 2018-04-25) by Johannes Schindelin (CC'ed), so let's ask input from him as an area expert.
Thanks.
Quoted 184 lines · Nicolas Guichard via GitGitGadget
From: Nicolas Guichard <[email protected]>
When interactively rebasing merge commits, the commit message is parsed to extract a probably meaningful label name. For instance if the merge commit is “Merge branch 'feature0'”, then the rebase script will have thes lines:
``` label feature0 merge -C $sha feature0 # “Merge branch 'feature0' ```This heuristic fails in the case of octopus merges or when the merge commit message is actually unrelated to the parent commits.
An example that combines both is:
``` *---. 967bfa4 (HEAD -> integration) Integration |\ \ \ | | | * 2135be1 (feature2, feat2) Feature 2 | |_|/ |/| | | | * c88b01a Feature 1 | |/ |/| | * 75f3139 (feat0) Feature 0 |/ * 25c86d0 (main) Initial commit ```yields the labels Integration, Integration-2 and Integration-3.
Fix this by using a branch name for each merge commit's parent that is the tip of at least one branch, and falling back to a label derived from the merge commit message otherwise.
In the example above, the labels become feat0, Integration and feature2.Signed-off-by Nicolas Guichard <[email protected]>--- sequencer.c | 25 +++++++++++++++++-------- t/t3404-rebase-interactive.sh | 4 ++-- t/t3430-rebase-merges.sh | 12 ++++++------ 3 files changed, 25 insertions(+), 16 deletions(-)sequencer.c +17
-8@@ -5833,7 +5833,7 @@ static int make_script_with_merges(struct pretty_print_context *pp,int root_with_onto = flags &TODO_LIST_ROOT_WITH_ONTO ;int skipped_commit =0 ;struct strbuf buf =STRBUF_INIT , oneline =STRBUF_INIT ; -struct strbuf label =STRBUF_INIT ; +struct strbuf label_from_message =STRBUF_INIT ;struct commit_list *commits =NULL , **tail = &commits, *iter;struct commit_list *tips =NULL , **tips_tail = &tips;struct commit *commit;@@ -5856,6 +5856,7 @@ static int make_script_with_merges(struct pretty_print_context *pp,oidmap_init (&state.commit2label,0 );hashmap_init (&state.labels, labels_cmp,NULL ,0 );strbuf_init (&state.buf,32 ); +load_branch_decorations ();if (revs->cmdline.nr && (revs->cmdline.rev[0 ].flags &BOTTOM )) {struct labels_entry *onto_label_entry;@@ -5916,18 +5917,18 @@ static int make_script_with_merges(struct pretty_print_context *pp,continue ; } -/* Create a label */ -strbuf_reset (&label); +/* Create a label from the commit message */ +strbuf_reset (&label_from_message);if (skip_prefix (oneline.buf,"Merge " , &p1) && (p1 =strchr (p1,'\'' )) && (p2 =strchr (++p1,'\'' ))) -strbuf_add (&label, p1, p2 - p1); +strbuf_add (&label_from_message, p1, p2 - p1);else if (skip_prefix (oneline.buf,"Merge pull request " , &p1) && (p1 =strstr (p1," from " ))) -strbuf_addstr (&label, p1 +strlen (" from " )); +strbuf_addstr (&label_from_message, p1 +strlen (" from " ));else -strbuf_addbuf (&label, &oneline); +strbuf_addbuf (&label_from_message, &oneline);strbuf_reset (&buf); strbuf_addf(&buf, "%s -C %s",@@ -5935,6 +5936,14 @@ static int make_script_with_merges(struct pretty_print_context *pp,/* label the tips of merged branches */ for (; to_merge; to_merge = to_merge->next) { +const char *label = label_from_message.buf; +const struct name_decoration *decoration = +get_name_decoration (&to_merge->item->object); + +if (decoration) +skip_prefix (decoration->name,"refs/heads/" , + &label); + oid = &to_merge->item->object.oid;strbuf_addch (&buf,' ' );@@ -5947,7 +5956,7 @@ static int make_script_with_merges(struct pretty_print_context *pp, tips_tail = &commit_list_insert (to_merge->item, tips_tail)->next; -strbuf_addstr (&buf,label_oid (oid, label.buf, &state)); +strbuf_addstr (&buf,label_oid (oid, label, &state)); }strbuf_addf (&buf," # %s" , oneline.buf);@@ -6055,7 +6064,7 @@ static int make_script_with_merges(struct pretty_print_context *pp,free_commit_list (commits);free_commit_list (tips); -strbuf_release (&label); +strbuf_release (&label_from_message);strbuf_release (&oneline);strbuf_release (&buf);t/t3404-rebase-interactive.sh +2
-2@@ -1870,7 +1870,7 @@ test_expect_success '--update-refs adds commands with --rebase-merges' ' pick $(git log -1 --format=%h branch2~1) F pick $(git log -1 --format=%h branch2) I update-ref refs/heads/branch2 - label merge + label branch2 reset onto pick $(git log -1 --format=%h refs/heads/second) J update-ref refs/heads/second@@ -1881,7 +1881,7 @@ test_expect_success '--update-refs adds commands with --rebase-merges' ' update-ref refs/heads/third pick $(git log -1 --format=%h HEAD~2) M update-ref refs/heads/no-conflict-branch - merge -C $(git log -1 --format=%h HEAD~1) merge # merge + merge -C $(git log -1 --format=%h HEAD~1) branch2 # merge update-ref refs/heads/merge-branch EOFt/t3430-rebase-merges.sh +6
-6@@ -108,19 +108,19 @@ test_expect_success 'generate correct todo list' ' reset onto pick $b B - label E + label first reset onto pick $c C label branch-point pick $f F pick $g G - label H + label second reset branch-point # C pick $d D - merge -C $e E # E - merge -C $h H # H + merge -C $e first # E + merge -C $h second # H EOF@@ -462,11 +462,11 @@ test_expect_success 'A root commit can be a cousin, treat it that way' ' ' test_expect_success 'labels that are object IDs are rewritten' ' - git checkout -b third B && + git checkout --detach B && test_commit I && third=$(git rev-parse HEAD) && git checkout -b labels main && - git merge --no-commit third && + git merge --no-commit $third && test_tick && git commit -m "Merge commit '\''$third'\'' into labels" && echo noop >script-from-scratch &&
v2 cover rebase-merges: try and use branch names for labels
In reply to Nicolas Guichard via GitGitGadgetWhen interactively rebasing merge commits, the commit message is parsed to extract a probably meaningful label name. For instance if the merge commit is “Merge branch 'feature0'”, then the rebase script will have thes lines:
label feature0
merge -C $sha feature0 # “Merge branch 'feature0'
This heuristic fails in the case of octopus merges or when the merge commit message is actually unrelated to the parent commits.
An example that combines both is:
*---. 967bfa4 (HEAD -> integration) Integration
|\ \ \ | | | * 2135be1 (feature2, feat2) Feature 2 | |_|/ |/| | | | * c88b01a Feature 1 | |/ |/| | * 75f3139 (feat0) Feature 0 |/
* 25c86d0 (main) Initial commit
which yields the labels Integration, Integration-2 and Integration-3.
Fix this by using a branch name for each merge commit's parent that is the tip of at least one branch, and falling back to a label derived from the merge commit message otherwise. In the example above, the labels become feat0, Integration and feature2.
Changes since v1:
* moved load_branch_decorations to re-use the decoration_loaded guard and avoid pointlessly appending "refs/heads/" to a static string_list, as pointed out by Junio C Hamano (thanks!)
* fixed a leak in load_branch_decorations found by making the filter string_lists non-static
Nicolas Guichard (3):
load_branch_decorations: fix memory leak with non-static filters
rebase-update-refs: extract load_branch_decorations
rebase-merges: try and use branch names as labels
log-tree.c | 26 +++++++++++++++++++++++++ log-tree.h | 1 + sequencer.c | 36 +++++++++++++++++------------------ t/t3404-rebase-interactive.sh | 4 ++-- t/t3430-rebase-merges.sh | 12 ++++++------ 5 files changed, 53 insertions(+), 26 deletions(-)
base-commit: 8895aca99693e22ec4856744d5b2c25b8736a111
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-git-1784%2Fnicolas-guichard%2Fuse-branch-names-for-rebase-merges-labels-v2
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-git-1784/nicolas-guichard/use-branch-names-for-rebase-merges-labels-v2
Pull-Request: https://github.com/git/git/pull/1784
Range-diff vs v1:
-: ----------- > 1: 6250a7f6d6c load_branch_decorations: fix memory leak with non-static filters 1: 7f3d5e5da35 ! 2: 167418d10d1 sequencer.c: extract load_branch_decorations
@@ Metadata
Author: Nicolas Guichard <[email protected]>
## Commit message ##
- sequencer.c: extract load_branch_decorations
+ rebase-update-refs: extract load_branch_decorations
Extract load_branch_decorations from todo_list_add_update_ref_commands so it can be re-used in make_script_with_merges.
+ Since it can now be called multiple times, use non-static lists and place
+ it next to load_ref_decorations to re-use the decoration_loaded guard.
+
- ## sequencer.c ##
-@@ sequencer.c: static const char *label_oid(struct object_id *oid, const char *label,
- return string_entry->string;
+ ## log-tree.c ##
+@@ log-tree.c: void load_ref_decorations(struct decoration_filter *filter, int flags)
+ }
}
-+static void load_branch_decorations(void)
++void load_branch_decorations(void)
+{
-+ static struct string_list decorate_refs_exclude = STRING_LIST_INIT_NODUP;
-+ static struct string_list decorate_refs_exclude_config = STRING_LIST_INIT_NODUP;
-+ static struct string_list decorate_refs_include = STRING_LIST_INIT_NODUP;
-+ struct decoration_filter decoration_filter = {
-+ .include_ref_pattern = &decorate_refs_include,
-+ .exclude_ref_pattern = &decorate_refs_exclude,
-+ .exclude_ref_config_pattern = &decorate_refs_exclude_config,
-+ };
-+ string_list_append(&decorate_refs_include, "refs/heads/");
-+ load_ref_decorations(&decoration_filter, 0);
++ if (!decoration_loaded) {
++ struct string_list decorate_refs_exclude = STRING_LIST_INIT_NODUP;
++ struct string_list decorate_refs_exclude_config = STRING_LIST_INIT_NODUP;
++ struct string_list decorate_refs_include = STRING_LIST_INIT_NODUP;
++ struct decoration_filter decoration_filter = {
++ .include_ref_pattern = &decorate_refs_include,
++ .exclude_ref_pattern = &decorate_refs_exclude,
++ .exclude_ref_config_pattern = &decorate_refs_exclude_config,
++ };
++
++ string_list_append(&decorate_refs_include, "refs/heads/");
++ load_ref_decorations(&decoration_filter, 0);
++
++ string_list_clear(&decorate_refs_exclude, false);
++ string_list_clear(&decorate_refs_exclude_config, false);
++ string_list_clear(&decorate_refs_include, false);
++ }
+}
+
- static int make_script_with_merges(struct pretty_print_context *pp,
- struct rev_info *revs, struct strbuf *out,
- unsigned flags)
+ static void show_parents(struct commit *commit, int abbrev, FILE *file)
+ {
+ struct commit_list *p;
+
+ ## log-tree.h ##
+@@ log-tree.h: void log_write_email_headers(struct rev_info *opt, struct commit *commit,
+ int *need_8bit_cte_p,
+ int maybe_multipart);
+ void load_ref_decorations(struct decoration_filter *filter, int flags); ++void load_branch_decorations(void);
+
+ void fmt_output_commit(struct strbuf *, struct commit *, struct rev_info *);
+ void fmt_output_subject(struct strbuf *, const char *subject, struct rev_info *); +
+ ## sequencer.c ##
@@ sequencer.c: static int add_decorations_to_list(const struct commit *commit,
static int todo_list_add_update_ref_commands(struct todo_list *todo_list) {
2: 9afe428927d = 3: dfa1f0a7648 rebase-merges: try and use branch names as labels
Signature · 1 line
gitgitgadget
PATCH v2 1/3 load_branch_decorations: fix memory leak with non-static filters
From: Nicolas Guichard <[email protected]>
load_branch_decorations calls normalize_glob_ref on each string of filter's string_lists. This effectively replaces the potentially non-owning char* of those items with an owning char*.
Set the strdup_string flag on those string_lists.
This was not caught until now because:
- when passing string_lists already with the strdup_string already set, the behaviour was correct
- when passing static string_lists, the new char* remain reachable until program exit
--- log-tree.c | 5 +++++ 1 file changed, 5 insertions(+)
log-tree.c +5 -0
@@ -232,6 +232,11 @@ void load_ref_decorations(struct decoration_filter *filter, int flags)for_each_string_list_item (item, filter->exclude_ref_config_pattern) {normalize_glob_ref (item,NULL , item->string); } + +// normalize_glob_ref duplicates the strings + filter->exclude_ref_pattern->strdup_strings = true; + filter->include_ref_pattern->strdup_strings = true; + filter->exclude_ref_config_pattern->strdup_strings = true; } decoration_loaded =1 ; decoration_flags = flags;
Signature · 1 line
gitgitgadget
Re: [PATCH v2 1/3] load_branch_decorations: fix memory leak with non-static filters
Quoted 6 lines · Nicolas Guichard via GitGitGadget
load_branch_decorationscallsnormalize_glob_refon each string of filter'sstring_lists. This effectively replaces the potentially non-owning char* of those items with an owning char*.Set the
strdup_stringflag on thosestring_lists.
Quoted 7 lines
This was not caught until now because:
- when passingstring_listsalready with thestrdup_stringalready set, the behaviour was correct
- when passing staticstring_lists, the new char* remain reachable until program exitSigned-off-by Nicolas Guichard <[email protected]>
Not a proper review; just a couple style nits below...
log-tree.c void load_ref_decorations(struct decoration_filter *filter, int flags) · line 235
Quoted 6 lines
log-tree.c +4
-0@@ -232,6 +232,11 @@ void load_ref_decorations(struct decoration_filter *filter, int flags) +// normalize_glob_ref duplicates the strings + filter->exclude_ref_pattern->strdup_strings = true; + filter->include_ref_pattern->strdup_strings = true; + filter->exclude_ref_config_pattern->strdup_strings = true;
For the sake of older platforms and older compilers, we're still avoiding certain modernisms on this project. Instead:
* use /* ... */ style comments instead of // style
* use 1 instead of true (and 0 instead of false)
PATCH v2 2/3 rebase-update-refs: extract load_branch_decorations
In reply to Nicolas Guichard via GitGitGadgetFrom: Nicolas Guichard <[email protected]>
Extract load_branch_decorations from todo_list_add_update_ref_commands so it can be re-used in make_script_with_merges.
Since it can now be called multiple times, use non-static lists and place it next to load_ref_decorations to re-use the decoration_loaded guard.
--- log-tree.c | 21 +++++++++++++++++++++ log-tree.h | 1 + sequencer.c | 11 +---------- 3 files changed, 23 insertions(+), 10 deletions(-)
log-tree.c +21 -0
@@ -248,6 +248,27 @@ void load_ref_decorations(struct decoration_filter *filter, int flags) } } +void load_branch_decorations (void ) +{ +if (!decoration_loaded) { +struct string_list decorate_refs_exclude =STRING_LIST_INIT_NODUP ; +struct string_list decorate_refs_exclude_config =STRING_LIST_INIT_NODUP ; +struct string_list decorate_refs_include =STRING_LIST_INIT_NODUP ; +struct decoration_filter decoration_filter = { + .include_ref_pattern = &decorate_refs_include, + .exclude_ref_pattern = &decorate_refs_exclude, + .exclude_ref_config_pattern = &decorate_refs_exclude_config, + }; + +string_list_append (&decorate_refs_include,"refs/heads/" ); +load_ref_decorations (&decoration_filter,0 ); + +string_list_clear (&decorate_refs_exclude, false); +string_list_clear (&decorate_refs_exclude_config, false); +string_list_clear (&decorate_refs_include, false); + } +} +static void show_parents (struct commit *commit,int abbrev,FILE *file) {struct commit_list *p;
log-tree.h +1 -0
@@ -33,6 +33,7 @@ void log_write_email_headers(struct rev_info *opt, struct commit *commit,int *need_8bit_cte_p, int maybe_multipart);void load_ref_decorations (struct decoration_filter *filter,int flags); +void load_branch_decorations (void );void fmt_output_commit (struct strbuf *,struct commit *,struct rev_info *);void fmt_output_subject (struct strbuf *,const char *subject,struct rev_info *);
sequencer.c +1 -10
@@ -6403,14 +6403,6 @@ static int add_decorations_to_list(const struct commit *commit,static int todo_list_add_update_ref_commands (struct todo_list *todo_list) {int i, res; -static struct string_list decorate_refs_exclude =STRING_LIST_INIT_NODUP ; -static struct string_list decorate_refs_exclude_config =STRING_LIST_INIT_NODUP ; -static struct string_list decorate_refs_include =STRING_LIST_INIT_NODUP ; -struct decoration_filter decoration_filter = { - .include_ref_pattern = &decorate_refs_include, - .exclude_ref_pattern = &decorate_refs_exclude, - .exclude_ref_config_pattern = &decorate_refs_exclude_config, - };struct todo_add_branch_context ctx = { .buf = &todo_list->buf, .refs_to_oids =STRING_LIST_INIT_DUP ,
@@ -6419,8 +6411,7 @@ static int todo_list_add_update_ref_commands(struct todo_list *todo_list) ctx.items_alloc =2 * todo_list->nr +1 ;ALLOC_ARRAY (ctx.items, ctx.items_alloc); -string_list_append (&decorate_refs_include,"refs/heads/" ); -load_ref_decorations (&decoration_filter,0 ); +load_branch_decorations ();for (i =0 ; i < todo_list->nr; ) {struct todo_item *item = &todo_list->items[i];
Signature · 1 line
gitgitgadget
Re: [PATCH v2 2/3] rebase-update-refs: extract load_branch_decorations
Quoted 19 lines · Nicolas Guichard via GitGitGadget
Extract
load_branch_decorationsfromtodo_list_add_update_ref_commandsso it can be re-used inmake_script_with_merges.Since it can now be called multiple times, use non-static lists and place it next to
load_ref_decorationsto re-use thedecoration_loadedguard.Signed-off-by Nicolas Guichard <[email protected]>---
log-tree.c +9
-0@@ -248,6 +248,27 @@ void load_ref_decorations(struct decoration_filter *filter, int flags) +void load_branch_decorations (void ) +{ +if (!decoration_loaded) { +struct string_list decorate_refs_exclude =STRING_LIST_INIT_NODUP ; +struct string_list decorate_refs_exclude_config =STRING_LIST_INIT_NODUP ; +struct string_list decorate_refs_include =STRING_LIST_INIT_NODUP ; +struct decoration_filter decoration_filter = { + .include_ref_pattern = &decorate_refs_include, + .exclude_ref_pattern = &decorate_refs_exclude,
log-tree.c void load_ref_decorations(struct decoration_filter *filter, int flags) · line 266
Quoted 10 lines
log-tree.c +10
-0+ .exclude_ref_config_pattern = &decorate_refs_exclude_config, + }; + +string_list_append (&decorate_refs_include,"refs/heads/" ); +load_ref_decorations (&decoration_filter,0 ); + +string_list_clear (&decorate_refs_exclude, false); +string_list_clear (&decorate_refs_exclude_config, false); +string_list_clear (&decorate_refs_include, false); + }
Same minor style nit as previous patch:
* use 0 instead of false
PATCH v2 3/3 rebase-merges: try and use branch names as labels
In reply to Nicolas Guichard via GitGitGadgetFrom: Nicolas Guichard <[email protected]>
When interactively rebasing merge commits, the commit message is parsed to extract a probably meaningful label name. For instance if the merge commit is “Merge branch 'feature0'”, then the rebase script will have thes lines:
``` label feature0 merge -C $sha feature0 # “Merge branch 'feature0' ```
This heuristic fails in the case of octopus merges or when the merge commit message is actually unrelated to the parent commits.
An example that combines both is:
``` *---. 967bfa4 (HEAD -> integration) Integration |\ \ \ | | | * 2135be1 (feature2, feat2) Feature 2 | |_|/ |/| | | | * c88b01a Feature 1 | |/ |/| | * 75f3139 (feat0) Feature 0 |/ * 25c86d0 (main) Initial commit ```
yields the labels Integration, Integration-2 and Integration-3.
Fix this by using a branch name for each merge commit's parent that is the tip of at least one branch, and falling back to a label derived from the merge commit message otherwise.
In the example above, the labels become feat0, Integration and feature2.
--- sequencer.c | 25 +++++++++++++++++-------- t/t3404-rebase-interactive.sh | 4 ++-- t/t3430-rebase-merges.sh | 12 ++++++------ 3 files changed, 25 insertions(+), 16 deletions(-)
sequencer.c +17 -8
@@ -5819,7 +5819,7 @@ static int make_script_with_merges(struct pretty_print_context *pp,int root_with_onto = flags &TODO_LIST_ROOT_WITH_ONTO ;int skipped_commit =0 ;struct strbuf buf =STRBUF_INIT , oneline =STRBUF_INIT ; -struct strbuf label =STRBUF_INIT ; +struct strbuf label_from_message =STRBUF_INIT ;struct commit_list *commits =NULL , **tail = &commits, *iter;struct commit_list *tips =NULL , **tips_tail = &tips;struct commit *commit;
@@ -5842,6 +5842,7 @@ static int make_script_with_merges(struct pretty_print_context *pp,oidmap_init (&state.commit2label,0 );hashmap_init (&state.labels, labels_cmp,NULL ,0 );strbuf_init (&state.buf,32 ); +load_branch_decorations ();if (revs->cmdline.nr && (revs->cmdline.rev[0 ].flags &BOTTOM )) {struct labels_entry *onto_label_entry;
@@ -5902,18 +5903,18 @@ static int make_script_with_merges(struct pretty_print_context *pp,continue ; } -/* Create a label */ -strbuf_reset (&label); +/* Create a label from the commit message */ +strbuf_reset (&label_from_message);if (skip_prefix (oneline.buf,"Merge " , &p1) && (p1 =strchr (p1,'\'' )) && (p2 =strchr (++p1,'\'' ))) -strbuf_add (&label, p1, p2 - p1); +strbuf_add (&label_from_message, p1, p2 - p1);else if (skip_prefix (oneline.buf,"Merge pull request " , &p1) && (p1 =strstr (p1," from " ))) -strbuf_addstr (&label, p1 +strlen (" from " )); +strbuf_addstr (&label_from_message, p1 +strlen (" from " ));else -strbuf_addbuf (&label, &oneline); +strbuf_addbuf (&label_from_message, &oneline);strbuf_reset (&buf); strbuf_addf(&buf, "%s -C %s",
@@ -5921,6 +5922,14 @@ static int make_script_with_merges(struct pretty_print_context *pp,/* label the tips of merged branches */ for (; to_merge; to_merge = to_merge->next) { +const char *label = label_from_message.buf; +const struct name_decoration *decoration = +get_name_decoration (&to_merge->item->object); + +if (decoration) +skip_prefix (decoration->name,"refs/heads/" , + &label); + oid = &to_merge->item->object.oid;strbuf_addch (&buf,' ' );
@@ -5933,7 +5942,7 @@ static int make_script_with_merges(struct pretty_print_context *pp, tips_tail = &commit_list_insert (to_merge->item, tips_tail)->next; -strbuf_addstr (&buf,label_oid (oid, label.buf, &state)); +strbuf_addstr (&buf,label_oid (oid, label, &state)); }strbuf_addf (&buf," # %s" , oneline.buf);
@@ -6041,7 +6050,7 @@ static int make_script_with_merges(struct pretty_print_context *pp,free_commit_list (commits);free_commit_list (tips); -strbuf_release (&label); +strbuf_release (&label_from_message);strbuf_release (&oneline);strbuf_release (&buf);
t/t3404-rebase-interactive.sh +2 -2
@@ -1870,7 +1870,7 @@ test_expect_success '--update-refs adds commands with --rebase-merges' ' pick $(git log -1 --format=%h branch2~1) F pick $(git log -1 --format=%h branch2) I update-ref refs/heads/branch2 - label merge + label branch2 reset onto pick $(git log -1 --format=%h refs/heads/second) J update-ref refs/heads/second
@@ -1881,7 +1881,7 @@ test_expect_success '--update-refs adds commands with --rebase-merges' ' update-ref refs/heads/third pick $(git log -1 --format=%h HEAD~2) M update-ref refs/heads/no-conflict-branch - merge -C $(git log -1 --format=%h HEAD~1) merge # merge + merge -C $(git log -1 --format=%h HEAD~1) branch2 # merge update-ref refs/heads/merge-branch EOF
t/t3430-rebase-merges.sh +6 -6
@@ -108,19 +108,19 @@ test_expect_success 'generate correct todo list' ' reset onto pick $b B - label E + label first reset onto pick $c C label branch-point pick $f F pick $g G - label H + label second reset branch-point # C pick $d D - merge -C $e E # E - merge -C $h H # H + merge -C $e first # E + merge -C $h second # H EOF
@@ -462,11 +462,11 @@ test_expect_success 'A root commit can be a cousin, treat it that way' ' ' test_expect_success 'labels that are object IDs are rewritten' ' - git checkout -b third B && + git checkout --detach B && test_commit I && third=$(git rev-parse HEAD) && git checkout -b labels main && - git merge --no-commit third && + git merge --no-commit $third && test_tick && git commit -m "Merge commit '\''$third'\'' into labels" && echo noop >script-from-scratch &&
Signature · 1 line
gitgitgadget
v3 cover rebase-merges: try and use branch names for labels
In reply to Nicolas Guichard via GitGitGadgetWhen interactively rebasing merge commits, the commit message is parsed to extract a probably meaningful label name. For instance if the merge commit is “Merge branch 'feature0'”, then the rebase script will have thes lines:
label feature0
merge -C $sha feature0 # “Merge branch 'feature0'
This heuristic fails in the case of octopus merges or when the merge commit message is actually unrelated to the parent commits.
An example that combines both is:
*---. 967bfa4 (HEAD -> integration) Integration
|\ \ \ | | | * 2135be1 (feature2, feat2) Feature 2 | |_|/ |/| | | | * c88b01a Feature 1 | |/ |/| | * 75f3139 (feat0) Feature 0 |/
* 25c86d0 (main) Initial commit
which yields the labels Integration, Integration-2 and Integration-3.
Fix this by using a branch name for each merge commit's parent that is the tip of at least one branch, and falling back to a label derived from the merge commit message otherwise. In the example above, the labels become feat0, Integration and feature2.
Changes since v1:
* moved load_branch_decorations to re-use the decoration_loaded guard and avoid pointlessly appending "refs/heads/" to a static string_list, as pointed out by Junio C Hamano (thanks!)
* fixed a leak in load_branch_decorations found by making the filter string_lists non-static
Changes since v2:
* style changes (true/false -> 1/0 and // -> /* */)
Nicolas Guichard (3):
load_branch_decorations: fix memory leak with non-static filters
rebase-update-refs: extract load_branch_decorations
rebase-merges: try and use branch names as labels
log-tree.c | 26 +++++++++++++++++++++++++ log-tree.h | 1 + sequencer.c | 36 +++++++++++++++++------------------ t/t3404-rebase-interactive.sh | 4 ++-- t/t3430-rebase-merges.sh | 12 ++++++------ 5 files changed, 53 insertions(+), 26 deletions(-)
base-commit: 777489f9e09c8d0dd6b12f9d90de6376330577a2
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-git-1784%2Fnicolas-guichard%2Fuse-branch-names-for-rebase-merges-labels-v3
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-git-1784/nicolas-guichard/use-branch-names-for-rebase-merges-labels-v3
Pull-Request: https://github.com/git/git/pull/1784
Range-diff vs v2:
1: 6250a7f6d6c ! 1: e030ddd91f3 load_branch_decorations: fix memory leak with non-static filters
@@ log-tree.c: void load_ref_decorations(struct decoration_filter *filter, int flag
normalize_glob_ref(item, NULL, item->string);
}
+
-+ // normalize_glob_ref duplicates the strings
-+ filter->exclude_ref_pattern->strdup_strings = true;
-+ filter->include_ref_pattern->strdup_strings = true;
-+ filter->exclude_ref_config_pattern->strdup_strings = true;
++ /* normalize_glob_ref duplicates the strings */
++ filter->exclude_ref_pattern->strdup_strings = 1;
++ filter->include_ref_pattern->strdup_strings = 1;
++ filter->exclude_ref_config_pattern->strdup_strings = 1;
}
decoration_loaded = 1;
decoration_flags = flags;
2: 167418d10d1 ! 2: 1dad6096eb7 rebase-update-refs: extract load_branch_decorations
@@ log-tree.c: void load_ref_decorations(struct decoration_filter *filter, int flag
+ string_list_append(&decorate_refs_include, "refs/heads/");
+ load_ref_decorations(&decoration_filter, 0);
+
-+ string_list_clear(&decorate_refs_exclude, false);
-+ string_list_clear(&decorate_refs_exclude_config, false);
-+ string_list_clear(&decorate_refs_include, false);
++ string_list_clear(&decorate_refs_exclude, 0);
++ string_list_clear(&decorate_refs_exclude_config, 0);
++ string_list_clear(&decorate_refs_include, 0);
+ }
+}
+ 3: dfa1f0a7648 = 3: 19d8253da07 rebase-merges: try and use branch names as labels
Signature · 1 line
gitgitgadget
PATCH v3 1/3 load_branch_decorations: fix memory leak with non-static filters
From: Nicolas Guichard <[email protected]>
load_branch_decorations calls normalize_glob_ref on each string of filter's string_lists. This effectively replaces the potentially non-owning char* of those items with an owning char*.
Set the strdup_string flag on those string_lists.
This was not caught until now because:
- when passing string_lists already with the strdup_string already set, the behaviour was correct
- when passing static string_lists, the new char* remain reachable until program exit
--- log-tree.c | 5 +++++ 1 file changed, 5 insertions(+)
log-tree.c +5 -0
@@ -232,6 +232,11 @@ void load_ref_decorations(struct decoration_filter *filter, int flags)for_each_string_list_item (item, filter->exclude_ref_config_pattern) {normalize_glob_ref (item,NULL , item->string); } + +/* normalize_glob_ref duplicates the strings */ + filter->exclude_ref_pattern->strdup_strings =1 ; + filter->include_ref_pattern->strdup_strings =1 ; + filter->exclude_ref_config_pattern->strdup_strings =1 ; } decoration_loaded =1 ; decoration_flags = flags;
Signature · 1 line
gitgitgadget
PATCH v3 2/3 rebase-update-refs: extract load_branch_decorations
In reply to Nicolas Guichard via GitGitGadgetFrom: Nicolas Guichard <[email protected]>
Extract load_branch_decorations from todo_list_add_update_ref_commands so it can be re-used in make_script_with_merges.
Since it can now be called multiple times, use non-static lists and place it next to load_ref_decorations to re-use the decoration_loaded guard.
--- log-tree.c | 21 +++++++++++++++++++++ log-tree.h | 1 + sequencer.c | 11 +---------- 3 files changed, 23 insertions(+), 10 deletions(-)
log-tree.c +21 -0
@@ -248,6 +248,27 @@ void load_ref_decorations(struct decoration_filter *filter, int flags) } } +void load_branch_decorations (void ) +{ +if (!decoration_loaded) { +struct string_list decorate_refs_exclude =STRING_LIST_INIT_NODUP ; +struct string_list decorate_refs_exclude_config =STRING_LIST_INIT_NODUP ; +struct string_list decorate_refs_include =STRING_LIST_INIT_NODUP ; +struct decoration_filter decoration_filter = { + .include_ref_pattern = &decorate_refs_include, + .exclude_ref_pattern = &decorate_refs_exclude, + .exclude_ref_config_pattern = &decorate_refs_exclude_config, + }; + +string_list_append (&decorate_refs_include,"refs/heads/" ); +load_ref_decorations (&decoration_filter,0 ); + +string_list_clear (&decorate_refs_exclude,0 ); +string_list_clear (&decorate_refs_exclude_config,0 ); +string_list_clear (&decorate_refs_include,0 ); + } +} +static void show_parents (struct commit *commit,int abbrev,FILE *file) {struct commit_list *p;
log-tree.h +1 -0
@@ -33,6 +33,7 @@ void log_write_email_headers(struct rev_info *opt, struct commit *commit,int *need_8bit_cte_p, int maybe_multipart);void load_ref_decorations (struct decoration_filter *filter,int flags); +void load_branch_decorations (void );void fmt_output_commit (struct strbuf *,struct commit *,struct rev_info *);void fmt_output_subject (struct strbuf *,const char *subject,struct rev_info *);
sequencer.c +1 -10
@@ -6403,14 +6403,6 @@ static int add_decorations_to_list(const struct commit *commit,static int todo_list_add_update_ref_commands (struct todo_list *todo_list) {int i, res; -static struct string_list decorate_refs_exclude =STRING_LIST_INIT_NODUP ; -static struct string_list decorate_refs_exclude_config =STRING_LIST_INIT_NODUP ; -static struct string_list decorate_refs_include =STRING_LIST_INIT_NODUP ; -struct decoration_filter decoration_filter = { - .include_ref_pattern = &decorate_refs_include, - .exclude_ref_pattern = &decorate_refs_exclude, - .exclude_ref_config_pattern = &decorate_refs_exclude_config, - };struct todo_add_branch_context ctx = { .buf = &todo_list->buf, .refs_to_oids =STRING_LIST_INIT_DUP ,
@@ -6419,8 +6411,7 @@ static int todo_list_add_update_ref_commands(struct todo_list *todo_list) ctx.items_alloc =2 * todo_list->nr +1 ;ALLOC_ARRAY (ctx.items, ctx.items_alloc); -string_list_append (&decorate_refs_include,"refs/heads/" ); -load_ref_decorations (&decoration_filter,0 ); +load_branch_decorations ();for (i =0 ; i < todo_list->nr; ) {struct todo_item *item = &todo_list->items[i];
Signature · 1 line
gitgitgadget
PATCH v3 3/3 rebase-merges: try and use branch names as labels
In reply to Nicolas Guichard via GitGitGadgetFrom: Nicolas Guichard <[email protected]>
When interactively rebasing merge commits, the commit message is parsed to extract a probably meaningful label name. For instance if the merge commit is “Merge branch 'feature0'”, then the rebase script will have thes lines:
``` label feature0 merge -C $sha feature0 # “Merge branch 'feature0' ```
This heuristic fails in the case of octopus merges or when the merge commit message is actually unrelated to the parent commits.
An example that combines both is:
``` *---. 967bfa4 (HEAD -> integration) Integration |\ \ \ | | | * 2135be1 (feature2, feat2) Feature 2 | |_|/ |/| | | | * c88b01a Feature 1 | |/ |/| | * 75f3139 (feat0) Feature 0 |/ * 25c86d0 (main) Initial commit ```
yields the labels Integration, Integration-2 and Integration-3.
Fix this by using a branch name for each merge commit's parent that is the tip of at least one branch, and falling back to a label derived from the merge commit message otherwise.
In the example above, the labels become feat0, Integration and feature2.
--- sequencer.c | 25 +++++++++++++++++-------- t/t3404-rebase-interactive.sh | 4 ++-- t/t3430-rebase-merges.sh | 12 ++++++------ 3 files changed, 25 insertions(+), 16 deletions(-)
sequencer.c +17 -8
@@ -5819,7 +5819,7 @@ static int make_script_with_merges(struct pretty_print_context *pp,int root_with_onto = flags &TODO_LIST_ROOT_WITH_ONTO ;int skipped_commit =0 ;struct strbuf buf =STRBUF_INIT , oneline =STRBUF_INIT ; -struct strbuf label =STRBUF_INIT ; +struct strbuf label_from_message =STRBUF_INIT ;struct commit_list *commits =NULL , **tail = &commits, *iter;struct commit_list *tips =NULL , **tips_tail = &tips;struct commit *commit;
@@ -5842,6 +5842,7 @@ static int make_script_with_merges(struct pretty_print_context *pp,oidmap_init (&state.commit2label,0 );hashmap_init (&state.labels, labels_cmp,NULL ,0 );strbuf_init (&state.buf,32 ); +load_branch_decorations ();if (revs->cmdline.nr && (revs->cmdline.rev[0 ].flags &BOTTOM )) {struct labels_entry *onto_label_entry;
@@ -5902,18 +5903,18 @@ static int make_script_with_merges(struct pretty_print_context *pp,continue ; } -/* Create a label */ -strbuf_reset (&label); +/* Create a label from the commit message */ +strbuf_reset (&label_from_message);if (skip_prefix (oneline.buf,"Merge " , &p1) && (p1 =strchr (p1,'\'' )) && (p2 =strchr (++p1,'\'' ))) -strbuf_add (&label, p1, p2 - p1); +strbuf_add (&label_from_message, p1, p2 - p1);else if (skip_prefix (oneline.buf,"Merge pull request " , &p1) && (p1 =strstr (p1," from " ))) -strbuf_addstr (&label, p1 +strlen (" from " )); +strbuf_addstr (&label_from_message, p1 +strlen (" from " ));else -strbuf_addbuf (&label, &oneline); +strbuf_addbuf (&label_from_message, &oneline);strbuf_reset (&buf); strbuf_addf(&buf, "%s -C %s",
@@ -5921,6 +5922,14 @@ static int make_script_with_merges(struct pretty_print_context *pp,/* label the tips of merged branches */ for (; to_merge; to_merge = to_merge->next) { +const char *label = label_from_message.buf; +const struct name_decoration *decoration = +get_name_decoration (&to_merge->item->object); + +if (decoration) +skip_prefix (decoration->name,"refs/heads/" , + &label); + oid = &to_merge->item->object.oid;strbuf_addch (&buf,' ' );
@@ -5933,7 +5942,7 @@ static int make_script_with_merges(struct pretty_print_context *pp, tips_tail = &commit_list_insert (to_merge->item, tips_tail)->next; -strbuf_addstr (&buf,label_oid (oid, label.buf, &state)); +strbuf_addstr (&buf,label_oid (oid, label, &state)); }strbuf_addf (&buf," # %s" , oneline.buf);
@@ -6041,7 +6050,7 @@ static int make_script_with_merges(struct pretty_print_context *pp,free_commit_list (commits);free_commit_list (tips); -strbuf_release (&label); +strbuf_release (&label_from_message);strbuf_release (&oneline);strbuf_release (&buf);
t/t3404-rebase-interactive.sh +2 -2
@@ -1870,7 +1870,7 @@ test_expect_success '--update-refs adds commands with --rebase-merges' ' pick $(git log -1 --format=%h branch2~1) F pick $(git log -1 --format=%h branch2) I update-ref refs/heads/branch2 - label merge + label branch2 reset onto pick $(git log -1 --format=%h refs/heads/second) J update-ref refs/heads/second
@@ -1881,7 +1881,7 @@ test_expect_success '--update-refs adds commands with --rebase-merges' ' update-ref refs/heads/third pick $(git log -1 --format=%h HEAD~2) M update-ref refs/heads/no-conflict-branch - merge -C $(git log -1 --format=%h HEAD~1) merge # merge + merge -C $(git log -1 --format=%h HEAD~1) branch2 # merge update-ref refs/heads/merge-branch EOF
t/t3430-rebase-merges.sh +6 -6
@@ -108,19 +108,19 @@ test_expect_success 'generate correct todo list' ' reset onto pick $b B - label E + label first reset onto pick $c C label branch-point pick $f F pick $g G - label H + label second reset branch-point # C pick $d D - merge -C $e E # E - merge -C $h H # H + merge -C $e first # E + merge -C $h second # H EOF
@@ -462,11 +462,11 @@ test_expect_success 'A root commit can be a cousin, treat it that way' ' ' test_expect_success 'labels that are object IDs are rewritten' ' - git checkout -b third B && + git checkout --detach B && test_commit I && third=$(git rev-parse HEAD) && git checkout -b labels main && - git merge --no-commit third && + git merge --no-commit $third && test_tick && git commit -m "Merge commit '\''$third'\'' into labels" && echo noop >script-from-scratch &&
Signature · 1 line
gitgitgadget
Re: [PATCH v3 3/3] rebase-merges: try and use branch names as labels
Hi Nicolas
Quoted 28 lines · Nicolas Guichard via GitGitGadget
From: Nicolas Guichard <[email protected]>
When interactively rebasing merge commits, the commit message is parsed to extract a probably meaningful label name. For instance if the merge commit is “Merge branch 'feature0'”, then the rebase script will have thes lines:
``` label feature0 merge -C $sha feature0 # “Merge branch 'feature0' ```This heuristic fails in the case of octopus merges or when the merge commit message is actually unrelated to the parent commits.
An example that combines both is:
``` *---. 967bfa4 (HEAD -> integration) Integration |\ \ \ | | | * 2135be1 (feature2, feat2) Feature 2 | |_|/ |/| | | | * c88b01a Feature 1 | |/ |/| | * 75f3139 (feat0) Feature 0 |/ * 25c86d0 (main) Initial commit ```
Quoted 6 lines
yields the labels Integration, Integration-2 and Integration-3.
Fix this by using a branch name for each merge commit's parent that is the tip of at least one branch, and falling back to a label derived from the merge commit message otherwise.
In the example above, the labels become feat0, Integration and feature2.
This looks like a nicely described useful improvement, thank you for working on it. The way the code is structured means we always calculate the fallback label before seeing if there is a branch name we could use instead but as calculating the fallback is cheap I don't think that's a problem in practice.
Thanks
Phillip
Quoted 149 lines
Signed-off-by Nicolas Guichard <[email protected]>--- sequencer.c | 25 +++++++++++++++++-------- t/t3404-rebase-interactive.sh | 4 ++-- t/t3430-rebase-merges.sh | 12 ++++++------ 3 files changed, 25 insertions(+), 16 deletions(-)sequencer.c +17
-8@@ -5819,7 +5819,7 @@ static int make_script_with_merges(struct pretty_print_context *pp,int root_with_onto = flags &TODO_LIST_ROOT_WITH_ONTO ;int skipped_commit =0 ;struct strbuf buf =STRBUF_INIT , oneline =STRBUF_INIT ; -struct strbuf label =STRBUF_INIT ; +struct strbuf label_from_message =STRBUF_INIT ;struct commit_list *commits =NULL , **tail = &commits, *iter;struct commit_list *tips =NULL , **tips_tail = &tips;struct commit *commit;@@ -5842,6 +5842,7 @@ static int make_script_with_merges(struct pretty_print_context *pp,oidmap_init (&state.commit2label,0 );hashmap_init (&state.labels, labels_cmp,NULL ,0 );strbuf_init (&state.buf,32 ); +load_branch_decorations ();if (revs->cmdline.nr && (revs->cmdline.rev[0 ].flags &BOTTOM )) {struct labels_entry *onto_label_entry;@@ -5902,18 +5903,18 @@ static int make_script_with_merges(struct pretty_print_context *pp,continue ; } -/* Create a label */ -strbuf_reset (&label); +/* Create a label from the commit message */ +strbuf_reset (&label_from_message);if (skip_prefix (oneline.buf,"Merge " , &p1) && (p1 =strchr (p1,'\'' )) && (p2 =strchr (++p1,'\'' ))) -strbuf_add (&label, p1, p2 - p1); +strbuf_add (&label_from_message, p1, p2 - p1);else if (skip_prefix (oneline.buf,"Merge pull request " , &p1) && (p1 =strstr (p1," from " ))) -strbuf_addstr (&label, p1 +strlen (" from " )); +strbuf_addstr (&label_from_message, p1 +strlen (" from " ));else -strbuf_addbuf (&label, &oneline); +strbuf_addbuf (&label_from_message, &oneline);strbuf_reset (&buf); strbuf_addf(&buf, "%s -C %s",@@ -5921,6 +5922,14 @@ static int make_script_with_merges(struct pretty_print_context *pp,/* label the tips of merged branches */ for (; to_merge; to_merge = to_merge->next) { +const char *label = label_from_message.buf; +const struct name_decoration *decoration = +get_name_decoration (&to_merge->item->object); + +if (decoration) +skip_prefix (decoration->name,"refs/heads/" , + &label); + oid = &to_merge->item->object.oid;strbuf_addch (&buf,' ' );@@ -5933,7 +5942,7 @@ static int make_script_with_merges(struct pretty_print_context *pp, tips_tail = &commit_list_insert (to_merge->item, tips_tail)->next; -strbuf_addstr (&buf,label_oid (oid, label.buf, &state)); +strbuf_addstr (&buf,label_oid (oid, label, &state)); }strbuf_addf (&buf," # %s" , oneline.buf);@@ -6041,7 +6050,7 @@ static int make_script_with_merges(struct pretty_print_context *pp,free_commit_list (commits);free_commit_list (tips); -strbuf_release (&label); +strbuf_release (&label_from_message);strbuf_release (&oneline);strbuf_release (&buf);t/t3404-rebase-interactive.sh +2
-2@@ -1870,7 +1870,7 @@ test_expect_success '--update-refs adds commands with --rebase-merges' ' pick $(git log -1 --format=%h branch2~1) F pick $(git log -1 --format=%h branch2) I update-ref refs/heads/branch2 - label merge + label branch2 reset onto pick $(git log -1 --format=%h refs/heads/second) J update-ref refs/heads/second@@ -1881,7 +1881,7 @@ test_expect_success '--update-refs adds commands with --rebase-merges' ' update-ref refs/heads/third pick $(git log -1 --format=%h HEAD~2) M update-ref refs/heads/no-conflict-branch - merge -C $(git log -1 --format=%h HEAD~1) merge # merge + merge -C $(git log -1 --format=%h HEAD~1) branch2 # merge update-ref refs/heads/merge-branch EOFt/t3430-rebase-merges.sh +6
-6@@ -108,19 +108,19 @@ test_expect_success 'generate correct todo list' ' reset onto pick $b B - label E + label first reset onto pick $c C label branch-point pick $f F pick $g G - label H + label second reset branch-point # C pick $d D - merge -C $e E # E - merge -C $h H # H + merge -C $e first # E + merge -C $h second # H EOF@@ -462,11 +462,11 @@ test_expect_success 'A root commit can be a cousin, treat it that way' ' ' test_expect_success 'labels that are object IDs are rewritten' ' - git checkout -b third B && + git checkout --detach B && test_commit I && third=$(git rev-parse HEAD) && git checkout -b labels main && - git merge --no-commit third && + git merge --no-commit $third && test_tick && git commit -m "Merge commit '\''$third'\'' into labels" && echo noop >script-from-scratch &&
Re: [PATCH v3 3/3] rebase-merges: try and use branch names as labels
Quoted 36 lines · Phillip Wood
Hi Nicolas
Quoted 26 lines · Nicolas Guichard via GitGitGadget
From: Nicolas Guichard <[email protected]>
When interactively rebasing merge commits, the commit message is parsed to
extract a probably meaningful label name. For instance if the merge commit is “Merge branch 'feature0'”, then the rebase script will have thes lines:``` label feature0 merge -C $sha feature0 # “Merge branch 'feature0' ```This heuristic fails in the case of octopus merges or when the merge commit
message is actually unrelated to the parent commits.
An example that combines both is:``` *---. 967bfa4 (HEAD -> integration) Integration |\ \ \ | | | * 2135be1 (feature2, feat2) Feature 2 | |_|/ |/| | | | * c88b01a Feature 1 | |/ |/| | * 75f3139 (feat0) Feature 0 |/ * 25c86d0 (main) Initial commit ```Quoted 6 lines
yields the labels Integration, Integration-2 and Integration-3. Fix this by using a branch name for each merge commit's parent that is the
tip of at least one branch, and falling back to a label derived from the merge commit message otherwise.
In the example above, the labels become feat0, Integration and feature2.
Quoted 5 lines
This looks like a nicely described useful improvement, thank you for working on it. The way the code is structured means we always calculate the fallback label before seeing if there is a branch name we could use instead but as calculating the fallback is cheap I don't think that's a problem in practice.
Thanks, both of you.
Will queue.
Hi Nicolas
Thanks for working on this. This version looks good to me
Thanks
Phillip
Quoted 97 lines · Nicolas Guichard via GitGitGadget
When interactively rebasing merge commits, the commit message is parsed to extract a probably meaningful label name. For instance if the merge commit is “Merge branch 'feature0'”, then the rebase script will have thes lines:
label feature0
merge -C $sha feature0 # “Merge branch 'feature0'This heuristic fails in the case of octopus merges or when the merge commit message is actually unrelated to the parent commits.
An example that combines both is:
*---. 967bfa4 (HEAD -> integration) Integration
|\ \ \ | | | * 2135be1 (feature2, feat2) Feature 2 | |_|/ |/| | | | * c88b01a Feature 1 | |/ |/| | * 75f3139 (feat0) Feature 0 |/*
25c86d0(main) Initial commitwhich yields the labels Integration, Integration-2 and Integration-3.
Fix this by using a branch name for each merge commit's parent that is the tip of at least one branch, and falling back to a label derived from the merge commit message otherwise. In the example above, the labels become feat0, Integration and feature2.
Changes since v1:
* moved
load_branch_decorationsto re-use thedecoration_loadedguard and avoid pointlessly appending "refs/heads/" to a staticstring_list, as pointed out by Junio C Hamano (thanks!)
* fixed a leak inload_branch_decorationsfound by making the filterstring_listsnon-staticChanges since v2:
* style changes (true/false -> 1/0 and // -> /* */)
Nicolas Guichard (3):
load_branch_decorations: fix memory leak with non-static filters
rebase-update-refs: extractload_branch_decorations
rebase-merges: try and use branch names as labelslog-tree.c | 26 +++++++++++++++++++++++++ log-tree.h | 1 + sequencer.c | 36 +++++++++++++++++------------------ t/t3404-rebase-interactive.sh | 4 ++-- t/t3430-rebase-merges.sh | 12 ++++++------ 5 files changed, 53 insertions(+), 26 deletions(-)base-commit:
777489f9e09c8d0dd6b12f9d90de6376330577a2
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-git-1784%2Fnicolas-guichard%2Fuse-branch-names-for-rebase-merges-labels-v3
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-git-1784/nicolas-guichard/use-branch-names-for-rebase-merges-labels-v3
Pull-Request: https://github.com/git/git/pull/1784Range-diff vs v2:
1: 6250a7f6d6c ! 1: e030ddd91f3 load_branch_decorations: fix memory leak with non-static filters @@ log-tree.c: void load_ref_decorations(struct decoration_filter *filter, int flag normalize_glob_ref(item, NULL, item->string); } + -+ // normalize_glob_ref duplicates the strings -+ filter->exclude_ref_pattern->strdup_strings = true; -+ filter->include_ref_pattern->strdup_strings = true; -+ filter->exclude_ref_config_pattern->strdup_strings = true; ++ /* normalize_glob_ref duplicates the strings */ ++ filter->exclude_ref_pattern->strdup_strings = 1; ++ filter->include_ref_pattern->strdup_strings = 1; ++ filter->exclude_ref_config_pattern->strdup_strings = 1; } decoration_loaded = 1; decoration_flags = flags; 2: 167418d10d1 ! 2: 1dad6096eb7 rebase-update-refs: extract load_branch_decorations @@ log-tree.c: void load_ref_decorations(struct decoration_filter *filter, int flag + string_list_append(&decorate_refs_include, "refs/heads/"); + load_ref_decorations(&decoration_filter, 0); + -+ string_list_clear(&decorate_refs_exclude, false); -+ string_list_clear(&decorate_refs_exclude_config, false); -+ string_list_clear(&decorate_refs_include, false); ++ string_list_clear(&decorate_refs_exclude, 0); ++ string_list_clear(&decorate_refs_exclude_config, 0); ++ string_list_clear(&decorate_refs_include, 0); + } +} + 3: dfa1f0a7648 = 3: 19d8253da07 rebase-merges: try and use branch names as labels