Git fork

Merge branch 'sj/ref-consistency-checks-more'

"git fsck" becomes more careful when checking the refs.

* sj/ref-consistency-checks-more:
builtin/fsck: add `git refs verify` child process
packed-backend: check whether the "packed-refs" is sorted
packed-backend: add "packed-refs" entry consistency check
packed-backend: check whether the refname contains NUL characters
packed-backend: add "packed-refs" header consistency check
packed-backend: check if header starts with "# pack-refs with: "
packed-backend: check whether the "packed-refs" is regular file
builtin/refs: get worktrees without reading head information
t0602: use subshell to ensure working directory unchanged

+1131 -452
+14
Documentation/fsck-msgids.adoc
··· 16 16 `badObjectSha1`:: 17 17 (ERROR) An object has a bad sha1. 18 18 19 + `badPackedRefEntry`:: 20 + (ERROR) The "packed-refs" file contains an invalid entry. 21 + 22 + `badPackedRefHeader`:: 23 + (ERROR) The "packed-refs" file contains an invalid 24 + header. 25 + 19 26 `badParentSha1`:: 20 27 (ERROR) A commit object has a bad parent sha1. 21 28 ··· 175 182 176 183 `nullSha1`:: 177 184 (WARN) Tree contains entries pointing to a null sha1. 185 + 186 + `packedRefEntryNotTerminated`:: 187 + (ERROR) The "packed-refs" file contains an entry that is 188 + not terminated by a newline. 189 + 190 + `packedRefUnsorted`:: 191 + (ERROR) The "packed-refs" file is not sorted. 178 192 179 193 `refMissingNewline`:: 180 194 (INFO) A loose ref that does not end with newline(LF). As
+6 -1
Documentation/git-fsck.adoc
··· 12 12 'git fsck' [--tags] [--root] [--unreachable] [--cache] [--no-reflogs] 13 13 [--[no-]full] [--strict] [--verbose] [--lost-found] 14 14 [--[no-]dangling] [--[no-]progress] [--connectivity-only] 15 - [--[no-]name-objects] [<object>...] 15 + [--[no-]name-objects] [--[no-]references] [<object>...] 16 16 17 17 DESCRIPTION 18 18 ----------- ··· 103 103 --no-progress or --verbose is specified. --progress forces 104 104 progress status even if the standard error stream is not 105 105 directed to a terminal. 106 + 107 + --[no-]references:: 108 + Control whether to check the references database consistency 109 + via 'git refs verify'. See linkgit:git-refs[1] for details. 110 + The default is to check the references database. 106 111 107 112 CONFIGURATION 108 113 -------------
+32 -1
builtin/fsck.c
··· 50 50 static int show_progress = -1; 51 51 static int show_dangling = 1; 52 52 static int name_objects; 53 + static int check_references = 1; 53 54 #define ERROR_OBJECT 01 54 55 #define ERROR_REACHABLE 02 55 56 #define ERROR_PACK 04 ··· 905 906 return res; 906 907 } 907 908 909 + static void fsck_refs(struct repository *r) 910 + { 911 + struct child_process refs_verify = CHILD_PROCESS_INIT; 912 + struct progress *progress = NULL; 913 + 914 + if (show_progress) 915 + progress = start_progress(r, _("Checking ref database"), 1); 916 + 917 + if (verbose) 918 + fprintf_ln(stderr, _("Checking ref database")); 919 + 920 + child_process_init(&refs_verify); 921 + refs_verify.git_cmd = 1; 922 + strvec_pushl(&refs_verify.args, "refs", "verify", NULL); 923 + if (verbose) 924 + strvec_push(&refs_verify.args, "--verbose"); 925 + if (check_strict) 926 + strvec_push(&refs_verify.args, "--strict"); 927 + 928 + if (run_command(&refs_verify)) 929 + errors_found |= ERROR_REFS; 930 + 931 + display_progress(progress, 1); 932 + stop_progress(&progress); 933 + } 934 + 908 935 static char const * const fsck_usage[] = { 909 936 N_("git fsck [--tags] [--root] [--unreachable] [--cache] [--no-reflogs]\n" 910 937 " [--[no-]full] [--strict] [--verbose] [--lost-found]\n" 911 938 " [--[no-]dangling] [--[no-]progress] [--connectivity-only]\n" 912 - " [--[no-]name-objects] [<object>...]"), 939 + " [--[no-]name-objects] [--[no-]references] [<object>...]"), 913 940 NULL 914 941 }; 915 942 ··· 928 955 N_("write dangling objects in .git/lost-found")), 929 956 OPT_BOOL(0, "progress", &show_progress, N_("show progress")), 930 957 OPT_BOOL(0, "name-objects", &name_objects, N_("show verbose names for reachable objects")), 958 + OPT_BOOL(0, "references", &check_references, N_("check reference database consistency")), 931 959 OPT_END(), 932 960 }; 933 961 ··· 969 997 970 998 git_config(git_fsck_config, &fsck_obj_options); 971 999 prepare_repo_settings(the_repository); 1000 + 1001 + if (check_references) 1002 + fsck_refs(the_repository); 972 1003 973 1004 if (connectivity_only) { 974 1005 for_each_loose_object(mark_loose_for_connectivity, NULL, 0);
+1 -1
builtin/refs.c
··· 91 91 git_config(git_fsck_config, &fsck_refs_options); 92 92 prepare_repo_settings(the_repository); 93 93 94 - worktrees = get_worktrees(); 94 + worktrees = get_worktrees_without_reading_head(); 95 95 for (size_t i = 0; worktrees[i]; i++) 96 96 ret |= refs_fsck(get_worktree_ref_store(worktrees[i]), 97 97 &fsck_refs_options, worktrees[i]);
+4
fsck.h
··· 30 30 FUNC(BAD_EMAIL, ERROR) \ 31 31 FUNC(BAD_NAME, ERROR) \ 32 32 FUNC(BAD_OBJECT_SHA1, ERROR) \ 33 + FUNC(BAD_PACKED_REF_ENTRY, ERROR) \ 34 + FUNC(BAD_PACKED_REF_HEADER, ERROR) \ 33 35 FUNC(BAD_PARENT_SHA1, ERROR) \ 34 36 FUNC(BAD_REF_CONTENT, ERROR) \ 35 37 FUNC(BAD_REF_FILETYPE, ERROR) \ ··· 53 55 FUNC(MISSING_TYPE, ERROR) \ 54 56 FUNC(MISSING_TYPE_ENTRY, ERROR) \ 55 57 FUNC(MULTIPLE_AUTHORS, ERROR) \ 58 + FUNC(PACKED_REF_ENTRY_NOT_TERMINATED, ERROR) \ 59 + FUNC(PACKED_REF_UNSORTED, ERROR) \ 56 60 FUNC(TREE_NOT_SORTED, ERROR) \ 57 61 FUNC(UNKNOWN_TYPE, ERROR) \ 58 62 FUNC(ZERO_PADDED_DATE, ERROR) \
+351 -12
refs/packed-backend.c
··· 4 4 #include "../git-compat-util.h" 5 5 #include "../config.h" 6 6 #include "../dir.h" 7 + #include "../fsck.h" 7 8 #include "../gettext.h" 8 9 #include "../hash.h" 9 10 #include "../hex.h" ··· 299 300 size_t len; 300 301 }; 301 302 302 - static int cmp_packed_ref_records(const void *v1, const void *v2, 303 - void *cb_data) 303 + 304 + static int cmp_packed_refname(const char *r1, const char *r2) 304 305 { 305 - const struct snapshot *snapshot = cb_data; 306 - const struct snapshot_record *e1 = v1, *e2 = v2; 307 - const char *r1 = e1->start + snapshot_hexsz(snapshot) + 1; 308 - const char *r2 = e2->start + snapshot_hexsz(snapshot) + 1; 309 - 310 306 while (1) { 311 307 if (*r1 == '\n') 312 308 return *r2 == '\n' ? 0 : -1; ··· 319 315 r1++; 320 316 r2++; 321 317 } 318 + } 319 + 320 + static int cmp_packed_ref_records(const void *v1, const void *v2, 321 + void *cb_data) 322 + { 323 + const struct snapshot *snapshot = cb_data; 324 + const struct snapshot_record *e1 = v1, *e2 = v2; 325 + const char *r1 = e1->start + snapshot_hexsz(snapshot) + 1; 326 + const char *r2 = e2->start + snapshot_hexsz(snapshot) + 1; 327 + 328 + return cmp_packed_refname(r1, r2); 322 329 } 323 330 324 331 /* ··· 493 500 last_line, eof - last_line); 494 501 } 495 502 503 + /* 504 + * When parsing the "packed-refs" file, we will parse it line by line. 505 + * Because we know the start pointer of the refname and the next 506 + * newline pointer, we could calculate the length of the refname by 507 + * subtracting the two pointers. However, there is a corner case where 508 + * the refname contains corrupted embedded NUL characters. And 509 + * `check_refname_format()` will not catch this when the truncated 510 + * refname is still a valid refname. To prevent this, we need to check 511 + * whether the refname contains the NUL characters. 512 + */ 513 + static int refname_contains_nul(struct strbuf *refname) 514 + { 515 + return !!memchr(refname->buf, '\0', refname->len); 516 + } 517 + 496 518 #define SMALL_FILE_SIZE (32*1024) 497 519 498 520 /* ··· 693 715 694 716 tmp = xmemdupz(snapshot->buf, eol - snapshot->buf); 695 717 696 - if (!skip_prefix(tmp, "# pack-refs with:", (const char **)&p)) 718 + if (!skip_prefix(tmp, "# pack-refs with: ", (const char **)&p)) 697 719 die_invalid_line(refs->path, 698 720 snapshot->buf, 699 721 snapshot->eof - snapshot->buf); ··· 893 915 894 916 strbuf_add(&iter->refname_buf, p, eol - p); 895 917 iter->base.refname = iter->refname_buf.buf; 918 + 919 + if (refname_contains_nul(&iter->refname_buf)) 920 + die("packed refname contains embedded NULL: %s", iter->base.refname); 896 921 897 922 if (check_refname_format(iter->base.refname, REFNAME_ALLOW_ONELEVEL)) { 898 923 if (!refname_is_safe(iter->base.refname)) ··· 1748 1773 return empty_ref_iterator_begin(); 1749 1774 } 1750 1775 1751 - static int packed_fsck(struct ref_store *ref_store UNUSED, 1752 - struct fsck_options *o UNUSED, 1776 + static int packed_fsck_ref_next_line(struct fsck_options *o, 1777 + unsigned long line_number, const char *start, 1778 + const char *eof, const char **eol) 1779 + { 1780 + int ret = 0; 1781 + 1782 + *eol = memchr(start, '\n', eof - start); 1783 + if (!*eol) { 1784 + struct strbuf packed_entry = STRBUF_INIT; 1785 + struct fsck_ref_report report = { 0 }; 1786 + 1787 + strbuf_addf(&packed_entry, "packed-refs line %lu", line_number); 1788 + report.path = packed_entry.buf; 1789 + ret = fsck_report_ref(o, &report, 1790 + FSCK_MSG_PACKED_REF_ENTRY_NOT_TERMINATED, 1791 + "'%.*s' is not terminated with a newline", 1792 + (int)(eof - start), start); 1793 + 1794 + /* 1795 + * There is no newline but we still want to parse it to the end of 1796 + * the buffer. 1797 + */ 1798 + *eol = eof; 1799 + strbuf_release(&packed_entry); 1800 + } 1801 + 1802 + return ret; 1803 + } 1804 + 1805 + static int packed_fsck_ref_header(struct fsck_options *o, 1806 + const char *start, const char *eol, 1807 + unsigned int *sorted) 1808 + { 1809 + struct string_list traits = STRING_LIST_INIT_NODUP; 1810 + char *tmp_line; 1811 + int ret = 0; 1812 + char *p; 1813 + 1814 + tmp_line = xmemdupz(start, eol - start); 1815 + if (!skip_prefix(tmp_line, "# pack-refs with: ", (const char **)&p)) { 1816 + struct fsck_ref_report report = { 0 }; 1817 + report.path = "packed-refs.header"; 1818 + 1819 + ret = fsck_report_ref(o, &report, 1820 + FSCK_MSG_BAD_PACKED_REF_HEADER, 1821 + "'%.*s' does not start with '# pack-refs with: '", 1822 + (int)(eol - start), start); 1823 + goto cleanup; 1824 + } 1825 + 1826 + string_list_split_in_place(&traits, p, " ", -1); 1827 + *sorted = unsorted_string_list_has_string(&traits, "sorted"); 1828 + 1829 + cleanup: 1830 + free(tmp_line); 1831 + string_list_clear(&traits, 0); 1832 + return ret; 1833 + } 1834 + 1835 + static int packed_fsck_ref_peeled_line(struct fsck_options *o, 1836 + struct ref_store *ref_store, 1837 + unsigned long line_number, 1838 + const char *start, const char *eol) 1839 + { 1840 + struct strbuf packed_entry = STRBUF_INIT; 1841 + struct fsck_ref_report report = { 0 }; 1842 + struct object_id peeled; 1843 + const char *p; 1844 + int ret = 0; 1845 + 1846 + /* 1847 + * Skip the '^' and parse the peeled oid. 1848 + */ 1849 + start++; 1850 + if (parse_oid_hex_algop(start, &peeled, &p, ref_store->repo->hash_algo)) { 1851 + strbuf_addf(&packed_entry, "packed-refs line %lu", line_number); 1852 + report.path = packed_entry.buf; 1853 + 1854 + ret = fsck_report_ref(o, &report, 1855 + FSCK_MSG_BAD_PACKED_REF_ENTRY, 1856 + "'%.*s' has invalid peeled oid", 1857 + (int)(eol - start), start); 1858 + goto cleanup; 1859 + } 1860 + 1861 + if (p != eol) { 1862 + strbuf_addf(&packed_entry, "packed-refs line %lu", line_number); 1863 + report.path = packed_entry.buf; 1864 + 1865 + ret = fsck_report_ref(o, &report, 1866 + FSCK_MSG_BAD_PACKED_REF_ENTRY, 1867 + "has trailing garbage after peeled oid '%.*s'", 1868 + (int)(eol - p), p); 1869 + goto cleanup; 1870 + } 1871 + 1872 + cleanup: 1873 + strbuf_release(&packed_entry); 1874 + return ret; 1875 + } 1876 + 1877 + static int packed_fsck_ref_main_line(struct fsck_options *o, 1878 + struct ref_store *ref_store, 1879 + unsigned long line_number, 1880 + struct strbuf *refname, 1881 + const char *start, const char *eol) 1882 + { 1883 + struct strbuf packed_entry = STRBUF_INIT; 1884 + struct fsck_ref_report report = { 0 }; 1885 + struct object_id oid; 1886 + const char *p; 1887 + int ret = 0; 1888 + 1889 + if (parse_oid_hex_algop(start, &oid, &p, ref_store->repo->hash_algo)) { 1890 + strbuf_addf(&packed_entry, "packed-refs line %lu", line_number); 1891 + report.path = packed_entry.buf; 1892 + 1893 + ret = fsck_report_ref(o, &report, 1894 + FSCK_MSG_BAD_PACKED_REF_ENTRY, 1895 + "'%.*s' has invalid oid", 1896 + (int)(eol - start), start); 1897 + goto cleanup; 1898 + } 1899 + 1900 + if (p == eol || !isspace(*p)) { 1901 + strbuf_addf(&packed_entry, "packed-refs line %lu", line_number); 1902 + report.path = packed_entry.buf; 1903 + 1904 + ret = fsck_report_ref(o, &report, 1905 + FSCK_MSG_BAD_PACKED_REF_ENTRY, 1906 + "has no space after oid '%s' but with '%.*s'", 1907 + oid_to_hex(&oid), (int)(eol - p), p); 1908 + goto cleanup; 1909 + } 1910 + 1911 + p++; 1912 + strbuf_reset(refname); 1913 + strbuf_add(refname, p, eol - p); 1914 + if (refname_contains_nul(refname)) { 1915 + strbuf_addf(&packed_entry, "packed-refs line %lu", line_number); 1916 + report.path = packed_entry.buf; 1917 + 1918 + ret = fsck_report_ref(o, &report, 1919 + FSCK_MSG_BAD_PACKED_REF_ENTRY, 1920 + "refname '%s' contains NULL binaries", 1921 + refname->buf); 1922 + } 1923 + 1924 + if (check_refname_format(refname->buf, 0)) { 1925 + strbuf_addf(&packed_entry, "packed-refs line %lu", line_number); 1926 + report.path = packed_entry.buf; 1927 + 1928 + ret = fsck_report_ref(o, &report, 1929 + FSCK_MSG_BAD_REF_NAME, 1930 + "has bad refname '%s'", refname->buf); 1931 + } 1932 + 1933 + cleanup: 1934 + strbuf_release(&packed_entry); 1935 + return ret; 1936 + } 1937 + 1938 + static int packed_fsck_ref_sorted(struct fsck_options *o, 1939 + struct ref_store *ref_store, 1940 + const char *start, const char *eof) 1941 + { 1942 + size_t hexsz = ref_store->repo->hash_algo->hexsz; 1943 + struct strbuf packed_entry = STRBUF_INIT; 1944 + struct fsck_ref_report report = { 0 }; 1945 + struct strbuf refname1 = STRBUF_INIT; 1946 + struct strbuf refname2 = STRBUF_INIT; 1947 + unsigned long line_number = 1; 1948 + const char *former = NULL; 1949 + const char *current; 1950 + const char *eol; 1951 + int ret = 0; 1952 + 1953 + if (*start == '#') { 1954 + eol = memchr(start, '\n', eof - start); 1955 + start = eol + 1; 1956 + line_number++; 1957 + } 1958 + 1959 + for (; start < eof; line_number++, start = eol + 1) { 1960 + eol = memchr(start, '\n', eof - start); 1961 + 1962 + if (*start == '^') 1963 + continue; 1964 + 1965 + if (!former) { 1966 + former = start + hexsz + 1; 1967 + continue; 1968 + } 1969 + 1970 + current = start + hexsz + 1; 1971 + if (cmp_packed_refname(former, current) >= 0) { 1972 + const char *err_fmt = 1973 + "refname '%s' is less than previous refname '%s'"; 1974 + 1975 + eol = memchr(former, '\n', eof - former); 1976 + strbuf_add(&refname1, former, eol - former); 1977 + eol = memchr(current, '\n', eof - current); 1978 + strbuf_add(&refname2, current, eol - current); 1979 + 1980 + strbuf_addf(&packed_entry, "packed-refs line %lu", line_number); 1981 + report.path = packed_entry.buf; 1982 + ret = fsck_report_ref(o, &report, 1983 + FSCK_MSG_PACKED_REF_UNSORTED, 1984 + err_fmt, refname2.buf, refname1.buf); 1985 + goto cleanup; 1986 + } 1987 + former = current; 1988 + } 1989 + 1990 + cleanup: 1991 + strbuf_release(&packed_entry); 1992 + strbuf_release(&refname1); 1993 + strbuf_release(&refname2); 1994 + return ret; 1995 + } 1996 + 1997 + static int packed_fsck_ref_content(struct fsck_options *o, 1998 + struct ref_store *ref_store, 1999 + unsigned int *sorted, 2000 + const char *start, const char *eof) 2001 + { 2002 + struct strbuf refname = STRBUF_INIT; 2003 + unsigned long line_number = 1; 2004 + const char *eol; 2005 + int ret = 0; 2006 + 2007 + ret |= packed_fsck_ref_next_line(o, line_number, start, eof, &eol); 2008 + if (*start == '#') { 2009 + ret |= packed_fsck_ref_header(o, start, eol, sorted); 2010 + 2011 + start = eol + 1; 2012 + line_number++; 2013 + } 2014 + 2015 + while (start < eof) { 2016 + ret |= packed_fsck_ref_next_line(o, line_number, start, eof, &eol); 2017 + ret |= packed_fsck_ref_main_line(o, ref_store, line_number, &refname, start, eol); 2018 + start = eol + 1; 2019 + line_number++; 2020 + if (start < eof && *start == '^') { 2021 + ret |= packed_fsck_ref_next_line(o, line_number, start, eof, &eol); 2022 + ret |= packed_fsck_ref_peeled_line(o, ref_store, line_number, 2023 + start, eol); 2024 + start = eol + 1; 2025 + line_number++; 2026 + } 2027 + } 2028 + 2029 + strbuf_release(&refname); 2030 + return ret; 2031 + } 2032 + 2033 + static int packed_fsck(struct ref_store *ref_store, 2034 + struct fsck_options *o, 1753 2035 struct worktree *wt) 1754 2036 { 2037 + struct packed_ref_store *refs = packed_downcast(ref_store, 2038 + REF_STORE_READ, "fsck"); 2039 + struct strbuf packed_ref_content = STRBUF_INIT; 2040 + unsigned int sorted = 0; 2041 + struct stat st; 2042 + int ret = 0; 2043 + int fd = -1; 1755 2044 1756 2045 if (!is_main_worktree(wt)) 1757 - return 0; 2046 + goto cleanup; 2047 + 2048 + if (o->verbose) 2049 + fprintf_ln(stderr, "Checking packed-refs file %s", refs->path); 1758 2050 1759 - return 0; 2051 + fd = open_nofollow(refs->path, O_RDONLY); 2052 + if (fd < 0) { 2053 + /* 2054 + * If the packed-refs file doesn't exist, there's nothing 2055 + * to check. 2056 + */ 2057 + if (errno == ENOENT) 2058 + goto cleanup; 2059 + 2060 + if (errno == ELOOP) { 2061 + struct fsck_ref_report report = { 0 }; 2062 + report.path = "packed-refs"; 2063 + ret = fsck_report_ref(o, &report, 2064 + FSCK_MSG_BAD_REF_FILETYPE, 2065 + "not a regular file but a symlink"); 2066 + goto cleanup; 2067 + } 2068 + 2069 + ret = error_errno(_("unable to open '%s'"), refs->path); 2070 + goto cleanup; 2071 + } else if (fstat(fd, &st) < 0) { 2072 + ret = error_errno(_("unable to stat '%s'"), refs->path); 2073 + goto cleanup; 2074 + } else if (!S_ISREG(st.st_mode)) { 2075 + struct fsck_ref_report report = { 0 }; 2076 + report.path = "packed-refs"; 2077 + ret = fsck_report_ref(o, &report, 2078 + FSCK_MSG_BAD_REF_FILETYPE, 2079 + "not a regular file"); 2080 + goto cleanup; 2081 + } 2082 + 2083 + if (strbuf_read(&packed_ref_content, fd, 0) < 0) { 2084 + ret = error_errno(_("unable to read '%s'"), refs->path); 2085 + goto cleanup; 2086 + } 2087 + 2088 + ret = packed_fsck_ref_content(o, ref_store, &sorted, packed_ref_content.buf, 2089 + packed_ref_content.buf + packed_ref_content.len); 2090 + if (!ret && sorted) 2091 + ret = packed_fsck_ref_sorted(o, ref_store, packed_ref_content.buf, 2092 + packed_ref_content.buf + packed_ref_content.len); 2093 + 2094 + cleanup: 2095 + if (fd >= 0) 2096 + close(fd); 2097 + strbuf_release(&packed_ref_content); 2098 + return ret; 1760 2099 } 1761 2100 1762 2101 struct ref_storage_be refs_be_packed = {
+710 -437
t/t0602-reffiles-fsck.sh
··· 14 14 git init repo && 15 15 branch_dir_prefix=.git/refs/heads && 16 16 tag_dir_prefix=.git/refs/tags && 17 - cd repo && 17 + ( 18 + cd repo && 18 19 19 - git commit --allow-empty -m initial && 20 - git checkout -b default-branch && 21 - git tag default-tag && 22 - git tag multi_hierarchy/default-tag && 23 - 24 - cp $branch_dir_prefix/default-branch $branch_dir_prefix/@ && 25 - git refs verify 2>err && 26 - test_must_be_empty err && 27 - rm $branch_dir_prefix/@ && 20 + git commit --allow-empty -m initial && 21 + git checkout -b default-branch && 22 + git tag default-tag && 23 + git tag multi_hierarchy/default-tag && 28 24 29 - cp $tag_dir_prefix/default-tag $tag_dir_prefix/tag-1.lock && 30 - git refs verify 2>err && 31 - rm $tag_dir_prefix/tag-1.lock && 32 - test_must_be_empty err && 25 + cp $branch_dir_prefix/default-branch $branch_dir_prefix/@ && 26 + git refs verify 2>err && 27 + test_must_be_empty err && 28 + rm $branch_dir_prefix/@ && 33 29 34 - cp $tag_dir_prefix/default-tag $tag_dir_prefix/.lock && 35 - test_must_fail git refs verify 2>err && 36 - cat >expect <<-EOF && 37 - error: refs/tags/.lock: badRefName: invalid refname format 38 - EOF 39 - rm $tag_dir_prefix/.lock && 40 - test_cmp expect err && 30 + cp $tag_dir_prefix/default-tag $tag_dir_prefix/tag-1.lock && 31 + git refs verify 2>err && 32 + rm $tag_dir_prefix/tag-1.lock && 33 + test_must_be_empty err && 41 34 42 - for refname in ".refname-starts-with-dot" "~refname-has-stride" 43 - do 44 - cp $branch_dir_prefix/default-branch "$branch_dir_prefix/$refname" && 35 + cp $tag_dir_prefix/default-tag $tag_dir_prefix/.lock && 45 36 test_must_fail git refs verify 2>err && 46 37 cat >expect <<-EOF && 47 - error: refs/heads/$refname: badRefName: invalid refname format 38 + error: refs/tags/.lock: badRefName: invalid refname format 48 39 EOF 49 - rm "$branch_dir_prefix/$refname" && 50 - test_cmp expect err || return 1 51 - done && 40 + rm $tag_dir_prefix/.lock && 41 + test_cmp expect err && 52 42 53 - for refname in ".refname-starts-with-dot" "~refname-has-stride" 54 - do 55 - cp $tag_dir_prefix/default-tag "$tag_dir_prefix/$refname" && 56 - test_must_fail git refs verify 2>err && 57 - cat >expect <<-EOF && 58 - error: refs/tags/$refname: badRefName: invalid refname format 59 - EOF 60 - rm "$tag_dir_prefix/$refname" && 61 - test_cmp expect err || return 1 62 - done && 43 + for refname in ".refname-starts-with-dot" "~refname-has-stride" 44 + do 45 + cp $branch_dir_prefix/default-branch "$branch_dir_prefix/$refname" && 46 + test_must_fail git refs verify 2>err && 47 + cat >expect <<-EOF && 48 + error: refs/heads/$refname: badRefName: invalid refname format 49 + EOF 50 + rm "$branch_dir_prefix/$refname" && 51 + test_cmp expect err || return 1 52 + done && 63 53 64 - for refname in ".refname-starts-with-dot" "~refname-has-stride" 65 - do 66 - cp $tag_dir_prefix/multi_hierarchy/default-tag "$tag_dir_prefix/multi_hierarchy/$refname" && 67 - test_must_fail git refs verify 2>err && 68 - cat >expect <<-EOF && 69 - error: refs/tags/multi_hierarchy/$refname: badRefName: invalid refname format 70 - EOF 71 - rm "$tag_dir_prefix/multi_hierarchy/$refname" && 72 - test_cmp expect err || return 1 73 - done && 54 + for refname in ".refname-starts-with-dot" "~refname-has-stride" 55 + do 56 + cp $tag_dir_prefix/default-tag "$tag_dir_prefix/$refname" && 57 + test_must_fail git refs verify 2>err && 58 + cat >expect <<-EOF && 59 + error: refs/tags/$refname: badRefName: invalid refname format 60 + EOF 61 + rm "$tag_dir_prefix/$refname" && 62 + test_cmp expect err || return 1 63 + done && 74 64 75 - for refname in ".refname-starts-with-dot" "~refname-has-stride" 76 - do 77 - mkdir "$branch_dir_prefix/$refname" && 78 - cp $branch_dir_prefix/default-branch "$branch_dir_prefix/$refname/default-branch" && 79 - test_must_fail git refs verify 2>err && 80 - cat >expect <<-EOF && 81 - error: refs/heads/$refname/default-branch: badRefName: invalid refname format 82 - EOF 83 - rm -r "$branch_dir_prefix/$refname" && 84 - test_cmp expect err || return 1 85 - done 65 + for refname in ".refname-starts-with-dot" "~refname-has-stride" 66 + do 67 + cp $tag_dir_prefix/multi_hierarchy/default-tag "$tag_dir_prefix/multi_hierarchy/$refname" && 68 + test_must_fail git refs verify 2>err && 69 + cat >expect <<-EOF && 70 + error: refs/tags/multi_hierarchy/$refname: badRefName: invalid refname format 71 + EOF 72 + rm "$tag_dir_prefix/multi_hierarchy/$refname" && 73 + test_cmp expect err || return 1 74 + done && 75 + 76 + for refname in ".refname-starts-with-dot" "~refname-has-stride" 77 + do 78 + mkdir "$branch_dir_prefix/$refname" && 79 + cp $branch_dir_prefix/default-branch "$branch_dir_prefix/$refname/default-branch" && 80 + test_must_fail git refs verify 2>err && 81 + cat >expect <<-EOF && 82 + error: refs/heads/$refname/default-branch: badRefName: invalid refname format 83 + EOF 84 + rm -r "$branch_dir_prefix/$refname" && 85 + test_cmp expect err || return 1 86 + done 87 + ) 86 88 ' 87 89 88 90 test_expect_success 'ref name check should be adapted into fsck messages' ' 89 91 test_when_finished "rm -rf repo" && 90 92 git init repo && 91 93 branch_dir_prefix=.git/refs/heads && 92 - cd repo && 93 - git commit --allow-empty -m initial && 94 - git checkout -b branch-1 && 94 + ( 95 + cd repo && 96 + git commit --allow-empty -m initial && 97 + git checkout -b branch-1 && 95 98 96 - cp $branch_dir_prefix/branch-1 $branch_dir_prefix/.branch-1 && 97 - git -c fsck.badRefName=warn refs verify 2>err && 98 - cat >expect <<-EOF && 99 - warning: refs/heads/.branch-1: badRefName: invalid refname format 100 - EOF 101 - rm $branch_dir_prefix/.branch-1 && 102 - test_cmp expect err && 99 + cp $branch_dir_prefix/branch-1 $branch_dir_prefix/.branch-1 && 100 + git -c fsck.badRefName=warn refs verify 2>err && 101 + cat >expect <<-EOF && 102 + warning: refs/heads/.branch-1: badRefName: invalid refname format 103 + EOF 104 + rm $branch_dir_prefix/.branch-1 && 105 + test_cmp expect err && 103 106 104 - cp $branch_dir_prefix/branch-1 $branch_dir_prefix/.branch-1 && 105 - git -c fsck.badRefName=ignore refs verify 2>err && 106 - test_must_be_empty err 107 + cp $branch_dir_prefix/branch-1 $branch_dir_prefix/.branch-1 && 108 + git -c fsck.badRefName=ignore refs verify 2>err && 109 + test_must_be_empty err 110 + ) 107 111 ' 108 112 109 113 test_expect_success 'ref name check should work for multiple worktrees' ' 110 114 test_when_finished "rm -rf repo" && 111 115 git init repo && 116 + ( 117 + cd repo && 118 + test_commit initial && 119 + git checkout -b branch-1 && 120 + test_commit second && 121 + git checkout -b branch-2 && 122 + test_commit third && 123 + git checkout -b branch-3 && 124 + git worktree add ./worktree-1 branch-1 && 125 + git worktree add ./worktree-2 branch-2 && 126 + worktree1_refdir_prefix=.git/worktrees/worktree-1/refs/worktree && 127 + worktree2_refdir_prefix=.git/worktrees/worktree-2/refs/worktree && 112 128 113 - cd repo && 114 - test_commit initial && 115 - git checkout -b branch-1 && 116 - test_commit second && 117 - git checkout -b branch-2 && 118 - test_commit third && 119 - git checkout -b branch-3 && 120 - git worktree add ./worktree-1 branch-1 && 121 - git worktree add ./worktree-2 branch-2 && 122 - worktree1_refdir_prefix=.git/worktrees/worktree-1/refs/worktree && 123 - worktree2_refdir_prefix=.git/worktrees/worktree-2/refs/worktree && 129 + ( 130 + cd worktree-1 && 131 + git update-ref refs/worktree/branch-4 refs/heads/branch-3 132 + ) && 133 + ( 134 + cd worktree-2 && 135 + git update-ref refs/worktree/branch-4 refs/heads/branch-3 136 + ) && 124 137 125 - ( 126 - cd worktree-1 && 127 - git update-ref refs/worktree/branch-4 refs/heads/branch-3 128 - ) && 129 - ( 130 - cd worktree-2 && 131 - git update-ref refs/worktree/branch-4 refs/heads/branch-3 132 - ) && 138 + cp $worktree1_refdir_prefix/branch-4 $worktree1_refdir_prefix/'\'' branch-5'\'' && 139 + cp $worktree2_refdir_prefix/branch-4 $worktree2_refdir_prefix/'\''~branch-6'\'' && 133 140 134 - cp $worktree1_refdir_prefix/branch-4 $worktree1_refdir_prefix/'\'' branch-5'\'' && 135 - cp $worktree2_refdir_prefix/branch-4 $worktree2_refdir_prefix/'\''~branch-6'\'' && 141 + test_must_fail git refs verify 2>err && 142 + cat >expect <<-EOF && 143 + error: worktrees/worktree-1/refs/worktree/ branch-5: badRefName: invalid refname format 144 + error: worktrees/worktree-2/refs/worktree/~branch-6: badRefName: invalid refname format 145 + EOF 146 + sort err >sorted_err && 147 + test_cmp expect sorted_err && 136 148 137 - test_must_fail git refs verify 2>err && 138 - cat >expect <<-EOF && 139 - error: worktrees/worktree-1/refs/worktree/ branch-5: badRefName: invalid refname format 140 - error: worktrees/worktree-2/refs/worktree/~branch-6: badRefName: invalid refname format 141 - EOF 142 - sort err >sorted_err && 143 - test_cmp expect sorted_err && 144 - 145 - for worktree in "worktree-1" "worktree-2" 146 - do 147 - ( 148 - cd $worktree && 149 - test_must_fail git refs verify 2>err && 150 - cat >expect <<-EOF && 151 - error: worktrees/worktree-1/refs/worktree/ branch-5: badRefName: invalid refname format 152 - error: worktrees/worktree-2/refs/worktree/~branch-6: badRefName: invalid refname format 153 - EOF 154 - sort err >sorted_err && 155 - test_cmp expect sorted_err || return 1 156 - ) 157 - done 149 + for worktree in "worktree-1" "worktree-2" 150 + do 151 + ( 152 + cd $worktree && 153 + test_must_fail git refs verify 2>err && 154 + cat >expect <<-EOF && 155 + error: worktrees/worktree-1/refs/worktree/ branch-5: badRefName: invalid refname format 156 + error: worktrees/worktree-2/refs/worktree/~branch-6: badRefName: invalid refname format 157 + EOF 158 + sort err >sorted_err && 159 + test_cmp expect sorted_err || return 1 160 + ) 161 + done 162 + ) 158 163 ' 159 164 160 165 test_expect_success 'regular ref content should be checked (individual)' ' 161 166 test_when_finished "rm -rf repo" && 162 167 git init repo && 163 168 branch_dir_prefix=.git/refs/heads && 164 - cd repo && 165 - test_commit default && 166 - mkdir -p "$branch_dir_prefix/a/b" && 169 + ( 170 + cd repo && 171 + test_commit default && 172 + mkdir -p "$branch_dir_prefix/a/b" && 173 + 174 + git refs verify 2>err && 175 + test_must_be_empty err && 167 176 168 - git refs verify 2>err && 169 - test_must_be_empty err && 177 + for bad_content in "$(git rev-parse main)x" "xfsazqfxcadas" "Xfsazqfxcadas" 178 + do 179 + printf "%s" $bad_content >$branch_dir_prefix/branch-bad && 180 + test_must_fail git refs verify 2>err && 181 + cat >expect <<-EOF && 182 + error: refs/heads/branch-bad: badRefContent: $bad_content 183 + EOF 184 + rm $branch_dir_prefix/branch-bad && 185 + test_cmp expect err || return 1 186 + done && 170 187 171 - for bad_content in "$(git rev-parse main)x" "xfsazqfxcadas" "Xfsazqfxcadas" 172 - do 173 - printf "%s" $bad_content >$branch_dir_prefix/branch-bad && 174 - test_must_fail git refs verify 2>err && 175 - cat >expect <<-EOF && 176 - error: refs/heads/branch-bad: badRefContent: $bad_content 177 - EOF 178 - rm $branch_dir_prefix/branch-bad && 179 - test_cmp expect err || return 1 180 - done && 188 + for bad_content in "$(git rev-parse main)x" "xfsazqfxcadas" "Xfsazqfxcadas" 189 + do 190 + printf "%s" $bad_content >$branch_dir_prefix/a/b/branch-bad && 191 + test_must_fail git refs verify 2>err && 192 + cat >expect <<-EOF && 193 + error: refs/heads/a/b/branch-bad: badRefContent: $bad_content 194 + EOF 195 + rm $branch_dir_prefix/a/b/branch-bad && 196 + test_cmp expect err || return 1 197 + done && 181 198 182 - for bad_content in "$(git rev-parse main)x" "xfsazqfxcadas" "Xfsazqfxcadas" 183 - do 184 - printf "%s" $bad_content >$branch_dir_prefix/a/b/branch-bad && 185 - test_must_fail git refs verify 2>err && 199 + printf "%s" "$(git rev-parse main)" >$branch_dir_prefix/branch-no-newline && 200 + git refs verify 2>err && 186 201 cat >expect <<-EOF && 187 - error: refs/heads/a/b/branch-bad: badRefContent: $bad_content 202 + warning: refs/heads/branch-no-newline: refMissingNewline: misses LF at the end 188 203 EOF 189 - rm $branch_dir_prefix/a/b/branch-bad && 190 - test_cmp expect err || return 1 191 - done && 204 + rm $branch_dir_prefix/branch-no-newline && 205 + test_cmp expect err && 192 206 193 - printf "%s" "$(git rev-parse main)" >$branch_dir_prefix/branch-no-newline && 194 - git refs verify 2>err && 195 - cat >expect <<-EOF && 196 - warning: refs/heads/branch-no-newline: refMissingNewline: misses LF at the end 197 - EOF 198 - rm $branch_dir_prefix/branch-no-newline && 199 - test_cmp expect err && 207 + for trailing_content in " garbage" " more garbage" 208 + do 209 + printf "%s" "$(git rev-parse main)$trailing_content" >$branch_dir_prefix/branch-garbage && 210 + git refs verify 2>err && 211 + cat >expect <<-EOF && 212 + warning: refs/heads/branch-garbage: trailingRefContent: has trailing garbage: '\''$trailing_content'\'' 213 + EOF 214 + rm $branch_dir_prefix/branch-garbage && 215 + test_cmp expect err || return 1 216 + done && 200 217 201 - for trailing_content in " garbage" " more garbage" 202 - do 203 - printf "%s" "$(git rev-parse main)$trailing_content" >$branch_dir_prefix/branch-garbage && 218 + printf "%s\n\n\n" "$(git rev-parse main)" >$branch_dir_prefix/branch-garbage-special && 204 219 git refs verify 2>err && 205 220 cat >expect <<-EOF && 206 - warning: refs/heads/branch-garbage: trailingRefContent: has trailing garbage: '\''$trailing_content'\'' 207 - EOF 208 - rm $branch_dir_prefix/branch-garbage && 209 - test_cmp expect err || return 1 210 - done && 221 + warning: refs/heads/branch-garbage-special: trailingRefContent: has trailing garbage: '\'' 211 222 212 - printf "%s\n\n\n" "$(git rev-parse main)" >$branch_dir_prefix/branch-garbage-special && 213 - git refs verify 2>err && 214 - cat >expect <<-EOF && 215 - warning: refs/heads/branch-garbage-special: trailingRefContent: has trailing garbage: '\'' 216 223 217 - 218 - '\'' 219 - EOF 220 - rm $branch_dir_prefix/branch-garbage-special && 221 - test_cmp expect err && 224 + '\'' 225 + EOF 226 + rm $branch_dir_prefix/branch-garbage-special && 227 + test_cmp expect err && 222 228 223 - printf "%s\n\n\n garbage" "$(git rev-parse main)" >$branch_dir_prefix/branch-garbage-special && 224 - git refs verify 2>err && 225 - cat >expect <<-EOF && 226 - warning: refs/heads/branch-garbage-special: trailingRefContent: has trailing garbage: '\'' 229 + printf "%s\n\n\n garbage" "$(git rev-parse main)" >$branch_dir_prefix/branch-garbage-special && 230 + git refs verify 2>err && 231 + cat >expect <<-EOF && 232 + warning: refs/heads/branch-garbage-special: trailingRefContent: has trailing garbage: '\'' 227 233 228 234 229 - garbage'\'' 230 - EOF 231 - rm $branch_dir_prefix/branch-garbage-special && 232 - test_cmp expect err 235 + garbage'\'' 236 + EOF 237 + rm $branch_dir_prefix/branch-garbage-special && 238 + test_cmp expect err 239 + ) 233 240 ' 234 241 235 242 test_expect_success 'regular ref content should be checked (aggregate)' ' ··· 237 244 git init repo && 238 245 branch_dir_prefix=.git/refs/heads && 239 246 tag_dir_prefix=.git/refs/tags && 240 - cd repo && 241 - test_commit default && 242 - mkdir -p "$branch_dir_prefix/a/b" && 247 + ( 248 + cd repo && 249 + test_commit default && 250 + mkdir -p "$branch_dir_prefix/a/b" && 243 251 244 - bad_content_1=$(git rev-parse main)x && 245 - bad_content_2=xfsazqfxcadas && 246 - bad_content_3=Xfsazqfxcadas && 247 - printf "%s" $bad_content_1 >$tag_dir_prefix/tag-bad-1 && 248 - printf "%s" $bad_content_2 >$tag_dir_prefix/tag-bad-2 && 249 - printf "%s" $bad_content_3 >$branch_dir_prefix/a/b/branch-bad && 250 - printf "%s" "$(git rev-parse main)" >$branch_dir_prefix/branch-no-newline && 251 - printf "%s garbage" "$(git rev-parse main)" >$branch_dir_prefix/branch-garbage && 252 + bad_content_1=$(git rev-parse main)x && 253 + bad_content_2=xfsazqfxcadas && 254 + bad_content_3=Xfsazqfxcadas && 255 + printf "%s" $bad_content_1 >$tag_dir_prefix/tag-bad-1 && 256 + printf "%s" $bad_content_2 >$tag_dir_prefix/tag-bad-2 && 257 + printf "%s" $bad_content_3 >$branch_dir_prefix/a/b/branch-bad && 258 + printf "%s" "$(git rev-parse main)" >$branch_dir_prefix/branch-no-newline && 259 + printf "%s garbage" "$(git rev-parse main)" >$branch_dir_prefix/branch-garbage && 252 260 253 - test_must_fail git refs verify 2>err && 254 - cat >expect <<-EOF && 255 - error: refs/heads/a/b/branch-bad: badRefContent: $bad_content_3 256 - error: refs/tags/tag-bad-1: badRefContent: $bad_content_1 257 - error: refs/tags/tag-bad-2: badRefContent: $bad_content_2 258 - warning: refs/heads/branch-garbage: trailingRefContent: has trailing garbage: '\'' garbage'\'' 259 - warning: refs/heads/branch-no-newline: refMissingNewline: misses LF at the end 260 - EOF 261 - sort err >sorted_err && 262 - test_cmp expect sorted_err 261 + test_must_fail git refs verify 2>err && 262 + cat >expect <<-EOF && 263 + error: refs/heads/a/b/branch-bad: badRefContent: $bad_content_3 264 + error: refs/tags/tag-bad-1: badRefContent: $bad_content_1 265 + error: refs/tags/tag-bad-2: badRefContent: $bad_content_2 266 + warning: refs/heads/branch-garbage: trailingRefContent: has trailing garbage: '\'' garbage'\'' 267 + warning: refs/heads/branch-no-newline: refMissingNewline: misses LF at the end 268 + EOF 269 + sort err >sorted_err && 270 + test_cmp expect sorted_err 271 + ) 263 272 ' 264 273 265 274 test_expect_success 'textual symref content should be checked (individual)' ' 266 275 test_when_finished "rm -rf repo" && 267 276 git init repo && 268 277 branch_dir_prefix=.git/refs/heads && 269 - cd repo && 270 - test_commit default && 271 - mkdir -p "$branch_dir_prefix/a/b" && 278 + ( 279 + cd repo && 280 + test_commit default && 281 + mkdir -p "$branch_dir_prefix/a/b" && 272 282 273 - for good_referent in "refs/heads/branch" "HEAD" 274 - do 275 - printf "ref: %s\n" $good_referent >$branch_dir_prefix/branch-good && 283 + for good_referent in "refs/heads/branch" "HEAD" 284 + do 285 + printf "ref: %s\n" $good_referent >$branch_dir_prefix/branch-good && 286 + git refs verify 2>err && 287 + rm $branch_dir_prefix/branch-good && 288 + test_must_be_empty err || return 1 289 + done && 290 + 291 + for bad_referent in "refs/heads/.branch" "refs/heads/~branch" "refs/heads/?branch" 292 + do 293 + printf "ref: %s\n" $bad_referent >$branch_dir_prefix/branch-bad && 294 + test_must_fail git refs verify 2>err && 295 + cat >expect <<-EOF && 296 + error: refs/heads/branch-bad: badReferentName: points to invalid refname '\''$bad_referent'\'' 297 + EOF 298 + rm $branch_dir_prefix/branch-bad && 299 + test_cmp expect err || return 1 300 + done && 301 + 302 + printf "ref: refs/heads/branch" >$branch_dir_prefix/branch-no-newline && 276 303 git refs verify 2>err && 277 - rm $branch_dir_prefix/branch-good && 278 - test_must_be_empty err || return 1 279 - done && 304 + cat >expect <<-EOF && 305 + warning: refs/heads/branch-no-newline: refMissingNewline: misses LF at the end 306 + EOF 307 + rm $branch_dir_prefix/branch-no-newline && 308 + test_cmp expect err && 280 309 281 - for bad_referent in "refs/heads/.branch" "refs/heads/~branch" "refs/heads/?branch" 282 - do 283 - printf "ref: %s\n" $bad_referent >$branch_dir_prefix/branch-bad && 284 - test_must_fail git refs verify 2>err && 310 + printf "ref: refs/heads/branch " >$branch_dir_prefix/a/b/branch-trailing-1 && 311 + git refs verify 2>err && 285 312 cat >expect <<-EOF && 286 - error: refs/heads/branch-bad: badReferentName: points to invalid refname '\''$bad_referent'\'' 313 + warning: refs/heads/a/b/branch-trailing-1: refMissingNewline: misses LF at the end 314 + warning: refs/heads/a/b/branch-trailing-1: trailingRefContent: has trailing whitespaces or newlines 287 315 EOF 288 - rm $branch_dir_prefix/branch-bad && 289 - test_cmp expect err || return 1 290 - done && 291 - 292 - printf "ref: refs/heads/branch" >$branch_dir_prefix/branch-no-newline && 293 - git refs verify 2>err && 294 - cat >expect <<-EOF && 295 - warning: refs/heads/branch-no-newline: refMissingNewline: misses LF at the end 296 - EOF 297 - rm $branch_dir_prefix/branch-no-newline && 298 - test_cmp expect err && 299 - 300 - printf "ref: refs/heads/branch " >$branch_dir_prefix/a/b/branch-trailing-1 && 301 - git refs verify 2>err && 302 - cat >expect <<-EOF && 303 - warning: refs/heads/a/b/branch-trailing-1: refMissingNewline: misses LF at the end 304 - warning: refs/heads/a/b/branch-trailing-1: trailingRefContent: has trailing whitespaces or newlines 305 - EOF 306 - rm $branch_dir_prefix/a/b/branch-trailing-1 && 307 - test_cmp expect err && 316 + rm $branch_dir_prefix/a/b/branch-trailing-1 && 317 + test_cmp expect err && 308 318 309 - printf "ref: refs/heads/branch\n\n" >$branch_dir_prefix/a/b/branch-trailing-2 && 310 - git refs verify 2>err && 311 - cat >expect <<-EOF && 312 - warning: refs/heads/a/b/branch-trailing-2: trailingRefContent: has trailing whitespaces or newlines 313 - EOF 314 - rm $branch_dir_prefix/a/b/branch-trailing-2 && 315 - test_cmp expect err && 319 + printf "ref: refs/heads/branch\n\n" >$branch_dir_prefix/a/b/branch-trailing-2 && 320 + git refs verify 2>err && 321 + cat >expect <<-EOF && 322 + warning: refs/heads/a/b/branch-trailing-2: trailingRefContent: has trailing whitespaces or newlines 323 + EOF 324 + rm $branch_dir_prefix/a/b/branch-trailing-2 && 325 + test_cmp expect err && 316 326 317 - printf "ref: refs/heads/branch \n" >$branch_dir_prefix/a/b/branch-trailing-3 && 318 - git refs verify 2>err && 319 - cat >expect <<-EOF && 320 - warning: refs/heads/a/b/branch-trailing-3: trailingRefContent: has trailing whitespaces or newlines 321 - EOF 322 - rm $branch_dir_prefix/a/b/branch-trailing-3 && 323 - test_cmp expect err && 327 + printf "ref: refs/heads/branch \n" >$branch_dir_prefix/a/b/branch-trailing-3 && 328 + git refs verify 2>err && 329 + cat >expect <<-EOF && 330 + warning: refs/heads/a/b/branch-trailing-3: trailingRefContent: has trailing whitespaces or newlines 331 + EOF 332 + rm $branch_dir_prefix/a/b/branch-trailing-3 && 333 + test_cmp expect err && 324 334 325 - printf "ref: refs/heads/branch \n " >$branch_dir_prefix/a/b/branch-complicated && 326 - git refs verify 2>err && 327 - cat >expect <<-EOF && 328 - warning: refs/heads/a/b/branch-complicated: refMissingNewline: misses LF at the end 329 - warning: refs/heads/a/b/branch-complicated: trailingRefContent: has trailing whitespaces or newlines 330 - EOF 331 - rm $branch_dir_prefix/a/b/branch-complicated && 332 - test_cmp expect err 335 + printf "ref: refs/heads/branch \n " >$branch_dir_prefix/a/b/branch-complicated && 336 + git refs verify 2>err && 337 + cat >expect <<-EOF && 338 + warning: refs/heads/a/b/branch-complicated: refMissingNewline: misses LF at the end 339 + warning: refs/heads/a/b/branch-complicated: trailingRefContent: has trailing whitespaces or newlines 340 + EOF 341 + rm $branch_dir_prefix/a/b/branch-complicated && 342 + test_cmp expect err 343 + ) 333 344 ' 334 345 335 346 test_expect_success 'textual symref content should be checked (aggregate)' ' ··· 337 348 git init repo && 338 349 branch_dir_prefix=.git/refs/heads && 339 350 tag_dir_prefix=.git/refs/tags && 340 - cd repo && 341 - test_commit default && 342 - mkdir -p "$branch_dir_prefix/a/b" && 351 + ( 352 + cd repo && 353 + test_commit default && 354 + mkdir -p "$branch_dir_prefix/a/b" && 343 355 344 - printf "ref: refs/heads/branch\n" >$branch_dir_prefix/branch-good && 345 - printf "ref: HEAD\n" >$branch_dir_prefix/branch-head && 346 - printf "ref: refs/heads/branch" >$branch_dir_prefix/branch-no-newline-1 && 347 - printf "ref: refs/heads/branch " >$branch_dir_prefix/a/b/branch-trailing-1 && 348 - printf "ref: refs/heads/branch\n\n" >$branch_dir_prefix/a/b/branch-trailing-2 && 349 - printf "ref: refs/heads/branch \n" >$branch_dir_prefix/a/b/branch-trailing-3 && 350 - printf "ref: refs/heads/branch \n " >$branch_dir_prefix/a/b/branch-complicated && 351 - printf "ref: refs/heads/.branch\n" >$branch_dir_prefix/branch-bad-1 && 356 + printf "ref: refs/heads/branch\n" >$branch_dir_prefix/branch-good && 357 + printf "ref: HEAD\n" >$branch_dir_prefix/branch-head && 358 + printf "ref: refs/heads/branch" >$branch_dir_prefix/branch-no-newline-1 && 359 + printf "ref: refs/heads/branch " >$branch_dir_prefix/a/b/branch-trailing-1 && 360 + printf "ref: refs/heads/branch\n\n" >$branch_dir_prefix/a/b/branch-trailing-2 && 361 + printf "ref: refs/heads/branch \n" >$branch_dir_prefix/a/b/branch-trailing-3 && 362 + printf "ref: refs/heads/branch \n " >$branch_dir_prefix/a/b/branch-complicated && 363 + printf "ref: refs/heads/.branch\n" >$branch_dir_prefix/branch-bad-1 && 352 364 353 - test_must_fail git refs verify 2>err && 354 - cat >expect <<-EOF && 355 - error: refs/heads/branch-bad-1: badReferentName: points to invalid refname '\''refs/heads/.branch'\'' 356 - warning: refs/heads/a/b/branch-complicated: refMissingNewline: misses LF at the end 357 - warning: refs/heads/a/b/branch-complicated: trailingRefContent: has trailing whitespaces or newlines 358 - warning: refs/heads/a/b/branch-trailing-1: refMissingNewline: misses LF at the end 359 - warning: refs/heads/a/b/branch-trailing-1: trailingRefContent: has trailing whitespaces or newlines 360 - warning: refs/heads/a/b/branch-trailing-2: trailingRefContent: has trailing whitespaces or newlines 361 - warning: refs/heads/a/b/branch-trailing-3: trailingRefContent: has trailing whitespaces or newlines 362 - warning: refs/heads/branch-no-newline-1: refMissingNewline: misses LF at the end 363 - EOF 364 - sort err >sorted_err && 365 - test_cmp expect sorted_err 365 + test_must_fail git refs verify 2>err && 366 + cat >expect <<-EOF && 367 + error: refs/heads/branch-bad-1: badReferentName: points to invalid refname '\''refs/heads/.branch'\'' 368 + warning: refs/heads/a/b/branch-complicated: refMissingNewline: misses LF at the end 369 + warning: refs/heads/a/b/branch-complicated: trailingRefContent: has trailing whitespaces or newlines 370 + warning: refs/heads/a/b/branch-trailing-1: refMissingNewline: misses LF at the end 371 + warning: refs/heads/a/b/branch-trailing-1: trailingRefContent: has trailing whitespaces or newlines 372 + warning: refs/heads/a/b/branch-trailing-2: trailingRefContent: has trailing whitespaces or newlines 373 + warning: refs/heads/a/b/branch-trailing-3: trailingRefContent: has trailing whitespaces or newlines 374 + warning: refs/heads/branch-no-newline-1: refMissingNewline: misses LF at the end 375 + EOF 376 + sort err >sorted_err && 377 + test_cmp expect sorted_err 378 + ) 366 379 ' 367 380 368 381 test_expect_success 'the target of the textual symref should be checked' ' ··· 370 383 git init repo && 371 384 branch_dir_prefix=.git/refs/heads && 372 385 tag_dir_prefix=.git/refs/tags && 373 - cd repo && 374 - test_commit default && 375 - mkdir -p "$branch_dir_prefix/a/b" && 386 + ( 387 + cd repo && 388 + test_commit default && 389 + mkdir -p "$branch_dir_prefix/a/b" && 376 390 377 - for good_referent in "refs/heads/branch" "HEAD" "refs/tags/tag" 378 - do 379 - printf "ref: %s\n" $good_referent >$branch_dir_prefix/branch-good && 380 - git refs verify 2>err && 381 - rm $branch_dir_prefix/branch-good && 382 - test_must_be_empty err || return 1 383 - done && 391 + for good_referent in "refs/heads/branch" "HEAD" "refs/tags/tag" 392 + do 393 + printf "ref: %s\n" $good_referent >$branch_dir_prefix/branch-good && 394 + git refs verify 2>err && 395 + rm $branch_dir_prefix/branch-good && 396 + test_must_be_empty err || return 1 397 + done && 384 398 385 - for nonref_referent in "refs-back/heads/branch" "refs-back/tags/tag" "reflogs/refs/heads/branch" 386 - do 387 - printf "ref: %s\n" $nonref_referent >$branch_dir_prefix/branch-bad-1 && 388 - git refs verify 2>err && 389 - cat >expect <<-EOF && 390 - warning: refs/heads/branch-bad-1: symrefTargetIsNotARef: points to non-ref target '\''$nonref_referent'\'' 391 - EOF 392 - rm $branch_dir_prefix/branch-bad-1 && 393 - test_cmp expect err || return 1 394 - done 399 + for nonref_referent in "refs-back/heads/branch" "refs-back/tags/tag" "reflogs/refs/heads/branch" 400 + do 401 + printf "ref: %s\n" $nonref_referent >$branch_dir_prefix/branch-bad-1 && 402 + git refs verify 2>err && 403 + cat >expect <<-EOF && 404 + warning: refs/heads/branch-bad-1: symrefTargetIsNotARef: points to non-ref target '\''$nonref_referent'\'' 405 + EOF 406 + rm $branch_dir_prefix/branch-bad-1 && 407 + test_cmp expect err || return 1 408 + done 409 + ) 395 410 ' 396 411 397 412 test_expect_success SYMLINKS 'symlink symref content should be checked' ' ··· 399 414 git init repo && 400 415 branch_dir_prefix=.git/refs/heads && 401 416 tag_dir_prefix=.git/refs/tags && 402 - cd repo && 403 - test_commit default && 404 - mkdir -p "$branch_dir_prefix/a/b" && 417 + ( 418 + cd repo && 419 + test_commit default && 420 + mkdir -p "$branch_dir_prefix/a/b" && 405 421 406 - ln -sf ./main $branch_dir_prefix/branch-symbolic-good && 407 - git refs verify 2>err && 408 - cat >expect <<-EOF && 409 - warning: refs/heads/branch-symbolic-good: symlinkRef: use deprecated symbolic link for symref 410 - EOF 411 - rm $branch_dir_prefix/branch-symbolic-good && 412 - test_cmp expect err && 422 + ln -sf ./main $branch_dir_prefix/branch-symbolic-good && 423 + git refs verify 2>err && 424 + cat >expect <<-EOF && 425 + warning: refs/heads/branch-symbolic-good: symlinkRef: use deprecated symbolic link for symref 426 + EOF 427 + rm $branch_dir_prefix/branch-symbolic-good && 428 + test_cmp expect err && 413 429 414 - ln -sf ../../logs/branch-escape $branch_dir_prefix/branch-symbolic && 415 - git refs verify 2>err && 416 - cat >expect <<-EOF && 417 - warning: refs/heads/branch-symbolic: symlinkRef: use deprecated symbolic link for symref 418 - warning: refs/heads/branch-symbolic: symrefTargetIsNotARef: points to non-ref target '\''logs/branch-escape'\'' 419 - EOF 420 - rm $branch_dir_prefix/branch-symbolic && 421 - test_cmp expect err && 430 + ln -sf ../../logs/branch-escape $branch_dir_prefix/branch-symbolic && 431 + git refs verify 2>err && 432 + cat >expect <<-EOF && 433 + warning: refs/heads/branch-symbolic: symlinkRef: use deprecated symbolic link for symref 434 + warning: refs/heads/branch-symbolic: symrefTargetIsNotARef: points to non-ref target '\''logs/branch-escape'\'' 435 + EOF 436 + rm $branch_dir_prefix/branch-symbolic && 437 + test_cmp expect err && 422 438 423 - ln -sf ./"branch " $branch_dir_prefix/branch-symbolic-bad && 424 - test_must_fail git refs verify 2>err && 425 - cat >expect <<-EOF && 426 - warning: refs/heads/branch-symbolic-bad: symlinkRef: use deprecated symbolic link for symref 427 - error: refs/heads/branch-symbolic-bad: badReferentName: points to invalid refname '\''refs/heads/branch '\'' 428 - EOF 429 - rm $branch_dir_prefix/branch-symbolic-bad && 430 - test_cmp expect err && 439 + ln -sf ./"branch " $branch_dir_prefix/branch-symbolic-bad && 440 + test_must_fail git refs verify 2>err && 441 + cat >expect <<-EOF && 442 + warning: refs/heads/branch-symbolic-bad: symlinkRef: use deprecated symbolic link for symref 443 + error: refs/heads/branch-symbolic-bad: badReferentName: points to invalid refname '\''refs/heads/branch '\'' 444 + EOF 445 + rm $branch_dir_prefix/branch-symbolic-bad && 446 + test_cmp expect err && 431 447 432 - ln -sf ./".tag" $tag_dir_prefix/tag-symbolic-1 && 433 - test_must_fail git refs verify 2>err && 434 - cat >expect <<-EOF && 435 - warning: refs/tags/tag-symbolic-1: symlinkRef: use deprecated symbolic link for symref 436 - error: refs/tags/tag-symbolic-1: badReferentName: points to invalid refname '\''refs/tags/.tag'\'' 437 - EOF 438 - rm $tag_dir_prefix/tag-symbolic-1 && 439 - test_cmp expect err 448 + ln -sf ./".tag" $tag_dir_prefix/tag-symbolic-1 && 449 + test_must_fail git refs verify 2>err && 450 + cat >expect <<-EOF && 451 + warning: refs/tags/tag-symbolic-1: symlinkRef: use deprecated symbolic link for symref 452 + error: refs/tags/tag-symbolic-1: badReferentName: points to invalid refname '\''refs/tags/.tag'\'' 453 + EOF 454 + rm $tag_dir_prefix/tag-symbolic-1 && 455 + test_cmp expect err 456 + ) 440 457 ' 441 458 442 459 test_expect_success SYMLINKS 'symlink symref content should be checked (worktree)' ' 443 460 test_when_finished "rm -rf repo" && 444 461 git init repo && 445 - cd repo && 446 - test_commit default && 447 - git branch branch-1 && 448 - git branch branch-2 && 449 - git branch branch-3 && 450 - git worktree add ./worktree-1 branch-2 && 451 - git worktree add ./worktree-2 branch-3 && 452 - main_worktree_refdir_prefix=.git/refs/heads && 453 - worktree1_refdir_prefix=.git/worktrees/worktree-1/refs/worktree && 454 - worktree2_refdir_prefix=.git/worktrees/worktree-2/refs/worktree && 455 - 456 462 ( 457 - cd worktree-1 && 458 - git update-ref refs/worktree/branch-4 refs/heads/branch-1 459 - ) && 460 - ( 461 - cd worktree-2 && 462 - git update-ref refs/worktree/branch-4 refs/heads/branch-1 463 - ) && 463 + cd repo && 464 + test_commit default && 465 + git branch branch-1 && 466 + git branch branch-2 && 467 + git branch branch-3 && 468 + git worktree add ./worktree-1 branch-2 && 469 + git worktree add ./worktree-2 branch-3 && 470 + main_worktree_refdir_prefix=.git/refs/heads && 471 + worktree1_refdir_prefix=.git/worktrees/worktree-1/refs/worktree && 472 + worktree2_refdir_prefix=.git/worktrees/worktree-2/refs/worktree && 464 473 465 - ln -sf ../../../../refs/heads/good-branch $worktree1_refdir_prefix/branch-symbolic-good && 466 - git refs verify 2>err && 467 - cat >expect <<-EOF && 468 - warning: worktrees/worktree-1/refs/worktree/branch-symbolic-good: symlinkRef: use deprecated symbolic link for symref 469 - EOF 470 - rm $worktree1_refdir_prefix/branch-symbolic-good && 471 - test_cmp expect err && 474 + ( 475 + cd worktree-1 && 476 + git update-ref refs/worktree/branch-4 refs/heads/branch-1 477 + ) && 478 + ( 479 + cd worktree-2 && 480 + git update-ref refs/worktree/branch-4 refs/heads/branch-1 481 + ) && 472 482 473 - ln -sf ../../../../worktrees/worktree-1/good-branch $worktree2_refdir_prefix/branch-symbolic-good && 474 - git refs verify 2>err && 475 - cat >expect <<-EOF && 476 - warning: worktrees/worktree-2/refs/worktree/branch-symbolic-good: symlinkRef: use deprecated symbolic link for symref 477 - EOF 478 - rm $worktree2_refdir_prefix/branch-symbolic-good && 479 - test_cmp expect err && 483 + ln -sf ../../../../refs/heads/good-branch $worktree1_refdir_prefix/branch-symbolic-good && 484 + git refs verify 2>err && 485 + cat >expect <<-EOF && 486 + warning: worktrees/worktree-1/refs/worktree/branch-symbolic-good: symlinkRef: use deprecated symbolic link for symref 487 + EOF 488 + rm $worktree1_refdir_prefix/branch-symbolic-good && 489 + test_cmp expect err && 480 490 481 - ln -sf ../../worktrees/worktree-2/good-branch $main_worktree_refdir_prefix/branch-symbolic-good && 482 - git refs verify 2>err && 483 - cat >expect <<-EOF && 484 - warning: refs/heads/branch-symbolic-good: symlinkRef: use deprecated symbolic link for symref 485 - EOF 486 - rm $main_worktree_refdir_prefix/branch-symbolic-good && 487 - test_cmp expect err && 491 + ln -sf ../../../../worktrees/worktree-1/good-branch $worktree2_refdir_prefix/branch-symbolic-good && 492 + git refs verify 2>err && 493 + cat >expect <<-EOF && 494 + warning: worktrees/worktree-2/refs/worktree/branch-symbolic-good: symlinkRef: use deprecated symbolic link for symref 495 + EOF 496 + rm $worktree2_refdir_prefix/branch-symbolic-good && 497 + test_cmp expect err && 488 498 489 - ln -sf ../../../../logs/branch-escape $worktree1_refdir_prefix/branch-symbolic && 490 - git refs verify 2>err && 491 - cat >expect <<-EOF && 492 - warning: worktrees/worktree-1/refs/worktree/branch-symbolic: symlinkRef: use deprecated symbolic link for symref 493 - warning: worktrees/worktree-1/refs/worktree/branch-symbolic: symrefTargetIsNotARef: points to non-ref target '\''logs/branch-escape'\'' 494 - EOF 495 - rm $worktree1_refdir_prefix/branch-symbolic && 496 - test_cmp expect err && 499 + ln -sf ../../worktrees/worktree-2/good-branch $main_worktree_refdir_prefix/branch-symbolic-good && 500 + git refs verify 2>err && 501 + cat >expect <<-EOF && 502 + warning: refs/heads/branch-symbolic-good: symlinkRef: use deprecated symbolic link for symref 503 + EOF 504 + rm $main_worktree_refdir_prefix/branch-symbolic-good && 505 + test_cmp expect err && 497 506 498 - for bad_referent_name in ".tag" "branch " 499 - do 500 - ln -sf ./"$bad_referent_name" $worktree1_refdir_prefix/bad-symbolic && 501 - test_must_fail git refs verify 2>err && 507 + ln -sf ../../../../logs/branch-escape $worktree1_refdir_prefix/branch-symbolic && 508 + git refs verify 2>err && 502 509 cat >expect <<-EOF && 503 - warning: worktrees/worktree-1/refs/worktree/bad-symbolic: symlinkRef: use deprecated symbolic link for symref 504 - error: worktrees/worktree-1/refs/worktree/bad-symbolic: badReferentName: points to invalid refname '\''worktrees/worktree-1/refs/worktree/$bad_referent_name'\'' 510 + warning: worktrees/worktree-1/refs/worktree/branch-symbolic: symlinkRef: use deprecated symbolic link for symref 511 + warning: worktrees/worktree-1/refs/worktree/branch-symbolic: symrefTargetIsNotARef: points to non-ref target '\''logs/branch-escape'\'' 505 512 EOF 506 - rm $worktree1_refdir_prefix/bad-symbolic && 513 + rm $worktree1_refdir_prefix/branch-symbolic && 507 514 test_cmp expect err && 508 515 509 - ln -sf ../../../../refs/heads/"$bad_referent_name" $worktree1_refdir_prefix/bad-symbolic && 510 - test_must_fail git refs verify 2>err && 516 + for bad_referent_name in ".tag" "branch " 517 + do 518 + ln -sf ./"$bad_referent_name" $worktree1_refdir_prefix/bad-symbolic && 519 + test_must_fail git refs verify 2>err && 520 + cat >expect <<-EOF && 521 + warning: worktrees/worktree-1/refs/worktree/bad-symbolic: symlinkRef: use deprecated symbolic link for symref 522 + error: worktrees/worktree-1/refs/worktree/bad-symbolic: badReferentName: points to invalid refname '\''worktrees/worktree-1/refs/worktree/$bad_referent_name'\'' 523 + EOF 524 + rm $worktree1_refdir_prefix/bad-symbolic && 525 + test_cmp expect err && 526 + 527 + ln -sf ../../../../refs/heads/"$bad_referent_name" $worktree1_refdir_prefix/bad-symbolic && 528 + test_must_fail git refs verify 2>err && 529 + cat >expect <<-EOF && 530 + warning: worktrees/worktree-1/refs/worktree/bad-symbolic: symlinkRef: use deprecated symbolic link for symref 531 + error: worktrees/worktree-1/refs/worktree/bad-symbolic: badReferentName: points to invalid refname '\''refs/heads/$bad_referent_name'\'' 532 + EOF 533 + rm $worktree1_refdir_prefix/bad-symbolic && 534 + test_cmp expect err && 535 + 536 + ln -sf ./"$bad_referent_name" $worktree2_refdir_prefix/bad-symbolic && 537 + test_must_fail git refs verify 2>err && 538 + cat >expect <<-EOF && 539 + warning: worktrees/worktree-2/refs/worktree/bad-symbolic: symlinkRef: use deprecated symbolic link for symref 540 + error: worktrees/worktree-2/refs/worktree/bad-symbolic: badReferentName: points to invalid refname '\''worktrees/worktree-2/refs/worktree/$bad_referent_name'\'' 541 + EOF 542 + rm $worktree2_refdir_prefix/bad-symbolic && 543 + test_cmp expect err && 544 + 545 + ln -sf ../../../../refs/heads/"$bad_referent_name" $worktree2_refdir_prefix/bad-symbolic && 546 + test_must_fail git refs verify 2>err && 547 + cat >expect <<-EOF && 548 + warning: worktrees/worktree-2/refs/worktree/bad-symbolic: symlinkRef: use deprecated symbolic link for symref 549 + error: worktrees/worktree-2/refs/worktree/bad-symbolic: badReferentName: points to invalid refname '\''refs/heads/$bad_referent_name'\'' 550 + EOF 551 + rm $worktree2_refdir_prefix/bad-symbolic && 552 + test_cmp expect err || return 1 553 + done 554 + ) 555 + ' 556 + 557 + test_expect_success 'ref content checks should work with worktrees' ' 558 + test_when_finished "rm -rf repo" && 559 + git init repo && 560 + ( 561 + cd repo && 562 + test_commit default && 563 + git branch branch-1 && 564 + git branch branch-2 && 565 + git branch branch-3 && 566 + git worktree add ./worktree-1 branch-2 && 567 + git worktree add ./worktree-2 branch-3 && 568 + worktree1_refdir_prefix=.git/worktrees/worktree-1/refs/worktree && 569 + worktree2_refdir_prefix=.git/worktrees/worktree-2/refs/worktree && 570 + 571 + ( 572 + cd worktree-1 && 573 + git update-ref refs/worktree/branch-4 refs/heads/branch-1 574 + ) && 575 + ( 576 + cd worktree-2 && 577 + git update-ref refs/worktree/branch-4 refs/heads/branch-1 578 + ) && 579 + 580 + for bad_content in "$(git rev-parse HEAD)x" "xfsazqfxcadas" "Xfsazqfxcadas" 581 + do 582 + printf "%s" $bad_content >$worktree1_refdir_prefix/bad-branch-1 && 583 + test_must_fail git refs verify 2>err && 584 + cat >expect <<-EOF && 585 + error: worktrees/worktree-1/refs/worktree/bad-branch-1: badRefContent: $bad_content 586 + EOF 587 + rm $worktree1_refdir_prefix/bad-branch-1 && 588 + test_cmp expect err || return 1 589 + done && 590 + 591 + for bad_content in "$(git rev-parse HEAD)x" "xfsazqfxcadas" "Xfsazqfxcadas" 592 + do 593 + printf "%s" $bad_content >$worktree2_refdir_prefix/bad-branch-2 && 594 + test_must_fail git refs verify 2>err && 595 + cat >expect <<-EOF && 596 + error: worktrees/worktree-2/refs/worktree/bad-branch-2: badRefContent: $bad_content 597 + EOF 598 + rm $worktree2_refdir_prefix/bad-branch-2 && 599 + test_cmp expect err || return 1 600 + done && 601 + 602 + printf "%s" "$(git rev-parse HEAD)" >$worktree1_refdir_prefix/branch-no-newline && 603 + git refs verify 2>err && 511 604 cat >expect <<-EOF && 512 - warning: worktrees/worktree-1/refs/worktree/bad-symbolic: symlinkRef: use deprecated symbolic link for symref 513 - error: worktrees/worktree-1/refs/worktree/bad-symbolic: badReferentName: points to invalid refname '\''refs/heads/$bad_referent_name'\'' 605 + warning: worktrees/worktree-1/refs/worktree/branch-no-newline: refMissingNewline: misses LF at the end 514 606 EOF 515 - rm $worktree1_refdir_prefix/bad-symbolic && 607 + rm $worktree1_refdir_prefix/branch-no-newline && 516 608 test_cmp expect err && 517 609 518 - ln -sf ./"$bad_referent_name" $worktree2_refdir_prefix/bad-symbolic && 610 + printf "%s garbage" "$(git rev-parse HEAD)" >$worktree1_refdir_prefix/branch-garbage && 611 + git refs verify 2>err && 612 + cat >expect <<-EOF && 613 + warning: worktrees/worktree-1/refs/worktree/branch-garbage: trailingRefContent: has trailing garbage: '\'' garbage'\'' 614 + EOF 615 + rm $worktree1_refdir_prefix/branch-garbage && 616 + test_cmp expect err 617 + ) 618 + ' 619 + 620 + test_expect_success SYMLINKS 'the filetype of packed-refs should be checked' ' 621 + test_when_finished "rm -rf repo" && 622 + git init repo && 623 + ( 624 + cd repo && 625 + test_commit default && 626 + git branch branch-1 && 627 + git branch branch-2 && 628 + git branch branch-3 && 629 + git pack-refs --all && 630 + 631 + mv .git/packed-refs .git/packed-refs-back && 632 + ln -sf packed-refs-back .git/packed-refs && 519 633 test_must_fail git refs verify 2>err && 520 634 cat >expect <<-EOF && 521 - warning: worktrees/worktree-2/refs/worktree/bad-symbolic: symlinkRef: use deprecated symbolic link for symref 522 - error: worktrees/worktree-2/refs/worktree/bad-symbolic: badReferentName: points to invalid refname '\''worktrees/worktree-2/refs/worktree/$bad_referent_name'\'' 635 + error: packed-refs: badRefFiletype: not a regular file but a symlink 523 636 EOF 524 - rm $worktree2_refdir_prefix/bad-symbolic && 637 + rm .git/packed-refs && 525 638 test_cmp expect err && 526 639 527 - ln -sf ../../../../refs/heads/"$bad_referent_name" $worktree2_refdir_prefix/bad-symbolic && 640 + mkdir .git/packed-refs && 528 641 test_must_fail git refs verify 2>err && 529 642 cat >expect <<-EOF && 530 - warning: worktrees/worktree-2/refs/worktree/bad-symbolic: symlinkRef: use deprecated symbolic link for symref 531 - error: worktrees/worktree-2/refs/worktree/bad-symbolic: badReferentName: points to invalid refname '\''refs/heads/$bad_referent_name'\'' 643 + error: packed-refs: badRefFiletype: not a regular file 532 644 EOF 533 - rm $worktree2_refdir_prefix/bad-symbolic && 534 - test_cmp expect err || return 1 535 - done 645 + rm -r .git/packed-refs && 646 + test_cmp expect err 647 + ) 536 648 ' 537 649 538 - test_expect_success 'ref content checks should work with worktrees' ' 650 + test_expect_success 'packed-refs header should be checked' ' 539 651 test_when_finished "rm -rf repo" && 540 652 git init repo && 541 - cd repo && 542 - test_commit default && 543 - git branch branch-1 && 544 - git branch branch-2 && 545 - git branch branch-3 && 546 - git worktree add ./worktree-1 branch-2 && 547 - git worktree add ./worktree-2 branch-3 && 548 - worktree1_refdir_prefix=.git/worktrees/worktree-1/refs/worktree && 549 - worktree2_refdir_prefix=.git/worktrees/worktree-2/refs/worktree && 653 + ( 654 + cd repo && 655 + test_commit default && 656 + 657 + git refs verify 2>err && 658 + test_must_be_empty err && 659 + 660 + for bad_header in "# pack-refs wit: peeled fully-peeled sorted " \ 661 + "# pack-refs with traits: peeled fully-peeled sorted " \ 662 + "# pack-refs with a: peeled fully-peeled" \ 663 + "# pack-refs with:peeled fully-peeled sorted" 664 + do 665 + printf "%s\n" "$bad_header" >.git/packed-refs && 666 + test_must_fail git refs verify 2>err && 667 + cat >expect <<-EOF && 668 + error: packed-refs.header: badPackedRefHeader: '\''$bad_header'\'' does not start with '\''# pack-refs with: '\'' 669 + EOF 670 + rm .git/packed-refs && 671 + test_cmp expect err || return 1 672 + done 673 + ) 674 + ' 675 + 676 + test_expect_success 'packed-refs missing header should not be reported' ' 677 + test_when_finished "rm -rf repo" && 678 + git init repo && 679 + ( 680 + cd repo && 681 + test_commit default && 682 + 683 + printf "$(git rev-parse HEAD) refs/heads/main\n" >.git/packed-refs && 684 + git refs verify 2>err && 685 + test_must_be_empty err 686 + ) 687 + ' 550 688 689 + test_expect_success 'packed-refs unknown traits should not be reported' ' 690 + test_when_finished "rm -rf repo" && 691 + git init repo && 551 692 ( 552 - cd worktree-1 && 553 - git update-ref refs/worktree/branch-4 refs/heads/branch-1 554 - ) && 693 + cd repo && 694 + test_commit default && 695 + 696 + printf "# pack-refs with: peeled fully-peeled sorted foo\n" >.git/packed-refs && 697 + git refs verify 2>err && 698 + test_must_be_empty err 699 + ) 700 + ' 701 + 702 + test_expect_success 'packed-refs content should be checked' ' 703 + test_when_finished "rm -rf repo" && 704 + git init repo && 555 705 ( 556 - cd worktree-2 && 557 - git update-ref refs/worktree/branch-4 refs/heads/branch-1 558 - ) && 706 + cd repo && 707 + test_commit default && 708 + git branch branch-1 && 709 + git branch branch-2 && 710 + git tag -a annotated-tag-1 -m tag-1 && 711 + git tag -a annotated-tag-2 -m tag-2 && 712 + 713 + branch_1_oid=$(git rev-parse branch-1) && 714 + branch_2_oid=$(git rev-parse branch-2) && 715 + tag_1_oid=$(git rev-parse annotated-tag-1) && 716 + tag_2_oid=$(git rev-parse annotated-tag-2) && 717 + tag_1_peeled_oid=$(git rev-parse annotated-tag-1^{}) && 718 + tag_2_peeled_oid=$(git rev-parse annotated-tag-2^{}) && 719 + short_oid=$(printf "%s" $tag_1_peeled_oid | cut -c 1-4) && 559 720 560 - for bad_content in "$(git rev-parse HEAD)x" "xfsazqfxcadas" "Xfsazqfxcadas" 561 - do 562 - printf "%s" $bad_content >$worktree1_refdir_prefix/bad-branch-1 && 721 + cat >.git/packed-refs <<-EOF && 722 + # pack-refs with: peeled fully-peeled sorted 723 + $short_oid refs/heads/branch-1 724 + ${branch_1_oid}x 725 + $branch_2_oid refs/heads/bad-branch 726 + $branch_2_oid refs/heads/branch. 727 + $tag_1_oid refs/tags/annotated-tag-3 728 + ^$short_oid 729 + $tag_2_oid refs/tags/annotated-tag-4. 730 + ^$tag_2_peeled_oid garbage 731 + EOF 563 732 test_must_fail git refs verify 2>err && 564 733 cat >expect <<-EOF && 565 - error: worktrees/worktree-1/refs/worktree/bad-branch-1: badRefContent: $bad_content 734 + error: packed-refs line 2: badPackedRefEntry: '\''$short_oid refs/heads/branch-1'\'' has invalid oid 735 + error: packed-refs line 3: badPackedRefEntry: has no space after oid '\''$branch_1_oid'\'' but with '\''x'\'' 736 + error: packed-refs line 4: badRefName: has bad refname '\'' refs/heads/bad-branch'\'' 737 + error: packed-refs line 5: badRefName: has bad refname '\''refs/heads/branch.'\'' 738 + error: packed-refs line 7: badPackedRefEntry: '\''$short_oid'\'' has invalid peeled oid 739 + error: packed-refs line 8: badRefName: has bad refname '\''refs/tags/annotated-tag-4.'\'' 740 + error: packed-refs line 9: badPackedRefEntry: has trailing garbage after peeled oid '\'' garbage'\'' 566 741 EOF 567 - rm $worktree1_refdir_prefix/bad-branch-1 && 568 - test_cmp expect err || return 1 569 - done && 742 + test_cmp expect err 743 + ) 744 + ' 570 745 571 - for bad_content in "$(git rev-parse HEAD)x" "xfsazqfxcadas" "Xfsazqfxcadas" 572 - do 573 - printf "%s" $bad_content >$worktree2_refdir_prefix/bad-branch-2 && 746 + test_expect_success 'packed-ref with sorted trait should be checked' ' 747 + test_when_finished "rm -rf repo" && 748 + git init repo && 749 + ( 750 + cd repo && 751 + test_commit default && 752 + git branch branch-1 && 753 + git branch branch-2 && 754 + git tag -a annotated-tag-1 -m tag-1 && 755 + branch_1_oid=$(git rev-parse branch-1) && 756 + branch_2_oid=$(git rev-parse branch-2) && 757 + tag_1_oid=$(git rev-parse annotated-tag-1) && 758 + tag_1_peeled_oid=$(git rev-parse annotated-tag-1^{}) && 759 + refname1="refs/heads/main" && 760 + refname2="refs/heads/foo" && 761 + refname3="refs/tags/foo" && 762 + 763 + cat >.git/packed-refs <<-EOF && 764 + # pack-refs with: peeled fully-peeled sorted 765 + EOF 766 + git refs verify 2>err && 767 + rm .git/packed-refs && 768 + test_must_be_empty err && 769 + 770 + cat >.git/packed-refs <<-EOF && 771 + # pack-refs with: peeled fully-peeled sorted 772 + $branch_2_oid $refname1 773 + EOF 774 + git refs verify 2>err && 775 + rm .git/packed-refs && 776 + test_must_be_empty err && 777 + 778 + cat >.git/packed-refs <<-EOF && 779 + # pack-refs with: peeled fully-peeled sorted 780 + $branch_2_oid $refname1 781 + $branch_1_oid $refname2 782 + $tag_1_oid $refname3 783 + EOF 574 784 test_must_fail git refs verify 2>err && 575 785 cat >expect <<-EOF && 576 - error: worktrees/worktree-2/refs/worktree/bad-branch-2: badRefContent: $bad_content 786 + error: packed-refs line 3: packedRefUnsorted: refname '\''$refname2'\'' is less than previous refname '\''$refname1'\'' 787 + EOF 788 + rm .git/packed-refs && 789 + test_cmp expect err && 790 + 791 + cat >.git/packed-refs <<-EOF && 792 + # pack-refs with: peeled fully-peeled sorted 793 + $tag_1_oid $refname3 794 + ^$tag_1_peeled_oid 795 + $branch_2_oid $refname2 796 + EOF 797 + test_must_fail git refs verify 2>err && 798 + cat >expect <<-EOF && 799 + error: packed-refs line 4: packedRefUnsorted: refname '\''$refname2'\'' is less than previous refname '\''$refname3'\'' 800 + EOF 801 + rm .git/packed-refs && 802 + test_cmp expect err 803 + ) 804 + ' 805 + 806 + test_expect_success 'packed-ref without sorted trait should not be checked' ' 807 + test_when_finished "rm -rf repo" && 808 + git init repo && 809 + ( 810 + cd repo && 811 + test_commit default && 812 + git branch branch-1 && 813 + git branch branch-2 && 814 + git tag -a annotated-tag-1 -m tag-1 && 815 + branch_1_oid=$(git rev-parse branch-1) && 816 + branch_2_oid=$(git rev-parse branch-2) && 817 + tag_1_oid=$(git rev-parse annotated-tag-1) && 818 + tag_1_peeled_oid=$(git rev-parse annotated-tag-1^{}) && 819 + refname1="refs/heads/main" && 820 + refname2="refs/heads/foo" && 821 + refname3="refs/tags/foo" && 822 + 823 + cat >.git/packed-refs <<-EOF && 824 + # pack-refs with: peeled fully-peeled 825 + $branch_2_oid $refname1 826 + $branch_1_oid $refname2 577 827 EOF 578 - rm $worktree2_refdir_prefix/bad-branch-2 && 579 - test_cmp expect err || return 1 580 - done && 828 + git refs verify 2>err && 829 + test_must_be_empty err 830 + ) 831 + ' 832 + 833 + test_expect_success '--[no-]references option should apply to fsck' ' 834 + test_when_finished "rm -rf repo" && 835 + git init repo && 836 + branch_dir_prefix=.git/refs/heads && 837 + ( 838 + cd repo && 839 + test_commit default && 840 + for trailing_content in " garbage" " more garbage" 841 + do 842 + printf "%s" "$(git rev-parse HEAD)$trailing_content" >$branch_dir_prefix/branch-garbage && 843 + git fsck 2>err && 844 + cat >expect <<-EOF && 845 + warning: refs/heads/branch-garbage: trailingRefContent: has trailing garbage: '\''$trailing_content'\'' 846 + EOF 847 + rm $branch_dir_prefix/branch-garbage && 848 + test_cmp expect err || return 1 849 + done && 581 850 582 - printf "%s" "$(git rev-parse HEAD)" >$worktree1_refdir_prefix/branch-no-newline && 583 - git refs verify 2>err && 584 - cat >expect <<-EOF && 585 - warning: worktrees/worktree-1/refs/worktree/branch-no-newline: refMissingNewline: misses LF at the end 586 - EOF 587 - rm $worktree1_refdir_prefix/branch-no-newline && 588 - test_cmp expect err && 851 + for trailing_content in " garbage" " more garbage" 852 + do 853 + printf "%s" "$(git rev-parse HEAD)$trailing_content" >$branch_dir_prefix/branch-garbage && 854 + git fsck --references 2>err && 855 + cat >expect <<-EOF && 856 + warning: refs/heads/branch-garbage: trailingRefContent: has trailing garbage: '\''$trailing_content'\'' 857 + EOF 858 + rm $branch_dir_prefix/branch-garbage && 859 + test_cmp expect err || return 1 860 + done && 589 861 590 - printf "%s garbage" "$(git rev-parse HEAD)" >$worktree1_refdir_prefix/branch-garbage && 591 - git refs verify 2>err && 592 - cat >expect <<-EOF && 593 - warning: worktrees/worktree-1/refs/worktree/branch-garbage: trailingRefContent: has trailing garbage: '\'' garbage'\'' 594 - EOF 595 - rm $worktree1_refdir_prefix/branch-garbage && 596 - test_cmp expect err 862 + for trailing_content in " garbage" " more garbage" 863 + do 864 + printf "%s" "$(git rev-parse HEAD)$trailing_content" >$branch_dir_prefix/branch-garbage && 865 + git fsck --no-references 2>err && 866 + rm $branch_dir_prefix/branch-garbage && 867 + test_must_be_empty err || return 1 868 + done 869 + ) 597 870 ' 598 871 599 872 test_done
+5
worktree.c
··· 199 199 return get_worktrees_internal(0); 200 200 } 201 201 202 + struct worktree **get_worktrees_without_reading_head(void) 203 + { 204 + return get_worktrees_internal(1); 205 + } 206 + 202 207 char *get_worktree_git_dir(const struct worktree *wt) 203 208 { 204 209 if (!wt)
+8
worktree.h
··· 31 31 struct worktree **get_worktrees(void); 32 32 33 33 /* 34 + * Like `get_worktrees`, but does not read HEAD. Skip reading HEAD allows to 35 + * get the worktree without worrying about failures pertaining to parsing 36 + * the HEAD ref. This is useful in contexts where it is assumed that the 37 + * refdb may not be in a consistent state. 38 + */ 39 + struct worktree **get_worktrees_without_reading_head(void); 40 + 41 + /* 34 42 * Returns 1 if linked worktrees exist, 0 otherwise. 35 43 */ 36 44 int submodule_uses_worktrees(const char *path);