path: move `enter_repo()` into "setup.c"
The function `enter_repo()` is used to enter a repository at a given path. As such it sits way closer to setting up a repository than it does with handling paths, but regardless of that it's located in "path.c" instead of in "setup.c". Move the function into "setup.c". Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Patrick Steinhardt committed
Nov 19, 2025 at 08:50 UTC
831e02340b9de46c9ea0a1bbce3894f390f5a45e
8 files changed
+123
-118
builtin/receive-pack.c
+1
-1
@@ -34,7 +34,6 @@
34
#include "object-file.h"
35
#include "object-name.h"
36
#include "odb.h"
37
-#include "path.h"
37
#include "protocol.h"
38
#include "commit-reach.h"
39
#include "server-info.h"
@@ -42,6 +41,7 @@
41
#include "trace2.h"
42
#include "worktree.h"
43
#include "shallow.h"
44
+#include "setup.h"
45
#include "parse-options.h"
46
47
static const char * const receive_pack_usage[] = {
builtin/upload-archive.c
+1
-1
@@ -4,8 +4,8 @@
4
#define USE_THE_REPOSITORY_VARIABLE
5
#include "builtin.h"
6
#include "archive.h"
7
-#include "path.h"
7
#include "pkt-line.h"
8
+#include "setup.h"
9
#include "sideband.h"
10
#include "run-command.h"
11
#include "strvec.h"
builtin/upload-pack.c
+1
-1
@@ -5,11 +5,11 @@
5
#include "gettext.h"
6
#include "pkt-line.h"
7
#include "parse-options.h"
8
-#include "path.h"
8
#include "protocol.h"
9
#include "replace-object.h"
10
#include "upload-pack.h"
11
#include "serve.h"
12
+#include "setup.h"
13
#include "commit.h"
14
#include "environment.h"
15
http-backend.c
+1
@@ -16,6 +16,7 @@
16
#include "run-command.h"
17
#include "string-list.h"
18
#include "url.h"
19
+#include "setup.h"
20
#include "strvec.h"
21
#include "packfile.h"
22
#include "odb.h"
path.c
-100
@@ -738,106 +738,6 @@ return_null:
738
return NULL;
739
}
740
741
-/*
742
- * First, one directory to try is determined by the following algorithm.
743
- *
744
- * (0) If "strict" is given, the path is used as given and no DWIM is
745
- * done. Otherwise:
746
- * (1) "~/path" to mean path under the running user's home directory;
747
- * (2) "~user/path" to mean path under named user's home directory;
748
- * (3) "relative/path" to mean cwd relative directory; or
749
- * (4) "/absolute/path" to mean absolute directory.
750
- *
751
- * Unless "strict" is given, we check "%s/.git", "%s", "%s.git/.git", "%s.git"
752
- * in this order. We select the first one that is a valid git repository, and
753
- * chdir() to it. If none match, or we fail to chdir, we return NULL.
754
- *
755
- * If all goes well, we return the directory we used to chdir() (but
756
- * before ~user is expanded), avoiding getcwd() resolving symbolic
757
- * links. User relative paths are also returned as they are given,
758
- * except DWIM suffixing.
759
- */
760
-const char *enter_repo(const char *path, unsigned flags)
761
-{
762
- static struct strbuf validated_path = STRBUF_INIT;
763
- static struct strbuf used_path = STRBUF_INIT;
764
-
765
- if (!path)
766
- return NULL;
767
-
768
- if (!(flags & ENTER_REPO_STRICT)) {
769
- static const char *suffix[] = {
770
- "/.git", "", ".git/.git", ".git", NULL,
771
- };
772
- const char *gitfile;
773
- int len = strlen(path);
774
- int i;
775
- while ((1 < len) && (path[len-1] == '/'))
776
- len--;
777
-
778
- /*
779
- * We can handle arbitrary-sized buffers, but this remains as a
780
- * sanity check on untrusted input.
781
- */
782
- if (PATH_MAX <= len)
783
- return NULL;
784
-
785
- strbuf_reset(&used_path);
786
- strbuf_reset(&validated_path);
787
- strbuf_add(&used_path, path, len);
788
- strbuf_add(&validated_path, path, len);
789
-
790
- if (used_path.buf[0] == '~') {
791
- char *newpath = interpolate_path(used_path.buf, 0);
792
- if (!newpath)
793
- return NULL;
794
- strbuf_attach(&used_path, newpath, strlen(newpath),
795
- strlen(newpath));
796
- }
797
- for (i = 0; suffix[i]; i++) {
798
- struct stat st;
799
- size_t baselen = used_path.len;
800
- strbuf_addstr(&used_path, suffix[i]);
801
- if (!stat(used_path.buf, &st) &&
802
- (S_ISREG(st.st_mode) ||
803
- (S_ISDIR(st.st_mode) && is_git_directory(used_path.buf)))) {
804
- strbuf_addstr(&validated_path, suffix[i]);
805
- break;
806
- }
807
- strbuf_setlen(&used_path, baselen);
808
- }
809
- if (!suffix[i])
810
- return NULL;
811
- gitfile = read_gitfile(used_path.buf);
812
- if (!(flags & ENTER_REPO_ANY_OWNER_OK))
813
- die_upon_dubious_ownership(gitfile, NULL, used_path.buf);
814
- if (gitfile) {
815
- strbuf_reset(&used_path);
816
- strbuf_addstr(&used_path, gitfile);
817
- }
818
- if (chdir(used_path.buf))
819
- return NULL;
820
- path = validated_path.buf;
821
- }
822
- else {
823
- const char *gitfile = read_gitfile(path);
824
- if (!(flags & ENTER_REPO_ANY_OWNER_OK))
825
- die_upon_dubious_ownership(gitfile, NULL, path);
826
- if (gitfile)
827
- path = gitfile;
828
- if (chdir(path))
829
- return NULL;
830
- }
831
-
832
- if (is_git_directory(".")) {
833
- set_git_dir(".", 0);
834
- check_repository_format(NULL);
835
- return path;
836
- }
837
-
838
- return NULL;
839
-}
840
-
741
int calc_shared_perm(struct repository *repo,
742
int mode)
743
{
path.h
-15
@@ -146,21 +146,6 @@ int adjust_shared_perm(struct repository *repo, const char *path);
146
147
char *interpolate_path(const char *path, int real_home);
148
149
-/* The bits are as follows:
150
- *
151
- * - ENTER_REPO_STRICT: callers that require exact paths (as opposed
152
- * to allowing known suffixes like ".git", ".git/.git" to be
153
- * omitted) can set this bit.
154
- *
155
- * - ENTER_REPO_ANY_OWNER_OK: callers that are willing to run without
156
- * ownership check can set this bit.
157
- */
158
-enum {
159
- ENTER_REPO_STRICT = (1<<0),
160
- ENTER_REPO_ANY_OWNER_OK = (1<<1),
161
-};
162
-
163
-const char *enter_repo(const char *path, unsigned flags);
149
const char *remove_leading_path(const char *in, const char *prefix);
150
const char *relative_path(const char *in, const char *prefix, struct strbuf *sb);
151
int normalize_path_copy_len(char *dst, const char *src, int *prefix_len);
setup.c
+81
@@ -1703,6 +1703,87 @@ void set_git_dir(const char *path, int make_realpath)
1703
strbuf_release(&realpath);
1704
}
1705
1706
+const char *enter_repo(const char *path, unsigned flags)
1707
+{
1708
+ static struct strbuf validated_path = STRBUF_INIT;
1709
+ static struct strbuf used_path = STRBUF_INIT;
1710
+
1711
+ if (!path)
1712
+ return NULL;
1713
+
1714
+ if (!(flags & ENTER_REPO_STRICT)) {
1715
+ static const char *suffix[] = {
1716
+ "/.git", "", ".git/.git", ".git", NULL,
1717
+ };
1718
+ const char *gitfile;
1719
+ int len = strlen(path);
1720
+ int i;
1721
+ while ((1 < len) && (path[len-1] == '/'))
1722
+ len--;
1723
+
1724
+ /*
1725
+ * We can handle arbitrary-sized buffers, but this remains as a
1726
+ * sanity check on untrusted input.
1727
+ */
1728
+ if (PATH_MAX <= len)
1729
+ return NULL;
1730
+
1731
+ strbuf_reset(&used_path);
1732
+ strbuf_reset(&validated_path);
1733
+ strbuf_add(&used_path, path, len);
1734
+ strbuf_add(&validated_path, path, len);
1735
+
1736
+ if (used_path.buf[0] == '~') {
1737
+ char *newpath = interpolate_path(used_path.buf, 0);
1738
+ if (!newpath)
1739
+ return NULL;
1740
+ strbuf_attach(&used_path, newpath, strlen(newpath),
1741
+ strlen(newpath));
1742
+ }
1743
+ for (i = 0; suffix[i]; i++) {
1744
+ struct stat st;
1745
+ size_t baselen = used_path.len;
1746
+ strbuf_addstr(&used_path, suffix[i]);
1747
+ if (!stat(used_path.buf, &st) &&
1748
+ (S_ISREG(st.st_mode) ||
1749
+ (S_ISDIR(st.st_mode) && is_git_directory(used_path.buf)))) {
1750
+ strbuf_addstr(&validated_path, suffix[i]);
1751
+ break;
1752
+ }
1753
+ strbuf_setlen(&used_path, baselen);
1754
+ }
1755
+ if (!suffix[i])
1756
+ return NULL;
1757
+ gitfile = read_gitfile(used_path.buf);
1758
+ if (!(flags & ENTER_REPO_ANY_OWNER_OK))
1759
+ die_upon_dubious_ownership(gitfile, NULL, used_path.buf);
1760
+ if (gitfile) {
1761
+ strbuf_reset(&used_path);
1762
+ strbuf_addstr(&used_path, gitfile);
1763
+ }
1764
+ if (chdir(used_path.buf))
1765
+ return NULL;
1766
+ path = validated_path.buf;
1767
+ }
1768
+ else {
1769
+ const char *gitfile = read_gitfile(path);
1770
+ if (!(flags & ENTER_REPO_ANY_OWNER_OK))
1771
+ die_upon_dubious_ownership(gitfile, NULL, path);
1772
+ if (gitfile)
1773
+ path = gitfile;
1774
+ if (chdir(path))
1775
+ return NULL;
1776
+ }
1777
+
1778
+ if (is_git_directory(".")) {
1779
+ set_git_dir(".", 0);
1780
+ check_repository_format(NULL);
1781
+ return path;
1782
+ }
1783
+
1784
+ return NULL;
1785
+}
1786
+
1787
static int git_work_tree_initialized;
1788
1789
/*
setup.h
+38
@@ -97,6 +97,44 @@ static inline int discover_git_directory(struct strbuf *commondir,
97
void set_git_dir(const char *path, int make_realpath);
98
void set_git_work_tree(const char *tree);
99
100
+/* Flags that can be passed to `enter_repo()`. */
101
+enum {
102
+ /*
103
+ * Callers that require exact paths (as opposed to allowing known
104
+ * suffixes like ".git", ".git/.git" to be omitted) can set this bit.
105
+ */
106
+ ENTER_REPO_STRICT = (1<<0),
107
+
108
+ /*
109
+ * Callers that are willing to run without ownership check can set this
110
+ * bit.
111
+ */
112
+ ENTER_REPO_ANY_OWNER_OK = (1<<1),
113
+};
114
+
115
+/*
116
+ * Discover and enter a repository.
117
+ *
118
+ * First, one directory to try is determined by the following algorithm.
119
+ *
120
+ * (0) If "strict" is given, the path is used as given and no DWIM is
121
+ * done. Otherwise:
122
+ * (1) "~/path" to mean path under the running user's home directory;
123
+ * (2) "~user/path" to mean path under named user's home directory;
124
+ * (3) "relative/path" to mean cwd relative directory; or
125
+ * (4) "/absolute/path" to mean absolute directory.
126
+ *
127
+ * Unless "strict" is given, we check "%s/.git", "%s", "%s.git/.git", "%s.git"
128
+ * in this order. We select the first one that is a valid git repository, and
129
+ * chdir() to it. If none match, or we fail to chdir, we return NULL.
130
+ *
131
+ * If all goes well, we return the directory we used to chdir() (but
132
+ * before ~user is expanded), avoiding getcwd() resolving symbolic
133
+ * links. User relative paths are also returned as they are given,
134
+ * except DWIM suffixing.
135
+ */
136
+const char *enter_repo(const char *path, unsigned flags);
137
+
138
const char *setup_git_directory_gently(int *);
139
const char *setup_git_directory(void);
140
char *prefix_path(const char *prefix, int len, const char *path);