* [PATCH 1/4] convert: pass 'repo' to the working tree conversion functions
2026-10-24 22:00 [PATCH 0/4] environment: move line ending config variables into repo_config_values Aniket Gupta
@ 2026-10-24 22:00 ` Aniket Gupta
2026-10-24 22:00 ` [PATCH 2/4] environment: move auto_crlf into repo_config_values Aniket Gupta
` (3 subsequent siblings)
4 siblings, 0 replies; 9+ messages in thread
From: Aniket Gupta @ 2026-10-24 22:00 UTC (permalink / raw)
To: git; +Cc: gitster, christian.couder, cat, belkid98, ps, phillip.wood123
The functions that convert a blob to its working tree format take a
'struct conv_attrs' but no repository, even though what they do
depends on configuration such as 'core.autocrlf' and 'core.eol'. As
we migrate these configuration variables into the repository struct,
the functions need access to the repository context.
Add a 'struct repository *' parameter to convert_to_working_tree_ca(),
async_convert_to_working_tree_ca() and get_stream_filter_ca(), and
update all callers to pass the appropriate repository instance. The
parameter is not used yet, so mark it as UNUSED for now.
The convert_to_working_tree() and async_convert_to_working_tree()
wrappers were static inline functions in 'convert.h'. They need to
get the repository from the index, which 'convert.h' does not know
about, so move them into 'convert.c'.
Signed-off-by: Aniket Gupta <aniketgupta3001@gmail.com>
---
convert.c | 39 +++++++++++++++++++++++++++++++++++----
convert.h | 38 ++++++++++++++++----------------------
entry.c | 16 +++++++++++-----
parallel-checkout.c | 8 +++++---
4 files changed, 67 insertions(+), 34 deletions(-)
diff --git a/convert.c b/convert.c
index 036506842c..95bdfafdd0 100644
--- a/convert.c
+++ b/convert.c
@@ -1520,7 +1520,8 @@ static int convert_to_working_tree_ca_internal(const struct conv_attrs *ca,
return ret | ret_filter;
}
-int async_convert_to_working_tree_ca(const struct conv_attrs *ca,
+int async_convert_to_working_tree_ca(struct repository *repo UNUSED,
+ const struct conv_attrs *ca,
const char *path, const char *src,
size_t len, struct strbuf *dst,
const struct checkout_metadata *meta,
@@ -1530,7 +1531,8 @@ int async_convert_to_working_tree_ca(const struct conv_attrs *ca,
meta, dco);
}
-int convert_to_working_tree_ca(const struct conv_attrs *ca,
+int convert_to_working_tree_ca(struct repository *repo UNUSED,
+ const struct conv_attrs *ca,
const char *path, const char *src,
size_t len, struct strbuf *dst,
const struct checkout_metadata *meta)
@@ -1539,6 +1541,32 @@ int convert_to_working_tree_ca(const struct conv_attrs *ca,
meta, NULL);
}
+int convert_to_working_tree(struct index_state *istate,
+ const char *path, const char *src,
+ size_t len, struct strbuf *dst,
+ const struct checkout_metadata *meta)
+{
+ struct repository *repo = istate && istate->repo ?
+ istate->repo : the_repository;
+ struct conv_attrs ca;
+ convert_attrs(istate, &ca, path);
+ return convert_to_working_tree_ca(repo, &ca, path, src, len, dst, meta);
+}
+
+int async_convert_to_working_tree(struct index_state *istate,
+ const char *path, const char *src,
+ size_t len, struct strbuf *dst,
+ const struct checkout_metadata *meta,
+ void *dco)
+{
+ struct repository *repo = istate && istate->repo ?
+ istate->repo : the_repository;
+ struct conv_attrs ca;
+ convert_attrs(istate, &ca, path);
+ return async_convert_to_working_tree_ca(repo, &ca, path, src, len, dst,
+ meta, dco);
+}
+
int renormalize_buffer(struct index_state *istate, const char *path,
const char *src, size_t len, struct strbuf *dst)
{
@@ -1981,7 +2009,8 @@ static struct stream_filter *ident_filter(const struct object_id *oid)
* Note that you would be crazy to set CRLF, smudge/clean or ident to a
* large binary blob you would want us not to slurp into the memory!
*/
-struct stream_filter *get_stream_filter_ca(const struct conv_attrs *ca,
+struct stream_filter *get_stream_filter_ca(struct repository *repo UNUSED,
+ const struct conv_attrs *ca,
const struct object_id *oid)
{
struct stream_filter *filter = NULL;
@@ -2006,7 +2035,9 @@ struct stream_filter *get_stream_filter(struct index_state *istate,
{
struct conv_attrs ca;
convert_attrs(istate, &ca, path);
- return get_stream_filter_ca(&ca, oid);
+ return get_stream_filter_ca(istate && istate->repo ?
+ istate->repo : the_repository,
+ &ca, oid);
}
void free_stream_filter(struct stream_filter *filter)
diff --git a/convert.h b/convert.h
index 0a6e4086b8..137fa1593a 100644
--- a/convert.h
+++ b/convert.h
@@ -8,6 +8,7 @@
#include "string-list.h"
struct index_state;
+struct repository;
struct strbuf;
#define CONV_EOL_RNDTRP_DIE (1<<0) /* Die if CRLF to LF to CRLF is different */
@@ -103,34 +104,26 @@ const char *get_convert_attr_ascii(struct index_state *istate,
int convert_to_git(struct index_state *istate,
const char *path, const char *src, size_t len,
struct strbuf *dst, int conv_flags);
-int convert_to_working_tree_ca(const struct conv_attrs *ca,
+int convert_to_working_tree_ca(struct repository *repo,
+ const struct conv_attrs *ca,
const char *path, const char *src,
size_t len, struct strbuf *dst,
const struct checkout_metadata *meta);
-int async_convert_to_working_tree_ca(const struct conv_attrs *ca,
+int async_convert_to_working_tree_ca(struct repository *repo,
+ const struct conv_attrs *ca,
const char *path, const char *src,
size_t len, struct strbuf *dst,
const struct checkout_metadata *meta,
void *dco);
-static inline int convert_to_working_tree(struct index_state *istate,
- const char *path, const char *src,
- size_t len, struct strbuf *dst,
- const struct checkout_metadata *meta)
-{
- struct conv_attrs ca;
- convert_attrs(istate, &ca, path);
- return convert_to_working_tree_ca(&ca, path, src, len, dst, meta);
-}
-static inline int async_convert_to_working_tree(struct index_state *istate,
- const char *path, const char *src,
- size_t len, struct strbuf *dst,
- const struct checkout_metadata *meta,
- void *dco)
-{
- struct conv_attrs ca;
- convert_attrs(istate, &ca, path);
- return async_convert_to_working_tree_ca(&ca, path, src, len, dst, meta, dco);
-}
+int convert_to_working_tree(struct index_state *istate,
+ const char *path, const char *src,
+ size_t len, struct strbuf *dst,
+ const struct checkout_metadata *meta);
+int async_convert_to_working_tree(struct index_state *istate,
+ const char *path, const char *src,
+ size_t len, struct strbuf *dst,
+ const struct checkout_metadata *meta,
+ void *dco);
int async_query_available_blobs(const char *cmd,
struct string_list *available_paths);
int renormalize_buffer(struct index_state *istate,
@@ -183,7 +176,8 @@ struct stream_filter; /* opaque */
struct stream_filter *get_stream_filter(struct index_state *istate,
const char *path,
const struct object_id *);
-struct stream_filter *get_stream_filter_ca(const struct conv_attrs *ca,
+struct stream_filter *get_stream_filter_ca(struct repository *repo,
+ const struct conv_attrs *ca,
const struct object_id *oid);
void free_stream_filter(struct stream_filter *);
int is_null_stream_filter(struct stream_filter *);
diff --git a/entry.c b/entry.c
index 1c4f0f4407..7fda86e67f 100644
--- a/entry.c
+++ b/entry.c
@@ -296,11 +296,14 @@ static int write_entry(struct cache_entry *ce, char *path, struct conv_attrs *ca
const struct submodule *sub;
struct checkout_metadata meta;
static int scratch_nr_checkouts;
+ struct repository *repo = state->istate && state->istate->repo ?
+ state->istate->repo : the_repository;
clone_checkout_metadata(&meta, &state->meta, &ce->oid);
if (ce_mode_s_ifmt == S_IFREG) {
- struct stream_filter *filter = get_stream_filter_ca(ca, &ce->oid);
+ struct stream_filter *filter =
+ get_stream_filter_ca(repo, ca, &ce->oid);
if (filter &&
!streaming_write_entry(ce, path, filter,
state, to_tempfile,
@@ -348,9 +351,11 @@ static int write_entry(struct cache_entry *ce, char *path, struct conv_attrs *ca
* Convert from git internal format to working tree format
*/
if (dco && dco->state != CE_NO_DELAY) {
- ret = async_convert_to_working_tree_ca(ca, ce->name,
+ ret = async_convert_to_working_tree_ca(repo, ca,
+ ce->name,
new_blob, size,
- &buf, &meta, dco);
+ &buf, &meta,
+ dco);
if (ret) {
struct string_list_item *item =
string_list_lookup(&dco->paths, ce->name);
@@ -362,8 +367,9 @@ static int write_entry(struct cache_entry *ce, char *path, struct conv_attrs *ca
}
}
} else {
- ret = convert_to_working_tree_ca(ca, ce->name, new_blob,
- size, &buf, &meta);
+ ret = convert_to_working_tree_ca(repo, ca, ce->name,
+ new_blob, size, &buf,
+ &meta);
}
if (ret) {
diff --git a/parallel-checkout.c b/parallel-checkout.c
index 0bf4bd6d4a..51a4db4f67 100644
--- a/parallel-checkout.c
+++ b/parallel-checkout.c
@@ -279,7 +279,8 @@ static int write_pc_item_to_fd(struct parallel_checkout_item *pc_item, int fd,
/* Sanity check */
ASSERT(is_eligible_for_parallel_checkout(pc_item->ce, &pc_item->ca));
- filter = get_stream_filter_ca(&pc_item->ca, &pc_item->ce->oid);
+ filter = get_stream_filter_ca(the_repository, &pc_item->ca,
+ &pc_item->ce->oid);
if (filter) {
if (odb_stream_blob_to_fd(the_repository->objects, fd,
&pc_item->ce->oid, filter, 1)) {
@@ -302,8 +303,9 @@ static int write_pc_item_to_fd(struct parallel_checkout_item *pc_item, int fd,
* checkout, so pass NULL. Note: if that changes, the metadata must also
* be passed from the main process to the workers.
*/
- ret = convert_to_working_tree_ca(&pc_item->ca, pc_item->ce->name,
- blob, size, &buf, NULL);
+ ret = convert_to_working_tree_ca(the_repository, &pc_item->ca,
+ pc_item->ce->name, blob, size, &buf,
+ NULL);
if (ret) {
size_t newsize;
--
2.43.0
^ permalink raw reply related [flat|nested] 9+ messages in thread* [PATCH 2/4] environment: move auto_crlf into repo_config_values
2026-10-24 22:00 [PATCH 0/4] environment: move line ending config variables into repo_config_values Aniket Gupta
2026-10-24 22:00 ` [PATCH 1/4] convert: pass 'repo' to the working tree conversion functions Aniket Gupta
@ 2026-10-24 22:00 ` Aniket Gupta
2026-10-24 22:00 ` [PATCH 3/4] environment: move core_eol " Aniket Gupta
` (2 subsequent siblings)
4 siblings, 0 replies; 9+ messages in thread
From: Aniket Gupta @ 2026-10-24 22:00 UTC (permalink / raw)
To: git; +Cc: gitster, christian.couder, cat, belkid98, ps, phillip.wood123
The global variable 'auto_crlf' holds the value of the 'core.autocrlf'
configuration, which controls whether line endings are converted when
files are added to and checked out of the repository. Move it into
'struct repo_config_values' to continue the libification effort.
While 'enum auto_crlf' ideally belongs in 'convert.h', moving it there
introduces a circular dependency chain:
convert.h -> hash.h -> repository.h -> environment.h.
Therefore, the enum definition is kept in 'environment.h' just below
'enum object_creation_mode', under the existing NEEDSWORK comment for
future cleanup. Initialize the per-repository value to its default in
'repo_config_values_init()'.
Modify the configuration parsing in environment.c to update the
per-repository structure directly. To read the value, introduce the
getter 'repo_auto_crlf()' and pass the repository down to the helpers
in 'convert.c' that need it.
Signed-off-by: Aniket Gupta <aniketgupta3001@gmail.com>
---
convert.c | 68 +++++++++++++++++++++++++++++++--------------------
convert.h | 8 ------
environment.c | 13 +++++++---
environment.h | 9 +++++++
4 files changed, 60 insertions(+), 38 deletions(-)
diff --git a/convert.c b/convert.c
index 95bdfafdd0..7c7fdd4b2d 100644
--- a/convert.c
+++ b/convert.c
@@ -158,11 +158,11 @@ const char *get_wt_convert_stats_ascii(const char *path)
return ret;
}
-static int text_eol_is_crlf(void)
+static int text_eol_is_crlf(struct repository *repo)
{
- if (auto_crlf == AUTO_CRLF_TRUE)
+ if (repo_auto_crlf(repo) == AUTO_CRLF_TRUE)
return 1;
- else if (auto_crlf == AUTO_CRLF_INPUT)
+ else if (repo_auto_crlf(repo) == AUTO_CRLF_INPUT)
return 0;
if (core_eol == EOL_CRLF)
return 1;
@@ -171,7 +171,8 @@ static int text_eol_is_crlf(void)
return 0;
}
-static enum eol output_eol(enum convert_crlf_action crlf_action)
+static enum eol output_eol(struct repository *repo,
+ enum convert_crlf_action crlf_action)
{
switch (crlf_action) {
case CRLF_BINARY:
@@ -188,7 +189,7 @@ static enum eol output_eol(enum convert_crlf_action crlf_action)
case CRLF_TEXT:
case CRLF_AUTO:
/* fall through */
- return text_eol_is_crlf() ? EOL_CRLF : EOL_LF;
+ return text_eol_is_crlf(repo) ? EOL_CRLF : EOL_LF;
}
warning(_("illegal crlf_action %d"), (int)crlf_action);
return core_eol;
@@ -244,10 +245,11 @@ static int has_crlf_in_index(struct index_state *istate, const char *path)
return has_crlf;
}
-static int will_convert_lf_to_crlf(struct text_stat *stats,
+static int will_convert_lf_to_crlf(struct repository *repo,
+ struct text_stat *stats,
enum convert_crlf_action crlf_action)
{
- if (output_eol(crlf_action) != EOL_CRLF)
+ if (output_eol(repo, crlf_action) != EOL_CRLF)
return 0;
/* No "naked" LF? Nothing to convert, regardless. */
if (!stats->lonelf)
@@ -505,6 +507,8 @@ static int crlf_to_git(struct index_state *istate,
struct strbuf *buf,
enum convert_crlf_action crlf_action, int conv_flags)
{
+ struct repository *repo = istate && istate->repo ?
+ istate->repo : the_repository;
struct text_stat stats;
char *dst;
int convert_crlf_into_lf;
@@ -547,7 +551,7 @@ static int crlf_to_git(struct index_state *istate,
new_stats.crlf = 0;
}
/* simulate "git checkout" */
- if (will_convert_lf_to_crlf(&new_stats, crlf_action)) {
+ if (will_convert_lf_to_crlf(repo, &new_stats, crlf_action)) {
new_stats.crlf += new_stats.lonelf;
new_stats.lonelf = 0;
}
@@ -589,17 +593,18 @@ static int crlf_to_git(struct index_state *istate,
return 1;
}
-static int crlf_to_worktree(const char *src, size_t len, struct strbuf *buf,
+static int crlf_to_worktree(struct repository *repo,
+ const char *src, size_t len, struct strbuf *buf,
enum convert_crlf_action crlf_action)
{
char *to_free = NULL;
struct text_stat stats;
- if (!len || output_eol(crlf_action) != EOL_CRLF)
+ if (!len || output_eol(repo, crlf_action) != EOL_CRLF)
return 0;
gather_stats(src, len, &stats);
- if (!will_convert_lf_to_crlf(&stats, crlf_action))
+ if (!will_convert_lf_to_crlf(repo, &stats, crlf_action))
return 0;
/* are we "faking" in place editing ? */
@@ -1321,6 +1326,8 @@ static struct attr_check *check;
void convert_attrs(struct index_state *istate,
struct conv_attrs *ca, const char *path)
{
+ struct repository *repo = istate && istate->repo ?
+ istate->repo : the_repository;
struct attr_check_item *ccheck = NULL;
if (!check) {
@@ -1354,12 +1361,16 @@ void convert_attrs(struct index_state *istate,
/* Save attr and make a decision for action */
ca->attr_action = ca->crlf_action;
if (ca->crlf_action == CRLF_TEXT)
- ca->crlf_action = text_eol_is_crlf() ? CRLF_TEXT_CRLF : CRLF_TEXT_INPUT;
- if (ca->crlf_action == CRLF_UNDEFINED && auto_crlf == AUTO_CRLF_FALSE)
+ ca->crlf_action = text_eol_is_crlf(repo) ?
+ CRLF_TEXT_CRLF : CRLF_TEXT_INPUT;
+ if (ca->crlf_action == CRLF_UNDEFINED &&
+ repo_auto_crlf(repo) == AUTO_CRLF_FALSE)
ca->crlf_action = CRLF_BINARY;
- if (ca->crlf_action == CRLF_UNDEFINED && auto_crlf == AUTO_CRLF_TRUE)
+ if (ca->crlf_action == CRLF_UNDEFINED &&
+ repo_auto_crlf(repo) == AUTO_CRLF_TRUE)
ca->crlf_action = CRLF_AUTO_CRLF;
- if (ca->crlf_action == CRLF_UNDEFINED && auto_crlf == AUTO_CRLF_INPUT)
+ if (ca->crlf_action == CRLF_UNDEFINED &&
+ repo_auto_crlf(repo) == AUTO_CRLF_INPUT)
ca->crlf_action = CRLF_AUTO_INPUT;
}
@@ -1479,7 +1490,8 @@ void convert_to_git_filter_fd(struct index_state *istate,
ident_to_git(dst->buf, dst->len, dst, ca.ident);
}
-static int convert_to_working_tree_ca_internal(const struct conv_attrs *ca,
+static int convert_to_working_tree_ca_internal(struct repository *repo,
+ const struct conv_attrs *ca,
const char *path, const char *src,
size_t len, struct strbuf *dst,
int normalizing,
@@ -1499,7 +1511,7 @@ static int convert_to_working_tree_ca_internal(const struct conv_attrs *ca,
* support smudge). The filters might expect CRLFs.
*/
if ((ca->drv && (ca->drv->smudge || ca->drv->process)) || !normalizing) {
- ret |= crlf_to_worktree(src, len, dst, ca->crlf_action);
+ ret |= crlf_to_worktree(repo, src, len, dst, ca->crlf_action);
if (ret) {
src = dst->buf;
len = dst->len;
@@ -1520,25 +1532,25 @@ static int convert_to_working_tree_ca_internal(const struct conv_attrs *ca,
return ret | ret_filter;
}
-int async_convert_to_working_tree_ca(struct repository *repo UNUSED,
+int async_convert_to_working_tree_ca(struct repository *repo,
const struct conv_attrs *ca,
const char *path, const char *src,
size_t len, struct strbuf *dst,
const struct checkout_metadata *meta,
void *dco)
{
- return convert_to_working_tree_ca_internal(ca, path, src, len, dst, 0,
- meta, dco);
+ return convert_to_working_tree_ca_internal(repo, ca, path, src, len,
+ dst, 0, meta, dco);
}
-int convert_to_working_tree_ca(struct repository *repo UNUSED,
+int convert_to_working_tree_ca(struct repository *repo,
const struct conv_attrs *ca,
const char *path, const char *src,
size_t len, struct strbuf *dst,
const struct checkout_metadata *meta)
{
- return convert_to_working_tree_ca_internal(ca, path, src, len, dst, 0,
- meta, NULL);
+ return convert_to_working_tree_ca_internal(repo, ca, path, src, len,
+ dst, 0, meta, NULL);
}
int convert_to_working_tree(struct index_state *istate,
@@ -1570,12 +1582,14 @@ int async_convert_to_working_tree(struct index_state *istate,
int renormalize_buffer(struct index_state *istate, const char *path,
const char *src, size_t len, struct strbuf *dst)
{
+ struct repository *repo = istate && istate->repo ?
+ istate->repo : the_repository;
struct conv_attrs ca;
int ret;
convert_attrs(istate, &ca, path);
- ret = convert_to_working_tree_ca_internal(&ca, path, src, len, dst, 1,
- NULL, NULL);
+ ret = convert_to_working_tree_ca_internal(repo, &ca, path, src, len,
+ dst, 1, NULL, NULL);
if (ret) {
src = dst->buf;
len = dst->len;
@@ -2009,7 +2023,7 @@ static struct stream_filter *ident_filter(const struct object_id *oid)
* Note that you would be crazy to set CRLF, smudge/clean or ident to a
* large binary blob you would want us not to slurp into the memory!
*/
-struct stream_filter *get_stream_filter_ca(struct repository *repo UNUSED,
+struct stream_filter *get_stream_filter_ca(struct repository *repo,
const struct conv_attrs *ca,
const struct object_id *oid)
{
@@ -2021,7 +2035,7 @@ struct stream_filter *get_stream_filter_ca(struct repository *repo UNUSED,
if (ca->ident)
filter = ident_filter(oid);
- if (output_eol(ca->crlf_action) == EOL_CRLF)
+ if (output_eol(repo, ca->crlf_action) == EOL_CRLF)
filter = cascade_filter(filter, lf_to_crlf_filter());
else
filter = cascade_filter(filter, &null_filter_singleton);
diff --git a/convert.h b/convert.h
index 137fa1593a..dae11d372d 100644
--- a/convert.h
+++ b/convert.h
@@ -19,14 +19,6 @@ struct strbuf;
extern int global_conv_flags_eol;
-enum auto_crlf {
- AUTO_CRLF_FALSE = 0,
- AUTO_CRLF_TRUE = 1,
- AUTO_CRLF_INPUT = -1
-};
-
-extern enum auto_crlf auto_crlf;
-
enum eol {
EOL_UNSET,
EOL_CRLF,
diff --git a/environment.c b/environment.c
index c83cf44839..bbac8ed8c9 100644
--- a/environment.c
+++ b/environment.c
@@ -49,7 +49,6 @@ int fsync_object_files = -1;
int use_fsync = -1;
enum fsync_method fsync_method = FSYNC_METHOD_DEFAULT;
enum fsync_component fsync_components = FSYNC_COMPONENTS_DEFAULT;
-enum auto_crlf auto_crlf = AUTO_CRLF_FALSE;
enum eol core_eol = EOL_UNSET;
int global_conv_flags_eol = CONV_EOL_RNDTRP_WARN;
char *check_roundtrip_encoding;
@@ -152,6 +151,13 @@ int repo_has_symlinks(struct repository *repo)
: platform_has_symlinks();
}
+enum auto_crlf repo_auto_crlf(struct repository *repo)
+{
+ return repo->initialized
+ ? repo_config_values(repo)->auto_crlf
+ : AUTO_CRLF_FALSE;
+}
+
const char *repo_excludes_file(struct repository *repo)
{
struct repo_config_values *cfg = repo_config_values(repo);
@@ -420,10 +426,10 @@ int git_default_core_config(const char *var, const char *value,
if (!strcmp(var, "core.autocrlf")) {
if (value && !strcasecmp(value, "input")) {
- auto_crlf = AUTO_CRLF_INPUT;
+ cfg->auto_crlf = AUTO_CRLF_INPUT;
return 0;
}
- auto_crlf = git_config_bool(var, value);
+ cfg->auto_crlf = git_config_bool(var, value);
return 0;
}
@@ -777,6 +783,7 @@ void repo_config_values_init(struct repo_config_values *cfg)
cfg->trust_executable_bit = 1;
cfg->has_symlinks = platform_has_symlinks();
cfg->use_nanosec = 0;
+ cfg->auto_crlf = AUTO_CRLF_FALSE;
/* section "sparse" config values */
cfg->sparse_expect_files_outside_of_patterns = 0;
diff --git a/environment.h b/environment.h
index 49c86e8879..872da3576b 100644
--- a/environment.h
+++ b/environment.h
@@ -123,6 +123,12 @@ enum object_creation_mode {
OBJECT_CREATION_USES_RENAMES = 1
};
+enum auto_crlf {
+ AUTO_CRLF_FALSE = 0,
+ AUTO_CRLF_TRUE = 1,
+ AUTO_CRLF_INPUT = -1
+};
+
struct repo_config_values {
/* section "core" config values */
char *attributes_file;
@@ -149,6 +155,7 @@ struct repo_config_values {
int trust_executable_bit;
int has_symlinks;
int use_nanosec;
+ enum auto_crlf auto_crlf;
/* section "sparse" config values */
int sparse_expect_files_outside_of_patterns;
@@ -203,6 +210,8 @@ int repo_trust_executable_bit(struct repository *repo);
int repo_has_symlinks(struct repository *repo);
+enum auto_crlf repo_auto_crlf(struct repository *repo);
+
const char *repo_excludes_file(struct repository *repo);
void repo_config_values_init(struct repo_config_values *cfg);
--
2.43.0
^ permalink raw reply related [flat|nested] 9+ messages in thread* [PATCH 3/4] environment: move core_eol into repo_config_values
2026-10-24 22:00 [PATCH 0/4] environment: move line ending config variables into repo_config_values Aniket Gupta
2026-10-24 22:00 ` [PATCH 1/4] convert: pass 'repo' to the working tree conversion functions Aniket Gupta
2026-10-24 22:00 ` [PATCH 2/4] environment: move auto_crlf into repo_config_values Aniket Gupta
@ 2026-10-24 22:00 ` Aniket Gupta
2026-10-24 22:00 ` [PATCH 4/4] environment: move global_conv_flags_eol " Aniket Gupta
2026-10-26 12:27 ` [PATCH 0/4] environment: move line ending config variables " Patrick Steinhardt
4 siblings, 0 replies; 9+ messages in thread
From: Aniket Gupta @ 2026-10-24 22:00 UTC (permalink / raw)
To: git; +Cc: gitster, christian.couder, cat, belkid98, ps, phillip.wood123
The global variable 'core_eol' holds the value of the 'core.eol'
configuration, which sets the line ending used for files that are
converted to the working tree format. Move it into 'struct
repo_config_values' to continue the libification effort.
As with 'enum auto_crlf', moving 'enum eol' to 'convert.h' would
introduce a circular dependency chain:
convert.h -> hash.h -> repository.h -> environment.h.
Therefore, keep the enum definition in 'environment.h' next to the
other ones, under the existing NEEDSWORK comment. Initialize the
per-repository value to its default in 'repo_config_values_init()'.
Modify the configuration parsing in environment.c to update the
per-repository structure directly, and introduce the getter
'repo_core_eol()' to read the value in 'convert.c'.
Signed-off-by: Aniket Gupta <aniketgupta3001@gmail.com>
---
convert.c | 6 +++---
convert.h | 12 ------------
environment.c | 17 ++++++++++++-----
environment.h | 14 ++++++++++++++
4 files changed, 29 insertions(+), 20 deletions(-)
diff --git a/convert.c b/convert.c
index 7c7fdd4b2d..1d4e8a246b 100644
--- a/convert.c
+++ b/convert.c
@@ -164,9 +164,9 @@ static int text_eol_is_crlf(struct repository *repo)
return 1;
else if (repo_auto_crlf(repo) == AUTO_CRLF_INPUT)
return 0;
- if (core_eol == EOL_CRLF)
+ if (repo_core_eol(repo) == EOL_CRLF)
return 1;
- if (core_eol == EOL_UNSET && EOL_NATIVE == EOL_CRLF)
+ if (repo_core_eol(repo) == EOL_UNSET && EOL_NATIVE == EOL_CRLF)
return 1;
return 0;
}
@@ -192,7 +192,7 @@ static enum eol output_eol(struct repository *repo,
return text_eol_is_crlf(repo) ? EOL_CRLF : EOL_LF;
}
warning(_("illegal crlf_action %d"), (int)crlf_action);
- return core_eol;
+ return repo_core_eol(repo);
}
static void check_global_conv_flags_eol(const char *path,
diff --git a/convert.h b/convert.h
index dae11d372d..3c51130177 100644
--- a/convert.h
+++ b/convert.h
@@ -19,17 +19,6 @@ struct strbuf;
extern int global_conv_flags_eol;
-enum eol {
- EOL_UNSET,
- EOL_CRLF,
- EOL_LF,
-#ifdef NATIVE_CRLF
- EOL_NATIVE = EOL_CRLF
-#else
- EOL_NATIVE = EOL_LF
-#endif
-};
-
enum ce_delay_state {
CE_NO_DELAY = 0,
CE_CAN_DELAY = 1,
@@ -84,7 +73,6 @@ struct conv_attrs {
void convert_attrs(struct index_state *istate,
struct conv_attrs *ca, const char *path);
-extern enum eol core_eol;
extern char *check_roundtrip_encoding;
const char *get_cached_convert_stats_ascii(struct index_state *istate,
const char *path);
diff --git a/environment.c b/environment.c
index bbac8ed8c9..6445994986 100644
--- a/environment.c
+++ b/environment.c
@@ -49,7 +49,6 @@ int fsync_object_files = -1;
int use_fsync = -1;
enum fsync_method fsync_method = FSYNC_METHOD_DEFAULT;
enum fsync_component fsync_components = FSYNC_COMPONENTS_DEFAULT;
-enum eol core_eol = EOL_UNSET;
int global_conv_flags_eol = CONV_EOL_RNDTRP_WARN;
char *check_roundtrip_encoding;
#ifndef OBJECT_CREATION_MODE
@@ -158,6 +157,13 @@ enum auto_crlf repo_auto_crlf(struct repository *repo)
: AUTO_CRLF_FALSE;
}
+enum eol repo_core_eol(struct repository *repo)
+{
+ return repo->initialized
+ ? repo_config_values(repo)->core_eol
+ : EOL_UNSET;
+}
+
const char *repo_excludes_file(struct repository *repo)
{
struct repo_config_values *cfg = repo_config_values(repo);
@@ -447,13 +453,13 @@ int git_default_core_config(const char *var, const char *value,
if (!strcmp(var, "core.eol")) {
if (value && !strcasecmp(value, "lf"))
- core_eol = EOL_LF;
+ cfg->core_eol = EOL_LF;
else if (value && !strcasecmp(value, "crlf"))
- core_eol = EOL_CRLF;
+ cfg->core_eol = EOL_CRLF;
else if (value && !strcasecmp(value, "native"))
- core_eol = EOL_NATIVE;
+ cfg->core_eol = EOL_NATIVE;
else
- core_eol = EOL_UNSET;
+ cfg->core_eol = EOL_UNSET;
return 0;
}
@@ -784,6 +790,7 @@ void repo_config_values_init(struct repo_config_values *cfg)
cfg->has_symlinks = platform_has_symlinks();
cfg->use_nanosec = 0;
cfg->auto_crlf = AUTO_CRLF_FALSE;
+ cfg->core_eol = EOL_UNSET;
/* section "sparse" config values */
cfg->sparse_expect_files_outside_of_patterns = 0;
diff --git a/environment.h b/environment.h
index 872da3576b..bf6701560d 100644
--- a/environment.h
+++ b/environment.h
@@ -129,6 +129,17 @@ enum auto_crlf {
AUTO_CRLF_INPUT = -1
};
+enum eol {
+ EOL_UNSET,
+ EOL_CRLF,
+ EOL_LF,
+#ifdef NATIVE_CRLF
+ EOL_NATIVE = EOL_CRLF
+#else
+ EOL_NATIVE = EOL_LF
+#endif
+};
+
struct repo_config_values {
/* section "core" config values */
char *attributes_file;
@@ -156,6 +167,7 @@ struct repo_config_values {
int has_symlinks;
int use_nanosec;
enum auto_crlf auto_crlf;
+ enum eol core_eol;
/* section "sparse" config values */
int sparse_expect_files_outside_of_patterns;
@@ -212,6 +224,8 @@ int repo_has_symlinks(struct repository *repo);
enum auto_crlf repo_auto_crlf(struct repository *repo);
+enum eol repo_core_eol(struct repository *repo);
+
const char *repo_excludes_file(struct repository *repo);
void repo_config_values_init(struct repo_config_values *cfg);
--
2.43.0
^ permalink raw reply related [flat|nested] 9+ messages in thread* [PATCH 4/4] environment: move global_conv_flags_eol into repo_config_values
2026-10-24 22:00 [PATCH 0/4] environment: move line ending config variables into repo_config_values Aniket Gupta
` (2 preceding siblings ...)
2026-10-24 22:00 ` [PATCH 3/4] environment: move core_eol " Aniket Gupta
@ 2026-10-24 22:00 ` Aniket Gupta
2026-10-26 12:27 ` [PATCH 0/4] environment: move line ending config variables " Patrick Steinhardt
4 siblings, 0 replies; 9+ messages in thread
From: Aniket Gupta @ 2026-10-24 22:00 UTC (permalink / raw)
To: git; +Cc: gitster, christian.couder, cat, belkid98, ps, phillip.wood123
The global variable 'global_conv_flags_eol' holds the value of the
'core.safecrlf' configuration, which controls whether Git warns or
refuses to proceed when converting line endings would not be
reversible. Move it into 'struct repo_config_values' to continue the
libification effort.
Initialize the per-repository value to its default in
'repo_config_values_init()', and modify the configuration parsing in
environment.c to update the per-repository structure directly.
To read the value, introduce the getter 'repo_global_conv_flags_eol()'
and update its users in diff.c, combine-diff.c and object-file.c. In
object-file.c, pass the index to get_conv_flags() so that it can find
the repository.
Signed-off-by: Aniket Gupta <aniketgupta3001@gmail.com>
---
combine-diff.c | 4 +++-
convert.h | 2 --
diff.c | 2 +-
environment.c | 13 ++++++++++---
environment.h | 3 +++
object-file.c | 11 +++++++----
6 files changed, 24 insertions(+), 11 deletions(-)
diff --git a/combine-diff.c b/combine-diff.c
index 717d537688..c77990aacf 100644
--- a/combine-diff.c
+++ b/combine-diff.c
@@ -1098,9 +1098,11 @@ static void show_patch_diff(struct combine_diff_path *elem, int num_parent,
/* If not a fake symlink, apply filters, e.g. autocrlf */
if (is_file) {
struct strbuf buf = STRBUF_INIT;
+ int conv_flags =
+ repo_global_conv_flags_eol(rev->diffopt.repo);
if (convert_to_git(rev->diffopt.repo->index,
- elem->path, result, len, &buf, global_conv_flags_eol)) {
+ elem->path, result, len, &buf, conv_flags)) {
free(result);
result = strbuf_detach(&buf, &len);
result_size = len;
diff --git a/convert.h b/convert.h
index 3c51130177..18be39ca90 100644
--- a/convert.h
+++ b/convert.h
@@ -17,8 +17,6 @@ struct strbuf;
#define CONV_EOL_KEEP_CRLF (1<<3) /* Keep CRLF line endings as is */
#define CONV_WRITE_OBJECT (1<<4) /* Content is written to the index */
-extern int global_conv_flags_eol;
-
enum ce_delay_state {
CE_NO_DELAY = 0,
CE_CAN_DELAY = 1,
diff --git a/diff.c b/diff.c
index b4ac17f8ef..7eb45160c2 100644
--- a/diff.c
+++ b/diff.c
@@ -4480,7 +4480,7 @@ int diff_populate_filespec(struct repository *r,
int size_only = options ? options->check_size_only : 0;
int check_binary = options ? options->check_binary : 0;
int err = 0;
- int conv_flags = global_conv_flags_eol;
+ int conv_flags = repo_global_conv_flags_eol(r);
/*
* demote FAIL to WARN to allow inspecting the situation
* instead of refusing.
diff --git a/environment.c b/environment.c
index 6445994986..9b98b3b075 100644
--- a/environment.c
+++ b/environment.c
@@ -49,7 +49,6 @@ int fsync_object_files = -1;
int use_fsync = -1;
enum fsync_method fsync_method = FSYNC_METHOD_DEFAULT;
enum fsync_component fsync_components = FSYNC_COMPONENTS_DEFAULT;
-int global_conv_flags_eol = CONV_EOL_RNDTRP_WARN;
char *check_roundtrip_encoding;
#ifndef OBJECT_CREATION_MODE
#define OBJECT_CREATION_MODE OBJECT_CREATION_USES_HARDLINKS
@@ -164,6 +163,13 @@ enum eol repo_core_eol(struct repository *repo)
: EOL_UNSET;
}
+int repo_global_conv_flags_eol(struct repository *repo)
+{
+ return repo->initialized
+ ? repo_config_values(repo)->global_conv_flags_eol
+ : CONV_EOL_RNDTRP_WARN;
+}
+
const char *repo_excludes_file(struct repository *repo)
{
struct repo_config_values *cfg = repo_config_values(repo);
@@ -442,11 +448,11 @@ int git_default_core_config(const char *var, const char *value,
if (!strcmp(var, "core.safecrlf")) {
int eol_rndtrp_die;
if (value && !strcasecmp(value, "warn")) {
- global_conv_flags_eol = CONV_EOL_RNDTRP_WARN;
+ cfg->global_conv_flags_eol = CONV_EOL_RNDTRP_WARN;
return 0;
}
eol_rndtrp_die = git_config_bool(var, value);
- global_conv_flags_eol = eol_rndtrp_die ?
+ cfg->global_conv_flags_eol = eol_rndtrp_die ?
CONV_EOL_RNDTRP_DIE : 0;
return 0;
}
@@ -791,6 +797,7 @@ void repo_config_values_init(struct repo_config_values *cfg)
cfg->use_nanosec = 0;
cfg->auto_crlf = AUTO_CRLF_FALSE;
cfg->core_eol = EOL_UNSET;
+ cfg->global_conv_flags_eol = CONV_EOL_RNDTRP_WARN;
/* section "sparse" config values */
cfg->sparse_expect_files_outside_of_patterns = 0;
diff --git a/environment.h b/environment.h
index bf6701560d..47d7a9792d 100644
--- a/environment.h
+++ b/environment.h
@@ -168,6 +168,7 @@ struct repo_config_values {
int use_nanosec;
enum auto_crlf auto_crlf;
enum eol core_eol;
+ int global_conv_flags_eol;
/* section "sparse" config values */
int sparse_expect_files_outside_of_patterns;
@@ -226,6 +227,8 @@ enum auto_crlf repo_auto_crlf(struct repository *repo);
enum eol repo_core_eol(struct repository *repo);
+int repo_global_conv_flags_eol(struct repository *repo);
+
const char *repo_excludes_file(struct repository *repo);
void repo_config_values_init(struct repo_config_values *cfg);
diff --git a/object-file.c b/object-file.c
index c049bf13f7..b3ab8f5bcb 100644
--- a/object-file.c
+++ b/object-file.c
@@ -33,12 +33,15 @@
#include "tempfile.h"
#include "tmp-objdir.h"
-static int get_conv_flags(unsigned flags)
+static int get_conv_flags(struct index_state *istate, unsigned flags)
{
+ struct repository *repo = istate && istate->repo ?
+ istate->repo : the_repository;
+
if (flags & INDEX_RENORMALIZE)
return CONV_EOL_RENORMALIZE;
else if (flags & INDEX_WRITE_OBJECT)
- return global_conv_flags_eol | CONV_WRITE_OBJECT;
+ return repo_global_conv_flags_eol(repo) | CONV_WRITE_OBJECT;
else
return 0;
}
@@ -576,7 +579,7 @@ static int index_mem(struct index_state *istate,
*/
if ((type == OBJ_BLOB) && path) {
if (convert_to_git(istate, path, buf, size, &nbuf,
- get_conv_flags(flags))) {
+ get_conv_flags(istate, flags))) {
buf = nbuf.buf;
size = nbuf.len;
}
@@ -615,7 +618,7 @@ static int index_stream_convert_blob(struct index_state *istate,
ASSERT(would_convert_to_git_filter_fd(istate, path));
convert_to_git_filter_fd(istate, path, fd, &sbuf,
- get_conv_flags(flags));
+ get_conv_flags(istate, flags));
if (write_object)
ret = odb_write_object(istate->repo->objects, sbuf.buf, sbuf.len, OBJ_BLOB,
--
2.43.0
^ permalink raw reply related [flat|nested] 9+ messages in thread* Re: [PATCH 0/4] environment: move line ending config variables into repo_config_values
2026-10-24 22:00 [PATCH 0/4] environment: move line ending config variables into repo_config_values Aniket Gupta
` (3 preceding siblings ...)
2026-10-24 22:00 ` [PATCH 4/4] environment: move global_conv_flags_eol " Aniket Gupta
@ 2026-10-26 12:27 ` Patrick Steinhardt
2026-10-26 13:10 ` Aniket Gupta
2026-10-26 15:53 ` Junio C Hamano
4 siblings, 2 replies; 9+ messages in thread
From: Patrick Steinhardt @ 2026-10-26 12:27 UTC (permalink / raw)
To: Aniket Gupta
Cc: git, gitster, christian.couder, cat, belkid98, phillip.wood123
Hi,
On Sat, Oct 24, 2026 at 10:00:08PM +0000, Aniket Gupta wrote:
> Hi,
>
> This series moves the global variables behind core.autocrlf, core.eol
> and core.safecrlf into 'struct repo_config_values' to continue the
> libification effort.
>
> The first patch passes 'repo' to the working tree conversion
> functions which need it to read the values. The other three move one
> variable each just like the earlier conversions.
>
> An alternative to passing 'repo' would be to store the resolved values
> in 'struct conv_attrs'. I went with passing it since that is what the
> earlier conversions did, but I can change it if you prefer.
This isn't really your fault, but we've had the discussion multiple
times by now that we need to stop moving more config values into
`repo_config_values` until we have a way for how to decouple it from
`the_repository`. The problem here is that the only way to populate
those settings is via `repo_config(git_default_config)`, and that
function will populate the repo config values of `the_repository`.
Consequently, `repo_config_values()` BUGs when called with a different
repostiory.
While these patches _look_ like they libify Git more, they actually do
the exact opposite right now and tie us more and more to
`the_repository`. So I'm inclined to say that we should hold off merging
these patches until we fix that issue, or otherwise we paint ourselves
into a corner.
Patrick
^ permalink raw reply [flat|nested] 9+ messages in thread* Re: [PATCH 0/4] environment: move line ending config variables into repo_config_values
2026-10-26 12:27 ` [PATCH 0/4] environment: move line ending config variables " Patrick Steinhardt
@ 2026-10-26 13:10 ` Aniket Gupta
2026-10-26 13:25 ` Patrick Steinhardt
2026-10-26 15:53 ` Junio C Hamano
1 sibling, 1 reply; 9+ messages in thread
From: Aniket Gupta @ 2026-10-26 13:10 UTC (permalink / raw)
To: ps; +Cc: git, gitster, christian.couder, cat, belkid98, phillip.wood123
Hi Patrick,
Thanks for the explanation. I was not aware of this and will hold off.
Is there any thread or branch about decoupling that I could read? I
would love to contribute to it if I can.
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH 0/4] environment: move line ending config variables into repo_config_values
2026-10-26 13:10 ` Aniket Gupta
@ 2026-10-26 13:25 ` Patrick Steinhardt
0 siblings, 0 replies; 9+ messages in thread
From: Patrick Steinhardt @ 2026-10-26 13:25 UTC (permalink / raw)
To: Aniket Gupta
Cc: git, gitster, christian.couder, cat, belkid98, phillip.wood123
Hey Aniket,
On Mon, Oct 26, 2026 at 01:10:23PM +0000, Aniket Gupta wrote:
> Hi Patrick,
>
> Thanks for the explanation. I was not aware of this and will hold off.
> Is there any thread or branch about decoupling that I could read? I
> would love to contribute to it if I can.
Sorry, I should have provided a reference right from the start. I think
<xmqq8q5n1fa2.fsf@gitster.g> is where we discussed this most in-depth.
Thanks!
Patrick
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH 0/4] environment: move line ending config variables into repo_config_values
2026-10-26 12:27 ` [PATCH 0/4] environment: move line ending config variables " Patrick Steinhardt
2026-10-26 13:10 ` Aniket Gupta
@ 2026-10-26 15:53 ` Junio C Hamano
1 sibling, 0 replies; 9+ messages in thread
From: Junio C Hamano @ 2026-10-26 15:53 UTC (permalink / raw)
To: Patrick Steinhardt
Cc: Aniket Gupta, git, christian.couder, cat, belkid98,
phillip.wood123
Patrick Steinhardt <ps@pks.im> writes:
> While these patches _look_ like they libify Git more, they actually do
> the exact opposite right now and tie us more and more to
> `the_repository`. So I'm inclined to say that we should hold off merging
> these patches until we fix that issue, or otherwise we paint ourselves
> into a corner.
Could you please volunteer to add a quick patch to add a comment
next to the problematic structure to tell people stop moving things
there (for now) and point at the message I am responding to?
Thanks.
^ permalink raw reply [flat|nested] 9+ messages in thread