Skip to content

Commit 44451a2

Browse files
john-caigitster
authored andcommitted
attr: teach "--attr-source=<tree>" global option to "git"
Earlier, 47cfc9b (attr: add flag `--source` to work with tree-ish, 2023-01-14) taught "git check-attr" the "--source=<tree>" option to allow it to read attribute files from a tree-ish, but did so only for the command. Just like "check-attr" users wanted a way to use attributes from a tree-ish and not from the working tree files, users of other commands (like "git diff") would benefit from the same. Undo most of the UI change the commit made, while keeping the internal logic to read attributes from a given tree-ish. Expose the internal logic via a new "--attr-source=<tree>" command line option given to "git", so that it can be used with any git command that runs as part of the main git process. Additionally, add an environment variable GIT_ATTR_SOURCE that is set when --attr-source is passed in, so that subprocesses use the same value for the attributes source tree. Signed-off-by: John Cai <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 48d89b5 commit 44451a2

16 files changed

+140
-29
lines changed

Documentation/git.txt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,11 @@ If you just want to run git as if it was started in `<path>` then use
212212
nohelpers (exclude helper commands), alias and config
213213
(retrieve command list from config variable completion.commands)
214214

215+
--attr-source=<tree-ish>::
216+
Read gitattributes from <tree-ish> instead of the worktree. See
217+
linkgit:gitattributes[5]. This is equivalent to setting the
218+
`GIT_ATTR_SOURCE` environment variable.
219+
215220
GIT COMMANDS
216221
------------
217222

@@ -686,6 +691,9 @@ for further details.
686691
tells Git not to verify the SSL certificate when fetching or
687692
pushing over HTTPS.
688693

694+
`GIT_ATTR_SOURCE`::
695+
Sets the treeish that gitattributes will be read from.
696+
689697
`GIT_ASKPASS`::
690698
If this environment variable is set, then Git commands which need to
691699
acquire passwords or passphrases (e.g. for HTTP or IMAP authentication)

archive.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ static const struct attr_check *get_archive_attrs(struct index_state *istate,
128128
static struct attr_check *check;
129129
if (!check)
130130
check = attr_check_initl("export-ignore", "export-subst", NULL);
131-
git_check_attr(istate, NULL, path, check);
131+
git_check_attr(istate, path, check);
132132
return check;
133133
}
134134

attr.c

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include "object-store.h"
2121
#include "setup.h"
2222
#include "thread-utils.h"
23+
#include "object-name.h"
2324

2425
const char git_attr__true[] = "(builtin)true";
2526
const char git_attr__false[] = "\0(builtin)false";
@@ -1169,11 +1170,42 @@ static void collect_some_attrs(struct index_state *istate,
11691170
fill(path, pathlen, basename_offset, check->stack, check->all_attrs, rem);
11701171
}
11711172

1173+
static const char *default_attr_source_tree_object_name;
1174+
1175+
void set_git_attr_source(const char *tree_object_name)
1176+
{
1177+
default_attr_source_tree_object_name = xstrdup(tree_object_name);
1178+
}
1179+
1180+
static void compute_default_attr_source(struct object_id *attr_source)
1181+
{
1182+
if (!default_attr_source_tree_object_name)
1183+
default_attr_source_tree_object_name = getenv(GIT_ATTR_SOURCE_ENVIRONMENT);
1184+
1185+
if (!default_attr_source_tree_object_name || !is_null_oid(attr_source))
1186+
return;
1187+
1188+
if (repo_get_oid_treeish(the_repository, default_attr_source_tree_object_name, attr_source))
1189+
die(_("bad --attr-source or GIT_ATTR_SOURCE"));
1190+
}
1191+
1192+
static struct object_id *default_attr_source(void)
1193+
{
1194+
static struct object_id attr_source;
1195+
1196+
if (is_null_oid(&attr_source))
1197+
compute_default_attr_source(&attr_source);
1198+
if (is_null_oid(&attr_source))
1199+
return NULL;
1200+
return &attr_source;
1201+
}
1202+
11721203
void git_check_attr(struct index_state *istate,
1173-
const struct object_id *tree_oid, const char *path,
1204+
const char *path,
11741205
struct attr_check *check)
11751206
{
11761207
int i;
1208+
const struct object_id *tree_oid = default_attr_source();
11771209

11781210
collect_some_attrs(istate, tree_oid, path, check);
11791211

@@ -1186,10 +1218,11 @@ void git_check_attr(struct index_state *istate,
11861218
}
11871219
}
11881220

1189-
void git_all_attrs(struct index_state *istate, const struct object_id *tree_oid,
1221+
void git_all_attrs(struct index_state *istate,
11901222
const char *path, struct attr_check *check)
11911223
{
11921224
int i;
1225+
const struct object_id *tree_oid = default_attr_source();
11931226

11941227
attr_check_reset(check);
11951228
collect_some_attrs(istate, tree_oid, path, check);

attr.h

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@
4545
* const char *path;
4646
*
4747
* setup_check();
48-
* git_check_attr(&the_index, tree_oid, path, check);
48+
* git_check_attr(&the_index, path, check);
4949
* ------------
5050
*
5151
* - Act on `.value` member of the result, left in `check->items[]`:
@@ -120,7 +120,6 @@
120120
#define ATTR_MAX_FILE_SIZE (100 * 1024 * 1024)
121121

122122
struct index_state;
123-
struct object_id;
124123

125124
/**
126125
* An attribute is an opaque object that is identified by its name. Pass the
@@ -135,6 +134,12 @@ struct git_attr;
135134
struct all_attrs_item;
136135
struct attr_stack;
137136

137+
/*
138+
* The textual object name for the tree-ish used by git_check_attr()
139+
* to read attributes from (instead of from the working tree).
140+
*/
141+
void set_git_attr_source(const char *);
142+
138143
/*
139144
* Given a string, return the gitattribute object that
140145
* corresponds to it.
@@ -203,14 +208,14 @@ void attr_check_free(struct attr_check *check);
203208
const char *git_attr_name(const struct git_attr *);
204209

205210
void git_check_attr(struct index_state *istate,
206-
const struct object_id *tree_oid, const char *path,
211+
const char *path,
207212
struct attr_check *check);
208213

209214
/*
210215
* Retrieve all attributes that apply to the specified path.
211216
* check holds the attributes and their values.
212217
*/
213-
void git_all_attrs(struct index_state *istate, const struct object_id *tree_oid,
218+
void git_all_attrs(struct index_state *istate,
214219
const char *path, struct attr_check *check);
215220

216221
enum git_attr_direction {

builtin/check-attr.c

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -63,25 +63,25 @@ static void output_attr(struct attr_check *check, const char *file)
6363
}
6464

6565
static void check_attr(const char *prefix, struct attr_check *check,
66-
const struct object_id *tree_oid, int collect_all,
66+
int collect_all,
6767
const char *file)
6868

6969
{
7070
char *full_path =
7171
prefix_path(prefix, prefix ? strlen(prefix) : 0, file);
7272

7373
if (collect_all) {
74-
git_all_attrs(&the_index, tree_oid, full_path, check);
74+
git_all_attrs(&the_index, full_path, check);
7575
} else {
76-
git_check_attr(&the_index, tree_oid, full_path, check);
76+
git_check_attr(&the_index, full_path, check);
7777
}
7878
output_attr(check, file);
7979

8080
free(full_path);
8181
}
8282

8383
static void check_attr_stdin_paths(const char *prefix, struct attr_check *check,
84-
const struct object_id *tree_oid, int collect_all)
84+
int collect_all)
8585
{
8686
struct strbuf buf = STRBUF_INIT;
8787
struct strbuf unquoted = STRBUF_INIT;
@@ -95,7 +95,7 @@ static void check_attr_stdin_paths(const char *prefix, struct attr_check *check,
9595
die("line is badly quoted");
9696
strbuf_swap(&buf, &unquoted);
9797
}
98-
check_attr(prefix, check, tree_oid, collect_all, buf.buf);
98+
check_attr(prefix, check, collect_all, buf.buf);
9999
maybe_flush_or_die(stdout, "attribute to stdout");
100100
}
101101
strbuf_release(&buf);
@@ -111,7 +111,6 @@ static NORETURN void error_with_usage(const char *msg)
111111
int cmd_check_attr(int argc, const char **argv, const char *prefix)
112112
{
113113
struct attr_check *check;
114-
struct object_id *tree_oid = NULL;
115114
struct object_id initialized_oid;
116115
int cnt, i, doubledash, filei;
117116

@@ -187,14 +186,14 @@ int cmd_check_attr(int argc, const char **argv, const char *prefix)
187186
if (source) {
188187
if (repo_get_oid_tree(the_repository, source, &initialized_oid))
189188
die("%s: not a valid tree-ish source", source);
190-
tree_oid = &initialized_oid;
189+
set_git_attr_source(source);
191190
}
192191

193192
if (stdin_paths)
194-
check_attr_stdin_paths(prefix, check, tree_oid, all_attrs);
193+
check_attr_stdin_paths(prefix, check, all_attrs);
195194
else {
196195
for (i = filei; i < argc; i++)
197-
check_attr(prefix, check, tree_oid, all_attrs, argv[i]);
196+
check_attr(prefix, check, all_attrs, argv[i]);
198197
maybe_flush_or_die(stdout, "attribute to stdout");
199198
}
200199

builtin/pack-objects.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1331,7 +1331,7 @@ static int no_try_delta(const char *path)
13311331

13321332
if (!check)
13331333
check = attr_check_initl("delta", NULL);
1334-
git_check_attr(the_repository->index, NULL, path, check);
1334+
git_check_attr(the_repository->index, path, check);
13351335
if (ATTR_FALSE(check->items[0].value))
13361336
return 1;
13371337
return 0;

convert.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1314,7 +1314,7 @@ void convert_attrs(struct index_state *istate,
13141314
git_config(read_convert_config, NULL);
13151315
}
13161316

1317-
git_check_attr(istate, NULL, path, check);
1317+
git_check_attr(istate, path, check);
13181318
ccheck = check->items;
13191319
ca->crlf_action = git_path_check_crlf(ccheck + 4);
13201320
if (ca->crlf_action == CRLF_UNDEFINED)

environment.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ const char *getenv_safe(struct strvec *argv, const char *name);
5555
#define GIT_QUARANTINE_ENVIRONMENT "GIT_QUARANTINE_PATH"
5656
#define GIT_OPTIONAL_LOCKS_ENVIRONMENT "GIT_OPTIONAL_LOCKS"
5757
#define GIT_TEXT_DOMAIN_DIR_ENVIRONMENT "GIT_TEXTDOMAINDIR"
58+
#define GIT_ATTR_SOURCE_ENVIRONMENT "GIT_ATTR_SOURCE"
5859

5960
/*
6061
* Environment variable used in handshaking the wire protocol.

git.c

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include "alias.h"
1010
#include "replace-object.h"
1111
#include "setup.h"
12+
#include "attr.h"
1213
#include "shallow.h"
1314
#include "trace.h"
1415
#include "trace2.h"
@@ -314,6 +315,21 @@ static int handle_options(const char ***argv, int *argc, int *envchanged)
314315
} else {
315316
exit(list_cmds(cmd));
316317
}
318+
} else if (!strcmp(cmd, "--attr-source")) {
319+
if (*argc < 2) {
320+
fprintf(stderr, _("no attribute source given for --attr-source\n" ));
321+
usage(git_usage_string);
322+
}
323+
setenv(GIT_ATTR_SOURCE_ENVIRONMENT, (*argv)[1], 1);
324+
if (envchanged)
325+
*envchanged = 1;
326+
(*argv)++;
327+
(*argc)--;
328+
} else if (skip_prefix(cmd, "--attr-source=", &cmd)) {
329+
set_git_attr_source(cmd);
330+
setenv(GIT_ATTR_SOURCE_ENVIRONMENT, cmd, 1);
331+
if (envchanged)
332+
*envchanged = 1;
317333
} else {
318334
fprintf(stderr, _("unknown option: %s\n"), cmd);
319335
usage(git_usage_string);

ll-merge.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -393,7 +393,7 @@ enum ll_merge_result ll_merge(mmbuffer_t *result_buf,
393393
normalize_file(theirs, path, istate);
394394
}
395395

396-
git_check_attr(istate, NULL, path, check);
396+
git_check_attr(istate, path, check);
397397
ll_driver_name = check->items[0].value;
398398
if (check->items[1].value) {
399399
marker_size = atoi(check->items[1].value);
@@ -421,7 +421,7 @@ int ll_merge_marker_size(struct index_state *istate, const char *path)
421421

422422
if (!check)
423423
check = attr_check_initl("conflict-marker-size", NULL);
424-
git_check_attr(istate, NULL, path, check);
424+
git_check_attr(istate, path, check);
425425
if (check->items[0].value) {
426426
marker_size = atoi(check->items[0].value);
427427
if (marker_size <= 0)

0 commit comments

Comments
 (0)