110
strbuf_rtrim(&worktree_path);
111
strbuf_strip_suffix(&worktree_path, "/.git");
112
113
+ if (!is_absolute_path(worktree_path.buf)) {
114
+ strbuf_strip_suffix(&path, "gitdir");
115
+ strbuf_addbuf(&path, &worktree_path);
116
+ strbuf_realpath_forgiving(&worktree_path, path.buf, 0);
117
+ }
118
+
119
CALLOC_ARRAY(worktree, 1);
120
worktree->repo = the_repository;
121
worktree->path = strbuf_detach(&worktree_path, NULL);
379
void update_worktree_location(struct worktree *wt, const char *path_)
380
{
381
struct strbuf path = STRBUF_INIT;
382
+ struct strbuf repo = STRBUF_INIT;
383
+ struct strbuf file = STRBUF_INIT;
384
+ struct strbuf tmp = STRBUF_INIT;
385
386
if (is_main_worktree(wt))
387
BUG("can't relocate main worktree");
388
389
+ strbuf_realpath(&repo, git_common_path("worktrees/%s", wt->id), 1);
390
strbuf_realpath(&path, path_, 1);
391
if (fspathcmp(wt->path, path.buf)) {
382
- write_file(git_common_path("worktrees/%s/gitdir", wt->id),
383
- "%s/.git", path.buf);
392
+ strbuf_addf(&file, "%s/gitdir", repo.buf);
393
+ write_file(file.buf, "%s/.git", relative_path(path.buf, repo.buf, &tmp));
394
+ strbuf_reset(&file);
395
+ strbuf_addf(&file, "%s/.git", path.buf);
396
+ write_file(file.buf, "gitdir: %s", relative_path(repo.buf, path.buf, &tmp));
397
+
398
free(wt->path);
399
wt->path = strbuf_detach(&path, NULL);
400
}
401
strbuf_release(&path);
402
+ strbuf_release(&repo);
403
+ strbuf_release(&file);
404
+ strbuf_release(&tmp);
405
}
406
407
int is_worktree_being_rebased(const struct worktree *wt,
581
{
582
struct strbuf dotgit = STRBUF_INIT;
583
struct strbuf repo = STRBUF_INIT;
567
- char *backlink;
584
+ struct strbuf backlink = STRBUF_INIT;
585
+ struct strbuf tmp = STRBUF_INIT;
586
+ char *dotgit_contents = NULL;
587
const char *repair = NULL;
588
int err;
589
590
/* missing worktree can't be repaired */
591
if (!file_exists(wt->path))
573
- return;
592
+ goto done;
593
594
if (!is_directory(wt->path)) {
595
fn(1, wt->path, _("not a directory"), cb_data);
577
- return;
596
+ goto done;
597
}
598
599
strbuf_realpath(&repo, git_common_path("worktrees/%s", wt->id), 1);
600
strbuf_addf(&dotgit, "%s/.git", wt->path);
582
- backlink = xstrdup_or_null(read_gitfile_gently(dotgit.buf, &err));
601
+ dotgit_contents = xstrdup_or_null(read_gitfile_gently(dotgit.buf, &err));
602
+
603
+ if (dotgit_contents) {
604
+ if (is_absolute_path(dotgit_contents)) {
605
+ strbuf_addstr(&backlink, dotgit_contents);
606
+ } else {
607
+ strbuf_addf(&backlink, "%s/%s", wt->path, dotgit_contents);
608
+ strbuf_realpath_forgiving(&backlink, backlink.buf, 0);
609
+ }
610
+ }
611
612
if (err == READ_GITFILE_ERR_NOT_A_FILE)
613
fn(1, wt->path, _(".git is not a file"), cb_data);
614
else if (err)
615
repair = _(".git file broken");
588
- else if (fspathcmp(backlink, repo.buf))
616
+ else if (fspathcmp(backlink.buf, repo.buf))
617
repair = _(".git file incorrect");
618
619
if (repair) {
620
fn(0, wt->path, repair, cb_data);
593
- write_file(dotgit.buf, "gitdir: %s", repo.buf);
621
+ write_file(dotgit.buf, "gitdir: %s", relative_path(repo.buf, wt->path, &tmp));
622
}
623
596
- free(backlink);
624
+done:
625
+ free(dotgit_contents);
626
strbuf_release(&repo);
627
strbuf_release(&dotgit);
628
+ strbuf_release(&backlink);
629
+ strbuf_release(&tmp);
630
}
631
632
static void repair_noop(int iserr UNUSED,
649
free_worktrees(worktrees);
650
}
651
652
+void repair_worktree_after_gitdir_move(struct worktree *wt, const char *old_path)
653
+{
654
+ struct strbuf path = STRBUF_INIT;
655
+ struct strbuf repo = STRBUF_INIT;
656
+ struct strbuf gitdir = STRBUF_INIT;
657
+ struct strbuf dotgit = STRBUF_INIT;
658
+ struct strbuf olddotgit = STRBUF_INIT;
659
+ struct strbuf tmp = STRBUF_INIT;
660
+
661
+ if (is_main_worktree(wt))
662
+ goto done;
663
+
664
+ strbuf_realpath(&repo, git_common_path("worktrees/%s", wt->id), 1);
665
+ strbuf_addf(&gitdir, "%s/gitdir", repo.buf);
666
+
667
+ if (strbuf_read_file(&olddotgit, gitdir.buf, 0) < 0)
668
+ goto done;
669
+
670
+ strbuf_rtrim(&olddotgit);
671
+ if (is_absolute_path(olddotgit.buf)) {
672
+ strbuf_addbuf(&dotgit, &olddotgit);
673
+ } else {
674
+ strbuf_addf(&dotgit, "%s/worktrees/%s/%s", old_path, wt->id, olddotgit.buf);
675
+ strbuf_realpath_forgiving(&dotgit, dotgit.buf, 0);
676
+ }
677
+
678
+ if (!file_exists(dotgit.buf))
679
+ goto done;
680
+
681
+ strbuf_addbuf(&path, &dotgit);
682
+ strbuf_strip_suffix(&path, "/.git");
683
+
684
+ write_file(dotgit.buf, "gitdir: %s", relative_path(repo.buf, path.buf, &tmp));
685
+ write_file(gitdir.buf, "%s", relative_path(dotgit.buf, repo.buf, &tmp));
686
+done:
687
+ strbuf_release(&path);
688
+ strbuf_release(&repo);
689
+ strbuf_release(&gitdir);
690
+ strbuf_release(&dotgit);
691
+ strbuf_release(&olddotgit);
692
+ strbuf_release(&tmp);
693
+}
694
+
695
+void repair_worktrees_after_gitdir_move(const char *old_path)
696
+{
697
+ struct worktree **worktrees = get_worktrees_internal(1);
698
+ struct worktree **wt = worktrees + 1; /* +1 skips main worktree */
699
+
700
+ for (; *wt; wt++)
701
+ repair_worktree_after_gitdir_move(*wt, old_path);
702
+ free_worktrees(worktrees);
703
+}
704
+
705
static int is_main_worktree_path(const char *path)
706
{
707
struct strbuf target = STRBUF_INIT;
768
struct strbuf inferred_backlink = STRBUF_INIT;
769
struct strbuf gitdir = STRBUF_INIT;
770
struct strbuf olddotgit = STRBUF_INIT;
771
+ struct strbuf realolddotgit = STRBUF_INIT;
772
+ struct strbuf tmp = STRBUF_INIT;
773
char *dotgit_contents = NULL;
774
const char *repair = NULL;
775
int err;
787
}
788
789
infer_backlink(realdotgit.buf, &inferred_backlink);
790
+ strbuf_realpath_forgiving(&inferred_backlink, inferred_backlink.buf, 0);
791
dotgit_contents = xstrdup_or_null(read_gitfile_gently(realdotgit.buf, &err));
792
if (dotgit_contents) {
706
- strbuf_addstr(&backlink, dotgit_contents);
793
+ if (is_absolute_path(dotgit_contents)) {
794
+ strbuf_addstr(&backlink, dotgit_contents);
795
+ } else {
796
+ strbuf_addbuf(&backlink, &realdotgit);
797
+ strbuf_strip_suffix(&backlink, ".git");
798
+ strbuf_addstr(&backlink, dotgit_contents);
799
+ strbuf_realpath_forgiving(&backlink, backlink.buf, 0);
800
+ }
801
} else if (err == READ_GITFILE_ERR_NOT_A_FILE) {
802
fn(1, realdotgit.buf, _("unable to locate repository; .git is not a file"), cb_data);
803
goto done;
815
fn(1, realdotgit.buf, _("unable to locate repository; .git file does not reference a repository"), cb_data);
816
goto done;
817
}
724
- } else if (err) {
818
+ } else {
819
fn(1, realdotgit.buf, _("unable to locate repository; .git file broken"), cb_data);
820
goto done;
821
}
847
repair = _("gitdir unreadable");
848
else {
849
strbuf_rtrim(&olddotgit);
756
- if (fspathcmp(olddotgit.buf, realdotgit.buf))
850
+ if (is_absolute_path(olddotgit.buf)) {
851
+ strbuf_addbuf(&realolddotgit, &olddotgit);
852
+ } else {
853
+ strbuf_addf(&realolddotgit, "%s/%s", backlink.buf, olddotgit.buf);
854
+ strbuf_realpath_forgiving(&realolddotgit, realolddotgit.buf, 0);
855
+ }
856
+ if (fspathcmp(realolddotgit.buf, realdotgit.buf))
857
repair = _("gitdir incorrect");
858
}
859
860
if (repair) {
861
fn(0, gitdir.buf, repair, cb_data);
762
- write_file(gitdir.buf, "%s", realdotgit.buf);
862
+ write_file(gitdir.buf, "%s", relative_path(realdotgit.buf, backlink.buf, &tmp));
863
}
864
done:
865
free(dotgit_contents);
866
strbuf_release(&olddotgit);
867
+ strbuf_release(&realolddotgit);
868
strbuf_release(&backlink);
869
strbuf_release(&inferred_backlink);
870
strbuf_release(&gitdir);
871
strbuf_release(&realdotgit);
872
strbuf_release(&dotgit);
873
+ strbuf_release(&tmp);
874
}
875
876
int should_prune_worktree(const char *id, struct strbuf *reason, char **wtpath, timestamp_t expire)
877
{
878
struct stat st;
777
- char *path;
879
+ struct strbuf dotgit = STRBUF_INIT;
880
+ struct strbuf gitdir = STRBUF_INIT;
881
+ struct strbuf repo = STRBUF_INIT;
882
+ struct strbuf file = STRBUF_INIT;
883
+ char *path = NULL;
884
+ int rc = 0;
885
int fd;
886
size_t len;
887
ssize_t read_result;
888
889
*wtpath = NULL;
783
- if (!is_directory(git_path("worktrees/%s", id))) {
890
+ strbuf_realpath(&repo, git_common_path("worktrees/%s", id), 1);
891
+ strbuf_addf(&gitdir, "%s/gitdir", repo.buf);
892
+ if (!is_directory(repo.buf)) {
893
strbuf_addstr(reason, _("not a valid directory"));
785
- return 1;
894
+ rc = 1;
895
+ goto done;
896
}
787
- if (file_exists(git_path("worktrees/%s/locked", id)))
788
- return 0;
789
- if (stat(git_path("worktrees/%s/gitdir", id), &st)) {
897
+ strbuf_addf(&file, "%s/locked", repo.buf);
898
+ if (file_exists(file.buf)) {
899
+ goto done;
900
+ }
901
+ if (stat(gitdir.buf, &st)) {
902
strbuf_addstr(reason, _("gitdir file does not exist"));
791
- return 1;
903
+ rc = 1;
904
+ goto done;
905
}
793
- fd = open(git_path("worktrees/%s/gitdir", id), O_RDONLY);
906
+ fd = open(gitdir.buf, O_RDONLY);
907
if (fd < 0) {
908
strbuf_addf(reason, _("unable to read gitdir file (%s)"),
909
strerror(errno));
797
- return 1;
910
+ rc = 1;
911
+ goto done;
912
}
913
len = xsize_t(st.st_size);
914
path = xmallocz(len);
915
916
read_result = read_in_full(fd, path, len);
917
+ close(fd);
918
if (read_result < 0) {
919
strbuf_addf(reason, _("unable to read gitdir file (%s)"),
920
strerror(errno));
806
- close(fd);
807
- free(path);
808
- return 1;
809
- }
810
- close(fd);
811
-
812
- if (read_result != len) {
921
+ rc = 1;
922
+ goto done;
923
+ } else if (read_result != len) {
924
strbuf_addf(reason,
925
_("short read (expected %"PRIuMAX" bytes, read %"PRIuMAX")"),
926
(uintmax_t)len, (uintmax_t)read_result);
816
- free(path);
817
- return 1;
927
+ rc = 1;
928
+ goto done;
929
}
930
while (len && (path[len - 1] == '\n' || path[len - 1] == '\r'))
931
len--;
932
if (!len) {
933
strbuf_addstr(reason, _("invalid gitdir file"));
823
- free(path);
824
- return 1;
934
+ rc = 1;
935
+ goto done;
936
}
937
path[len] = '\0';
827
- if (!file_exists(path)) {
828
- if (stat(git_path("worktrees/%s/index", id), &st) ||
829
- st.st_mtime <= expire) {
938
+ if (is_absolute_path(path)) {
939
+ strbuf_addstr(&dotgit, path);
940
+ } else {
941
+ strbuf_addf(&dotgit, "%s/%s", repo.buf, path);
942
+ strbuf_realpath_forgiving(&dotgit, dotgit.buf, 0);
943
+ }
944
+ if (!file_exists(dotgit.buf)) {
945
+ strbuf_reset(&file);
946
+ strbuf_addf(&file, "%s/index", repo.buf);
947
+ if (stat(file.buf, &st) || st.st_mtime <= expire) {
948
strbuf_addstr(reason, _("gitdir file points to non-existent location"));
831
- free(path);
832
- return 1;
833
- } else {
834
- *wtpath = path;
835
- return 0;
949
+ rc = 1;
950
+ goto done;
951
}
952
}
838
- *wtpath = path;
839
- return 0;
953
+ *wtpath = strbuf_detach(&dotgit, NULL);
954
+done:
955
+ free(path);
956
+ strbuf_release(&dotgit);
957
+ strbuf_release(&gitdir);
958
+ strbuf_release(&repo);
959
+ strbuf_release(&file);
960
+ return rc;
961
}
962
963
static int move_config_setting(const char *key, const char *value,