2 * Copyright (c) 2017 Martin Pieuchot <mpi@openbsd.org>
3 * Copyright (c) 2018, 2019, 2020 Stefan Sperling <stsp@openbsd.org>
4 * Copyright (c) 2020 Ori Bernstein <ori@openbsd.org>
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19 #include <sys/queue.h>
21 #include <sys/types.h>
42 #include "got_compat.h"
44 #include "got_version.h"
45 #include "got_error.h"
46 #include "got_object.h"
47 #include "got_reference.h"
48 #include "got_repository.h"
50 #include "got_cancel.h"
51 #include "got_worktree.h"
53 #include "got_commit_graph.h"
54 #include "got_fetch.h"
56 #include "got_blame.h"
57 #include "got_privsep.h"
58 #include "got_opentemp.h"
59 #include "got_gotconfig.h"
61 #include "got_patch.h"
66 #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0]))
69 static volatile sig_atomic_t sigint_received
;
70 static volatile sig_atomic_t sigpipe_received
;
73 catch_sigint(int signo
)
79 catch_sigpipe(int signo
)
87 const struct got_error
*(*cmd_main
)(int, char *[]);
88 void (*cmd_usage
)(void);
89 const char *cmd_alias
;
92 __dead
static void usage(int, int);
93 __dead
static void usage_init(void);
94 __dead
static void usage_import(void);
95 __dead
static void usage_clone(void);
96 __dead
static void usage_fetch(void);
97 __dead
static void usage_checkout(void);
98 __dead
static void usage_update(void);
99 __dead
static void usage_log(void);
100 __dead
static void usage_diff(void);
101 __dead
static void usage_blame(void);
102 __dead
static void usage_tree(void);
103 __dead
static void usage_status(void);
104 __dead
static void usage_ref(void);
105 __dead
static void usage_branch(void);
106 __dead
static void usage_tag(void);
107 __dead
static void usage_add(void);
108 __dead
static void usage_remove(void);
109 __dead
static void usage_patch(void);
110 __dead
static void usage_revert(void);
111 __dead
static void usage_commit(void);
112 __dead
static void usage_send(void);
113 __dead
static void usage_cherrypick(void);
114 __dead
static void usage_backout(void);
115 __dead
static void usage_rebase(void);
116 __dead
static void usage_histedit(void);
117 __dead
static void usage_integrate(void);
118 __dead
static void usage_merge(void);
119 __dead
static void usage_stage(void);
120 __dead
static void usage_unstage(void);
121 __dead
static void usage_cat(void);
122 __dead
static void usage_info(void);
124 static const struct got_error
* cmd_init(int, char *[]);
125 static const struct got_error
* cmd_import(int, char *[]);
126 static const struct got_error
* cmd_clone(int, char *[]);
127 static const struct got_error
* cmd_fetch(int, char *[]);
128 static const struct got_error
* cmd_checkout(int, char *[]);
129 static const struct got_error
* cmd_update(int, char *[]);
130 static const struct got_error
* cmd_log(int, char *[]);
131 static const struct got_error
* cmd_diff(int, char *[]);
132 static const struct got_error
* cmd_blame(int, char *[]);
133 static const struct got_error
* cmd_tree(int, char *[]);
134 static const struct got_error
* cmd_status(int, char *[]);
135 static const struct got_error
* cmd_ref(int, char *[]);
136 static const struct got_error
* cmd_branch(int, char *[]);
137 static const struct got_error
* cmd_tag(int, char *[]);
138 static const struct got_error
* cmd_add(int, char *[]);
139 static const struct got_error
* cmd_remove(int, char *[]);
140 static const struct got_error
* cmd_patch(int, char *[]);
141 static const struct got_error
* cmd_revert(int, char *[]);
142 static const struct got_error
* cmd_commit(int, char *[]);
143 static const struct got_error
* cmd_send(int, char *[]);
144 static const struct got_error
* cmd_cherrypick(int, char *[]);
145 static const struct got_error
* cmd_backout(int, char *[]);
146 static const struct got_error
* cmd_rebase(int, char *[]);
147 static const struct got_error
* cmd_histedit(int, char *[]);
148 static const struct got_error
* cmd_integrate(int, char *[]);
149 static const struct got_error
* cmd_merge(int, char *[]);
150 static const struct got_error
* cmd_stage(int, char *[]);
151 static const struct got_error
* cmd_unstage(int, char *[]);
152 static const struct got_error
* cmd_cat(int, char *[]);
153 static const struct got_error
* cmd_info(int, char *[]);
155 static const struct got_cmd got_commands
[] = {
156 { "init", cmd_init
, usage_init
, "" },
157 { "import", cmd_import
, usage_import
, "im" },
158 { "clone", cmd_clone
, usage_clone
, "cl" },
159 { "fetch", cmd_fetch
, usage_fetch
, "fe" },
160 { "checkout", cmd_checkout
, usage_checkout
, "co" },
161 { "update", cmd_update
, usage_update
, "up" },
162 { "log", cmd_log
, usage_log
, "" },
163 { "diff", cmd_diff
, usage_diff
, "di" },
164 { "blame", cmd_blame
, usage_blame
, "bl" },
165 { "tree", cmd_tree
, usage_tree
, "tr" },
166 { "status", cmd_status
, usage_status
, "st" },
167 { "ref", cmd_ref
, usage_ref
, "" },
168 { "branch", cmd_branch
, usage_branch
, "br" },
169 { "tag", cmd_tag
, usage_tag
, "" },
170 { "add", cmd_add
, usage_add
, "" },
171 { "remove", cmd_remove
, usage_remove
, "rm" },
172 { "patch", cmd_patch
, usage_patch
, "pa" },
173 { "revert", cmd_revert
, usage_revert
, "rv" },
174 { "commit", cmd_commit
, usage_commit
, "ci" },
175 { "send", cmd_send
, usage_send
, "se" },
176 { "cherrypick", cmd_cherrypick
, usage_cherrypick
, "cy" },
177 { "backout", cmd_backout
, usage_backout
, "bo" },
178 { "rebase", cmd_rebase
, usage_rebase
, "rb" },
179 { "histedit", cmd_histedit
, usage_histedit
, "he" },
180 { "integrate", cmd_integrate
, usage_integrate
,"ig" },
181 { "merge", cmd_merge
, usage_merge
, "mg" },
182 { "stage", cmd_stage
, usage_stage
, "sg" },
183 { "unstage", cmd_unstage
, usage_unstage
, "ug" },
184 { "cat", cmd_cat
, usage_cat
, "" },
185 { "info", cmd_info
, usage_info
, "" },
189 list_commands(FILE *fp
)
193 fprintf(fp
, "commands:");
194 for (i
= 0; i
< nitems(got_commands
); i
++) {
195 const struct got_cmd
*cmd
= &got_commands
[i
];
196 fprintf(fp
, " %s", cmd
->cmd_name
);
202 option_conflict(char a
, char b
)
204 errx(1, "-%c and -%c options are mutually exclusive", a
, b
);
208 main(int argc
, char *argv
[])
210 const struct got_cmd
*cmd
;
213 int hflag
= 0, Vflag
= 0;
214 static const struct option longopts
[] = {
215 { "version", no_argument
, NULL
, 'V' },
219 setlocale(LC_CTYPE
, "");
221 while ((ch
= getopt_long(argc
, argv
, "+hV", longopts
, NULL
)) != -1) {
241 got_version_print_str();
246 usage(hflag
, hflag
? 0 : 1);
248 signal(SIGINT
, catch_sigint
);
249 signal(SIGPIPE
, catch_sigpipe
);
251 for (i
= 0; i
< nitems(got_commands
); i
++) {
252 const struct got_error
*error
;
254 cmd
= &got_commands
[i
];
256 if (strcmp(cmd
->cmd_name
, argv
[0]) != 0 &&
257 strcmp(cmd
->cmd_alias
, argv
[0]) != 0)
263 error
= cmd
->cmd_main(argc
, argv
);
264 if (error
&& error
->code
!= GOT_ERR_CANCELLED
&&
265 error
->code
!= GOT_ERR_PRIVSEP_EXIT
&&
266 !(sigpipe_received
&&
267 error
->code
== GOT_ERR_ERRNO
&& errno
== EPIPE
) &&
269 error
->code
== GOT_ERR_ERRNO
&& errno
== EINTR
)) {
270 fprintf(stderr
, "%s: %s\n", getprogname(), error
->msg
);
277 fprintf(stderr
, "%s: unknown command '%s'\n", getprogname(), argv
[0]);
278 list_commands(stderr
);
283 usage(int hflag
, int status
)
285 FILE *fp
= (status
== 0) ? stdout
: stderr
;
287 fprintf(fp
, "usage: %s [-h] [-V | --version] command [arg ...]\n",
294 static const struct got_error
*
295 get_editor(char **abspath
)
297 const struct got_error
*err
= NULL
;
302 editor
= getenv("VISUAL");
304 editor
= getenv("EDITOR");
307 err
= got_path_find_prog(abspath
, editor
);
312 if (*abspath
== NULL
) {
313 *abspath
= strdup("/bin/ed");
314 if (*abspath
== NULL
)
315 return got_error_from_errno("strdup");
321 static const struct got_error
*
322 apply_unveil(const char *repo_path
, int repo_read_only
,
323 const char *worktree_path
)
325 const struct got_error
*err
;
328 if (unveil("gmon.out", "rwc") != 0)
329 return got_error_from_errno2("unveil", "gmon.out");
331 if (repo_path
&& unveil(repo_path
, repo_read_only
? "r" : "rwc") != 0)
332 return got_error_from_errno2("unveil", repo_path
);
334 if (worktree_path
&& unveil(worktree_path
, "rwc") != 0)
335 return got_error_from_errno2("unveil", worktree_path
);
337 if (unveil(GOT_TMPDIR_STR
, "rwc") != 0)
338 return got_error_from_errno2("unveil", GOT_TMPDIR_STR
);
340 err
= got_privsep_unveil_exec_helpers();
344 if (unveil(NULL
, NULL
) != 0)
345 return got_error_from_errno("unveil");
353 fprintf(stderr
, "usage: %s init repository-path\n", getprogname());
357 static const struct got_error
*
358 cmd_init(int argc
, char *argv
[])
360 const struct got_error
*error
= NULL
;
361 char *repo_path
= NULL
;
364 while ((ch
= getopt(argc
, argv
, "")) != -1) {
376 if (pledge("stdio rpath wpath cpath unveil", NULL
) == -1)
382 repo_path
= strdup(argv
[0]);
383 if (repo_path
== NULL
)
384 return got_error_from_errno("strdup");
386 got_path_strip_trailing_slashes(repo_path
);
388 error
= got_path_mkdir(repo_path
);
390 !(error
->code
== GOT_ERR_ERRNO
&& errno
== EEXIST
))
393 error
= apply_unveil(repo_path
, 0, NULL
);
397 error
= got_repo_init(repo_path
);
406 fprintf(stderr
, "usage: %s import [-b branch] [-m message] "
407 "[-r repository-path] [-I pattern] path\n", getprogname());
412 spawn_editor(const char *editor
, const char *file
)
415 sig_t sighup
, sigint
, sigquit
;
418 sighup
= signal(SIGHUP
, SIG_IGN
);
419 sigint
= signal(SIGINT
, SIG_IGN
);
420 sigquit
= signal(SIGQUIT
, SIG_IGN
);
422 switch (pid
= fork()) {
426 execl(editor
, editor
, file
, (char *)NULL
);
430 while (waitpid(pid
, &st
, 0) == -1)
435 (void)signal(SIGHUP
, sighup
);
436 (void)signal(SIGINT
, sigint
);
437 (void)signal(SIGQUIT
, sigquit
);
439 if (!WIFEXITED(st
)) {
444 return WEXITSTATUS(st
);
447 static const struct got_error
*
448 edit_logmsg(char **logmsg
, const char *editor
, const char *logmsg_path
,
449 const char *initial_content
, size_t initial_content_len
,
450 int require_modification
)
452 const struct got_error
*err
= NULL
;
458 size_t len
, logmsg_len
;
459 char *initial_content_stripped
= NULL
, *buf
= NULL
, *s
;
463 if (stat(logmsg_path
, &st
) == -1)
464 return got_error_from_errno2("stat", logmsg_path
);
466 if (spawn_editor(editor
, logmsg_path
) == -1)
467 return got_error_from_errno("failed spawning editor");
469 if (stat(logmsg_path
, &st2
) == -1)
470 return got_error_from_errno("stat");
472 if (require_modification
&&
473 st
.st_mtime
== st2
.st_mtime
&& st
.st_size
== st2
.st_size
)
474 return got_error_msg(GOT_ERR_COMMIT_MSG_EMPTY
,
475 "no changes made to commit message, aborting");
478 * Set up a stripped version of the initial content without comments
479 * and blank lines. We need this in order to check if the message
480 * has in fact been edited.
482 initial_content_stripped
= malloc(initial_content_len
+ 1);
483 if (initial_content_stripped
== NULL
)
484 return got_error_from_errno("malloc");
485 initial_content_stripped
[0] = '\0';
487 buf
= strdup(initial_content
);
489 err
= got_error_from_errno("strdup");
494 while ((line
= strsep(&s
, "\n")) != NULL
) {
495 if ((line
[0] == '#' || (len
== 0 && line
[0] == '\n')))
496 continue; /* remove comments and leading empty lines */
497 len
= strlcat(initial_content_stripped
, line
,
498 initial_content_len
+ 1);
499 if (len
>= initial_content_len
+ 1) {
500 err
= got_error(GOT_ERR_NO_SPACE
);
504 while (len
> 0 && initial_content_stripped
[len
- 1] == '\n') {
505 initial_content_stripped
[len
- 1] = '\0';
509 logmsg_len
= st2
.st_size
;
510 *logmsg
= malloc(logmsg_len
+ 1);
512 return got_error_from_errno("malloc");
515 fp
= fopen(logmsg_path
, "re");
517 err
= got_error_from_errno("fopen");
522 while ((linelen
= getline(&line
, &linesize
, fp
)) != -1) {
523 if ((line
[0] == '#' || (len
== 0 && line
[0] == '\n')))
524 continue; /* remove comments and leading empty lines */
525 len
= strlcat(*logmsg
, line
, logmsg_len
+ 1);
526 if (len
>= logmsg_len
+ 1) {
527 err
= got_error(GOT_ERR_NO_SPACE
);
533 err
= got_ferror(fp
, GOT_ERR_IO
);
536 while (len
> 0 && (*logmsg
)[len
- 1] == '\n') {
537 (*logmsg
)[len
- 1] = '\0';
542 err
= got_error_msg(GOT_ERR_COMMIT_MSG_EMPTY
,
543 "commit message cannot be empty, aborting");
546 if (require_modification
&&
547 strcmp(*logmsg
, initial_content_stripped
) == 0)
548 err
= got_error_msg(GOT_ERR_COMMIT_MSG_EMPTY
,
549 "no changes made to commit message, aborting");
551 free(initial_content_stripped
);
553 if (fp
&& fclose(fp
) == EOF
&& err
== NULL
)
554 err
= got_error_from_errno("fclose");
562 static const struct got_error
*
563 collect_import_msg(char **logmsg
, char **logmsg_path
, const char *editor
,
564 const char *path_dir
, const char *branch_name
)
566 char *initial_content
= NULL
;
567 const struct got_error
*err
= NULL
;
568 int initial_content_len
;
571 initial_content_len
= asprintf(&initial_content
,
572 "\n# %s to be imported to branch %s\n", path_dir
,
574 if (initial_content_len
== -1)
575 return got_error_from_errno("asprintf");
577 err
= got_opentemp_named_fd(logmsg_path
, &fd
,
578 GOT_TMPDIR_STR
"/got-importmsg");
582 if (write(fd
, initial_content
, initial_content_len
) == -1) {
583 err
= got_error_from_errno2("write", *logmsg_path
);
587 err
= edit_logmsg(logmsg
, editor
, *logmsg_path
, initial_content
,
588 initial_content_len
, 1);
590 if (fd
!= -1 && close(fd
) == -1 && err
== NULL
)
591 err
= got_error_from_errno2("close", *logmsg_path
);
592 free(initial_content
);
600 static const struct got_error
*
601 import_progress(void *arg
, const char *path
)
603 printf("A %s\n", path
);
608 valid_author(const char *author
)
611 * Really dumb email address check; we're only doing this to
612 * avoid git's object parser breaking on commits we create.
614 while (*author
&& *author
!= '<')
618 while (*author
&& *author
!= '@')
622 while (*author
&& *author
!= '>')
624 return *author
== '>';
627 static const struct got_error
*
628 get_author(char **author
, struct got_repository
*repo
,
629 struct got_worktree
*worktree
)
631 const struct got_error
*err
= NULL
;
632 const char *got_author
= NULL
, *name
, *email
;
633 const struct got_gotconfig
*worktree_conf
= NULL
, *repo_conf
= NULL
;
638 worktree_conf
= got_worktree_get_gotconfig(worktree
);
639 repo_conf
= got_repo_get_gotconfig(repo
);
642 * Priority of potential author information sources, from most
643 * significant to least significant:
644 * 1) work tree's .got/got.conf file
645 * 2) repository's got.conf file
646 * 3) repository's git config file
647 * 4) environment variables
648 * 5) global git config files (in user's home directory or /etc)
652 got_author
= got_gotconfig_get_author(worktree_conf
);
653 if (got_author
== NULL
)
654 got_author
= got_gotconfig_get_author(repo_conf
);
655 if (got_author
== NULL
) {
656 name
= got_repo_get_gitconfig_author_name(repo
);
657 email
= got_repo_get_gitconfig_author_email(repo
);
659 if (asprintf(author
, "%s <%s>", name
, email
) == -1)
660 return got_error_from_errno("asprintf");
664 got_author
= getenv("GOT_AUTHOR");
665 if (got_author
== NULL
) {
666 name
= got_repo_get_global_gitconfig_author_name(repo
);
667 email
= got_repo_get_global_gitconfig_author_email(
670 if (asprintf(author
, "%s <%s>", name
, email
)
672 return got_error_from_errno("asprintf");
675 /* TODO: Look up user in password database? */
676 return got_error(GOT_ERR_COMMIT_NO_AUTHOR
);
680 *author
= strdup(got_author
);
682 return got_error_from_errno("strdup");
684 if (!valid_author(*author
)) {
685 err
= got_error_fmt(GOT_ERR_COMMIT_NO_EMAIL
, "%s", *author
);
692 static const struct got_error
*
693 get_allowed_signers(char **allowed_signers
, struct got_repository
*repo
,
694 struct got_worktree
*worktree
)
696 const char *got_allowed_signers
= NULL
;
697 const struct got_gotconfig
*worktree_conf
= NULL
, *repo_conf
= NULL
;
699 *allowed_signers
= NULL
;
702 worktree_conf
= got_worktree_get_gotconfig(worktree
);
703 repo_conf
= got_repo_get_gotconfig(repo
);
706 * Priority of potential author information sources, from most
707 * significant to least significant:
708 * 1) work tree's .got/got.conf file
709 * 2) repository's got.conf file
713 got_allowed_signers
= got_gotconfig_get_allowed_signers_file(
715 if (got_allowed_signers
== NULL
)
716 got_allowed_signers
= got_gotconfig_get_allowed_signers_file(
719 if (got_allowed_signers
) {
720 *allowed_signers
= strdup(got_allowed_signers
);
721 if (*allowed_signers
== NULL
)
722 return got_error_from_errno("strdup");
727 static const struct got_error
*
728 get_revoked_signers(char **revoked_signers
, struct got_repository
*repo
,
729 struct got_worktree
*worktree
)
731 const char *got_revoked_signers
= NULL
;
732 const struct got_gotconfig
*worktree_conf
= NULL
, *repo_conf
= NULL
;
734 *revoked_signers
= NULL
;
737 worktree_conf
= got_worktree_get_gotconfig(worktree
);
738 repo_conf
= got_repo_get_gotconfig(repo
);
741 * Priority of potential author information sources, from most
742 * significant to least significant:
743 * 1) work tree's .got/got.conf file
744 * 2) repository's got.conf file
748 got_revoked_signers
= got_gotconfig_get_revoked_signers_file(
750 if (got_revoked_signers
== NULL
)
751 got_revoked_signers
= got_gotconfig_get_revoked_signers_file(
754 if (got_revoked_signers
) {
755 *revoked_signers
= strdup(got_revoked_signers
);
756 if (*revoked_signers
== NULL
)
757 return got_error_from_errno("strdup");
762 static const struct got_error
*
763 get_gitconfig_path(char **gitconfig_path
)
765 const char *homedir
= getenv("HOME");
767 *gitconfig_path
= NULL
;
769 if (asprintf(gitconfig_path
, "%s/.gitconfig", homedir
) == -1)
770 return got_error_from_errno("asprintf");
776 static const struct got_error
*
777 cmd_import(int argc
, char *argv
[])
779 const struct got_error
*error
= NULL
;
780 char *path_dir
= NULL
, *repo_path
= NULL
, *logmsg
= NULL
;
781 char *gitconfig_path
= NULL
, *editor
= NULL
, *author
= NULL
;
782 const char *branch_name
= "main";
783 char *refname
= NULL
, *id_str
= NULL
, *logmsg_path
= NULL
;
784 struct got_repository
*repo
= NULL
;
785 struct got_reference
*branch_ref
= NULL
, *head_ref
= NULL
;
786 struct got_object_id
*new_commit_id
= NULL
;
788 struct got_pathlist_head ignores
;
789 struct got_pathlist_entry
*pe
;
790 int preserve_logmsg
= 0;
791 int *pack_fds
= NULL
;
793 TAILQ_INIT(&ignores
);
795 while ((ch
= getopt(argc
, argv
, "b:m:r:I:")) != -1) {
798 branch_name
= optarg
;
801 logmsg
= strdup(optarg
);
802 if (logmsg
== NULL
) {
803 error
= got_error_from_errno("strdup");
808 repo_path
= realpath(optarg
, NULL
);
809 if (repo_path
== NULL
) {
810 error
= got_error_from_errno2("realpath",
816 if (optarg
[0] == '\0')
818 error
= got_pathlist_insert(&pe
, &ignores
, optarg
,
833 if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd "
841 if (repo_path
== NULL
) {
842 repo_path
= getcwd(NULL
, 0);
843 if (repo_path
== NULL
)
844 return got_error_from_errno("getcwd");
846 got_path_strip_trailing_slashes(repo_path
);
847 error
= get_gitconfig_path(&gitconfig_path
);
850 error
= got_repo_pack_fds_open(&pack_fds
);
853 error
= got_repo_open(&repo
, repo_path
, gitconfig_path
, pack_fds
);
857 error
= get_author(&author
, repo
, NULL
);
862 * Don't let the user create a branch name with a leading '-'.
863 * While technically a valid reference name, this case is usually
864 * an unintended typo.
866 if (branch_name
[0] == '-')
867 return got_error_path(branch_name
, GOT_ERR_REF_NAME_MINUS
);
869 if (asprintf(&refname
, "refs/heads/%s", branch_name
) == -1) {
870 error
= got_error_from_errno("asprintf");
874 error
= got_ref_open(&branch_ref
, repo
, refname
, 0);
876 if (error
->code
!= GOT_ERR_NOT_REF
)
879 error
= got_error_msg(GOT_ERR_BRANCH_EXISTS
,
880 "import target branch already exists");
884 path_dir
= realpath(argv
[0], NULL
);
885 if (path_dir
== NULL
) {
886 error
= got_error_from_errno2("realpath", argv
[0]);
889 got_path_strip_trailing_slashes(path_dir
);
892 * unveil(2) traverses exec(2); if an editor is used we have
893 * to apply unveil after the log message has been written.
895 if (logmsg
== NULL
|| strlen(logmsg
) == 0) {
896 error
= get_editor(&editor
);
900 error
= collect_import_msg(&logmsg
, &logmsg_path
, editor
,
903 if (error
->code
!= GOT_ERR_COMMIT_MSG_EMPTY
&&
910 if (unveil(path_dir
, "r") != 0) {
911 error
= got_error_from_errno2("unveil", path_dir
);
917 error
= apply_unveil(got_repo_get_path(repo
), 0, NULL
);
924 error
= got_repo_import(&new_commit_id
, path_dir
, logmsg
,
925 author
, &ignores
, repo
, import_progress
, NULL
);
932 error
= got_ref_alloc(&branch_ref
, refname
, new_commit_id
);
939 error
= got_ref_write(branch_ref
, repo
);
946 error
= got_object_id_str(&id_str
, new_commit_id
);
953 error
= got_ref_open(&head_ref
, repo
, GOT_REF_HEAD
, 0);
955 if (error
->code
!= GOT_ERR_NOT_REF
) {
961 error
= got_ref_alloc_symref(&head_ref
, GOT_REF_HEAD
,
969 error
= got_ref_write(head_ref
, repo
);
977 printf("Created branch %s with commit %s\n",
978 got_ref_get_name(branch_ref
), id_str
);
981 const struct got_error
*pack_err
=
982 got_repo_pack_fds_close(pack_fds
);
986 if (preserve_logmsg
) {
987 fprintf(stderr
, "%s: log message preserved in %s\n",
988 getprogname(), logmsg_path
);
989 } else if (logmsg_path
&& unlink(logmsg_path
) == -1 && error
== NULL
)
990 error
= got_error_from_errno2("unlink", logmsg_path
);
999 free(gitconfig_path
);
1001 got_ref_close(branch_ref
);
1003 got_ref_close(head_ref
);
1010 fprintf(stderr
, "usage: %s clone [-a] [-b branch] [-l] [-m] [-q] [-v] "
1011 "[-R reference] repository-url [directory]\n", getprogname());
1015 struct got_fetch_progress_arg
{
1016 char last_scaled_size
[FMT_SCALED_STRSIZE
];
1018 int last_p_resolved
;
1021 struct got_repository
*repo
;
1024 int configs_created
;
1026 struct got_pathlist_head
*symrefs
;
1027 struct got_pathlist_head
*wanted_branches
;
1028 struct got_pathlist_head
*wanted_refs
;
1032 const char *remote_repo_path
;
1033 const char *git_url
;
1034 int fetch_all_branches
;
1035 int mirror_references
;
1039 /* XXX forward declaration */
1040 static const struct got_error
*
1041 create_config_files(const char *proto
, const char *host
, const char *port
,
1042 const char *remote_repo_path
, const char *git_url
, int fetch_all_branches
,
1043 int mirror_references
, struct got_pathlist_head
*symrefs
,
1044 struct got_pathlist_head
*wanted_branches
,
1045 struct got_pathlist_head
*wanted_refs
, struct got_repository
*repo
);
1047 static const struct got_error
*
1048 fetch_progress(void *arg
, const char *message
, off_t packfile_size
,
1049 int nobj_total
, int nobj_indexed
, int nobj_loose
, int nobj_resolved
)
1051 const struct got_error
*err
= NULL
;
1052 struct got_fetch_progress_arg
*a
= arg
;
1053 char scaled_size
[FMT_SCALED_STRSIZE
];
1054 int p_indexed
, p_resolved
;
1055 int print_size
= 0, print_indexed
= 0, print_resolved
= 0;
1058 * In order to allow a failed clone to be resumed with 'got fetch'
1059 * we try to create configuration files as soon as possible.
1060 * Once the server has sent information about its default branch
1061 * we have all required information.
1063 if (a
->create_configs
&& !a
->configs_created
&&
1064 !TAILQ_EMPTY(a
->config_info
.symrefs
)) {
1065 err
= create_config_files(a
->config_info
.proto
,
1066 a
->config_info
.host
, a
->config_info
.port
,
1067 a
->config_info
.remote_repo_path
,
1068 a
->config_info
.git_url
,
1069 a
->config_info
.fetch_all_branches
,
1070 a
->config_info
.mirror_references
,
1071 a
->config_info
.symrefs
,
1072 a
->config_info
.wanted_branches
,
1073 a
->config_info
.wanted_refs
, a
->repo
);
1076 a
->configs_created
= 1;
1079 if (a
->verbosity
< 0)
1082 if (message
&& message
[0] != '\0') {
1083 printf("\rserver: %s", message
);
1088 if (packfile_size
> 0 || nobj_indexed
> 0) {
1089 if (fmt_scaled(packfile_size
, scaled_size
) == 0 &&
1090 (a
->last_scaled_size
[0] == '\0' ||
1091 strcmp(scaled_size
, a
->last_scaled_size
)) != 0) {
1093 if (strlcpy(a
->last_scaled_size
, scaled_size
,
1094 FMT_SCALED_STRSIZE
) >= FMT_SCALED_STRSIZE
)
1095 return got_error(GOT_ERR_NO_SPACE
);
1097 if (nobj_indexed
> 0) {
1098 p_indexed
= (nobj_indexed
* 100) / nobj_total
;
1099 if (p_indexed
!= a
->last_p_indexed
) {
1100 a
->last_p_indexed
= p_indexed
;
1105 if (nobj_resolved
> 0) {
1106 p_resolved
= (nobj_resolved
* 100) /
1107 (nobj_total
- nobj_loose
);
1108 if (p_resolved
!= a
->last_p_resolved
) {
1109 a
->last_p_resolved
= p_resolved
;
1117 if (print_size
|| print_indexed
|| print_resolved
)
1120 printf("%*s fetched", FMT_SCALED_STRSIZE
- 2, scaled_size
);
1122 printf("; indexing %d%%", p_indexed
);
1124 printf("; resolving deltas %d%%", p_resolved
);
1125 if (print_size
|| print_indexed
|| print_resolved
)
1131 static const struct got_error
*
1132 create_symref(const char *refname
, struct got_reference
*target_ref
,
1133 int verbosity
, struct got_repository
*repo
)
1135 const struct got_error
*err
;
1136 struct got_reference
*head_symref
;
1138 err
= got_ref_alloc_symref(&head_symref
, refname
, target_ref
);
1142 err
= got_ref_write(head_symref
, repo
);
1143 if (err
== NULL
&& verbosity
> 0) {
1144 printf("Created reference %s: %s\n", GOT_REF_HEAD
,
1145 got_ref_get_name(target_ref
));
1147 got_ref_close(head_symref
);
1151 static const struct got_error
*
1152 list_remote_refs(struct got_pathlist_head
*symrefs
,
1153 struct got_pathlist_head
*refs
)
1155 const struct got_error
*err
;
1156 struct got_pathlist_entry
*pe
;
1158 TAILQ_FOREACH(pe
, symrefs
, entry
) {
1159 const char *refname
= pe
->path
;
1160 const char *targetref
= pe
->data
;
1162 printf("%s: %s\n", refname
, targetref
);
1165 TAILQ_FOREACH(pe
, refs
, entry
) {
1166 const char *refname
= pe
->path
;
1167 struct got_object_id
*id
= pe
->data
;
1170 err
= got_object_id_str(&id_str
, id
);
1173 printf("%s: %s\n", refname
, id_str
);
1180 static const struct got_error
*
1181 create_ref(const char *refname
, struct got_object_id
*id
,
1182 int verbosity
, struct got_repository
*repo
)
1184 const struct got_error
*err
= NULL
;
1185 struct got_reference
*ref
;
1188 err
= got_object_id_str(&id_str
, id
);
1192 err
= got_ref_alloc(&ref
, refname
, id
);
1196 err
= got_ref_write(ref
, repo
);
1199 if (err
== NULL
&& verbosity
>= 0)
1200 printf("Created reference %s: %s\n", refname
, id_str
);
1207 match_wanted_ref(const char *refname
, const char *wanted_ref
)
1209 if (strncmp(refname
, "refs/", 5) != 0)
1214 * Prevent fetching of references that won't make any
1215 * sense outside of the remote repository's context.
1217 if (strncmp(refname
, "got/", 4) == 0)
1219 if (strncmp(refname
, "remotes/", 8) == 0)
1222 if (strncmp(wanted_ref
, "refs/", 5) == 0)
1225 /* Allow prefix match. */
1226 if (got_path_is_child(refname
, wanted_ref
, strlen(wanted_ref
)))
1229 /* Allow exact match. */
1230 return (strcmp(refname
, wanted_ref
) == 0);
1234 is_wanted_ref(struct got_pathlist_head
*wanted_refs
, const char *refname
)
1236 struct got_pathlist_entry
*pe
;
1238 TAILQ_FOREACH(pe
, wanted_refs
, entry
) {
1239 if (match_wanted_ref(refname
, pe
->path
))
1246 static const struct got_error
*
1247 create_wanted_ref(const char *refname
, struct got_object_id
*id
,
1248 const char *remote_repo_name
, int verbosity
, struct got_repository
*repo
)
1250 const struct got_error
*err
;
1251 char *remote_refname
;
1253 if (strncmp("refs/", refname
, 5) == 0)
1256 if (asprintf(&remote_refname
, "refs/remotes/%s/%s",
1257 remote_repo_name
, refname
) == -1)
1258 return got_error_from_errno("asprintf");
1260 err
= create_ref(remote_refname
, id
, verbosity
, repo
);
1261 free(remote_refname
);
1265 static const struct got_error
*
1266 create_gotconfig(const char *proto
, const char *host
, const char *port
,
1267 const char *remote_repo_path
, const char *default_branch
,
1268 int fetch_all_branches
, struct got_pathlist_head
*wanted_branches
,
1269 struct got_pathlist_head
*wanted_refs
, int mirror_references
,
1270 struct got_repository
*repo
)
1272 const struct got_error
*err
= NULL
;
1273 char *gotconfig_path
= NULL
;
1274 char *gotconfig
= NULL
;
1275 FILE *gotconfig_file
= NULL
;
1276 const char *branchname
= NULL
;
1277 char *branches
= NULL
, *refs
= NULL
;
1280 if (!fetch_all_branches
&& !TAILQ_EMPTY(wanted_branches
)) {
1281 struct got_pathlist_entry
*pe
;
1282 TAILQ_FOREACH(pe
, wanted_branches
, entry
) {
1284 branchname
= pe
->path
;
1285 if (strncmp(branchname
, "refs/heads/", 11) == 0)
1287 if (asprintf(&s
, "%s\"%s\" ",
1288 branches
? branches
: "", branchname
) == -1) {
1289 err
= got_error_from_errno("asprintf");
1295 } else if (!fetch_all_branches
&& default_branch
) {
1296 branchname
= default_branch
;
1297 if (strncmp(branchname
, "refs/heads/", 11) == 0)
1299 if (asprintf(&branches
, "\"%s\" ", branchname
) == -1) {
1300 err
= got_error_from_errno("asprintf");
1304 if (!TAILQ_EMPTY(wanted_refs
)) {
1305 struct got_pathlist_entry
*pe
;
1306 TAILQ_FOREACH(pe
, wanted_refs
, entry
) {
1308 const char *refname
= pe
->path
;
1309 if (strncmp(refname
, "refs/", 5) == 0)
1311 if (asprintf(&s
, "%s\"%s\" ",
1312 refs
? refs
: "", refname
) == -1) {
1313 err
= got_error_from_errno("asprintf");
1321 /* Create got.conf(5). */
1322 gotconfig_path
= got_repo_get_path_gotconfig(repo
);
1323 if (gotconfig_path
== NULL
) {
1324 err
= got_error_from_errno("got_repo_get_path_gotconfig");
1327 gotconfig_file
= fopen(gotconfig_path
, "ae");
1328 if (gotconfig_file
== NULL
) {
1329 err
= got_error_from_errno2("fopen", gotconfig_path
);
1332 if (asprintf(&gotconfig
,
1337 "\trepository \"%s\"\n"
1343 GOT_FETCH_DEFAULT_REMOTE_NAME
, host
, proto
,
1344 port
? "\tport " : "", port
? port
: "", port
? "\n" : "",
1345 remote_repo_path
, branches
? "\tbranch { " : "",
1346 branches
? branches
: "", branches
? "}\n" : "",
1347 refs
? "\treference { " : "", refs
? refs
: "", refs
? "}\n" : "",
1348 mirror_references
? "\tmirror_references yes\n" : "",
1349 fetch_all_branches
? "\tfetch_all_branches yes\n" : "") == -1) {
1350 err
= got_error_from_errno("asprintf");
1353 n
= fwrite(gotconfig
, 1, strlen(gotconfig
), gotconfig_file
);
1354 if (n
!= strlen(gotconfig
)) {
1355 err
= got_ferror(gotconfig_file
, GOT_ERR_IO
);
1360 if (gotconfig_file
&& fclose(gotconfig_file
) == EOF
&& err
== NULL
)
1361 err
= got_error_from_errno2("fclose", gotconfig_path
);
1362 free(gotconfig_path
);
1367 static const struct got_error
*
1368 create_gitconfig(const char *git_url
, const char *default_branch
,
1369 int fetch_all_branches
, struct got_pathlist_head
*wanted_branches
,
1370 struct got_pathlist_head
*wanted_refs
, int mirror_references
,
1371 struct got_repository
*repo
)
1373 const struct got_error
*err
= NULL
;
1374 char *gitconfig_path
= NULL
;
1375 char *gitconfig
= NULL
;
1376 FILE *gitconfig_file
= NULL
;
1377 char *branches
= NULL
, *refs
= NULL
;
1378 const char *branchname
;
1381 /* Create a config file Git can understand. */
1382 gitconfig_path
= got_repo_get_path_gitconfig(repo
);
1383 if (gitconfig_path
== NULL
) {
1384 err
= got_error_from_errno("got_repo_get_path_gitconfig");
1387 gitconfig_file
= fopen(gitconfig_path
, "ae");
1388 if (gitconfig_file
== NULL
) {
1389 err
= got_error_from_errno2("fopen", gitconfig_path
);
1392 if (fetch_all_branches
) {
1393 if (mirror_references
) {
1394 if (asprintf(&branches
,
1395 "\tfetch = refs/heads/*:refs/heads/*\n") == -1) {
1396 err
= got_error_from_errno("asprintf");
1399 } else if (asprintf(&branches
,
1400 "\tfetch = refs/heads/*:refs/remotes/%s/*\n",
1401 GOT_FETCH_DEFAULT_REMOTE_NAME
) == -1) {
1402 err
= got_error_from_errno("asprintf");
1405 } else if (!TAILQ_EMPTY(wanted_branches
)) {
1406 struct got_pathlist_entry
*pe
;
1407 TAILQ_FOREACH(pe
, wanted_branches
, entry
) {
1409 branchname
= pe
->path
;
1410 if (strncmp(branchname
, "refs/heads/", 11) == 0)
1412 if (mirror_references
) {
1414 "%s\tfetch = refs/heads/%s:refs/heads/%s\n",
1415 branches
? branches
: "",
1416 branchname
, branchname
) == -1) {
1417 err
= got_error_from_errno("asprintf");
1420 } else if (asprintf(&s
,
1421 "%s\tfetch = refs/heads/%s:refs/remotes/%s/%s\n",
1422 branches
? branches
: "",
1423 branchname
, GOT_FETCH_DEFAULT_REMOTE_NAME
,
1424 branchname
) == -1) {
1425 err
= got_error_from_errno("asprintf");
1433 * If the server specified a default branch, use just that one.
1434 * Otherwise fall back to fetching all branches on next fetch.
1436 if (default_branch
) {
1437 branchname
= default_branch
;
1438 if (strncmp(branchname
, "refs/heads/", 11) == 0)
1441 branchname
= "*"; /* fall back to all branches */
1442 if (mirror_references
) {
1443 if (asprintf(&branches
,
1444 "\tfetch = refs/heads/%s:refs/heads/%s\n",
1445 branchname
, branchname
) == -1) {
1446 err
= got_error_from_errno("asprintf");
1449 } else if (asprintf(&branches
,
1450 "\tfetch = refs/heads/%s:refs/remotes/%s/%s\n",
1451 branchname
, GOT_FETCH_DEFAULT_REMOTE_NAME
,
1452 branchname
) == -1) {
1453 err
= got_error_from_errno("asprintf");
1457 if (!TAILQ_EMPTY(wanted_refs
)) {
1458 struct got_pathlist_entry
*pe
;
1459 TAILQ_FOREACH(pe
, wanted_refs
, entry
) {
1461 const char *refname
= pe
->path
;
1462 if (strncmp(refname
, "refs/", 5) == 0)
1464 if (mirror_references
) {
1466 "%s\tfetch = refs/%s:refs/%s\n",
1467 refs
? refs
: "", refname
, refname
) == -1) {
1468 err
= got_error_from_errno("asprintf");
1471 } else if (asprintf(&s
,
1472 "%s\tfetch = refs/%s:refs/remotes/%s/%s\n",
1474 refname
, GOT_FETCH_DEFAULT_REMOTE_NAME
,
1476 err
= got_error_from_errno("asprintf");
1484 if (asprintf(&gitconfig
,
1489 "\tfetch = refs/tags/*:refs/tags/*\n",
1490 GOT_FETCH_DEFAULT_REMOTE_NAME
, git_url
, branches
? branches
: "",
1491 refs
? refs
: "") == -1) {
1492 err
= got_error_from_errno("asprintf");
1495 n
= fwrite(gitconfig
, 1, strlen(gitconfig
), gitconfig_file
);
1496 if (n
!= strlen(gitconfig
)) {
1497 err
= got_ferror(gitconfig_file
, GOT_ERR_IO
);
1501 if (gitconfig_file
&& fclose(gitconfig_file
) == EOF
&& err
== NULL
)
1502 err
= got_error_from_errno2("fclose", gitconfig_path
);
1503 free(gitconfig_path
);
1508 static const struct got_error
*
1509 create_config_files(const char *proto
, const char *host
, const char *port
,
1510 const char *remote_repo_path
, const char *git_url
, int fetch_all_branches
,
1511 int mirror_references
, struct got_pathlist_head
*symrefs
,
1512 struct got_pathlist_head
*wanted_branches
,
1513 struct got_pathlist_head
*wanted_refs
, struct got_repository
*repo
)
1515 const struct got_error
*err
= NULL
;
1516 const char *default_branch
= NULL
;
1517 struct got_pathlist_entry
*pe
;
1520 * If we asked for a set of wanted branches then use the first
1523 if (!TAILQ_EMPTY(wanted_branches
)) {
1524 pe
= TAILQ_FIRST(wanted_branches
);
1525 default_branch
= pe
->path
;
1527 /* First HEAD ref listed by server is the default branch. */
1528 TAILQ_FOREACH(pe
, symrefs
, entry
) {
1529 const char *refname
= pe
->path
;
1530 const char *target
= pe
->data
;
1532 if (strcmp(refname
, GOT_REF_HEAD
) != 0)
1535 default_branch
= target
;
1540 /* Create got.conf(5). */
1541 err
= create_gotconfig(proto
, host
, port
, remote_repo_path
,
1542 default_branch
, fetch_all_branches
, wanted_branches
,
1543 wanted_refs
, mirror_references
, repo
);
1547 /* Create a config file Git can understand. */
1548 return create_gitconfig(git_url
, default_branch
, fetch_all_branches
,
1549 wanted_branches
, wanted_refs
, mirror_references
, repo
);
1552 static const struct got_error
*
1553 cmd_clone(int argc
, char *argv
[])
1555 const struct got_error
*error
= NULL
;
1556 const char *uri
, *dirname
;
1557 char *proto
, *host
, *port
, *repo_name
, *server_path
;
1558 char *default_destdir
= NULL
, *id_str
= NULL
;
1559 const char *repo_path
;
1560 struct got_repository
*repo
= NULL
;
1561 struct got_pathlist_head refs
, symrefs
, wanted_branches
, wanted_refs
;
1562 struct got_pathlist_entry
*pe
;
1563 struct got_object_id
*pack_hash
= NULL
;
1564 int ch
, fetchfd
= -1, fetchstatus
;
1565 pid_t fetchpid
= -1;
1566 struct got_fetch_progress_arg fpa
;
1567 char *git_url
= NULL
;
1568 int verbosity
= 0, fetch_all_branches
= 0, mirror_references
= 0;
1569 int list_refs_only
= 0;
1570 int *pack_fds
= NULL
;
1573 TAILQ_INIT(&symrefs
);
1574 TAILQ_INIT(&wanted_branches
);
1575 TAILQ_INIT(&wanted_refs
);
1577 while ((ch
= getopt(argc
, argv
, "ab:lmvqR:")) != -1) {
1580 fetch_all_branches
= 1;
1583 error
= got_pathlist_append(&wanted_branches
,
1592 mirror_references
= 1;
1597 else if (verbosity
< 3)
1604 error
= got_pathlist_append(&wanted_refs
,
1617 if (fetch_all_branches
&& !TAILQ_EMPTY(&wanted_branches
))
1618 option_conflict('a', 'b');
1619 if (list_refs_only
) {
1620 if (!TAILQ_EMPTY(&wanted_branches
))
1621 option_conflict('l', 'b');
1622 if (fetch_all_branches
)
1623 option_conflict('l', 'a');
1624 if (mirror_references
)
1625 option_conflict('l', 'm');
1626 if (!TAILQ_EMPTY(&wanted_refs
))
1627 option_conflict('l', 'R');
1639 error
= got_dial_parse_uri(&proto
, &host
, &port
, &server_path
,
1644 if (asprintf(&git_url
, "%s://%s%s%s%s%s", proto
,
1645 host
, port
? ":" : "", port
? port
: "",
1646 server_path
[0] != '/' ? "/" : "", server_path
) == -1) {
1647 error
= got_error_from_errno("asprintf");
1651 if (strcmp(proto
, "git") == 0) {
1653 if (pledge("stdio rpath wpath cpath fattr flock proc exec "
1654 "sendfd dns inet unveil", NULL
) == -1)
1657 } else if (strcmp(proto
, "git+ssh") == 0 ||
1658 strcmp(proto
, "ssh") == 0) {
1660 if (pledge("stdio rpath wpath cpath fattr flock proc exec "
1661 "sendfd unveil", NULL
) == -1)
1664 } else if (strcmp(proto
, "http") == 0 ||
1665 strcmp(proto
, "git+http") == 0) {
1666 error
= got_error_path(proto
, GOT_ERR_NOT_IMPL
);
1669 error
= got_error_path(proto
, GOT_ERR_BAD_PROTO
);
1672 if (dirname
== NULL
) {
1673 if (asprintf(&default_destdir
, "%s.git", repo_name
) == -1) {
1674 error
= got_error_from_errno("asprintf");
1677 repo_path
= default_destdir
;
1679 repo_path
= dirname
;
1681 if (!list_refs_only
) {
1682 error
= got_path_mkdir(repo_path
);
1684 (!(error
->code
== GOT_ERR_ERRNO
&& errno
== EISDIR
) &&
1685 !(error
->code
== GOT_ERR_ERRNO
&& errno
== EEXIST
)))
1687 if (!got_path_dir_is_empty(repo_path
)) {
1688 error
= got_error_path(repo_path
,
1689 GOT_ERR_DIR_NOT_EMPTY
);
1694 error
= got_dial_apply_unveil(proto
);
1698 error
= apply_unveil(repo_path
, 0, NULL
);
1703 printf("Connecting to %s%s%s\n", host
,
1704 port
? ":" : "", port
? port
: "");
1706 error
= got_fetch_connect(&fetchpid
, &fetchfd
, proto
, host
, port
,
1707 server_path
, verbosity
);
1711 if (!list_refs_only
) {
1712 error
= got_repo_init(repo_path
);
1715 error
= got_repo_pack_fds_open(&pack_fds
);
1718 error
= got_repo_open(&repo
, repo_path
, NULL
, pack_fds
);
1723 fpa
.last_scaled_size
[0] = '\0';
1724 fpa
.last_p_indexed
= -1;
1725 fpa
.last_p_resolved
= -1;
1726 fpa
.verbosity
= verbosity
;
1727 fpa
.create_configs
= 1;
1728 fpa
.configs_created
= 0;
1730 fpa
.config_info
.symrefs
= &symrefs
;
1731 fpa
.config_info
.wanted_branches
= &wanted_branches
;
1732 fpa
.config_info
.wanted_refs
= &wanted_refs
;
1733 fpa
.config_info
.proto
= proto
;
1734 fpa
.config_info
.host
= host
;
1735 fpa
.config_info
.port
= port
;
1736 fpa
.config_info
.remote_repo_path
= server_path
;
1737 fpa
.config_info
.git_url
= git_url
;
1738 fpa
.config_info
.fetch_all_branches
= fetch_all_branches
;
1739 fpa
.config_info
.mirror_references
= mirror_references
;
1740 error
= got_fetch_pack(&pack_hash
, &refs
, &symrefs
,
1741 GOT_FETCH_DEFAULT_REMOTE_NAME
, mirror_references
,
1742 fetch_all_branches
, &wanted_branches
, &wanted_refs
,
1743 list_refs_only
, verbosity
, fetchfd
, repo
,
1744 fetch_progress
, &fpa
);
1748 if (list_refs_only
) {
1749 error
= list_remote_refs(&symrefs
, &refs
);
1753 if (pack_hash
== NULL
) {
1754 error
= got_error_fmt(GOT_ERR_FETCH_FAILED
, "%s",
1755 "server sent an empty pack file");
1758 error
= got_object_id_str(&id_str
, pack_hash
);
1762 printf("\nFetched %s.pack\n", id_str
);
1765 /* Set up references provided with the pack file. */
1766 TAILQ_FOREACH(pe
, &refs
, entry
) {
1767 const char *refname
= pe
->path
;
1768 struct got_object_id
*id
= pe
->data
;
1769 char *remote_refname
;
1771 if (is_wanted_ref(&wanted_refs
, refname
) &&
1772 !mirror_references
) {
1773 error
= create_wanted_ref(refname
, id
,
1774 GOT_FETCH_DEFAULT_REMOTE_NAME
,
1775 verbosity
- 1, repo
);
1781 error
= create_ref(refname
, id
, verbosity
- 1, repo
);
1785 if (mirror_references
)
1788 if (strncmp("refs/heads/", refname
, 11) != 0)
1791 if (asprintf(&remote_refname
,
1792 "refs/remotes/%s/%s", GOT_FETCH_DEFAULT_REMOTE_NAME
,
1793 refname
+ 11) == -1) {
1794 error
= got_error_from_errno("asprintf");
1797 error
= create_ref(remote_refname
, id
, verbosity
- 1, repo
);
1798 free(remote_refname
);
1803 /* Set the HEAD reference if the server provided one. */
1804 TAILQ_FOREACH(pe
, &symrefs
, entry
) {
1805 struct got_reference
*target_ref
;
1806 const char *refname
= pe
->path
;
1807 const char *target
= pe
->data
;
1808 char *remote_refname
= NULL
, *remote_target
= NULL
;
1810 if (strcmp(refname
, GOT_REF_HEAD
) != 0)
1813 error
= got_ref_open(&target_ref
, repo
, target
, 0);
1815 if (error
->code
== GOT_ERR_NOT_REF
) {
1822 error
= create_symref(refname
, target_ref
, verbosity
, repo
);
1823 got_ref_close(target_ref
);
1827 if (mirror_references
)
1830 if (strncmp("refs/heads/", target
, 11) != 0)
1833 if (asprintf(&remote_refname
,
1834 "refs/remotes/%s/%s", GOT_FETCH_DEFAULT_REMOTE_NAME
,
1836 error
= got_error_from_errno("asprintf");
1839 if (asprintf(&remote_target
,
1840 "refs/remotes/%s/%s", GOT_FETCH_DEFAULT_REMOTE_NAME
,
1841 target
+ 11) == -1) {
1842 error
= got_error_from_errno("asprintf");
1843 free(remote_refname
);
1846 error
= got_ref_open(&target_ref
, repo
, remote_target
, 0);
1848 free(remote_refname
);
1849 free(remote_target
);
1850 if (error
->code
== GOT_ERR_NOT_REF
) {
1856 error
= create_symref(remote_refname
, target_ref
,
1857 verbosity
- 1, repo
);
1858 free(remote_refname
);
1859 free(remote_target
);
1860 got_ref_close(target_ref
);
1866 * We failed to set the HEAD reference. If we asked for
1867 * a set of wanted branches use the first of one of those
1868 * which could be fetched instead.
1870 TAILQ_FOREACH(pe
, &wanted_branches
, entry
) {
1871 const char *target
= pe
->path
;
1872 struct got_reference
*target_ref
;
1874 error
= got_ref_open(&target_ref
, repo
, target
, 0);
1876 if (error
->code
== GOT_ERR_NOT_REF
) {
1883 error
= create_symref(GOT_REF_HEAD
, target_ref
,
1885 got_ref_close(target_ref
);
1893 printf("Created %s repository '%s'\n",
1894 mirror_references
? "mirrored" : "cloned", repo_path
);
1897 const struct got_error
*pack_err
=
1898 got_repo_pack_fds_close(pack_fds
);
1903 if (kill(fetchpid
, SIGTERM
) == -1)
1904 error
= got_error_from_errno("kill");
1905 if (waitpid(fetchpid
, &fetchstatus
, 0) == -1 && error
== NULL
)
1906 error
= got_error_from_errno("waitpid");
1908 if (fetchfd
!= -1 && close(fetchfd
) == -1 && error
== NULL
)
1909 error
= got_error_from_errno("close");
1911 const struct got_error
*close_err
= got_repo_close(repo
);
1915 TAILQ_FOREACH(pe
, &refs
, entry
) {
1916 free((void *)pe
->path
);
1919 got_pathlist_free(&refs
);
1920 TAILQ_FOREACH(pe
, &symrefs
, entry
) {
1921 free((void *)pe
->path
);
1924 got_pathlist_free(&symrefs
);
1925 got_pathlist_free(&wanted_branches
);
1926 got_pathlist_free(&wanted_refs
);
1933 free(default_destdir
);
1938 static const struct got_error
*
1939 update_ref(struct got_reference
*ref
, struct got_object_id
*new_id
,
1940 int replace_tags
, int verbosity
, struct got_repository
*repo
)
1942 const struct got_error
*err
= NULL
;
1943 char *new_id_str
= NULL
;
1944 struct got_object_id
*old_id
= NULL
;
1946 err
= got_object_id_str(&new_id_str
, new_id
);
1950 if (!replace_tags
&&
1951 strncmp(got_ref_get_name(ref
), "refs/tags/", 10) == 0) {
1952 err
= got_ref_resolve(&old_id
, repo
, ref
);
1955 if (got_object_id_cmp(old_id
, new_id
) == 0)
1957 if (verbosity
>= 0) {
1958 printf("Rejecting update of existing tag %s: %s\n",
1959 got_ref_get_name(ref
), new_id_str
);
1964 if (got_ref_is_symbolic(ref
)) {
1965 if (verbosity
>= 0) {
1966 printf("Replacing reference %s: %s\n",
1967 got_ref_get_name(ref
),
1968 got_ref_get_symref_target(ref
));
1970 err
= got_ref_change_symref_to_ref(ref
, new_id
);
1973 err
= got_ref_write(ref
, repo
);
1977 err
= got_ref_resolve(&old_id
, repo
, ref
);
1980 if (got_object_id_cmp(old_id
, new_id
) == 0)
1983 err
= got_ref_change_ref(ref
, new_id
);
1986 err
= got_ref_write(ref
, repo
);
1992 printf("Updated %s: %s\n", got_ref_get_name(ref
),
2000 static const struct got_error
*
2001 update_symref(const char *refname
, struct got_reference
*target_ref
,
2002 int verbosity
, struct got_repository
*repo
)
2004 const struct got_error
*err
= NULL
, *unlock_err
;
2005 struct got_reference
*symref
;
2006 int symref_is_locked
= 0;
2008 err
= got_ref_open(&symref
, repo
, refname
, 1);
2010 if (err
->code
!= GOT_ERR_NOT_REF
)
2012 err
= got_ref_alloc_symref(&symref
, refname
, target_ref
);
2016 err
= got_ref_write(symref
, repo
);
2021 printf("Created reference %s: %s\n",
2022 got_ref_get_name(symref
),
2023 got_ref_get_symref_target(symref
));
2025 symref_is_locked
= 1;
2027 if (strcmp(got_ref_get_symref_target(symref
),
2028 got_ref_get_name(target_ref
)) == 0)
2031 err
= got_ref_change_symref(symref
,
2032 got_ref_get_name(target_ref
));
2036 err
= got_ref_write(symref
, repo
);
2041 printf("Updated %s: %s\n", got_ref_get_name(symref
),
2042 got_ref_get_symref_target(symref
));
2046 if (symref_is_locked
) {
2047 unlock_err
= got_ref_unlock(symref
);
2048 if (unlock_err
&& err
== NULL
)
2051 got_ref_close(symref
);
2058 fprintf(stderr
, "usage: %s fetch [-a] [-b branch] [-d] [-l] "
2059 "[-r repository-path] [-t] [-q] [-v] [-R reference] [-X] "
2060 "[remote-repository-name]\n",
2065 static const struct got_error
*
2066 delete_missing_ref(struct got_reference
*ref
,
2067 int verbosity
, struct got_repository
*repo
)
2069 const struct got_error
*err
= NULL
;
2070 struct got_object_id
*id
= NULL
;
2071 char *id_str
= NULL
;
2073 if (got_ref_is_symbolic(ref
)) {
2074 err
= got_ref_delete(ref
, repo
);
2077 if (verbosity
>= 0) {
2078 printf("Deleted %s: %s\n",
2079 got_ref_get_name(ref
),
2080 got_ref_get_symref_target(ref
));
2083 err
= got_ref_resolve(&id
, repo
, ref
);
2086 err
= got_object_id_str(&id_str
, id
);
2090 err
= got_ref_delete(ref
, repo
);
2093 if (verbosity
>= 0) {
2094 printf("Deleted %s: %s\n",
2095 got_ref_get_name(ref
), id_str
);
2104 static const struct got_error
*
2105 delete_missing_refs(struct got_pathlist_head
*their_refs
,
2106 struct got_pathlist_head
*their_symrefs
,
2107 const struct got_remote_repo
*remote
,
2108 int verbosity
, struct got_repository
*repo
)
2110 const struct got_error
*err
= NULL
, *unlock_err
;
2111 struct got_reflist_head my_refs
;
2112 struct got_reflist_entry
*re
;
2113 struct got_pathlist_entry
*pe
;
2114 char *remote_namespace
= NULL
;
2115 char *local_refname
= NULL
;
2117 TAILQ_INIT(&my_refs
);
2119 if (asprintf(&remote_namespace
, "refs/remotes/%s/", remote
->name
)
2121 return got_error_from_errno("asprintf");
2123 err
= got_ref_list(&my_refs
, repo
, NULL
, got_ref_cmp_by_name
, NULL
);
2127 TAILQ_FOREACH(re
, &my_refs
, entry
) {
2128 const char *refname
= got_ref_get_name(re
->ref
);
2129 const char *their_refname
;
2131 if (remote
->mirror_references
) {
2132 their_refname
= refname
;
2134 if (strncmp(refname
, remote_namespace
,
2135 strlen(remote_namespace
)) == 0) {
2136 if (strcmp(refname
+ strlen(remote_namespace
),
2139 if (asprintf(&local_refname
, "refs/heads/%s",
2140 refname
+ strlen(remote_namespace
)) == -1) {
2141 err
= got_error_from_errno("asprintf");
2144 } else if (strncmp(refname
, "refs/tags/", 10) != 0)
2147 their_refname
= local_refname
;
2150 TAILQ_FOREACH(pe
, their_refs
, entry
) {
2151 if (strcmp(their_refname
, pe
->path
) == 0)
2157 TAILQ_FOREACH(pe
, their_symrefs
, entry
) {
2158 if (strcmp(their_refname
, pe
->path
) == 0)
2164 err
= delete_missing_ref(re
->ref
, verbosity
, repo
);
2168 if (local_refname
) {
2169 struct got_reference
*ref
;
2170 err
= got_ref_open(&ref
, repo
, local_refname
, 1);
2172 if (err
->code
!= GOT_ERR_NOT_REF
)
2174 free(local_refname
);
2175 local_refname
= NULL
;
2178 err
= delete_missing_ref(ref
, verbosity
, repo
);
2181 unlock_err
= got_ref_unlock(ref
);
2183 if (unlock_err
&& err
== NULL
) {
2188 free(local_refname
);
2189 local_refname
= NULL
;
2193 free(remote_namespace
);
2194 free(local_refname
);
2198 static const struct got_error
*
2199 update_wanted_ref(const char *refname
, struct got_object_id
*id
,
2200 const char *remote_repo_name
, int verbosity
, struct got_repository
*repo
)
2202 const struct got_error
*err
, *unlock_err
;
2203 char *remote_refname
;
2204 struct got_reference
*ref
;
2206 if (strncmp("refs/", refname
, 5) == 0)
2209 if (asprintf(&remote_refname
, "refs/remotes/%s/%s",
2210 remote_repo_name
, refname
) == -1)
2211 return got_error_from_errno("asprintf");
2213 err
= got_ref_open(&ref
, repo
, remote_refname
, 1);
2215 if (err
->code
!= GOT_ERR_NOT_REF
)
2217 err
= create_ref(remote_refname
, id
, verbosity
, repo
);
2219 err
= update_ref(ref
, id
, 0, verbosity
, repo
);
2220 unlock_err
= got_ref_unlock(ref
);
2221 if (unlock_err
&& err
== NULL
)
2226 free(remote_refname
);
2230 static const struct got_error
*
2231 delete_ref(struct got_repository
*repo
, struct got_reference
*ref
)
2233 const struct got_error
*err
= NULL
;
2234 struct got_object_id
*id
= NULL
;
2235 char *id_str
= NULL
;
2238 if (got_ref_is_symbolic(ref
)) {
2239 target
= got_ref_get_symref_target(ref
);
2241 err
= got_ref_resolve(&id
, repo
, ref
);
2244 err
= got_object_id_str(&id_str
, id
);
2250 err
= got_ref_delete(ref
, repo
);
2254 printf("Deleted %s: %s\n", got_ref_get_name(ref
), target
);
2261 static const struct got_error
*
2262 delete_refs_for_remote(struct got_repository
*repo
, const char *remote_name
)
2264 const struct got_error
*err
= NULL
;
2265 struct got_reflist_head refs
;
2266 struct got_reflist_entry
*re
;
2271 if (asprintf(&prefix
, "refs/remotes/%s", remote_name
) == -1) {
2272 err
= got_error_from_errno("asprintf");
2275 err
= got_ref_list(&refs
, repo
, prefix
, got_ref_cmp_by_name
, NULL
);
2279 TAILQ_FOREACH(re
, &refs
, entry
)
2280 delete_ref(repo
, re
->ref
);
2282 got_ref_list_free(&refs
);
2286 static const struct got_error
*
2287 cmd_fetch(int argc
, char *argv
[])
2289 const struct got_error
*error
= NULL
, *unlock_err
;
2290 char *cwd
= NULL
, *repo_path
= NULL
;
2291 const char *remote_name
;
2292 char *proto
= NULL
, *host
= NULL
, *port
= NULL
;
2293 char *repo_name
= NULL
, *server_path
= NULL
;
2294 const struct got_remote_repo
*remotes
, *remote
= NULL
;
2296 char *id_str
= NULL
;
2297 struct got_repository
*repo
= NULL
;
2298 struct got_worktree
*worktree
= NULL
;
2299 const struct got_gotconfig
*repo_conf
= NULL
, *worktree_conf
= NULL
;
2300 struct got_pathlist_head refs
, symrefs
, wanted_branches
, wanted_refs
;
2301 struct got_pathlist_entry
*pe
;
2302 struct got_object_id
*pack_hash
= NULL
;
2303 int i
, ch
, fetchfd
= -1, fetchstatus
;
2304 pid_t fetchpid
= -1;
2305 struct got_fetch_progress_arg fpa
;
2306 int verbosity
= 0, fetch_all_branches
= 0, list_refs_only
= 0;
2307 int delete_refs
= 0, replace_tags
= 0, delete_remote
= 0;
2308 int *pack_fds
= NULL
;
2311 TAILQ_INIT(&symrefs
);
2312 TAILQ_INIT(&wanted_branches
);
2313 TAILQ_INIT(&wanted_refs
);
2315 while ((ch
= getopt(argc
, argv
, "ab:dlr:tvqR:X")) != -1) {
2318 fetch_all_branches
= 1;
2321 error
= got_pathlist_append(&wanted_branches
,
2333 repo_path
= realpath(optarg
, NULL
);
2334 if (repo_path
== NULL
)
2335 return got_error_from_errno2("realpath",
2337 got_path_strip_trailing_slashes(repo_path
);
2345 else if (verbosity
< 3)
2352 error
= got_pathlist_append(&wanted_refs
,
2368 if (fetch_all_branches
&& !TAILQ_EMPTY(&wanted_branches
))
2369 option_conflict('a', 'b');
2370 if (list_refs_only
) {
2371 if (!TAILQ_EMPTY(&wanted_branches
))
2372 option_conflict('l', 'b');
2373 if (fetch_all_branches
)
2374 option_conflict('l', 'a');
2376 option_conflict('l', 'd');
2378 option_conflict('l', 'X');
2380 if (delete_remote
) {
2381 if (fetch_all_branches
)
2382 option_conflict('X', 'a');
2383 if (!TAILQ_EMPTY(&wanted_branches
))
2384 option_conflict('X', 'b');
2386 option_conflict('X', 'd');
2388 option_conflict('X', 't');
2389 if (!TAILQ_EMPTY(&wanted_refs
))
2390 option_conflict('X', 'R');
2395 errx(1, "-X option requires a remote name");
2396 remote_name
= GOT_FETCH_DEFAULT_REMOTE_NAME
;
2397 } else if (argc
== 1)
2398 remote_name
= argv
[0];
2402 cwd
= getcwd(NULL
, 0);
2404 error
= got_error_from_errno("getcwd");
2408 error
= got_repo_pack_fds_open(&pack_fds
);
2412 if (repo_path
== NULL
) {
2413 error
= got_worktree_open(&worktree
, cwd
);
2414 if (error
&& error
->code
!= GOT_ERR_NOT_WORKTREE
)
2420 strdup(got_worktree_get_repo_path(worktree
));
2421 if (repo_path
== NULL
)
2422 error
= got_error_from_errno("strdup");
2426 repo_path
= strdup(cwd
);
2427 if (repo_path
== NULL
) {
2428 error
= got_error_from_errno("strdup");
2434 error
= got_repo_open(&repo
, repo_path
, NULL
, pack_fds
);
2438 if (delete_remote
) {
2439 error
= delete_refs_for_remote(repo
, remote_name
);
2440 goto done
; /* nothing else to do */
2444 worktree_conf
= got_worktree_get_gotconfig(worktree
);
2445 if (worktree_conf
) {
2446 got_gotconfig_get_remotes(&nremotes
, &remotes
,
2448 for (i
= 0; i
< nremotes
; i
++) {
2449 if (strcmp(remotes
[i
].name
, remote_name
) == 0) {
2450 remote
= &remotes
[i
];
2456 if (remote
== NULL
) {
2457 repo_conf
= got_repo_get_gotconfig(repo
);
2459 got_gotconfig_get_remotes(&nremotes
, &remotes
,
2461 for (i
= 0; i
< nremotes
; i
++) {
2462 if (strcmp(remotes
[i
].name
, remote_name
) == 0) {
2463 remote
= &remotes
[i
];
2469 if (remote
== NULL
) {
2470 got_repo_get_gitconfig_remotes(&nremotes
, &remotes
, repo
);
2471 for (i
= 0; i
< nremotes
; i
++) {
2472 if (strcmp(remotes
[i
].name
, remote_name
) == 0) {
2473 remote
= &remotes
[i
];
2478 if (remote
== NULL
) {
2479 error
= got_error_path(remote_name
, GOT_ERR_NO_REMOTE
);
2483 if (TAILQ_EMPTY(&wanted_branches
)) {
2484 if (!fetch_all_branches
)
2485 fetch_all_branches
= remote
->fetch_all_branches
;
2486 for (i
= 0; i
< remote
->nfetch_branches
; i
++) {
2487 got_pathlist_append(&wanted_branches
,
2488 remote
->fetch_branches
[i
], NULL
);
2491 if (TAILQ_EMPTY(&wanted_refs
)) {
2492 for (i
= 0; i
< remote
->nfetch_refs
; i
++) {
2493 got_pathlist_append(&wanted_refs
,
2494 remote
->fetch_refs
[i
], NULL
);
2498 error
= got_dial_parse_uri(&proto
, &host
, &port
, &server_path
,
2499 &repo_name
, remote
->fetch_url
);
2503 if (strcmp(proto
, "git") == 0) {
2505 if (pledge("stdio rpath wpath cpath fattr flock proc exec "
2506 "sendfd dns inet unveil", NULL
) == -1)
2509 } else if (strcmp(proto
, "git+ssh") == 0 ||
2510 strcmp(proto
, "ssh") == 0) {
2512 if (pledge("stdio rpath wpath cpath fattr flock proc exec "
2513 "sendfd unveil", NULL
) == -1)
2516 } else if (strcmp(proto
, "http") == 0 ||
2517 strcmp(proto
, "git+http") == 0) {
2518 error
= got_error_path(proto
, GOT_ERR_NOT_IMPL
);
2521 error
= got_error_path(proto
, GOT_ERR_BAD_PROTO
);
2525 error
= got_dial_apply_unveil(proto
);
2529 error
= apply_unveil(got_repo_get_path(repo
), 0, NULL
);
2534 printf("Connecting to \"%s\" %s%s%s\n", remote
->name
, host
,
2535 port
? ":" : "", port
? port
: "");
2537 error
= got_fetch_connect(&fetchpid
, &fetchfd
, proto
, host
, port
,
2538 server_path
, verbosity
);
2542 fpa
.last_scaled_size
[0] = '\0';
2543 fpa
.last_p_indexed
= -1;
2544 fpa
.last_p_resolved
= -1;
2545 fpa
.verbosity
= verbosity
;
2547 fpa
.create_configs
= 0;
2548 fpa
.configs_created
= 0;
2549 memset(&fpa
.config_info
, 0, sizeof(fpa
.config_info
));
2550 error
= got_fetch_pack(&pack_hash
, &refs
, &symrefs
, remote
->name
,
2551 remote
->mirror_references
, fetch_all_branches
, &wanted_branches
,
2552 &wanted_refs
, list_refs_only
, verbosity
, fetchfd
, repo
,
2553 fetch_progress
, &fpa
);
2557 if (list_refs_only
) {
2558 error
= list_remote_refs(&symrefs
, &refs
);
2562 if (pack_hash
== NULL
) {
2564 printf("Already up-to-date\n");
2565 } else if (verbosity
>= 0) {
2566 error
= got_object_id_str(&id_str
, pack_hash
);
2569 printf("\nFetched %s.pack\n", id_str
);
2574 /* Update references provided with the pack file. */
2575 TAILQ_FOREACH(pe
, &refs
, entry
) {
2576 const char *refname
= pe
->path
;
2577 struct got_object_id
*id
= pe
->data
;
2578 struct got_reference
*ref
;
2579 char *remote_refname
;
2581 if (is_wanted_ref(&wanted_refs
, refname
) &&
2582 !remote
->mirror_references
) {
2583 error
= update_wanted_ref(refname
, id
,
2584 remote
->name
, verbosity
, repo
);
2590 if (remote
->mirror_references
||
2591 strncmp("refs/tags/", refname
, 10) == 0) {
2592 error
= got_ref_open(&ref
, repo
, refname
, 1);
2594 if (error
->code
!= GOT_ERR_NOT_REF
)
2596 error
= create_ref(refname
, id
, verbosity
,
2601 error
= update_ref(ref
, id
, replace_tags
,
2603 unlock_err
= got_ref_unlock(ref
);
2604 if (unlock_err
&& error
== NULL
)
2610 } else if (strncmp("refs/heads/", refname
, 11) == 0) {
2611 if (asprintf(&remote_refname
, "refs/remotes/%s/%s",
2612 remote_name
, refname
+ 11) == -1) {
2613 error
= got_error_from_errno("asprintf");
2617 error
= got_ref_open(&ref
, repo
, remote_refname
, 1);
2619 if (error
->code
!= GOT_ERR_NOT_REF
)
2621 error
= create_ref(remote_refname
, id
,
2626 error
= update_ref(ref
, id
, replace_tags
,
2628 unlock_err
= got_ref_unlock(ref
);
2629 if (unlock_err
&& error
== NULL
)
2636 /* Also create a local branch if none exists yet. */
2637 error
= got_ref_open(&ref
, repo
, refname
, 1);
2639 if (error
->code
!= GOT_ERR_NOT_REF
)
2641 error
= create_ref(refname
, id
, verbosity
,
2646 unlock_err
= got_ref_unlock(ref
);
2647 if (unlock_err
&& error
== NULL
)
2654 error
= delete_missing_refs(&refs
, &symrefs
, remote
,
2660 if (!remote
->mirror_references
) {
2661 /* Update remote HEAD reference if the server provided one. */
2662 TAILQ_FOREACH(pe
, &symrefs
, entry
) {
2663 struct got_reference
*target_ref
;
2664 const char *refname
= pe
->path
;
2665 const char *target
= pe
->data
;
2666 char *remote_refname
= NULL
, *remote_target
= NULL
;
2668 if (strcmp(refname
, GOT_REF_HEAD
) != 0)
2671 if (strncmp("refs/heads/", target
, 11) != 0)
2674 if (asprintf(&remote_refname
, "refs/remotes/%s/%s",
2675 remote
->name
, refname
) == -1) {
2676 error
= got_error_from_errno("asprintf");
2679 if (asprintf(&remote_target
, "refs/remotes/%s/%s",
2680 remote
->name
, target
+ 11) == -1) {
2681 error
= got_error_from_errno("asprintf");
2682 free(remote_refname
);
2686 error
= got_ref_open(&target_ref
, repo
, remote_target
,
2689 free(remote_refname
);
2690 free(remote_target
);
2691 if (error
->code
== GOT_ERR_NOT_REF
) {
2697 error
= update_symref(remote_refname
, target_ref
,
2699 free(remote_refname
);
2700 free(remote_target
);
2701 got_ref_close(target_ref
);
2708 if (kill(fetchpid
, SIGTERM
) == -1)
2709 error
= got_error_from_errno("kill");
2710 if (waitpid(fetchpid
, &fetchstatus
, 0) == -1 && error
== NULL
)
2711 error
= got_error_from_errno("waitpid");
2713 if (fetchfd
!= -1 && close(fetchfd
) == -1 && error
== NULL
)
2714 error
= got_error_from_errno("close");
2716 const struct got_error
*close_err
= got_repo_close(repo
);
2721 got_worktree_close(worktree
);
2723 const struct got_error
*pack_err
=
2724 got_repo_pack_fds_close(pack_fds
);
2728 TAILQ_FOREACH(pe
, &refs
, entry
) {
2729 free((void *)pe
->path
);
2732 got_pathlist_free(&refs
);
2733 TAILQ_FOREACH(pe
, &symrefs
, entry
) {
2734 free((void *)pe
->path
);
2737 got_pathlist_free(&symrefs
);
2738 got_pathlist_free(&wanted_branches
);
2739 got_pathlist_free(&wanted_refs
);
2754 usage_checkout(void)
2756 fprintf(stderr
, "usage: %s checkout [-E] [-b branch] [-c commit] "
2757 "[-p prefix] [-q] repository-path [worktree-path]\n",
2763 show_worktree_base_ref_warning(void)
2765 fprintf(stderr
, "%s: warning: could not create a reference "
2766 "to the work tree's base commit; the commit could be "
2767 "garbage-collected by Git or 'gotadmin cleanup'; making the "
2768 "repository writable and running 'got update' will prevent this\n",
2772 struct got_checkout_progress_arg
{
2773 const char *worktree_path
;
2774 int had_base_commit_ref_error
;
2778 static const struct got_error
*
2779 checkout_progress(void *arg
, unsigned char status
, const char *path
)
2781 struct got_checkout_progress_arg
*a
= arg
;
2783 /* Base commit bump happens silently. */
2784 if (status
== GOT_STATUS_BUMP_BASE
)
2787 if (status
== GOT_STATUS_BASE_REF_ERR
) {
2788 a
->had_base_commit_ref_error
= 1;
2792 while (path
[0] == '/')
2795 if (a
->verbosity
>= 0)
2796 printf("%c %s/%s\n", status
, a
->worktree_path
, path
);
2801 static const struct got_error
*
2802 check_cancelled(void *arg
)
2804 if (sigint_received
|| sigpipe_received
)
2805 return got_error(GOT_ERR_CANCELLED
);
2809 static const struct got_error
*
2810 check_linear_ancestry(struct got_object_id
*commit_id
,
2811 struct got_object_id
*base_commit_id
, int allow_forwards_in_time_only
,
2812 struct got_repository
*repo
)
2814 const struct got_error
*err
= NULL
;
2815 struct got_object_id
*yca_id
;
2817 err
= got_commit_graph_find_youngest_common_ancestor(&yca_id
,
2818 commit_id
, base_commit_id
, 1, repo
, check_cancelled
, NULL
);
2823 return got_error(GOT_ERR_ANCESTRY
);
2826 * Require a straight line of history between the target commit
2827 * and the work tree's base commit.
2829 * Non-linear situations such as this require a rebase:
2831 * (commit) D F (base_commit)
2839 * 'got update' only handles linear cases:
2840 * Update forwards in time: A (base/yca) - B - C - D (commit)
2841 * Update backwards in time: D (base) - C - B - A (commit/yca)
2843 if (allow_forwards_in_time_only
) {
2844 if (got_object_id_cmp(base_commit_id
, yca_id
) != 0)
2845 return got_error(GOT_ERR_ANCESTRY
);
2846 } else if (got_object_id_cmp(commit_id
, yca_id
) != 0 &&
2847 got_object_id_cmp(base_commit_id
, yca_id
) != 0)
2848 return got_error(GOT_ERR_ANCESTRY
);
2854 static const struct got_error
*
2855 check_same_branch(struct got_object_id
*commit_id
,
2856 struct got_reference
*head_ref
, struct got_object_id
*yca_id
,
2857 struct got_repository
*repo
)
2859 const struct got_error
*err
= NULL
;
2860 struct got_commit_graph
*graph
= NULL
;
2861 struct got_object_id
*head_commit_id
= NULL
;
2862 int is_same_branch
= 0;
2864 err
= got_ref_resolve(&head_commit_id
, repo
, head_ref
);
2868 if (got_object_id_cmp(head_commit_id
, commit_id
) == 0) {
2872 if (yca_id
&& got_object_id_cmp(commit_id
, yca_id
) == 0) {
2877 err
= got_commit_graph_open(&graph
, "/", 1);
2881 err
= got_commit_graph_iter_start(graph
, head_commit_id
, repo
,
2882 check_cancelled
, NULL
);
2887 struct got_object_id
*id
;
2888 err
= got_commit_graph_iter_next(&id
, graph
, repo
,
2889 check_cancelled
, NULL
);
2891 if (err
->code
== GOT_ERR_ITER_COMPLETED
)
2897 if (yca_id
&& got_object_id_cmp(id
, yca_id
) == 0)
2899 if (got_object_id_cmp(id
, commit_id
) == 0) {
2907 got_commit_graph_close(graph
);
2908 free(head_commit_id
);
2909 if (!err
&& !is_same_branch
)
2910 err
= got_error(GOT_ERR_ANCESTRY
);
2914 static const struct got_error
*
2915 checkout_ancestry_error(struct got_reference
*ref
, const char *commit_id_str
)
2917 static char msg
[512];
2918 const char *branch_name
;
2920 if (got_ref_is_symbolic(ref
))
2921 branch_name
= got_ref_get_symref_target(ref
);
2923 branch_name
= got_ref_get_name(ref
);
2925 if (strncmp("refs/heads/", branch_name
, 11) == 0)
2928 snprintf(msg
, sizeof(msg
),
2929 "target commit is not contained in branch '%s'; "
2930 "the branch to use must be specified with -b; "
2931 "if necessary a new branch can be created for "
2932 "this commit with 'got branch -c %s BRANCH_NAME'",
2933 branch_name
, commit_id_str
);
2935 return got_error_msg(GOT_ERR_ANCESTRY
, msg
);
2938 static const struct got_error
*
2939 cmd_checkout(int argc
, char *argv
[])
2941 const struct got_error
*error
= NULL
;
2942 struct got_repository
*repo
= NULL
;
2943 struct got_reference
*head_ref
= NULL
, *ref
= NULL
;
2944 struct got_worktree
*worktree
= NULL
;
2945 char *repo_path
= NULL
;
2946 char *worktree_path
= NULL
;
2947 const char *path_prefix
= "";
2948 const char *branch_name
= GOT_REF_HEAD
, *refname
= NULL
;
2949 char *commit_id_str
= NULL
;
2950 struct got_object_id
*commit_id
= NULL
;
2952 int ch
, same_path_prefix
, allow_nonempty
= 0, verbosity
= 0;
2953 struct got_pathlist_head paths
;
2954 struct got_checkout_progress_arg cpa
;
2955 int *pack_fds
= NULL
;
2959 while ((ch
= getopt(argc
, argv
, "b:c:Ep:q")) != -1) {
2962 branch_name
= optarg
;
2965 commit_id_str
= strdup(optarg
);
2966 if (commit_id_str
== NULL
)
2967 return got_error_from_errno("strdup");
2973 path_prefix
= optarg
;
2988 if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd "
2989 "unveil", NULL
) == -1)
2993 char *base
, *dotgit
;
2995 repo_path
= realpath(argv
[0], NULL
);
2996 if (repo_path
== NULL
)
2997 return got_error_from_errno2("realpath", argv
[0]);
2998 cwd
= getcwd(NULL
, 0);
3000 error
= got_error_from_errno("getcwd");
3007 error
= got_path_basename(&base
, path
);
3010 dotgit
= strstr(base
, ".git");
3013 if (asprintf(&worktree_path
, "%s/%s", cwd
, base
) == -1) {
3014 error
= got_error_from_errno("asprintf");
3019 } else if (argc
== 2) {
3020 repo_path
= realpath(argv
[0], NULL
);
3021 if (repo_path
== NULL
) {
3022 error
= got_error_from_errno2("realpath", argv
[0]);
3025 worktree_path
= realpath(argv
[1], NULL
);
3026 if (worktree_path
== NULL
) {
3027 if (errno
!= ENOENT
) {
3028 error
= got_error_from_errno2("realpath",
3032 worktree_path
= strdup(argv
[1]);
3033 if (worktree_path
== NULL
) {
3034 error
= got_error_from_errno("strdup");
3041 got_path_strip_trailing_slashes(repo_path
);
3042 got_path_strip_trailing_slashes(worktree_path
);
3044 error
= got_repo_pack_fds_open(&pack_fds
);
3048 error
= got_repo_open(&repo
, repo_path
, NULL
, pack_fds
);
3052 /* Pre-create work tree path for unveil(2) */
3053 error
= got_path_mkdir(worktree_path
);
3055 if (!(error
->code
== GOT_ERR_ERRNO
&& errno
== EISDIR
) &&
3056 !(error
->code
== GOT_ERR_ERRNO
&& errno
== EEXIST
))
3058 if (!allow_nonempty
&&
3059 !got_path_dir_is_empty(worktree_path
)) {
3060 error
= got_error_path(worktree_path
,
3061 GOT_ERR_DIR_NOT_EMPTY
);
3066 error
= apply_unveil(got_repo_get_path(repo
), 0, worktree_path
);
3070 error
= got_ref_open(&head_ref
, repo
, branch_name
, 0);
3074 error
= got_worktree_init(worktree_path
, head_ref
, path_prefix
, repo
);
3075 if (error
!= NULL
&& !(error
->code
== GOT_ERR_ERRNO
&& errno
== EEXIST
))
3078 error
= got_worktree_open(&worktree
, worktree_path
);
3082 error
= got_worktree_match_path_prefix(&same_path_prefix
, worktree
,
3086 if (!same_path_prefix
) {
3087 error
= got_error(GOT_ERR_PATH_PREFIX
);
3091 if (commit_id_str
) {
3092 struct got_reflist_head refs
;
3094 error
= got_ref_list(&refs
, repo
, NULL
, got_ref_cmp_by_name
,
3098 error
= got_repo_match_object_id(&commit_id
, NULL
,
3099 commit_id_str
, GOT_OBJ_TYPE_COMMIT
, &refs
, repo
);
3100 got_ref_list_free(&refs
);
3103 error
= check_linear_ancestry(commit_id
,
3104 got_worktree_get_base_commit_id(worktree
), 0, repo
);
3105 if (error
!= NULL
) {
3106 if (error
->code
== GOT_ERR_ANCESTRY
) {
3107 error
= checkout_ancestry_error(
3108 head_ref
, commit_id_str
);
3112 error
= check_same_branch(commit_id
, head_ref
, NULL
, repo
);
3114 if (error
->code
== GOT_ERR_ANCESTRY
) {
3115 error
= checkout_ancestry_error(
3116 head_ref
, commit_id_str
);
3120 error
= got_worktree_set_base_commit_id(worktree
, repo
,
3124 /* Expand potentially abbreviated commit ID string. */
3125 free(commit_id_str
);
3126 error
= got_object_id_str(&commit_id_str
, commit_id
);
3130 commit_id
= got_object_id_dup(
3131 got_worktree_get_base_commit_id(worktree
));
3132 if (commit_id
== NULL
) {
3133 error
= got_error_from_errno("got_object_id_dup");
3136 error
= got_object_id_str(&commit_id_str
, commit_id
);
3141 error
= got_pathlist_append(&paths
, "", NULL
);
3144 cpa
.worktree_path
= worktree_path
;
3145 cpa
.had_base_commit_ref_error
= 0;
3146 cpa
.verbosity
= verbosity
;
3147 error
= got_worktree_checkout_files(worktree
, &paths
, repo
,
3148 checkout_progress
, &cpa
, check_cancelled
, NULL
);
3152 if (got_ref_is_symbolic(head_ref
)) {
3153 error
= got_ref_resolve_symbolic(&ref
, repo
, head_ref
);
3156 refname
= got_ref_get_name(ref
);
3158 refname
= got_ref_get_name(head_ref
);
3159 printf("Checked out %s: %s\n", refname
, commit_id_str
);
3160 printf("Now shut up and hack\n");
3161 if (cpa
.had_base_commit_ref_error
)
3162 show_worktree_base_ref_warning();
3165 const struct got_error
*pack_err
=
3166 got_repo_pack_fds_close(pack_fds
);
3171 got_ref_close(head_ref
);
3174 got_pathlist_free(&paths
);
3175 free(commit_id_str
);
3178 free(worktree_path
);
3183 struct got_update_progress_arg
{
3195 print_update_progress_stats(struct got_update_progress_arg
*upa
)
3197 if (!upa
->did_something
)
3200 if (upa
->conflicts
> 0)
3201 printf("Files with new merge conflicts: %d\n", upa
->conflicts
);
3202 if (upa
->obstructed
> 0)
3203 printf("File paths obstructed by a non-regular file: %d\n",
3205 if (upa
->not_updated
> 0)
3206 printf("Files not updated because of existing merge "
3207 "conflicts: %d\n", upa
->not_updated
);
3211 * The meaning of some status codes differs between merge-style operations and
3212 * update operations. For example, the ! status code means "file was missing"
3213 * if changes were merged into the work tree, and "missing file was restored"
3214 * if the work tree was updated. This function should be used by any operation
3215 * which merges changes into the work tree without updating the work tree.
3218 print_merge_progress_stats(struct got_update_progress_arg
*upa
)
3220 if (!upa
->did_something
)
3223 if (upa
->conflicts
> 0)
3224 printf("Files with new merge conflicts: %d\n", upa
->conflicts
);
3225 if (upa
->obstructed
> 0)
3226 printf("File paths obstructed by a non-regular file: %d\n",
3228 if (upa
->missing
> 0)
3229 printf("Files which had incoming changes but could not be "
3230 "found in the work tree: %d\n", upa
->missing
);
3231 if (upa
->not_deleted
> 0)
3232 printf("Files not deleted due to differences in deleted "
3233 "content: %d\n", upa
->not_deleted
);
3234 if (upa
->unversioned
> 0)
3235 printf("Files not merged because an unversioned file was "
3236 "found in the work tree: %d\n", upa
->unversioned
);
3242 fprintf(stderr
, "usage: %s update [-b branch] [-c commit] [-q] "
3248 static const struct got_error
*
3249 update_progress(void *arg
, unsigned char status
, const char *path
)
3251 struct got_update_progress_arg
*upa
= arg
;
3253 if (status
== GOT_STATUS_EXISTS
||
3254 status
== GOT_STATUS_BASE_REF_ERR
)
3257 upa
->did_something
= 1;
3259 /* Base commit bump happens silently. */
3260 if (status
== GOT_STATUS_BUMP_BASE
)
3263 if (status
== GOT_STATUS_CONFLICT
)
3265 if (status
== GOT_STATUS_OBSTRUCTED
)
3267 if (status
== GOT_STATUS_CANNOT_UPDATE
)
3269 if (status
== GOT_STATUS_MISSING
)
3271 if (status
== GOT_STATUS_CANNOT_DELETE
)
3273 if (status
== GOT_STATUS_UNVERSIONED
)
3276 while (path
[0] == '/')
3278 if (upa
->verbosity
>= 0)
3279 printf("%c %s\n", status
, path
);
3284 static const struct got_error
*
3285 switch_head_ref(struct got_reference
*head_ref
,
3286 struct got_object_id
*commit_id
, struct got_worktree
*worktree
,
3287 struct got_repository
*repo
)
3289 const struct got_error
*err
= NULL
;
3291 int ref_has_moved
= 0;
3293 /* Trivial case: switching between two different references. */
3294 if (strcmp(got_ref_get_name(head_ref
),
3295 got_worktree_get_head_ref_name(worktree
)) != 0) {
3296 printf("Switching work tree from %s to %s\n",
3297 got_worktree_get_head_ref_name(worktree
),
3298 got_ref_get_name(head_ref
));
3299 return got_worktree_set_head_ref(worktree
, head_ref
);
3302 err
= check_linear_ancestry(commit_id
,
3303 got_worktree_get_base_commit_id(worktree
), 0, repo
);
3305 if (err
->code
!= GOT_ERR_ANCESTRY
)
3312 /* Switching to a rebased branch with the same reference name. */
3313 err
= got_object_id_str(&base_id_str
,
3314 got_worktree_get_base_commit_id(worktree
));
3317 printf("Reference %s now points at a different branch\n",
3318 got_worktree_get_head_ref_name(worktree
));
3319 printf("Switching work tree from %s to %s\n", base_id_str
,
3320 got_worktree_get_head_ref_name(worktree
));
3324 static const struct got_error
*
3325 check_rebase_or_histedit_in_progress(struct got_worktree
*worktree
)
3327 const struct got_error
*err
;
3330 err
= got_worktree_rebase_in_progress(&in_progress
, worktree
);
3334 return got_error(GOT_ERR_REBASING
);
3336 err
= got_worktree_histedit_in_progress(&in_progress
, worktree
);
3340 return got_error(GOT_ERR_HISTEDIT_BUSY
);
3345 static const struct got_error
*
3346 check_merge_in_progress(struct got_worktree
*worktree
,
3347 struct got_repository
*repo
)
3349 const struct got_error
*err
;
3352 err
= got_worktree_merge_in_progress(&in_progress
, worktree
, repo
);
3356 return got_error(GOT_ERR_MERGE_BUSY
);
3361 static const struct got_error
*
3362 get_worktree_paths_from_argv(struct got_pathlist_head
*paths
, int argc
,
3363 char *argv
[], struct got_worktree
*worktree
)
3365 const struct got_error
*err
= NULL
;
3367 struct got_pathlist_entry
*new;
3373 return got_error_from_errno("strdup");
3374 return got_pathlist_append(paths
, path
, NULL
);
3377 for (i
= 0; i
< argc
; i
++) {
3378 err
= got_worktree_resolve_path(&path
, worktree
, argv
[i
]);
3381 err
= got_pathlist_insert(&new, paths
, path
, NULL
);
3382 if (err
|| new == NULL
/* duplicate */) {
3392 static const struct got_error
*
3393 wrap_not_worktree_error(const struct got_error
*orig_err
,
3394 const char *cmdname
, const char *path
)
3396 const struct got_error
*err
;
3397 struct got_repository
*repo
;
3398 static char msg
[512];
3399 int *pack_fds
= NULL
;
3401 err
= got_repo_pack_fds_open(&pack_fds
);
3405 err
= got_repo_open(&repo
, path
, NULL
, pack_fds
);
3409 snprintf(msg
, sizeof(msg
),
3410 "'got %s' needs a work tree in addition to a git repository\n"
3411 "Work trees can be checked out from this Git repository with "
3413 "The got(1) manual page contains more information.", cmdname
);
3414 err
= got_error_msg(GOT_ERR_NOT_WORKTREE
, msg
);
3415 got_repo_close(repo
);
3417 const struct got_error
*pack_err
=
3418 got_repo_pack_fds_close(pack_fds
);
3425 static const struct got_error
*
3426 cmd_update(int argc
, char *argv
[])
3428 const struct got_error
*error
= NULL
;
3429 struct got_repository
*repo
= NULL
;
3430 struct got_worktree
*worktree
= NULL
;
3431 char *worktree_path
= NULL
;
3432 struct got_object_id
*commit_id
= NULL
;
3433 char *commit_id_str
= NULL
;
3434 const char *branch_name
= NULL
;
3435 struct got_reference
*head_ref
= NULL
;
3436 struct got_pathlist_head paths
;
3437 struct got_pathlist_entry
*pe
;
3438 int ch
, verbosity
= 0;
3439 struct got_update_progress_arg upa
;
3440 int *pack_fds
= NULL
;
3444 while ((ch
= getopt(argc
, argv
, "b:c:q")) != -1) {
3447 branch_name
= optarg
;
3450 commit_id_str
= strdup(optarg
);
3451 if (commit_id_str
== NULL
)
3452 return got_error_from_errno("strdup");
3467 if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd "
3468 "unveil", NULL
) == -1)
3471 worktree_path
= getcwd(NULL
, 0);
3472 if (worktree_path
== NULL
) {
3473 error
= got_error_from_errno("getcwd");
3477 error
= got_repo_pack_fds_open(&pack_fds
);
3481 error
= got_worktree_open(&worktree
, worktree_path
);
3483 if (error
->code
== GOT_ERR_NOT_WORKTREE
)
3484 error
= wrap_not_worktree_error(error
, "update",
3489 error
= check_rebase_or_histedit_in_progress(worktree
);
3493 error
= got_repo_open(&repo
, got_worktree_get_repo_path(worktree
),
3498 error
= apply_unveil(got_repo_get_path(repo
), 0,
3499 got_worktree_get_root_path(worktree
));
3503 error
= check_merge_in_progress(worktree
, repo
);
3507 error
= get_worktree_paths_from_argv(&paths
, argc
, argv
, worktree
);
3511 error
= got_ref_open(&head_ref
, repo
, branch_name
? branch_name
:
3512 got_worktree_get_head_ref_name(worktree
), 0);
3515 if (commit_id_str
== NULL
) {
3516 error
= got_ref_resolve(&commit_id
, repo
, head_ref
);
3519 error
= got_object_id_str(&commit_id_str
, commit_id
);
3523 struct got_reflist_head refs
;
3525 error
= got_ref_list(&refs
, repo
, NULL
, got_ref_cmp_by_name
,
3529 error
= got_repo_match_object_id(&commit_id
, NULL
,
3530 commit_id_str
, GOT_OBJ_TYPE_COMMIT
, &refs
, repo
);
3531 got_ref_list_free(&refs
);
3532 free(commit_id_str
);
3533 commit_id_str
= NULL
;
3536 error
= got_object_id_str(&commit_id_str
, commit_id
);
3542 struct got_object_id
*head_commit_id
;
3543 TAILQ_FOREACH(pe
, &paths
, entry
) {
3544 if (pe
->path_len
== 0)
3546 error
= got_error_msg(GOT_ERR_BAD_PATH
,
3547 "switching between branches requires that "
3548 "the entire work tree gets updated");
3551 error
= got_ref_resolve(&head_commit_id
, repo
, head_ref
);
3554 error
= check_linear_ancestry(commit_id
, head_commit_id
, 0,
3556 free(head_commit_id
);
3559 error
= check_same_branch(commit_id
, head_ref
, NULL
, repo
);
3562 error
= switch_head_ref(head_ref
, commit_id
, worktree
, repo
);
3566 error
= check_linear_ancestry(commit_id
,
3567 got_worktree_get_base_commit_id(worktree
), 0, repo
);
3568 if (error
!= NULL
) {
3569 if (error
->code
== GOT_ERR_ANCESTRY
)
3570 error
= got_error(GOT_ERR_BRANCH_MOVED
);
3573 error
= check_same_branch(commit_id
, head_ref
, NULL
, repo
);
3578 if (got_object_id_cmp(got_worktree_get_base_commit_id(worktree
),
3580 error
= got_worktree_set_base_commit_id(worktree
, repo
,
3586 memset(&upa
, 0, sizeof(upa
));
3587 upa
.verbosity
= verbosity
;
3588 error
= got_worktree_checkout_files(worktree
, &paths
, repo
,
3589 update_progress
, &upa
, check_cancelled
, NULL
);
3593 if (upa
.did_something
) {
3594 printf("Updated to %s: %s\n",
3595 got_worktree_get_head_ref_name(worktree
), commit_id_str
);
3597 printf("Already up-to-date\n");
3599 print_update_progress_stats(&upa
);
3602 const struct got_error
*pack_err
=
3603 got_repo_pack_fds_close(pack_fds
);
3607 free(worktree_path
);
3608 TAILQ_FOREACH(pe
, &paths
, entry
)
3609 free((char *)pe
->path
);
3610 got_pathlist_free(&paths
);
3612 free(commit_id_str
);
3616 static const struct got_error
*
3617 diff_blobs(struct got_object_id
*blob_id1
, struct got_object_id
*blob_id2
,
3618 const char *path
, int diff_context
, int ignore_whitespace
,
3619 int force_text_diff
, struct got_repository
*repo
, FILE *outfile
)
3621 const struct got_error
*err
= NULL
;
3622 struct got_blob_object
*blob1
= NULL
, *blob2
= NULL
;
3623 FILE *f1
= NULL
, *f2
= NULL
;
3624 int fd1
= -1, fd2
= -1;
3626 fd1
= got_opentempfd();
3628 return got_error_from_errno("got_opentempfd");
3629 fd2
= got_opentempfd();
3631 err
= got_error_from_errno("got_opentempfd");
3636 err
= got_object_open_as_blob(&blob1
, repo
, blob_id1
, 8192,
3642 err
= got_object_open_as_blob(&blob2
, repo
, blob_id2
, 8192, fd2
);
3646 f1
= got_opentemp();
3648 err
= got_error_from_errno("got_opentemp");
3651 f2
= got_opentemp();
3653 err
= got_error_from_errno("got_opentemp");
3657 while (path
[0] == '/')
3659 err
= got_diff_blob(NULL
, NULL
, blob1
, blob2
, f1
, f2
, path
, path
,
3660 GOT_DIFF_ALGORITHM_PATIENCE
, diff_context
, ignore_whitespace
,
3661 force_text_diff
, outfile
);
3663 if (fd1
!= -1 && close(fd1
) == -1 && err
== NULL
)
3664 err
= got_error_from_errno("close");
3666 got_object_blob_close(blob1
);
3667 if (fd2
!= -1 && close(fd2
) == -1 && err
== NULL
)
3668 err
= got_error_from_errno("close");
3669 got_object_blob_close(blob2
);
3670 if (f1
&& fclose(f1
) == EOF
&& err
== NULL
)
3671 err
= got_error_from_errno("fclose");
3672 if (f2
&& fclose(f2
) == EOF
&& err
== NULL
)
3673 err
= got_error_from_errno("fclose");
3677 static const struct got_error
*
3678 diff_trees(struct got_object_id
*tree_id1
, struct got_object_id
*tree_id2
,
3679 const char *path
, int diff_context
, int ignore_whitespace
,
3680 int force_text_diff
, struct got_repository
*repo
, FILE *outfile
)
3682 const struct got_error
*err
= NULL
;
3683 struct got_tree_object
*tree1
= NULL
, *tree2
= NULL
;
3684 struct got_diff_blob_output_unidiff_arg arg
;
3685 FILE *f1
= NULL
, *f2
= NULL
;
3686 int fd1
= -1, fd2
= -1;
3689 err
= got_object_open_as_tree(&tree1
, repo
, tree_id1
);
3692 fd1
= got_opentempfd();
3694 err
= got_error_from_errno("got_opentempfd");
3699 err
= got_object_open_as_tree(&tree2
, repo
, tree_id2
);
3703 f1
= got_opentemp();
3705 err
= got_error_from_errno("got_opentemp");
3709 f2
= got_opentemp();
3711 err
= got_error_from_errno("got_opentemp");
3714 fd2
= got_opentempfd();
3716 err
= got_error_from_errno("got_opentempfd");
3719 arg
.diff_context
= diff_context
;
3720 arg
.ignore_whitespace
= ignore_whitespace
;
3721 arg
.force_text_diff
= force_text_diff
;
3722 arg
.diff_algo
= GOT_DIFF_ALGORITHM_PATIENCE
;
3723 arg
.outfile
= outfile
;
3724 arg
.line_offsets
= NULL
;
3726 while (path
[0] == '/')
3728 err
= got_diff_tree(tree1
, tree2
, f1
, f2
, fd1
, fd2
, path
, path
, repo
,
3729 got_diff_blob_output_unidiff
, &arg
, 1);
3732 got_object_tree_close(tree1
);
3734 got_object_tree_close(tree2
);
3735 if (f1
&& fclose(f1
) == EOF
&& err
== NULL
)
3736 err
= got_error_from_errno("fclose");
3737 if (f2
&& fclose(f2
) == EOF
&& err
== NULL
)
3738 err
= got_error_from_errno("fclose");
3739 if (fd1
!= -1 && close(fd1
) == -1 && err
== NULL
)
3740 err
= got_error_from_errno("close");
3741 if (fd2
!= -1 && close(fd2
) == -1 && err
== NULL
)
3742 err
= got_error_from_errno("close");
3746 static const struct got_error
*
3747 get_changed_paths(struct got_pathlist_head
*paths
,
3748 struct got_commit_object
*commit
, struct got_repository
*repo
)
3750 const struct got_error
*err
= NULL
;
3751 struct got_object_id
*tree_id1
= NULL
, *tree_id2
= NULL
;
3752 struct got_tree_object
*tree1
= NULL
, *tree2
= NULL
;
3753 struct got_object_qid
*qid
;
3755 qid
= STAILQ_FIRST(got_object_commit_get_parent_ids(commit
));
3757 struct got_commit_object
*pcommit
;
3758 err
= got_object_open_as_commit(&pcommit
, repo
,
3763 tree_id1
= got_object_id_dup(
3764 got_object_commit_get_tree_id(pcommit
));
3765 if (tree_id1
== NULL
) {
3766 got_object_commit_close(pcommit
);
3767 return got_error_from_errno("got_object_id_dup");
3769 got_object_commit_close(pcommit
);
3774 err
= got_object_open_as_tree(&tree1
, repo
, tree_id1
);
3779 tree_id2
= got_object_commit_get_tree_id(commit
);
3780 err
= got_object_open_as_tree(&tree2
, repo
, tree_id2
);
3784 err
= got_diff_tree(tree1
, tree2
, NULL
, NULL
, -1, -1, "", "", repo
,
3785 got_diff_tree_collect_changed_paths
, paths
, 0);
3788 got_object_tree_close(tree1
);
3790 got_object_tree_close(tree2
);
3795 static const struct got_error
*
3796 print_patch(struct got_commit_object
*commit
, struct got_object_id
*id
,
3797 const char *path
, int diff_context
, struct got_repository
*repo
,
3800 const struct got_error
*err
= NULL
;
3801 struct got_commit_object
*pcommit
= NULL
;
3802 char *id_str1
= NULL
, *id_str2
= NULL
;
3803 struct got_object_id
*obj_id1
= NULL
, *obj_id2
= NULL
;
3804 struct got_object_qid
*qid
;
3806 qid
= STAILQ_FIRST(got_object_commit_get_parent_ids(commit
));
3808 err
= got_object_open_as_commit(&pcommit
, repo
,
3812 err
= got_object_id_str(&id_str1
, &qid
->id
);
3817 err
= got_object_id_str(&id_str2
, id
);
3821 if (path
&& path
[0] != '\0') {
3823 err
= got_object_id_by_path(&obj_id2
, repo
, commit
, path
);
3827 err
= got_object_id_by_path(&obj_id1
, repo
,
3830 if (err
->code
!= GOT_ERR_NO_TREE_ENTRY
) {
3836 err
= got_object_get_type(&obj_type
, repo
, obj_id2
);
3842 "diff %s %s\n", id_str1
? id_str1
: "/dev/null", id_str2
);
3843 fprintf(outfile
, "commit - %s\n",
3844 id_str1
? id_str1
: "/dev/null");
3845 fprintf(outfile
, "commit + %s\n", id_str2
);
3847 case GOT_OBJ_TYPE_BLOB
:
3848 err
= diff_blobs(obj_id1
, obj_id2
, path
, diff_context
,
3849 0, 0, repo
, outfile
);
3851 case GOT_OBJ_TYPE_TREE
:
3852 err
= diff_trees(obj_id1
, obj_id2
, path
, diff_context
,
3853 0, 0, repo
, outfile
);
3856 err
= got_error(GOT_ERR_OBJ_TYPE
);
3862 obj_id2
= got_object_commit_get_tree_id(commit
);
3864 obj_id1
= got_object_commit_get_tree_id(pcommit
);
3866 "diff %s %s\n", id_str1
? id_str1
: "/dev/null", id_str2
);
3867 fprintf(outfile
, "commit - %s\n",
3868 id_str1
? id_str1
: "/dev/null");
3869 fprintf(outfile
, "commit + %s\n", id_str2
);
3870 err
= diff_trees(obj_id1
, obj_id2
, "", diff_context
, 0, 0,
3877 got_object_commit_close(pcommit
);
3882 get_datestr(time_t *time
, char *datebuf
)
3884 struct tm mytm
, *tm
;
3887 tm
= gmtime_r(time
, &mytm
);
3890 s
= asctime_r(tm
, datebuf
);
3893 p
= strchr(s
, '\n');
3899 static const struct got_error
*
3900 match_commit(int *have_match
, struct got_object_id
*id
,
3901 struct got_commit_object
*commit
, regex_t
*regex
)
3903 const struct got_error
*err
= NULL
;
3904 regmatch_t regmatch
;
3905 char *id_str
= NULL
, *logmsg
= NULL
;
3909 err
= got_object_id_str(&id_str
, id
);
3913 err
= got_object_commit_get_logmsg(&logmsg
, commit
);
3917 if (regexec(regex
, got_object_commit_get_author(commit
), 1,
3918 ®match
, 0) == 0 ||
3919 regexec(regex
, got_object_commit_get_committer(commit
), 1,
3920 ®match
, 0) == 0 ||
3921 regexec(regex
, id_str
, 1, ®match
, 0) == 0 ||
3922 regexec(regex
, logmsg
, 1, ®match
, 0) == 0)
3931 match_changed_paths(int *have_match
, struct got_pathlist_head
*changed_paths
,
3934 regmatch_t regmatch
;
3935 struct got_pathlist_entry
*pe
;
3939 TAILQ_FOREACH(pe
, changed_paths
, entry
) {
3940 if (regexec(regex
, pe
->path
, 1, ®match
, 0) == 0) {
3947 static const struct got_error
*
3948 match_patch(int *have_match
, struct got_commit_object
*commit
,
3949 struct got_object_id
*id
, const char *path
, int diff_context
,
3950 struct got_repository
*repo
, regex_t
*regex
, FILE *f
)
3952 const struct got_error
*err
= NULL
;
3954 size_t linesize
= 0;
3956 regmatch_t regmatch
;
3960 err
= got_opentemp_truncate(f
);
3964 err
= print_patch(commit
, id
, path
, diff_context
, repo
, f
);
3968 if (fseeko(f
, 0L, SEEK_SET
) == -1) {
3969 err
= got_error_from_errno("fseeko");
3973 while ((linelen
= getline(&line
, &linesize
, f
)) != -1) {
3974 if (regexec(regex
, line
, 1, ®match
, 0) == 0) {
3984 #define GOT_COMMIT_SEP_STR "-----------------------------------------------\n"
3986 static const struct got_error
*
3987 build_refs_str(char **refs_str
, struct got_reflist_head
*refs
,
3988 struct got_object_id
*id
, struct got_repository
*repo
,
3991 static const struct got_error
*err
= NULL
;
3992 struct got_reflist_entry
*re
;
3998 TAILQ_FOREACH(re
, refs
, entry
) {
3999 struct got_tag_object
*tag
= NULL
;
4000 struct got_object_id
*ref_id
;
4003 name
= got_ref_get_name(re
->ref
);
4004 if (strcmp(name
, GOT_REF_HEAD
) == 0)
4006 if (strncmp(name
, "refs/", 5) == 0)
4008 if (strncmp(name
, "got/", 4) == 0)
4010 if (strncmp(name
, "heads/", 6) == 0)
4012 if (strncmp(name
, "remotes/", 8) == 0) {
4016 s
= strstr(name
, "/" GOT_REF_HEAD
);
4017 if (s
!= NULL
&& s
[strlen(s
)] == '\0')
4020 err
= got_ref_resolve(&ref_id
, repo
, re
->ref
);
4023 if (strncmp(name
, "tags/", 5) == 0) {
4024 err
= got_object_open_as_tag(&tag
, repo
, ref_id
);
4026 if (err
->code
!= GOT_ERR_OBJ_TYPE
) {
4030 /* Ref points at something other than a tag. */
4035 cmp
= got_object_id_cmp(tag
?
4036 got_object_tag_get_object_id(tag
) : ref_id
, id
);
4039 got_object_tag_close(tag
);
4043 if (asprintf(refs_str
, "%s%s%s", s
? s
: "",
4044 s
? ", " : "", name
) == -1) {
4045 err
= got_error_from_errno("asprintf");
4056 static const struct got_error
*
4057 print_commit_oneline(struct got_commit_object
*commit
, struct got_object_id
*id
,
4058 struct got_repository
*repo
, struct got_reflist_object_id_map
*refs_idmap
)
4060 const struct got_error
*err
= NULL
;
4061 char *ref_str
= NULL
, *id_str
= NULL
, *logmsg0
= NULL
;
4062 char *comma
, *s
, *nl
;
4063 struct got_reflist_head
*refs
;
4064 char datebuf
[12]; /* YYYY-MM-DD + SPACE + NUL */
4066 time_t committer_time
;
4068 refs
= got_reflist_object_id_map_lookup(refs_idmap
, id
);
4070 err
= build_refs_str(&ref_str
, refs
, id
, repo
, 1);
4074 /* Display the first matching ref only. */
4075 if (ref_str
&& (comma
= strchr(ref_str
, ',')) != NULL
)
4079 if (ref_str
== NULL
) {
4080 err
= got_object_id_str(&id_str
, id
);
4085 committer_time
= got_object_commit_get_committer_time(commit
);
4086 if (gmtime_r(&committer_time
, &tm
) == NULL
) {
4087 err
= got_error_from_errno("gmtime_r");
4090 if (strftime(datebuf
, sizeof(datebuf
), "%G-%m-%d ", &tm
) == 0) {
4091 err
= got_error(GOT_ERR_NO_SPACE
);
4095 err
= got_object_commit_get_logmsg(&logmsg0
, commit
);
4100 while (isspace((unsigned char)s
[0]))
4103 nl
= strchr(s
, '\n');
4109 printf("%s%-7s %s\n", datebuf
, ref_str
, s
);
4111 printf("%s%.7s %s\n", datebuf
, id_str
, s
);
4113 if (fflush(stdout
) != 0 && err
== NULL
)
4114 err
= got_error_from_errno("fflush");
4122 static const struct got_error
*
4123 print_commit(struct got_commit_object
*commit
, struct got_object_id
*id
,
4124 struct got_repository
*repo
, const char *path
,
4125 struct got_pathlist_head
*changed_paths
, int show_patch
,
4126 int diff_context
, struct got_reflist_object_id_map
*refs_idmap
,
4127 const char *custom_refs_str
)
4129 const struct got_error
*err
= NULL
;
4130 char *id_str
, *datestr
, *logmsg0
, *logmsg
, *line
;
4132 time_t committer_time
;
4133 const char *author
, *committer
;
4134 char *refs_str
= NULL
;
4136 err
= got_object_id_str(&id_str
, id
);
4140 if (custom_refs_str
== NULL
) {
4141 struct got_reflist_head
*refs
;
4142 refs
= got_reflist_object_id_map_lookup(refs_idmap
, id
);
4144 err
= build_refs_str(&refs_str
, refs
, id
, repo
, 0);
4150 printf(GOT_COMMIT_SEP_STR
);
4151 if (custom_refs_str
)
4152 printf("commit %s (%s)\n", id_str
, custom_refs_str
);
4154 printf("commit %s%s%s%s\n", id_str
, refs_str
? " (" : "",
4155 refs_str
? refs_str
: "", refs_str
? ")" : "");
4160 printf("from: %s\n", got_object_commit_get_author(commit
));
4161 committer_time
= got_object_commit_get_committer_time(commit
);
4162 datestr
= get_datestr(&committer_time
, datebuf
);
4164 printf("date: %s UTC\n", datestr
);
4165 author
= got_object_commit_get_author(commit
);
4166 committer
= got_object_commit_get_committer(commit
);
4167 if (strcmp(author
, committer
) != 0)
4168 printf("via: %s\n", committer
);
4169 if (got_object_commit_get_nparents(commit
) > 1) {
4170 const struct got_object_id_queue
*parent_ids
;
4171 struct got_object_qid
*qid
;
4173 parent_ids
= got_object_commit_get_parent_ids(commit
);
4174 STAILQ_FOREACH(qid
, parent_ids
, entry
) {
4175 err
= got_object_id_str(&id_str
, &qid
->id
);
4178 printf("parent %d: %s\n", n
++, id_str
);
4184 err
= got_object_commit_get_logmsg(&logmsg0
, commit
);
4190 line
= strsep(&logmsg
, "\n");
4192 printf(" %s\n", line
);
4196 if (changed_paths
) {
4197 struct got_pathlist_entry
*pe
;
4198 TAILQ_FOREACH(pe
, changed_paths
, entry
) {
4199 struct got_diff_changed_path
*cp
= pe
->data
;
4200 printf(" %c %s\n", cp
->status
, pe
->path
);
4205 err
= print_patch(commit
, id
, path
, diff_context
, repo
, stdout
);
4210 if (fflush(stdout
) != 0 && err
== NULL
)
4211 err
= got_error_from_errno("fflush");
4218 static const struct got_error
*
4219 print_commits(struct got_object_id
*root_id
, struct got_object_id
*end_id
,
4220 struct got_repository
*repo
, const char *path
, int show_changed_paths
,
4221 int show_patch
, const char *search_pattern
, int diff_context
, int limit
,
4222 int log_branches
, int reverse_display_order
,
4223 struct got_reflist_object_id_map
*refs_idmap
, int one_line
,
4226 const struct got_error
*err
;
4227 struct got_commit_graph
*graph
;
4230 struct got_object_id_queue reversed_commits
;
4231 struct got_object_qid
*qid
;
4232 struct got_commit_object
*commit
;
4233 struct got_pathlist_head changed_paths
;
4234 struct got_pathlist_entry
*pe
;
4236 STAILQ_INIT(&reversed_commits
);
4237 TAILQ_INIT(&changed_paths
);
4239 if (search_pattern
&& regcomp(®ex
, search_pattern
,
4240 REG_EXTENDED
| REG_NOSUB
| REG_NEWLINE
))
4241 return got_error_msg(GOT_ERR_REGEX
, search_pattern
);
4243 err
= got_commit_graph_open(&graph
, path
, !log_branches
);
4246 err
= got_commit_graph_iter_start(graph
, root_id
, repo
,
4247 check_cancelled
, NULL
);
4251 struct got_object_id
*id
;
4253 if (sigint_received
|| sigpipe_received
)
4256 err
= got_commit_graph_iter_next(&id
, graph
, repo
,
4257 check_cancelled
, NULL
);
4259 if (err
->code
== GOT_ERR_ITER_COMPLETED
)
4266 err
= got_object_open_as_commit(&commit
, repo
, id
);
4270 if (show_changed_paths
&& !reverse_display_order
) {
4271 err
= get_changed_paths(&changed_paths
, commit
, repo
);
4276 if (search_pattern
) {
4277 err
= match_commit(&have_match
, id
, commit
, ®ex
);
4279 got_object_commit_close(commit
);
4282 if (have_match
== 0 && show_changed_paths
)
4283 match_changed_paths(&have_match
,
4284 &changed_paths
, ®ex
);
4285 if (have_match
== 0 && show_patch
) {
4286 err
= match_patch(&have_match
, commit
, id
,
4287 path
, diff_context
, repo
, ®ex
,
4292 if (have_match
== 0) {
4293 got_object_commit_close(commit
);
4294 TAILQ_FOREACH(pe
, &changed_paths
, entry
) {
4295 free((char *)pe
->path
);
4298 got_pathlist_free(&changed_paths
);
4303 if (reverse_display_order
) {
4304 err
= got_object_qid_alloc(&qid
, id
);
4307 STAILQ_INSERT_HEAD(&reversed_commits
, qid
, entry
);
4308 got_object_commit_close(commit
);
4311 err
= print_commit_oneline(commit
, id
,
4314 err
= print_commit(commit
, id
, repo
, path
,
4315 show_changed_paths
? &changed_paths
: NULL
,
4316 show_patch
, diff_context
, refs_idmap
, NULL
);
4317 got_object_commit_close(commit
);
4321 if ((limit
&& --limit
== 0) ||
4322 (end_id
&& got_object_id_cmp(id
, end_id
) == 0))
4325 TAILQ_FOREACH(pe
, &changed_paths
, entry
) {
4326 free((char *)pe
->path
);
4329 got_pathlist_free(&changed_paths
);
4331 if (reverse_display_order
) {
4332 STAILQ_FOREACH(qid
, &reversed_commits
, entry
) {
4333 err
= got_object_open_as_commit(&commit
, repo
,
4337 if (show_changed_paths
) {
4338 err
= get_changed_paths(&changed_paths
,
4344 err
= print_commit_oneline(commit
, &qid
->id
,
4347 err
= print_commit(commit
, &qid
->id
, repo
, path
,
4348 show_changed_paths
? &changed_paths
: NULL
,
4349 show_patch
, diff_context
, refs_idmap
, NULL
);
4350 got_object_commit_close(commit
);
4353 TAILQ_FOREACH(pe
, &changed_paths
, entry
) {
4354 free((char *)pe
->path
);
4357 got_pathlist_free(&changed_paths
);
4361 while (!STAILQ_EMPTY(&reversed_commits
)) {
4362 qid
= STAILQ_FIRST(&reversed_commits
);
4363 STAILQ_REMOVE_HEAD(&reversed_commits
, entry
);
4364 got_object_qid_free(qid
);
4366 TAILQ_FOREACH(pe
, &changed_paths
, entry
) {
4367 free((char *)pe
->path
);
4370 got_pathlist_free(&changed_paths
);
4373 got_commit_graph_close(graph
);
4380 fprintf(stderr
, "usage: %s log [-b] [-p] [-P] [-s] [-c commit] "
4381 "[-C number] [ -l N ] [-x commit] [-S search-pattern] "
4382 "[-r repository-path] [-R] [path]\n", getprogname());
4387 get_default_log_limit(void)
4389 const char *got_default_log_limit
;
4393 got_default_log_limit
= getenv("GOT_LOG_DEFAULT_LIMIT");
4394 if (got_default_log_limit
== NULL
)
4396 n
= strtonum(got_default_log_limit
, 0, INT_MAX
, &errstr
);
4402 static const struct got_error
*
4403 cmd_log(int argc
, char *argv
[])
4405 const struct got_error
*error
;
4406 struct got_repository
*repo
= NULL
;
4407 struct got_worktree
*worktree
= NULL
;
4408 struct got_object_id
*start_id
= NULL
, *end_id
= NULL
;
4409 char *repo_path
= NULL
, *path
= NULL
, *cwd
= NULL
, *in_repo_path
= NULL
;
4410 const char *start_commit
= NULL
, *end_commit
= NULL
;
4411 const char *search_pattern
= NULL
;
4412 int diff_context
= -1, ch
;
4413 int show_changed_paths
= 0, show_patch
= 0, limit
= 0, log_branches
= 0;
4414 int reverse_display_order
= 0, one_line
= 0;
4416 struct got_reflist_head refs
;
4417 struct got_reflist_object_id_map
*refs_idmap
= NULL
;
4418 FILE *tmpfile
= NULL
;
4419 int *pack_fds
= NULL
;
4424 if (pledge("stdio rpath wpath cpath flock proc exec sendfd unveil",
4430 limit
= get_default_log_limit();
4432 while ((ch
= getopt(argc
, argv
, "bpPc:C:l:r:RsS:x:")) != -1) {
4438 show_changed_paths
= 1;
4441 start_commit
= optarg
;
4444 diff_context
= strtonum(optarg
, 0, GOT_DIFF_MAX_CONTEXT
,
4447 errx(1, "number of context lines is %s: %s",
4451 limit
= strtonum(optarg
, 0, INT_MAX
, &errstr
);
4453 errx(1, "number of commits is %s: %s",
4460 repo_path
= realpath(optarg
, NULL
);
4461 if (repo_path
== NULL
)
4462 return got_error_from_errno2("realpath",
4464 got_path_strip_trailing_slashes(repo_path
);
4467 reverse_display_order
= 1;
4473 search_pattern
= optarg
;
4476 end_commit
= optarg
;
4487 if (diff_context
== -1)
4489 else if (!show_patch
)
4490 errx(1, "-C requires -p");
4492 if (one_line
&& (show_patch
|| show_changed_paths
))
4493 errx(1, "cannot use -s with -p or -P");
4495 cwd
= getcwd(NULL
, 0);
4497 error
= got_error_from_errno("getcwd");
4501 error
= got_repo_pack_fds_open(&pack_fds
);
4505 if (repo_path
== NULL
) {
4506 error
= got_worktree_open(&worktree
, cwd
);
4507 if (error
&& error
->code
!= GOT_ERR_NOT_WORKTREE
)
4514 error
= got_worktree_resolve_path(&path
, worktree
,
4519 path
= strdup(argv
[0]);
4521 error
= got_error_from_errno("strdup");
4525 } else if (argc
!= 0)
4528 if (repo_path
== NULL
) {
4529 repo_path
= worktree
?
4530 strdup(got_worktree_get_repo_path(worktree
)) : strdup(cwd
);
4532 if (repo_path
== NULL
) {
4533 error
= got_error_from_errno("strdup");
4537 error
= got_repo_open(&repo
, repo_path
, NULL
, pack_fds
);
4541 error
= apply_unveil(got_repo_get_path(repo
), 1,
4542 worktree
? got_worktree_get_root_path(worktree
) : NULL
);
4546 error
= got_ref_list(&refs
, repo
, NULL
, got_ref_cmp_by_name
, NULL
);
4550 error
= got_reflist_object_id_map_create(&refs_idmap
, &refs
, repo
);
4554 if (start_commit
== NULL
) {
4555 struct got_reference
*head_ref
;
4556 struct got_commit_object
*commit
= NULL
;
4557 error
= got_ref_open(&head_ref
, repo
,
4558 worktree
? got_worktree_get_head_ref_name(worktree
)
4562 error
= got_ref_resolve(&start_id
, repo
, head_ref
);
4563 got_ref_close(head_ref
);
4566 error
= got_object_open_as_commit(&commit
, repo
,
4570 got_object_commit_close(commit
);
4572 error
= got_repo_match_object_id(&start_id
, NULL
,
4573 start_commit
, GOT_OBJ_TYPE_COMMIT
, &refs
, repo
);
4577 if (end_commit
!= NULL
) {
4578 error
= got_repo_match_object_id(&end_id
, NULL
,
4579 end_commit
, GOT_OBJ_TYPE_COMMIT
, &refs
, repo
);
4586 * If a path was specified on the command line it was resolved
4587 * to a path in the work tree above. Prepend the work tree's
4588 * path prefix to obtain the corresponding in-repository path.
4592 prefix
= got_worktree_get_path_prefix(worktree
);
4593 if (asprintf(&in_repo_path
, "%s%s%s", prefix
,
4594 (path
[0] != '\0') ? "/" : "", path
) == -1) {
4595 error
= got_error_from_errno("asprintf");
4600 error
= got_repo_map_path(&in_repo_path
, repo
,
4606 path
= in_repo_path
;
4610 /* Release work tree lock. */
4611 got_worktree_close(worktree
);
4615 if (search_pattern
&& show_patch
) {
4616 tmpfile
= got_opentemp();
4617 if (tmpfile
== NULL
) {
4618 error
= got_error_from_errno("got_opentemp");
4623 error
= print_commits(start_id
, end_id
, repo
, path
? path
: "",
4624 show_changed_paths
, show_patch
, search_pattern
, diff_context
,
4625 limit
, log_branches
, reverse_display_order
, refs_idmap
, one_line
,
4632 got_worktree_close(worktree
);
4634 const struct got_error
*close_err
= got_repo_close(repo
);
4639 const struct got_error
*pack_err
=
4640 got_repo_pack_fds_close(pack_fds
);
4645 got_reflist_object_id_map_free(refs_idmap
);
4646 if (tmpfile
&& fclose(tmpfile
) == EOF
&& error
== NULL
)
4647 error
= got_error_from_errno("fclose");
4648 got_ref_list_free(&refs
);
4655 fprintf(stderr
, "usage: %s diff [-a] [-c commit] [-C number] "
4656 "[-r repository-path] [-s] [-w] [-P] "
4657 "[object1 object2 | path ...]\n", getprogname());
4661 struct print_diff_arg
{
4662 struct got_repository
*repo
;
4663 struct got_worktree
*worktree
;
4668 enum got_diff_algorithm diff_algo
;
4669 int ignore_whitespace
;
4670 int force_text_diff
;
4676 * Create a file which contains the target path of a symlink so we can feed
4677 * it as content to the diff engine.
4679 static const struct got_error
*
4680 get_symlink_target_file(int *fd
, int dirfd
, const char *de_name
,
4681 const char *abspath
)
4683 const struct got_error
*err
= NULL
;
4684 char target_path
[PATH_MAX
];
4685 ssize_t target_len
, outlen
;
4690 target_len
= readlinkat(dirfd
, de_name
, target_path
, PATH_MAX
);
4691 if (target_len
== -1)
4692 return got_error_from_errno2("readlinkat", abspath
);
4694 target_len
= readlink(abspath
, target_path
, PATH_MAX
);
4695 if (target_len
== -1)
4696 return got_error_from_errno2("readlink", abspath
);
4699 *fd
= got_opentempfd();
4701 return got_error_from_errno("got_opentempfd");
4703 outlen
= write(*fd
, target_path
, target_len
);
4705 err
= got_error_from_errno("got_opentempfd");
4709 if (lseek(*fd
, 0, SEEK_SET
) == -1) {
4710 err
= got_error_from_errno2("lseek", abspath
);
4721 static const struct got_error
*
4722 print_diff(void *arg
, unsigned char status
, unsigned char staged_status
,
4723 const char *path
, struct got_object_id
*blob_id
,
4724 struct got_object_id
*staged_blob_id
, struct got_object_id
*commit_id
,
4725 int dirfd
, const char *de_name
)
4727 struct print_diff_arg
*a
= arg
;
4728 const struct got_error
*err
= NULL
;
4729 struct got_blob_object
*blob1
= NULL
;
4730 int fd
= -1, fd1
= -1, fd2
= -1;
4732 char *abspath
= NULL
, *label1
= NULL
;
4737 if (a
->diff_staged
) {
4738 if (staged_status
!= GOT_STATUS_MODIFY
&&
4739 staged_status
!= GOT_STATUS_ADD
&&
4740 staged_status
!= GOT_STATUS_DELETE
)
4743 if (staged_status
== GOT_STATUS_DELETE
)
4745 if (status
== GOT_STATUS_NONEXISTENT
)
4746 return got_error_set_errno(ENOENT
, path
);
4747 if (status
!= GOT_STATUS_MODIFY
&&
4748 status
!= GOT_STATUS_ADD
&&
4749 status
!= GOT_STATUS_DELETE
&&
4750 status
!= GOT_STATUS_CONFLICT
)
4754 err
= got_opentemp_truncate(a
->f1
);
4756 return got_error_from_errno("got_opentemp_truncate");
4757 err
= got_opentemp_truncate(a
->f2
);
4759 return got_error_from_errno("got_opentemp_truncate");
4761 if (!a
->header_shown
) {
4762 printf("diff %s%s\n", a
->diff_staged
? "-s " : "",
4763 got_worktree_get_root_path(a
->worktree
));
4764 printf("commit - %s\n", a
->id_str
);
4765 printf("path + %s%s\n",
4766 got_worktree_get_root_path(a
->worktree
),
4767 a
->diff_staged
? " (staged changes)" : "");
4768 a
->header_shown
= 1;
4771 if (a
->diff_staged
) {
4772 const char *label1
= NULL
, *label2
= NULL
;
4773 switch (staged_status
) {
4774 case GOT_STATUS_MODIFY
:
4778 case GOT_STATUS_ADD
:
4781 case GOT_STATUS_DELETE
:
4785 return got_error(GOT_ERR_FILE_STATUS
);
4787 fd1
= got_opentempfd();
4789 err
= got_error_from_errno("got_opentempfd");
4792 fd2
= got_opentempfd();
4794 err
= got_error_from_errno("got_opentempfd");
4797 err
= got_diff_objects_as_blobs(NULL
, NULL
, a
->f1
, a
->f2
,
4798 fd1
, fd2
, blob_id
, staged_blob_id
, label1
, label2
,
4799 a
->diff_algo
, a
->diff_context
, a
->ignore_whitespace
,
4800 a
->force_text_diff
, a
->repo
, stdout
);
4804 fd1
= got_opentempfd();
4806 err
= got_error_from_errno("got_opentempfd");
4810 if (staged_status
== GOT_STATUS_ADD
||
4811 staged_status
== GOT_STATUS_MODIFY
) {
4813 err
= got_object_open_as_blob(&blob1
, a
->repo
, staged_blob_id
,
4817 err
= got_object_id_str(&id_str
, staged_blob_id
);
4820 if (asprintf(&label1
, "%s (staged)", id_str
) == -1) {
4821 err
= got_error_from_errno("asprintf");
4826 } else if (status
!= GOT_STATUS_ADD
) {
4827 err
= got_object_open_as_blob(&blob1
, a
->repo
, blob_id
, 8192,
4833 if (status
!= GOT_STATUS_DELETE
) {
4834 if (asprintf(&abspath
, "%s/%s",
4835 got_worktree_get_root_path(a
->worktree
), path
) == -1) {
4836 err
= got_error_from_errno("asprintf");
4841 fd
= openat(dirfd
, de_name
,
4842 O_RDONLY
| O_NOFOLLOW
| O_CLOEXEC
);
4844 if (!got_err_open_nofollow_on_symlink()) {
4845 err
= got_error_from_errno2("openat",
4849 err
= get_symlink_target_file(&fd
, dirfd
,
4855 fd
= open(abspath
, O_RDONLY
| O_NOFOLLOW
| O_CLOEXEC
);
4857 if (!got_err_open_nofollow_on_symlink()) {
4858 err
= got_error_from_errno2("open",
4862 err
= get_symlink_target_file(&fd
, dirfd
,
4868 if (fstat(fd
, &sb
) == -1) {
4869 err
= got_error_from_errno2("fstat", abspath
);
4872 f2
= fdopen(fd
, "r");
4874 err
= got_error_from_errno2("fdopen", abspath
);
4884 err
= got_object_blob_dump_to_file(&size1
, NULL
, NULL
,
4890 err
= got_diff_blob_file(blob1
, a
->f1
, size1
, label1
, f2
? f2
: a
->f2
,
4891 f2_exists
, sb
.st_size
, path
, GOT_DIFF_ALGORITHM_PATIENCE
,
4892 a
->diff_context
, a
->ignore_whitespace
, a
->force_text_diff
, stdout
);
4894 if (fd1
!= -1 && close(fd1
) == -1 && err
== NULL
)
4895 err
= got_error_from_errno("close");
4896 if (fd2
!= -1 && close(fd2
) == -1 && err
== NULL
)
4897 err
= got_error_from_errno("close");
4899 got_object_blob_close(blob1
);
4900 if (fd
!= -1 && close(fd
) == -1 && err
== NULL
)
4901 err
= got_error_from_errno("close");
4902 if (f2
&& fclose(f2
) == EOF
&& err
== NULL
)
4903 err
= got_error_from_errno("fclose");
4908 static const struct got_error
*
4909 cmd_diff(int argc
, char *argv
[])
4911 const struct got_error
*error
;
4912 struct got_repository
*repo
= NULL
;
4913 struct got_worktree
*worktree
= NULL
;
4914 char *cwd
= NULL
, *repo_path
= NULL
;
4915 const char *commit_args
[2] = { NULL
, NULL
};
4916 int ncommit_args
= 0;
4917 struct got_object_id
*ids
[2] = { NULL
, NULL
};
4918 char *labels
[2] = { NULL
, NULL
};
4919 int type1
= GOT_OBJ_TYPE_ANY
, type2
= GOT_OBJ_TYPE_ANY
;
4920 int diff_context
= 3, diff_staged
= 0, ignore_whitespace
= 0, ch
, i
;
4921 int force_text_diff
= 0, force_path
= 0, rflag
= 0;
4923 struct got_reflist_head refs
;
4924 struct got_pathlist_head paths
;
4925 struct got_pathlist_entry
*pe
;
4926 FILE *f1
= NULL
, *f2
= NULL
;
4927 int fd1
= -1, fd2
= -1;
4928 int *pack_fds
= NULL
;
4934 if (pledge("stdio rpath wpath cpath flock proc exec sendfd unveil",
4939 while ((ch
= getopt(argc
, argv
, "ac:C:r:swP")) != -1) {
4942 force_text_diff
= 1;
4945 if (ncommit_args
>= 2)
4946 errx(1, "too many -c options used");
4947 commit_args
[ncommit_args
++] = optarg
;
4950 diff_context
= strtonum(optarg
, 0, GOT_DIFF_MAX_CONTEXT
,
4953 errx(1, "number of context lines is %s: %s",
4957 repo_path
= realpath(optarg
, NULL
);
4958 if (repo_path
== NULL
)
4959 return got_error_from_errno2("realpath",
4961 got_path_strip_trailing_slashes(repo_path
);
4968 ignore_whitespace
= 1;
4982 cwd
= getcwd(NULL
, 0);
4984 error
= got_error_from_errno("getcwd");
4988 error
= got_repo_pack_fds_open(&pack_fds
);
4992 if (repo_path
== NULL
) {
4993 error
= got_worktree_open(&worktree
, cwd
);
4994 if (error
&& error
->code
!= GOT_ERR_NOT_WORKTREE
)
5000 strdup(got_worktree_get_repo_path(worktree
));
5001 if (repo_path
== NULL
) {
5002 error
= got_error_from_errno("strdup");
5006 repo_path
= strdup(cwd
);
5007 if (repo_path
== NULL
) {
5008 error
= got_error_from_errno("strdup");
5014 error
= got_repo_open(&repo
, repo_path
, NULL
, pack_fds
);
5019 if (rflag
|| worktree
== NULL
|| ncommit_args
> 0) {
5021 error
= got_error_msg(GOT_ERR_NOT_IMPL
,
5022 "-P option can only be used when diffing "
5027 error
= got_error_msg(GOT_ERR_NOT_IMPL
,
5028 "-s option can only be used when diffing "
5034 error
= apply_unveil(got_repo_get_path(repo
), 1,
5035 worktree
? got_worktree_get_root_path(worktree
) : NULL
);
5039 if ((!force_path
&& argc
== 2) || ncommit_args
> 0) {
5040 int obj_type
= (ncommit_args
> 0 ?
5041 GOT_OBJ_TYPE_COMMIT
: GOT_OBJ_TYPE_ANY
);
5042 error
= got_ref_list(&refs
, repo
, NULL
, got_ref_cmp_by_name
,
5046 for (i
= 0; i
< (ncommit_args
> 0 ? ncommit_args
: argc
); i
++) {
5048 if (ncommit_args
> 0)
5049 arg
= commit_args
[i
];
5052 error
= got_repo_match_object_id(&ids
[i
], &labels
[i
],
5053 arg
, obj_type
, &refs
, repo
);
5055 if (error
->code
!= GOT_ERR_NOT_REF
&&
5056 error
->code
!= GOT_ERR_NO_OBJ
)
5058 if (ncommit_args
> 0)
5066 f1
= got_opentemp();
5068 error
= got_error_from_errno("got_opentemp");
5072 f2
= got_opentemp();
5074 error
= got_error_from_errno("got_opentemp");
5078 if (ncommit_args
== 0 && (ids
[0] == NULL
|| ids
[1] == NULL
)) {
5079 struct print_diff_arg arg
;
5082 if (worktree
== NULL
) {
5083 if (argc
== 2 && ids
[0] == NULL
) {
5084 error
= got_error_path(argv
[0], GOT_ERR_NO_OBJ
);
5086 } else if (argc
== 2 && ids
[1] == NULL
) {
5087 error
= got_error_path(argv
[1], GOT_ERR_NO_OBJ
);
5089 } else if (argc
> 0) {
5090 error
= got_error_fmt(GOT_ERR_NOT_WORKTREE
,
5091 "%s", "specified paths cannot be resolved");
5094 error
= got_error(GOT_ERR_NOT_WORKTREE
);
5099 error
= get_worktree_paths_from_argv(&paths
, argc
, argv
,
5104 error
= got_object_id_str(&id_str
,
5105 got_worktree_get_base_commit_id(worktree
));
5109 arg
.worktree
= worktree
;
5110 arg
.diff_algo
= GOT_DIFF_ALGORITHM_PATIENCE
;
5111 arg
.diff_context
= diff_context
;
5112 arg
.id_str
= id_str
;
5113 arg
.header_shown
= 0;
5114 arg
.diff_staged
= diff_staged
;
5115 arg
.ignore_whitespace
= ignore_whitespace
;
5116 arg
.force_text_diff
= force_text_diff
;
5120 error
= got_worktree_status(worktree
, &paths
, repo
, 0,
5121 print_diff
, &arg
, check_cancelled
, NULL
);
5126 if (ncommit_args
== 1) {
5127 struct got_commit_object
*commit
;
5128 error
= got_object_open_as_commit(&commit
, repo
, ids
[0]);
5132 labels
[1] = labels
[0];
5134 if (got_object_commit_get_nparents(commit
) > 0) {
5135 const struct got_object_id_queue
*pids
;
5136 struct got_object_qid
*pid
;
5137 pids
= got_object_commit_get_parent_ids(commit
);
5138 pid
= STAILQ_FIRST(pids
);
5139 ids
[0] = got_object_id_dup(&pid
->id
);
5140 if (ids
[0] == NULL
) {
5141 error
= got_error_from_errno(
5142 "got_object_id_dup");
5143 got_object_commit_close(commit
);
5146 error
= got_object_id_str(&labels
[0], ids
[0]);
5148 got_object_commit_close(commit
);
5153 labels
[0] = strdup("/dev/null");
5154 if (labels
[0] == NULL
) {
5155 error
= got_error_from_errno("strdup");
5156 got_object_commit_close(commit
);
5161 got_object_commit_close(commit
);
5164 if (ncommit_args
== 0 && argc
> 2) {
5165 error
= got_error_msg(GOT_ERR_BAD_PATH
,
5166 "path arguments cannot be used when diffing two objects");
5171 error
= got_object_get_type(&type1
, repo
, ids
[0]);
5176 error
= got_object_get_type(&type2
, repo
, ids
[1]);
5179 if (type1
!= GOT_OBJ_TYPE_ANY
&& type1
!= type2
) {
5180 error
= got_error(GOT_ERR_OBJ_TYPE
);
5183 if (type1
== GOT_OBJ_TYPE_BLOB
&& argc
> 0) {
5184 error
= got_error_msg(GOT_ERR_OBJ_TYPE
,
5185 "path arguments cannot be used when diffing blobs");
5189 for (i
= 0; ncommit_args
> 0 && i
< argc
; i
++) {
5191 struct got_pathlist_entry
*new;
5195 error
= got_worktree_resolve_path(&p
, worktree
,
5199 prefix
= got_worktree_get_path_prefix(worktree
);
5200 while (prefix
[0] == '/')
5202 if (asprintf(&in_repo_path
, "%s%s%s", prefix
,
5203 (p
[0] != '\0' && prefix
[0] != '\0') ? "/" : "",
5205 error
= got_error_from_errno("asprintf");
5211 char *mapped_path
, *s
;
5212 error
= got_repo_map_path(&mapped_path
, repo
, argv
[i
]);
5218 in_repo_path
= strdup(s
);
5219 if (in_repo_path
== NULL
) {
5220 error
= got_error_from_errno("asprintf");
5227 error
= got_pathlist_insert(&new, &paths
, in_repo_path
, NULL
);
5228 if (error
|| new == NULL
/* duplicate */)
5235 /* Release work tree lock. */
5236 got_worktree_close(worktree
);
5240 fd1
= got_opentempfd();
5242 error
= got_error_from_errno("got_opentempfd");
5246 fd2
= got_opentempfd();
5248 error
= got_error_from_errno("got_opentempfd");
5252 switch (type1
== GOT_OBJ_TYPE_ANY
? type2
: type1
) {
5253 case GOT_OBJ_TYPE_BLOB
:
5254 error
= got_diff_objects_as_blobs(NULL
, NULL
, f1
, f2
,
5255 fd1
, fd2
, ids
[0], ids
[1], NULL
, NULL
,
5256 GOT_DIFF_ALGORITHM_PATIENCE
, diff_context
,
5257 ignore_whitespace
, force_text_diff
, repo
, stdout
);
5259 case GOT_OBJ_TYPE_TREE
:
5260 error
= got_diff_objects_as_trees(NULL
, NULL
, f1
, f2
, fd1
, fd2
,
5261 ids
[0], ids
[1], &paths
, "", "",
5262 GOT_DIFF_ALGORITHM_PATIENCE
, diff_context
,
5263 ignore_whitespace
, force_text_diff
, repo
, stdout
);
5265 case GOT_OBJ_TYPE_COMMIT
:
5266 printf("diff %s %s\n", labels
[0], labels
[1]);
5267 error
= got_diff_objects_as_commits(NULL
, NULL
, f1
, f2
,
5268 fd1
, fd2
, ids
[0], ids
[1], &paths
,
5269 GOT_DIFF_ALGORITHM_PATIENCE
, diff_context
,
5270 ignore_whitespace
, force_text_diff
, repo
, stdout
);
5273 error
= got_error(GOT_ERR_OBJ_TYPE
);
5281 got_worktree_close(worktree
);
5283 const struct got_error
*close_err
= got_repo_close(repo
);
5288 const struct got_error
*pack_err
=
5289 got_repo_pack_fds_close(pack_fds
);
5293 TAILQ_FOREACH(pe
, &paths
, entry
)
5294 free((char *)pe
->path
);
5295 got_pathlist_free(&paths
);
5296 got_ref_list_free(&refs
);
5297 if (f1
&& fclose(f1
) == EOF
&& error
== NULL
)
5298 error
= got_error_from_errno("fclose");
5299 if (f2
&& fclose(f2
) == EOF
&& error
== NULL
)
5300 error
= got_error_from_errno("fclose");
5301 if (fd1
!= -1 && close(fd1
) == -1 && error
== NULL
)
5302 error
= got_error_from_errno("close");
5303 if (fd2
!= -1 && close(fd2
) == -1 && error
== NULL
)
5304 error
= got_error_from_errno("close");
5312 "usage: %s blame [-c commit] [-r repository-path] path\n",
5321 char datebuf
[11]; /* YYYY-MM-DD + NUL */
5324 struct blame_cb_args
{
5325 struct blame_line
*lines
;
5329 off_t
*line_offsets
;
5331 struct got_repository
*repo
;
5334 static const struct got_error
*
5335 blame_cb(void *arg
, int nlines
, int lineno
,
5336 struct got_commit_object
*commit
, struct got_object_id
*id
)
5338 const struct got_error
*err
= NULL
;
5339 struct blame_cb_args
*a
= arg
;
5340 struct blame_line
*bline
;
5342 size_t linesize
= 0;
5345 time_t committer_time
;
5347 if (nlines
!= a
->nlines
||
5348 (lineno
!= -1 && lineno
< 1) || lineno
> a
->nlines
)
5349 return got_error(GOT_ERR_RANGE
);
5351 if (sigint_received
)
5352 return got_error(GOT_ERR_ITER_COMPLETED
);
5355 return NULL
; /* no change in this commit */
5357 /* Annotate this line. */
5358 bline
= &a
->lines
[lineno
- 1];
5359 if (bline
->annotated
)
5361 err
= got_object_id_str(&bline
->id_str
, id
);
5365 bline
->committer
= strdup(got_object_commit_get_committer(commit
));
5366 if (bline
->committer
== NULL
) {
5367 err
= got_error_from_errno("strdup");
5371 committer_time
= got_object_commit_get_committer_time(commit
);
5372 if (gmtime_r(&committer_time
, &tm
) == NULL
)
5373 return got_error_from_errno("gmtime_r");
5374 if (strftime(bline
->datebuf
, sizeof(bline
->datebuf
), "%G-%m-%d",
5376 err
= got_error(GOT_ERR_NO_SPACE
);
5379 bline
->annotated
= 1;
5381 /* Print lines annotated so far. */
5382 bline
= &a
->lines
[a
->lineno_cur
- 1];
5383 if (!bline
->annotated
)
5386 offset
= a
->line_offsets
[a
->lineno_cur
- 1];
5387 if (fseeko(a
->f
, offset
, SEEK_SET
) == -1) {
5388 err
= got_error_from_errno("fseeko");
5392 while (bline
->annotated
) {
5393 char *smallerthan
, *at
, *nl
, *committer
;
5396 if (getline(&line
, &linesize
, a
->f
) == -1) {
5398 err
= got_error_from_errno("getline");
5402 committer
= bline
->committer
;
5403 smallerthan
= strchr(committer
, '<');
5404 if (smallerthan
&& smallerthan
[1] != '\0')
5405 committer
= smallerthan
+ 1;
5406 at
= strchr(committer
, '@');
5409 len
= strlen(committer
);
5411 committer
[8] = '\0';
5413 nl
= strchr(line
, '\n');
5416 printf("%.*d) %.8s %s %-8s %s\n", a
->nlines_prec
, a
->lineno_cur
,
5417 bline
->id_str
, bline
->datebuf
, committer
, line
);
5420 bline
= &a
->lines
[a
->lineno_cur
- 1];
5427 static const struct got_error
*
5428 cmd_blame(int argc
, char *argv
[])
5430 const struct got_error
*error
;
5431 struct got_repository
*repo
= NULL
;
5432 struct got_worktree
*worktree
= NULL
;
5433 char *path
, *cwd
= NULL
, *repo_path
= NULL
, *in_repo_path
= NULL
;
5434 char *link_target
= NULL
;
5435 struct got_object_id
*obj_id
= NULL
;
5436 struct got_object_id
*commit_id
= NULL
;
5437 struct got_commit_object
*commit
= NULL
;
5438 struct got_blob_object
*blob
= NULL
;
5439 char *commit_id_str
= NULL
;
5440 struct blame_cb_args bca
;
5441 int ch
, obj_type
, i
, fd1
= -1, fd2
= -1, fd3
= -1;
5443 int *pack_fds
= NULL
;
5444 FILE *f1
= NULL
, *f2
= NULL
;
5446 fd1
= got_opentempfd();
5448 return got_error_from_errno("got_opentempfd");
5450 memset(&bca
, 0, sizeof(bca
));
5453 if (pledge("stdio rpath wpath cpath flock proc exec sendfd unveil",
5458 while ((ch
= getopt(argc
, argv
, "c:r:")) != -1) {
5461 commit_id_str
= optarg
;
5464 repo_path
= realpath(optarg
, NULL
);
5465 if (repo_path
== NULL
)
5466 return got_error_from_errno2("realpath",
5468 got_path_strip_trailing_slashes(repo_path
);
5484 cwd
= getcwd(NULL
, 0);
5486 error
= got_error_from_errno("getcwd");
5490 error
= got_repo_pack_fds_open(&pack_fds
);
5494 if (repo_path
== NULL
) {
5495 error
= got_worktree_open(&worktree
, cwd
);
5496 if (error
&& error
->code
!= GOT_ERR_NOT_WORKTREE
)
5502 strdup(got_worktree_get_repo_path(worktree
));
5503 if (repo_path
== NULL
) {
5504 error
= got_error_from_errno("strdup");
5509 repo_path
= strdup(cwd
);
5510 if (repo_path
== NULL
) {
5511 error
= got_error_from_errno("strdup");
5517 error
= got_repo_open(&repo
, repo_path
, NULL
, pack_fds
);
5522 const char *prefix
= got_worktree_get_path_prefix(worktree
);
5525 error
= got_worktree_resolve_path(&p
, worktree
, path
);
5528 if (asprintf(&in_repo_path
, "%s%s%s", prefix
,
5529 (p
[0] != '\0' && !got_path_is_root_dir(prefix
)) ? "/" : "",
5531 error
= got_error_from_errno("asprintf");
5536 error
= apply_unveil(got_repo_get_path(repo
), 1, NULL
);
5538 error
= apply_unveil(got_repo_get_path(repo
), 1, NULL
);
5541 error
= got_repo_map_path(&in_repo_path
, repo
, path
);
5546 if (commit_id_str
== NULL
) {
5547 struct got_reference
*head_ref
;
5548 error
= got_ref_open(&head_ref
, repo
, worktree
?
5549 got_worktree_get_head_ref_name(worktree
) : GOT_REF_HEAD
, 0);
5552 error
= got_ref_resolve(&commit_id
, repo
, head_ref
);
5553 got_ref_close(head_ref
);
5557 struct got_reflist_head refs
;
5559 error
= got_ref_list(&refs
, repo
, NULL
, got_ref_cmp_by_name
,
5563 error
= got_repo_match_object_id(&commit_id
, NULL
,
5564 commit_id_str
, GOT_OBJ_TYPE_COMMIT
, &refs
, repo
);
5565 got_ref_list_free(&refs
);
5571 /* Release work tree lock. */
5572 got_worktree_close(worktree
);
5576 error
= got_object_open_as_commit(&commit
, repo
, commit_id
);
5580 error
= got_object_resolve_symlinks(&link_target
, in_repo_path
,
5585 error
= got_object_id_by_path(&obj_id
, repo
, commit
,
5586 link_target
? link_target
: in_repo_path
);
5590 error
= got_object_get_type(&obj_type
, repo
, obj_id
);
5594 if (obj_type
!= GOT_OBJ_TYPE_BLOB
) {
5595 error
= got_error_path(link_target
? link_target
: in_repo_path
,
5600 error
= got_object_open_as_blob(&blob
, repo
, obj_id
, 8192, fd1
);
5603 bca
.f
= got_opentemp();
5604 if (bca
.f
== NULL
) {
5605 error
= got_error_from_errno("got_opentemp");
5608 error
= got_object_blob_dump_to_file(&filesize
, &bca
.nlines
,
5609 &bca
.line_offsets
, bca
.f
, blob
);
5610 if (error
|| bca
.nlines
== 0)
5613 /* Don't include \n at EOF in the blame line count. */
5614 if (bca
.line_offsets
[bca
.nlines
- 1] == filesize
)
5617 bca
.lines
= calloc(bca
.nlines
, sizeof(*bca
.lines
));
5618 if (bca
.lines
== NULL
) {
5619 error
= got_error_from_errno("calloc");
5623 bca
.nlines_prec
= 0;
5631 fd2
= got_opentempfd();
5633 error
= got_error_from_errno("got_opentempfd");
5636 fd3
= got_opentempfd();
5638 error
= got_error_from_errno("got_opentempfd");
5641 f1
= got_opentemp();
5643 error
= got_error_from_errno("got_opentemp");
5646 f2
= got_opentemp();
5648 error
= got_error_from_errno("got_opentemp");
5651 error
= got_blame(link_target
? link_target
: in_repo_path
, commit_id
,
5652 repo
, GOT_DIFF_ALGORITHM_PATIENCE
, blame_cb
, &bca
,
5653 check_cancelled
, NULL
, fd2
, fd3
, f1
, f2
);
5662 got_object_commit_close(commit
);
5664 if (fd1
!= -1 && close(fd1
) == -1 && error
== NULL
)
5665 error
= got_error_from_errno("close");
5666 if (fd2
!= -1 && close(fd2
) == -1 && error
== NULL
)
5667 error
= got_error_from_errno("close");
5668 if (fd3
!= -1 && close(fd3
) == -1 && error
== NULL
)
5669 error
= got_error_from_errno("close");
5670 if (f1
&& fclose(f1
) == EOF
&& error
== NULL
)
5671 error
= got_error_from_errno("fclose");
5672 if (f2
&& fclose(f2
) == EOF
&& error
== NULL
)
5673 error
= got_error_from_errno("fclose");
5676 got_object_blob_close(blob
);
5678 got_worktree_close(worktree
);
5680 const struct got_error
*close_err
= got_repo_close(repo
);
5685 const struct got_error
*pack_err
=
5686 got_repo_pack_fds_close(pack_fds
);
5691 for (i
= 0; i
< bca
.nlines
; i
++) {
5692 struct blame_line
*bline
= &bca
.lines
[i
];
5693 free(bline
->id_str
);
5694 free(bline
->committer
);
5698 free(bca
.line_offsets
);
5699 if (bca
.f
&& fclose(bca
.f
) == EOF
&& error
== NULL
)
5700 error
= got_error_from_errno("fclose");
5708 "usage: %s tree [-c commit] [-r repository-path] [-iR] [path]\n",
5713 static const struct got_error
*
5714 print_entry(struct got_tree_entry
*te
, const char *id
, const char *path
,
5715 const char *root_path
, struct got_repository
*repo
)
5717 const struct got_error
*err
= NULL
;
5718 int is_root_path
= (strcmp(path
, root_path
) == 0);
5719 const char *modestr
= "";
5720 mode_t mode
= got_tree_entry_get_mode(te
);
5721 char *link_target
= NULL
;
5723 path
+= strlen(root_path
);
5724 while (path
[0] == '/')
5727 if (got_object_tree_entry_is_submodule(te
))
5729 else if (S_ISLNK(mode
)) {
5732 err
= got_tree_entry_get_symlink_target(&link_target
, te
, repo
);
5735 for (i
= 0; i
< strlen(link_target
); i
++) {
5736 if (!isprint((unsigned char)link_target
[i
]))
5737 link_target
[i
] = '?';
5742 else if (S_ISDIR(mode
))
5744 else if (mode
& S_IXUSR
)
5747 printf("%s%s%s%s%s%s%s\n", id
? id
: "", path
,
5748 is_root_path
? "" : "/", got_tree_entry_get_name(te
), modestr
,
5749 link_target
? " -> ": "", link_target
? link_target
: "");
5755 static const struct got_error
*
5756 print_tree(const char *path
, struct got_commit_object
*commit
,
5757 int show_ids
, int recurse
, const char *root_path
,
5758 struct got_repository
*repo
)
5760 const struct got_error
*err
= NULL
;
5761 struct got_object_id
*tree_id
= NULL
;
5762 struct got_tree_object
*tree
= NULL
;
5765 err
= got_object_id_by_path(&tree_id
, repo
, commit
, path
);
5769 err
= got_object_open_as_tree(&tree
, repo
, tree_id
);
5772 nentries
= got_object_tree_get_nentries(tree
);
5773 for (i
= 0; i
< nentries
; i
++) {
5774 struct got_tree_entry
*te
;
5777 if (sigint_received
|| sigpipe_received
)
5780 te
= got_object_tree_get_entry(tree
, i
);
5783 err
= got_object_id_str(&id_str
,
5784 got_tree_entry_get_id(te
));
5787 if (asprintf(&id
, "%s ", id_str
) == -1) {
5788 err
= got_error_from_errno("asprintf");
5794 err
= print_entry(te
, id
, path
, root_path
, repo
);
5799 if (recurse
&& S_ISDIR(got_tree_entry_get_mode(te
))) {
5801 if (asprintf(&child_path
, "%s%s%s", path
,
5802 path
[0] == '/' && path
[1] == '\0' ? "" : "/",
5803 got_tree_entry_get_name(te
)) == -1) {
5804 err
= got_error_from_errno("asprintf");
5807 err
= print_tree(child_path
, commit
, show_ids
, 1,
5816 got_object_tree_close(tree
);
5821 static const struct got_error
*
5822 cmd_tree(int argc
, char *argv
[])
5824 const struct got_error
*error
;
5825 struct got_repository
*repo
= NULL
;
5826 struct got_worktree
*worktree
= NULL
;
5827 const char *path
, *refname
= NULL
;
5828 char *cwd
= NULL
, *repo_path
= NULL
, *in_repo_path
= NULL
;
5829 struct got_object_id
*commit_id
= NULL
;
5830 struct got_commit_object
*commit
= NULL
;
5831 char *commit_id_str
= NULL
;
5832 int show_ids
= 0, recurse
= 0;
5834 int *pack_fds
= NULL
;
5837 if (pledge("stdio rpath wpath cpath flock proc exec sendfd unveil",
5842 while ((ch
= getopt(argc
, argv
, "c:r:iR")) != -1) {
5845 commit_id_str
= optarg
;
5848 repo_path
= realpath(optarg
, NULL
);
5849 if (repo_path
== NULL
)
5850 return got_error_from_errno2("realpath",
5852 got_path_strip_trailing_slashes(repo_path
);
5876 cwd
= getcwd(NULL
, 0);
5878 error
= got_error_from_errno("getcwd");
5882 error
= got_repo_pack_fds_open(&pack_fds
);
5886 if (repo_path
== NULL
) {
5887 error
= got_worktree_open(&worktree
, cwd
);
5888 if (error
&& error
->code
!= GOT_ERR_NOT_WORKTREE
)
5894 strdup(got_worktree_get_repo_path(worktree
));
5895 if (repo_path
== NULL
)
5896 error
= got_error_from_errno("strdup");
5900 repo_path
= strdup(cwd
);
5901 if (repo_path
== NULL
) {
5902 error
= got_error_from_errno("strdup");
5908 error
= got_repo_open(&repo
, repo_path
, NULL
, pack_fds
);
5913 const char *prefix
= got_worktree_get_path_prefix(worktree
);
5918 error
= got_worktree_resolve_path(&p
, worktree
, path
);
5921 if (asprintf(&in_repo_path
, "%s%s%s", prefix
,
5922 (p
[0] != '\0' && !got_path_is_root_dir(prefix
)) ? "/" : "",
5924 error
= got_error_from_errno("asprintf");
5929 error
= apply_unveil(got_repo_get_path(repo
), 1, NULL
);
5933 error
= apply_unveil(got_repo_get_path(repo
), 1, NULL
);
5938 error
= got_repo_map_path(&in_repo_path
, repo
, path
);
5943 if (commit_id_str
== NULL
) {
5944 struct got_reference
*head_ref
;
5946 refname
= got_worktree_get_head_ref_name(worktree
);
5948 refname
= GOT_REF_HEAD
;
5949 error
= got_ref_open(&head_ref
, repo
, refname
, 0);
5952 error
= got_ref_resolve(&commit_id
, repo
, head_ref
);
5953 got_ref_close(head_ref
);
5957 struct got_reflist_head refs
;
5959 error
= got_ref_list(&refs
, repo
, NULL
, got_ref_cmp_by_name
,
5963 error
= got_repo_match_object_id(&commit_id
, NULL
,
5964 commit_id_str
, GOT_OBJ_TYPE_COMMIT
, &refs
, repo
);
5965 got_ref_list_free(&refs
);
5971 /* Release work tree lock. */
5972 got_worktree_close(worktree
);
5976 error
= got_object_open_as_commit(&commit
, repo
, commit_id
);
5980 error
= print_tree(in_repo_path
, commit
, show_ids
, recurse
,
5981 in_repo_path
, repo
);
5988 got_object_commit_close(commit
);
5990 got_worktree_close(worktree
);
5992 const struct got_error
*close_err
= got_repo_close(repo
);
5997 const struct got_error
*pack_err
=
5998 got_repo_pack_fds_close(pack_fds
);
6008 fprintf(stderr
, "usage: %s status [-I] [-s status-codes ] "
6009 "[-S status-codes] [path ...]\n", getprogname());
6013 struct got_status_arg
{
6018 static const struct got_error
*
6019 print_status(void *arg
, unsigned char status
, unsigned char staged_status
,
6020 const char *path
, struct got_object_id
*blob_id
,
6021 struct got_object_id
*staged_blob_id
, struct got_object_id
*commit_id
,
6022 int dirfd
, const char *de_name
)
6024 struct got_status_arg
*st
= arg
;
6026 if (status
== staged_status
&& (status
== GOT_STATUS_DELETE
))
6027 status
= GOT_STATUS_NO_CHANGE
;
6028 if (st
!= NULL
&& st
->status_codes
) {
6029 size_t ncodes
= strlen(st
->status_codes
);
6032 for (i
= 0; i
< ncodes
; i
++) {
6034 if (status
== st
->status_codes
[i
] ||
6035 staged_status
== st
->status_codes
[i
]) {
6040 if (status
== st
->status_codes
[i
] ||
6041 staged_status
== st
->status_codes
[i
])
6046 if (st
->suppress
&& j
== 0)
6053 printf("%c%c %s\n", status
, staged_status
, path
);
6057 static const struct got_error
*
6058 cmd_status(int argc
, char *argv
[])
6060 const struct got_error
*error
= NULL
;
6061 struct got_repository
*repo
= NULL
;
6062 struct got_worktree
*worktree
= NULL
;
6063 struct got_status_arg st
;
6065 struct got_pathlist_head paths
;
6066 struct got_pathlist_entry
*pe
;
6067 int ch
, i
, no_ignores
= 0;
6068 int *pack_fds
= NULL
;
6072 memset(&st
, 0, sizeof(st
));
6073 st
.status_codes
= NULL
;
6076 while ((ch
= getopt(argc
, argv
, "Is:S:")) != -1) {
6082 if (st
.status_codes
!= NULL
&& st
.suppress
== 0)
6083 option_conflict('S', 's');
6087 for (i
= 0; i
< strlen(optarg
); i
++) {
6088 switch (optarg
[i
]) {
6089 case GOT_STATUS_MODIFY
:
6090 case GOT_STATUS_ADD
:
6091 case GOT_STATUS_DELETE
:
6092 case GOT_STATUS_CONFLICT
:
6093 case GOT_STATUS_MISSING
:
6094 case GOT_STATUS_OBSTRUCTED
:
6095 case GOT_STATUS_UNVERSIONED
:
6096 case GOT_STATUS_MODE_CHANGE
:
6097 case GOT_STATUS_NONEXISTENT
:
6100 errx(1, "invalid status code '%c'",
6104 if (ch
== 's' && st
.suppress
)
6105 option_conflict('s', 'S');
6106 st
.status_codes
= optarg
;
6118 if (pledge("stdio rpath wpath cpath flock proc exec sendfd unveil",
6122 cwd
= getcwd(NULL
, 0);
6124 error
= got_error_from_errno("getcwd");
6128 error
= got_repo_pack_fds_open(&pack_fds
);
6132 error
= got_worktree_open(&worktree
, cwd
);
6134 if (error
->code
== GOT_ERR_NOT_WORKTREE
)
6135 error
= wrap_not_worktree_error(error
, "status", cwd
);
6139 error
= got_repo_open(&repo
, got_worktree_get_repo_path(worktree
),
6144 error
= apply_unveil(got_repo_get_path(repo
), 1,
6145 got_worktree_get_root_path(worktree
));
6149 error
= get_worktree_paths_from_argv(&paths
, argc
, argv
, worktree
);
6153 error
= got_worktree_status(worktree
, &paths
, repo
, no_ignores
,
6154 print_status
, &st
, check_cancelled
, NULL
);
6157 const struct got_error
*pack_err
=
6158 got_repo_pack_fds_close(pack_fds
);
6163 TAILQ_FOREACH(pe
, &paths
, entry
)
6164 free((char *)pe
->path
);
6165 got_pathlist_free(&paths
);
6174 "usage: %s ref [-r repository] [-l] [-t] [-c object] "
6175 "[-s reference] [-d] [name]\n",
6180 static const struct got_error
*
6181 list_refs(struct got_repository
*repo
, const char *refname
, int sort_by_time
)
6183 static const struct got_error
*err
= NULL
;
6184 struct got_reflist_head refs
;
6185 struct got_reflist_entry
*re
;
6188 err
= got_ref_list(&refs
, repo
, refname
, sort_by_time
?
6189 got_ref_cmp_by_commit_timestamp_descending
: got_ref_cmp_by_name
,
6194 TAILQ_FOREACH(re
, &refs
, entry
) {
6196 refstr
= got_ref_to_str(re
->ref
);
6197 if (refstr
== NULL
) {
6198 err
= got_error_from_errno("got_ref_to_str");
6201 printf("%s: %s\n", got_ref_get_name(re
->ref
), refstr
);
6205 got_ref_list_free(&refs
);
6209 static const struct got_error
*
6210 delete_ref_by_name(struct got_repository
*repo
, const char *refname
)
6212 const struct got_error
*err
;
6213 struct got_reference
*ref
;
6215 err
= got_ref_open(&ref
, repo
, refname
, 0);
6219 err
= delete_ref(repo
, ref
);
6224 static const struct got_error
*
6225 add_ref(struct got_repository
*repo
, const char *refname
, const char *target
)
6227 const struct got_error
*err
= NULL
;
6228 struct got_object_id
*id
= NULL
;
6229 struct got_reference
*ref
= NULL
;
6230 struct got_reflist_head refs
;
6233 * Don't let the user create a reference name with a leading '-'.
6234 * While technically a valid reference name, this case is usually
6235 * an unintended typo.
6237 if (refname
[0] == '-')
6238 return got_error_path(refname
, GOT_ERR_REF_NAME_MINUS
);
6241 err
= got_ref_list(&refs
, repo
, NULL
, got_ref_cmp_by_name
, NULL
);
6244 err
= got_repo_match_object_id(&id
, NULL
, target
, GOT_OBJ_TYPE_ANY
,
6246 got_ref_list_free(&refs
);
6250 err
= got_ref_alloc(&ref
, refname
, id
);
6254 err
= got_ref_write(ref
, repo
);
6262 static const struct got_error
*
6263 add_symref(struct got_repository
*repo
, const char *refname
, const char *target
)
6265 const struct got_error
*err
= NULL
;
6266 struct got_reference
*ref
= NULL
;
6267 struct got_reference
*target_ref
= NULL
;
6270 * Don't let the user create a reference name with a leading '-'.
6271 * While technically a valid reference name, this case is usually
6272 * an unintended typo.
6274 if (refname
[0] == '-')
6275 return got_error_path(refname
, GOT_ERR_REF_NAME_MINUS
);
6277 err
= got_ref_open(&target_ref
, repo
, target
, 0);
6281 err
= got_ref_alloc_symref(&ref
, refname
, target_ref
);
6285 err
= got_ref_write(ref
, repo
);
6288 got_ref_close(target_ref
);
6294 static const struct got_error
*
6295 cmd_ref(int argc
, char *argv
[])
6297 const struct got_error
*error
= NULL
;
6298 struct got_repository
*repo
= NULL
;
6299 struct got_worktree
*worktree
= NULL
;
6300 char *cwd
= NULL
, *repo_path
= NULL
;
6301 int ch
, do_list
= 0, do_delete
= 0, sort_by_time
= 0;
6302 const char *obj_arg
= NULL
, *symref_target
= NULL
;
6303 char *refname
= NULL
;
6304 int *pack_fds
= NULL
;
6306 while ((ch
= getopt(argc
, argv
, "c:dr:ls:t")) != -1) {
6315 repo_path
= realpath(optarg
, NULL
);
6316 if (repo_path
== NULL
)
6317 return got_error_from_errno2("realpath",
6319 got_path_strip_trailing_slashes(repo_path
);
6325 symref_target
= optarg
;
6336 if (obj_arg
&& do_list
)
6337 option_conflict('c', 'l');
6338 if (obj_arg
&& do_delete
)
6339 option_conflict('c', 'd');
6340 if (obj_arg
&& symref_target
)
6341 option_conflict('c', 's');
6342 if (symref_target
&& do_delete
)
6343 option_conflict('s', 'd');
6344 if (symref_target
&& do_list
)
6345 option_conflict('s', 'l');
6346 if (do_delete
&& do_list
)
6347 option_conflict('d', 'l');
6348 if (sort_by_time
&& !do_list
)
6349 errx(1, "-t option requires -l option");
6355 if (argc
!= 0 && argc
!= 1)
6358 refname
= strdup(argv
[0]);
6359 if (refname
== NULL
) {
6360 error
= got_error_from_errno("strdup");
6367 refname
= strdup(argv
[0]);
6368 if (refname
== NULL
) {
6369 error
= got_error_from_errno("strdup");
6375 got_path_strip_trailing_slashes(refname
);
6378 if (pledge("stdio rpath wpath cpath fattr flock proc exec "
6379 "sendfd unveil", NULL
) == -1)
6382 cwd
= getcwd(NULL
, 0);
6384 error
= got_error_from_errno("getcwd");
6388 error
= got_repo_pack_fds_open(&pack_fds
);
6392 if (repo_path
== NULL
) {
6393 error
= got_worktree_open(&worktree
, cwd
);
6394 if (error
&& error
->code
!= GOT_ERR_NOT_WORKTREE
)
6400 strdup(got_worktree_get_repo_path(worktree
));
6401 if (repo_path
== NULL
)
6402 error
= got_error_from_errno("strdup");
6406 repo_path
= strdup(cwd
);
6407 if (repo_path
== NULL
) {
6408 error
= got_error_from_errno("strdup");
6414 error
= got_repo_open(&repo
, repo_path
, NULL
, pack_fds
);
6420 /* Remove "cpath" promise. */
6421 if (pledge("stdio rpath wpath flock proc exec sendfd unveil",
6427 error
= apply_unveil(got_repo_get_path(repo
), do_list
,
6428 worktree
? got_worktree_get_root_path(worktree
) : NULL
);
6433 error
= list_refs(repo
, refname
, sort_by_time
);
6435 error
= delete_ref_by_name(repo
, refname
);
6436 else if (symref_target
)
6437 error
= add_symref(repo
, refname
, symref_target
);
6439 if (obj_arg
== NULL
)
6441 error
= add_ref(repo
, refname
, obj_arg
);
6446 const struct got_error
*close_err
= got_repo_close(repo
);
6451 got_worktree_close(worktree
);
6453 const struct got_error
*pack_err
=
6454 got_repo_pack_fds_close(pack_fds
);
6467 "usage: %s branch [-c commit] [-d] [-r repository] [-l] [-t] "
6468 "[-n] [name]\n", getprogname());
6472 static const struct got_error
*
6473 list_branch(struct got_repository
*repo
, struct got_worktree
*worktree
,
6474 struct got_reference
*ref
)
6476 const struct got_error
*err
= NULL
;
6477 const char *refname
, *marker
= " ";
6480 refname
= got_ref_get_name(ref
);
6481 if (worktree
&& strcmp(refname
,
6482 got_worktree_get_head_ref_name(worktree
)) == 0) {
6483 struct got_object_id
*id
= NULL
;
6485 err
= got_ref_resolve(&id
, repo
, ref
);
6488 if (got_object_id_cmp(id
,
6489 got_worktree_get_base_commit_id(worktree
)) == 0)
6496 if (strncmp(refname
, "refs/heads/", 11) == 0)
6498 if (strncmp(refname
, "refs/got/worktree/", 18) == 0)
6500 if (strncmp(refname
, "refs/remotes/", 13) == 0)
6503 refstr
= got_ref_to_str(ref
);
6505 return got_error_from_errno("got_ref_to_str");
6507 printf("%s%s: %s\n", marker
, refname
, refstr
);
6512 static const struct got_error
*
6513 show_current_branch(struct got_repository
*repo
, struct got_worktree
*worktree
)
6515 const char *refname
;
6517 if (worktree
== NULL
)
6518 return got_error(GOT_ERR_NOT_WORKTREE
);
6520 refname
= got_worktree_get_head_ref_name(worktree
);
6522 if (strncmp(refname
, "refs/heads/", 11) == 0)
6524 if (strncmp(refname
, "refs/got/worktree/", 18) == 0)
6527 printf("%s\n", refname
);
6532 static const struct got_error
*
6533 list_branches(struct got_repository
*repo
, struct got_worktree
*worktree
,
6536 static const struct got_error
*err
= NULL
;
6537 struct got_reflist_head refs
;
6538 struct got_reflist_entry
*re
;
6539 struct got_reference
*temp_ref
= NULL
;
6540 int rebase_in_progress
, histedit_in_progress
;
6545 err
= got_worktree_rebase_in_progress(&rebase_in_progress
,
6550 err
= got_worktree_histedit_in_progress(&histedit_in_progress
,
6555 if (rebase_in_progress
|| histedit_in_progress
) {
6556 err
= got_ref_open(&temp_ref
, repo
,
6557 got_worktree_get_head_ref_name(worktree
), 0);
6560 list_branch(repo
, worktree
, temp_ref
);
6561 got_ref_close(temp_ref
);
6565 err
= got_ref_list(&refs
, repo
, "refs/heads", sort_by_time
?
6566 got_ref_cmp_by_commit_timestamp_descending
: got_ref_cmp_by_name
,
6571 TAILQ_FOREACH(re
, &refs
, entry
)
6572 list_branch(repo
, worktree
, re
->ref
);
6574 got_ref_list_free(&refs
);
6576 err
= got_ref_list(&refs
, repo
, "refs/remotes", sort_by_time
?
6577 got_ref_cmp_by_commit_timestamp_descending
: got_ref_cmp_by_name
,
6582 TAILQ_FOREACH(re
, &refs
, entry
)
6583 list_branch(repo
, worktree
, re
->ref
);
6585 got_ref_list_free(&refs
);
6590 static const struct got_error
*
6591 delete_branch(struct got_repository
*repo
, struct got_worktree
*worktree
,
6592 const char *branch_name
)
6594 const struct got_error
*err
= NULL
;
6595 struct got_reference
*ref
= NULL
;
6596 char *refname
, *remote_refname
= NULL
;
6598 if (strncmp(branch_name
, "refs/", 5) == 0)
6600 if (strncmp(branch_name
, "heads/", 6) == 0)
6602 else if (strncmp(branch_name
, "remotes/", 8) == 0)
6605 if (asprintf(&refname
, "refs/heads/%s", branch_name
) == -1)
6606 return got_error_from_errno("asprintf");
6608 if (asprintf(&remote_refname
, "refs/remotes/%s",
6609 branch_name
) == -1) {
6610 err
= got_error_from_errno("asprintf");
6614 err
= got_ref_open(&ref
, repo
, refname
, 0);
6616 const struct got_error
*err2
;
6617 if (err
->code
!= GOT_ERR_NOT_REF
)
6620 * Keep 'err' intact such that if neither branch exists
6621 * we report "refs/heads" rather than "refs/remotes" in
6622 * our error message.
6624 err2
= got_ref_open(&ref
, repo
, remote_refname
, 0);
6631 strcmp(got_worktree_get_head_ref_name(worktree
),
6632 got_ref_get_name(ref
)) == 0) {
6633 err
= got_error_msg(GOT_ERR_SAME_BRANCH
,
6634 "will not delete this work tree's current branch");
6638 err
= delete_ref(repo
, ref
);
6643 free(remote_refname
);
6647 static const struct got_error
*
6648 add_branch(struct got_repository
*repo
, const char *branch_name
,
6649 struct got_object_id
*base_commit_id
)
6651 const struct got_error
*err
= NULL
;
6652 struct got_reference
*ref
= NULL
;
6653 char *base_refname
= NULL
, *refname
= NULL
;
6656 * Don't let the user create a branch name with a leading '-'.
6657 * While technically a valid reference name, this case is usually
6658 * an unintended typo.
6660 if (branch_name
[0] == '-')
6661 return got_error_path(branch_name
, GOT_ERR_REF_NAME_MINUS
);
6663 if (strncmp(branch_name
, "refs/heads/", 11) == 0)
6666 if (asprintf(&refname
, "refs/heads/%s", branch_name
) == -1) {
6667 err
= got_error_from_errno("asprintf");
6671 err
= got_ref_open(&ref
, repo
, refname
, 0);
6673 err
= got_error(GOT_ERR_BRANCH_EXISTS
);
6675 } else if (err
->code
!= GOT_ERR_NOT_REF
)
6678 err
= got_ref_alloc(&ref
, refname
, base_commit_id
);
6682 err
= got_ref_write(ref
, repo
);
6691 static const struct got_error
*
6692 cmd_branch(int argc
, char *argv
[])
6694 const struct got_error
*error
= NULL
;
6695 struct got_repository
*repo
= NULL
;
6696 struct got_worktree
*worktree
= NULL
;
6697 char *cwd
= NULL
, *repo_path
= NULL
;
6698 int ch
, do_list
= 0, do_show
= 0, do_update
= 1, sort_by_time
= 0;
6699 const char *delref
= NULL
, *commit_id_arg
= NULL
;
6700 struct got_reference
*ref
= NULL
;
6701 struct got_pathlist_head paths
;
6702 struct got_pathlist_entry
*pe
;
6703 struct got_object_id
*commit_id
= NULL
;
6704 char *commit_id_str
= NULL
;
6705 int *pack_fds
= NULL
;
6709 while ((ch
= getopt(argc
, argv
, "c:d:r:lnt")) != -1) {
6712 commit_id_arg
= optarg
;
6718 repo_path
= realpath(optarg
, NULL
);
6719 if (repo_path
== NULL
)
6720 return got_error_from_errno2("realpath",
6722 got_path_strip_trailing_slashes(repo_path
);
6739 if (do_list
&& delref
)
6740 option_conflict('l', 'd');
6741 if (sort_by_time
&& !do_list
)
6742 errx(1, "-t option requires -l option");
6747 if (!do_list
&& !delref
&& argc
== 0)
6750 if ((do_list
|| delref
|| do_show
) && commit_id_arg
!= NULL
)
6751 errx(1, "-c option can only be used when creating a branch");
6753 if (do_list
|| delref
) {
6756 } else if (!do_show
&& argc
!= 1)
6760 if (pledge("stdio rpath wpath cpath fattr flock proc exec "
6761 "sendfd unveil", NULL
) == -1)
6764 cwd
= getcwd(NULL
, 0);
6766 error
= got_error_from_errno("getcwd");
6770 error
= got_repo_pack_fds_open(&pack_fds
);
6774 if (repo_path
== NULL
) {
6775 error
= got_worktree_open(&worktree
, cwd
);
6776 if (error
&& error
->code
!= GOT_ERR_NOT_WORKTREE
)
6782 strdup(got_worktree_get_repo_path(worktree
));
6783 if (repo_path
== NULL
)
6784 error
= got_error_from_errno("strdup");
6788 repo_path
= strdup(cwd
);
6789 if (repo_path
== NULL
) {
6790 error
= got_error_from_errno("strdup");
6796 error
= got_repo_open(&repo
, repo_path
, NULL
, pack_fds
);
6801 if (do_list
|| do_show
) {
6802 /* Remove "cpath" promise. */
6803 if (pledge("stdio rpath wpath flock proc exec sendfd unveil",
6809 error
= apply_unveil(got_repo_get_path(repo
), do_list
,
6810 worktree
? got_worktree_get_root_path(worktree
) : NULL
);
6815 error
= show_current_branch(repo
, worktree
);
6817 error
= list_branches(repo
, worktree
, sort_by_time
);
6819 error
= delete_branch(repo
, worktree
, delref
);
6821 struct got_reflist_head refs
;
6823 error
= got_ref_list(&refs
, repo
, NULL
, got_ref_cmp_by_name
,
6827 if (commit_id_arg
== NULL
)
6828 commit_id_arg
= worktree
?
6829 got_worktree_get_head_ref_name(worktree
) :
6831 error
= got_repo_match_object_id(&commit_id
, NULL
,
6832 commit_id_arg
, GOT_OBJ_TYPE_COMMIT
, &refs
, repo
);
6833 got_ref_list_free(&refs
);
6836 error
= add_branch(repo
, argv
[0], commit_id
);
6839 if (worktree
&& do_update
) {
6840 struct got_update_progress_arg upa
;
6841 char *branch_refname
= NULL
;
6843 error
= got_object_id_str(&commit_id_str
, commit_id
);
6846 error
= get_worktree_paths_from_argv(&paths
, 0, NULL
,
6850 if (asprintf(&branch_refname
, "refs/heads/%s", argv
[0])
6852 error
= got_error_from_errno("asprintf");
6855 error
= got_ref_open(&ref
, repo
, branch_refname
, 0);
6856 free(branch_refname
);
6859 error
= switch_head_ref(ref
, commit_id
, worktree
,
6863 error
= got_worktree_set_base_commit_id(worktree
, repo
,
6867 memset(&upa
, 0, sizeof(upa
));
6868 error
= got_worktree_checkout_files(worktree
, &paths
,
6869 repo
, update_progress
, &upa
, check_cancelled
,
6873 if (upa
.did_something
) {
6874 printf("Updated to %s: %s\n",
6875 got_worktree_get_head_ref_name(worktree
),
6878 print_update_progress_stats(&upa
);
6885 const struct got_error
*close_err
= got_repo_close(repo
);
6890 got_worktree_close(worktree
);
6892 const struct got_error
*pack_err
=
6893 got_repo_pack_fds_close(pack_fds
);
6900 free(commit_id_str
);
6901 TAILQ_FOREACH(pe
, &paths
, entry
)
6902 free((char *)pe
->path
);
6903 got_pathlist_free(&paths
);
6912 "usage: %s tag [-c commit] [-r repository] [-l] "
6913 "[-m message] [-s signer-id] [-V] name\n",
6919 static const struct got_error
*
6920 sort_tags(struct got_reflist_head
*sorted
, struct got_reflist_head
*tags
)
6922 const struct got_error
*err
= NULL
;
6923 struct got_reflist_entry
*re
, *se
, *new;
6924 struct got_object_id
*re_id
, *se_id
;
6925 struct got_tag_object
*re_tag
, *se_tag
;
6926 time_t re_time
, se_time
;
6928 STAILQ_FOREACH(re
, tags
, entry
) {
6929 se
= STAILQ_FIRST(sorted
);
6931 err
= got_reflist_entry_dup(&new, re
);
6934 STAILQ_INSERT_HEAD(sorted
, new, entry
);
6937 err
= got_ref_resolve(&re_id
, repo
, re
->ref
);
6940 err
= got_object_open_as_tag(&re_tag
, repo
, re_id
);
6944 re_time
= got_object_tag_get_tagger_time(re_tag
);
6945 got_object_tag_close(re_tag
);
6949 err
= got_ref_resolve(&se_id
, repo
, re
->ref
);
6952 err
= got_object_open_as_tag(&se_tag
, repo
, se_id
);
6956 se_time
= got_object_tag_get_tagger_time(se_tag
);
6957 got_object_tag_close(se_tag
);
6959 if (se_time
> re_time
) {
6960 err
= got_reflist_entry_dup(&new, re
);
6963 STAILQ_INSERT_AFTER(sorted
, se
, new, entry
);
6966 se
= STAILQ_NEXT(se
, entry
);
6975 static const struct got_error
*
6976 get_tag_refname(char **refname
, const char *tag_name
)
6978 const struct got_error
*err
;
6980 if (strncmp("refs/tags/", tag_name
, 10) == 0) {
6981 *refname
= strdup(tag_name
);
6982 if (*refname
== NULL
)
6983 return got_error_from_errno("strdup");
6984 } else if (asprintf(refname
, "refs/tags/%s", tag_name
) == -1) {
6985 err
= got_error_from_errno("asprintf");
6993 static const struct got_error
*
6994 list_tags(struct got_repository
*repo
, const char *tag_name
, int verify_tags
,
6995 const char *allowed_signers
, const char *revoked_signers
, int verbosity
)
6997 static const struct got_error
*err
= NULL
;
6998 struct got_reflist_head refs
;
6999 struct got_reflist_entry
*re
;
7000 char *wanted_refname
= NULL
;
7005 err
= got_ref_list(&refs
, repo
, "refs/tags", got_ref_cmp_tags
, repo
);
7010 struct got_reference
*ref
;
7011 err
= get_tag_refname(&wanted_refname
, tag_name
);
7014 /* Wanted tag reference should exist. */
7015 err
= got_ref_open(&ref
, repo
, wanted_refname
, 0);
7021 TAILQ_FOREACH(re
, &refs
, entry
) {
7022 const char *refname
;
7023 char *refstr
, *tagmsg0
, *tagmsg
, *line
, *id_str
, *datestr
;
7025 const char *tagger
, *ssh_sig
= NULL
;
7026 char *sig_msg
= NULL
;
7028 struct got_object_id
*id
;
7029 struct got_tag_object
*tag
;
7030 struct got_commit_object
*commit
= NULL
;
7032 refname
= got_ref_get_name(re
->ref
);
7033 if (strncmp(refname
, "refs/tags/", 10) != 0 ||
7034 (wanted_refname
&& strcmp(refname
, wanted_refname
) != 0))
7037 refstr
= got_ref_to_str(re
->ref
);
7038 if (refstr
== NULL
) {
7039 err
= got_error_from_errno("got_ref_to_str");
7043 err
= got_ref_resolve(&id
, repo
, re
->ref
);
7046 err
= got_object_open_as_tag(&tag
, repo
, id
);
7048 if (err
->code
!= GOT_ERR_OBJ_TYPE
) {
7052 /* "lightweight" tag */
7053 err
= got_object_open_as_commit(&commit
, repo
, id
);
7058 tagger
= got_object_commit_get_committer(commit
);
7060 got_object_commit_get_committer_time(commit
);
7061 err
= got_object_id_str(&id_str
, id
);
7067 tagger
= got_object_tag_get_tagger(tag
);
7068 tagger_time
= got_object_tag_get_tagger_time(tag
);
7069 err
= got_object_id_str(&id_str
,
7070 got_object_tag_get_object_id(tag
));
7076 ssh_sig
= got_sigs_get_tagmsg_ssh_signature(
7077 got_object_tag_get_message(tag
));
7078 if (ssh_sig
&& allowed_signers
== NULL
) {
7079 err
= got_error_msg(
7080 GOT_ERR_VERIFY_TAG_SIGNATURE
,
7081 "SSH signature verification requires "
7082 "setting allowed_signers in "
7088 printf("%stag %s %s\n", GOT_COMMIT_SEP_STR
, refname
, refstr
);
7090 printf("from: %s\n", tagger
);
7091 datestr
= get_datestr(&tagger_time
, datebuf
);
7093 printf("date: %s UTC\n", datestr
);
7095 printf("object: %s %s\n", GOT_OBJ_LABEL_COMMIT
, id_str
);
7097 switch (got_object_tag_get_object_type(tag
)) {
7098 case GOT_OBJ_TYPE_BLOB
:
7099 printf("object: %s %s\n", GOT_OBJ_LABEL_BLOB
,
7102 case GOT_OBJ_TYPE_TREE
:
7103 printf("object: %s %s\n", GOT_OBJ_LABEL_TREE
,
7106 case GOT_OBJ_TYPE_COMMIT
:
7107 printf("object: %s %s\n", GOT_OBJ_LABEL_COMMIT
,
7110 case GOT_OBJ_TYPE_TAG
:
7111 printf("object: %s %s\n", GOT_OBJ_LABEL_TAG
,
7121 err
= got_sigs_verify_tag_ssh(&sig_msg
, tag
, ssh_sig
,
7122 allowed_signers
, revoked_signers
, verbosity
);
7123 if (err
&& err
->code
== GOT_ERR_BAD_TAG_SIGNATURE
)
7127 printf("signature: %s", sig_msg
);
7133 err
= got_object_commit_get_logmsg(&tagmsg0
, commit
);
7136 got_object_commit_close(commit
);
7138 tagmsg0
= strdup(got_object_tag_get_message(tag
));
7139 got_object_tag_close(tag
);
7140 if (tagmsg0
== NULL
) {
7141 err
= got_error_from_errno("strdup");
7148 line
= strsep(&tagmsg
, "\n");
7150 printf(" %s\n", line
);
7155 got_ref_list_free(&refs
);
7156 free(wanted_refname
);
7158 if (err
== NULL
&& bad_sigs
)
7159 err
= got_error(GOT_ERR_BAD_TAG_SIGNATURE
);
7163 static const struct got_error
*
7164 get_tag_message(char **tagmsg
, char **tagmsg_path
, const char *commit_id_str
,
7165 const char *tag_name
, const char *repo_path
)
7167 const struct got_error
*err
= NULL
;
7168 char *template = NULL
, *initial_content
= NULL
;
7169 char *editor
= NULL
;
7170 int initial_content_len
;
7173 if (asprintf(&template, GOT_TMPDIR_STR
"/got-tagmsg") == -1) {
7174 err
= got_error_from_errno("asprintf");
7178 initial_content_len
= asprintf(&initial_content
,
7179 "\n# tagging commit %s as %s\n",
7180 commit_id_str
, tag_name
);
7181 if (initial_content_len
== -1) {
7182 err
= got_error_from_errno("asprintf");
7186 err
= got_opentemp_named_fd(tagmsg_path
, &fd
, template);
7190 if (write(fd
, initial_content
, initial_content_len
) == -1) {
7191 err
= got_error_from_errno2("write", *tagmsg_path
);
7195 err
= get_editor(&editor
);
7198 err
= edit_logmsg(tagmsg
, editor
, *tagmsg_path
, initial_content
,
7199 initial_content_len
, 1);
7201 free(initial_content
);
7205 if (fd
!= -1 && close(fd
) == -1 && err
== NULL
)
7206 err
= got_error_from_errno2("close", *tagmsg_path
);
7215 static const struct got_error
*
7216 add_tag(struct got_repository
*repo
, const char *tagger
,
7217 const char *tag_name
, const char *commit_arg
, const char *tagmsg_arg
,
7218 const char *signer_id
, int verbosity
)
7220 const struct got_error
*err
= NULL
;
7221 struct got_object_id
*commit_id
= NULL
, *tag_id
= NULL
;
7222 char *label
= NULL
, *commit_id_str
= NULL
;
7223 struct got_reference
*ref
= NULL
;
7224 char *refname
= NULL
, *tagmsg
= NULL
;
7225 char *tagmsg_path
= NULL
, *tag_id_str
= NULL
;
7226 int preserve_tagmsg
= 0;
7227 struct got_reflist_head refs
;
7232 * Don't let the user create a tag name with a leading '-'.
7233 * While technically a valid reference name, this case is usually
7234 * an unintended typo.
7236 if (tag_name
[0] == '-')
7237 return got_error_path(tag_name
, GOT_ERR_REF_NAME_MINUS
);
7239 err
= got_ref_list(&refs
, repo
, NULL
, got_ref_cmp_by_name
, NULL
);
7243 err
= got_repo_match_object_id(&commit_id
, &label
, commit_arg
,
7244 GOT_OBJ_TYPE_COMMIT
, &refs
, repo
);
7248 err
= got_object_id_str(&commit_id_str
, commit_id
);
7252 err
= get_tag_refname(&refname
, tag_name
);
7255 if (strncmp("refs/tags/", tag_name
, 10) == 0)
7258 err
= got_ref_open(&ref
, repo
, refname
, 0);
7260 err
= got_error(GOT_ERR_TAG_EXISTS
);
7262 } else if (err
->code
!= GOT_ERR_NOT_REF
)
7265 if (tagmsg_arg
== NULL
) {
7266 err
= get_tag_message(&tagmsg
, &tagmsg_path
, commit_id_str
,
7267 tag_name
, got_repo_get_path(repo
));
7269 if (err
->code
!= GOT_ERR_COMMIT_MSG_EMPTY
&&
7270 tagmsg_path
!= NULL
)
7271 preserve_tagmsg
= 1;
7274 /* Editor is done; we can now apply unveil(2) */
7275 err
= got_sigs_apply_unveil();
7278 err
= apply_unveil(got_repo_get_path(repo
), 0, NULL
);
7283 err
= got_object_tag_create(&tag_id
, tag_name
, commit_id
,
7284 tagger
, time(NULL
), tagmsg
? tagmsg
: tagmsg_arg
, signer_id
, repo
,
7288 preserve_tagmsg
= 1;
7292 err
= got_ref_alloc(&ref
, refname
, tag_id
);
7295 preserve_tagmsg
= 1;
7299 err
= got_ref_write(ref
, repo
);
7302 preserve_tagmsg
= 1;
7306 err
= got_object_id_str(&tag_id_str
, tag_id
);
7309 preserve_tagmsg
= 1;
7312 printf("Created tag %s\n", tag_id_str
);
7314 if (preserve_tagmsg
) {
7315 fprintf(stderr
, "%s: tag message preserved in %s\n",
7316 getprogname(), tagmsg_path
);
7317 } else if (tagmsg_path
&& unlink(tagmsg_path
) == -1 && err
== NULL
)
7318 err
= got_error_from_errno2("unlink", tagmsg_path
);
7323 free(commit_id_str
);
7327 got_ref_list_free(&refs
);
7331 static const struct got_error
*
7332 cmd_tag(int argc
, char *argv
[])
7334 const struct got_error
*error
= NULL
;
7335 struct got_repository
*repo
= NULL
;
7336 struct got_worktree
*worktree
= NULL
;
7337 char *cwd
= NULL
, *repo_path
= NULL
, *commit_id_str
= NULL
;
7338 char *gitconfig_path
= NULL
, *tagger
= NULL
;
7339 char *allowed_signers
= NULL
, *revoked_signers
= NULL
;
7340 const char *tag_name
= NULL
, *commit_id_arg
= NULL
, *tagmsg
= NULL
;
7341 int ch
, do_list
= 0, verify_tags
= 0, verbosity
= 0;
7342 const char *signer_id
= NULL
;
7343 int *pack_fds
= NULL
;
7345 while ((ch
= getopt(argc
, argv
, "c:m:r:ls:Vv")) != -1) {
7348 commit_id_arg
= optarg
;
7354 repo_path
= realpath(optarg
, NULL
);
7355 if (repo_path
== NULL
)
7356 return got_error_from_errno2("realpath",
7358 got_path_strip_trailing_slashes(repo_path
);
7372 else if (verbosity
< 3)
7384 if (do_list
|| verify_tags
) {
7385 if (commit_id_arg
!= NULL
)
7387 "-c option can only be used when creating a tag");
7389 option_conflict('l', 'm');
7391 option_conflict('l', 's');
7393 option_conflict('l', 'V');
7396 } else if (argc
!= 1)
7400 if (commit_id_arg
!= NULL
)
7402 "-c option can only be used when creating a tag");
7404 option_conflict('V', 'm');
7406 option_conflict('V', 's');
7408 option_conflict('V', 'l');
7415 if (pledge("stdio rpath wpath cpath fattr flock proc exec "
7416 "sendfd unveil", NULL
) == -1)
7419 cwd
= getcwd(NULL
, 0);
7421 error
= got_error_from_errno("getcwd");
7425 error
= got_repo_pack_fds_open(&pack_fds
);
7429 if (repo_path
== NULL
) {
7430 error
= got_worktree_open(&worktree
, cwd
);
7431 if (error
&& error
->code
!= GOT_ERR_NOT_WORKTREE
)
7437 strdup(got_worktree_get_repo_path(worktree
));
7438 if (repo_path
== NULL
)
7439 error
= got_error_from_errno("strdup");
7443 repo_path
= strdup(cwd
);
7444 if (repo_path
== NULL
) {
7445 error
= got_error_from_errno("strdup");
7451 if (do_list
|| verify_tags
) {
7452 error
= got_repo_open(&repo
, repo_path
, NULL
, pack_fds
);
7455 error
= get_allowed_signers(&allowed_signers
, repo
, worktree
);
7458 error
= get_revoked_signers(&revoked_signers
, repo
, worktree
);
7462 /* Release work tree lock. */
7463 got_worktree_close(worktree
);
7468 * Remove "cpath" promise unless needed for signature tmpfile
7472 got_sigs_apply_unveil();
7475 if (pledge("stdio rpath wpath flock proc exec sendfd "
7476 "unveil", NULL
) == -1)
7480 error
= apply_unveil(got_repo_get_path(repo
), 1, NULL
);
7483 error
= list_tags(repo
, tag_name
, verify_tags
, allowed_signers
,
7484 revoked_signers
, verbosity
);
7486 error
= get_gitconfig_path(&gitconfig_path
);
7489 error
= got_repo_open(&repo
, repo_path
, gitconfig_path
,
7494 error
= get_author(&tagger
, repo
, worktree
);
7498 /* Release work tree lock. */
7499 got_worktree_close(worktree
);
7505 error
= got_sigs_apply_unveil();
7509 error
= apply_unveil(got_repo_get_path(repo
), 0, NULL
);
7514 if (commit_id_arg
== NULL
) {
7515 struct got_reference
*head_ref
;
7516 struct got_object_id
*commit_id
;
7517 error
= got_ref_open(&head_ref
, repo
,
7518 worktree
? got_worktree_get_head_ref_name(worktree
)
7522 error
= got_ref_resolve(&commit_id
, repo
, head_ref
);
7523 got_ref_close(head_ref
);
7526 error
= got_object_id_str(&commit_id_str
, commit_id
);
7532 error
= add_tag(repo
, tagger
, tag_name
,
7533 commit_id_str
? commit_id_str
: commit_id_arg
, tagmsg
,
7534 signer_id
, verbosity
);
7538 const struct got_error
*close_err
= got_repo_close(repo
);
7543 got_worktree_close(worktree
);
7545 const struct got_error
*pack_err
=
7546 got_repo_pack_fds_close(pack_fds
);
7552 free(gitconfig_path
);
7553 free(commit_id_str
);
7555 free(allowed_signers
);
7556 free(revoked_signers
);
7563 fprintf(stderr
, "usage: %s add [-R] [-I] path ...\n",
7568 static const struct got_error
*
7569 add_progress(void *arg
, unsigned char status
, const char *path
)
7571 while (path
[0] == '/')
7573 printf("%c %s\n", status
, path
);
7577 static const struct got_error
*
7578 cmd_add(int argc
, char *argv
[])
7580 const struct got_error
*error
= NULL
;
7581 struct got_repository
*repo
= NULL
;
7582 struct got_worktree
*worktree
= NULL
;
7584 struct got_pathlist_head paths
;
7585 struct got_pathlist_entry
*pe
;
7586 int ch
, can_recurse
= 0, no_ignores
= 0;
7587 int *pack_fds
= NULL
;
7591 while ((ch
= getopt(argc
, argv
, "IR")) != -1) {
7609 if (pledge("stdio rpath wpath cpath flock proc exec sendfd unveil",
7616 cwd
= getcwd(NULL
, 0);
7618 error
= got_error_from_errno("getcwd");
7622 error
= got_repo_pack_fds_open(&pack_fds
);
7626 error
= got_worktree_open(&worktree
, cwd
);
7628 if (error
->code
== GOT_ERR_NOT_WORKTREE
)
7629 error
= wrap_not_worktree_error(error
, "add", cwd
);
7633 error
= got_repo_open(&repo
, got_worktree_get_repo_path(worktree
),
7638 error
= apply_unveil(got_repo_get_path(repo
), 1,
7639 got_worktree_get_root_path(worktree
));
7643 error
= get_worktree_paths_from_argv(&paths
, argc
, argv
, worktree
);
7650 TAILQ_FOREACH(pe
, &paths
, entry
) {
7651 if (asprintf(&ondisk_path
, "%s/%s",
7652 got_worktree_get_root_path(worktree
),
7654 error
= got_error_from_errno("asprintf");
7657 if (lstat(ondisk_path
, &sb
) == -1) {
7658 if (errno
== ENOENT
) {
7662 error
= got_error_from_errno2("lstat",
7668 if (S_ISDIR(sb
.st_mode
)) {
7669 error
= got_error_msg(GOT_ERR_BAD_PATH
,
7670 "adding directories requires -R option");
7676 error
= got_worktree_schedule_add(worktree
, &paths
, add_progress
,
7677 NULL
, repo
, no_ignores
);
7680 const struct got_error
*close_err
= got_repo_close(repo
);
7685 got_worktree_close(worktree
);
7687 const struct got_error
*pack_err
=
7688 got_repo_pack_fds_close(pack_fds
);
7692 TAILQ_FOREACH(pe
, &paths
, entry
)
7693 free((char *)pe
->path
);
7694 got_pathlist_free(&paths
);
7702 fprintf(stderr
, "usage: %s remove [-f] [-k] [-R] [-s status-codes] "
7703 "path ...\n", getprogname());
7707 static const struct got_error
*
7708 print_remove_status(void *arg
, unsigned char status
,
7709 unsigned char staged_status
, const char *path
)
7711 while (path
[0] == '/')
7713 if (status
== GOT_STATUS_NONEXISTENT
)
7715 if (status
== staged_status
&& (status
== GOT_STATUS_DELETE
))
7716 status
= GOT_STATUS_NO_CHANGE
;
7717 printf("%c%c %s\n", status
, staged_status
, path
);
7721 static const struct got_error
*
7722 cmd_remove(int argc
, char *argv
[])
7724 const struct got_error
*error
= NULL
;
7725 struct got_worktree
*worktree
= NULL
;
7726 struct got_repository
*repo
= NULL
;
7727 const char *status_codes
= NULL
;
7729 struct got_pathlist_head paths
;
7730 struct got_pathlist_entry
*pe
;
7731 int ch
, delete_local_mods
= 0, can_recurse
= 0, keep_on_disk
= 0, i
;
7732 int ignore_missing_paths
= 0;
7733 int *pack_fds
= NULL
;
7737 while ((ch
= getopt(argc
, argv
, "fkRs:")) != -1) {
7740 delete_local_mods
= 1;
7741 ignore_missing_paths
= 1;
7750 for (i
= 0; i
< strlen(optarg
); i
++) {
7751 switch (optarg
[i
]) {
7752 case GOT_STATUS_MODIFY
:
7753 delete_local_mods
= 1;
7755 case GOT_STATUS_MISSING
:
7756 ignore_missing_paths
= 1;
7759 errx(1, "invalid status code '%c'",
7763 status_codes
= optarg
;
7775 if (pledge("stdio rpath wpath cpath flock proc exec sendfd unveil",
7782 cwd
= getcwd(NULL
, 0);
7784 error
= got_error_from_errno("getcwd");
7788 error
= got_repo_pack_fds_open(&pack_fds
);
7792 error
= got_worktree_open(&worktree
, cwd
);
7794 if (error
->code
== GOT_ERR_NOT_WORKTREE
)
7795 error
= wrap_not_worktree_error(error
, "remove", cwd
);
7799 error
= got_repo_open(&repo
, got_worktree_get_repo_path(worktree
),
7804 error
= apply_unveil(got_repo_get_path(repo
), 1,
7805 got_worktree_get_root_path(worktree
));
7809 error
= get_worktree_paths_from_argv(&paths
, argc
, argv
, worktree
);
7816 TAILQ_FOREACH(pe
, &paths
, entry
) {
7817 if (asprintf(&ondisk_path
, "%s/%s",
7818 got_worktree_get_root_path(worktree
),
7820 error
= got_error_from_errno("asprintf");
7823 if (lstat(ondisk_path
, &sb
) == -1) {
7824 if (errno
== ENOENT
) {
7828 error
= got_error_from_errno2("lstat",
7834 if (S_ISDIR(sb
.st_mode
)) {
7835 error
= got_error_msg(GOT_ERR_BAD_PATH
,
7836 "removing directories requires -R option");
7842 error
= got_worktree_schedule_delete(worktree
, &paths
,
7843 delete_local_mods
, status_codes
, print_remove_status
, NULL
,
7844 repo
, keep_on_disk
, ignore_missing_paths
);
7847 const struct got_error
*close_err
= got_repo_close(repo
);
7852 got_worktree_close(worktree
);
7854 const struct got_error
*pack_err
=
7855 got_repo_pack_fds_close(pack_fds
);
7859 TAILQ_FOREACH(pe
, &paths
, entry
)
7860 free((char *)pe
->path
);
7861 got_pathlist_free(&paths
);
7869 fprintf(stderr
, "usage: %s patch [-n] [-p strip-count] "
7870 "[-R] [patchfile]\n", getprogname());
7874 static const struct got_error
*
7875 patch_from_stdin(int *patchfd
)
7877 const struct got_error
*err
= NULL
;
7879 char *path
, buf
[BUFSIZ
];
7880 sig_t sighup
, sigint
, sigquit
;
7882 err
= got_opentemp_named_fd(&path
, patchfd
,
7883 GOT_TMPDIR_STR
"/got-patch");
7889 sighup
= signal(SIGHUP
, SIG_DFL
);
7890 sigint
= signal(SIGINT
, SIG_DFL
);
7891 sigquit
= signal(SIGQUIT
, SIG_DFL
);
7894 r
= read(0, buf
, sizeof(buf
));
7896 err
= got_error_from_errno("read");
7901 if (write(*patchfd
, buf
, r
) == -1) {
7902 err
= got_error_from_errno("write");
7907 signal(SIGHUP
, sighup
);
7908 signal(SIGINT
, sigint
);
7909 signal(SIGQUIT
, sigquit
);
7911 if (err
== NULL
&& lseek(*patchfd
, 0, SEEK_SET
) == -1)
7912 err
= got_error_from_errno("lseek");
7922 static const struct got_error
*
7923 patch_progress(void *arg
, const char *old
, const char *new,
7924 unsigned char status
, const struct got_error
*error
, int old_from
,
7925 int old_lines
, int new_from
, int new_lines
, int offset
,
7926 int ws_mangled
, const struct got_error
*hunk_err
)
7928 const char *path
= new == NULL
? old
: new;
7930 while (*path
== '/')
7934 printf("%c %s\n", status
, path
);
7937 fprintf(stderr
, "%s: %s\n", getprogname(), error
->msg
);
7939 if (offset
!= 0 || hunk_err
!= NULL
|| ws_mangled
) {
7940 printf("@@ -%d,%d +%d,%d @@ ", old_from
,
7941 old_lines
, new_from
, new_lines
);
7942 if (hunk_err
!= NULL
)
7943 printf("%s\n", hunk_err
->msg
);
7944 else if (offset
!= 0)
7945 printf("applied with offset %d\n", offset
);
7947 printf("hunk contains mangled whitespace\n");
7953 static const struct got_error
*
7954 cmd_patch(int argc
, char *argv
[])
7956 const struct got_error
*error
= NULL
, *close_error
= NULL
;
7957 struct got_worktree
*worktree
= NULL
;
7958 struct got_repository
*repo
= NULL
;
7961 int ch
, nop
= 0, strip
= -1, reverse
= 0;
7963 int *pack_fds
= NULL
;
7965 while ((ch
= getopt(argc
, argv
, "np:R")) != -1) {
7971 strip
= strtonum(optarg
, 0, INT_MAX
, &errstr
);
7973 errx(1, "pathname strip count is %s: %s",
7989 error
= patch_from_stdin(&patchfd
);
7992 } else if (argc
== 1) {
7993 patchfd
= open(argv
[0], O_RDONLY
);
7994 if (patchfd
== -1) {
7995 error
= got_error_from_errno2("open", argv
[0]);
8001 if ((cwd
= getcwd(NULL
, 0)) == NULL
) {
8002 error
= got_error_from_errno("getcwd");
8006 error
= got_repo_pack_fds_open(&pack_fds
);
8010 error
= got_worktree_open(&worktree
, cwd
);
8014 const char *repo_path
= got_worktree_get_repo_path(worktree
);
8015 error
= got_repo_open(&repo
, repo_path
, NULL
, pack_fds
);
8019 error
= apply_unveil(got_repo_get_path(repo
), 0,
8020 got_worktree_get_root_path(worktree
));
8025 if (pledge("stdio rpath wpath cpath fattr proc exec sendfd flock",
8030 error
= got_patch(patchfd
, worktree
, repo
, nop
, strip
, reverse
,
8031 &patch_progress
, NULL
, check_cancelled
, NULL
);
8035 close_error
= got_repo_close(repo
);
8037 error
= close_error
;
8039 if (worktree
!= NULL
) {
8040 close_error
= got_worktree_close(worktree
);
8042 error
= close_error
;
8045 const struct got_error
*pack_err
=
8046 got_repo_pack_fds_close(pack_fds
);
8057 fprintf(stderr
, "usage: %s revert [-p] [-F response-script] [-R] "
8058 "path ...\n", getprogname());
8062 static const struct got_error
*
8063 revert_progress(void *arg
, unsigned char status
, const char *path
)
8065 if (status
== GOT_STATUS_UNVERSIONED
)
8068 while (path
[0] == '/')
8070 printf("%c %s\n", status
, path
);
8074 struct choose_patch_arg
{
8075 FILE *patch_script_file
;
8079 static const struct got_error
*
8080 show_change(unsigned char status
, const char *path
, FILE *patch_file
, int n
,
8081 int nchanges
, const char *action
)
8083 const struct got_error
*err
;
8085 size_t linesize
= 0;
8089 case GOT_STATUS_ADD
:
8090 printf("A %s\n%s this addition? [y/n] ", path
, action
);
8092 case GOT_STATUS_DELETE
:
8093 printf("D %s\n%s this deletion? [y/n] ", path
, action
);
8095 case GOT_STATUS_MODIFY
:
8096 if (fseek(patch_file
, 0L, SEEK_SET
) == -1)
8097 return got_error_from_errno("fseek");
8098 printf(GOT_COMMIT_SEP_STR
);
8099 while ((linelen
= getline(&line
, &linesize
, patch_file
)) != -1)
8101 if (linelen
== -1 && ferror(patch_file
)) {
8102 err
= got_error_from_errno("getline");
8107 printf(GOT_COMMIT_SEP_STR
);
8108 printf("M %s (change %d of %d)\n%s this change? [y/n/q] ",
8109 path
, n
, nchanges
, action
);
8112 return got_error_path(path
, GOT_ERR_FILE_STATUS
);
8118 static const struct got_error
*
8119 choose_patch(int *choice
, void *arg
, unsigned char status
, const char *path
,
8120 FILE *patch_file
, int n
, int nchanges
)
8122 const struct got_error
*err
= NULL
;
8124 size_t linesize
= 0;
8127 struct choose_patch_arg
*a
= arg
;
8129 *choice
= GOT_PATCH_CHOICE_NONE
;
8131 if (a
->patch_script_file
) {
8133 err
= show_change(status
, path
, patch_file
, n
, nchanges
,
8137 linelen
= getline(&line
, &linesize
, a
->patch_script_file
);
8138 if (linelen
== -1) {
8139 if (ferror(a
->patch_script_file
))
8140 return got_error_from_errno("getline");
8143 nl
= strchr(line
, '\n');
8146 if (strcmp(line
, "y") == 0) {
8147 *choice
= GOT_PATCH_CHOICE_YES
;
8149 } else if (strcmp(line
, "n") == 0) {
8150 *choice
= GOT_PATCH_CHOICE_NO
;
8152 } else if (strcmp(line
, "q") == 0 &&
8153 status
== GOT_STATUS_MODIFY
) {
8154 *choice
= GOT_PATCH_CHOICE_QUIT
;
8157 printf("invalid response '%s'\n", line
);
8162 while (resp
!= 'y' && resp
!= 'n' && resp
!= 'q') {
8163 err
= show_change(status
, path
, patch_file
, n
, nchanges
,
8170 if (status
== GOT_STATUS_MODIFY
) {
8171 if (resp
!= 'y' && resp
!= 'n' && resp
!= 'q') {
8172 printf("invalid response '%c'\n", resp
);
8175 } else if (resp
!= 'y' && resp
!= 'n') {
8176 printf("invalid response '%c'\n", resp
);
8182 *choice
= GOT_PATCH_CHOICE_YES
;
8183 else if (resp
== 'n')
8184 *choice
= GOT_PATCH_CHOICE_NO
;
8185 else if (resp
== 'q' && status
== GOT_STATUS_MODIFY
)
8186 *choice
= GOT_PATCH_CHOICE_QUIT
;
8191 static const struct got_error
*
8192 cmd_revert(int argc
, char *argv
[])
8194 const struct got_error
*error
= NULL
;
8195 struct got_worktree
*worktree
= NULL
;
8196 struct got_repository
*repo
= NULL
;
8197 char *cwd
= NULL
, *path
= NULL
;
8198 struct got_pathlist_head paths
;
8199 struct got_pathlist_entry
*pe
;
8200 int ch
, can_recurse
= 0, pflag
= 0;
8201 FILE *patch_script_file
= NULL
;
8202 const char *patch_script_path
= NULL
;
8203 struct choose_patch_arg cpa
;
8204 int *pack_fds
= NULL
;
8208 while ((ch
= getopt(argc
, argv
, "pF:R")) != -1) {
8214 patch_script_path
= optarg
;
8229 if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd "
8230 "unveil", NULL
) == -1)
8235 if (patch_script_path
&& !pflag
)
8236 errx(1, "-F option can only be used together with -p option");
8238 cwd
= getcwd(NULL
, 0);
8240 error
= got_error_from_errno("getcwd");
8244 error
= got_repo_pack_fds_open(&pack_fds
);
8248 error
= got_worktree_open(&worktree
, cwd
);
8250 if (error
->code
== GOT_ERR_NOT_WORKTREE
)
8251 error
= wrap_not_worktree_error(error
, "revert", cwd
);
8255 error
= got_repo_open(&repo
, got_worktree_get_repo_path(worktree
),
8260 if (patch_script_path
) {
8261 patch_script_file
= fopen(patch_script_path
, "re");
8262 if (patch_script_file
== NULL
) {
8263 error
= got_error_from_errno2("fopen",
8268 error
= apply_unveil(got_repo_get_path(repo
), 1,
8269 got_worktree_get_root_path(worktree
));
8273 error
= get_worktree_paths_from_argv(&paths
, argc
, argv
, worktree
);
8280 TAILQ_FOREACH(pe
, &paths
, entry
) {
8281 if (asprintf(&ondisk_path
, "%s/%s",
8282 got_worktree_get_root_path(worktree
),
8284 error
= got_error_from_errno("asprintf");
8287 if (lstat(ondisk_path
, &sb
) == -1) {
8288 if (errno
== ENOENT
) {
8292 error
= got_error_from_errno2("lstat",
8298 if (S_ISDIR(sb
.st_mode
)) {
8299 error
= got_error_msg(GOT_ERR_BAD_PATH
,
8300 "reverting directories requires -R option");
8306 cpa
.patch_script_file
= patch_script_file
;
8307 cpa
.action
= "revert";
8308 error
= got_worktree_revert(worktree
, &paths
, revert_progress
, NULL
,
8309 pflag
? choose_patch
: NULL
, &cpa
, repo
);
8311 if (patch_script_file
&& fclose(patch_script_file
) == EOF
&&
8313 error
= got_error_from_errno2("fclose", patch_script_path
);
8315 const struct got_error
*close_err
= got_repo_close(repo
);
8320 got_worktree_close(worktree
);
8322 const struct got_error
*pack_err
=
8323 got_repo_pack_fds_close(pack_fds
);
8335 fprintf(stderr
, "usage: %s commit [-F path] [-m msg] [-N] [-S] "
8336 "[path ...]\n", getprogname());
8340 struct collect_commit_logmsg_arg
{
8341 const char *cmdline_log
;
8342 const char *prepared_log
;
8343 int non_interactive
;
8345 const char *worktree_path
;
8346 const char *branch_name
;
8347 const char *repo_path
;
8352 static const struct got_error
*
8353 read_prepared_logmsg(char **logmsg
, const char *path
)
8355 const struct got_error
*err
= NULL
;
8361 memset(&sb
, 0, sizeof(sb
));
8363 f
= fopen(path
, "re");
8365 return got_error_from_errno2("fopen", path
);
8367 if (fstat(fileno(f
), &sb
) == -1) {
8368 err
= got_error_from_errno2("fstat", path
);
8371 if (sb
.st_size
== 0) {
8372 err
= got_error(GOT_ERR_COMMIT_MSG_EMPTY
);
8376 *logmsg
= malloc(sb
.st_size
+ 1);
8377 if (*logmsg
== NULL
) {
8378 err
= got_error_from_errno("malloc");
8382 r
= fread(*logmsg
, 1, sb
.st_size
, f
);
8383 if (r
!= sb
.st_size
) {
8385 err
= got_error_from_errno2("fread", path
);
8387 err
= got_error(GOT_ERR_IO
);
8390 (*logmsg
)[sb
.st_size
] = '\0';
8392 if (fclose(f
) == EOF
&& err
== NULL
)
8393 err
= got_error_from_errno2("fclose", path
);
8402 static const struct got_error
*
8403 collect_commit_logmsg(struct got_pathlist_head
*commitable_paths
, char **logmsg
,
8406 char *initial_content
= NULL
;
8407 struct got_pathlist_entry
*pe
;
8408 const struct got_error
*err
= NULL
;
8409 char *template = NULL
;
8410 struct collect_commit_logmsg_arg
*a
= arg
;
8411 int initial_content_len
;
8415 /* if a message was specified on the command line, just use it */
8416 if (a
->cmdline_log
!= NULL
&& strlen(a
->cmdline_log
) != 0) {
8417 len
= strlen(a
->cmdline_log
) + 1;
8418 *logmsg
= malloc(len
+ 1);
8419 if (*logmsg
== NULL
)
8420 return got_error_from_errno("malloc");
8421 strlcpy(*logmsg
, a
->cmdline_log
, len
);
8423 } else if (a
->prepared_log
!= NULL
&& a
->non_interactive
)
8424 return read_prepared_logmsg(logmsg
, a
->prepared_log
);
8426 if (asprintf(&template, "%s/logmsg", a
->worktree_path
) == -1)
8427 return got_error_from_errno("asprintf");
8429 err
= got_opentemp_named_fd(&a
->logmsg_path
, &fd
, template);
8433 if (a
->prepared_log
) {
8435 err
= read_prepared_logmsg(&msg
, a
->prepared_log
);
8438 if (write(fd
, msg
, strlen(msg
)) == -1) {
8439 err
= got_error_from_errno2("write", a
->logmsg_path
);
8446 initial_content_len
= asprintf(&initial_content
,
8447 "\n# changes to be committed on branch %s:\n",
8449 if (initial_content_len
== -1) {
8450 err
= got_error_from_errno("asprintf");
8454 if (write(fd
, initial_content
, initial_content_len
) == -1) {
8455 err
= got_error_from_errno2("write", a
->logmsg_path
);
8459 TAILQ_FOREACH(pe
, commitable_paths
, entry
) {
8460 struct got_commitable
*ct
= pe
->data
;
8461 dprintf(fd
, "# %c %s\n",
8462 got_commitable_get_status(ct
),
8463 got_commitable_get_path(ct
));
8466 err
= edit_logmsg(logmsg
, a
->editor
, a
->logmsg_path
, initial_content
,
8467 initial_content_len
, a
->prepared_log
? 0 : 1);
8469 free(initial_content
);
8472 if (fd
!= -1 && close(fd
) == -1 && err
== NULL
)
8473 err
= got_error_from_errno2("close", a
->logmsg_path
);
8475 /* Editor is done; we can now apply unveil(2) */
8477 err
= apply_unveil(a
->repo_path
, 0, a
->worktree_path
);
8485 static const struct got_error
*
8486 cmd_commit(int argc
, char *argv
[])
8488 const struct got_error
*error
= NULL
;
8489 struct got_worktree
*worktree
= NULL
;
8490 struct got_repository
*repo
= NULL
;
8491 char *cwd
= NULL
, *id_str
= NULL
;
8492 struct got_object_id
*id
= NULL
;
8493 const char *logmsg
= NULL
;
8494 char *prepared_logmsg
= NULL
;
8495 struct collect_commit_logmsg_arg cl_arg
;
8496 char *gitconfig_path
= NULL
, *editor
= NULL
, *author
= NULL
;
8497 int ch
, rebase_in_progress
, histedit_in_progress
, preserve_logmsg
= 0;
8498 int allow_bad_symlinks
= 0, non_interactive
= 0, merge_in_progress
= 0;
8499 struct got_pathlist_head paths
;
8500 int *pack_fds
= NULL
;
8503 cl_arg
.logmsg_path
= NULL
;
8505 while ((ch
= getopt(argc
, argv
, "F:m:NS")) != -1) {
8509 option_conflict('F', 'm');
8510 prepared_logmsg
= realpath(optarg
, NULL
);
8511 if (prepared_logmsg
== NULL
)
8512 return got_error_from_errno2("realpath",
8516 if (prepared_logmsg
)
8517 option_conflict('m', 'F');
8521 non_interactive
= 1;
8524 allow_bad_symlinks
= 1;
8536 if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd "
8537 "unveil", NULL
) == -1)
8540 cwd
= getcwd(NULL
, 0);
8542 error
= got_error_from_errno("getcwd");
8546 error
= got_repo_pack_fds_open(&pack_fds
);
8550 error
= got_worktree_open(&worktree
, cwd
);
8552 if (error
->code
== GOT_ERR_NOT_WORKTREE
)
8553 error
= wrap_not_worktree_error(error
, "commit", cwd
);
8557 error
= got_worktree_rebase_in_progress(&rebase_in_progress
, worktree
);
8560 if (rebase_in_progress
) {
8561 error
= got_error(GOT_ERR_REBASING
);
8565 error
= got_worktree_histedit_in_progress(&histedit_in_progress
,
8570 error
= get_gitconfig_path(&gitconfig_path
);
8573 error
= got_repo_open(&repo
, got_worktree_get_repo_path(worktree
),
8574 gitconfig_path
, pack_fds
);
8578 error
= got_worktree_merge_in_progress(&merge_in_progress
, worktree
, repo
);
8581 if (merge_in_progress
) {
8582 error
= got_error(GOT_ERR_MERGE_BUSY
);
8586 error
= get_author(&author
, repo
, worktree
);
8591 * unveil(2) traverses exec(2); if an editor is used we have
8592 * to apply unveil after the log message has been written.
8594 if (logmsg
== NULL
|| strlen(logmsg
) == 0)
8595 error
= get_editor(&editor
);
8597 error
= apply_unveil(got_repo_get_path(repo
), 0,
8598 got_worktree_get_root_path(worktree
));
8602 error
= get_worktree_paths_from_argv(&paths
, argc
, argv
, worktree
);
8606 cl_arg
.editor
= editor
;
8607 cl_arg
.cmdline_log
= logmsg
;
8608 cl_arg
.prepared_log
= prepared_logmsg
;
8609 cl_arg
.non_interactive
= non_interactive
;
8610 cl_arg
.worktree_path
= got_worktree_get_root_path(worktree
);
8611 cl_arg
.branch_name
= got_worktree_get_head_ref_name(worktree
);
8612 if (!histedit_in_progress
) {
8613 if (strncmp(cl_arg
.branch_name
, "refs/heads/", 11) != 0) {
8614 error
= got_error(GOT_ERR_COMMIT_BRANCH
);
8617 cl_arg
.branch_name
+= 11;
8619 cl_arg
.repo_path
= got_repo_get_path(repo
);
8620 error
= got_worktree_commit(&id
, worktree
, &paths
, author
, NULL
,
8621 allow_bad_symlinks
, collect_commit_logmsg
, &cl_arg
,
8622 print_status
, NULL
, repo
);
8624 if (error
->code
!= GOT_ERR_COMMIT_MSG_EMPTY
&&
8625 cl_arg
.logmsg_path
!= NULL
)
8626 preserve_logmsg
= 1;
8630 error
= got_object_id_str(&id_str
, id
);
8633 printf("Created commit %s\n", id_str
);
8635 if (preserve_logmsg
) {
8636 fprintf(stderr
, "%s: log message preserved in %s\n",
8637 getprogname(), cl_arg
.logmsg_path
);
8638 } else if (cl_arg
.logmsg_path
&& unlink(cl_arg
.logmsg_path
) == -1 &&
8640 error
= got_error_from_errno2("unlink", cl_arg
.logmsg_path
);
8641 free(cl_arg
.logmsg_path
);
8643 const struct got_error
*close_err
= got_repo_close(repo
);
8648 got_worktree_close(worktree
);
8650 const struct got_error
*pack_err
=
8651 got_repo_pack_fds_close(pack_fds
);
8657 free(gitconfig_path
);
8660 free(prepared_logmsg
);
8667 fprintf(stderr
, "usage: %s send [-a] [-b branch] [-d branch] [-f] "
8668 "[-r repository-path] [-t tag] [-T] [-q] [-v] "
8669 "[remote-repository]\n", getprogname());
8674 print_load_info(int print_colored
, int print_found
, int print_trees
,
8675 int ncolored
, int nfound
, int ntrees
)
8677 if (print_colored
) {
8678 printf("%d commit%s colored", ncolored
,
8679 ncolored
== 1 ? "" : "s");
8682 printf("%s%d object%s found",
8683 ncolored
> 0 ? "; " : "",
8684 nfound
, nfound
== 1 ? "" : "s");
8687 printf("; %d tree%s scanned", ntrees
,
8688 ntrees
== 1 ? "" : "s");
8692 struct got_send_progress_arg
{
8693 char last_scaled_packsize
[FMT_SCALED_STRSIZE
];
8700 int last_nobj_total
;
8704 int printed_something
;
8706 struct got_pathlist_head
*delete_branches
;
8709 static const struct got_error
*
8710 send_progress(void *arg
, int ncolored
, int nfound
, int ntrees
,
8711 off_t packfile_size
, int ncommits
, int nobj_total
, int nobj_deltify
,
8712 int nobj_written
, off_t bytes_sent
, const char *refname
, int success
)
8714 struct got_send_progress_arg
*a
= arg
;
8715 char scaled_packsize
[FMT_SCALED_STRSIZE
];
8716 char scaled_sent
[FMT_SCALED_STRSIZE
];
8717 int p_deltify
= 0, p_written
= 0, p_sent
= 0;
8718 int print_colored
= 0, print_found
= 0, print_trees
= 0;
8719 int print_searching
= 0, print_total
= 0;
8720 int print_deltify
= 0, print_written
= 0, print_sent
= 0;
8722 if (a
->verbosity
< 0)
8726 const char *status
= success
? "accepted" : "rejected";
8729 struct got_pathlist_entry
*pe
;
8730 TAILQ_FOREACH(pe
, a
->delete_branches
, entry
) {
8731 const char *branchname
= pe
->path
;
8732 if (got_path_cmp(branchname
, refname
,
8733 strlen(branchname
), strlen(refname
)) == 0) {
8735 a
->sent_something
= 1;
8741 if (a
->printed_something
)
8743 printf("Server has %s %s", status
, refname
);
8744 a
->printed_something
= 1;
8748 if (a
->last_ncolored
!= ncolored
) {
8750 a
->last_ncolored
= ncolored
;
8753 if (a
->last_nfound
!= nfound
) {
8756 a
->last_nfound
= nfound
;
8759 if (a
->last_ntrees
!= ntrees
) {
8763 a
->last_ntrees
= ntrees
;
8766 if ((print_colored
|| print_found
|| print_trees
) &&
8769 print_load_info(print_colored
, print_found
, print_trees
,
8770 ncolored
, nfound
, ntrees
);
8771 a
->printed_something
= 1;
8774 } else if (!a
->loading_done
) {
8776 print_load_info(1, 1, 1, ncolored
, nfound
, ntrees
);
8778 a
->loading_done
= 1;
8781 if (fmt_scaled(packfile_size
, scaled_packsize
) == -1)
8782 return got_error_from_errno("fmt_scaled");
8783 if (fmt_scaled(bytes_sent
, scaled_sent
) == -1)
8784 return got_error_from_errno("fmt_scaled");
8786 if (a
->last_ncommits
!= ncommits
) {
8787 print_searching
= 1;
8788 a
->last_ncommits
= ncommits
;
8791 if (a
->last_nobj_total
!= nobj_total
) {
8792 print_searching
= 1;
8794 a
->last_nobj_total
= nobj_total
;
8797 if (packfile_size
> 0 && (a
->last_scaled_packsize
[0] == '\0' ||
8798 strcmp(scaled_packsize
, a
->last_scaled_packsize
)) != 0) {
8799 if (strlcpy(a
->last_scaled_packsize
, scaled_packsize
,
8800 FMT_SCALED_STRSIZE
) >= FMT_SCALED_STRSIZE
)
8801 return got_error(GOT_ERR_NO_SPACE
);
8804 if (nobj_deltify
> 0 || nobj_written
> 0) {
8805 if (nobj_deltify
> 0) {
8806 p_deltify
= (nobj_deltify
* 100) / nobj_total
;
8807 if (p_deltify
!= a
->last_p_deltify
) {
8808 a
->last_p_deltify
= p_deltify
;
8809 print_searching
= 1;
8814 if (nobj_written
> 0) {
8815 p_written
= (nobj_written
* 100) / nobj_total
;
8816 if (p_written
!= a
->last_p_written
) {
8817 a
->last_p_written
= p_written
;
8818 print_searching
= 1;
8826 if (bytes_sent
> 0) {
8827 p_sent
= (bytes_sent
* 100) / packfile_size
;
8828 if (p_sent
!= a
->last_p_sent
) {
8829 a
->last_p_sent
= p_sent
;
8830 print_searching
= 1;
8836 a
->sent_something
= 1;
8839 if (print_searching
|| print_total
|| print_deltify
|| print_written
||
8842 if (print_searching
)
8843 printf("packing %d reference%s", ncommits
,
8844 ncommits
== 1 ? "" : "s");
8846 printf("; %d object%s", nobj_total
,
8847 nobj_total
== 1 ? "" : "s");
8849 printf("; deltify: %d%%", p_deltify
);
8851 printf("; uploading pack: %*s %d%%", FMT_SCALED_STRSIZE
- 2,
8852 scaled_packsize
, p_sent
);
8853 else if (print_written
)
8854 printf("; writing pack: %*s %d%%", FMT_SCALED_STRSIZE
- 2,
8855 scaled_packsize
, p_written
);
8856 if (print_searching
|| print_total
|| print_deltify
||
8857 print_written
|| print_sent
) {
8858 a
->printed_something
= 1;
8864 static const struct got_error
*
8865 cmd_send(int argc
, char *argv
[])
8867 const struct got_error
*error
= NULL
;
8868 char *cwd
= NULL
, *repo_path
= NULL
;
8869 const char *remote_name
;
8870 char *proto
= NULL
, *host
= NULL
, *port
= NULL
;
8871 char *repo_name
= NULL
, *server_path
= NULL
;
8872 const struct got_remote_repo
*remotes
, *remote
= NULL
;
8873 int nremotes
, nbranches
= 0, ntags
= 0, ndelete_branches
= 0;
8874 struct got_repository
*repo
= NULL
;
8875 struct got_worktree
*worktree
= NULL
;
8876 const struct got_gotconfig
*repo_conf
= NULL
, *worktree_conf
= NULL
;
8877 struct got_pathlist_head branches
;
8878 struct got_pathlist_head tags
;
8879 struct got_reflist_head all_branches
;
8880 struct got_reflist_head all_tags
;
8881 struct got_pathlist_head delete_args
;
8882 struct got_pathlist_head delete_branches
;
8883 struct got_reflist_entry
*re
;
8884 struct got_pathlist_entry
*pe
;
8885 int i
, ch
, sendfd
= -1, sendstatus
;
8887 struct got_send_progress_arg spa
;
8888 int verbosity
= 0, overwrite_refs
= 0;
8889 int send_all_branches
= 0, send_all_tags
= 0;
8890 struct got_reference
*ref
= NULL
;
8891 int *pack_fds
= NULL
;
8893 TAILQ_INIT(&branches
);
8895 TAILQ_INIT(&all_branches
);
8896 TAILQ_INIT(&all_tags
);
8897 TAILQ_INIT(&delete_args
);
8898 TAILQ_INIT(&delete_branches
);
8900 while ((ch
= getopt(argc
, argv
, "ab:d:fr:t:Tvq")) != -1) {
8903 send_all_branches
= 1;
8906 error
= got_pathlist_append(&branches
, optarg
, NULL
);
8912 error
= got_pathlist_append(&delete_args
, optarg
, NULL
);
8920 repo_path
= realpath(optarg
, NULL
);
8921 if (repo_path
== NULL
)
8922 return got_error_from_errno2("realpath",
8924 got_path_strip_trailing_slashes(repo_path
);
8927 error
= got_pathlist_append(&tags
, optarg
, NULL
);
8938 else if (verbosity
< 3)
8952 if (send_all_branches
&& !TAILQ_EMPTY(&branches
))
8953 option_conflict('a', 'b');
8954 if (send_all_tags
&& !TAILQ_EMPTY(&tags
))
8955 option_conflict('T', 't');
8959 remote_name
= GOT_SEND_DEFAULT_REMOTE_NAME
;
8961 remote_name
= argv
[0];
8965 cwd
= getcwd(NULL
, 0);
8967 error
= got_error_from_errno("getcwd");
8971 error
= got_repo_pack_fds_open(&pack_fds
);
8975 if (repo_path
== NULL
) {
8976 error
= got_worktree_open(&worktree
, cwd
);
8977 if (error
&& error
->code
!= GOT_ERR_NOT_WORKTREE
)
8983 strdup(got_worktree_get_repo_path(worktree
));
8984 if (repo_path
== NULL
)
8985 error
= got_error_from_errno("strdup");
8989 repo_path
= strdup(cwd
);
8990 if (repo_path
== NULL
) {
8991 error
= got_error_from_errno("strdup");
8997 error
= got_repo_open(&repo
, repo_path
, NULL
, pack_fds
);
9002 worktree_conf
= got_worktree_get_gotconfig(worktree
);
9003 if (worktree_conf
) {
9004 got_gotconfig_get_remotes(&nremotes
, &remotes
,
9006 for (i
= 0; i
< nremotes
; i
++) {
9007 if (strcmp(remotes
[i
].name
, remote_name
) == 0) {
9008 remote
= &remotes
[i
];
9014 if (remote
== NULL
) {
9015 repo_conf
= got_repo_get_gotconfig(repo
);
9017 got_gotconfig_get_remotes(&nremotes
, &remotes
,
9019 for (i
= 0; i
< nremotes
; i
++) {
9020 if (strcmp(remotes
[i
].name
, remote_name
) == 0) {
9021 remote
= &remotes
[i
];
9027 if (remote
== NULL
) {
9028 got_repo_get_gitconfig_remotes(&nremotes
, &remotes
, repo
);
9029 for (i
= 0; i
< nremotes
; i
++) {
9030 if (strcmp(remotes
[i
].name
, remote_name
) == 0) {
9031 remote
= &remotes
[i
];
9036 if (remote
== NULL
) {
9037 error
= got_error_path(remote_name
, GOT_ERR_NO_REMOTE
);
9041 error
= got_dial_parse_uri(&proto
, &host
, &port
, &server_path
,
9042 &repo_name
, remote
->send_url
);
9046 if (strcmp(proto
, "git") == 0) {
9048 if (pledge("stdio rpath wpath cpath fattr flock proc exec "
9049 "sendfd dns inet unveil", NULL
) == -1)
9052 } else if (strcmp(proto
, "git+ssh") == 0 ||
9053 strcmp(proto
, "ssh") == 0) {
9055 if (pledge("stdio rpath wpath cpath fattr flock proc exec "
9056 "sendfd unveil", NULL
) == -1)
9059 } else if (strcmp(proto
, "http") == 0 ||
9060 strcmp(proto
, "git+http") == 0) {
9061 error
= got_error_path(proto
, GOT_ERR_NOT_IMPL
);
9064 error
= got_error_path(proto
, GOT_ERR_BAD_PROTO
);
9068 error
= got_dial_apply_unveil(proto
);
9072 error
= apply_unveil(got_repo_get_path(repo
), 0, NULL
);
9076 if (send_all_branches
) {
9077 error
= got_ref_list(&all_branches
, repo
, "refs/heads",
9078 got_ref_cmp_by_name
, NULL
);
9081 TAILQ_FOREACH(re
, &all_branches
, entry
) {
9082 const char *branchname
= got_ref_get_name(re
->ref
);
9083 error
= got_pathlist_append(&branches
,
9089 } else if (nbranches
== 0) {
9090 for (i
= 0; i
< remote
->nsend_branches
; i
++) {
9091 got_pathlist_append(&branches
,
9092 remote
->send_branches
[i
], NULL
);
9096 if (send_all_tags
) {
9097 error
= got_ref_list(&all_tags
, repo
, "refs/tags",
9098 got_ref_cmp_by_name
, NULL
);
9101 TAILQ_FOREACH(re
, &all_tags
, entry
) {
9102 const char *tagname
= got_ref_get_name(re
->ref
);
9103 error
= got_pathlist_append(&tags
,
9112 * To prevent accidents only branches in refs/heads/ can be deleted
9113 * with 'got send -d'.
9114 * Deleting anything else requires local repository access or Git.
9116 TAILQ_FOREACH(pe
, &delete_args
, entry
) {
9117 const char *branchname
= pe
->path
;
9119 struct got_pathlist_entry
*new;
9120 if (strncmp(branchname
, "refs/heads/", 11) == 0) {
9121 s
= strdup(branchname
);
9123 error
= got_error_from_errno("strdup");
9127 if (asprintf(&s
, "refs/heads/%s", branchname
) == -1) {
9128 error
= got_error_from_errno("asprintf");
9132 error
= got_pathlist_insert(&new, &delete_branches
, s
, NULL
);
9133 if (error
|| new == NULL
/* duplicate */)
9140 if (nbranches
== 0 && ndelete_branches
== 0) {
9141 struct got_reference
*head_ref
;
9143 error
= got_ref_open(&head_ref
, repo
,
9144 got_worktree_get_head_ref_name(worktree
), 0);
9146 error
= got_ref_open(&head_ref
, repo
, GOT_REF_HEAD
, 0);
9149 if (got_ref_is_symbolic(head_ref
)) {
9150 error
= got_ref_resolve_symbolic(&ref
, repo
, head_ref
);
9151 got_ref_close(head_ref
);
9156 error
= got_pathlist_append(&branches
, got_ref_get_name(ref
),
9164 printf("Connecting to \"%s\" %s%s%s\n", remote
->name
, host
,
9165 port
? ":" : "", port
? port
: "");
9167 error
= got_send_connect(&sendpid
, &sendfd
, proto
, host
, port
,
9168 server_path
, verbosity
);
9172 memset(&spa
, 0, sizeof(spa
));
9173 spa
.last_scaled_packsize
[0] = '\0';
9174 spa
.last_p_deltify
= -1;
9175 spa
.last_p_written
= -1;
9176 spa
.verbosity
= verbosity
;
9177 spa
.delete_branches
= &delete_branches
;
9178 error
= got_send_pack(remote_name
, &branches
, &tags
, &delete_branches
,
9179 verbosity
, overwrite_refs
, sendfd
, repo
, send_progress
, &spa
,
9180 check_cancelled
, NULL
);
9181 if (spa
.printed_something
)
9185 if (!spa
.sent_something
&& verbosity
>= 0)
9186 printf("Already up-to-date\n");
9189 if (kill(sendpid
, SIGTERM
) == -1)
9190 error
= got_error_from_errno("kill");
9191 if (waitpid(sendpid
, &sendstatus
, 0) == -1 && error
== NULL
)
9192 error
= got_error_from_errno("waitpid");
9194 if (sendfd
!= -1 && close(sendfd
) == -1 && error
== NULL
)
9195 error
= got_error_from_errno("close");
9197 const struct got_error
*close_err
= got_repo_close(repo
);
9202 got_worktree_close(worktree
);
9204 const struct got_error
*pack_err
=
9205 got_repo_pack_fds_close(pack_fds
);
9211 got_pathlist_free(&branches
);
9212 got_pathlist_free(&tags
);
9213 got_ref_list_free(&all_branches
);
9214 got_ref_list_free(&all_tags
);
9215 got_pathlist_free(&delete_args
);
9216 TAILQ_FOREACH(pe
, &delete_branches
, entry
)
9217 free((char *)pe
->path
);
9218 got_pathlist_free(&delete_branches
);
9230 usage_cherrypick(void)
9232 fprintf(stderr
, "usage: %s cherrypick commit-id\n", getprogname());
9236 static const struct got_error
*
9237 cmd_cherrypick(int argc
, char *argv
[])
9239 const struct got_error
*error
= NULL
;
9240 struct got_worktree
*worktree
= NULL
;
9241 struct got_repository
*repo
= NULL
;
9242 char *cwd
= NULL
, *commit_id_str
= NULL
;
9243 struct got_object_id
*commit_id
= NULL
;
9244 struct got_commit_object
*commit
= NULL
;
9245 struct got_object_qid
*pid
;
9247 struct got_update_progress_arg upa
;
9248 int *pack_fds
= NULL
;
9250 while ((ch
= getopt(argc
, argv
, "")) != -1) {
9262 if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd "
9263 "unveil", NULL
) == -1)
9269 cwd
= getcwd(NULL
, 0);
9271 error
= got_error_from_errno("getcwd");
9275 error
= got_repo_pack_fds_open(&pack_fds
);
9279 error
= got_worktree_open(&worktree
, cwd
);
9281 if (error
->code
== GOT_ERR_NOT_WORKTREE
)
9282 error
= wrap_not_worktree_error(error
, "cherrypick",
9287 error
= got_repo_open(&repo
, got_worktree_get_repo_path(worktree
),
9292 error
= apply_unveil(got_repo_get_path(repo
), 0,
9293 got_worktree_get_root_path(worktree
));
9297 error
= got_repo_match_object_id(&commit_id
, NULL
, argv
[0],
9298 GOT_OBJ_TYPE_COMMIT
, NULL
, repo
);
9301 error
= got_object_id_str(&commit_id_str
, commit_id
);
9305 error
= got_object_open_as_commit(&commit
, repo
, commit_id
);
9308 pid
= STAILQ_FIRST(got_object_commit_get_parent_ids(commit
));
9309 memset(&upa
, 0, sizeof(upa
));
9310 error
= got_worktree_merge_files(worktree
, pid
? &pid
->id
: NULL
,
9311 commit_id
, repo
, update_progress
, &upa
, check_cancelled
,
9316 if (upa
.did_something
)
9317 printf("Merged commit %s\n", commit_id_str
);
9318 print_merge_progress_stats(&upa
);
9321 got_object_commit_close(commit
);
9322 free(commit_id_str
);
9324 got_worktree_close(worktree
);
9326 const struct got_error
*close_err
= got_repo_close(repo
);
9331 const struct got_error
*pack_err
=
9332 got_repo_pack_fds_close(pack_fds
);
9343 fprintf(stderr
, "usage: %s backout commit-id\n", getprogname());
9347 static const struct got_error
*
9348 cmd_backout(int argc
, char *argv
[])
9350 const struct got_error
*error
= NULL
;
9351 struct got_worktree
*worktree
= NULL
;
9352 struct got_repository
*repo
= NULL
;
9353 char *cwd
= NULL
, *commit_id_str
= NULL
;
9354 struct got_object_id
*commit_id
= NULL
;
9355 struct got_commit_object
*commit
= NULL
;
9356 struct got_object_qid
*pid
;
9358 struct got_update_progress_arg upa
;
9359 int *pack_fds
= NULL
;
9361 while ((ch
= getopt(argc
, argv
, "")) != -1) {
9373 if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd "
9374 "unveil", NULL
) == -1)
9380 cwd
= getcwd(NULL
, 0);
9382 error
= got_error_from_errno("getcwd");
9386 error
= got_repo_pack_fds_open(&pack_fds
);
9390 error
= got_worktree_open(&worktree
, cwd
);
9392 if (error
->code
== GOT_ERR_NOT_WORKTREE
)
9393 error
= wrap_not_worktree_error(error
, "backout", cwd
);
9397 error
= got_repo_open(&repo
, got_worktree_get_repo_path(worktree
),
9402 error
= apply_unveil(got_repo_get_path(repo
), 0,
9403 got_worktree_get_root_path(worktree
));
9407 error
= got_repo_match_object_id(&commit_id
, NULL
, argv
[0],
9408 GOT_OBJ_TYPE_COMMIT
, NULL
, repo
);
9411 error
= got_object_id_str(&commit_id_str
, commit_id
);
9415 error
= got_object_open_as_commit(&commit
, repo
, commit_id
);
9418 pid
= STAILQ_FIRST(got_object_commit_get_parent_ids(commit
));
9420 error
= got_error(GOT_ERR_ROOT_COMMIT
);
9424 memset(&upa
, 0, sizeof(upa
));
9425 error
= got_worktree_merge_files(worktree
, commit_id
, &pid
->id
,
9426 repo
, update_progress
, &upa
, check_cancelled
, NULL
);
9430 if (upa
.did_something
)
9431 printf("Backed out commit %s\n", commit_id_str
);
9432 print_merge_progress_stats(&upa
);
9435 got_object_commit_close(commit
);
9436 free(commit_id_str
);
9438 got_worktree_close(worktree
);
9440 const struct got_error
*close_err
= got_repo_close(repo
);
9445 const struct got_error
*pack_err
=
9446 got_repo_pack_fds_close(pack_fds
);
9456 fprintf(stderr
, "usage: %s rebase [-a] [-c] [-l] [-X] [branch]\n",
9462 trim_logmsg(char *logmsg
, int limit
)
9467 len
= strlen(logmsg
);
9471 nl
= strchr(logmsg
, '\n');
9476 static const struct got_error
*
9477 get_short_logmsg(char **logmsg
, int limit
, struct got_commit_object
*commit
)
9479 const struct got_error
*err
;
9480 char *logmsg0
= NULL
;
9483 err
= got_object_commit_get_logmsg(&logmsg0
, commit
);
9488 while (isspace((unsigned char)s
[0]))
9491 *logmsg
= strdup(s
);
9492 if (*logmsg
== NULL
) {
9493 err
= got_error_from_errno("strdup");
9497 trim_logmsg(*logmsg
, limit
);
9503 static const struct got_error
*
9504 show_rebase_merge_conflict(struct got_object_id
*id
,
9505 struct got_repository
*repo
)
9507 const struct got_error
*err
;
9508 struct got_commit_object
*commit
= NULL
;
9509 char *id_str
= NULL
, *logmsg
= NULL
;
9511 err
= got_object_open_as_commit(&commit
, repo
, id
);
9515 err
= got_object_id_str(&id_str
, id
);
9521 err
= get_short_logmsg(&logmsg
, 42, commit
);
9525 printf("%s -> merge conflict: %s\n", id_str
, logmsg
);
9528 got_object_commit_close(commit
);
9533 static const struct got_error
*
9534 show_rebase_progress(struct got_commit_object
*commit
,
9535 struct got_object_id
*old_id
, struct got_object_id
*new_id
)
9537 const struct got_error
*err
;
9538 char *old_id_str
= NULL
, *new_id_str
= NULL
, *logmsg
= NULL
;
9540 err
= got_object_id_str(&old_id_str
, old_id
);
9545 err
= got_object_id_str(&new_id_str
, new_id
);
9550 old_id_str
[12] = '\0';
9552 new_id_str
[12] = '\0';
9554 err
= get_short_logmsg(&logmsg
, 42, commit
);
9558 printf("%s -> %s: %s\n", old_id_str
,
9559 new_id_str
? new_id_str
: "no-op change", logmsg
);
9567 static const struct got_error
*
9568 rebase_complete(struct got_worktree
*worktree
, struct got_fileindex
*fileindex
,
9569 struct got_reference
*branch
, struct got_reference
*new_base_branch
,
9570 struct got_reference
*tmp_branch
, struct got_repository
*repo
,
9573 printf("Switching work tree to %s\n", got_ref_get_name(branch
));
9574 return got_worktree_rebase_complete(worktree
, fileindex
,
9575 new_base_branch
, tmp_branch
, branch
, repo
, create_backup
);
9578 static const struct got_error
*
9579 rebase_commit(struct got_pathlist_head
*merged_paths
,
9580 struct got_worktree
*worktree
, struct got_fileindex
*fileindex
,
9581 struct got_reference
*tmp_branch
,
9582 struct got_object_id
*commit_id
, struct got_repository
*repo
)
9584 const struct got_error
*error
;
9585 struct got_commit_object
*commit
;
9586 struct got_object_id
*new_commit_id
;
9588 error
= got_object_open_as_commit(&commit
, repo
, commit_id
);
9592 error
= got_worktree_rebase_commit(&new_commit_id
, merged_paths
,
9593 worktree
, fileindex
, tmp_branch
, commit
, commit_id
, repo
);
9595 if (error
->code
!= GOT_ERR_COMMIT_NO_CHANGES
)
9597 error
= show_rebase_progress(commit
, commit_id
, NULL
);
9599 error
= show_rebase_progress(commit
, commit_id
, new_commit_id
);
9600 free(new_commit_id
);
9603 got_object_commit_close(commit
);
9607 struct check_path_prefix_arg
{
9608 const char *path_prefix
;
9613 static const struct got_error
*
9614 check_path_prefix_in_diff(void *arg
, struct got_blob_object
*blob1
,
9615 struct got_blob_object
*blob2
, FILE *f1
, FILE *f2
,
9616 struct got_object_id
*id1
, struct got_object_id
*id2
,
9617 const char *path1
, const char *path2
,
9618 mode_t mode1
, mode_t mode2
, struct got_repository
*repo
)
9620 struct check_path_prefix_arg
*a
= arg
;
9622 if ((path1
&& !got_path_is_child(path1
, a
->path_prefix
, a
->len
)) ||
9623 (path2
&& !got_path_is_child(path2
, a
->path_prefix
, a
->len
)))
9624 return got_error(a
->errcode
);
9629 static const struct got_error
*
9630 check_path_prefix(struct got_object_id
*parent_id
,
9631 struct got_object_id
*commit_id
, const char *path_prefix
,
9632 int errcode
, struct got_repository
*repo
)
9634 const struct got_error
*err
;
9635 struct got_tree_object
*tree1
= NULL
, *tree2
= NULL
;
9636 struct got_commit_object
*commit
= NULL
, *parent_commit
= NULL
;
9637 struct check_path_prefix_arg cpp_arg
;
9639 if (got_path_is_root_dir(path_prefix
))
9642 err
= got_object_open_as_commit(&commit
, repo
, commit_id
);
9646 err
= got_object_open_as_commit(&parent_commit
, repo
, parent_id
);
9650 err
= got_object_open_as_tree(&tree1
, repo
,
9651 got_object_commit_get_tree_id(parent_commit
));
9655 err
= got_object_open_as_tree(&tree2
, repo
,
9656 got_object_commit_get_tree_id(commit
));
9660 cpp_arg
.path_prefix
= path_prefix
;
9661 while (cpp_arg
.path_prefix
[0] == '/')
9662 cpp_arg
.path_prefix
++;
9663 cpp_arg
.len
= strlen(cpp_arg
.path_prefix
);
9664 cpp_arg
.errcode
= errcode
;
9665 err
= got_diff_tree(tree1
, tree2
, NULL
, NULL
, -1, -1, "", "", repo
,
9666 check_path_prefix_in_diff
, &cpp_arg
, 0);
9669 got_object_tree_close(tree1
);
9671 got_object_tree_close(tree2
);
9673 got_object_commit_close(commit
);
9675 got_object_commit_close(parent_commit
);
9679 static const struct got_error
*
9680 collect_commits(struct got_object_id_queue
*commits
,
9681 struct got_object_id
*initial_commit_id
,
9682 struct got_object_id
*iter_start_id
, struct got_object_id
*iter_stop_id
,
9683 const char *path_prefix
, int path_prefix_errcode
,
9684 struct got_repository
*repo
)
9686 const struct got_error
*err
= NULL
;
9687 struct got_commit_graph
*graph
= NULL
;
9688 struct got_object_id
*parent_id
= NULL
;
9689 struct got_object_qid
*qid
;
9690 struct got_object_id
*commit_id
= initial_commit_id
;
9692 err
= got_commit_graph_open(&graph
, "/", 1);
9696 err
= got_commit_graph_iter_start(graph
, iter_start_id
, repo
,
9697 check_cancelled
, NULL
);
9700 while (got_object_id_cmp(commit_id
, iter_stop_id
) != 0) {
9701 err
= got_commit_graph_iter_next(&parent_id
, graph
, repo
,
9702 check_cancelled
, NULL
);
9704 if (err
->code
== GOT_ERR_ITER_COMPLETED
) {
9705 err
= got_error_msg(GOT_ERR_ANCESTRY
,
9706 "ran out of commits to rebase before "
9707 "youngest common ancestor commit has "
9712 err
= check_path_prefix(parent_id
, commit_id
,
9713 path_prefix
, path_prefix_errcode
, repo
);
9717 err
= got_object_qid_alloc(&qid
, commit_id
);
9720 STAILQ_INSERT_HEAD(commits
, qid
, entry
);
9721 commit_id
= parent_id
;
9725 got_commit_graph_close(graph
);
9729 static const struct got_error
*
9730 get_commit_brief_str(char **brief_str
, struct got_commit_object
*commit
)
9732 const struct got_error
*err
= NULL
;
9733 time_t committer_time
;
9735 char datebuf
[11]; /* YYYY-MM-DD + NUL */
9736 char *author0
= NULL
, *author
, *smallerthan
;
9737 char *logmsg0
= NULL
, *logmsg
, *newline
;
9739 committer_time
= got_object_commit_get_committer_time(commit
);
9740 if (gmtime_r(&committer_time
, &tm
) == NULL
)
9741 return got_error_from_errno("gmtime_r");
9742 if (strftime(datebuf
, sizeof(datebuf
), "%G-%m-%d", &tm
) == 0)
9743 return got_error(GOT_ERR_NO_SPACE
);
9745 author0
= strdup(got_object_commit_get_author(commit
));
9746 if (author0
== NULL
)
9747 return got_error_from_errno("strdup");
9749 smallerthan
= strchr(author
, '<');
9750 if (smallerthan
&& smallerthan
[1] != '\0')
9751 author
= smallerthan
+ 1;
9752 author
[strcspn(author
, "@>")] = '\0';
9754 err
= got_object_commit_get_logmsg(&logmsg0
, commit
);
9758 while (*logmsg
== '\n')
9760 newline
= strchr(logmsg
, '\n');
9764 if (asprintf(brief_str
, "%s %s %s",
9765 datebuf
, author
, logmsg
) == -1)
9766 err
= got_error_from_errno("asprintf");
9773 static const struct got_error
*
9774 delete_backup_ref(struct got_reference
*ref
, struct got_object_id
*id
,
9775 struct got_repository
*repo
)
9777 const struct got_error
*err
;
9780 err
= got_object_id_str(&id_str
, id
);
9784 err
= got_ref_delete(ref
, repo
);
9788 printf("Deleted %s: %s\n", got_ref_get_name(ref
), id_str
);
9794 static const struct got_error
*
9795 print_backup_ref(const char *branch_name
, const char *new_id_str
,
9796 struct got_object_id
*old_commit_id
, struct got_commit_object
*old_commit
,
9797 struct got_reflist_object_id_map
*refs_idmap
,
9798 struct got_repository
*repo
)
9800 const struct got_error
*err
= NULL
;
9801 struct got_reflist_head
*refs
;
9802 char *refs_str
= NULL
;
9803 struct got_object_id
*new_commit_id
= NULL
;
9804 struct got_commit_object
*new_commit
= NULL
;
9805 char *new_commit_brief_str
= NULL
;
9806 struct got_object_id
*yca_id
= NULL
;
9807 struct got_commit_object
*yca_commit
= NULL
;
9808 char *yca_id_str
= NULL
, *yca_brief_str
= NULL
;
9809 char *custom_refs_str
;
9811 if (asprintf(&custom_refs_str
, "formerly %s", branch_name
) == -1)
9812 return got_error_from_errno("asprintf");
9814 err
= print_commit(old_commit
, old_commit_id
, repo
, NULL
, NULL
,
9815 0, 0, refs_idmap
, custom_refs_str
);
9819 err
= got_object_resolve_id_str(&new_commit_id
, repo
, new_id_str
);
9823 refs
= got_reflist_object_id_map_lookup(refs_idmap
, new_commit_id
);
9825 err
= build_refs_str(&refs_str
, refs
, new_commit_id
, repo
, 0);
9830 err
= got_object_open_as_commit(&new_commit
, repo
, new_commit_id
);
9834 err
= get_commit_brief_str(&new_commit_brief_str
, new_commit
);
9838 err
= got_commit_graph_find_youngest_common_ancestor(&yca_id
,
9839 old_commit_id
, new_commit_id
, 1, repo
, check_cancelled
, NULL
);
9843 printf("has become commit %s%s%s%s\n %s\n", new_id_str
,
9844 refs_str
? " (" : "", refs_str
? refs_str
: "",
9845 refs_str
? ")" : "", new_commit_brief_str
);
9846 if (yca_id
&& got_object_id_cmp(yca_id
, new_commit_id
) != 0 &&
9847 got_object_id_cmp(yca_id
, old_commit_id
) != 0) {
9851 err
= got_object_open_as_commit(&yca_commit
, repo
, yca_id
);
9855 err
= get_commit_brief_str(&yca_brief_str
, yca_commit
);
9859 err
= got_object_id_str(&yca_id_str
, yca_id
);
9863 refs
= got_reflist_object_id_map_lookup(refs_idmap
, yca_id
);
9865 err
= build_refs_str(&refs_str
, refs
, yca_id
, repo
, 0);
9869 printf("history forked at %s%s%s%s\n %s\n",
9871 refs_str
? " (" : "", refs_str
? refs_str
: "",
9872 refs_str
? ")" : "", yca_brief_str
);
9875 free(custom_refs_str
);
9876 free(new_commit_id
);
9880 free(yca_brief_str
);
9882 got_object_commit_close(new_commit
);
9884 got_object_commit_close(yca_commit
);
9889 static const struct got_error
*
9890 process_backup_refs(const char *backup_ref_prefix
,
9891 const char *wanted_branch_name
,
9892 int delete, struct got_repository
*repo
)
9894 const struct got_error
*err
;
9895 struct got_reflist_head refs
, backup_refs
;
9896 struct got_reflist_entry
*re
;
9897 const size_t backup_ref_prefix_len
= strlen(backup_ref_prefix
);
9898 struct got_object_id
*old_commit_id
= NULL
;
9899 char *branch_name
= NULL
;
9900 struct got_commit_object
*old_commit
= NULL
;
9901 struct got_reflist_object_id_map
*refs_idmap
= NULL
;
9902 int wanted_branch_found
= 0;
9905 TAILQ_INIT(&backup_refs
);
9907 err
= got_ref_list(&refs
, repo
, NULL
, got_ref_cmp_by_name
, NULL
);
9911 err
= got_reflist_object_id_map_create(&refs_idmap
, &refs
, repo
);
9915 if (wanted_branch_name
) {
9916 if (strncmp(wanted_branch_name
, "refs/heads/", 11) == 0)
9917 wanted_branch_name
+= 11;
9920 err
= got_ref_list(&backup_refs
, repo
, backup_ref_prefix
,
9921 got_ref_cmp_by_commit_timestamp_descending
, repo
);
9925 TAILQ_FOREACH(re
, &backup_refs
, entry
) {
9926 const char *refname
= got_ref_get_name(re
->ref
);
9929 err
= check_cancelled(NULL
);
9933 err
= got_ref_resolve(&old_commit_id
, repo
, re
->ref
);
9937 err
= got_object_open_as_commit(&old_commit
, repo
,
9942 if (strncmp(backup_ref_prefix
, refname
,
9943 backup_ref_prefix_len
) == 0)
9944 refname
+= backup_ref_prefix_len
;
9946 while (refname
[0] == '/')
9949 branch_name
= strdup(refname
);
9950 if (branch_name
== NULL
) {
9951 err
= got_error_from_errno("strdup");
9954 slash
= strrchr(branch_name
, '/');
9957 refname
+= strlen(branch_name
) + 1;
9960 if (wanted_branch_name
== NULL
||
9961 strcmp(wanted_branch_name
, branch_name
) == 0) {
9962 wanted_branch_found
= 1;
9964 err
= delete_backup_ref(re
->ref
,
9965 old_commit_id
, repo
);
9967 err
= print_backup_ref(branch_name
, refname
,
9968 old_commit_id
, old_commit
, refs_idmap
,
9975 free(old_commit_id
);
9976 old_commit_id
= NULL
;
9979 got_object_commit_close(old_commit
);
9983 if (wanted_branch_name
&& !wanted_branch_found
) {
9984 err
= got_error_fmt(GOT_ERR_NOT_REF
,
9985 "%s/%s/", backup_ref_prefix
, wanted_branch_name
);
9989 got_reflist_object_id_map_free(refs_idmap
);
9990 got_ref_list_free(&refs
);
9991 got_ref_list_free(&backup_refs
);
9992 free(old_commit_id
);
9995 got_object_commit_close(old_commit
);
9999 static const struct got_error
*
10000 abort_progress(void *arg
, unsigned char status
, const char *path
)
10003 * Unversioned files should not clutter progress output when
10004 * an operation is aborted.
10006 if (status
== GOT_STATUS_UNVERSIONED
)
10009 return update_progress(arg
, status
, path
);
10012 static const struct got_error
*
10013 cmd_rebase(int argc
, char *argv
[])
10015 const struct got_error
*error
= NULL
;
10016 struct got_worktree
*worktree
= NULL
;
10017 struct got_repository
*repo
= NULL
;
10018 struct got_fileindex
*fileindex
= NULL
;
10020 struct got_reference
*branch
= NULL
;
10021 struct got_reference
*new_base_branch
= NULL
, *tmp_branch
= NULL
;
10022 struct got_object_id
*commit_id
= NULL
, *parent_id
= NULL
;
10023 struct got_object_id
*resume_commit_id
= NULL
;
10024 struct got_object_id
*branch_head_commit_id
= NULL
, *yca_id
= NULL
;
10025 struct got_commit_object
*commit
= NULL
;
10026 int ch
, rebase_in_progress
= 0, abort_rebase
= 0, continue_rebase
= 0;
10027 int histedit_in_progress
= 0, merge_in_progress
= 0;
10028 int create_backup
= 1, list_backups
= 0, delete_backups
= 0;
10029 struct got_object_id_queue commits
;
10030 struct got_pathlist_head merged_paths
;
10031 const struct got_object_id_queue
*parent_ids
;
10032 struct got_object_qid
*qid
, *pid
;
10033 struct got_update_progress_arg upa
;
10034 int *pack_fds
= NULL
;
10036 STAILQ_INIT(&commits
);
10037 TAILQ_INIT(&merged_paths
);
10038 memset(&upa
, 0, sizeof(upa
));
10040 while ((ch
= getopt(argc
, argv
, "aclX")) != -1) {
10046 continue_rebase
= 1;
10052 delete_backups
= 1;
10064 if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd "
10065 "unveil", NULL
) == -1)
10068 if (list_backups
) {
10070 option_conflict('l', 'a');
10071 if (continue_rebase
)
10072 option_conflict('l', 'c');
10073 if (delete_backups
)
10074 option_conflict('l', 'X');
10075 if (argc
!= 0 && argc
!= 1)
10077 } else if (delete_backups
) {
10079 option_conflict('X', 'a');
10080 if (continue_rebase
)
10081 option_conflict('X', 'c');
10083 option_conflict('l', 'X');
10084 if (argc
!= 0 && argc
!= 1)
10087 if (abort_rebase
&& continue_rebase
)
10089 else if (abort_rebase
|| continue_rebase
) {
10092 } else if (argc
!= 1)
10096 cwd
= getcwd(NULL
, 0);
10098 error
= got_error_from_errno("getcwd");
10102 error
= got_repo_pack_fds_open(&pack_fds
);
10106 error
= got_worktree_open(&worktree
, cwd
);
10108 if (list_backups
|| delete_backups
) {
10109 if (error
->code
!= GOT_ERR_NOT_WORKTREE
)
10112 if (error
->code
== GOT_ERR_NOT_WORKTREE
)
10113 error
= wrap_not_worktree_error(error
,
10119 error
= got_repo_open(&repo
,
10120 worktree
? got_worktree_get_repo_path(worktree
) : cwd
, NULL
,
10125 error
= apply_unveil(got_repo_get_path(repo
), 0,
10126 worktree
? got_worktree_get_root_path(worktree
) : NULL
);
10130 if (list_backups
|| delete_backups
) {
10131 error
= process_backup_refs(
10132 GOT_WORKTREE_REBASE_BACKUP_REF_PREFIX
,
10133 argc
== 1 ? argv
[0] : NULL
, delete_backups
, repo
);
10134 goto done
; /* nothing else to do */
10137 error
= got_worktree_histedit_in_progress(&histedit_in_progress
,
10141 if (histedit_in_progress
) {
10142 error
= got_error(GOT_ERR_HISTEDIT_BUSY
);
10146 error
= got_worktree_merge_in_progress(&merge_in_progress
,
10150 if (merge_in_progress
) {
10151 error
= got_error(GOT_ERR_MERGE_BUSY
);
10155 error
= got_worktree_rebase_in_progress(&rebase_in_progress
, worktree
);
10159 if (abort_rebase
) {
10160 if (!rebase_in_progress
) {
10161 error
= got_error(GOT_ERR_NOT_REBASING
);
10164 error
= got_worktree_rebase_continue(&resume_commit_id
,
10165 &new_base_branch
, &tmp_branch
, &branch
, &fileindex
,
10169 printf("Switching work tree to %s\n",
10170 got_ref_get_symref_target(new_base_branch
));
10171 error
= got_worktree_rebase_abort(worktree
, fileindex
, repo
,
10172 new_base_branch
, abort_progress
, &upa
);
10175 printf("Rebase of %s aborted\n", got_ref_get_name(branch
));
10176 print_merge_progress_stats(&upa
);
10177 goto done
; /* nothing else to do */
10180 if (continue_rebase
) {
10181 if (!rebase_in_progress
) {
10182 error
= got_error(GOT_ERR_NOT_REBASING
);
10185 error
= got_worktree_rebase_continue(&resume_commit_id
,
10186 &new_base_branch
, &tmp_branch
, &branch
, &fileindex
,
10191 error
= rebase_commit(NULL
, worktree
, fileindex
, tmp_branch
,
10192 resume_commit_id
, repo
);
10196 yca_id
= got_object_id_dup(resume_commit_id
);
10197 if (yca_id
== NULL
) {
10198 error
= got_error_from_errno("got_object_id_dup");
10202 error
= got_ref_open(&branch
, repo
, argv
[0], 0);
10207 error
= got_ref_resolve(&branch_head_commit_id
, repo
, branch
);
10211 if (!continue_rebase
) {
10212 struct got_object_id
*base_commit_id
;
10214 base_commit_id
= got_worktree_get_base_commit_id(worktree
);
10215 error
= got_commit_graph_find_youngest_common_ancestor(&yca_id
,
10216 base_commit_id
, branch_head_commit_id
, 1, repo
,
10217 check_cancelled
, NULL
);
10220 if (yca_id
== NULL
) {
10221 error
= got_error_msg(GOT_ERR_ANCESTRY
,
10222 "specified branch shares no common ancestry "
10223 "with work tree's branch");
10227 error
= check_same_branch(base_commit_id
, branch
, yca_id
, repo
);
10229 if (error
->code
!= GOT_ERR_ANCESTRY
)
10233 struct got_pathlist_head paths
;
10234 printf("%s is already based on %s\n",
10235 got_ref_get_name(branch
),
10236 got_worktree_get_head_ref_name(worktree
));
10237 error
= switch_head_ref(branch
, branch_head_commit_id
,
10241 error
= got_worktree_set_base_commit_id(worktree
, repo
,
10242 branch_head_commit_id
);
10245 TAILQ_INIT(&paths
);
10246 error
= got_pathlist_append(&paths
, "", NULL
);
10249 error
= got_worktree_checkout_files(worktree
,
10250 &paths
, repo
, update_progress
, &upa
,
10251 check_cancelled
, NULL
);
10252 got_pathlist_free(&paths
);
10255 if (upa
.did_something
) {
10257 error
= got_object_id_str(&id_str
,
10258 branch_head_commit_id
);
10261 printf("Updated to %s: %s\n",
10262 got_worktree_get_head_ref_name(worktree
),
10266 printf("Already up-to-date\n");
10267 print_update_progress_stats(&upa
);
10272 commit_id
= branch_head_commit_id
;
10273 error
= got_object_open_as_commit(&commit
, repo
, commit_id
);
10277 parent_ids
= got_object_commit_get_parent_ids(commit
);
10278 pid
= STAILQ_FIRST(parent_ids
);
10280 error
= got_error(GOT_ERR_EMPTY_REBASE
);
10283 error
= collect_commits(&commits
, commit_id
, &pid
->id
,
10284 yca_id
, got_worktree_get_path_prefix(worktree
),
10285 GOT_ERR_REBASE_PATH
, repo
);
10286 got_object_commit_close(commit
);
10291 if (!continue_rebase
) {
10292 error
= got_worktree_rebase_prepare(&new_base_branch
,
10293 &tmp_branch
, &fileindex
, worktree
, branch
, repo
);
10298 if (STAILQ_EMPTY(&commits
)) {
10299 if (continue_rebase
) {
10300 error
= rebase_complete(worktree
, fileindex
,
10301 branch
, new_base_branch
, tmp_branch
, repo
,
10305 /* Fast-forward the reference of the branch. */
10306 struct got_object_id
*new_head_commit_id
;
10308 error
= got_ref_resolve(&new_head_commit_id
, repo
,
10312 error
= got_object_id_str(&id_str
, new_head_commit_id
);
10313 printf("Forwarding %s to commit %s\n",
10314 got_ref_get_name(branch
), id_str
);
10316 error
= got_ref_change_ref(branch
,
10317 new_head_commit_id
);
10320 /* No backup needed since objects did not change. */
10326 STAILQ_FOREACH(qid
, &commits
, entry
) {
10328 commit_id
= &qid
->id
;
10329 parent_id
= pid
? &pid
->id
: yca_id
;
10332 memset(&upa
, 0, sizeof(upa
));
10333 error
= got_worktree_rebase_merge_files(&merged_paths
,
10334 worktree
, fileindex
, parent_id
, commit_id
, repo
,
10335 update_progress
, &upa
, check_cancelled
, NULL
);
10339 print_merge_progress_stats(&upa
);
10340 if (upa
.conflicts
> 0 || upa
.missing
> 0 ||
10341 upa
.not_deleted
> 0 || upa
.unversioned
> 0) {
10342 if (upa
.conflicts
> 0) {
10343 error
= show_rebase_merge_conflict(&qid
->id
,
10348 got_worktree_rebase_pathlist_free(&merged_paths
);
10352 error
= rebase_commit(&merged_paths
, worktree
, fileindex
,
10353 tmp_branch
, commit_id
, repo
);
10354 got_worktree_rebase_pathlist_free(&merged_paths
);
10359 if (upa
.conflicts
> 0 || upa
.missing
> 0 ||
10360 upa
.not_deleted
> 0 || upa
.unversioned
> 0) {
10361 error
= got_worktree_rebase_postpone(worktree
, fileindex
);
10364 if (upa
.conflicts
> 0 && upa
.missing
== 0 &&
10365 upa
.not_deleted
== 0 && upa
.unversioned
== 0) {
10366 error
= got_error_msg(GOT_ERR_CONFLICTS
,
10367 "conflicts must be resolved before rebasing "
10369 } else if (upa
.conflicts
> 0) {
10370 error
= got_error_msg(GOT_ERR_CONFLICTS
,
10371 "conflicts must be resolved before rebasing "
10372 "can continue; changes destined for some "
10373 "files were not yet merged and should be "
10374 "merged manually if required before the "
10375 "rebase operation is continued");
10377 error
= got_error_msg(GOT_ERR_CONFLICTS
,
10378 "changes destined for some files were not "
10379 "yet merged and should be merged manually "
10380 "if required before the rebase operation "
10384 error
= rebase_complete(worktree
, fileindex
, branch
,
10385 new_base_branch
, tmp_branch
, repo
, create_backup
);
10387 got_object_id_queue_free(&commits
);
10388 free(branch_head_commit_id
);
10389 free(resume_commit_id
);
10392 got_object_commit_close(commit
);
10394 got_ref_close(branch
);
10395 if (new_base_branch
)
10396 got_ref_close(new_base_branch
);
10398 got_ref_close(tmp_branch
);
10400 got_worktree_close(worktree
);
10402 const struct got_error
*close_err
= got_repo_close(repo
);
10407 const struct got_error
*pack_err
=
10408 got_repo_pack_fds_close(pack_fds
);
10416 usage_histedit(void)
10418 fprintf(stderr
, "usage: %s histedit [-a] [-c] [-e] [-f] "
10419 "[-F histedit-script] [-m] [-l] [-X] [branch]\n",
10424 #define GOT_HISTEDIT_PICK 'p'
10425 #define GOT_HISTEDIT_EDIT 'e'
10426 #define GOT_HISTEDIT_FOLD 'f'
10427 #define GOT_HISTEDIT_DROP 'd'
10428 #define GOT_HISTEDIT_MESG 'm'
10430 static const struct got_histedit_cmd
{
10431 unsigned char code
;
10434 } got_histedit_cmds
[] = {
10435 { GOT_HISTEDIT_PICK
, "pick", "use commit" },
10436 { GOT_HISTEDIT_EDIT
, "edit", "use commit but stop for amending" },
10437 { GOT_HISTEDIT_FOLD
, "fold", "combine with next commit that will "
10439 { GOT_HISTEDIT_DROP
, "drop", "remove commit from history" },
10440 { GOT_HISTEDIT_MESG
, "mesg",
10441 "single-line log message for commit above (open editor if empty)" },
10444 struct got_histedit_list_entry
{
10445 TAILQ_ENTRY(got_histedit_list_entry
) entry
;
10446 struct got_object_id
*commit_id
;
10447 const struct got_histedit_cmd
*cmd
;
10450 TAILQ_HEAD(got_histedit_list
, got_histedit_list_entry
);
10452 static const struct got_error
*
10453 histedit_write_commit(struct got_object_id
*commit_id
, const char *cmdname
,
10454 FILE *f
, struct got_repository
*repo
)
10456 const struct got_error
*err
= NULL
;
10457 char *logmsg
= NULL
, *id_str
= NULL
;
10458 struct got_commit_object
*commit
= NULL
;
10461 err
= got_object_open_as_commit(&commit
, repo
, commit_id
);
10465 err
= get_short_logmsg(&logmsg
, 34, commit
);
10469 err
= got_object_id_str(&id_str
, commit_id
);
10473 n
= fprintf(f
, "%s %s %s\n", cmdname
, id_str
, logmsg
);
10475 err
= got_ferror(f
, GOT_ERR_IO
);
10478 got_object_commit_close(commit
);
10484 static const struct got_error
*
10485 histedit_write_commit_list(struct got_object_id_queue
*commits
,
10486 FILE *f
, int edit_logmsg_only
, int fold_only
, int edit_only
,
10487 struct got_repository
*repo
)
10489 const struct got_error
*err
= NULL
;
10490 struct got_object_qid
*qid
;
10491 const char *histedit_cmd
= NULL
;
10493 if (STAILQ_EMPTY(commits
))
10494 return got_error(GOT_ERR_EMPTY_HISTEDIT
);
10496 STAILQ_FOREACH(qid
, commits
, entry
) {
10497 histedit_cmd
= got_histedit_cmds
[0].name
;
10499 histedit_cmd
= "edit";
10500 else if (fold_only
&& STAILQ_NEXT(qid
, entry
) != NULL
)
10501 histedit_cmd
= "fold";
10502 err
= histedit_write_commit(&qid
->id
, histedit_cmd
, f
, repo
);
10505 if (edit_logmsg_only
) {
10506 int n
= fprintf(f
, "%c\n", GOT_HISTEDIT_MESG
);
10508 err
= got_ferror(f
, GOT_ERR_IO
);
10517 static const struct got_error
*
10518 write_cmd_list(FILE *f
, const char *branch_name
,
10519 struct got_object_id_queue
*commits
)
10521 const struct got_error
*err
= NULL
;
10525 struct got_object_qid
*qid
;
10527 qid
= STAILQ_FIRST(commits
);
10528 err
= got_object_id_str(&id_str
, &qid
->id
);
10533 "# Editing the history of branch '%s' starting at\n"
10535 "# Commits will be processed in order from top to "
10536 "bottom of this file.\n", branch_name
, id_str
);
10538 err
= got_ferror(f
, GOT_ERR_IO
);
10542 n
= fprintf(f
, "# Available histedit commands:\n");
10544 err
= got_ferror(f
, GOT_ERR_IO
);
10548 for (i
= 0; i
< nitems(got_histedit_cmds
); i
++) {
10549 const struct got_histedit_cmd
*cmd
= &got_histedit_cmds
[i
];
10550 n
= fprintf(f
, "# %s (%c): %s\n", cmd
->name
, cmd
->code
,
10553 err
= got_ferror(f
, GOT_ERR_IO
);
10562 static const struct got_error
*
10563 histedit_syntax_error(int lineno
)
10565 static char msg
[42];
10568 ret
= snprintf(msg
, sizeof(msg
), "histedit syntax error on line %d",
10570 if (ret
== -1 || ret
>= sizeof(msg
))
10571 return got_error(GOT_ERR_HISTEDIT_SYNTAX
);
10573 return got_error_msg(GOT_ERR_HISTEDIT_SYNTAX
, msg
);
10576 static const struct got_error
*
10577 append_folded_commit_msg(char **new_msg
, struct got_histedit_list_entry
*hle
,
10578 char *logmsg
, struct got_repository
*repo
)
10580 const struct got_error
*err
;
10581 struct got_commit_object
*folded_commit
= NULL
;
10582 char *id_str
, *folded_logmsg
= NULL
;
10584 err
= got_object_id_str(&id_str
, hle
->commit_id
);
10588 err
= got_object_open_as_commit(&folded_commit
, repo
, hle
->commit_id
);
10592 err
= got_object_commit_get_logmsg(&folded_logmsg
, folded_commit
);
10595 if (asprintf(new_msg
, "%s%s# log message of folded commit %s: %s",
10596 logmsg
? logmsg
: "", logmsg
? "\n" : "", id_str
,
10597 folded_logmsg
) == -1) {
10598 err
= got_error_from_errno("asprintf");
10602 got_object_commit_close(folded_commit
);
10604 free(folded_logmsg
);
10608 static struct got_histedit_list_entry
*
10609 get_folded_commits(struct got_histedit_list_entry
*hle
)
10611 struct got_histedit_list_entry
*prev
, *folded
= NULL
;
10613 prev
= TAILQ_PREV(hle
, got_histedit_list
, entry
);
10614 while (prev
&& (prev
->cmd
->code
== GOT_HISTEDIT_FOLD
||
10615 prev
->cmd
->code
== GOT_HISTEDIT_DROP
)) {
10616 if (prev
->cmd
->code
== GOT_HISTEDIT_FOLD
)
10618 prev
= TAILQ_PREV(prev
, got_histedit_list
, entry
);
10624 static const struct got_error
*
10625 histedit_edit_logmsg(struct got_histedit_list_entry
*hle
,
10626 struct got_repository
*repo
)
10628 char *logmsg_path
= NULL
, *id_str
= NULL
, *orig_logmsg
= NULL
;
10629 char *logmsg
= NULL
, *new_msg
= NULL
, *editor
= NULL
;
10630 const struct got_error
*err
= NULL
;
10631 struct got_commit_object
*commit
= NULL
;
10634 struct got_histedit_list_entry
*folded
= NULL
;
10636 err
= got_object_open_as_commit(&commit
, repo
, hle
->commit_id
);
10640 folded
= get_folded_commits(hle
);
10642 while (folded
!= hle
) {
10643 if (folded
->cmd
->code
== GOT_HISTEDIT_DROP
) {
10644 folded
= TAILQ_NEXT(folded
, entry
);
10647 err
= append_folded_commit_msg(&new_msg
, folded
,
10653 folded
= TAILQ_NEXT(folded
, entry
);
10657 err
= got_object_id_str(&id_str
, hle
->commit_id
);
10660 err
= got_object_commit_get_logmsg(&orig_logmsg
, commit
);
10663 logmsg_len
= asprintf(&new_msg
,
10664 "%s\n# original log message of commit %s: %s",
10665 logmsg
? logmsg
: "", id_str
, orig_logmsg
);
10666 if (logmsg_len
== -1) {
10667 err
= got_error_from_errno("asprintf");
10673 err
= got_object_id_str(&id_str
, hle
->commit_id
);
10677 err
= got_opentemp_named_fd(&logmsg_path
, &fd
,
10678 GOT_TMPDIR_STR
"/got-logmsg");
10682 write(fd
, logmsg
, logmsg_len
);
10685 err
= get_editor(&editor
);
10689 err
= edit_logmsg(&hle
->logmsg
, editor
, logmsg_path
, logmsg
,
10692 if (err
->code
!= GOT_ERR_COMMIT_MSG_EMPTY
)
10695 hle
->logmsg
= strdup(new_msg
);
10696 if (hle
->logmsg
== NULL
)
10697 err
= got_error_from_errno("strdup");
10700 if (logmsg_path
&& unlink(logmsg_path
) != 0 && err
== NULL
)
10701 err
= got_error_from_errno2("unlink", logmsg_path
);
10707 got_object_commit_close(commit
);
10711 static const struct got_error
*
10712 histedit_parse_list(struct got_histedit_list
*histedit_cmds
,
10713 FILE *f
, struct got_repository
*repo
)
10715 const struct got_error
*err
= NULL
;
10716 char *line
= NULL
, *p
, *end
;
10720 const struct got_histedit_cmd
*cmd
;
10721 struct got_object_id
*commit_id
= NULL
;
10722 struct got_histedit_list_entry
*hle
= NULL
;
10725 len
= getline(&line
, &size
, f
);
10727 const struct got_error
*getline_err
;
10730 getline_err
= got_error_from_errno("getline");
10731 err
= got_ferror(f
, getline_err
->code
);
10736 while (isspace((unsigned char)p
[0]))
10738 if (p
[0] == '#' || p
[0] == '\0') {
10744 for (i
= 0; i
< nitems(got_histedit_cmds
); i
++) {
10745 cmd
= &got_histedit_cmds
[i
];
10746 if (strncmp(cmd
->name
, p
, strlen(cmd
->name
)) == 0 &&
10747 isspace((unsigned char)p
[strlen(cmd
->name
)])) {
10748 p
+= strlen(cmd
->name
);
10751 if (p
[0] == cmd
->code
&& isspace((unsigned char)p
[1])) {
10756 if (i
== nitems(got_histedit_cmds
)) {
10757 err
= histedit_syntax_error(lineno
);
10760 while (isspace((unsigned char)p
[0]))
10762 if (cmd
->code
== GOT_HISTEDIT_MESG
) {
10763 if (hle
== NULL
|| hle
->logmsg
!= NULL
) {
10764 err
= got_error(GOT_ERR_HISTEDIT_CMD
);
10767 if (p
[0] == '\0') {
10768 err
= histedit_edit_logmsg(hle
, repo
);
10772 hle
->logmsg
= strdup(p
);
10773 if (hle
->logmsg
== NULL
) {
10774 err
= got_error_from_errno("strdup");
10783 while (end
[0] && !isspace((unsigned char)end
[0]))
10787 err
= got_object_resolve_id_str(&commit_id
, repo
, p
);
10789 /* override error code */
10790 err
= histedit_syntax_error(lineno
);
10794 hle
= malloc(sizeof(*hle
));
10796 err
= got_error_from_errno("malloc");
10800 hle
->commit_id
= commit_id
;
10801 hle
->logmsg
= NULL
;
10805 TAILQ_INSERT_TAIL(histedit_cmds
, hle
, entry
);
10813 static const struct got_error
*
10814 histedit_check_script(struct got_histedit_list
*histedit_cmds
,
10815 struct got_object_id_queue
*commits
, struct got_repository
*repo
)
10817 const struct got_error
*err
= NULL
;
10818 struct got_object_qid
*qid
;
10819 struct got_histedit_list_entry
*hle
;
10820 static char msg
[92];
10823 if (TAILQ_EMPTY(histedit_cmds
))
10824 return got_error_msg(GOT_ERR_EMPTY_HISTEDIT
,
10825 "histedit script contains no commands");
10826 if (STAILQ_EMPTY(commits
))
10827 return got_error(GOT_ERR_EMPTY_HISTEDIT
);
10829 TAILQ_FOREACH(hle
, histedit_cmds
, entry
) {
10830 struct got_histedit_list_entry
*hle2
;
10831 TAILQ_FOREACH(hle2
, histedit_cmds
, entry
) {
10834 if (got_object_id_cmp(hle
->commit_id
,
10835 hle2
->commit_id
) != 0)
10837 err
= got_object_id_str(&id_str
, hle
->commit_id
);
10840 snprintf(msg
, sizeof(msg
), "commit %s is listed "
10841 "more than once in histedit script", id_str
);
10843 return got_error_msg(GOT_ERR_HISTEDIT_CMD
, msg
);
10847 STAILQ_FOREACH(qid
, commits
, entry
) {
10848 TAILQ_FOREACH(hle
, histedit_cmds
, entry
) {
10849 if (got_object_id_cmp(&qid
->id
, hle
->commit_id
) == 0)
10853 err
= got_object_id_str(&id_str
, &qid
->id
);
10856 snprintf(msg
, sizeof(msg
),
10857 "commit %s missing from histedit script", id_str
);
10859 return got_error_msg(GOT_ERR_HISTEDIT_CMD
, msg
);
10863 hle
= TAILQ_LAST(histedit_cmds
, got_histedit_list
);
10864 if (hle
&& hle
->cmd
->code
== GOT_HISTEDIT_FOLD
)
10865 return got_error_msg(GOT_ERR_HISTEDIT_CMD
,
10866 "last commit in histedit script cannot be folded");
10871 static const struct got_error
*
10872 histedit_run_editor(struct got_histedit_list
*histedit_cmds
,
10873 const char *path
, struct got_object_id_queue
*commits
,
10874 struct got_repository
*repo
)
10876 const struct got_error
*err
= NULL
;
10880 err
= get_editor(&editor
);
10884 if (spawn_editor(editor
, path
) == -1) {
10885 err
= got_error_from_errno("failed spawning editor");
10889 f
= fopen(path
, "re");
10891 err
= got_error_from_errno("fopen");
10894 err
= histedit_parse_list(histedit_cmds
, f
, repo
);
10898 err
= histedit_check_script(histedit_cmds
, commits
, repo
);
10900 if (f
&& fclose(f
) == EOF
&& err
== NULL
)
10901 err
= got_error_from_errno("fclose");
10906 static const struct got_error
*
10907 histedit_edit_list_retry(struct got_histedit_list
*, const struct got_error
*,
10908 struct got_object_id_queue
*, const char *, const char *,
10909 struct got_repository
*);
10911 static const struct got_error
*
10912 histedit_edit_script(struct got_histedit_list
*histedit_cmds
,
10913 struct got_object_id_queue
*commits
, const char *branch_name
,
10914 int edit_logmsg_only
, int fold_only
, int edit_only
,
10915 struct got_repository
*repo
)
10917 const struct got_error
*err
;
10921 err
= got_opentemp_named(&path
, &f
, "got-histedit");
10925 err
= write_cmd_list(f
, branch_name
, commits
);
10929 err
= histedit_write_commit_list(commits
, f
, edit_logmsg_only
,
10930 fold_only
, edit_only
, repo
);
10934 if (edit_logmsg_only
|| fold_only
|| edit_only
) {
10936 err
= histedit_parse_list(histedit_cmds
, f
, repo
);
10938 if (fclose(f
) == EOF
) {
10939 err
= got_error_from_errno("fclose");
10943 err
= histedit_run_editor(histedit_cmds
, path
, commits
, repo
);
10945 if (err
->code
!= GOT_ERR_HISTEDIT_SYNTAX
&&
10946 err
->code
!= GOT_ERR_HISTEDIT_CMD
)
10948 err
= histedit_edit_list_retry(histedit_cmds
, err
,
10949 commits
, path
, branch_name
, repo
);
10953 if (f
&& fclose(f
) == EOF
&& err
== NULL
)
10954 err
= got_error_from_errno("fclose");
10955 if (path
&& unlink(path
) != 0 && err
== NULL
)
10956 err
= got_error_from_errno2("unlink", path
);
10961 static const struct got_error
*
10962 histedit_save_list(struct got_histedit_list
*histedit_cmds
,
10963 struct got_worktree
*worktree
, struct got_repository
*repo
)
10965 const struct got_error
*err
= NULL
;
10968 struct got_histedit_list_entry
*hle
;
10969 struct got_commit_object
*commit
= NULL
;
10971 err
= got_worktree_get_histedit_script_path(&path
, worktree
);
10975 f
= fopen(path
, "we");
10977 err
= got_error_from_errno2("fopen", path
);
10980 TAILQ_FOREACH(hle
, histedit_cmds
, entry
) {
10981 err
= histedit_write_commit(hle
->commit_id
, hle
->cmd
->name
, f
,
10987 int n
= fprintf(f
, "%c %s\n",
10988 GOT_HISTEDIT_MESG
, hle
->logmsg
);
10990 err
= got_ferror(f
, GOT_ERR_IO
);
10996 if (f
&& fclose(f
) == EOF
&& err
== NULL
)
10997 err
= got_error_from_errno("fclose");
11000 got_object_commit_close(commit
);
11005 histedit_free_list(struct got_histedit_list
*histedit_cmds
)
11007 struct got_histedit_list_entry
*hle
;
11009 while ((hle
= TAILQ_FIRST(histedit_cmds
))) {
11010 TAILQ_REMOVE(histedit_cmds
, hle
, entry
);
11015 static const struct got_error
*
11016 histedit_load_list(struct got_histedit_list
*histedit_cmds
,
11017 const char *path
, struct got_repository
*repo
)
11019 const struct got_error
*err
= NULL
;
11022 f
= fopen(path
, "re");
11024 err
= got_error_from_errno2("fopen", path
);
11028 err
= histedit_parse_list(histedit_cmds
, f
, repo
);
11030 if (f
&& fclose(f
) == EOF
&& err
== NULL
)
11031 err
= got_error_from_errno("fclose");
11035 static const struct got_error
*
11036 histedit_edit_list_retry(struct got_histedit_list
*histedit_cmds
,
11037 const struct got_error
*edit_err
, struct got_object_id_queue
*commits
,
11038 const char *path
, const char *branch_name
, struct got_repository
*repo
)
11040 const struct got_error
*err
= NULL
, *prev_err
= edit_err
;
11043 while (resp
!= 'c' && resp
!= 'r' && resp
!= 'a') {
11044 printf("%s: %s\n(c)ontinue editing, (r)estart editing, "
11045 "or (a)bort: ", getprogname(), prev_err
->msg
);
11050 histedit_free_list(histedit_cmds
);
11051 err
= histedit_run_editor(histedit_cmds
, path
, commits
,
11054 if (err
->code
!= GOT_ERR_HISTEDIT_SYNTAX
&&
11055 err
->code
!= GOT_ERR_HISTEDIT_CMD
)
11062 } else if (resp
== 'r') {
11063 histedit_free_list(histedit_cmds
);
11064 err
= histedit_edit_script(histedit_cmds
,
11065 commits
, branch_name
, 0, 0, 0, repo
);
11067 if (err
->code
!= GOT_ERR_HISTEDIT_SYNTAX
&&
11068 err
->code
!= GOT_ERR_HISTEDIT_CMD
)
11075 } else if (resp
== 'a') {
11076 err
= got_error(GOT_ERR_HISTEDIT_CANCEL
);
11079 printf("invalid response '%c'\n", resp
);
11085 static const struct got_error
*
11086 histedit_complete(struct got_worktree
*worktree
,
11087 struct got_fileindex
*fileindex
, struct got_reference
*tmp_branch
,
11088 struct got_reference
*branch
, struct got_repository
*repo
)
11090 printf("Switching work tree to %s\n",
11091 got_ref_get_symref_target(branch
));
11092 return got_worktree_histedit_complete(worktree
, fileindex
, tmp_branch
,
11096 static const struct got_error
*
11097 show_histedit_progress(struct got_commit_object
*commit
,
11098 struct got_histedit_list_entry
*hle
, struct got_object_id
*new_id
)
11100 const struct got_error
*err
;
11101 char *old_id_str
= NULL
, *new_id_str
= NULL
, *logmsg
= NULL
;
11103 err
= got_object_id_str(&old_id_str
, hle
->commit_id
);
11108 err
= got_object_id_str(&new_id_str
, new_id
);
11113 old_id_str
[12] = '\0';
11115 new_id_str
[12] = '\0';
11118 logmsg
= strdup(hle
->logmsg
);
11119 if (logmsg
== NULL
) {
11120 err
= got_error_from_errno("strdup");
11123 trim_logmsg(logmsg
, 42);
11125 err
= get_short_logmsg(&logmsg
, 42, commit
);
11130 switch (hle
->cmd
->code
) {
11131 case GOT_HISTEDIT_PICK
:
11132 case GOT_HISTEDIT_EDIT
:
11133 printf("%s -> %s: %s\n", old_id_str
,
11134 new_id_str
? new_id_str
: "no-op change", logmsg
);
11136 case GOT_HISTEDIT_DROP
:
11137 case GOT_HISTEDIT_FOLD
:
11138 printf("%s -> %s commit: %s\n", old_id_str
, hle
->cmd
->name
,
11150 static const struct got_error
*
11151 histedit_commit(struct got_pathlist_head
*merged_paths
,
11152 struct got_worktree
*worktree
, struct got_fileindex
*fileindex
,
11153 struct got_reference
*tmp_branch
, struct got_histedit_list_entry
*hle
,
11154 struct got_repository
*repo
)
11156 const struct got_error
*err
;
11157 struct got_commit_object
*commit
;
11158 struct got_object_id
*new_commit_id
;
11160 if ((hle
->cmd
->code
== GOT_HISTEDIT_EDIT
|| get_folded_commits(hle
))
11161 && hle
->logmsg
== NULL
) {
11162 err
= histedit_edit_logmsg(hle
, repo
);
11167 err
= got_object_open_as_commit(&commit
, repo
, hle
->commit_id
);
11171 err
= got_worktree_histedit_commit(&new_commit_id
, merged_paths
,
11172 worktree
, fileindex
, tmp_branch
, commit
, hle
->commit_id
,
11173 hle
->logmsg
, repo
);
11175 if (err
->code
!= GOT_ERR_COMMIT_NO_CHANGES
)
11177 err
= show_histedit_progress(commit
, hle
, NULL
);
11179 err
= show_histedit_progress(commit
, hle
, new_commit_id
);
11180 free(new_commit_id
);
11183 got_object_commit_close(commit
);
11187 static const struct got_error
*
11188 histedit_skip_commit(struct got_histedit_list_entry
*hle
,
11189 struct got_worktree
*worktree
, struct got_repository
*repo
)
11191 const struct got_error
*error
;
11192 struct got_commit_object
*commit
;
11194 error
= got_worktree_histedit_skip_commit(worktree
, hle
->commit_id
,
11199 error
= got_object_open_as_commit(&commit
, repo
, hle
->commit_id
);
11203 error
= show_histedit_progress(commit
, hle
, NULL
);
11204 got_object_commit_close(commit
);
11208 static const struct got_error
*
11209 check_local_changes(void *arg
, unsigned char status
,
11210 unsigned char staged_status
, const char *path
,
11211 struct got_object_id
*blob_id
, struct got_object_id
*staged_blob_id
,
11212 struct got_object_id
*commit_id
, int dirfd
, const char *de_name
)
11214 int *have_local_changes
= arg
;
11217 case GOT_STATUS_ADD
:
11218 case GOT_STATUS_DELETE
:
11219 case GOT_STATUS_MODIFY
:
11220 case GOT_STATUS_CONFLICT
:
11221 *have_local_changes
= 1;
11222 return got_error(GOT_ERR_CANCELLED
);
11227 switch (staged_status
) {
11228 case GOT_STATUS_ADD
:
11229 case GOT_STATUS_DELETE
:
11230 case GOT_STATUS_MODIFY
:
11231 *have_local_changes
= 1;
11232 return got_error(GOT_ERR_CANCELLED
);
11240 static const struct got_error
*
11241 cmd_histedit(int argc
, char *argv
[])
11243 const struct got_error
*error
= NULL
;
11244 struct got_worktree
*worktree
= NULL
;
11245 struct got_fileindex
*fileindex
= NULL
;
11246 struct got_repository
*repo
= NULL
;
11248 struct got_reference
*branch
= NULL
;
11249 struct got_reference
*tmp_branch
= NULL
;
11250 struct got_object_id
*resume_commit_id
= NULL
;
11251 struct got_object_id
*base_commit_id
= NULL
;
11252 struct got_object_id
*head_commit_id
= NULL
;
11253 struct got_commit_object
*commit
= NULL
;
11254 int ch
, rebase_in_progress
= 0, merge_in_progress
= 0;
11255 struct got_update_progress_arg upa
;
11256 int edit_in_progress
= 0, abort_edit
= 0, continue_edit
= 0;
11257 int edit_logmsg_only
= 0, fold_only
= 0, edit_only
= 0;
11258 int list_backups
= 0, delete_backups
= 0;
11259 const char *edit_script_path
= NULL
;
11260 struct got_object_id_queue commits
;
11261 struct got_pathlist_head merged_paths
;
11262 const struct got_object_id_queue
*parent_ids
;
11263 struct got_object_qid
*pid
;
11264 struct got_histedit_list histedit_cmds
;
11265 struct got_histedit_list_entry
*hle
;
11266 int *pack_fds
= NULL
;
11268 STAILQ_INIT(&commits
);
11269 TAILQ_INIT(&histedit_cmds
);
11270 TAILQ_INIT(&merged_paths
);
11271 memset(&upa
, 0, sizeof(upa
));
11273 while ((ch
= getopt(argc
, argv
, "acefF:mlX")) != -1) {
11288 edit_script_path
= optarg
;
11291 edit_logmsg_only
= 1;
11297 delete_backups
= 1;
11309 if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd "
11310 "unveil", NULL
) == -1)
11313 if (abort_edit
&& continue_edit
)
11314 option_conflict('a', 'c');
11315 if (edit_script_path
&& edit_logmsg_only
)
11316 option_conflict('F', 'm');
11317 if (abort_edit
&& edit_logmsg_only
)
11318 option_conflict('a', 'm');
11319 if (continue_edit
&& edit_logmsg_only
)
11320 option_conflict('c', 'm');
11321 if (abort_edit
&& fold_only
)
11322 option_conflict('a', 'f');
11323 if (continue_edit
&& fold_only
)
11324 option_conflict('c', 'f');
11325 if (fold_only
&& edit_logmsg_only
)
11326 option_conflict('f', 'm');
11327 if (edit_script_path
&& fold_only
)
11328 option_conflict('F', 'f');
11329 if (abort_edit
&& edit_only
)
11330 option_conflict('a', 'e');
11331 if (continue_edit
&& edit_only
)
11332 option_conflict('c', 'e');
11333 if (edit_only
&& edit_logmsg_only
)
11334 option_conflict('e', 'm');
11335 if (edit_script_path
&& edit_only
)
11336 option_conflict('F', 'e');
11337 if (list_backups
) {
11339 option_conflict('l', 'a');
11341 option_conflict('l', 'c');
11342 if (edit_script_path
)
11343 option_conflict('l', 'F');
11344 if (edit_logmsg_only
)
11345 option_conflict('l', 'm');
11347 option_conflict('l', 'f');
11349 option_conflict('l', 'e');
11350 if (delete_backups
)
11351 option_conflict('l', 'X');
11352 if (argc
!= 0 && argc
!= 1)
11354 } else if (delete_backups
) {
11356 option_conflict('X', 'a');
11358 option_conflict('X', 'c');
11359 if (edit_script_path
)
11360 option_conflict('X', 'F');
11361 if (edit_logmsg_only
)
11362 option_conflict('X', 'm');
11364 option_conflict('X', 'f');
11366 option_conflict('X', 'e');
11368 option_conflict('X', 'l');
11369 if (argc
!= 0 && argc
!= 1)
11371 } else if (argc
!= 0)
11375 * This command cannot apply unveil(2) in all cases because the
11376 * user may choose to run an editor to edit the histedit script
11377 * and to edit individual commit log messages.
11378 * unveil(2) traverses exec(2); if an editor is used we have to
11379 * apply unveil after edit script and log messages have been written.
11380 * XXX TODO: Make use of unveil(2) where possible.
11383 cwd
= getcwd(NULL
, 0);
11385 error
= got_error_from_errno("getcwd");
11389 error
= got_repo_pack_fds_open(&pack_fds
);
11393 error
= got_worktree_open(&worktree
, cwd
);
11395 if (list_backups
|| delete_backups
) {
11396 if (error
->code
!= GOT_ERR_NOT_WORKTREE
)
11399 if (error
->code
== GOT_ERR_NOT_WORKTREE
)
11400 error
= wrap_not_worktree_error(error
,
11406 if (list_backups
|| delete_backups
) {
11407 error
= got_repo_open(&repo
,
11408 worktree
? got_worktree_get_repo_path(worktree
) : cwd
,
11412 error
= apply_unveil(got_repo_get_path(repo
), 0,
11413 worktree
? got_worktree_get_root_path(worktree
) : NULL
);
11416 error
= process_backup_refs(
11417 GOT_WORKTREE_HISTEDIT_BACKUP_REF_PREFIX
,
11418 argc
== 1 ? argv
[0] : NULL
, delete_backups
, repo
);
11419 goto done
; /* nothing else to do */
11422 error
= got_repo_open(&repo
, got_worktree_get_repo_path(worktree
),
11427 error
= got_worktree_rebase_in_progress(&rebase_in_progress
, worktree
);
11430 if (rebase_in_progress
) {
11431 error
= got_error(GOT_ERR_REBASING
);
11435 error
= got_worktree_merge_in_progress(&merge_in_progress
, worktree
,
11439 if (merge_in_progress
) {
11440 error
= got_error(GOT_ERR_MERGE_BUSY
);
11444 error
= got_worktree_histedit_in_progress(&edit_in_progress
, worktree
);
11448 if (edit_in_progress
&& edit_logmsg_only
) {
11449 error
= got_error_msg(GOT_ERR_HISTEDIT_BUSY
,
11450 "histedit operation is in progress in this "
11451 "work tree and must be continued or aborted "
11452 "before the -m option can be used");
11455 if (edit_in_progress
&& fold_only
) {
11456 error
= got_error_msg(GOT_ERR_HISTEDIT_BUSY
,
11457 "histedit operation is in progress in this "
11458 "work tree and must be continued or aborted "
11459 "before the -f option can be used");
11462 if (edit_in_progress
&& edit_only
) {
11463 error
= got_error_msg(GOT_ERR_HISTEDIT_BUSY
,
11464 "histedit operation is in progress in this "
11465 "work tree and must be continued or aborted "
11466 "before the -e option can be used");
11470 if (edit_in_progress
&& abort_edit
) {
11471 error
= got_worktree_histedit_continue(&resume_commit_id
,
11472 &tmp_branch
, &branch
, &base_commit_id
, &fileindex
,
11476 printf("Switching work tree to %s\n",
11477 got_ref_get_symref_target(branch
));
11478 error
= got_worktree_histedit_abort(worktree
, fileindex
, repo
,
11479 branch
, base_commit_id
, abort_progress
, &upa
);
11482 printf("Histedit of %s aborted\n",
11483 got_ref_get_symref_target(branch
));
11484 print_merge_progress_stats(&upa
);
11485 goto done
; /* nothing else to do */
11486 } else if (abort_edit
) {
11487 error
= got_error(GOT_ERR_NOT_HISTEDIT
);
11491 if (continue_edit
) {
11494 if (!edit_in_progress
) {
11495 error
= got_error(GOT_ERR_NOT_HISTEDIT
);
11499 error
= got_worktree_get_histedit_script_path(&path
, worktree
);
11503 error
= histedit_load_list(&histedit_cmds
, path
, repo
);
11508 error
= got_worktree_histedit_continue(&resume_commit_id
,
11509 &tmp_branch
, &branch
, &base_commit_id
, &fileindex
,
11514 error
= got_ref_resolve(&head_commit_id
, repo
, branch
);
11518 error
= got_object_open_as_commit(&commit
, repo
,
11522 parent_ids
= got_object_commit_get_parent_ids(commit
);
11523 pid
= STAILQ_FIRST(parent_ids
);
11525 error
= got_error(GOT_ERR_EMPTY_HISTEDIT
);
11528 error
= collect_commits(&commits
, head_commit_id
, &pid
->id
,
11529 base_commit_id
, got_worktree_get_path_prefix(worktree
),
11530 GOT_ERR_HISTEDIT_PATH
, repo
);
11531 got_object_commit_close(commit
);
11536 if (edit_in_progress
) {
11537 error
= got_error(GOT_ERR_HISTEDIT_BUSY
);
11541 error
= got_ref_open(&branch
, repo
,
11542 got_worktree_get_head_ref_name(worktree
), 0);
11546 if (strncmp(got_ref_get_name(branch
), "refs/heads/", 11) != 0) {
11547 error
= got_error_msg(GOT_ERR_COMMIT_BRANCH
,
11548 "will not edit commit history of a branch outside "
11549 "the \"refs/heads/\" reference namespace");
11553 error
= got_ref_resolve(&head_commit_id
, repo
, branch
);
11554 got_ref_close(branch
);
11559 error
= got_object_open_as_commit(&commit
, repo
,
11563 parent_ids
= got_object_commit_get_parent_ids(commit
);
11564 pid
= STAILQ_FIRST(parent_ids
);
11566 error
= got_error(GOT_ERR_EMPTY_HISTEDIT
);
11569 error
= collect_commits(&commits
, head_commit_id
, &pid
->id
,
11570 got_worktree_get_base_commit_id(worktree
),
11571 got_worktree_get_path_prefix(worktree
),
11572 GOT_ERR_HISTEDIT_PATH
, repo
);
11573 got_object_commit_close(commit
);
11578 if (STAILQ_EMPTY(&commits
)) {
11579 error
= got_error(GOT_ERR_EMPTY_HISTEDIT
);
11583 error
= got_worktree_histedit_prepare(&tmp_branch
, &branch
,
11584 &base_commit_id
, &fileindex
, worktree
, repo
);
11588 if (edit_script_path
) {
11589 error
= histedit_load_list(&histedit_cmds
,
11590 edit_script_path
, repo
);
11592 got_worktree_histedit_abort(worktree
, fileindex
,
11593 repo
, branch
, base_commit_id
,
11594 abort_progress
, &upa
);
11595 print_merge_progress_stats(&upa
);
11599 const char *branch_name
;
11600 branch_name
= got_ref_get_symref_target(branch
);
11601 if (strncmp(branch_name
, "refs/heads/", 11) == 0)
11603 error
= histedit_edit_script(&histedit_cmds
, &commits
,
11604 branch_name
, edit_logmsg_only
, fold_only
,
11607 got_worktree_histedit_abort(worktree
, fileindex
,
11608 repo
, branch
, base_commit_id
,
11609 abort_progress
, &upa
);
11610 print_merge_progress_stats(&upa
);
11616 error
= histedit_save_list(&histedit_cmds
, worktree
,
11619 got_worktree_histedit_abort(worktree
, fileindex
,
11620 repo
, branch
, base_commit_id
,
11621 abort_progress
, &upa
);
11622 print_merge_progress_stats(&upa
);
11628 error
= histedit_check_script(&histedit_cmds
, &commits
, repo
);
11632 TAILQ_FOREACH(hle
, &histedit_cmds
, entry
) {
11633 if (resume_commit_id
) {
11634 if (got_object_id_cmp(hle
->commit_id
,
11635 resume_commit_id
) != 0)
11638 resume_commit_id
= NULL
;
11639 if (hle
->cmd
->code
== GOT_HISTEDIT_DROP
||
11640 hle
->cmd
->code
== GOT_HISTEDIT_FOLD
) {
11641 error
= histedit_skip_commit(hle
, worktree
,
11646 struct got_pathlist_head paths
;
11647 int have_changes
= 0;
11649 TAILQ_INIT(&paths
);
11650 error
= got_pathlist_append(&paths
, "", NULL
);
11653 error
= got_worktree_status(worktree
, &paths
,
11654 repo
, 0, check_local_changes
, &have_changes
,
11655 check_cancelled
, NULL
);
11656 got_pathlist_free(&paths
);
11658 if (error
->code
!= GOT_ERR_CANCELLED
)
11660 if (sigint_received
|| sigpipe_received
)
11663 if (have_changes
) {
11664 error
= histedit_commit(NULL
, worktree
,
11665 fileindex
, tmp_branch
, hle
, repo
);
11669 error
= got_object_open_as_commit(
11670 &commit
, repo
, hle
->commit_id
);
11673 error
= show_histedit_progress(commit
,
11675 got_object_commit_close(commit
);
11684 if (hle
->cmd
->code
== GOT_HISTEDIT_DROP
) {
11685 error
= histedit_skip_commit(hle
, worktree
, repo
);
11691 error
= got_object_open_as_commit(&commit
, repo
,
11695 parent_ids
= got_object_commit_get_parent_ids(commit
);
11696 pid
= STAILQ_FIRST(parent_ids
);
11698 error
= got_worktree_histedit_merge_files(&merged_paths
,
11699 worktree
, fileindex
, &pid
->id
, hle
->commit_id
, repo
,
11700 update_progress
, &upa
, check_cancelled
, NULL
);
11703 got_object_commit_close(commit
);
11706 print_merge_progress_stats(&upa
);
11707 if (upa
.conflicts
> 0 || upa
.missing
> 0 ||
11708 upa
.not_deleted
> 0 || upa
.unversioned
> 0) {
11709 if (upa
.conflicts
> 0) {
11710 error
= show_rebase_merge_conflict(
11711 hle
->commit_id
, repo
);
11715 got_worktree_rebase_pathlist_free(&merged_paths
);
11719 if (hle
->cmd
->code
== GOT_HISTEDIT_EDIT
) {
11721 error
= got_object_id_str(&id_str
, hle
->commit_id
);
11724 printf("Stopping histedit for amending commit %s\n",
11727 got_worktree_rebase_pathlist_free(&merged_paths
);
11728 error
= got_worktree_histedit_postpone(worktree
,
11733 if (hle
->cmd
->code
== GOT_HISTEDIT_FOLD
) {
11734 error
= histedit_skip_commit(hle
, worktree
, repo
);
11740 error
= histedit_commit(&merged_paths
, worktree
, fileindex
,
11741 tmp_branch
, hle
, repo
);
11742 got_worktree_rebase_pathlist_free(&merged_paths
);
11747 if (upa
.conflicts
> 0 || upa
.missing
> 0 ||
11748 upa
.not_deleted
> 0 || upa
.unversioned
> 0) {
11749 error
= got_worktree_histedit_postpone(worktree
, fileindex
);
11752 if (upa
.conflicts
> 0 && upa
.missing
== 0 &&
11753 upa
.not_deleted
== 0 && upa
.unversioned
== 0) {
11754 error
= got_error_msg(GOT_ERR_CONFLICTS
,
11755 "conflicts must be resolved before histedit "
11757 } else if (upa
.conflicts
> 0) {
11758 error
= got_error_msg(GOT_ERR_CONFLICTS
,
11759 "conflicts must be resolved before histedit "
11760 "can continue; changes destined for some "
11761 "files were not yet merged and should be "
11762 "merged manually if required before the "
11763 "histedit operation is continued");
11765 error
= got_error_msg(GOT_ERR_CONFLICTS
,
11766 "changes destined for some files were not "
11767 "yet merged and should be merged manually "
11768 "if required before the histedit operation "
11772 error
= histedit_complete(worktree
, fileindex
, tmp_branch
,
11775 got_object_id_queue_free(&commits
);
11776 histedit_free_list(&histedit_cmds
);
11777 free(head_commit_id
);
11778 free(base_commit_id
);
11779 free(resume_commit_id
);
11781 got_object_commit_close(commit
);
11783 got_ref_close(branch
);
11785 got_ref_close(tmp_branch
);
11787 got_worktree_close(worktree
);
11789 const struct got_error
*close_err
= got_repo_close(repo
);
11794 const struct got_error
*pack_err
=
11795 got_repo_pack_fds_close(pack_fds
);
11803 usage_integrate(void)
11805 fprintf(stderr
, "usage: %s integrate branch\n", getprogname());
11809 static const struct got_error
*
11810 cmd_integrate(int argc
, char *argv
[])
11812 const struct got_error
*error
= NULL
;
11813 struct got_repository
*repo
= NULL
;
11814 struct got_worktree
*worktree
= NULL
;
11815 char *cwd
= NULL
, *refname
= NULL
, *base_refname
= NULL
;
11816 const char *branch_arg
= NULL
;
11817 struct got_reference
*branch_ref
= NULL
, *base_branch_ref
= NULL
;
11818 struct got_fileindex
*fileindex
= NULL
;
11819 struct got_object_id
*commit_id
= NULL
, *base_commit_id
= NULL
;
11821 struct got_update_progress_arg upa
;
11822 int *pack_fds
= NULL
;
11824 while ((ch
= getopt(argc
, argv
, "")) != -1) {
11837 branch_arg
= argv
[0];
11839 if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd "
11840 "unveil", NULL
) == -1)
11843 cwd
= getcwd(NULL
, 0);
11845 error
= got_error_from_errno("getcwd");
11849 error
= got_repo_pack_fds_open(&pack_fds
);
11853 error
= got_worktree_open(&worktree
, cwd
);
11855 if (error
->code
== GOT_ERR_NOT_WORKTREE
)
11856 error
= wrap_not_worktree_error(error
, "integrate",
11861 error
= check_rebase_or_histedit_in_progress(worktree
);
11865 error
= got_repo_open(&repo
, got_worktree_get_repo_path(worktree
),
11870 error
= apply_unveil(got_repo_get_path(repo
), 0,
11871 got_worktree_get_root_path(worktree
));
11875 error
= check_merge_in_progress(worktree
, repo
);
11879 if (asprintf(&refname
, "refs/heads/%s", branch_arg
) == -1) {
11880 error
= got_error_from_errno("asprintf");
11884 error
= got_worktree_integrate_prepare(&fileindex
, &branch_ref
,
11885 &base_branch_ref
, worktree
, refname
, repo
);
11889 refname
= strdup(got_ref_get_name(branch_ref
));
11890 if (refname
== NULL
) {
11891 error
= got_error_from_errno("strdup");
11892 got_worktree_integrate_abort(worktree
, fileindex
, repo
,
11893 branch_ref
, base_branch_ref
);
11896 base_refname
= strdup(got_ref_get_name(base_branch_ref
));
11897 if (base_refname
== NULL
) {
11898 error
= got_error_from_errno("strdup");
11899 got_worktree_integrate_abort(worktree
, fileindex
, repo
,
11900 branch_ref
, base_branch_ref
);
11904 error
= got_ref_resolve(&commit_id
, repo
, branch_ref
);
11908 error
= got_ref_resolve(&base_commit_id
, repo
, base_branch_ref
);
11912 if (got_object_id_cmp(commit_id
, base_commit_id
) == 0) {
11913 error
= got_error_msg(GOT_ERR_SAME_BRANCH
,
11914 "specified branch has already been integrated");
11915 got_worktree_integrate_abort(worktree
, fileindex
, repo
,
11916 branch_ref
, base_branch_ref
);
11920 error
= check_linear_ancestry(commit_id
, base_commit_id
, 1, repo
);
11922 if (error
->code
== GOT_ERR_ANCESTRY
)
11923 error
= got_error(GOT_ERR_REBASE_REQUIRED
);
11924 got_worktree_integrate_abort(worktree
, fileindex
, repo
,
11925 branch_ref
, base_branch_ref
);
11929 memset(&upa
, 0, sizeof(upa
));
11930 error
= got_worktree_integrate_continue(worktree
, fileindex
, repo
,
11931 branch_ref
, base_branch_ref
, update_progress
, &upa
,
11932 check_cancelled
, NULL
);
11936 printf("Integrated %s into %s\n", refname
, base_refname
);
11937 print_update_progress_stats(&upa
);
11940 const struct got_error
*close_err
= got_repo_close(repo
);
11945 got_worktree_close(worktree
);
11947 const struct got_error
*pack_err
=
11948 got_repo_pack_fds_close(pack_fds
);
11953 free(base_commit_id
);
11956 free(base_refname
);
11963 fprintf(stderr
, "usage: %s merge [-a] [-c] [-n] [branch]\n",
11968 static const struct got_error
*
11969 cmd_merge(int argc
, char *argv
[])
11971 const struct got_error
*error
= NULL
;
11972 struct got_worktree
*worktree
= NULL
;
11973 struct got_repository
*repo
= NULL
;
11974 struct got_fileindex
*fileindex
= NULL
;
11975 char *cwd
= NULL
, *id_str
= NULL
, *author
= NULL
;
11976 struct got_reference
*branch
= NULL
, *wt_branch
= NULL
;
11977 struct got_object_id
*branch_tip
= NULL
, *yca_id
= NULL
;
11978 struct got_object_id
*wt_branch_tip
= NULL
;
11979 int ch
, merge_in_progress
= 0, abort_merge
= 0, continue_merge
= 0;
11980 int interrupt_merge
= 0;
11981 struct got_update_progress_arg upa
;
11982 struct got_object_id
*merge_commit_id
= NULL
;
11983 char *branch_name
= NULL
;
11984 int *pack_fds
= NULL
;
11986 memset(&upa
, 0, sizeof(upa
));
11988 while ((ch
= getopt(argc
, argv
, "acn")) != -1) {
11994 continue_merge
= 1;
11997 interrupt_merge
= 1;
12009 if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd "
12010 "unveil", NULL
) == -1)
12014 if (abort_merge
&& continue_merge
)
12015 option_conflict('a', 'c');
12016 if (abort_merge
|| continue_merge
) {
12019 } else if (argc
!= 1)
12022 cwd
= getcwd(NULL
, 0);
12024 error
= got_error_from_errno("getcwd");
12028 error
= got_repo_pack_fds_open(&pack_fds
);
12032 error
= got_worktree_open(&worktree
, cwd
);
12034 if (error
->code
== GOT_ERR_NOT_WORKTREE
)
12035 error
= wrap_not_worktree_error(error
,
12040 error
= got_repo_open(&repo
,
12041 worktree
? got_worktree_get_repo_path(worktree
) : cwd
, NULL
,
12046 error
= apply_unveil(got_repo_get_path(repo
), 0,
12047 worktree
? got_worktree_get_root_path(worktree
) : NULL
);
12051 error
= check_rebase_or_histedit_in_progress(worktree
);
12055 error
= got_worktree_merge_in_progress(&merge_in_progress
, worktree
,
12061 if (!merge_in_progress
) {
12062 error
= got_error(GOT_ERR_NOT_MERGING
);
12065 error
= got_worktree_merge_continue(&branch_name
,
12066 &branch_tip
, &fileindex
, worktree
, repo
);
12069 error
= got_worktree_merge_abort(worktree
, fileindex
, repo
,
12070 abort_progress
, &upa
);
12073 printf("Merge of %s aborted\n", branch_name
);
12074 goto done
; /* nothing else to do */
12077 error
= get_author(&author
, repo
, worktree
);
12081 if (continue_merge
) {
12082 if (!merge_in_progress
) {
12083 error
= got_error(GOT_ERR_NOT_MERGING
);
12086 error
= got_worktree_merge_continue(&branch_name
,
12087 &branch_tip
, &fileindex
, worktree
, repo
);
12091 error
= got_ref_open(&branch
, repo
, argv
[0], 0);
12094 branch_name
= strdup(got_ref_get_name(branch
));
12095 if (branch_name
== NULL
) {
12096 error
= got_error_from_errno("strdup");
12099 error
= got_ref_resolve(&branch_tip
, repo
, branch
);
12104 error
= got_ref_open(&wt_branch
, repo
,
12105 got_worktree_get_head_ref_name(worktree
), 0);
12108 error
= got_ref_resolve(&wt_branch_tip
, repo
, wt_branch
);
12111 error
= got_commit_graph_find_youngest_common_ancestor(&yca_id
,
12112 wt_branch_tip
, branch_tip
, 0, repo
,
12113 check_cancelled
, NULL
);
12114 if (error
&& error
->code
!= GOT_ERR_ANCESTRY
)
12117 if (!continue_merge
) {
12118 error
= check_path_prefix(wt_branch_tip
, branch_tip
,
12119 got_worktree_get_path_prefix(worktree
),
12120 GOT_ERR_MERGE_PATH
, repo
);
12124 error
= check_same_branch(wt_branch_tip
, branch
,
12127 if (error
->code
!= GOT_ERR_ANCESTRY
)
12131 static char msg
[512];
12132 snprintf(msg
, sizeof(msg
),
12133 "cannot create a merge commit because "
12134 "%s is based on %s; %s can be integrated "
12135 "with 'got integrate' instead", branch_name
,
12136 got_worktree_get_head_ref_name(worktree
),
12138 error
= got_error_msg(GOT_ERR_SAME_BRANCH
, msg
);
12142 error
= got_worktree_merge_prepare(&fileindex
, worktree
,
12147 error
= got_worktree_merge_branch(worktree
, fileindex
,
12148 yca_id
, branch_tip
, repo
, update_progress
, &upa
,
12149 check_cancelled
, NULL
);
12152 print_merge_progress_stats(&upa
);
12153 if (!upa
.did_something
) {
12154 error
= got_worktree_merge_abort(worktree
, fileindex
,
12155 repo
, abort_progress
, &upa
);
12158 printf("Already up-to-date\n");
12163 if (interrupt_merge
) {
12164 error
= got_worktree_merge_postpone(worktree
, fileindex
);
12167 printf("Merge of %s interrupted on request\n", branch_name
);
12168 } else if (upa
.conflicts
> 0 || upa
.missing
> 0 ||
12169 upa
.not_deleted
> 0 || upa
.unversioned
> 0) {
12170 error
= got_worktree_merge_postpone(worktree
, fileindex
);
12173 if (upa
.conflicts
> 0 && upa
.missing
== 0 &&
12174 upa
.not_deleted
== 0 && upa
.unversioned
== 0) {
12175 error
= got_error_msg(GOT_ERR_CONFLICTS
,
12176 "conflicts must be resolved before merging "
12178 } else if (upa
.conflicts
> 0) {
12179 error
= got_error_msg(GOT_ERR_CONFLICTS
,
12180 "conflicts must be resolved before merging "
12181 "can continue; changes destined for some "
12182 "files were not yet merged and "
12183 "should be merged manually if required before the "
12184 "merge operation is continued");
12186 error
= got_error_msg(GOT_ERR_CONFLICTS
,
12187 "changes destined for some "
12188 "files were not yet merged and should be "
12189 "merged manually if required before the "
12190 "merge operation is continued");
12194 error
= got_worktree_merge_commit(&merge_commit_id
, worktree
,
12195 fileindex
, author
, NULL
, 1, branch_tip
, branch_name
,
12196 repo
, continue_merge
? print_status
: NULL
, NULL
);
12199 error
= got_worktree_merge_complete(worktree
, fileindex
, repo
);
12202 error
= got_object_id_str(&id_str
, merge_commit_id
);
12205 printf("Merged %s into %s: %s\n", branch_name
,
12206 got_worktree_get_head_ref_name(worktree
),
12212 free(merge_commit_id
);
12218 got_ref_close(branch
);
12220 got_ref_close(wt_branch
);
12222 got_worktree_close(worktree
);
12224 const struct got_error
*close_err
= got_repo_close(repo
);
12229 const struct got_error
*pack_err
=
12230 got_repo_pack_fds_close(pack_fds
);
12240 fprintf(stderr
, "usage: %s stage [-l] | [-p] [-F response-script] "
12241 "[-S] [file-path ...]\n",
12246 static const struct got_error
*
12247 print_stage(void *arg
, unsigned char status
, unsigned char staged_status
,
12248 const char *path
, struct got_object_id
*blob_id
,
12249 struct got_object_id
*staged_blob_id
, struct got_object_id
*commit_id
,
12250 int dirfd
, const char *de_name
)
12252 const struct got_error
*err
= NULL
;
12253 char *id_str
= NULL
;
12255 if (staged_status
!= GOT_STATUS_ADD
&&
12256 staged_status
!= GOT_STATUS_MODIFY
&&
12257 staged_status
!= GOT_STATUS_DELETE
)
12260 if (staged_status
== GOT_STATUS_ADD
||
12261 staged_status
== GOT_STATUS_MODIFY
)
12262 err
= got_object_id_str(&id_str
, staged_blob_id
);
12264 err
= got_object_id_str(&id_str
, blob_id
);
12268 printf("%s %c %s\n", id_str
, staged_status
, path
);
12273 static const struct got_error
*
12274 cmd_stage(int argc
, char *argv
[])
12276 const struct got_error
*error
= NULL
;
12277 struct got_repository
*repo
= NULL
;
12278 struct got_worktree
*worktree
= NULL
;
12280 struct got_pathlist_head paths
;
12281 struct got_pathlist_entry
*pe
;
12282 int ch
, list_stage
= 0, pflag
= 0, allow_bad_symlinks
= 0;
12283 FILE *patch_script_file
= NULL
;
12284 const char *patch_script_path
= NULL
;
12285 struct choose_patch_arg cpa
;
12286 int *pack_fds
= NULL
;
12288 TAILQ_INIT(&paths
);
12290 while ((ch
= getopt(argc
, argv
, "lpF:S")) != -1) {
12299 patch_script_path
= optarg
;
12302 allow_bad_symlinks
= 1;
12314 if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd "
12315 "unveil", NULL
) == -1)
12318 if (list_stage
&& (pflag
|| patch_script_path
))
12319 errx(1, "-l option cannot be used with other options");
12320 if (patch_script_path
&& !pflag
)
12321 errx(1, "-F option can only be used together with -p option");
12323 cwd
= getcwd(NULL
, 0);
12325 error
= got_error_from_errno("getcwd");
12329 error
= got_repo_pack_fds_open(&pack_fds
);
12333 error
= got_worktree_open(&worktree
, cwd
);
12335 if (error
->code
== GOT_ERR_NOT_WORKTREE
)
12336 error
= wrap_not_worktree_error(error
, "stage", cwd
);
12340 error
= got_repo_open(&repo
, got_worktree_get_repo_path(worktree
),
12345 if (patch_script_path
) {
12346 patch_script_file
= fopen(patch_script_path
, "re");
12347 if (patch_script_file
== NULL
) {
12348 error
= got_error_from_errno2("fopen",
12349 patch_script_path
);
12353 error
= apply_unveil(got_repo_get_path(repo
), 0,
12354 got_worktree_get_root_path(worktree
));
12358 error
= check_merge_in_progress(worktree
, repo
);
12362 error
= get_worktree_paths_from_argv(&paths
, argc
, argv
, worktree
);
12367 error
= got_worktree_status(worktree
, &paths
, repo
, 0,
12368 print_stage
, NULL
, check_cancelled
, NULL
);
12370 cpa
.patch_script_file
= patch_script_file
;
12371 cpa
.action
= "stage";
12372 error
= got_worktree_stage(worktree
, &paths
,
12373 pflag
? NULL
: print_status
, NULL
,
12374 pflag
? choose_patch
: NULL
, &cpa
,
12375 allow_bad_symlinks
, repo
);
12378 if (patch_script_file
&& fclose(patch_script_file
) == EOF
&&
12380 error
= got_error_from_errno2("fclose", patch_script_path
);
12382 const struct got_error
*close_err
= got_repo_close(repo
);
12387 got_worktree_close(worktree
);
12389 const struct got_error
*pack_err
=
12390 got_repo_pack_fds_close(pack_fds
);
12394 TAILQ_FOREACH(pe
, &paths
, entry
)
12395 free((char *)pe
->path
);
12396 got_pathlist_free(&paths
);
12402 usage_unstage(void)
12404 fprintf(stderr
, "usage: %s unstage [-p] [-F response-script] "
12405 "[file-path ...]\n",
12411 static const struct got_error
*
12412 cmd_unstage(int argc
, char *argv
[])
12414 const struct got_error
*error
= NULL
;
12415 struct got_repository
*repo
= NULL
;
12416 struct got_worktree
*worktree
= NULL
;
12418 struct got_pathlist_head paths
;
12419 struct got_pathlist_entry
*pe
;
12421 struct got_update_progress_arg upa
;
12422 FILE *patch_script_file
= NULL
;
12423 const char *patch_script_path
= NULL
;
12424 struct choose_patch_arg cpa
;
12425 int *pack_fds
= NULL
;
12427 TAILQ_INIT(&paths
);
12429 while ((ch
= getopt(argc
, argv
, "pF:")) != -1) {
12435 patch_script_path
= optarg
;
12447 if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd "
12448 "unveil", NULL
) == -1)
12451 if (patch_script_path
&& !pflag
)
12452 errx(1, "-F option can only be used together with -p option");
12454 cwd
= getcwd(NULL
, 0);
12456 error
= got_error_from_errno("getcwd");
12460 error
= got_repo_pack_fds_open(&pack_fds
);
12464 error
= got_worktree_open(&worktree
, cwd
);
12466 if (error
->code
== GOT_ERR_NOT_WORKTREE
)
12467 error
= wrap_not_worktree_error(error
, "unstage", cwd
);
12471 error
= got_repo_open(&repo
, got_worktree_get_repo_path(worktree
),
12476 if (patch_script_path
) {
12477 patch_script_file
= fopen(patch_script_path
, "re");
12478 if (patch_script_file
== NULL
) {
12479 error
= got_error_from_errno2("fopen",
12480 patch_script_path
);
12485 error
= apply_unveil(got_repo_get_path(repo
), 0,
12486 got_worktree_get_root_path(worktree
));
12490 error
= get_worktree_paths_from_argv(&paths
, argc
, argv
, worktree
);
12494 cpa
.patch_script_file
= patch_script_file
;
12495 cpa
.action
= "unstage";
12496 memset(&upa
, 0, sizeof(upa
));
12497 error
= got_worktree_unstage(worktree
, &paths
, update_progress
,
12498 &upa
, pflag
? choose_patch
: NULL
, &cpa
, repo
);
12500 print_merge_progress_stats(&upa
);
12502 if (patch_script_file
&& fclose(patch_script_file
) == EOF
&&
12504 error
= got_error_from_errno2("fclose", patch_script_path
);
12506 const struct got_error
*close_err
= got_repo_close(repo
);
12511 got_worktree_close(worktree
);
12513 const struct got_error
*pack_err
=
12514 got_repo_pack_fds_close(pack_fds
);
12518 TAILQ_FOREACH(pe
, &paths
, entry
)
12519 free((char *)pe
->path
);
12520 got_pathlist_free(&paths
);
12528 fprintf(stderr
, "usage: %s cat [-r repository ] [ -c commit ] [ -P ] "
12529 "arg1 [arg2 ...]\n", getprogname());
12533 static const struct got_error
*
12534 cat_blob(struct got_object_id
*id
, struct got_repository
*repo
, FILE *outfile
)
12536 const struct got_error
*err
;
12537 struct got_blob_object
*blob
;
12540 fd
= got_opentempfd();
12542 return got_error_from_errno("got_opentempfd");
12544 err
= got_object_open_as_blob(&blob
, repo
, id
, 8192, fd
);
12548 err
= got_object_blob_dump_to_file(NULL
, NULL
, NULL
, outfile
, blob
);
12550 if (fd
!= -1 && close(fd
) == -1 && err
== NULL
)
12551 err
= got_error_from_errno("close");
12553 got_object_blob_close(blob
);
12557 static const struct got_error
*
12558 cat_tree(struct got_object_id
*id
, struct got_repository
*repo
, FILE *outfile
)
12560 const struct got_error
*err
;
12561 struct got_tree_object
*tree
;
12564 err
= got_object_open_as_tree(&tree
, repo
, id
);
12568 nentries
= got_object_tree_get_nentries(tree
);
12569 for (i
= 0; i
< nentries
; i
++) {
12570 struct got_tree_entry
*te
;
12572 if (sigint_received
|| sigpipe_received
)
12574 te
= got_object_tree_get_entry(tree
, i
);
12575 err
= got_object_id_str(&id_str
, got_tree_entry_get_id(te
));
12578 fprintf(outfile
, "%s %.7o %s\n", id_str
,
12579 got_tree_entry_get_mode(te
),
12580 got_tree_entry_get_name(te
));
12584 got_object_tree_close(tree
);
12588 static const struct got_error
*
12589 cat_commit(struct got_object_id
*id
, struct got_repository
*repo
, FILE *outfile
)
12591 const struct got_error
*err
;
12592 struct got_commit_object
*commit
;
12593 const struct got_object_id_queue
*parent_ids
;
12594 struct got_object_qid
*pid
;
12595 char *id_str
= NULL
;
12596 const char *logmsg
= NULL
;
12599 err
= got_object_open_as_commit(&commit
, repo
, id
);
12603 err
= got_object_id_str(&id_str
, got_object_commit_get_tree_id(commit
));
12607 fprintf(outfile
, "%s%s\n", GOT_COMMIT_LABEL_TREE
, id_str
);
12608 parent_ids
= got_object_commit_get_parent_ids(commit
);
12609 fprintf(outfile
, "numparents %d\n",
12610 got_object_commit_get_nparents(commit
));
12611 STAILQ_FOREACH(pid
, parent_ids
, entry
) {
12613 err
= got_object_id_str(&pid_str
, &pid
->id
);
12616 fprintf(outfile
, "%s%s\n", GOT_COMMIT_LABEL_PARENT
, pid_str
);
12619 got_date_format_gmtoff(gmtoff
, sizeof(gmtoff
),
12620 got_object_commit_get_author_gmtoff(commit
));
12621 fprintf(outfile
, "%s%s %lld %s\n", GOT_COMMIT_LABEL_AUTHOR
,
12622 got_object_commit_get_author(commit
),
12623 (long long)got_object_commit_get_author_time(commit
),
12626 got_date_format_gmtoff(gmtoff
, sizeof(gmtoff
),
12627 got_object_commit_get_committer_gmtoff(commit
));
12628 fprintf(outfile
, "%s%s %lld %s\n", GOT_COMMIT_LABEL_COMMITTER
,
12629 got_object_commit_get_author(commit
),
12630 (long long)got_object_commit_get_committer_time(commit
),
12633 logmsg
= got_object_commit_get_logmsg_raw(commit
);
12634 fprintf(outfile
, "messagelen %zd\n", strlen(logmsg
));
12635 fprintf(outfile
, "%s", logmsg
);
12638 got_object_commit_close(commit
);
12642 static const struct got_error
*
12643 cat_tag(struct got_object_id
*id
, struct got_repository
*repo
, FILE *outfile
)
12645 const struct got_error
*err
;
12646 struct got_tag_object
*tag
;
12647 char *id_str
= NULL
;
12648 const char *tagmsg
= NULL
;
12651 err
= got_object_open_as_tag(&tag
, repo
, id
);
12655 err
= got_object_id_str(&id_str
, got_object_tag_get_object_id(tag
));
12659 fprintf(outfile
, "%s%s\n", GOT_TAG_LABEL_OBJECT
, id_str
);
12661 switch (got_object_tag_get_object_type(tag
)) {
12662 case GOT_OBJ_TYPE_BLOB
:
12663 fprintf(outfile
, "%s%s\n", GOT_TAG_LABEL_TYPE
,
12664 GOT_OBJ_LABEL_BLOB
);
12666 case GOT_OBJ_TYPE_TREE
:
12667 fprintf(outfile
, "%s%s\n", GOT_TAG_LABEL_TYPE
,
12668 GOT_OBJ_LABEL_TREE
);
12670 case GOT_OBJ_TYPE_COMMIT
:
12671 fprintf(outfile
, "%s%s\n", GOT_TAG_LABEL_TYPE
,
12672 GOT_OBJ_LABEL_COMMIT
);
12674 case GOT_OBJ_TYPE_TAG
:
12675 fprintf(outfile
, "%s%s\n", GOT_TAG_LABEL_TYPE
,
12676 GOT_OBJ_LABEL_TAG
);
12682 fprintf(outfile
, "%s%s\n", GOT_TAG_LABEL_TAG
,
12683 got_object_tag_get_name(tag
));
12685 got_date_format_gmtoff(gmtoff
, sizeof(gmtoff
),
12686 got_object_tag_get_tagger_gmtoff(tag
));
12687 fprintf(outfile
, "%s%s %lld %s\n", GOT_TAG_LABEL_TAGGER
,
12688 got_object_tag_get_tagger(tag
),
12689 (long long)got_object_tag_get_tagger_time(tag
),
12692 tagmsg
= got_object_tag_get_message(tag
);
12693 fprintf(outfile
, "messagelen %zd\n", strlen(tagmsg
));
12694 fprintf(outfile
, "%s", tagmsg
);
12697 got_object_tag_close(tag
);
12701 static const struct got_error
*
12702 cmd_cat(int argc
, char *argv
[])
12704 const struct got_error
*error
;
12705 struct got_repository
*repo
= NULL
;
12706 struct got_worktree
*worktree
= NULL
;
12707 char *cwd
= NULL
, *repo_path
= NULL
, *label
= NULL
;
12708 const char *commit_id_str
= NULL
;
12709 struct got_object_id
*id
= NULL
, *commit_id
= NULL
;
12710 struct got_commit_object
*commit
= NULL
;
12711 int ch
, obj_type
, i
, force_path
= 0;
12712 struct got_reflist_head refs
;
12713 int *pack_fds
= NULL
;
12718 if (pledge("stdio rpath wpath cpath flock proc exec sendfd unveil",
12723 while ((ch
= getopt(argc
, argv
, "c:r:P")) != -1) {
12726 commit_id_str
= optarg
;
12729 repo_path
= realpath(optarg
, NULL
);
12730 if (repo_path
== NULL
)
12731 return got_error_from_errno2("realpath",
12733 got_path_strip_trailing_slashes(repo_path
);
12747 cwd
= getcwd(NULL
, 0);
12749 error
= got_error_from_errno("getcwd");
12753 error
= got_repo_pack_fds_open(&pack_fds
);
12757 if (repo_path
== NULL
) {
12758 error
= got_worktree_open(&worktree
, cwd
);
12759 if (error
&& error
->code
!= GOT_ERR_NOT_WORKTREE
)
12762 repo_path
= strdup(
12763 got_worktree_get_repo_path(worktree
));
12764 if (repo_path
== NULL
) {
12765 error
= got_error_from_errno("strdup");
12769 /* Release work tree lock. */
12770 got_worktree_close(worktree
);
12775 if (repo_path
== NULL
) {
12776 repo_path
= strdup(cwd
);
12777 if (repo_path
== NULL
)
12778 return got_error_from_errno("strdup");
12781 error
= got_repo_open(&repo
, repo_path
, NULL
, pack_fds
);
12786 error
= apply_unveil(got_repo_get_path(repo
), 1, NULL
);
12790 error
= got_ref_list(&refs
, repo
, NULL
, got_ref_cmp_by_name
, NULL
);
12794 if (commit_id_str
== NULL
)
12795 commit_id_str
= GOT_REF_HEAD
;
12796 error
= got_repo_match_object_id(&commit_id
, NULL
,
12797 commit_id_str
, GOT_OBJ_TYPE_COMMIT
, &refs
, repo
);
12801 error
= got_object_open_as_commit(&commit
, repo
, commit_id
);
12805 for (i
= 0; i
< argc
; i
++) {
12807 error
= got_object_id_by_path(&id
, repo
, commit
,
12812 error
= got_repo_match_object_id(&id
, &label
, argv
[i
],
12813 GOT_OBJ_TYPE_ANY
, NULL
/* do not resolve tags */,
12816 if (error
->code
!= GOT_ERR_BAD_OBJ_ID_STR
&&
12817 error
->code
!= GOT_ERR_NOT_REF
)
12819 error
= got_object_id_by_path(&id
, repo
,
12826 error
= got_object_get_type(&obj_type
, repo
, id
);
12830 switch (obj_type
) {
12831 case GOT_OBJ_TYPE_BLOB
:
12832 error
= cat_blob(id
, repo
, stdout
);
12834 case GOT_OBJ_TYPE_TREE
:
12835 error
= cat_tree(id
, repo
, stdout
);
12837 case GOT_OBJ_TYPE_COMMIT
:
12838 error
= cat_commit(id
, repo
, stdout
);
12840 case GOT_OBJ_TYPE_TAG
:
12841 error
= cat_tag(id
, repo
, stdout
);
12844 error
= got_error(GOT_ERR_OBJ_TYPE
);
12859 got_object_commit_close(commit
);
12861 got_worktree_close(worktree
);
12863 const struct got_error
*close_err
= got_repo_close(repo
);
12868 const struct got_error
*pack_err
=
12869 got_repo_pack_fds_close(pack_fds
);
12874 got_ref_list_free(&refs
);
12881 fprintf(stderr
, "usage: %s info [path ...]\n",
12886 static const struct got_error
*
12887 print_path_info(void *arg
, const char *path
, mode_t mode
, time_t mtime
,
12888 struct got_object_id
*blob_id
, struct got_object_id
*staged_blob_id
,
12889 struct got_object_id
*commit_id
)
12891 const struct got_error
*err
= NULL
;
12892 char *id_str
= NULL
;
12894 struct tm mytm
, *tm
;
12895 struct got_pathlist_head
*paths
= arg
;
12896 struct got_pathlist_entry
*pe
;
12899 * Clear error indication from any of the path arguments which
12900 * would cause this file index entry to be displayed.
12902 TAILQ_FOREACH(pe
, paths
, entry
) {
12903 if (got_path_cmp(path
, pe
->path
, strlen(path
),
12904 pe
->path_len
) == 0 ||
12905 got_path_is_child(path
, pe
->path
, pe
->path_len
))
12906 pe
->data
= NULL
; /* no error */
12909 printf(GOT_COMMIT_SEP_STR
);
12911 printf("symlink: %s\n", path
);
12912 else if (S_ISREG(mode
)) {
12913 printf("file: %s\n", path
);
12914 printf("mode: %o\n", mode
& (S_IRWXU
| S_IRWXG
| S_IRWXO
));
12915 } else if (S_ISDIR(mode
))
12916 printf("directory: %s\n", path
);
12918 printf("something: %s\n", path
);
12920 tm
= localtime_r(&mtime
, &mytm
);
12923 if (strftime(datebuf
, sizeof(datebuf
), "%c %Z", tm
) == 0)
12924 return got_error(GOT_ERR_NO_SPACE
);
12925 printf("timestamp: %s\n", datebuf
);
12928 err
= got_object_id_str(&id_str
, blob_id
);
12931 printf("based on blob: %s\n", id_str
);
12935 if (staged_blob_id
) {
12936 err
= got_object_id_str(&id_str
, staged_blob_id
);
12939 printf("based on staged blob: %s\n", id_str
);
12944 err
= got_object_id_str(&id_str
, commit_id
);
12947 printf("based on commit: %s\n", id_str
);
12954 static const struct got_error
*
12955 cmd_info(int argc
, char *argv
[])
12957 const struct got_error
*error
= NULL
;
12958 struct got_worktree
*worktree
= NULL
;
12959 char *cwd
= NULL
, *id_str
= NULL
;
12960 struct got_pathlist_head paths
;
12961 struct got_pathlist_entry
*pe
;
12962 char *uuidstr
= NULL
;
12963 int ch
, show_files
= 0;
12964 int *pack_fds
= NULL
;
12966 TAILQ_INIT(&paths
);
12968 while ((ch
= getopt(argc
, argv
, "")) != -1) {
12980 if (pledge("stdio rpath wpath cpath flock proc exec sendfd unveil",
12984 cwd
= getcwd(NULL
, 0);
12986 error
= got_error_from_errno("getcwd");
12990 error
= got_repo_pack_fds_open(&pack_fds
);
12994 error
= got_worktree_open(&worktree
, cwd
);
12996 if (error
->code
== GOT_ERR_NOT_WORKTREE
)
12997 error
= wrap_not_worktree_error(error
, "info", cwd
);
13002 /* Remove "cpath" promise. */
13003 if (pledge("stdio rpath wpath flock proc exec sendfd unveil",
13007 error
= apply_unveil(NULL
, 0, got_worktree_get_root_path(worktree
));
13012 error
= get_worktree_paths_from_argv(&paths
, argc
, argv
,
13019 error
= got_object_id_str(&id_str
,
13020 got_worktree_get_base_commit_id(worktree
));
13024 error
= got_worktree_get_uuid(&uuidstr
, worktree
);
13028 printf("work tree: %s\n", got_worktree_get_root_path(worktree
));
13029 printf("work tree base commit: %s\n", id_str
);
13030 printf("work tree path prefix: %s\n",
13031 got_worktree_get_path_prefix(worktree
));
13032 printf("work tree branch reference: %s\n",
13033 got_worktree_get_head_ref_name(worktree
));
13034 printf("work tree UUID: %s\n", uuidstr
);
13035 printf("repository: %s\n", got_worktree_get_repo_path(worktree
));
13038 struct got_pathlist_entry
*pe
;
13039 TAILQ_FOREACH(pe
, &paths
, entry
) {
13040 if (pe
->path_len
== 0)
13043 * Assume this path will fail. This will be corrected
13044 * in print_path_info() in case the path does suceeed.
13046 pe
->data
= (void *)got_error_path(pe
->path
,
13049 error
= got_worktree_path_info(worktree
, &paths
,
13050 print_path_info
, &paths
, check_cancelled
, NULL
);
13053 TAILQ_FOREACH(pe
, &paths
, entry
) {
13054 if (pe
->data
!= NULL
) {
13055 error
= pe
->data
; /* bad path */
13062 const struct got_error
*pack_err
=
13063 got_repo_pack_fds_close(pack_fds
);
13067 TAILQ_FOREACH(pe
, &paths
, entry
)
13068 free((char *)pe
->path
);
13069 got_pathlist_free(&paths
);