worktree.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703
  1. #include "cache.h"
  2. #include "repository.h"
  3. #include "refs.h"
  4. #include "strbuf.h"
  5. #include "worktree.h"
  6. #include "dir.h"
  7. #include "wt-status.h"
  8. void free_worktrees(struct worktree **worktrees)
  9. {
  10. int i = 0;
  11. for (i = 0; worktrees[i]; i++) {
  12. free(worktrees[i]->path);
  13. free(worktrees[i]->id);
  14. free(worktrees[i]->head_ref);
  15. free(worktrees[i]->lock_reason);
  16. free(worktrees[i]);
  17. }
  18. free (worktrees);
  19. }
  20. /**
  21. * Update head_oid, head_ref and is_detached of the given worktree
  22. */
  23. static void add_head_info(struct worktree *wt)
  24. {
  25. int flags;
  26. const char *target;
  27. target = refs_resolve_ref_unsafe(get_worktree_ref_store(wt),
  28. "HEAD",
  29. 0,
  30. &wt->head_oid, &flags);
  31. if (!target)
  32. return;
  33. if (flags & REF_ISSYMREF)
  34. wt->head_ref = xstrdup(target);
  35. else
  36. wt->is_detached = 1;
  37. }
  38. /**
  39. * get the main worktree
  40. */
  41. static struct worktree *get_main_worktree(void)
  42. {
  43. struct worktree *worktree = NULL;
  44. struct strbuf worktree_path = STRBUF_INIT;
  45. strbuf_add_real_path(&worktree_path, get_git_common_dir());
  46. strbuf_strip_suffix(&worktree_path, "/.git");
  47. worktree = xcalloc(1, sizeof(*worktree));
  48. worktree->path = strbuf_detach(&worktree_path, NULL);
  49. /*
  50. * NEEDSWORK: If this function is called from a secondary worktree and
  51. * config.worktree is present, is_bare_repository_cfg will reflect the
  52. * contents of config.worktree, not the contents of the main worktree.
  53. * This means that worktree->is_bare may be set to 0 even if the main
  54. * worktree is configured to be bare.
  55. */
  56. worktree->is_bare = (is_bare_repository_cfg == 1) ||
  57. is_bare_repository();
  58. add_head_info(worktree);
  59. return worktree;
  60. }
  61. static struct worktree *get_linked_worktree(const char *id)
  62. {
  63. struct worktree *worktree = NULL;
  64. struct strbuf path = STRBUF_INIT;
  65. struct strbuf worktree_path = STRBUF_INIT;
  66. if (!id)
  67. die("Missing linked worktree name");
  68. strbuf_git_common_path(&path, the_repository, "worktrees/%s/gitdir", id);
  69. if (strbuf_read_file(&worktree_path, path.buf, 0) <= 0)
  70. /* invalid gitdir file */
  71. goto done;
  72. strbuf_rtrim(&worktree_path);
  73. strbuf_strip_suffix(&worktree_path, "/.git");
  74. worktree = xcalloc(1, sizeof(*worktree));
  75. worktree->path = strbuf_detach(&worktree_path, NULL);
  76. worktree->id = xstrdup(id);
  77. add_head_info(worktree);
  78. done:
  79. strbuf_release(&path);
  80. strbuf_release(&worktree_path);
  81. return worktree;
  82. }
  83. static void mark_current_worktree(struct worktree **worktrees)
  84. {
  85. char *git_dir = absolute_pathdup(get_git_dir());
  86. int i;
  87. for (i = 0; worktrees[i]; i++) {
  88. struct worktree *wt = worktrees[i];
  89. const char *wt_git_dir = get_worktree_git_dir(wt);
  90. if (!fspathcmp(git_dir, absolute_path(wt_git_dir))) {
  91. wt->is_current = 1;
  92. break;
  93. }
  94. }
  95. free(git_dir);
  96. }
  97. struct worktree **get_worktrees(void)
  98. {
  99. struct worktree **list = NULL;
  100. struct strbuf path = STRBUF_INIT;
  101. DIR *dir;
  102. struct dirent *d;
  103. int counter = 0, alloc = 2;
  104. ALLOC_ARRAY(list, alloc);
  105. list[counter++] = get_main_worktree();
  106. strbuf_addf(&path, "%s/worktrees", get_git_common_dir());
  107. dir = opendir(path.buf);
  108. strbuf_release(&path);
  109. if (dir) {
  110. while ((d = readdir(dir)) != NULL) {
  111. struct worktree *linked = NULL;
  112. if (is_dot_or_dotdot(d->d_name))
  113. continue;
  114. if ((linked = get_linked_worktree(d->d_name))) {
  115. ALLOC_GROW(list, counter + 1, alloc);
  116. list[counter++] = linked;
  117. }
  118. }
  119. closedir(dir);
  120. }
  121. ALLOC_GROW(list, counter + 1, alloc);
  122. list[counter] = NULL;
  123. mark_current_worktree(list);
  124. return list;
  125. }
  126. const char *get_worktree_git_dir(const struct worktree *wt)
  127. {
  128. if (!wt)
  129. return get_git_dir();
  130. else if (!wt->id)
  131. return get_git_common_dir();
  132. else
  133. return git_common_path("worktrees/%s", wt->id);
  134. }
  135. static struct worktree *find_worktree_by_suffix(struct worktree **list,
  136. const char *suffix)
  137. {
  138. struct worktree *found = NULL;
  139. int nr_found = 0, suffixlen;
  140. suffixlen = strlen(suffix);
  141. if (!suffixlen)
  142. return NULL;
  143. for (; *list && nr_found < 2; list++) {
  144. const char *path = (*list)->path;
  145. int pathlen = strlen(path);
  146. int start = pathlen - suffixlen;
  147. /* suffix must start at directory boundary */
  148. if ((!start || (start > 0 && is_dir_sep(path[start - 1]))) &&
  149. !fspathcmp(suffix, path + start)) {
  150. found = *list;
  151. nr_found++;
  152. }
  153. }
  154. return nr_found == 1 ? found : NULL;
  155. }
  156. struct worktree *find_worktree(struct worktree **list,
  157. const char *prefix,
  158. const char *arg)
  159. {
  160. struct worktree *wt;
  161. char *to_free = NULL;
  162. if ((wt = find_worktree_by_suffix(list, arg)))
  163. return wt;
  164. if (prefix)
  165. arg = to_free = prefix_filename(prefix, arg);
  166. wt = find_worktree_by_path(list, arg);
  167. free(to_free);
  168. return wt;
  169. }
  170. struct worktree *find_worktree_by_path(struct worktree **list, const char *p)
  171. {
  172. struct strbuf wt_path = STRBUF_INIT;
  173. char *path = real_pathdup(p, 0);
  174. if (!path)
  175. return NULL;
  176. for (; *list; list++) {
  177. if (!strbuf_realpath(&wt_path, (*list)->path, 0))
  178. continue;
  179. if (!fspathcmp(path, wt_path.buf))
  180. break;
  181. }
  182. free(path);
  183. strbuf_release(&wt_path);
  184. return *list;
  185. }
  186. int is_main_worktree(const struct worktree *wt)
  187. {
  188. return !wt->id;
  189. }
  190. const char *worktree_lock_reason(struct worktree *wt)
  191. {
  192. assert(!is_main_worktree(wt));
  193. if (!wt->lock_reason_valid) {
  194. struct strbuf path = STRBUF_INIT;
  195. strbuf_addstr(&path, worktree_git_path(wt, "locked"));
  196. if (file_exists(path.buf)) {
  197. struct strbuf lock_reason = STRBUF_INIT;
  198. if (strbuf_read_file(&lock_reason, path.buf, 0) < 0)
  199. die_errno(_("failed to read '%s'"), path.buf);
  200. strbuf_trim(&lock_reason);
  201. wt->lock_reason = strbuf_detach(&lock_reason, NULL);
  202. } else
  203. wt->lock_reason = NULL;
  204. wt->lock_reason_valid = 1;
  205. strbuf_release(&path);
  206. }
  207. return wt->lock_reason;
  208. }
  209. /* convenient wrapper to deal with NULL strbuf */
  210. static void strbuf_addf_gently(struct strbuf *buf, const char *fmt, ...)
  211. {
  212. va_list params;
  213. if (!buf)
  214. return;
  215. va_start(params, fmt);
  216. strbuf_vaddf(buf, fmt, params);
  217. va_end(params);
  218. }
  219. int validate_worktree(const struct worktree *wt, struct strbuf *errmsg,
  220. unsigned flags)
  221. {
  222. struct strbuf wt_path = STRBUF_INIT;
  223. struct strbuf realpath = STRBUF_INIT;
  224. char *path = NULL;
  225. int err, ret = -1;
  226. strbuf_addf(&wt_path, "%s/.git", wt->path);
  227. if (is_main_worktree(wt)) {
  228. if (is_directory(wt_path.buf)) {
  229. ret = 0;
  230. goto done;
  231. }
  232. /*
  233. * Main worktree using .git file to point to the
  234. * repository would make it impossible to know where
  235. * the actual worktree is if this function is executed
  236. * from another worktree. No .git file support for now.
  237. */
  238. strbuf_addf_gently(errmsg,
  239. _("'%s' at main working tree is not the repository directory"),
  240. wt_path.buf);
  241. goto done;
  242. }
  243. /*
  244. * Make sure "gitdir" file points to a real .git file and that
  245. * file points back here.
  246. */
  247. if (!is_absolute_path(wt->path)) {
  248. strbuf_addf_gently(errmsg,
  249. _("'%s' file does not contain absolute path to the working tree location"),
  250. git_common_path("worktrees/%s/gitdir", wt->id));
  251. goto done;
  252. }
  253. if (flags & WT_VALIDATE_WORKTREE_MISSING_OK &&
  254. !file_exists(wt->path)) {
  255. ret = 0;
  256. goto done;
  257. }
  258. if (!file_exists(wt_path.buf)) {
  259. strbuf_addf_gently(errmsg, _("'%s' does not exist"), wt_path.buf);
  260. goto done;
  261. }
  262. path = xstrdup_or_null(read_gitfile_gently(wt_path.buf, &err));
  263. if (!path) {
  264. strbuf_addf_gently(errmsg, _("'%s' is not a .git file, error code %d"),
  265. wt_path.buf, err);
  266. goto done;
  267. }
  268. strbuf_realpath(&realpath, git_common_path("worktrees/%s", wt->id), 1);
  269. ret = fspathcmp(path, realpath.buf);
  270. if (ret)
  271. strbuf_addf_gently(errmsg, _("'%s' does not point back to '%s'"),
  272. wt->path, git_common_path("worktrees/%s", wt->id));
  273. done:
  274. free(path);
  275. strbuf_release(&wt_path);
  276. strbuf_release(&realpath);
  277. return ret;
  278. }
  279. void update_worktree_location(struct worktree *wt, const char *path_)
  280. {
  281. struct strbuf path = STRBUF_INIT;
  282. if (is_main_worktree(wt))
  283. BUG("can't relocate main worktree");
  284. strbuf_realpath(&path, path_, 1);
  285. if (fspathcmp(wt->path, path.buf)) {
  286. write_file(git_common_path("worktrees/%s/gitdir", wt->id),
  287. "%s/.git", path.buf);
  288. free(wt->path);
  289. wt->path = strbuf_detach(&path, NULL);
  290. }
  291. strbuf_release(&path);
  292. }
  293. int is_worktree_being_rebased(const struct worktree *wt,
  294. const char *target)
  295. {
  296. struct wt_status_state state;
  297. int found_rebase;
  298. memset(&state, 0, sizeof(state));
  299. found_rebase = wt_status_check_rebase(wt, &state) &&
  300. (state.rebase_in_progress ||
  301. state.rebase_interactive_in_progress) &&
  302. state.branch &&
  303. skip_prefix(target, "refs/heads/", &target) &&
  304. !strcmp(state.branch, target);
  305. wt_status_state_free_buffers(&state);
  306. return found_rebase;
  307. }
  308. int is_worktree_being_bisected(const struct worktree *wt,
  309. const char *target)
  310. {
  311. struct wt_status_state state;
  312. int found_bisect;
  313. memset(&state, 0, sizeof(state));
  314. found_bisect = wt_status_check_bisect(wt, &state) &&
  315. state.branch &&
  316. skip_prefix(target, "refs/heads/", &target) &&
  317. !strcmp(state.branch, target);
  318. wt_status_state_free_buffers(&state);
  319. return found_bisect;
  320. }
  321. /*
  322. * note: this function should be able to detect shared symref even if
  323. * HEAD is temporarily detached (e.g. in the middle of rebase or
  324. * bisect). New commands that do similar things should update this
  325. * function as well.
  326. */
  327. const struct worktree *find_shared_symref(const char *symref,
  328. const char *target)
  329. {
  330. const struct worktree *existing = NULL;
  331. static struct worktree **worktrees;
  332. int i = 0;
  333. if (worktrees)
  334. free_worktrees(worktrees);
  335. worktrees = get_worktrees();
  336. for (i = 0; worktrees[i]; i++) {
  337. struct worktree *wt = worktrees[i];
  338. const char *symref_target;
  339. struct ref_store *refs;
  340. int flags;
  341. if (wt->is_bare)
  342. continue;
  343. if (wt->is_detached && !strcmp(symref, "HEAD")) {
  344. if (is_worktree_being_rebased(wt, target)) {
  345. existing = wt;
  346. break;
  347. }
  348. if (is_worktree_being_bisected(wt, target)) {
  349. existing = wt;
  350. break;
  351. }
  352. }
  353. refs = get_worktree_ref_store(wt);
  354. symref_target = refs_resolve_ref_unsafe(refs, symref, 0,
  355. NULL, &flags);
  356. if ((flags & REF_ISSYMREF) &&
  357. symref_target && !strcmp(symref_target, target)) {
  358. existing = wt;
  359. break;
  360. }
  361. }
  362. return existing;
  363. }
  364. int submodule_uses_worktrees(const char *path)
  365. {
  366. char *submodule_gitdir;
  367. struct strbuf sb = STRBUF_INIT, err = STRBUF_INIT;
  368. DIR *dir;
  369. struct dirent *d;
  370. int ret = 0;
  371. struct repository_format format = REPOSITORY_FORMAT_INIT;
  372. submodule_gitdir = git_pathdup_submodule(path, "%s", "");
  373. if (!submodule_gitdir)
  374. return 0;
  375. /* The env would be set for the superproject. */
  376. get_common_dir_noenv(&sb, submodule_gitdir);
  377. free(submodule_gitdir);
  378. strbuf_addstr(&sb, "/config");
  379. read_repository_format(&format, sb.buf);
  380. if (verify_repository_format(&format, &err)) {
  381. strbuf_release(&err);
  382. strbuf_release(&sb);
  383. clear_repository_format(&format);
  384. return 1;
  385. }
  386. clear_repository_format(&format);
  387. strbuf_release(&err);
  388. /* Replace config by worktrees. */
  389. strbuf_setlen(&sb, sb.len - strlen("config"));
  390. strbuf_addstr(&sb, "worktrees");
  391. /* See if there is any file inside the worktrees directory. */
  392. dir = opendir(sb.buf);
  393. strbuf_release(&sb);
  394. if (!dir)
  395. return 0;
  396. while ((d = readdir(dir)) != NULL) {
  397. if (is_dot_or_dotdot(d->d_name))
  398. continue;
  399. ret = 1;
  400. break;
  401. }
  402. closedir(dir);
  403. return ret;
  404. }
  405. int parse_worktree_ref(const char *worktree_ref, const char **name,
  406. int *name_length, const char **ref)
  407. {
  408. if (skip_prefix(worktree_ref, "main-worktree/", &worktree_ref)) {
  409. if (!*worktree_ref)
  410. return -1;
  411. if (name)
  412. *name = NULL;
  413. if (name_length)
  414. *name_length = 0;
  415. if (ref)
  416. *ref = worktree_ref;
  417. return 0;
  418. }
  419. if (skip_prefix(worktree_ref, "worktrees/", &worktree_ref)) {
  420. const char *slash = strchr(worktree_ref, '/');
  421. if (!slash || slash == worktree_ref || !slash[1])
  422. return -1;
  423. if (name)
  424. *name = worktree_ref;
  425. if (name_length)
  426. *name_length = slash - worktree_ref;
  427. if (ref)
  428. *ref = slash + 1;
  429. return 0;
  430. }
  431. return -1;
  432. }
  433. void strbuf_worktree_ref(const struct worktree *wt,
  434. struct strbuf *sb,
  435. const char *refname)
  436. {
  437. switch (ref_type(refname)) {
  438. case REF_TYPE_PSEUDOREF:
  439. case REF_TYPE_PER_WORKTREE:
  440. if (wt && !wt->is_current) {
  441. if (is_main_worktree(wt))
  442. strbuf_addstr(sb, "main-worktree/");
  443. else
  444. strbuf_addf(sb, "worktrees/%s/", wt->id);
  445. }
  446. break;
  447. case REF_TYPE_MAIN_PSEUDOREF:
  448. case REF_TYPE_OTHER_PSEUDOREF:
  449. break;
  450. case REF_TYPE_NORMAL:
  451. /*
  452. * For shared refs, don't prefix worktrees/ or
  453. * main-worktree/. It's not necessary and
  454. * files-backend.c can't handle it anyway.
  455. */
  456. break;
  457. }
  458. strbuf_addstr(sb, refname);
  459. }
  460. int other_head_refs(each_ref_fn fn, void *cb_data)
  461. {
  462. struct worktree **worktrees, **p;
  463. struct strbuf refname = STRBUF_INIT;
  464. int ret = 0;
  465. worktrees = get_worktrees();
  466. for (p = worktrees; *p; p++) {
  467. struct worktree *wt = *p;
  468. struct object_id oid;
  469. int flag;
  470. if (wt->is_current)
  471. continue;
  472. strbuf_reset(&refname);
  473. strbuf_worktree_ref(wt, &refname, "HEAD");
  474. if (!refs_read_ref_full(get_main_ref_store(the_repository),
  475. refname.buf,
  476. RESOLVE_REF_READING,
  477. &oid, &flag))
  478. ret = fn(refname.buf, &oid, flag, cb_data);
  479. if (ret)
  480. break;
  481. }
  482. free_worktrees(worktrees);
  483. strbuf_release(&refname);
  484. return ret;
  485. }
  486. /*
  487. * Repair worktree's /path/to/worktree/.git file if missing, corrupt, or not
  488. * pointing at <repo>/worktrees/<id>.
  489. */
  490. static void repair_gitfile(struct worktree *wt,
  491. worktree_repair_fn fn, void *cb_data)
  492. {
  493. struct strbuf dotgit = STRBUF_INIT;
  494. struct strbuf repo = STRBUF_INIT;
  495. char *backlink;
  496. const char *repair = NULL;
  497. int err;
  498. /* missing worktree can't be repaired */
  499. if (!file_exists(wt->path))
  500. return;
  501. if (!is_directory(wt->path)) {
  502. fn(1, wt->path, _("not a directory"), cb_data);
  503. return;
  504. }
  505. strbuf_realpath(&repo, git_common_path("worktrees/%s", wt->id), 1);
  506. strbuf_addf(&dotgit, "%s/.git", wt->path);
  507. backlink = xstrdup_or_null(read_gitfile_gently(dotgit.buf, &err));
  508. if (err == READ_GITFILE_ERR_NOT_A_FILE)
  509. fn(1, wt->path, _(".git is not a file"), cb_data);
  510. else if (err)
  511. repair = _(".git file broken");
  512. else if (fspathcmp(backlink, repo.buf))
  513. repair = _(".git file incorrect");
  514. if (repair) {
  515. fn(0, wt->path, repair, cb_data);
  516. write_file(dotgit.buf, "gitdir: %s", repo.buf);
  517. }
  518. free(backlink);
  519. strbuf_release(&repo);
  520. strbuf_release(&dotgit);
  521. }
  522. static void repair_noop(int iserr, const char *path, const char *msg,
  523. void *cb_data)
  524. {
  525. /* nothing */
  526. }
  527. void repair_worktrees(worktree_repair_fn fn, void *cb_data)
  528. {
  529. struct worktree **worktrees = get_worktrees();
  530. struct worktree **wt = worktrees + 1; /* +1 skips main worktree */
  531. if (!fn)
  532. fn = repair_noop;
  533. for (; *wt; wt++)
  534. repair_gitfile(*wt, fn, cb_data);
  535. free_worktrees(worktrees);
  536. }
  537. static int is_main_worktree_path(const char *path)
  538. {
  539. struct strbuf target = STRBUF_INIT;
  540. struct strbuf maindir = STRBUF_INIT;
  541. int cmp;
  542. strbuf_add_real_path(&target, path);
  543. strbuf_strip_suffix(&target, "/.git");
  544. strbuf_add_real_path(&maindir, get_git_common_dir());
  545. strbuf_strip_suffix(&maindir, "/.git");
  546. cmp = fspathcmp(maindir.buf, target.buf);
  547. strbuf_release(&maindir);
  548. strbuf_release(&target);
  549. return !cmp;
  550. }
  551. /*
  552. * Repair <repo>/worktrees/<id>/gitdir if missing, corrupt, or not pointing at
  553. * the worktree's path.
  554. */
  555. void repair_worktree_at_path(const char *path,
  556. worktree_repair_fn fn, void *cb_data)
  557. {
  558. struct strbuf dotgit = STRBUF_INIT;
  559. struct strbuf realdotgit = STRBUF_INIT;
  560. struct strbuf gitdir = STRBUF_INIT;
  561. struct strbuf olddotgit = STRBUF_INIT;
  562. char *backlink = NULL;
  563. const char *repair = NULL;
  564. int err;
  565. if (!fn)
  566. fn = repair_noop;
  567. if (is_main_worktree_path(path))
  568. goto done;
  569. strbuf_addf(&dotgit, "%s/.git", path);
  570. if (!strbuf_realpath(&realdotgit, dotgit.buf, 0)) {
  571. fn(1, path, _("not a valid path"), cb_data);
  572. goto done;
  573. }
  574. backlink = xstrdup_or_null(read_gitfile_gently(realdotgit.buf, &err));
  575. if (err == READ_GITFILE_ERR_NOT_A_FILE) {
  576. fn(1, realdotgit.buf, _("unable to locate repository; .git is not a file"), cb_data);
  577. goto done;
  578. } else if (err) {
  579. fn(1, realdotgit.buf, _("unable to locate repository; .git file broken"), cb_data);
  580. goto done;
  581. }
  582. strbuf_addf(&gitdir, "%s/gitdir", backlink);
  583. if (strbuf_read_file(&olddotgit, gitdir.buf, 0) < 0)
  584. repair = _("gitdir unreadable");
  585. else {
  586. strbuf_rtrim(&olddotgit);
  587. if (fspathcmp(olddotgit.buf, realdotgit.buf))
  588. repair = _("gitdir incorrect");
  589. }
  590. if (repair) {
  591. fn(0, gitdir.buf, repair, cb_data);
  592. write_file(gitdir.buf, "%s", realdotgit.buf);
  593. }
  594. done:
  595. free(backlink);
  596. strbuf_release(&olddotgit);
  597. strbuf_release(&gitdir);
  598. strbuf_release(&realdotgit);
  599. strbuf_release(&dotgit);
  600. }