Skip to content

Commit 8dbcba2

Browse files
committed
Merge branch 'ps/pseudo-refs' into seen
Assorted changes around pseudoref handling. * ps/pseudo-refs: bisect: consistently write BISECT_EXPECTED_REV via the refdb refs: complete list of special refs refs: propagate errno when reading special refs fails wt-status: read HEAD and ORIG_HEAD via the refdb
2 parents ae36652 + 0a06892 commit 8dbcba2

File tree

6 files changed

+87
-39
lines changed

6 files changed

+87
-39
lines changed

bisect.c

Lines changed: 4 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -470,7 +470,6 @@ static int read_bisect_refs(void)
470470
}
471471

472472
static GIT_PATH_FUNC(git_path_bisect_names, "BISECT_NAMES")
473-
static GIT_PATH_FUNC(git_path_bisect_expected_rev, "BISECT_EXPECTED_REV")
474473
static GIT_PATH_FUNC(git_path_bisect_ancestors_ok, "BISECT_ANCESTORS_OK")
475474
static GIT_PATH_FUNC(git_path_bisect_run, "BISECT_RUN")
476475
static GIT_PATH_FUNC(git_path_bisect_start, "BISECT_START")
@@ -706,26 +705,10 @@ static enum bisect_error error_if_skipped_commits(struct commit_list *tried,
706705

707706
static int is_expected_rev(const struct object_id *oid)
708707
{
709-
const char *filename = git_path_bisect_expected_rev();
710-
struct stat st;
711-
struct strbuf str = STRBUF_INIT;
712-
FILE *fp;
713-
int res = 0;
714-
715-
if (stat(filename, &st) || !S_ISREG(st.st_mode))
708+
struct object_id expected_oid;
709+
if (read_ref("BISECT_EXPECTED_REV", &expected_oid))
716710
return 0;
717-
718-
fp = fopen_or_warn(filename, "r");
719-
if (!fp)
720-
return 0;
721-
722-
if (strbuf_getline_lf(&str, fp) != EOF)
723-
res = !strcmp(str.buf, oid_to_hex(oid));
724-
725-
strbuf_release(&str);
726-
fclose(fp);
727-
728-
return res;
711+
return oideq(oid, &expected_oid);
729712
}
730713

731714
enum bisect_error bisect_checkout(const struct object_id *bisect_rev,
@@ -1184,10 +1167,10 @@ int bisect_clean_state(void)
11841167
struct string_list refs_for_removal = STRING_LIST_INIT_NODUP;
11851168
for_each_ref_in("refs/bisect", mark_for_removal, (void *) &refs_for_removal);
11861169
string_list_append(&refs_for_removal, xstrdup("BISECT_HEAD"));
1170+
string_list_append(&refs_for_removal, xstrdup("BISECT_EXPECTED_REV"));
11871171
result = delete_refs("bisect: remove", &refs_for_removal, REF_NO_DEREF);
11881172
refs_for_removal.strdup_strings = 1;
11891173
string_list_clear(&refs_for_removal, 0);
1190-
unlink_or_warn(git_path_bisect_expected_rev());
11911174
unlink_or_warn(git_path_bisect_ancestors_ok());
11921175
unlink_or_warn(git_path_bisect_log());
11931176
unlink_or_warn(git_path_bisect_names());

builtin/bisect.c

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
#include "revision.h"
1717

1818
static GIT_PATH_FUNC(git_path_bisect_terms, "BISECT_TERMS")
19-
static GIT_PATH_FUNC(git_path_bisect_expected_rev, "BISECT_EXPECTED_REV")
2019
static GIT_PATH_FUNC(git_path_bisect_ancestors_ok, "BISECT_ANCESTORS_OK")
2120
static GIT_PATH_FUNC(git_path_bisect_start, "BISECT_START")
2221
static GIT_PATH_FUNC(git_path_bisect_log, "BISECT_LOG")
@@ -919,7 +918,6 @@ static enum bisect_error bisect_state(struct bisect_terms *terms, int argc,
919918
const char *state;
920919
int i, verify_expected = 1;
921920
struct object_id oid, expected;
922-
struct strbuf buf = STRBUF_INIT;
923921
struct oid_array revs = OID_ARRAY_INIT;
924922

925923
if (!argc)
@@ -974,10 +972,8 @@ static enum bisect_error bisect_state(struct bisect_terms *terms, int argc,
974972
oid_array_append(&revs, &commit->object.oid);
975973
}
976974

977-
if (strbuf_read_file(&buf, git_path_bisect_expected_rev(), 0) < the_hash_algo->hexsz ||
978-
get_oid_hex(buf.buf, &expected) < 0)
975+
if (read_ref("BISECT_EXPECTED_REV", &expected))
979976
verify_expected = 0; /* Ignore invalid file contents */
980-
strbuf_release(&buf);
981977

982978
for (i = 0; i < revs.nr; i++) {
983979
if (bisect_write(state, oid_to_hex(&revs.oid[i]), terms, 0)) {
@@ -986,7 +982,7 @@ static enum bisect_error bisect_state(struct bisect_terms *terms, int argc,
986982
}
987983
if (verify_expected && !oideq(&revs.oid[i], &expected)) {
988984
unlink_or_warn(git_path_bisect_ancestors_ok());
989-
unlink_or_warn(git_path_bisect_expected_rev());
985+
delete_ref(NULL, "BISECT_EXPECTED_REV", NULL, REF_NO_DEREF);
990986
verify_expected = 0;
991987
}
992988
}

refs.c

Lines changed: 56 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1851,8 +1851,10 @@ static int refs_read_special_head(struct ref_store *ref_store,
18511851
int result = -1;
18521852
strbuf_addf(&full_path, "%s/%s", ref_store->gitdir, refname);
18531853

1854-
if (strbuf_read_file(&content, full_path.buf, 0) < 0)
1854+
if (strbuf_read_file(&content, full_path.buf, 0) < 0) {
1855+
*failure_errno = errno;
18551856
goto done;
1857+
}
18561858

18571859
result = parse_loose_ref_contents(content.buf, oid, referent, type,
18581860
failure_errno);
@@ -1863,15 +1865,66 @@ static int refs_read_special_head(struct ref_store *ref_store,
18631865
return result;
18641866
}
18651867

1868+
static int is_special_ref(const char *refname)
1869+
{
1870+
/*
1871+
* Special references get written and read directly via the filesystem
1872+
* by the subsystems that create them. Thus, they must not go through
1873+
* the reference backend but must instead be read directly. It is
1874+
* arguable whether this behaviour is sensible, or whether it's simply
1875+
* a leaky abstraction enabled by us only having a single reference
1876+
* backend implementation. But at least for a subset of references it
1877+
* indeed does make sense to treat them specially:
1878+
*
1879+
* - FETCH_HEAD may contain multiple object IDs, and each one of them
1880+
* carries additional metadata like where it came from.
1881+
*
1882+
* - MERGE_HEAD may contain multiple object IDs when merging multiple
1883+
* heads.
1884+
*
1885+
* There are some exceptions that you might expect to see on this list
1886+
* but which are handled exclusively via the reference backend:
1887+
*
1888+
* - BISECT_EXPECTED_REV
1889+
*
1890+
* - CHERRY_PICK_HEAD
1891+
*
1892+
* - HEAD
1893+
*
1894+
* - ORIG_HEAD
1895+
*
1896+
* - "rebase-apply/" and "rebase-merge/" contain all of the state for
1897+
* rebases, including some reference-like files. These are
1898+
* exclusively read and written via the filesystem and never go
1899+
* through the refdb.
1900+
*
1901+
* Writing or deleting references must consistently go either through
1902+
* the filesystem (special refs) or through the reference backend
1903+
* (normal ones).
1904+
*/
1905+
static const char * const special_refs[] = {
1906+
"AUTO_MERGE",
1907+
"FETCH_HEAD",
1908+
"MERGE_AUTOSTASH",
1909+
"MERGE_HEAD",
1910+
};
1911+
size_t i;
1912+
1913+
for (i = 0; i < ARRAY_SIZE(special_refs); i++)
1914+
if (!strcmp(refname, special_refs[i]))
1915+
return 1;
1916+
1917+
return 0;
1918+
}
1919+
18661920
int refs_read_raw_ref(struct ref_store *ref_store, const char *refname,
18671921
struct object_id *oid, struct strbuf *referent,
18681922
unsigned int *type, int *failure_errno)
18691923
{
18701924
assert(failure_errno);
1871-
if (!strcmp(refname, "FETCH_HEAD") || !strcmp(refname, "MERGE_HEAD")) {
1925+
if (is_special_ref(refname))
18721926
return refs_read_special_head(ref_store, refname, oid, referent,
18731927
type, failure_errno);
1874-
}
18751928

18761929
return ref_store->be->read_raw_ref(ref_store, refname, oid, referent,
18771930
type, failure_errno);

t/t1403-show-ref.sh

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -268,4 +268,14 @@ test_expect_success '--exists with directory fails with generic error' '
268268
test_cmp expect err
269269
'
270270

271+
test_expect_success '--exists with non-existent special ref' '
272+
test_expect_code 2 git show-ref --exists FETCH_HEAD
273+
'
274+
275+
test_expect_success '--exists with existing special ref' '
276+
test_when_finished "rm .git/FETCH_HEAD" &&
277+
git rev-parse HEAD >.git/FETCH_HEAD &&
278+
git show-ref --exists FETCH_HEAD
279+
'
280+
271281
test_done

t/t6030-bisect-porcelain.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1182,7 +1182,7 @@ test_expect_success 'git bisect reset cleans bisection state properly' '
11821182
git bisect bad $HASH4 &&
11831183
git bisect reset &&
11841184
test -z "$(git for-each-ref "refs/bisect/*")" &&
1185-
test_path_is_missing ".git/BISECT_EXPECTED_REV" &&
1185+
test_ref_missing BISECT_EXPECTED_REV &&
11861186
test_path_is_missing ".git/BISECT_ANCESTORS_OK" &&
11871187
test_path_is_missing ".git/BISECT_LOG" &&
11881188
test_path_is_missing ".git/BISECT_RUN" &&

wt-status.c

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1296,26 +1296,32 @@ static char *read_line_from_git_path(const char *filename)
12961296
static int split_commit_in_progress(struct wt_status *s)
12971297
{
12981298
int split_in_progress = 0;
1299-
char *head, *orig_head, *rebase_amend, *rebase_orig_head;
1299+
struct object_id head_oid, orig_head_oid;
1300+
char *rebase_amend, *rebase_orig_head;
1301+
int head_flags, orig_head_flags;
13001302

13011303
if ((!s->amend && !s->nowarn && !s->workdir_dirty) ||
13021304
!s->branch || strcmp(s->branch, "HEAD"))
13031305
return 0;
13041306

1305-
head = read_line_from_git_path("HEAD");
1306-
orig_head = read_line_from_git_path("ORIG_HEAD");
1307+
if (read_ref_full("HEAD", RESOLVE_REF_READING | RESOLVE_REF_NO_RECURSE,
1308+
&head_oid, &head_flags) ||
1309+
read_ref_full("ORIG_HEAD", RESOLVE_REF_READING | RESOLVE_REF_NO_RECURSE,
1310+
&orig_head_oid, &orig_head_flags))
1311+
return 0;
1312+
if (head_flags & REF_ISSYMREF || orig_head_flags & REF_ISSYMREF)
1313+
return 0;
1314+
13071315
rebase_amend = read_line_from_git_path("rebase-merge/amend");
13081316
rebase_orig_head = read_line_from_git_path("rebase-merge/orig-head");
13091317

1310-
if (!head || !orig_head || !rebase_amend || !rebase_orig_head)
1318+
if (!rebase_amend || !rebase_orig_head)
13111319
; /* fall through, no split in progress */
13121320
else if (!strcmp(rebase_amend, rebase_orig_head))
1313-
split_in_progress = !!strcmp(head, rebase_amend);
1314-
else if (strcmp(orig_head, rebase_orig_head))
1321+
split_in_progress = !!strcmp(oid_to_hex(&head_oid), rebase_amend);
1322+
else if (strcmp(oid_to_hex(&orig_head_oid), rebase_orig_head))
13151323
split_in_progress = 1;
13161324

1317-
free(head);
1318-
free(orig_head);
13191325
free(rebase_amend);
13201326
free(rebase_orig_head);
13211327

0 commit comments

Comments
 (0)