Re: [PATCH 3/4] git-merge-changelog: prefer idx_t
Thanks for the many improvements, Paul. Nevertheless, I feel that a few code style changes are in order: * I don't much like side effects inside parenthesized expressions, if the side effect and the expression are not semantically related: if (mapping->index_mapping_reverse[--jj] < 0) For me, such side effects are only OK e.g. in parsers, where one writes code like if (buf[i++] == '\n') * gl_list.h says that the return value of some functions can be (size_t)(-1). For consistency with that, write (size_t)(-1) here as well. The '-1' reminds the reader of the -1 return values of functions like 'strchr' or 'strrchr'. * Since in this file, variables starting with 'i' generally are indices into FILE1 and variables starting with 'j' generally are indices into FILE2, it's better to rename in2 to jrev. 2023-05-22 Bruno Haible git-merge-changelog: Code style changes. * lib/git-merge-changelog.c: Don't make side effects to variables inside parenthesized expressions. Write (size_t)(-1), for consistency with gl_list.h. (compute_mapping): Rename variable in2 to jrev. >From 37bf50231750f10ae1332a892ba2d3679836938a Mon Sep 17 00:00:00 2001 From: Bruno Haible Date: Mon, 22 May 2023 14:32:42 +0200 Subject: [PATCH] git-merge-changelog: Code style changes. * lib/git-merge-changelog.c: Don't make side effects to variables inside parenthesized expressions. Write (size_t)(-1), for consistency with gl_list.h. (compute_mapping): Rename variable in2 to jrev. --- ChangeLog | 8 ++ lib/git-merge-changelog.c | 194 +- 2 files changed, 114 insertions(+), 88 deletions(-) diff --git a/ChangeLog b/ChangeLog index 37eb0a06c6..dec17652c4 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +2023-05-22 Bruno Haible + + git-merge-changelog: Code style changes. + * lib/git-merge-changelog.c: Don't make side effects to variables + inside parenthesized expressions. Write (size_t)(-1), for consistency + with gl_list.h. + (compute_mapping): Rename variable in2 to jrev. + 2023-05-21 Paul Eggert strtol: match 'configure' to 'make check' diff --git a/lib/git-merge-changelog.c b/lib/git-merge-changelog.c index 2d6a440644..2ef745ec9d 100644 --- a/lib/git-merge-changelog.c +++ b/lib/git-merge-changelog.c @@ -41,7 +41,7 @@ /* Installation: - $ gnulib-tool --create-testdir --dir=/tmp/testdir123 git-merge-changelog + $ ./gnulib-tool --create-testdir --dir=/tmp/testdir123 git-merge-changelog $ cd /tmp/testdir123 $ ./configure $ make @@ -400,16 +400,19 @@ entries_mapping_get (struct entries_mapping *mapping, idx_t i) ptrdiff_t best_j = -1; double best_j_similarity = 0.0; for (j = n2; j > 0; ) -if (mapping->index_mapping_reverse[--j] < 0) - { -double similarity = - entry_fstrcmp (entry_i, file2->entries[j], best_j_similarity); -if (similarity > best_j_similarity) - { -best_j = j; -best_j_similarity = similarity; - } - } +{ + j--; + if (mapping->index_mapping_reverse[j] < 0) +{ + double similarity = +entry_fstrcmp (entry_i, file2->entries[j], best_j_similarity); + if (similarity > best_j_similarity) +{ + best_j = j; + best_j_similarity = similarity; +} +} +} if (best_j_similarity >= FSTRCMP_THRESHOLD) { /* Found a similar entry in file2. */ @@ -419,17 +422,20 @@ entries_mapping_get (struct entries_mapping *mapping, idx_t i) double best_i_similarity = 0.0; idx_t ii; for (ii = n1; ii > 0; ) -if (mapping->index_mapping[--ii] < 0) - { -double similarity = - entry_fstrcmp (file1->entries[ii], entry_j, - best_i_similarity); -if (similarity > best_i_similarity) - { -best_i = ii; -best_i_similarity = similarity; - } - } +{ + ii--; + if (mapping->index_mapping[ii] < 0) +{ + double similarity = +entry_fstrcmp (file1->entries[ii], entry_j, + best_i_similarity); + if (similarity > best_i_similarity) +{ + best_i = ii; + best_i_similarity = similarity; +} +} +} if (best_i_similarity >= FSTRCMP_THRESHOLD && best_i == i) { mapping->index_mapping[i] = b
[PATCH 4/4] git-merge-changelog: port to size_t padding
* lib/git-merge-changelog (entry_hashcode): As a nicety, Prefer SIZE_WIDTH to computing it ourselves. --- ChangeLog | 4 lib/git-merge-changelog.c | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index eb6066b42c..8b29eed568 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,9 @@ 2023-05-21 Paul Eggert + git-merge-changelog: port to size_t padding + * lib/git-merge-changelog (entry_hashcode): + As a nicety, Prefer SIZE_WIDTH to computing it ourselves. + git-merge-changelog: prefer idx_t * lib/git-merge-changelog.c: Include idx.h. (struct entry, entry_create, entry_hashcode) diff --git a/lib/git-merge-changelog.c b/lib/git-merge-changelog.c index 604099628e..2d6a440644 100644 --- a/lib/git-merge-changelog.c +++ b/lib/git-merge-changelog.c @@ -238,7 +238,7 @@ entry_hashcode (const void *elt) size_t h = 0; for (s = entry->string, n = entry->length; n > 0; s++, n--) -h = (unsigned char) *s + ((h << 9) | (h >> (sizeof (size_t) * CHAR_BIT - 9))); +h = (unsigned char) *s + ((h << 9) | (h >> (SIZE_WIDTH - 9))); entry->hashcode = h; entry->hashcode_cached = true; -- 2.39.2
[PATCH 2/4] git-merge-changelog: ssize_t → ptrdiff_t
Prefer ptrdiff_t to ssize_t, as per <https://lists.gnu.org/archive/html/emacs-devel/2014-10/msg00019.html>. * lib/git-merge-changelog.c (struct entries_mapping) (entries_mapping_get, entries_mapping_reverse_get) (compute_mapping, struct edit, struct differences, OFFSET) (OFFSET_MAX, EXTRA_CONTEXT_FIELDS, compute_differences, main): Use ptrdiff_t, not ssize_t. * modules/git-merge-changelog (Depends-on): Add stdint for PTRDIFF_MAX. --- ChangeLog | 10 lib/git-merge-changelog.c | 109 ++-- modules/git-merge-changelog | 1 + 3 files changed, 66 insertions(+), 54 deletions(-) diff --git a/ChangeLog b/ChangeLog index bed79ab76b..611a8e5014 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,15 @@ 2023-05-21 Paul Eggert + git-merge-changelog: ssize_t → ptrdiff_t + Prefer ptrdiff_t to ssize_t, as per + <https://lists.gnu.org/archive/html/emacs-devel/2014-10/msg00019.html>. + * lib/git-merge-changelog.c (struct entries_mapping) + (entries_mapping_get, entries_mapping_reverse_get) + (compute_mapping, struct edit, struct differences, OFFSET) + (OFFSET_MAX, EXTRA_CONTEXT_FIELDS, compute_differences, main): + Use ptrdiff_t, not ssize_t. + * modules/git-merge-changelog (Depends-on): Add stdint for PTRDIFF_MAX. + git-merge-changelog: port to ssize_t padding * lib/git-merge-changelog.c (OFFSET_MAX): New macro, as a nicety. diff --git a/lib/git-merge-changelog.c b/lib/git-merge-changelog.c index 16d874bd04..3e749ed59d 100644 --- a/lib/git-merge-changelog.c +++ b/lib/git-merge-changelog.c @@ -157,6 +157,7 @@ #include #include +#include #include #include #include @@ -372,18 +373,18 @@ struct entries_mapping /* Mapping from indices in FILE1 to indices in FILE2. A value -1 means that the entry from FILE1 is not found in FILE2. A value -2 means that it has not yet been computed. */ - ssize_t *index_mapping; + ptrdiff_t *index_mapping; /* Mapping from indices in FILE2 to indices in FILE1. A value -1 means that the entry from FILE2 is not found in FILE1. A value -2 means that it has not yet been computed. */ - ssize_t *index_mapping_reverse; + ptrdiff_t *index_mapping_reverse; }; /* Look up (or lazily compute) the mapping of an entry in FILE1. i is the index in FILE1. Return the index in FILE2, or -1 when the entry is not found in FILE2. */ -static ssize_t -entries_mapping_get (struct entries_mapping *mapping, ssize_t i) +static ptrdiff_t +entries_mapping_get (struct entries_mapping *mapping, ptrdiff_t i) { if (mapping->index_mapping[i] < -1) { @@ -392,10 +393,10 @@ entries_mapping_get (struct entries_mapping *mapping, ssize_t i) size_t n1 = file1->num_entries; size_t n2 = file2->num_entries; struct entry *entry_i = file1->entries[i]; - ssize_t j; + ptrdiff_t j; /* Search whether it approximately occurs in file2. */ - ssize_t best_j = -1; + ptrdiff_t best_j = -1; double best_j_similarity = 0.0; for (j = n2 - 1; j >= 0; j--) if (mapping->index_mapping_reverse[j] < 0) @@ -413,9 +414,9 @@ entries_mapping_get (struct entries_mapping *mapping, ssize_t i) /* Found a similar entry in file2. */ struct entry *entry_j = file2->entries[best_j]; /* Search whether it approximately occurs in file1 at index i. */ - ssize_t best_i = -1; + ptrdiff_t best_i = -1; double best_i_similarity = 0.0; - ssize_t ii; + ptrdiff_t ii; for (ii = n1 - 1; ii >= 0; ii--) if (mapping->index_mapping[ii] < 0) { @@ -445,8 +446,8 @@ entries_mapping_get (struct entries_mapping *mapping, ssize_t i) /* Look up (or lazily compute) the mapping of an entry in FILE2. j is the index in FILE2. Return the index in FILE1, or -1 when the entry is not found in FILE1. */ -static ssize_t -entries_mapping_reverse_get (struct entries_mapping *mapping, ssize_t j) +static ptrdiff_t +entries_mapping_reverse_get (struct entries_mapping *mapping, ptrdiff_t j) { if (mapping->index_mapping_reverse[j] < -1) { @@ -455,10 +456,10 @@ entries_mapping_reverse_get (struct entries_mapping *mapping, ssize_t j) size_t n1 = file1->num_entries; size_t n2 = file2->num_entries; struct entry *entry_j = file2->entries[j]; - ssize_t i; + ptrdiff_t i; /* Search whether it approximately occurs in file1. */ - ssize_t best_i = -1; + ptrdiff_t best_i = -1; double best_i_similarity = 0.0; for (i = n1 - 1; i >= 0; i--) if (mapping->index_mapping[i] < 0) @@ -476,9 +477,9 @@ entries_mapping_reverse_get (struct entries_mapping *mapping, ssize_t j) /* Found a similar entry in file1. */ struct entry *entry_i = file1->entries[best
[PATCH 3/4] git-merge-changelog: prefer idx_t
* lib/git-merge-changelog.c: Include idx.h. (struct entry, entry_create, entry_hashcode) (struct changelog_file, read_changelog_file) (entries_mapping_get, entries_mapping_reverse_get) (compute_mapping, struct edit, struct differences) (compute_differences, find_paragraph_end) (try_split_merged_entry, struct conflict, conflict_write, main): Prefer idx_t to ptrdiff_t and size_t when the value is a nonnegative index or size. Change a few for-loops so that the index never goes negative. * modules/git-merge-changelog (Depends-on): Add idx. --- ChangeLog | 13 +++ lib/git-merge-changelog.c | 201 ++-- modules/git-merge-changelog | 1 + 3 files changed, 116 insertions(+), 99 deletions(-) diff --git a/ChangeLog b/ChangeLog index 611a8e5014..eb6066b42c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,18 @@ 2023-05-21 Paul Eggert + git-merge-changelog: prefer idx_t + * lib/git-merge-changelog.c: Include idx.h. + (struct entry, entry_create, entry_hashcode) + (struct changelog_file, read_changelog_file) + (entries_mapping_get, entries_mapping_reverse_get) + (compute_mapping, struct edit, struct differences) + (compute_differences, find_paragraph_end) + (try_split_merged_entry, struct conflict, conflict_write, main): + Prefer idx_t to ptrdiff_t and size_t when the value is a + nonnegative index or size. Change a few for-loops so that + the index never goes negative. + * modules/git-merge-changelog (Depends-on): Add idx. + git-merge-changelog: ssize_t → ptrdiff_t Prefer ptrdiff_t to ssize_t, as per <https://lists.gnu.org/archive/html/emacs-devel/2014-10/msg00019.html>. diff --git a/lib/git-merge-changelog.c b/lib/git-merge-changelog.c index 3e749ed59d..604099628e 100644 --- a/lib/git-merge-changelog.c +++ b/lib/git-merge-changelog.c @@ -165,6 +165,7 @@ #include #include "error.h" +#include "idx.h" #include "read-file.h" #include "gl_xlist.h" #include "gl_array_list.h" @@ -195,7 +196,7 @@ struct entry { char *string; - size_t length; + idx_t length; /* Cache for the hash code. */ bool hashcode_cached; size_t hashcode; @@ -205,7 +206,7 @@ struct entry The memory region passed by the caller must of indefinite extent. It is *not* copied here. */ static struct entry * -entry_create (char *string, size_t length) +entry_create (char *string, idx_t length) { struct entry *result = XMALLOC (struct entry); result->string = string; @@ -233,7 +234,7 @@ entry_hashcode (const void *elt) { /* See https://www.haible.de/bruno/hashfunc.html. */ const char *s; - size_t n; + idx_t n; size_t h = 0; for (s = entry->string, n = entry->length; n > 0; s++, n--) @@ -287,7 +288,7 @@ struct changelog_file /* The entries, as a list in opposite direction. */ gl_list_t /* */ entries_reversed; /* The entries, as an array. */ - size_t num_entries; + idx_t num_entries; struct entry **entries; }; @@ -354,7 +355,7 @@ read_changelog_file (const char *filename, struct changelog_file *result) result->num_entries = gl_list_size (result->entries_list); result->entries = XNMALLOC (result->num_entries, struct entry *); { -size_t index = 0; +idx_t index = 0; gl_list_iterator_t iter = gl_list_iterator (result->entries_list); const void *elt; gl_list_node_t node; @@ -384,22 +385,22 @@ struct entries_mapping i is the index in FILE1. Return the index in FILE2, or -1 when the entry is not found in FILE2. */ static ptrdiff_t -entries_mapping_get (struct entries_mapping *mapping, ptrdiff_t i) +entries_mapping_get (struct entries_mapping *mapping, idx_t i) { if (mapping->index_mapping[i] < -1) { struct changelog_file *file1 = mapping->file1; struct changelog_file *file2 = mapping->file2; - size_t n1 = file1->num_entries; - size_t n2 = file2->num_entries; + idx_t n1 = file1->num_entries; + idx_t n2 = file2->num_entries; struct entry *entry_i = file1->entries[i]; - ptrdiff_t j; + idx_t j; /* Search whether it approximately occurs in file2. */ ptrdiff_t best_j = -1; double best_j_similarity = 0.0; - for (j = n2 - 1; j >= 0; j--) -if (mapping->index_mapping_reverse[j] < 0) + for (j = n2; j > 0; ) +if (mapping->index_mapping_reverse[--j] < 0) { double similarity = entry_fstrcmp (entry_i, file2->entries[j], best_j_similarity); @@ -416,9 +417,9 @@ entries_mapping_get (struct entries_mapping *mapping, ptrdiff_t i) /* Search whether it approximately occurs in file1 at index i. */ ptrdiff_t best_i = -1; double best_i_similarity = 0.0; - ptrdiff_t ii; -
[PATCH 1/4] git-merge-changelog: port to ssize_t padding
* lib/git-merge-changelog.c (OFFSET_MAX): New macro, as a nicety. --- ChangeLog | 5 + lib/git-merge-changelog.c | 1 + 2 files changed, 6 insertions(+) diff --git a/ChangeLog b/ChangeLog index 9cdb603b9b..bed79ab76b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2023-05-21 Paul Eggert + + git-merge-changelog: port to ssize_t padding + * lib/git-merge-changelog.c (OFFSET_MAX): New macro, as a nicety. + 2023-05-21 Bruno Haible limits-h tests: Check the value of SSIZE_MAX. diff --git a/lib/git-merge-changelog.c b/lib/git-merge-changelog.c index 67a932c5df..16d874bd04 100644 --- a/lib/git-merge-changelog.c +++ b/lib/git-merge-changelog.c @@ -639,6 +639,7 @@ struct differences #define ELEMENT struct entry * #define EQUAL entry_equals #define OFFSET ssize_t +#define OFFSET_MAX SSIZE_MAX #define EXTRA_CONTEXT_FIELDS \ ssize_t *index_mapping; \ ssize_t *index_mapping_reverse; -- 2.39.2
Re: gnupload, git-merge-changelog: Fix module description
I did: > * modules/git-merge-changelog (License): Change to GPLv2+. That doesn't work: It produces gnulib-tool warnings gnulib-tool: warning: module git-merge-changelog depends on a module with an incompatible license: c-strstr gnulib-tool: warning: module git-merge-changelog depends on a module with an incompatible license: diffseq gnulib-tool: warning: module git-merge-changelog depends on a module with an incompatible license: fstrcmp gnulib-tool: warning: module git-merge-changelog depends on a module with an incompatible license: fwriteerror gnulib-tool: warning: module git-merge-changelog depends on a module with an incompatible license: rbtreehash-list gnulib-tool: warning: module git-merge-changelog depends on a module with an incompatible license: xalloc gnulib-tool: warning: module git-merge-changelog depends on a module with an incompatible license: xalloc-die gnulib-tool: warning: module git-merge-changelog depends on a module with an incompatible license: xlist gnulib-tool: warning: module git-merge-changelog depends on a module with an incompatible license: xmalloca 2021-06-04 Bruno Haible git-merge-changelog: Fix license. * modules/git-merge-changelog (License): Change back to GPL. * lib/git-merge-changelog.c: Use a GPLv3+ notice. diff --git a/lib/git-merge-changelog.c b/lib/git-merge-changelog.c index 0301f8f..f1697de 100644 --- a/lib/git-merge-changelog.c +++ b/lib/git-merge-changelog.c @@ -1,12 +1,12 @@ /* git-merge-changelog - git "merge" driver for GNU style ChangeLog files. Copyright (C) 2008-2021 Bruno Haible - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + This file is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3 of the License, + or (at your option) any later version. - This program is distributed in the hope that it will be useful, + This file is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. diff --git a/modules/git-merge-changelog b/modules/git-merge-changelog index a88573c..c58ddc7 100644 --- a/modules/git-merge-changelog +++ b/modules/git-merge-changelog @@ -35,7 +35,7 @@ git_merge_changelog_LDADD = libgnu.a @LIBINTL@ $(LIBTHREAD) Include: License: -GPLv2+ +GPL Maintainer: all
gnupload, git-merge-changelog: Fix module description
In our current convention, when we talk about GPL we mean GPLv3+. The module 'git-merge-changelog', however, is meant to be GPLv2+, not GPLv3+ (for compatibility with git itself). And the module 'gnupload' is meant to be GPLv2+ as well. But gnulib-tool does not support build tools under GPLv2+ so far. This patch addresses it. 2021-06-04 Bruno Haible gnupload, git-merge-changelog: Fix module description. * gnulib-tool (func_import, func_create_testdir): Treat 'GPLv2+ build tool' like 'GPLed build tool'. * pygnulib/GLImport.py (prepare): Likewise. * modules/gnupload (License): Change to 'GPLv2+ build tool'. * modules/git-merge-changelog (License): Change to GPLv2+. >From a8f2dda75f0322d9c5d2e2cd8cebd6237b5249b1 Mon Sep 17 00:00:00 2001 From: Bruno Haible Date: Fri, 4 Jun 2021 20:42:44 +0200 Subject: [PATCH] gnupload, git-merge-changelog: Fix module description. * gnulib-tool (func_import, func_create_testdir): Treat 'GPLv2+ build tool' like 'GPLed build tool'. * pygnulib/GLImport.py (prepare): Likewise. * modules/gnupload (License): Change to 'GPLv2+ build tool'. * modules/git-merge-changelog (License): Change to GPLv2+. --- ChangeLog | 9 + gnulib-tool | 4 ++-- modules/git-merge-changelog | 2 +- modules/gnupload| 2 +- pygnulib/GLImport.py| 3 ++- 5 files changed, 15 insertions(+), 5 deletions(-) diff --git a/ChangeLog b/ChangeLog index 0e2bb84..07045eb 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,14 @@ 2021-06-04 Bruno Haible + gnupload, git-merge-changelog: Fix module description. + * gnulib-tool (func_import, func_create_testdir): Treat + 'GPLv2+ build tool' like 'GPLed build tool'. + * pygnulib/GLImport.py (prepare): Likewise. + * modules/gnupload (License): Change to 'GPLv2+ build tool'. + * modules/git-merge-changelog (License): Change to GPLv2+. + +2021-06-04 Bruno Haible + New directory with license notices. * etc/license-notices/*: New files. diff --git a/gnulib-tool b/gnulib-tool index 205503a..ad71f6e 100755 --- a/gnulib-tool +++ b/gnulib-tool @@ -5039,7 +5039,7 @@ func_import () for module in $main_modules; do license=`func_get_license $module` case $license in -'GPLed build tool') ;; +'GPLv2+ build tool' | 'GPLed build tool') ;; 'public domain' | 'unlimited' | 'unmodifiable license text') ;; *) case "$lgpl" in @@ -6240,7 +6240,7 @@ func_create_testdir () for module in $modules; do license=`func_get_license "$module"` case "$license" in - 'GPLed build tool') ;; + 'GPLv2+ build tool' | 'GPLed build tool') ;; 'public domain' | 'unlimited' | 'unmodifiable license text') ;; *) case "$requested_license" in diff --git a/modules/git-merge-changelog b/modules/git-merge-changelog index c58ddc7..a88573c 100644 --- a/modules/git-merge-changelog +++ b/modules/git-merge-changelog @@ -35,7 +35,7 @@ git_merge_changelog_LDADD = libgnu.a @LIBINTL@ $(LIBTHREAD) Include: License: -GPL +GPLv2+ Maintainer: all diff --git a/modules/gnupload b/modules/gnupload index acb4f0e..37179c2 100644 --- a/modules/gnupload +++ b/modules/gnupload @@ -15,7 +15,7 @@ Makefile.am: Include: License: -GPLed build tool +GPLv2+ build tool Maintainer: coreutils diff --git a/pygnulib/GLImport.py b/pygnulib/GLImport.py index 27a01be..4fa0025 100644 --- a/pygnulib/GLImport.py +++ b/pygnulib/GLImport.py @@ -837,7 +837,8 @@ AC_DEFUN([%s_FILE_LIST], [\n''' % macro_prefix listing = list() compatibilities = dict() incompatibilities = string() -compatibilities['all'] = ['GPLed build tool', 'public domain', 'unlimited', +compatibilities['all'] = ['GPLv2+ build tool', 'GPLed build tool', + 'public domain', 'unlimited', 'unmodifiable license text'] compatibilities[3] = ['LGPL', 'LGPLv2+', 'LGPLv3+'] compatibilities[2] = ['LGPLv2+'] -- 2.7.4
git-merge-changelog in debian
Hi, Per user request, git-merge-changelog is now a package in debian. The binary package is generated from the gnulib source package, along with the gnulib binary package. Debian mandates man pages for all binaries, so I adapted the comments at the top of git-merge-changelog.c into a man page. My *roff is a bit ropy, so I used perl's pod format. I've attached it, along with the pod2man output, feel free to include it if it's any use. cheers, Ian. -- Ian Beckwith - i...@erislabs.net - http://erislabs.net/ianb/ GPG fingerprint: AF6C C0F1 1E74 424B BCD5 4814 40EC C154 A8BA C1EA =head1 NAME git-merge-changelog - git merge driver for GNU ChangeLog files =head1 DESCRIPTION The default merge driver of 'git' Balways produces conflicts when pulling public modifications into a privately modified ChangeLog file. This is because ChangeLog files are always modified at the top; the default merge driver has no clue how to deal with this. Furthermore the conflicts are presented with more EltEltEltElt EgtEgtEgtEgt markers than necessary; this is because the default merge driver makes pointless efforts to look at the individual line changes inside a ChangeLog entry. This program serves as a 'git' merge driver that avoids these problems. =over 4 =item Z1. It produces no conflict when ChangeLog entries have been inserted at the top both in the public and in the private modification. It puts the privately added entries above the publicly added entries. =item Z2. It respects the structure of ChangeLog files: entries are not split into lines but kept together. =item Z3. It also handles the case of small modifications of past ChangeLog entries, or of removed ChangeLog entries: they are merged as one would expect it. =item Z4. Conflicts are presented at the top of the file, rather than where they occurred, so that the user will see them immediately. (Unlike for source code written in some programming language, conflict markers that are located several hundreds lines from the top will not cause any syntax error and therefore would be likely to remain unnoticed.) =back =head2 For git users: =over 4 =item - Add to .git/config of the checkout (or to your $HOME/.gitconfig) the lines [merge merge-changelog] name = GNU-style ChangeLog merge driver driver = /usr/bin/git-merge-changelog %O %A %B =item - In every directory that contains a ChangeLog file, add a file '.gitattributes' with this line: ChangeLogmerge=merge-changelog (See man 5 gitattributes for more info.) =back =head2 For bzr users: =over 4 =item - Install the 'extmerge' bzr plug-in listed at Lhttp://doc.bazaar.canonical.com/plugins/en/index.html Lhttp://wiki.bazaar.canonical.com/BzrPlugins =item - Add to your $HOME/.bazaar/bazaar.conf the line external_merge = git-merge-changelog %b %T %o =item - Then, to merge a conflict in a ChangeLog file, use $ bzr extmerge ChangeLog =back =head2 For hg users: =over 4 =item - Add to your $HOME/.hgrc the lines [merge-patterns] ChangeLog = git-merge-changelog [merge-tools] git-merge-changelog.executable = /usr/bin/git-merge-changelog git-merge-changelog.args = $base $local $other See Lhttp://www.selenic.com/mercurial/hgrc.5.html section Bmerge-tools for reference. =back =head2 Use as an alternative to 'diff3': git-merge-changelog performs the same role as diff3 -m, just with reordered arguments: $ git-merge-changelog %O %A %B is comparable to $ diff3 -m %A %O %B =head2 Calling convention: A merge driver is called with three filename arguments: =over 4 =item Z1. %O = The common ancestor of %A and %B. =item Z2. %A = The file's contents from the current branch. =item Z3. %B = The file's contents from the other branch; this is the contents being merged in. =back In case of a git stash apply or of an upstream pull (e.g. from a subsystem maintainer to a central maintainer) or of a downstream pull with --rebase: =over 4 =item Z2. %A = The file's newest pulled contents; modified by other committers. =item Z3. %B = The user's newest copy of the file; modified by the user. =back In case of a downstream pull (e.g. from a central repository to the user) or of an upstream pull with --rebase: =over 4 =item Z2. %A = The user's newest copy of the file; modified by the user. =item Z3. %B = The file's newest pulled contents; modified by other committers. =back It should write its merged output into file %A. It can also echo some remarks to stdout. It should exit with return code 0 if the merge could be resolved cleanly, or with non-zero return code if there were conflicts. =head2 How it works: The structure of a ChangeLog file: It consists of ChangeLog entries. A ChangeLog entry starts at a line following a blank line and that starts with a non-whitespace character, or at the beginning of a file. The merge driver works as follows: It reads the three files into memory and dissects them into ChangeLog entries. It then finds
Re: git-merge-changelog and EOL format on Windows
Date: Mon, 20 Jan 2014 03:57:40 +0100 (CET) From: Bruno Haible br...@clisp.org Cc: br...@clisp.org no similar explanation is provided for the output. The explanation is the general Newline Guidelines from unicode.org: http://www.unicode.org/versions/Unicode6.2.0/ch05.pdf#G10213 p. 156 rule R3a: If the intended target is unknown, map to the platform newline convention. And rule R4a as well. I doubt that Unicode Newline Guidelines are a good source in this case. They are just general guidelines for when no other higher-level protocols tell us what is TRT. But even those guidelines say, in rule R3: If the intended target is known, map NLF, LS, and PS depending on the target conventions. And in this case, the intended target _is_ indeed known: it is a Git repository that clones an upstream one, where files should preserve their EOL format, by virtue of the Git core.autocrlf setting, and because the files from the upstream repository will get tarred as-is into release tarballs on a Posix platform. According to the git documentation http://git-scm.com/book/ch7-1.html, section core.autocrlf, the setting git config --global core.autocrlf input should be perfect for Windows users. I don't think the way I set up my Git repositories is the issue here: after all, I used a documented value of a documented option. But since you've raised this... I'm not sure core.autocrlf input is really perfect: the documentation is unclear about what it does in all kinds of corner cases, like with files that have CRLF EOL format, such as DOS/Windows batch files, that are kept in the repository. In particular, if you commit changes in such a file, will Git convert its CRLF EOLs into Unix-style LF-only EOLs? If it will, that will (a) mark every line modified, and (b) cause the file to have Unix-style EOLs in the release tarballs, which will preclude the batch files from working correctly at least on some versions of DOS/Windows. Also, what if I create a new file with CRLF EOLs and commit it -- will it keep its EOL format? And what happens if I decide to deliberately convert a versioned file from Unix to DOS EOL format, or vice versa? I see no answers to these questions in the documentation, so even if today Git does work as I expect, it might change that in the future based on some judgment of the maintainers (especially since msysgit is maintained separately from the upstream Git, and includes quite a lot of code that is not in the upstream). Undocumented behavior is subject to change without notice. AFAICT, it already did in the not-so-far past. Therefore, I believe core.autocrlf false _is_ the right choice, as it can never do any harm by itself. It leaves the EOL issue to the user. And if you use Emacs as your text editor, editing will preserve the EOL format of existing files, so files that started as Unix EOL will stay that way. I can understand why you don't want git config --global core.autocrlf true (namely if you work a lot with Cygwin / Unix tools). I don't use Cygwin, and native ports of Unix tools I use have no trouble with CRLF EOLs. Emacs certainly doesn't, and neither do GCC, Grep, Diffutils, Patch, etc. So Cygwin etc. is not the source of the problem that triggered this patch. Anyway, IMO core.autocrlf true is even worse than input, especially with binary files and files with mixed EOLs. (Yes, I know about core.safecrlf, but I don't trust any program to be entirely safe when it futzes with the EOL format, and have enough gray hair to bear witness.) What triggered this patch was that I used git-merge-changelog with the msysgit port of Git for Windows, to cherry-pick a changeset from one branch to another. See this discussion on gdb-patches: https://sourceware.org/ml/gdb-patches/2014-01/msg00348.html and its 2 follow-ups for the details. As you might know, Emacs is on its way to switch to Git as its VCS. Emacs does have files with CRLF EOLs in its repository, does maintain at least 2 branches with cherry-picks/merges between them being routine, and some of its contributors (including myself) work on MS-Windows. In bzr, the current VCS used by Emacs, the default EOL handling is the equivalent of Git's autocrlf false, so users are accustomed to this setup, and will most probably want to carry it to Git. It would be a pity to have this problem get in the way when we switch. I was lucky to discover this issue in time to have it resolved. Given the above general rule, I believe that git-merge-changelog is not the only program that outputs CR-LFs on Windows, for input that had only LF as line terminator. Therefore setting core.autolf to 'true' should be the better solution, compared to modifying git-merge-changelog. I hope the above convinced you otherwise. In a nutshell, I think the EOL issue is best left to the user; programs should not make any changes there, unless specifically instructed by the user. The proposed changes will cause git-merge
Re: git-merge-changelog and EOL format on Windows
Hi Eli, Thank you for the suggestion. no similar explanation is provided for the output. The explanation is the general Newline Guidelines from unicode.org: http://www.unicode.org/versions/Unicode6.2.0/ch05.pdf#G10213 p. 156 rule R3a: If the intended target is unknown, map to the platform newline convention. And rule R4a as well. The result is that, when the program runs on MS-Windows, the merged ChangeLog file is always output with the DOS-style CR-LF EOLs. This gets in the way when git's core.autocrlf config option is set to false, because almost all projects have ChangeLog files in Unix LF-only EOL format, and the merged file will have all of its lines modified. Oops! According to the git documentation http://git-scm.com/book/ch7-1.html, section core.autocrlf, the setting git config --global core.autocrlf input should be perfect for Windows users. I can understand why you don't want git config --global core.autocrlf true (namely if you work a lot with Cygwin / Unix tools). Given the above general rule, I believe that git-merge-changelog is not the only program that outputs CR-LFs on Windows, for input that had only LF as line terminator. Therefore setting core.autolf to 'true' should be the better solution, compared to modifying git-merge-changelog. + p = strchr (buf, '\n'); + + if (p buf) + { + if (p[-1] == '\r') + result = true; + } + } If, despite your expectations, the first line is longer than 255 bytes, p will be NULL, and with a high probability on Linux/x86 (buf being stack-allocated, it is at an address between 0x8000 and 0xC000), p buf will evaluate to true, and the next statement will crash. Bruno
git-merge-changelog and EOL format on Windows
git-merge-changelog does its I/O in text mode. This is explained in the sources for the input direction: /* Read a ChangeLog file into memory. Return the contents in *RESULT. */ static void read_changelog_file (const char *filename, struct changelog_file *result) { /* Read the file in text mode, otherwise it's hard to recognize empty lines. */ But no similar explanation is provided for the output. The result is that, when the program runs on MS-Windows, the merged ChangeLog file is always output with the DOS-style CR-LF EOLs. This gets in the way when git's core.autocrlf config option is set to false, because almost all projects have ChangeLog files in Unix LF-only EOL format, and the merged file will have all of its lines modified. Oops! The changes below make git-merge-changelog on Windows attempt to preserve the EOL format of the original file. 2014-01-18 Eli Zaretskii e...@gnu.org Preserve the EOL format of the original ChangeLog file. * git-merge-changelog.c (detect_eol): New function. (main): Use it to detect the EOL format of the destination file (%A). If %A does not have DOS CR-LF EOL format, write the output in binary mode. --- gllib/git-merge-changelog.c~2013-01-24 07:30:17.0 +0200 +++ gllib/git-merge-changelog.c 2014-01-18 11:32:16.140625000 +0200 @@ -279,6 +279,48 @@ return similarity; } +/* Read the initial block of a ChangeLog file, and return true if it + uses the DOS/Windows CR-LF end-of-line format, false otherwise. */ +static bool +detect_eol (const char *destfn, const char *ancestorfn) +{ +#ifdef __MINGW32__ + /* ChangeLog files have relatively short lines, so we don't need to + read too much stuff, or worry about too long lines. */ + char buf[256]; + FILE *f = fopen (destfn, rb); + bool result = false; /* default to Unix-style EOLs */ + size_t nread; + + /* If the destination doesn't exist, inherit the EOL format from the + ancestor. */ + if (!f) +f = fopen (ancestorfn, rb); + if (f (nread = fread (buf, 1, sizeof (buf) - 1, f)) 0) +{ + char *p; + + buf[nread] = '\0'; + /* We assume consistent EOL format throughout the file, so it's +enough to examine the first end-of-line. */ + p = strchr (buf, '\n'); + + if (p buf) + { + if (p[-1] == '\r') + result = true; + } +} + + if (f) +fclose (f); + + return result; +#else /* !__MINGW32__ */ + return false; +#endif +} + /* This structure represents an entire ChangeLog file, after it was read into memory. */ struct changelog_file @@ -1079,6 +1121,7 @@ gl_list_node_t *result_entries_pointers; /* array of pointers into result_entries */ gl_list_t /* struct entry * */ result_entries; gl_list_t /* struct conflict * */ result_conflicts; +bool crlf; /* if true, A-FILE-NAME has DOS CR-LF EOL format */ ancestor_file_name = argv[optind]; destination_file_name = argv[optind + 1]; @@ -1186,6 +1229,10 @@ modified_file_name = other_file_name; } +/* We want to preserve the EOL format of the destination file, + which is the ChangeLog file in the current branch. */ +crlf = detect_eol (destination_file_name, ancestor_file_name); + /* Read the three files into memory. */ read_changelog_file (ancestor_file_name, ancestor_file); read_changelog_file (mainstream_file_name, mainstream_file); @@ -1648,7 +1695,7 @@ /* Output the result. */ { - FILE *fp = fopen (destination_file_name, w); + FILE *fp = fopen (destination_file_name, crlf ? w : wb); if (fp == NULL) { fprintf (stderr, could not write file '%s'\n, destination_file_name);
[PATCH] git-merge-changelog: Report bugs to bug-gnulib@gnu.org.
git-merge-changelog is maintained in gnulib, so bug reports should go to bug-gnulib@gnu.org, not bug-gnu-gett...@gnu.org. --- ChangeLog |4 lib/git-merge-changelog.c |2 +- 2 files changed, 5 insertions(+), 1 deletions(-) diff --git a/ChangeLog b/ChangeLog index 128acda..31bf40d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2012-03-18 Mark Wielaard m...@klomp.org + + lib/git-merge-changelog.c (status): Report bugs to bug-gnulib@gnu.org. + 2012-03-16 Paul Eggert egg...@cs.ucla.edu regex: diagnose too-large repeat counts in EREs diff --git a/lib/git-merge-changelog.c b/lib/git-merge-changelog.c index 500f55b..e2ad303 100644 --- a/lib/git-merge-changelog.c +++ b/lib/git-merge-changelog.c @@ -990,7 +990,7 @@ usage (int status) printf ( -h, --help display this help and exit\n); printf ( -V, --version output version information and exit\n); printf (\n); - fputs (Report bugs to bug-gnu-gett...@gnu.org.\n, + fputs (Report bugs to bug-gnulib@gnu.org.\n, stdout); } -- 1.7.7.6
[PATCH] git-merge-changelog: add specific example on how to use with hg.
* lib/git-merge-changelog.c: Add example on how to use in .hgrc. --- ChangeLog |5 + lib/git-merge-changelog.c | 10 +- 2 files changed, 14 insertions(+), 1 deletions(-) diff --git a/ChangeLog b/ChangeLog index e600a1d..9650fc3 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2012-03-15 Mark Wielaard m...@klomp.org + + git-merge-changelog: add specific example on how to use with hg. + * lib/git-merge-changelog.c: Add example on how to use in .hgrc. + 2012-03-15 Bruno Haible br...@clisp.org fmal: Avoid test failure on OpenBSD 5.1/SPARC64. diff --git a/lib/git-merge-changelog.c b/lib/git-merge-changelog.c index 500f55b..1c34364 100644 --- a/lib/git-merge-changelog.c +++ b/lib/git-merge-changelog.c @@ -75,7 +75,15 @@ $ bzr extmerge ChangeLog Additionally, for hg users: - - Add to your $HOME/.hgrc a couple of lines in a section [merge-tools]. + - Add to your $HOME/.hgrc the lines + +[merge-patterns] +ChangeLog = git-merge-changelog + +[merge-tools] +git-merge-changelog.executable = /usr/local/bin/git-merge-changelog +git-merge-changelog.args = $base $local $other + See http://www.selenic.com/mercurial/hgrc.5.html section merge-tools for reference. */ -- 1.7.7.6
Re: git-merge-changelog
The only special program in gnulib is git-merge-changelog; though now that I think about it, it makes more sense to split out git-merge-changelog into a seperate project. Yes, you're entirely right. The project has been created already: http://savannah.gnu.org/projects/vc-changelog/ It is empty, is the idea to only have git-merge-changelog there? I haven't moved it yet, due to lack of time / more urgent priorities. Would you like to help moving it? Wouldn't it be better to put it in vc-dwim?
git-merge-changelog in bin_PROGRAMS
It seems that git-merge-changelog is added to bin_PROGRAMS in the generated lib/Makefile.am, which causes it to get installed in exec_prefix/bin (at least in inetutils). Not sure why though; I couldn't find anything that struck me in the ChangeLog. Anyone know?
Re: git-merge-changelog in bin_PROGRAMS
Alfred M. Szmidt wrote: It seems that git-merge-changelog is added to bin_PROGRAMS in the generated lib/Makefile.am, which causes it to get installed in exec_prefix/bin (at least in inetutils). Not sure why though It's necessary so that the installation instructions at the top of this file work. make install should install the program in ${bindir}. The question is: why does inetutils contain this program? Simon wrote in [1]: ! I haven't seen any other project include git-merge-changelog, which ! makes some sense as it seems to be more of a developer tool not strictly ! related to building the project itself. Moreover only the committers need the tools. People who use the anonymous git checkout and don't contribute don't need it. Bruno [1] http://lists.gnu.org/archive/html/bug-inetutils/2011-11/msg00010.html
Re: git-merge-changelog in bin_PROGRAMS
It seems that git-merge-changelog is added to bin_PROGRAMS in the generated lib/Makefile.am, which causes it to get installed in exec_prefix/bin (at least in inetutils). Not sure why though It's necessary so that the installation instructions at the top of this file work. make install should install the program in ${bindir}. `make install' must _not_ install git-merge-changelog, this is a internal file to gnulib, and using gnulib in a package must not cause installation of extra files from gnulib. The crux is that gnulib seems to have changed this, somewhere to install git-merge-changelog in bindir. This is a serious regression; I'll roll a new inetutils release for now, but we need to fix this in some sensible manner. The question is: why does inetutils contain this program? Simon wrote in [1]: ! I haven't seen any other project include git-merge-changelog, ! which makes some sense as it seems to be more of a developer tool ! not strictly related to building the project itself. Moreover only the committers need the tools. People who use the anonymous git checkout and don't contribute don't need it. So that one can merge changelog entries without having to install it, since git is a DVCS, anyone can commit and pull which causes marge conflicts for ChangeLog entries at times. There are multiple modules that are only useful to maintainers, gnu-web-doc-update, gnupload, and those should not get installed either in bindir simply because one includes the module either. Cheers!
Re: git-merge-changelog in bin_PROGRAMS
What about this? I haven't tried it, but I think it should work. The only special program in gnulib is git-merge-changelog; though now that I think about it, it makes more sense to split out git-merge-changelog into a seperate project. 2012-01-03 Alfred M. Szmidt a...@gnu.org * modules/git-merge-changelog (bin_PROGRAMS): Variable renamed to ... (bin_nodist_PROGRAMS): ... this. diff --git a/modules/git-merge-changelog b/modules/git-merge-changelog index 857a8bc..aa05103 100644 --- a/modules/git-merge-changelog +++ b/modules/git-merge-changelog @@ -28,7 +28,7 @@ memcmp configure.ac: Makefile.am: -bin_PROGRAMS = git-merge-changelog +bin_nodist_PROGRAMS = git-merge-changelog git_merge_changelog_LDADD = libgnu.a @LIBINTL@ $(LIBTHREAD) Include:
Re: git-merge-changelog
Hi Alfred, The only special program in gnulib is git-merge-changelog; though now that I think about it, it makes more sense to split out git-merge-changelog into a seperate project. Yes, you're entirely right. The project has been created already: http://savannah.gnu.org/projects/vc-changelog/ I haven't moved it yet, due to lack of time / more urgent priorities. Would you like to help moving it? Bruno
[PATCH] git-merge-changelog: fix missing space after conflict markers
As required by git. Andreas. 2011-01-09 Andreas Schwab sch...@linux-m68k.org * lib/git-merge-changelog.c (conflict_write): Add space after conflict marker. --- lib/git-merge-changelog.c |4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/git-merge-changelog.c b/lib/git-merge-changelog.c index 652b40a..fb846d3 100644 --- a/lib/git-merge-changelog.c +++ b/lib/git-merge-changelog.c @@ -940,13 +940,13 @@ conflict_write (FILE *fp, struct conflict *c) /* Use the same syntax as git's default merge driver. Don't indent the contents of the entries (with things like or -), otherwise the user needs more textual editing to resolve the conflict. */ - fputs (\n, fp); + fputs ( \n, fp); for (i = 0; i c-num_old_entries; i++) entry_write (fp, c-old_entries[i]); fputs (===\n, fp); for (i = 0; i c-num_modified_entries; i++) entry_write (fp, c-modified_entries[i]); - fputs (\n, fp); + fputs ( \n, fp); } /* Long options. */ -- 1.7.3.5 -- Andreas Schwab, sch...@linux-m68k.org GPG Key fingerprint = 58CA 54C7 6D53 942B 1756 01D3 44D5 214B 8276 4ED5 And now for something completely different.
Re: [PATCH] git-merge-changelog: fix missing space after conflict markers
Hello Andreas, As required by git. What do you mean by that? The user is expected to resolve the conflict, and this implies removing the and markers, before doing git add conflicting-file. In other words: Please give a reproducible recipe for experiencing a problem that occurs without your patch. Please understand that I cannot apply patches that are not accompanied with a sufficiently clear rationale or a how to reproduce. Thanks. Bruno
Re: [PATCH] git-merge-changelog: fix missing space after conflict markers
Bruno Haible br...@clisp.org writes: Hello Andreas, As required by git. What do you mean by that? See rerere.c:is_cmarker. Andreas. -- Andreas Schwab, sch...@linux-m68k.org GPG Key fingerprint = 58CA 54C7 6D53 942B 1756 01D3 44D5 214B 8276 4ED5 And now for something completely different.
Re: [PATCH] git-merge-changelog: fix missing space after conflict markers
Bruno Haible br...@clisp.org writes: Andreas Schwab wrote: As required by git. What do you mean by that? See rerere.c:is_cmarker. Please give a how to reproduce. Enable rerere and cherry-pick a conflicting changelog. Andreas. -- Andreas Schwab, sch...@linux-m68k.org GPG Key fingerprint = 58CA 54C7 6D53 942B 1756 01D3 44D5 214B 8276 4ED5 And now for something completely different.
git-merge-changelog limitation? [was: [PATCH] parse-datetime: do some more renaming]
On 10/05/2010 02:52 PM, Paul Eggert wrote: +++ b/ChangeLog @@ -1,5 +1,12 @@ 2010-10-05 Paul Eggertegg...@cs.ucla.edu + parse-datetime: do some more renaming + * doc/parse-datetime.texi (Authors of parse_datetime): Call it + parse_datetime, not get_date. Mention the renaming. + * lib/parse-datetime.y: Call it parse_datetime, not getdate, + in comments. + * m4/bison.m4: Likewise. + more ports to Solaris tr, which needs [] around ranges Hmm, ChangeLog now has some out-of-order entries. This is probably due to me working on the rename before Paul's patch for additional tr fixes, with two ChangeLog paragraphs grouped under one date; at which point I did 'git pull --rebase'. Apparently, get decided that since my change didn't impact line 1, it didn't have any reason to call git-merge-changelog; therefore, my most recent paragraph on parse-datetime renaming was not floated to the top, even though it was pushed upstream after Paul's tr fixes. If my memory serves, this may be a 'feature' of newer git; older git would always run git-merge-changelog if one revision inserts at the file head while another inserted a paragraph at line 3. Or it may be an unintentional regression in git. At any rate, I'm wondering if this means that we need to add a custom diff driver for ChangeLogs, in addition to the merge driver; so that we have final say on whether two ChangeLog edits require the use of the merge driver. Let me know if you need me to spend time writing up an exact formula to reproduce the steps that led to my ChangeLog message not being rebased the way I think it should be. -- Eric Blake ebl...@redhat.com+1-801-349-2682 Libvirt virtualization library http://libvirt.org
Re: git-merge-changelog limitation?
Hi Eric, Hmm, ChangeLog now has some out-of-order entries. This is probably due to me working on the rename before Paul's patch for additional tr fixes, with two ChangeLog paragraphs grouped under one date Yes, I agree, it looks like this. at which point I did 'git pull --rebase'. I also use 'git pull --rebase' often, and git-merge-changelog brings the ChangeLog entries into the right order. Apparently, git decided that since my change didn't impact line 1, it didn't have any reason to call git-merge-changelog; therefore, my most recent paragraph on parse-datetime renaming was not floated to the top, even though it was pushed upstream after Paul's tr fixes. If my memory serves, this may be a 'feature' of newer git; older git would always run git-merge-changelog if one revision inserts at the file head while another inserted a paragraph at line 3. Well, I would consider it a bug in git if it didn't invoke the declared merge driver. That is the point of a custom merge driver. Let me know if you need me to spend time writing up an exact formula to reproduce the steps that led to my ChangeLog message not being rebased the way I think it should be. Yes, please. This will be useful to revisit once we have unit tests for the normal operation of git-merge-changelog. Bruno
Re: git-merge-changelog limitation?
On 10/05/2010 04:05 PM, Bruno Haible wrote: Well, I would consider it a bug in git if it didn't invoke the declared merge driver. That is the point of a custom merge driver. My understanding is that git only invokes the custom merge driver IF there was a diff conflict. But when the default git diff doesn't detect a conflict, then you ALSO have to have a custom diff driver. Let me know if you need me to spend time writing up an exact formula to reproduce the steps that led to my ChangeLog message not being rebased the way I think it should be. Yes, please. This will be useful to revisit once we have unit tests for the normal operation of git-merge-changelog. OK, although it may be another day or two (I've got bigger things on my plate right now, like strstr and memmem broken in glibc due to a bug in my str-two-way.h). -- Eric Blake ebl...@redhat.com+1-801-349-2682 Libvirt virtualization library http://libvirt.org
git-merge-changelog: add documentation
Hi, Brian Gough found out how to make use of the git-merge-changelog program for 'git'. Let me add his findings as documentation. Thanks a lot, Brian! 2010-08-14 Brian Gough b...@gnu.org Bruno Haible br...@clisp.org git-merge-changelog: add doc relating to use with bzr and hg. * lib/git-merge-changelog.c: Add comments regarding bzr, hg, diff3. *** lib/git-merge-changelog.c.orig Sat Aug 14 19:56:29 2010 --- lib/git-merge-changelog.c Sat Aug 14 19:50:16 2010 *** *** 40,62 */ /* Installation: $ gnulib-tool --create-testdir --dir=/tmp/testdir123 git-merge-changelog $ cd /tmp/testdir123 $ ./configure $ make $ make install -- Add to .git/config of the checkout (or to your $HOME/.gitconfig) the lines ! [merge merge-changelog] ! name = GNU-style ChangeLog merge driver ! driver = /usr/local/bin/git-merge-changelog %O %A %B !- In every directory that contains a ChangeLog file, add a file ! '.gitattributes' with this line: ! ChangeLogmerge=merge-changelog ! (See man 5 gitattributes for more info.) */ /* Calling convention: --- 40,91 */ /* Installation: + $ gnulib-tool --create-testdir --dir=/tmp/testdir123 git-merge-changelog $ cd /tmp/testdir123 $ ./configure $ make $ make install !Additionally, for git users: ! - Add to .git/config of the checkout (or to your $HOME/.gitconfig) the !lines ! ! [merge merge-changelog] ! name = GNU-style ChangeLog merge driver ! driver = /usr/local/bin/git-merge-changelog %O %A %B ! ! - In every directory that contains a ChangeLog file, add a file !'.gitattributes' with this line: ! ! ChangeLogmerge=merge-changelog ! !(See man 5 gitattributes for more info.) !Additionally, for bzr users: ! - Install the 'extmerge' bzr plug-in listed at ! http://doc.bazaar.canonical.com/plugins/en/index.html ! http://wiki.bazaar.canonical.com/BzrPlugins ! - Add to your $HOME/.bazaar/bazaar.conf the line ! external_merge = git-merge-changelog %b %T %o ! ! - Then, to merge a conflict in a ChangeLog file, use ! ! $ bzr extmerge ChangeLog ! !Additionally, for hg users: ! - Add to your $HOME/.hgrc a couple of lines in a section [merge-tools]. !See http://www.selenic.com/mercurial/hgrc.5.html section merge-tools !for reference. ! */ ! /* Use as an alternative to 'diff3': !git-merge-changelog performs the same role as diff3 -m, just with !reordered arguments: ! $ git-merge-changelog %O %A %B !is comparable to ! $ diff3 -m %A %O %B */ /* Calling convention:
Re: [FEATURE REQUEST] git-merge-changelog and lumped ChangeLog entries
At Sunday 18 July 2010, Bruno Haible wrote: Hello Stafano, Thanks for the suggestion. Eric Blake already suggested the same thing. It is planned that in a month or so, the git-merge-changelog is merged to a project of its own, then receives a test suite, and then we'll start to add more features. Good! Thank you for the test case; it will help us implement the feature for sure. Thank you very much for considering my request. Regards, Stefano
Re: [FEATURE REQUEST] git-merge-changelog and lumped ChangeLog entries
Hello Stafano, Some projects (like Automake) have the policy of keeping multiple ChangeLog entries having the same author and date lumped togheter, preferring e.g.: 2000-01-01 Foo Bar nob...@example.com Add foo Add bar over: 2000-01-01 Foo Bar nob...@example.com Add foo 2000-01-01 Foo Bar nob...@example.com Add bar For such projects, the git-merge-changelog user experience is somewhat marred, since the driver separates the lumped-togheter entries when rebasing, e.g. turning a ChangeLog entry like the former into one like the latter (see the attached script for an example). Thanks for the suggestion. Eric Blake already suggested the same thing. It is planned that in a month or so, the git-merge-changelog is merged to a project of its own, then receives a test suite, and then we'll start to add more features. Thank you for the test case; it will help us implement the feature for sure. Bruno
[FEATURE REQUEST] git-merge-changelog and lumped ChangeLog entries
Hello gnulibers. Some projects (like Automake) have the policy of keeping multiple ChangeLog entries having the same author and date lumped togheter, preferring e.g.: 2000-01-01 Foo Bar nob...@example.com Add foo Add bar over: 2000-01-01 Foo Bar nob...@example.com Add foo 2000-01-01 Foo Bar nob...@example.com Add bar For such projects, the git-merge-changelog user experience is somewhat marred, since the driver separates the lumped-togheter entries when rebasing, e.g. turning a ChangeLog entry like the former into one like the latter (see the attached script for an example). Do you think an option could be added to git-merge-changelog to make this behavior more configurable, and adjustable to the lumped-togheter policy? Regards, Stefano foo.sh Description: application/shellscript
Re: git-merge-changelog: mention --split-merged-entry in the header comment.
On 05/23/2010 10:12 AM, Bruno Haible wrote: Hi Ralf, I only now became aware of the --split-merged-entry option which git-merge-changelog provides, because I never bothered to look at --help output Whereas I was aware of the option, but thought I would never need it, and was then surprised to have conflicts in ChangeLog at each step while rebasing a series of 30 patches. It's nice that --split-merged-entry separates merged but unrelated entries to make the rebase succeed. But what about the converse - is there any demand for a filter that would merge neighboring entries if they share the same author and date, to get a rebased series to use the same style as the original branch, so that the mere act of rebasing doesn't break the author's style of merged entries? -- Eric Blake ebl...@redhat.com+1-801-349-2682 Libvirt virtualization library http://libvirt.org signature.asc Description: OpenPGP digital signature
Re: git-merge-changelog: mention --split-merged-entry in the header comment.
Hi Eric, merge neighboring entries if they share the same author and date, to get a rebased series to use the same style as the original branch, so that the mere act of rebasing doesn't break the author's style of merged entries? I can imagine an option that would serve this purpose (for ChangeLog entries coming from the local user). But before adding more changes (even bug fixes) to git-merge-changelog, I think the next step - long overdue - would be to create a test suite for it. Simply a set of quadruples (O, A, B, result). Bruno
Re: git-merge-changelog: mention --split-merged-entry in the header comment.
* Bruno Haible wrote on Sun, May 23, 2010 at 06:12:46PM CEST: Also, I noticed that this file is copyrighted by you, not to the FSF Oversight? Some day, I intend to put this into a better place than gnulib, or have it distributed as a contrib in git. Don't know. - Since git is GPLv2 and the FSF does not like GPLv2, it's easier to not involve the FSF at this point. Not to point out the obvious, but the FSF *is* involved at this point, since it distributes the gnulib code. Besides, I wouldn't know why the FSF should forbid GPLv2+ for code that has an obvious interest in being combined with GPLv2 code (even when it's not clear whether or not that combination constitutes a derivation in the sense of copyright). Cheers, Ralf
git-merge-changelog: mention --split-merged-entry in the header comment.
Hello Bruno, I only now became aware of the --split-merged-entry option which git-merge-changelog provides, because I never bothered to look at --help output, and the header comment was enough for me otherwise. Very nice! (I was going to try to extend the code to do something about split headers, but am happy now to see that the functionality alread exists.) How about this patch to mention the switch there? Also, I noticed that this file is copyrighted by you, not to the FSF Oversight? Cheers, and thanks again for this very helpful tool, Ralf git-merge-changelog: mention --split-merged-entry in the header comment. * lib/git-merge-changelog.c: Update header comment. diff --git a/lib/git-merge-changelog.c b/lib/git-merge-changelog.c index b9ab429..a6718db 100644 --- a/lib/git-merge-changelog.c +++ b/lib/git-merge-changelog.c @@ -51,6 +51,10 @@ name = GNU-style ChangeLog merge driver driver = /usr/local/bin/git-merge-changelog %O %A %B + Be sure to use an absolute path, otherwise the driver will not be found. + You can add the --split-merged-entry option if you merge unrelated entries + with the same date and author. + - In every directory that contains a ChangeLog file, add a file '.gitattributes' with this line:
Re: git-merge-changelog: mention --split-merged-entry in the header comment.
Hi Ralf, I only now became aware of the --split-merged-entry option which git-merge-changelog provides, because I never bothered to look at --help output Whereas I was aware of the option, but thought I would never need it, and was then surprised to have conflicts in ChangeLog at each step while rebasing a series of 30 patches. I think this indicates that the option should be on by default. I'm applying the patch below. + Be sure to use an absolute path, otherwise the driver will not be found. I think this is pretty clear from the instructions above. Also, I noticed that this file is copyrighted by you, not to the FSF Oversight? Some day, I intend to put this into a better place than gnulib, or have it distributed as a contrib in git. Don't know. - Since git is GPLv2 and the FSF does not like GPLv2, it's easier to not involve the FSF at this point. Bruno 2010-05-23 Bruno Haible br...@clisp.org git-merge-changelog: Enable --split-merged-entry by default. * lib/git-merge-changelog.c (main): Set split_merged_entry to true. (usage): Don't mention this option any more. Reported by Ralf Wildenhues. --- lib/git-merge-changelog.c.orig Sun May 23 18:02:02 2010 +++ lib/git-merge-changelog.c Sun May 23 17:58:06 2010 @@ -1,5 +1,5 @@ /* git-merge-changelog - git merge driver for GNU style ChangeLog files. - Copyright (C) 2008-2009 Bruno Haible br...@clisp.org + Copyright (C) 2008-2010 Bruno Haible br...@clisp.org This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -947,6 +947,7 @@ printf (B-FILE-NAME names the user-modified file.\n); printf (Writes the merged file into A-FILE-NAME.\n); printf (\n); + #if 0 /* --split-merged-entry is now on by default. */ printf (Operation modifiers:\n); printf (\ --split-merged-entryPossibly split a merged entry between paragraphs.\n\ @@ -955,6 +956,7 @@ newline, just because they happened on the same\n\ date.\n); printf (\n); + #endif printf (Informative output:\n); printf ( -h, --help display this help and exit\n); printf ( -V, --version output version information and exit\n); @@ -980,7 +982,7 @@ /* Set default values for variables. */ do_help = false; do_version = false; - split_merged_entry = false; + split_merged_entry = true; /* Parse command line options. */ while ((optchar = getopt_long (argc, argv, hV, long_options, NULL)) != EOF) @@ -995,7 +997,6 @@ do_version = true; break; case CHAR_MAX + 1: /* --split-merged-entry */ - split_merged_entry = true; break; default: usage (EXIT_FAILURE);
Re: git-merge-changelog crash
Rolf Bjarne Kvinge wrote: Attached are three files (o-file, a-file and b-file) which when run with git-merge-changelog causes an assertion in: #3 0x08049985 in main (argc=Cannot access memory at address 0x34a6) at git-merge-changelog.c:1469 1469 ASSERT (entry_equals (ancestor_file.entries[i], Could you please indicate - Which version of git-merge-changelog.c are you using? The ones inthe gnulib repository have that ASSERT line at a different line number than 1469. feb2268308fe0aa483e9614c714cd66480ba033e I added a couple of prinfs which probably shifted that line a bit. $ git checkout feb2268308fe0aa483e9614c714cd66480ba033e $ grep -n 'ASSERT (entry_equals (ancestor_file.entries' lib/git-merge-changelog.c 1579: ASSERT (entry_equals (ancestor_file.entries[i], Either your adding a couple of printfs removed 110 lines of code, or you were actually testing an older version. I think the latter is more likely, since with these older versions I reproduce the assertion failure with your three files. Actually it is the same bug as reported by Eric. The line number printed by gdb is confusing. With the source code prior to the fix, I get - when I compile with -g and no optimization: #0 0x7f0aa9c9d5c5 in raise () from /lib64/libc.so.6 #1 0x7f0aa9c9ebb3 in abort () from /lib64/libc.so.6 #2 0x004015c8 in compute_mapping (file1=0x7fffb21ddcc0, file2=0x7fffb21ddca0, result=0x7fffb21ddd00) at git-merge-changelog.c:368 #3 0x0040338f in main (argc=4, argv=0x7fffb21de078) at git-merge-changelog.c:1046 - when I compile with -g -O2: #0 0x7fcfba31d5c5 in raise () from /lib64/libc.so.6 #1 0x7fcfba31ebb3 in abort () from /lib64/libc.so.6 #2 0x00401eba in main (argc=value optimized out, argv=value optimized out) at git-merge-changelog.c:1467 So, when -O2 was used, gcc decided to inline compute_mapping and to merge all calls to abort() inside main() into a single one. Bottom line: Always recompile with g -O0 before attempting to obtain a stack trace! Bruno
Re: git-merge-changelog crash
Hi, Actually I'm not sure what I messed up, but I cleaned up every trace of the merge driver and re-installed it, and now it doesn't crash anymore. Sorry for wasting your time. Rolf Hi, Rolf Bjarne Kvinge wrote: Attached are three files (o-file, a-file and b-file) which when run with git-merge-changelog causes an assertion in: #3 0x08049985 in main (argc=Cannot access memory at address 0x34a6) at git-merge-changelog.c:1469 1469 ASSERT (entry_equals (ancestor_file.entries[i], Could you please indicate - Which version of git-merge-changelog.c are you using? The ones inthe gnulib repository have that ASSERT line at a different line number than 1469. feb2268308fe0aa483e9614c714cd66480ba033e I added a couple of prinfs which probably shifted that line a bit. - How are you calling git-merge-changelog (options and values of environment variables starting with GIT?). I can not reproduce a crash with the 3 files that you sent, on x86_64-linux. - As always, also the platform, please? OpenSuse 11.0 x86. Thanks. Bruno -- Using Opera's revolutionary e-mail client: http://www.opera.com/mail/
git-merge-changelog crash
Hi, Attached are three files (o-file, a-file and b-file) which when run with git-merge-changelog causes an assertion in: #3 0x08049985 in main (argc=Cannot access memory at address 0x34a6) at git-merge-changelog.c:1469 1469ASSERT (entry_equals (ancestor_file.entries[i], Note that I updated git-merge-changelog today, so the recent assert fixes didn't fix this issue. My typical use case is this: I work with git-svn, and have two branches, master, which tracks the remote svn repository, and a branch I work on 'work-branch'. work-branch is always rebased with master before doing anything else, so work-branch contains master + my work Now i cherry-pick a commit from work-branch onto master, commit (to svn also using 'git svn dcommit') After this I 'git svn rebase -l' the work-branch. Now once in a while git leaves the commit I cherry-picked in, with one issue: it contains only the ChangeLogs, effectively duplicating all the entries (since work-branch also contains the latest commit from master, which has all the changes I cherry-picked). I detect this (no problem really), and I do git rebase -i latest commit from master and comment out the bad commit with only changelogs to remove it completely. Problem is that now the merge driver crashes during the rebase process. Rolf -- Using Opera's revolutionary e-mail client: http://www.opera.com/mail/ o-file Description: Binary data b-file Description: Binary data a-file Description: Binary data
Re: git-merge-changelog crash
Hi, Rolf Bjarne Kvinge wrote: Attached are three files (o-file, a-file and b-file) which when run with git-merge-changelog causes an assertion in: #3 0x08049985 in main (argc=Cannot access memory at address 0x34a6) at git-merge-changelog.c:1469 1469 ASSERT (entry_equals (ancestor_file.entries[i], Could you please indicate - Which version of git-merge-changelog.c are you using? The ones in the gnulib repository have that ASSERT line at a different line number than 1469. - How are you calling git-merge-changelog (options and values of environment variables starting with GIT?). I can not reproduce a crash with the 3 files that you sent, on x86_64-linux. - As always, also the platform, please? Thanks. Bruno
git-merge-changelog crash
Hi, Attached are three files (o-file, a-file and b-file) which when run with git-merge-changelog causes an assertion in: #3 0x08049985 in main (argc=Cannot access memory at address 0x34a6) at git-merge-changelog.c:1469 1469ASSERT (entry_equals (ancestor_file.entries[i], Note that I updated git-merge-changelog today, so the recent assert fixes didn't fix this issue. I'm working on a feature branch and this happens when I cherry-pick one commit from that feature feature to another branch. Rolf -- Using Opera's revolutionary e-mail client: http://www.opera.com/mail/ a-file Description: Binary data b-file Description: Binary data o-file Description: Binary data
Re: git-merge-changelog crash
Hi again, My typical use case is this: I work with git-svn, and have two branches, master, which tracks the remote svn repository, and a branch I work on 'work-branch'. work-branch is always rebased with master before doing anything else, so work-branch contains master + my work Now i cherry-pick a commit from work-branch onto master, commit (to svn also using 'git svn dcommit') After this I 'git svn rebase -l' the work-branch. Now once in a while git leaves the commit I cherry-picked in, with one issue: it contains only the ChangeLogs, effectively duplicating all the entries (since work-branch also contains the latest commit from master, which has all the changes I cherry-picked). I detect this (no problem really), and I do git rebase -i latest commit from master and comment out the bad commit with only changelogs to remove it completely. Problem is that now the merge driver crashes during the rebase process (like in the sample I sent a few minutes ago) Rolf Hi, Attached are three files (o-file, a-file and b-file) which when run with git-merge-changelog causes an assertion in: #3 0x08049985 in main (argc=Cannot access memory at address 0x34a6) at git-merge-changelog.c:1469 1469 ASSERT (entry_equals (ancestor_file.entries[i], Note that I updated git-merge-changelog today, so the recent assert fixes didn't fix this issue. I'm working on a feature branch and this happens when I cherry-pick one commit from that feature feature to another branch. Rolf -- Using Opera's revolutionary e-mail client: http://www.opera.com/mail/
Re: git-merge-changelog question
Hi Eric, Is it also worth addressing the root cause of this? After all, it was git-merge-changelog that created file1 with more than 1 exact copy in the first place (via the earlier round of merging); it seems like it would be better for git-merge-changelog to fail with a merge conflict if both contributors provide an identical entry surrounded by differing context, than to create a file with duplicate entries. I don't think it is the role of a merge driver to do such a thing. The merge driver is only there because the fundamental unit in a ChangeLog file is not the line, but the entry. If you have that situation in a line-based file, like AUTHORS or NEWS, git would not have merged two distant lines with the same contents. Therefore ChangeLog shouldn't be different. Actually it is not wrong to have identical ChangeLog entries. I can easily imagine a ChangeLog like this: 2009-04-23 Stepan Kasal * doc/foo.texi: Fix typos in last commit. 2009-04-23 Bruno Haible * doc/foo.texi (Topic2): New section. 2009-04-23 Stepan Kasal * doc/foo.texi: Fix typos in last commit. 2009-04-22 Bruno Haible * doc/foo.texi (Topic1): New section. When you copy a commit from one branch to another (via git rebase for example), git will automatically drop hunks that were already contained in the new branch. Therefore when you use git rebase, you have to have an eye on the ChangeLog entries anyway, and fiddle with them afterwards (through git commit --amend or equivalent). Bruno
Re: git-merge-changelog question
Eric Blake wrote: This time, git removes the temporary .merge_file_*, but I confirmed that they can be recreated via: $ git show 5f008b:ChangeLog file1 $ git show 0b17f4:ChangeLog file2 $ git show cd172d:ChangeLog file3 $ git-merge-changelog --split-merged-entry file[123] Thanks again for this reproducible example. This fixes it: 2009-07-04 Bruno Haible br...@clisp.org Fix assertion. * lib/git-merge-changelog.c (compute_mapping): In the case where file1 contains more exact copies of a given entry than file2, leave the extra copies unpaired rather than aborting. Reported by Eric Blake. *** lib/git-merge-changelog.c.orig 2009-07-04 11:21:00.0 +0200 --- lib/git-merge-changelog.c 2009-07-04 11:19:29.0 +0200 *** *** 510,546 { j = n2 - 1 - j; /* Found an exact correspondence. */ ! ASSERT (index_mapping_reverse[j] 0); ! index_mapping[i] = j; ! index_mapping_reverse[j] = i; ! /* Look for more occurrences of the same entry. */ ! { ! ssize_t curr_i = i; ! ssize_t curr_j = j; ! ! for (;;) { ! ssize_t next_i; ! ssize_t next_j; ! next_i = ! gl_list_indexof_from (file1-entries_reversed, n1 - curr_i, ! entry); ! if (next_i 0) ! break; ! next_j = ! gl_list_indexof_from (file2-entries_reversed, n2 - curr_j, ! entry); ! if (next_j 0) ! break; ! curr_i = n1 - 1 - next_i; ! curr_j = n2 - 1 - next_j; ! ASSERT (index_mapping[curr_i] 0); ! ASSERT (index_mapping_reverse[curr_j] 0); ! index_mapping[curr_i] = curr_j; ! index_mapping_reverse[curr_j] = curr_i; } ! } } } --- 510,553 { j = n2 - 1 - j; /* Found an exact correspondence. */ ! /* If index_mapping_reverse[j] = 0, we have already seen other ! copies of this entry, and there were more occurrences of it in ! file1 than in file2. In this case, do nothing. */ ! if (index_mapping_reverse[j] 0) ! { ! index_mapping[i] = j; ! index_mapping_reverse[j] = i; ! /* Look for more occurrences of the same entry. Match them ! as long as they pair up. Unpaired occurrences of the same ! entry are left without mapping. */ { ! ssize_t curr_i = i; ! ssize_t curr_j = j; ! ! for (;;) ! { ! ssize_t next_i; ! ssize_t next_j; ! next_i = ! gl_list_indexof_from (file1-entries_reversed, ! n1 - curr_i, entry); ! if (next_i 0) ! break; ! next_j = ! gl_list_indexof_from (file2-entries_reversed, ! n2 - curr_j, entry); ! if (next_j 0) ! break; ! curr_i = n1 - 1 - next_i; ! curr_j = n2 - 1 - next_j; ! ASSERT (index_mapping[curr_i] 0); ! ASSERT (index_mapping_reverse[curr_j] 0); ! index_mapping[curr_i] = curr_j; ! index_mapping_reverse[curr_j] = curr_i; ! } } ! } } }
Re: git-merge-changelog question
-BEGIN PGP SIGNED MESSAGE- Hash: SHA1 According to Bruno Haible on 7/4/2009 3:26 AM: Fix assertion. * lib/git-merge-changelog.c (compute_mapping): In the case where file1 contains more exact copies of a given entry than file2, leave the extra copies unpaired rather than aborting. Reported by Eric Blake. Is it also worth addressing the root cause of this? After all, it was git-merge-changelog that created file1 with more than 1 exact copy in the first place (via the earlier round of merging); it seems like it would be better for git-merge-changelog to fail with a merge conflict if both contributors provide an identical entry surrounded by differing context, than to create a file with duplicate entries. - -- Don't work too hard, make some time for fun as well! Eric Blake e...@byu.net -BEGIN PGP SIGNATURE- Version: GnuPG v1.4.9 (Cygwin) Comment: Public key at home.comcast.net/~ericblake/eblake.gpg Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org iEYEARECAAYFAkpPx4kACgkQ84KuGfSFAYBwdgCeMPKdVNSAJt9kvb+HMTX/csNc qT0AniTFbEno6Bm9kU0fsOAQeiQyuNq1 =e2dg -END PGP SIGNATURE-
Re: git-merge-changelog question
Hi Eric, Here's a sequence of steps, comparable to what I tried to use to generate 14b8a31ef on the master branch (cherry-picked from branch-1.6). The example below uses hashes instead of symbolic names, in case you want to reproduce this even when the branches have advanced. Notice that it appears to get stuck in an infinite loop, consuming 100% CPU with no apparent progress after a while. $ git clone git://git.sv.gnu.org/m4.git $ cd m4 $ git config $ git reset --hard 6033d89 $ git config merge.merge-changelog.driver git-merge-changelog --split-merged-entry %O %A %B $ timeout 600 git cherry-pick cd172d9 Indeed, with these instructions, I reproduce. The guessed direction, that is, the meaning of the three files, is right. The two major problems in your case are: - There are small differences between ChangeLog entries on the branches. For example, on one branch you have a ChangeLog entry that starts with Thu Nov 5 12:37:13 1992 Francois Pinard (pinard at icule) and on the other branch it starts with 1992-11-05 François Pinard pin...@iro.umontreal.ca These small differences cause the fuzzy string matching to be activated, and it takes a lot of time. Two exactly equal entries could be detected by a quick hash table lookup. - The branches are very far away: $ ls -l ChangeLog .merge_file_* -rw--- 1 eblake None 172482 Jun 30 21:24 .merge_file_X15QyE -rw--- 1 eblake None 172697 Jun 30 21:24 .merge_file_aJFAU3 -rw--- 1 eblake None 466111 Jun 30 21:24 .merge_file_acCLpE -rw-r--r-- 1 eblake None 466111 Jun 30 19:15 ChangeLog You are merging from a branch that has only 1/3 of the entire development history. git-merge-changelog spends time looking for each of the other 2/3 of the ChangeLog file whether it can find some match. The attached change applies Ralf's improvement (originally for gettext's msgmerge program). With this, the time spent for the git cherry-pick command goes down: 516 sec - 81 sec Since this is obviously still not the speed that you desire, I continue to look... 2009-07-02 Bruno Haible br...@clisp.org Speed up approximate search for matching ChangeLog entries. * lib/git-merge-changelog.c (entry_fstrcmp): Add a lower_bound argument. Call fstrcmp_bounded instead of fstrcmp. (compute_mapping, try_split_merged_entry, main): Update callers. --- lib/git-merge-changelog.c.orig 2009-07-02 23:32:51.0 +0200 +++ lib/git-merge-changelog.c 2009-07-02 22:48:51.0 +0200 @@ -211,9 +211,12 @@ /* Perform a fuzzy comparison of two ChangeLog entries. Return a similarity measure of the two entries, a value between 0 and 1. - 0 stands for very distinct, 1 for identical. */ + 0 stands for very distinct, 1 for identical. + If the result is LOWER_BOUND, an arbitrary other value LOWER_BOUND can + be returned. */ static double -entry_fstrcmp (const struct entry *entry1, const struct entry *entry2) +entry_fstrcmp (const struct entry *entry1, const struct entry *entry2, + double lower_bound) { /* fstrcmp works only on NUL terminated strings. */ char *memory; @@ -233,7 +236,8 @@ p += entry2-length; *p++ = '\0'; } - similarity = fstrcmp (memory, memory + entry1-length + 1); + similarity = +fstrcmp_bounded (memory, memory + entry1-length + 1, lower_bound); freea (memory); return similarity; } @@ -410,7 +414,8 @@ for (j = n2 - 1; j = 0; j--) if (index_mapping_reverse[j] 0) { - double similarity = entry_fstrcmp (entry_i, file2-entries[j]); + double similarity = + entry_fstrcmp (entry_i, file2-entries[j], best_j_similarity); if (similarity best_j_similarity) { best_j = j; @@ -429,7 +434,8 @@ if (index_mapping[ii] 0) { double similarity = - entry_fstrcmp (file1-entries[ii], entry_j); + entry_fstrcmp (file1-entries[ii], entry_j, + best_i_similarity); if (similarity best_i_similarity) { best_i = i; @@ -729,7 +735,8 @@ new_body.string = new_entry-string + split_offset; new_body.length = new_entry-length - split_offset; - similarity = entry_fstrcmp (old_body, new_body); + similarity = + entry_fstrcmp (old_body, new_body, best_similarity); if (similarity best_similarity) { best_split_offset = split_offset; @@ -1219,7 +1226,8 @@ size_t i; for (i = edit-i1 + 1; i = edit-i2; i++) if (entry_fstrcmp (ancestor_file.entries[i], -modified_file.entries[i + edit-j2 - edit-i2
Re: git-merge-changelog question
Hi Eric, And with this patch, you get decent performance. $ time git cherry-pick cd172d9 Finished one cherry-pick. [master d8ac2b5] Fix description of limits on diversions. 3 files changed, 13 insertions(+), 5 deletions(-) real0m0.425s user0m0.300s sys 0m0.128s Now, can you show me a crashing situation, please (with either the old or the new git-merge-changelog)? 2009-07-02 Bruno Haible br...@clisp.org Speedup git-merge-changelog for git cherry-pick. * lib/git-merge-changelog.c (struct entries_mapping): New type. (entries_mapping_get): New function, extracted from compute_mapping. (entries_mapping_reverse_get): New function. (compute_mapping): Add a 'full' argument. Return the result in a 'struct entries_mapping'. (main): Update. Access the mappings through entries_mapping_get. Reported by Eric Blake. --- lib/git-merge-changelog.c.orig 2009-07-03 01:15:05.0 +0200 +++ lib/git-merge-changelog.c 2009-07-03 01:04:41.0 +0200 @@ -329,18 +329,159 @@ } } +/* A mapping (correspondence) between entries of FILE1 and of FILE2. */ +struct entries_mapping +{ + struct changelog_file *file1; + struct changelog_file *file2; + /* Mapping from indices in FILE1 to indices in FILE2. + A value -1 means that the entry from FILE1 is not found in FILE2. + A value -2 means that it has not yet been computed. */ + ssize_t *index_mapping; + /* Mapping from indices in FILE2 to indices in FILE1. + A value -1 means that the entry from FILE2 is not found in FILE1. + A value -2 means that it has not yet been computed. */ + ssize_t *index_mapping_reverse; +}; + +/* Look up (or lazily compute) the mapping of an entry in FILE1. + i is the index in FILE1. + Return the index in FILE2, or -1 when the entry is not found in FILE2. */ +static ssize_t +entries_mapping_get (struct entries_mapping *mapping, ssize_t i) +{ + if (mapping-index_mapping[i] -1) +{ + struct changelog_file *file1 = mapping-file1; + struct changelog_file *file2 = mapping-file2; + size_t n1 = file1-num_entries; + size_t n2 = file2-num_entries; + struct entry *entry_i = file1-entries[i]; + ssize_t j; + + /* Search whether it approximately occurs in file2. */ + ssize_t best_j = -1; + double best_j_similarity = 0.0; + for (j = n2 - 1; j = 0; j--) + if (mapping-index_mapping_reverse[j] 0) + { + double similarity = + entry_fstrcmp (entry_i, file2-entries[j], best_j_similarity); + if (similarity best_j_similarity) + { + best_j = j; + best_j_similarity = similarity; + } + } + if (best_j_similarity = FSTRCMP_THRESHOLD) + { + /* Found a similar entry in file2. */ + struct entry *entry_j = file2-entries[best_j]; + /* Search whether it approximately occurs in file1 at index i. */ + ssize_t best_i = -1; + double best_i_similarity = 0.0; + ssize_t ii; + for (ii = n1 - 1; ii = 0; ii--) + if (mapping-index_mapping[ii] 0) + { + double similarity = + entry_fstrcmp (file1-entries[ii], entry_j, +best_i_similarity); + if (similarity best_i_similarity) + { + best_i = ii; + best_i_similarity = similarity; + } + } + if (best_i_similarity = FSTRCMP_THRESHOLD best_i == i) + { + mapping-index_mapping[i] = best_j; + mapping-index_mapping_reverse[best_j] = i; + } + } + if (mapping-index_mapping[i] -1) + /* It does not approximately occur in FILE2. + Remember it, for next time. */ + mapping-index_mapping[i] = -1; +} + return mapping-index_mapping[i]; +} + +/* Look up (or lazily compute) the mapping of an entry in FILE2. + j is the index in FILE2. + Return the index in FILE1, or -1 when the entry is not found in FILE1. */ +static ssize_t +entries_mapping_reverse_get (struct entries_mapping *mapping, ssize_t j) +{ + if (mapping-index_mapping_reverse[j] -1) +{ + struct changelog_file *file1 = mapping-file1; + struct changelog_file *file2 = mapping-file2; + size_t n1 = file1-num_entries; + size_t n2 = file2-num_entries; + struct entry *entry_j = file2-entries[j]; + ssize_t i; + + /* Search whether it approximately occurs in file1. */ + ssize_t best_i = -1; + double best_i_similarity = 0.0; + for (i = n1 - 1; i = 0; i--) + if (mapping-index_mapping[i] 0) + { + double similarity = + entry_fstrcmp (file1-entries[i], entry_j, best_i_similarity); + if (similarity best_i_similarity) + { + best_i = i; + best_i_similarity
Re: git-merge-changelog question
-BEGIN PGP SIGNED MESSAGE- Hash: SHA1 According to Bruno Haible on 7/2/2009 5:17 PM: Now, can you show me a crashing situation, please (with either the old or the new git-merge-changelog)? Found one. This crashes under the old: $ git clone git://git.sv.gnu.org/m4.git $ cd m4 $ git reset --hard 0b17f4 # on branch-1.6 $ git config merge.merge-changelog.driver git-merge-changelog --split-merged-entry %O %A %B $ GIT_TRACE=2 git cherry-pick -x cd172d9 trace: built-in: git 'cherry-pick' '-x' 'cd172d9' trace: run_command: 'sh' '-c' 'git-merge-changelog --split-merged-entry .merge_file_FrP9zj .merge_file_vkrkds .merge_file_eQYSBK' fatal: Failed to execute internal merge This time, git removes the temporary .merge_file_*, but I confirmed that they can be recreated via: $ git show 5f008b:ChangeLog file1 $ git show 0b17f4:ChangeLog file2 $ git show cd172d:ChangeLog file3 $ git-merge-changelog --split-merged-entry file[123] - -- Don't work too hard, make some time for fun as well! Eric Blake e...@byu.net -BEGIN PGP SIGNATURE- Version: GnuPG v1.4.9 (Cygwin) Comment: Public key at home.comcast.net/~ericblake/eblake.gpg Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org iEYEARECAAYFAkpNZGwACgkQ84KuGfSFAYDzLwCgxG86DZwfSUjnnihubVz7qkFo QYEAnRmKazEZsziaQkRyBOQX4X0C3N7S =oegA -END PGP SIGNATURE-
Re: git-merge-changelog question
Eric Blake ebb9 at byu.net writes: According to Bruno Haible on 7/2/2009 5:17 PM: Now, can you show me a crashing situation, please (with either the old or the new git-merge-changelog)? Found one. This crashes under the old: And under the new. It is triggering an ASSERT failure, and I've traced it to the fact that branch-1.4's ChangeLog has identical entries, and one entry from branch-1.6 refuses to map back to two entries of branch-1.4 (I'm now searching for which botched commit created that situation): $ git checkout origin/branch-1.4 $ grep -B2 -A5 'Fix missing' ChangeLog 2008-07-17 Eric Blake e...@byu.net Fix missing copyright notices. * acinclude.m4: Add copyright license details. * c-boxes.el: Likewise. * checks/get-them: Likewise. * checks/check-them: Likewise. -- 2008-07-17 Eric Blake e...@byu.net Fix missing copyright notices. * acinclude.m4: Add copyright license details. * c-boxes.el: Likewise. * checks/get-them: Likewise. * checks/check-them: Likewise. -- Eric Blake
Re: git-merge-changelog question
Eric Blake ebb9 at byu.net writes: And under the new. It is triggering an ASSERT failure, and I've traced it to the fact that branch-1.4's ChangeLog has identical entries, and one entry from branch-1.6 refuses to map back to two entries of branch-1.4 (I'm now searching for which botched commit created that situation): It stems from the fact that I had two similar commits on different branches (the commits were not identical, but the effect to ChangeLog was): git show aacc94 git show 37222e then I merged those branches without consolidating identical ChangeLog entries: git show 9ecd0a And trying to reproduce it shows that even today's git-merge-changelog will still happily create this situation of duplicate entries: $ git branch stackovf 6864b6f $ git checkout 08dd3b2 $ GIT_TRACE=2 git merge stackovf trace: built-in: git 'merge' 'stackovf' trace: run_command: 'sh' '-c' 'git-merge-changelog --split-merged- entry .merge_file_aFw2Wz .merge_file_eeARjO .merge_file_mO9slg' Auto-merging ChangeLog Auto-merging NEWS CONFLICT (content): Merge conflict in NEWS Auto-merging checks/check-them Auto-merging checks/get-them Auto-merging doc/m4.texinfo Auto-merging examples/Makefile.am Removing examples/stackovf.sh Auto-merging src/m4.c Removing src/stackovf.c Automatic merge failed; fix conflicts and then commit the result. $ grep 'Fix missing' ChangeLog Fix missing copyright notices. Fix missing copyright notices. $ -- Eric Blake
git-merge-changelog question
-BEGIN PGP SIGNED MESSAGE- Hash: SHA1 I've repeatedly encountered a situation where git-merge-changelog is a hindrance rather than a help. Any time I commit a patch on one branch, then want to run 'git cherry-pick' to copy it to another, git-merge-changelog either segfaults or goes into a super-long processing loop trying to resolve all of the differences between the two changelog entries, rather than doing what I wanted of just cherry-picking the most recent changelog entry and ignoring all other differences in the two divergent histories. On projects like gnulib, where all development is in a single branch, this isn't much of an issue, but on projects like m4, bison, or automake, where multiple branches are actively maintained and commits are routinely copied from one branch to another, it gets quite annoying to have to edit my .git/info/attributes to disable the git-merge-changelog attribute, perform the cherry-pick, then re-enable the attribute. It would be nicer if git-merge-changelog could be taught how to recognize cherry-picks and treat them correctly. - -- Don't work too hard, make some time for fun as well! Eric Blake e...@byu.net -BEGIN PGP SIGNATURE- Version: GnuPG v1.4.9 (Cygwin) Comment: Public key at home.comcast.net/~ericblake/eblake.gpg Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org iEYEARECAAYFAkpKC1wACgkQ84KuGfSFAYBYzQCfZWHdsRyoCT8YZZfRMYSTEoyy 0SwAn1xD/Ml0FvCYYvLsqAHsj5KgZY6B =sG+I -END PGP SIGNATURE-
Re: git-merge-changelog question
Hi Eric, git-merge-changelog either segfaults Ouch. It's written as defensively as possible, and checked with valgrind. Therefore I thought that was impossible! Any time I commit a patch on one branch, then want to run 'git cherry-pick' to copy it to another, git-merge-changelog either segfaults or goes into a super-long processing loop trying to resolve all of the differences between the two changelog entries Can you prepare a reproducible example, please? I've never used 'git cherry-pick' (I only really learned how to use 'git merge' and 'git rebase' a couple of days ago), therefore I would have to guess how your commands looked like. Your example can be based on m4.git; I can check that out. Bruno
Re: git-merge-changelog question
I've repeatedly encountered a situation where git-merge-changelog is a hindrance rather than a help. Any time I commit a patch on one branch, then want to run 'git cherry-pick' to copy it to another, git-merge-changelog either segfaults or goes into a super-long processing loop trying to resolve all of the differences between the two changelog entries. Interesting, I never had this problem in GNU Smalltalk. Paolo
Re: git-merge-changelog question
-BEGIN PGP SIGNED MESSAGE- Hash: SHA1 According to Bruno Haible on 6/30/2009 2:28 PM: Hi Eric, git-merge-changelog either segfaults Ouch. It's written as defensively as possible, and checked with valgrind. Therefore I thought that was impossible! I haven't been found a simple formula for reproducing a segfault yet, but maybe I'll get something later. Next time it happens, I'll have to remember to report the exact sha1 hashes that caused the problem. Any time I commit a patch on one branch, then want to run 'git cherry-pick' to copy it to another, git-merge-changelog either segfaults or goes into a super-long processing loop trying to resolve all of the differences between the two changelog entries Can you prepare a reproducible example, please? I've never used 'git cherry-pick' (I only really learned how to use 'git merge' and 'git rebase' a couple of days ago), therefore I would have to guess how your commands looked like. Your example can be based on m4.git; I can check that out. Here's a sequence of steps, comparable to what I tried to use to generate 14b8a31ef on the master branch (cherry-picked from branch-1.6). The example below uses hashes instead of symbolic names, in case you want to reproduce this even when the branches have advanced. Notice that it appears to get stuck in an infinite loop, consuming 100% CPU with no apparent progress after a while. $ git clone git://git.sv.gnu.org/m4.git $ cd m4 $ git config $ git reset --hard 6033d89 $ git config merge.merge-changelog.driver git-merge-changelog --split-merged-entry %O %A %B $ timeout 600 git cherry-pick cd172d9 $ ls -l ChangeLog .merge_file_* - -rw--- 1 eblake None 172482 Jun 30 21:24 .merge_file_X15QyE - -rw--- 1 eblake None 172697 Jun 30 21:24 .merge_file_aJFAU3 - -rw--- 1 eblake None 466111 Jun 30 21:24 .merge_file_acCLpE - -rw-r--r-- 1 eblake None 466111 Jun 30 19:15 ChangeLog But as soon as I disable git-merge-changelog from running, git is able to perform the cherry-pick with its usual lightning speed. $ echo 'ChangeLog !merge' .git/info/attributes $ rm .merge_file_* $ time git cherry-pick cd172d9 [master c5eed30] Fix description of limits on diversions. 3 files changed, 13 insertions(+), 5 deletions(-) real0m1.769s user0m0.466s sys 0m0.465s - -- Don't work too hard, make some time for fun as well! Eric Blake e...@byu.net -BEGIN PGP SIGNATURE- Version: GnuPG v1.4.9 (Cygwin) Comment: Public key at home.comcast.net/~ericblake/eblake.gpg Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org iEYEARECAAYFAkpK2sEACgkQ84KuGfSFAYBz/ACePXFI7wxX3nMq8+63d9lHeN4H BioAoKB0mBK6HQwSE51JHOj5ynKTjWYQ =1cpI -END PGP SIGNATURE-
git-merge-changelog usage error during rebase
$ git checkout jy/auto-gettext Switched to branch jy/auto-gettext $ git rebase master First, rewinding head to replay your work on top of it... Applying Update to version 0.17 of GNU gettext. error: patch failed: ChangeLog:41 error: ChangeLog: patch does not apply Using index info to reconstruct a base tree... Falling back to patching base and 3-way merge... /usr/local/bin/git-merge-changelog: expected three arguments Auto-merged .gitignore Removed ABOUT-NLS Auto-merged ChangeLog CONFLICT (content): Merge conflict in ChangeLog Auto-merged import-gnulib.sh Removed po/Makefile.in.in Failed to merge in the changes. Patch failed at 0001. When you have resolved this problem run git rebase --continue. If you would prefer to skip this patch, instead run git rebase --skip. To restore the original branch and stop rebasing run git rebase --abort. The ChangeLog file doesn't have any conflict markers in it; in fact it seems to be the version from master. $ cat .git/config [core] repositoryformatversion = 0 filemode = true bare = false logallrefupdates = true [remote origin] url = ssh://j...@git.sv.gnu.org/srv/git/findutils.git fetch = +refs/heads/*:refs/remotes/origin/* [branch master] remote = origin merge = refs/heads/master [format] headers = To: findutils-patc...@gnu.org\n [branch rel-4-4-fixes] remote = origin merge = refs/heads/rel-4-4-fixes [branch rel-4-3-fixes] remote = origin merge = refs/heads/rel-4-3-fixes [branch rel-4-2-fixes] remote = origin merge = refs/heads/rel-4-2-fixes [merge cl-merge] name = GNU-style ChangeLog merge driver driver = /usr/local/bin/git-merge-changelog $ cat .gitattributes ChangeLogmerge=cl-merge $ /usr/local/bin/git-merge-changelog --version /usr/local/bin/git-merge-changelog Copyright (C) 2008 Free Software Foundation, Inc. License GPLv2+: GNU GPL version 2 or later http://gnu.org/licenses/gpl.html This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Written by Bruno Haible. $ git --version git version 1.5.6.5 Any ideas? James.
Re: git-merge-changelog usage error during rebase
On Mon, Mar 9, 2009 at 12:42 AM, James Youngman j...@gnu.org wrote: $ git checkout jy/auto-gettext Switched to branch jy/auto-gettext $ git rebase master First, rewinding head to replay your work on top of it... Applying Update to version 0.17 of GNU gettext. error: patch failed: ChangeLog:41 error: ChangeLog: patch does not apply Using index info to reconstruct a base tree... Falling back to patching base and 3-way merge... /usr/local/bin/git-merge-changelog: expected three arguments ... it looks like no arguments are being passed at all. James.
[PATCH] Install git-merge-changelog in bootstrap
This is another local patch I had for bootstrap in sed. It automatically adds to .git/config the required lines to use the git-merge-changelog driver. To use this feature, in addition, the project maintainer must add ChangeLog* merge=merge-changelog in the root .gitattributes file. Ok? Paolo 2008-09-29 Paolo Bonzini [EMAIL PROTECTED] * bootstrap: Install git-merge-changelog configuration entries if git is in use. --- build-aux/bootstrap.save2008-09-29 11:46:29.0 +0200 +++ build-aux/bootstrap 2008-09-29 11:44:39.0 +0200 @@ -218,6 +218,20 @@ echo $0: Bootstrapping from checked-out $package sources... +# See if we can use gnulib's git-merge-changelog merge driver. +if test -d .git (git --version) /dev/null 2/dev/null ; then + if git config merge.merge-changelog.driver /dev/null ; then +: + elif (git-merge-changelog --version) /dev/null 2/dev/null ; then +echo initializing git-merge-changelog driver +git config merge.merge-changelog.name 'GNU-style ChangeLog merge driver' +git config merge.merge-changelog.driver 'git-merge-changelog %O %A %B' + else +echo consider installing git-merge-changelog from gnulib + fi +fi + + cleanup_gnulib() { status=$? rm -fr gnulib
git-merge-changelog: fix link error
The git-merge-changelog does not link on MacOS X: gcc -std=gnu99 -g -O2 -o git-merge-changelog git-merge-changelog.o libgnu.a -lm Undefined symbols: _libintl_gettext, referenced from: _xalloc_die in libgnu.a(xalloc-die.o) _error_tail in libgnu.a(error.o) __getopt_internal_r in libgnu.a(getopt.o) ld: symbol(s) not found collect2: ld returned 1 exit status This should fix it: 2008-04-11 Bruno Haible [EMAIL PROTECTED] * modules/git-merge-changelog (git_merge_changelog_LDADD): Add LIBINTL. *** modules/git-merge-changelog.orig2008-04-11 13:26:41.0 +0200 --- modules/git-merge-changelog 2008-04-11 13:26:19.0 +0200 *** *** 26,32 Makefile.am: bin_PROGRAMS = git-merge-changelog ! git_merge_changelog_LDADD = libgnu.a Include: --- 26,32 Makefile.am: bin_PROGRAMS = git-merge-changelog ! git_merge_changelog_LDADD = libgnu.a @LIBINTL@ Include:
making a git-merge-changelog package
I just made this script that prepares a git-merge-changelog tarball. I don't know if it would be useful to have it in a cron job somewhere. It needs git in the path. #! /bin/sh mkdir -p git-merge-changelog cd git-merge-changelog if test -d gnulib/.git; then (cd gnulib git pull) else git clone git://git.sv.gnu.org/gnulib gnulib fi cat configure.ac \EOF AC_PREREQ(2.61) AC_INIT(git-merge-changelog, 0.0, bug-gnulib@gnu.org) AC_CONFIG_AUX_DIR(build-aux) AC_CONFIG_HEADERS(config.h) AC_PROG_CC AC_PROG_INSTALL gl_EARLY gl_INIT AM_INIT_AUTOMAKE AC_CONFIG_FILES(Makefile lib/Makefile) AC_OUTPUT EOF cat Makefile.am \EOF SUBDIRS = lib ACLOCAL_AMFLAGS = -I m4 AUTOMAKE_OPTIONS = foreign all-local:; cp lib/git-merge-changelog$(EXEEXT) . distclean-local:; rm -f git-merge-changelog$(EXEEXT) EOF gnulib/gnulib-tool --import git-merge-changelog autoreconf -fvi mkdir -p build cd build ../configure make distcheck cp git-merge-changelog-0.0.tar.gz .. cd .. rm -rf build