@@ -1956,9 +1956,51 @@ int git_configset_get_pathname(struct config_set *set, const char *key, char **d
1956
1956
struct comment_char_config {
1957
1957
unsigned last_key_id ;
1958
1958
bool auto_set ;
1959
+ bool auto_set_in_file ;
1960
+ struct strintmap key_flags ;
1961
+ size_t alloc , nr ;
1962
+ struct comment_char_config_item {
1963
+ unsigned key_id ;
1964
+ char * path ;
1965
+ enum config_scope scope ;
1966
+ } * item ;
1959
1967
};
1960
1968
1961
- #define COMMENT_CHAR_CFG_INIT { 0 }
1969
+ #define COMMENT_CHAR_CFG_INIT { \
1970
+ .key_flags = STRINTMAP_INIT, \
1971
+ }
1972
+
1973
+ static void comment_char_config_release (struct comment_char_config * config )
1974
+ {
1975
+ strintmap_clear (& config -> key_flags );
1976
+ for (size_t i = 0 ; i < config -> nr ; i ++ )
1977
+ free (config -> item [i ].path );
1978
+ free (config -> item );
1979
+ }
1980
+
1981
+ /* Used to track whether the key occurs more than once in a given file */
1982
+ #define KEY_SEEN_ONCE 1u
1983
+ #define KEY_SEEN_TWICE 2u
1984
+ #define COMMENT_KEY_SHIFT (id ) (2 * (id))
1985
+ #define COMMENT_KEY_MASK (id ) (3u << COMMENT_KEY_SHIFT(id))
1986
+
1987
+ static void set_comment_key_flags (struct comment_char_config * config ,
1988
+ const char * path , unsigned id , unsigned value )
1989
+ {
1990
+ unsigned old = strintmap_get (& config -> key_flags , path );
1991
+ unsigned new = (old & ~COMMENT_KEY_MASK (id )) |
1992
+ value << COMMENT_KEY_SHIFT (id );
1993
+
1994
+ strintmap_set (& config -> key_flags , path , new );
1995
+ }
1996
+
1997
+ static unsigned get_comment_key_flags (struct comment_char_config * config ,
1998
+ const char * path , unsigned id )
1999
+ {
2000
+ unsigned value = strintmap_get (& config -> key_flags , path );
2001
+
2002
+ return (value & COMMENT_KEY_MASK (id )) >> COMMENT_KEY_SHIFT (id );
2003
+ }
1962
2004
1963
2005
static const char * comment_key_name (unsigned id )
1964
2006
{
@@ -1974,10 +2016,10 @@ static const char* comment_key_name(unsigned id)
1974
2016
}
1975
2017
1976
2018
static void comment_char_callback (const char * key , const char * value ,
1977
- const struct config_context * ctx UNUSED ,
1978
- void * data )
2019
+ const struct config_context * ctx , void * data )
1979
2020
{
1980
2021
struct comment_char_config * config = data ;
2022
+ const struct key_value_info * kvi = ctx -> kvi ;
1981
2023
unsigned key_id ;
1982
2024
1983
2025
if (!strcmp (key , "core.commentchar" ))
@@ -1989,8 +2031,136 @@ static void comment_char_callback(const char *key, const char *value,
1989
2031
1990
2032
config -> last_key_id = key_id ;
1991
2033
config -> auto_set = value && !strcmp (value , "auto" );
2034
+ if (kvi -> origin_type != CONFIG_ORIGIN_FILE ) {
2035
+ return ;
2036
+ } else if (get_comment_key_flags (config , kvi -> filename , key_id )) {
2037
+ set_comment_key_flags (config , kvi -> filename , key_id ,
2038
+ KEY_SEEN_TWICE );
2039
+ } else {
2040
+ struct comment_char_config_item * item ;
2041
+
2042
+ ALLOC_GROW_BY (config -> item , config -> nr , 1 , config -> alloc );
2043
+ item = & config -> item [config -> nr - 1 ];
2044
+ item -> key_id = key_id ;
2045
+ item -> scope = kvi -> scope ;
2046
+ item -> path = xstrdup (kvi -> filename );
2047
+ set_comment_key_flags (config , kvi -> filename , key_id ,
2048
+ KEY_SEEN_ONCE );
2049
+ }
2050
+ config -> auto_set_in_file = config -> auto_set ;
1992
2051
}
1993
2052
2053
+ static void add_config_scope_arg (struct repository * repo , struct strbuf * buf ,
2054
+ struct comment_char_config_item * item )
2055
+ {
2056
+ char * global_config = git_global_config ();
2057
+ char * system_config = git_system_config ();
2058
+
2059
+ if (item -> scope == CONFIG_SCOPE_SYSTEM && access (item -> path , W_OK )) {
2060
+ /*
2061
+ * If the user cannot write to the system config recommend
2062
+ * setting the global config instead.
2063
+ */
2064
+ strbuf_addstr (buf , "--global " );
2065
+ } else if (fspatheq (item -> path , system_config )) {
2066
+ strbuf_addstr (buf , "--system " );
2067
+ } else if (fspatheq (item -> path , global_config )) {
2068
+ strbuf_addstr (buf , "--global " );
2069
+ } else if (fspatheq (item -> path ,
2070
+ mkpath ("%s/config" ,
2071
+ repo_get_git_dir (repo )))) {
2072
+ ; /* --local is the default */
2073
+ } else if (fspatheq (item -> path ,
2074
+ mkpath ("%s/config.worktree" ,
2075
+ repo_get_common_dir (repo )))) {
2076
+ strbuf_addstr (buf , "--worktree " );
2077
+ } else {
2078
+ const char * path = item -> path ;
2079
+ const char * home = getenv ("HOME" );
2080
+
2081
+ strbuf_addstr (buf , "--file " );
2082
+ if (home && !fspathncmp (path , home , strlen (home ))) {
2083
+ path += strlen (home );
2084
+ if (!fspathncmp (path , "/" , 1 ))
2085
+ path ++ ;
2086
+ strbuf_addstr (buf , "~/" );
2087
+ }
2088
+ sq_quote_buf_pretty (buf , path );
2089
+ strbuf_addch (buf , ' ' );
2090
+ }
2091
+
2092
+ free (global_config );
2093
+ free (system_config );
2094
+ }
2095
+
2096
+ static bool can_unset_comment_char_config (struct comment_char_config * config )
2097
+ {
2098
+ for (size_t i = 0 ; i < config -> nr ; i ++ ) {
2099
+ struct comment_char_config_item * item = & config -> item [i ];
2100
+
2101
+ if (item -> scope == CONFIG_SCOPE_SYSTEM &&
2102
+ access (item -> path , W_OK ))
2103
+ return false;
2104
+ }
2105
+
2106
+ return true;
2107
+ }
2108
+
2109
+ static void add_unset_auto_comment_char_advice (struct repository * repo ,
2110
+ struct comment_char_config * config )
2111
+ {
2112
+ struct strbuf buf = STRBUF_INIT ;
2113
+
2114
+ if (!can_unset_comment_char_config (config ))
2115
+ return ;
2116
+
2117
+ for (size_t i = 0 ; i < config -> nr ; i ++ ) {
2118
+ struct comment_char_config_item * item = & config -> item [i ];
2119
+
2120
+ strbuf_addstr (& buf , " git config unset " );
2121
+ add_config_scope_arg (repo , & buf , item );
2122
+ if (get_comment_key_flags (config , item -> path , item -> key_id ) == KEY_SEEN_TWICE )
2123
+ strbuf_addstr (& buf , "--all " );
2124
+ strbuf_addf (& buf , "%s\n" , comment_key_name (item -> key_id ));
2125
+ }
2126
+ advise (_ ("\nTo use the default comment string (#) please run\n\n%s" ),
2127
+ buf .buf );
2128
+ strbuf_release (& buf );
2129
+ }
2130
+
2131
+ static void add_comment_char_advice (struct repository * repo ,
2132
+ struct comment_char_config * config )
2133
+ {
2134
+ struct strbuf buf = STRBUF_INIT ;
2135
+ struct comment_char_config_item * item ;
2136
+ /* TRANSLATORS this is a place holder for the value of core.commentString */
2137
+ const char * placeholder = _ ("<comment string>" );
2138
+
2139
+ /*
2140
+ * If auto is set in the last file that we saw advise the user how to
2141
+ * update their config.
2142
+ */
2143
+ if (!config -> auto_set_in_file )
2144
+ return ;
2145
+
2146
+ add_unset_auto_comment_char_advice (repo , config );
2147
+ item = & config -> item [config -> nr - 1 ];
2148
+ strbuf_reset (& buf );
2149
+ strbuf_addstr (& buf , " git config set " );
2150
+ add_config_scope_arg (repo , & buf , item );
2151
+ strbuf_addf (& buf , "%s %s\n" , comment_key_name (item -> key_id ),
2152
+ placeholder );
2153
+ advise (_ ("\nTo set a custom comment string please run\n\n"
2154
+ "%s\nwhere '%s' is the string you wish to use.\n" ),
2155
+ buf .buf , placeholder );
2156
+ strbuf_release (& buf );
2157
+ }
2158
+
2159
+ #undef KEY_SEEN_ONCE
2160
+ #undef KEY_SEEN_TWICE
2161
+ #undef COMMENT_KEY_SHIFT
2162
+ #undef COMMENT_KEY_MASK
2163
+
1994
2164
struct repo_config {
1995
2165
struct repository * repo ;
1996
2166
struct comment_char_config comment_char_config ;
@@ -2001,18 +2171,26 @@ struct repo_config {
2001
2171
.repo = repo_, \
2002
2172
};
2003
2173
2174
+ static void repo_config_release (struct repo_config * config )
2175
+ {
2176
+ comment_char_config_release (& config -> comment_char_config );
2177
+ }
2178
+
2004
2179
#ifdef WITH_BREAKING_CHANGES
2005
- static void check_auto_comment_char_config (struct comment_char_config * config )
2180
+ static void check_auto_comment_char_config (struct repository * repo ,
2181
+ struct comment_char_config * config )
2006
2182
{
2007
2183
if (!config -> auto_set )
2008
2184
return ;
2009
2185
2010
2186
die_message (_ ("Support for '%s=auto' has been removed in Git 3.0" ),
2011
2187
comment_key_name (config -> last_key_id ));
2188
+ add_comment_char_advice (repo , config );
2012
2189
die (NULL );
2013
2190
}
2014
2191
#else
2015
- static void check_auto_comment_char_config (struct comment_char_config * config )
2192
+ static void check_auto_comment_char_config (struct repository * repo ,
2193
+ struct comment_char_config * config )
2016
2194
{
2017
2195
extern bool warn_on_auto_comment_char ;
2018
2196
const char * DEPRECATED_CONFIG_ENV =
@@ -2032,6 +2210,7 @@ static void check_auto_comment_char_config(struct comment_char_config *config)
2032
2210
2033
2211
warning (_ ("Support for '%s=auto' is deprecated and will be removed in "
2034
2212
"Git 3.0" ), comment_key_name (config -> last_key_id ));
2213
+ add_comment_char_advice (repo , config );
2035
2214
}
2036
2215
#endif /* WITH_BREAKING_CHANGES */
2037
2216
@@ -2040,7 +2219,8 @@ static void check_deprecated_config(struct repo_config *config)
2040
2219
if (!config -> repo -> check_deprecated_config )
2041
2220
return ;
2042
2221
2043
- check_auto_comment_char_config (& config -> comment_char_config );
2222
+ check_auto_comment_char_config (config -> repo ,
2223
+ & config -> comment_char_config );
2044
2224
}
2045
2225
2046
2226
static int repo_config_callback (const char * key , const char * value ,
@@ -2083,6 +2263,7 @@ static void repo_read_config(struct repository *repo)
2083
2263
*/
2084
2264
die (_ ("unknown error occurred while reading the configuration files" ));
2085
2265
check_deprecated_config (& config );
2266
+ repo_config_release (& config );
2086
2267
}
2087
2268
2088
2269
static void git_config_check_init (struct repository * repo )
0 commit comments