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 "got_compat.h"
21 #include <sys/queue.h>
23 #include <sys/types.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"
64 #include "got_keyword.h"
67 #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0]))
70 static volatile sig_atomic_t sigint_received
;
71 static volatile sig_atomic_t sigpipe_received
;
74 catch_sigint(int signo
)
80 catch_sigpipe(int signo
)
88 const struct got_error
*(*cmd_main
)(int, char *[]);
89 void (*cmd_usage
)(void);
90 const char *cmd_alias
;
93 __dead
static void usage(int, int);
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_import(int, char *[]);
125 static const struct got_error
* cmd_clone(int, char *[]);
126 static const struct got_error
* cmd_fetch(int, char *[]);
127 static const struct got_error
* cmd_checkout(int, char *[]);
128 static const struct got_error
* cmd_update(int, char *[]);
129 static const struct got_error
* cmd_log(int, char *[]);
130 static const struct got_error
* cmd_diff(int, char *[]);
131 static const struct got_error
* cmd_blame(int, char *[]);
132 static const struct got_error
* cmd_tree(int, char *[]);
133 static const struct got_error
* cmd_status(int, char *[]);
134 static const struct got_error
* cmd_ref(int, char *[]);
135 static const struct got_error
* cmd_branch(int, char *[]);
136 static const struct got_error
* cmd_tag(int, char *[]);
137 static const struct got_error
* cmd_add(int, char *[]);
138 static const struct got_error
* cmd_remove(int, char *[]);
139 static const struct got_error
* cmd_patch(int, char *[]);
140 static const struct got_error
* cmd_revert(int, char *[]);
141 static const struct got_error
* cmd_commit(int, char *[]);
142 static const struct got_error
* cmd_send(int, char *[]);
143 static const struct got_error
* cmd_cherrypick(int, char *[]);
144 static const struct got_error
* cmd_backout(int, char *[]);
145 static const struct got_error
* cmd_rebase(int, char *[]);
146 static const struct got_error
* cmd_histedit(int, char *[]);
147 static const struct got_error
* cmd_integrate(int, char *[]);
148 static const struct got_error
* cmd_merge(int, char *[]);
149 static const struct got_error
* cmd_stage(int, char *[]);
150 static const struct got_error
* cmd_unstage(int, char *[]);
151 static const struct got_error
* cmd_cat(int, char *[]);
152 static const struct got_error
* cmd_info(int, char *[]);
154 static const struct got_cmd got_commands
[] = {
155 { "import", cmd_import
, usage_import
, "im" },
156 { "clone", cmd_clone
, usage_clone
, "cl" },
157 { "fetch", cmd_fetch
, usage_fetch
, "fe" },
158 { "checkout", cmd_checkout
, usage_checkout
, "co" },
159 { "update", cmd_update
, usage_update
, "up" },
160 { "log", cmd_log
, usage_log
, "" },
161 { "diff", cmd_diff
, usage_diff
, "di" },
162 { "blame", cmd_blame
, usage_blame
, "bl" },
163 { "tree", cmd_tree
, usage_tree
, "tr" },
164 { "status", cmd_status
, usage_status
, "st" },
165 { "ref", cmd_ref
, usage_ref
, "" },
166 { "branch", cmd_branch
, usage_branch
, "br" },
167 { "tag", cmd_tag
, usage_tag
, "" },
168 { "add", cmd_add
, usage_add
, "" },
169 { "remove", cmd_remove
, usage_remove
, "rm" },
170 { "patch", cmd_patch
, usage_patch
, "pa" },
171 { "revert", cmd_revert
, usage_revert
, "rv" },
172 { "commit", cmd_commit
, usage_commit
, "ci" },
173 { "send", cmd_send
, usage_send
, "se" },
174 { "cherrypick", cmd_cherrypick
, usage_cherrypick
, "cy" },
175 { "backout", cmd_backout
, usage_backout
, "bo" },
176 { "rebase", cmd_rebase
, usage_rebase
, "rb" },
177 { "histedit", cmd_histedit
, usage_histedit
, "he" },
178 { "integrate", cmd_integrate
, usage_integrate
,"ig" },
179 { "merge", cmd_merge
, usage_merge
, "mg" },
180 { "stage", cmd_stage
, usage_stage
, "sg" },
181 { "unstage", cmd_unstage
, usage_unstage
, "ug" },
182 { "cat", cmd_cat
, usage_cat
, "" },
183 { "info", cmd_info
, usage_info
, "" },
187 list_commands(FILE *fp
)
191 fprintf(fp
, "commands:");
192 for (i
= 0; i
< nitems(got_commands
); i
++) {
193 const struct got_cmd
*cmd
= &got_commands
[i
];
194 fprintf(fp
, " %s", cmd
->cmd_name
);
200 option_conflict(char a
, char b
)
202 errx(1, "-%c and -%c options are mutually exclusive", a
, b
);
206 main(int argc
, char *argv
[])
208 const struct got_cmd
*cmd
;
211 int hflag
= 0, Vflag
= 0;
212 static const struct option longopts
[] = {
213 { "version", no_argument
, NULL
, 'V' },
217 setlocale(LC_CTYPE
, "");
219 while ((ch
= getopt_long(argc
, argv
, "+hV", longopts
, NULL
)) != -1) {
239 got_version_print_str();
244 usage(hflag
, hflag
? 0 : 1);
246 signal(SIGINT
, catch_sigint
);
247 signal(SIGPIPE
, catch_sigpipe
);
249 for (i
= 0; i
< nitems(got_commands
); i
++) {
250 const struct got_error
*error
;
252 cmd
= &got_commands
[i
];
254 if (strcmp(cmd
->cmd_name
, argv
[0]) != 0 &&
255 strcmp(cmd
->cmd_alias
, argv
[0]) != 0)
261 error
= cmd
->cmd_main(argc
, argv
);
262 if (error
&& error
->code
!= GOT_ERR_CANCELLED
&&
263 error
->code
!= GOT_ERR_PRIVSEP_EXIT
&&
264 !(sigpipe_received
&&
265 error
->code
== GOT_ERR_ERRNO
&& errno
== EPIPE
) &&
267 error
->code
== GOT_ERR_ERRNO
&& errno
== EINTR
)) {
269 fprintf(stderr
, "%s: %s\n", getprogname(), error
->msg
);
276 fprintf(stderr
, "%s: unknown command '%s'\n", getprogname(), argv
[0]);
277 list_commands(stderr
);
282 usage(int hflag
, int status
)
284 FILE *fp
= (status
== 0) ? stdout
: stderr
;
286 fprintf(fp
, "usage: %s [-hV] command [arg ...]\n",
293 static const struct got_error
*
294 get_editor(char **abspath
)
296 const struct got_error
*err
= NULL
;
301 editor
= getenv("VISUAL");
303 editor
= getenv("EDITOR");
306 err
= got_path_find_prog(abspath
, editor
);
311 if (*abspath
== NULL
) {
312 *abspath
= strdup("/usr/bin/vi");
313 if (*abspath
== NULL
)
314 return got_error_from_errno("strdup");
320 static const struct got_error
*
321 apply_unveil(const char *repo_path
, int repo_read_only
,
322 const char *worktree_path
)
324 const struct got_error
*err
;
327 if (unveil("gmon.out", "rwc") != 0)
328 return got_error_from_errno2("unveil", "gmon.out");
330 if (repo_path
&& unveil(repo_path
, repo_read_only
? "r" : "rwc") != 0)
331 return got_error_from_errno2("unveil", repo_path
);
333 if (worktree_path
&& unveil(worktree_path
, "rwc") != 0)
334 return got_error_from_errno2("unveil", worktree_path
);
336 if (unveil(GOT_TMPDIR_STR
, "rwc") != 0)
337 return got_error_from_errno2("unveil", GOT_TMPDIR_STR
);
339 err
= got_privsep_unveil_exec_helpers();
343 if (unveil(NULL
, NULL
) != 0)
344 return got_error_from_errno("unveil");
352 fprintf(stderr
, "usage: %s import [-b branch] [-I pattern] [-m message] "
353 "[-r repository-path] directory\n", getprogname());
358 spawn_editor(const char *editor
, const char *file
)
361 sig_t sighup
, sigint
, sigquit
;
364 sighup
= signal(SIGHUP
, SIG_IGN
);
365 sigint
= signal(SIGINT
, SIG_IGN
);
366 sigquit
= signal(SIGQUIT
, SIG_IGN
);
368 switch (pid
= fork()) {
372 execl(editor
, editor
, file
, (char *)NULL
);
376 while (waitpid(pid
, &st
, 0) == -1)
381 (void)signal(SIGHUP
, sighup
);
382 (void)signal(SIGINT
, sigint
);
383 (void)signal(SIGQUIT
, sigquit
);
385 if (!WIFEXITED(st
)) {
390 return WEXITSTATUS(st
);
393 static const struct got_error
*
394 read_logmsg(char **logmsg
, size_t *len
, FILE *fp
, size_t filesize
)
396 const struct got_error
*err
= NULL
;
403 if (fseeko(fp
, 0L, SEEK_SET
) == -1)
404 return got_error_from_errno("fseeko");
406 *logmsg
= malloc(filesize
+ 1);
408 return got_error_from_errno("malloc");
411 while (getline(&line
, &linesize
, fp
) != -1) {
412 if (line
[0] == '#' || (*len
== 0 && line
[0] == '\n'))
413 continue; /* remove comments and leading empty lines */
414 *len
= strlcat(*logmsg
, line
, filesize
+ 1);
415 if (*len
>= filesize
+ 1) {
416 err
= got_error(GOT_ERR_NO_SPACE
);
421 err
= got_ferror(fp
, GOT_ERR_IO
);
425 while (*len
> 0 && (*logmsg
)[*len
- 1] == '\n') {
426 (*logmsg
)[*len
- 1] = '\0';
439 static const struct got_error
*
440 edit_logmsg(char **logmsg
, const char *editor
, const char *logmsg_path
,
441 const char *initial_content
, size_t initial_content_len
,
442 int require_modification
)
444 const struct got_error
*err
= NULL
;
451 if (stat(logmsg_path
, &st
) == -1)
452 return got_error_from_errno2("stat", logmsg_path
);
454 if (spawn_editor(editor
, logmsg_path
) == -1)
455 return got_error_from_errno("failed spawning editor");
457 if (require_modification
) {
458 struct timespec timeout
;
462 nanosleep(&timeout
, NULL
);
465 if (stat(logmsg_path
, &st2
) == -1)
466 return got_error_from_errno2("stat", logmsg_path
);
468 if (require_modification
&& st
.st_size
== st2
.st_size
&&
469 timespeccmp(&st
.st_mtim
, &st2
.st_mtim
, ==))
470 return got_error_msg(GOT_ERR_COMMIT_MSG_EMPTY
,
471 "no changes made to commit message, aborting");
473 fp
= fopen(logmsg_path
, "re");
475 err
= got_error_from_errno("fopen");
479 /* strip comments and leading/trailing newlines */
480 err
= read_logmsg(logmsg
, &logmsg_len
, fp
, st2
.st_size
);
483 if (logmsg_len
== 0) {
484 err
= got_error_msg(GOT_ERR_COMMIT_MSG_EMPTY
,
485 "commit message cannot be empty, aborting");
489 if (fp
&& fclose(fp
) == EOF
&& err
== NULL
)
490 err
= got_error_from_errno("fclose");
498 static const struct got_error
*
499 collect_import_msg(char **logmsg
, char **logmsg_path
, const char *editor
,
500 const char *path_dir
, const char *branch_name
)
502 char *initial_content
= NULL
;
503 const struct got_error
*err
= NULL
;
504 int initial_content_len
;
507 initial_content_len
= asprintf(&initial_content
,
508 "\n# %s to be imported to branch %s\n", path_dir
,
510 if (initial_content_len
== -1)
511 return got_error_from_errno("asprintf");
513 err
= got_opentemp_named_fd(logmsg_path
, &fd
,
514 GOT_TMPDIR_STR
"/got-importmsg", "");
518 if (write(fd
, initial_content
, initial_content_len
) == -1) {
519 err
= got_error_from_errno2("write", *logmsg_path
);
522 if (close(fd
) == -1) {
523 err
= got_error_from_errno2("close", *logmsg_path
);
528 err
= edit_logmsg(logmsg
, editor
, *logmsg_path
, initial_content
,
529 initial_content_len
, 1);
531 if (fd
!= -1 && close(fd
) == -1 && err
== NULL
)
532 err
= got_error_from_errno2("close", *logmsg_path
);
533 free(initial_content
);
541 static const struct got_error
*
542 import_progress(void *arg
, const char *path
)
544 printf("A %s\n", path
);
548 static const struct got_error
*
549 valid_author(const char *author
)
551 const char *email
= author
;
554 * Git' expects the author (or committer) to be in the form
555 * "name <email>", which are mostly free form (see the
556 * "committer" description in git-fast-import(1)). We're only
557 * doing this to avoid git's object parser breaking on commits
561 while (*author
&& *author
!= '\n' && *author
!= '<' && *author
!= '>')
563 if (author
!= email
&& *author
== '<' && *(author
- 1) != ' ')
564 return got_error_fmt(GOT_ERR_COMMIT_BAD_AUTHOR
, "%s: space "
565 "between author name and email required", email
);
566 if (*author
++ != '<')
567 return got_error_fmt(GOT_ERR_COMMIT_NO_EMAIL
, "%s", email
);
568 while (*author
&& *author
!= '\n' && *author
!= '<' && *author
!= '>')
570 if (strcmp(author
, ">") != 0)
571 return got_error_fmt(GOT_ERR_COMMIT_NO_EMAIL
, "%s", email
);
575 static const struct got_error
*
576 get_author(char **author
, struct got_repository
*repo
,
577 struct got_worktree
*worktree
)
579 const struct got_error
*err
= NULL
;
580 const char *got_author
= NULL
, *name
, *email
;
581 const struct got_gotconfig
*worktree_conf
= NULL
, *repo_conf
= NULL
;
586 worktree_conf
= got_worktree_get_gotconfig(worktree
);
587 repo_conf
= got_repo_get_gotconfig(repo
);
590 * Priority of potential author information sources, from most
591 * significant to least significant:
592 * 1) work tree's .got/got.conf file
593 * 2) repository's got.conf file
594 * 3) repository's git config file
595 * 4) environment variables
596 * 5) global git config files (in user's home directory or /etc)
600 got_author
= got_gotconfig_get_author(worktree_conf
);
601 if (got_author
== NULL
)
602 got_author
= got_gotconfig_get_author(repo_conf
);
603 if (got_author
== NULL
) {
604 name
= got_repo_get_gitconfig_author_name(repo
);
605 email
= got_repo_get_gitconfig_author_email(repo
);
607 if (asprintf(author
, "%s <%s>", name
, email
) == -1)
608 return got_error_from_errno("asprintf");
612 got_author
= getenv("GOT_AUTHOR");
613 if (got_author
== NULL
) {
614 name
= got_repo_get_global_gitconfig_author_name(repo
);
615 email
= got_repo_get_global_gitconfig_author_email(
618 if (asprintf(author
, "%s <%s>", name
, email
)
620 return got_error_from_errno("asprintf");
623 /* TODO: Look up user in password database? */
624 return got_error(GOT_ERR_COMMIT_NO_AUTHOR
);
628 *author
= strdup(got_author
);
630 return got_error_from_errno("strdup");
632 err
= valid_author(*author
);
640 static const struct got_error
*
641 get_allowed_signers(char **allowed_signers
, struct got_repository
*repo
,
642 struct got_worktree
*worktree
)
644 const char *got_allowed_signers
= NULL
;
645 const struct got_gotconfig
*worktree_conf
= NULL
, *repo_conf
= NULL
;
647 *allowed_signers
= NULL
;
650 worktree_conf
= got_worktree_get_gotconfig(worktree
);
651 repo_conf
= got_repo_get_gotconfig(repo
);
654 * Priority of potential author information sources, from most
655 * significant to least significant:
656 * 1) work tree's .got/got.conf file
657 * 2) repository's got.conf file
661 got_allowed_signers
= got_gotconfig_get_allowed_signers_file(
663 if (got_allowed_signers
== NULL
)
664 got_allowed_signers
= got_gotconfig_get_allowed_signers_file(
667 if (got_allowed_signers
) {
668 *allowed_signers
= strdup(got_allowed_signers
);
669 if (*allowed_signers
== NULL
)
670 return got_error_from_errno("strdup");
675 static const struct got_error
*
676 get_revoked_signers(char **revoked_signers
, struct got_repository
*repo
,
677 struct got_worktree
*worktree
)
679 const char *got_revoked_signers
= NULL
;
680 const struct got_gotconfig
*worktree_conf
= NULL
, *repo_conf
= NULL
;
682 *revoked_signers
= NULL
;
685 worktree_conf
= got_worktree_get_gotconfig(worktree
);
686 repo_conf
= got_repo_get_gotconfig(repo
);
689 * Priority of potential author information sources, from most
690 * significant to least significant:
691 * 1) work tree's .got/got.conf file
692 * 2) repository's got.conf file
696 got_revoked_signers
= got_gotconfig_get_revoked_signers_file(
698 if (got_revoked_signers
== NULL
)
699 got_revoked_signers
= got_gotconfig_get_revoked_signers_file(
702 if (got_revoked_signers
) {
703 *revoked_signers
= strdup(got_revoked_signers
);
704 if (*revoked_signers
== NULL
)
705 return got_error_from_errno("strdup");
711 get_signer_id(struct got_repository
*repo
, struct got_worktree
*worktree
)
713 const char *got_signer_id
= NULL
;
714 const struct got_gotconfig
*worktree_conf
= NULL
, *repo_conf
= NULL
;
717 worktree_conf
= got_worktree_get_gotconfig(worktree
);
718 repo_conf
= got_repo_get_gotconfig(repo
);
721 * Priority of potential author information sources, from most
722 * significant to least significant:
723 * 1) work tree's .got/got.conf file
724 * 2) repository's got.conf file
728 got_signer_id
= got_gotconfig_get_signer_id(worktree_conf
);
729 if (got_signer_id
== NULL
)
730 got_signer_id
= got_gotconfig_get_signer_id(repo_conf
);
732 return got_signer_id
;
735 static const struct got_error
*
736 get_gitconfig_path(char **gitconfig_path
)
738 const char *homedir
= getenv("HOME");
740 *gitconfig_path
= NULL
;
742 if (asprintf(gitconfig_path
, "%s/.gitconfig", homedir
) == -1)
743 return got_error_from_errno("asprintf");
749 static const struct got_error
*
750 cmd_import(int argc
, char *argv
[])
752 const struct got_error
*error
= NULL
;
753 char *path_dir
= NULL
, *repo_path
= NULL
, *logmsg
= NULL
;
754 char *gitconfig_path
= NULL
, *editor
= NULL
, *author
= NULL
;
755 const char *branch_name
= NULL
;
756 char *id_str
= NULL
, *logmsg_path
= NULL
;
757 char refname
[PATH_MAX
] = "refs/heads/";
758 struct got_repository
*repo
= NULL
;
759 struct got_reference
*branch_ref
= NULL
, *head_ref
= NULL
;
760 struct got_object_id
*new_commit_id
= NULL
;
762 struct got_pathlist_head ignores
;
763 struct got_pathlist_entry
*pe
;
764 int preserve_logmsg
= 0;
765 int *pack_fds
= NULL
;
767 TAILQ_INIT(&ignores
);
770 if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd "
776 while ((ch
= getopt(argc
, argv
, "b:I:m:r:")) != -1) {
779 branch_name
= optarg
;
782 if (optarg
[0] == '\0')
784 error
= got_pathlist_insert(&pe
, &ignores
, optarg
,
790 logmsg
= strdup(optarg
);
791 if (logmsg
== NULL
) {
792 error
= got_error_from_errno("strdup");
797 repo_path
= realpath(optarg
, NULL
);
798 if (repo_path
== NULL
) {
799 error
= got_error_from_errno2("realpath",
816 if (repo_path
== NULL
) {
817 repo_path
= getcwd(NULL
, 0);
818 if (repo_path
== NULL
)
819 return got_error_from_errno("getcwd");
821 got_path_strip_trailing_slashes(repo_path
);
822 error
= get_gitconfig_path(&gitconfig_path
);
825 error
= got_repo_pack_fds_open(&pack_fds
);
828 error
= got_repo_open(&repo
, repo_path
, gitconfig_path
, pack_fds
);
832 error
= get_author(&author
, repo
, NULL
);
837 * Don't let the user create a branch name with a leading '-'.
838 * While technically a valid reference name, this case is usually
839 * an unintended typo.
841 if (branch_name
&& branch_name
[0] == '-')
842 return got_error_path(branch_name
, GOT_ERR_REF_NAME_MINUS
);
844 error
= got_ref_open(&head_ref
, repo
, GOT_REF_HEAD
, 0);
845 if (error
&& error
->code
!= GOT_ERR_NOT_REF
)
849 n
= strlcat(refname
, branch_name
, sizeof(refname
));
850 else if (head_ref
&& got_ref_is_symbolic(head_ref
))
851 n
= strlcpy(refname
, got_ref_get_symref_target(head_ref
),
854 n
= strlcat(refname
, "main", sizeof(refname
));
855 if (n
>= sizeof(refname
)) {
856 error
= got_error(GOT_ERR_NO_SPACE
);
860 error
= got_ref_open(&branch_ref
, repo
, refname
, 0);
862 if (error
->code
!= GOT_ERR_NOT_REF
)
865 error
= got_error_msg(GOT_ERR_BRANCH_EXISTS
,
866 "import target branch already exists");
870 path_dir
= realpath(argv
[0], NULL
);
871 if (path_dir
== NULL
) {
872 error
= got_error_from_errno2("realpath", argv
[0]);
875 got_path_strip_trailing_slashes(path_dir
);
878 * unveil(2) traverses exec(2); if an editor is used we have
879 * to apply unveil after the log message has been written.
881 if (logmsg
== NULL
|| *logmsg
== '\0') {
882 error
= get_editor(&editor
);
886 error
= collect_import_msg(&logmsg
, &logmsg_path
, editor
,
889 if (error
->code
!= GOT_ERR_COMMIT_MSG_EMPTY
&&
896 if (unveil(path_dir
, "r") != 0) {
897 error
= got_error_from_errno2("unveil", path_dir
);
903 error
= apply_unveil(got_repo_get_path(repo
), 0, NULL
);
910 error
= got_repo_import(&new_commit_id
, path_dir
, logmsg
,
911 author
, &ignores
, repo
, import_progress
, NULL
);
918 error
= got_ref_alloc(&branch_ref
, refname
, new_commit_id
);
925 error
= got_ref_write(branch_ref
, repo
);
932 error
= got_object_id_str(&id_str
, new_commit_id
);
939 error
= got_ref_open(&head_ref
, repo
, GOT_REF_HEAD
, 0);
941 if (error
->code
!= GOT_ERR_NOT_REF
) {
947 error
= got_ref_alloc_symref(&head_ref
, GOT_REF_HEAD
,
955 error
= got_ref_write(head_ref
, repo
);
963 printf("Created branch %s with commit %s\n",
964 got_ref_get_name(branch_ref
), id_str
);
967 const struct got_error
*pack_err
=
968 got_repo_pack_fds_close(pack_fds
);
973 const struct got_error
*close_err
= got_repo_close(repo
);
977 if (preserve_logmsg
) {
978 fprintf(stderr
, "%s: log message preserved in %s\n",
979 getprogname(), logmsg_path
);
980 } else if (logmsg_path
&& unlink(logmsg_path
) == -1 && error
== NULL
)
981 error
= got_error_from_errno2("unlink", logmsg_path
);
989 free(gitconfig_path
);
991 got_ref_close(branch_ref
);
993 got_ref_close(head_ref
);
1000 fprintf(stderr
, "usage: %s clone [-almqv] [-b branch] [-R reference] "
1001 "repository-URL [directory]\n", getprogname());
1005 struct got_fetch_progress_arg
{
1006 char last_scaled_size
[FMT_SCALED_STRSIZE
];
1008 int last_p_resolved
;
1011 struct got_repository
*repo
;
1014 int configs_created
;
1016 struct got_pathlist_head
*symrefs
;
1017 struct got_pathlist_head
*wanted_branches
;
1018 struct got_pathlist_head
*wanted_refs
;
1022 const char *remote_repo_path
;
1023 const char *git_url
;
1024 int fetch_all_branches
;
1025 int mirror_references
;
1029 /* XXX forward declaration */
1030 static const struct got_error
*
1031 create_config_files(const char *proto
, const char *host
, const char *port
,
1032 const char *remote_repo_path
, const char *git_url
, int fetch_all_branches
,
1033 int mirror_references
, struct got_pathlist_head
*symrefs
,
1034 struct got_pathlist_head
*wanted_branches
,
1035 struct got_pathlist_head
*wanted_refs
, struct got_repository
*repo
);
1037 static const struct got_error
*
1038 fetch_progress(void *arg
, const char *message
, off_t packfile_size
,
1039 int nobj_total
, int nobj_indexed
, int nobj_loose
, int nobj_resolved
)
1041 const struct got_error
*err
= NULL
;
1042 struct got_fetch_progress_arg
*a
= arg
;
1043 char scaled_size
[FMT_SCALED_STRSIZE
];
1044 int p_indexed
, p_resolved
;
1045 int print_size
= 0, print_indexed
= 0, print_resolved
= 0;
1048 * In order to allow a failed clone to be resumed with 'got fetch'
1049 * we try to create configuration files as soon as possible.
1050 * Once the server has sent information about its default branch
1051 * we have all required information.
1053 if (a
->create_configs
&& !a
->configs_created
&&
1054 !TAILQ_EMPTY(a
->config_info
.symrefs
)) {
1055 err
= create_config_files(a
->config_info
.proto
,
1056 a
->config_info
.host
, a
->config_info
.port
,
1057 a
->config_info
.remote_repo_path
,
1058 a
->config_info
.git_url
,
1059 a
->config_info
.fetch_all_branches
,
1060 a
->config_info
.mirror_references
,
1061 a
->config_info
.symrefs
,
1062 a
->config_info
.wanted_branches
,
1063 a
->config_info
.wanted_refs
, a
->repo
);
1066 a
->configs_created
= 1;
1069 if (a
->verbosity
< 0)
1072 if (message
&& message
[0] != '\0') {
1073 printf("\rserver: %s", message
);
1078 if (packfile_size
> 0 || nobj_indexed
> 0) {
1079 if (fmt_scaled(packfile_size
, scaled_size
) == 0 &&
1080 (a
->last_scaled_size
[0] == '\0' ||
1081 strcmp(scaled_size
, a
->last_scaled_size
)) != 0) {
1083 if (strlcpy(a
->last_scaled_size
, scaled_size
,
1084 FMT_SCALED_STRSIZE
) >= FMT_SCALED_STRSIZE
)
1085 return got_error(GOT_ERR_NO_SPACE
);
1087 if (nobj_indexed
> 0) {
1088 p_indexed
= (nobj_indexed
* 100) / nobj_total
;
1089 if (p_indexed
!= a
->last_p_indexed
) {
1090 a
->last_p_indexed
= p_indexed
;
1095 if (nobj_resolved
> 0) {
1096 p_resolved
= (nobj_resolved
* 100) /
1097 (nobj_total
- nobj_loose
);
1098 if (p_resolved
!= a
->last_p_resolved
) {
1099 a
->last_p_resolved
= p_resolved
;
1107 if (print_size
|| print_indexed
|| print_resolved
)
1110 printf("%*s fetched", FMT_SCALED_STRSIZE
- 2, scaled_size
);
1112 printf("; indexing %d%%", p_indexed
);
1114 printf("; resolving deltas %d%%", p_resolved
);
1115 if (print_size
|| print_indexed
|| print_resolved
)
1121 static const struct got_error
*
1122 create_symref(const char *refname
, struct got_reference
*target_ref
,
1123 int verbosity
, struct got_repository
*repo
)
1125 const struct got_error
*err
;
1126 struct got_reference
*head_symref
;
1128 err
= got_ref_alloc_symref(&head_symref
, refname
, target_ref
);
1132 err
= got_ref_write(head_symref
, repo
);
1133 if (err
== NULL
&& verbosity
> 0) {
1134 printf("Created reference %s: %s\n", GOT_REF_HEAD
,
1135 got_ref_get_name(target_ref
));
1137 got_ref_close(head_symref
);
1141 static const struct got_error
*
1142 list_remote_refs(struct got_pathlist_head
*symrefs
,
1143 struct got_pathlist_head
*refs
)
1145 const struct got_error
*err
;
1146 struct got_pathlist_entry
*pe
;
1148 TAILQ_FOREACH(pe
, symrefs
, entry
) {
1149 const char *refname
= pe
->path
;
1150 const char *targetref
= pe
->data
;
1152 printf("%s: %s\n", refname
, targetref
);
1155 TAILQ_FOREACH(pe
, refs
, entry
) {
1156 const char *refname
= pe
->path
;
1157 struct got_object_id
*id
= pe
->data
;
1160 err
= got_object_id_str(&id_str
, id
);
1163 printf("%s: %s\n", refname
, id_str
);
1170 static const struct got_error
*
1171 create_ref(const char *refname
, struct got_object_id
*id
,
1172 int verbosity
, struct got_repository
*repo
)
1174 const struct got_error
*err
= NULL
;
1175 struct got_reference
*ref
;
1178 err
= got_object_id_str(&id_str
, id
);
1182 err
= got_ref_alloc(&ref
, refname
, id
);
1186 err
= got_ref_write(ref
, repo
);
1189 if (err
== NULL
&& verbosity
>= 0)
1190 printf("Created reference %s: %s\n", refname
, id_str
);
1197 match_wanted_ref(const char *refname
, const char *wanted_ref
)
1199 if (strncmp(refname
, "refs/", 5) != 0)
1204 * Prevent fetching of references that won't make any
1205 * sense outside of the remote repository's context.
1207 if (strncmp(refname
, "got/", 4) == 0)
1209 if (strncmp(refname
, "remotes/", 8) == 0)
1212 if (strncmp(wanted_ref
, "refs/", 5) == 0)
1215 /* Allow prefix match. */
1216 if (got_path_is_child(refname
, wanted_ref
, strlen(wanted_ref
)))
1219 /* Allow exact match. */
1220 return (strcmp(refname
, wanted_ref
) == 0);
1224 is_wanted_ref(struct got_pathlist_head
*wanted_refs
, const char *refname
)
1226 struct got_pathlist_entry
*pe
;
1228 TAILQ_FOREACH(pe
, wanted_refs
, entry
) {
1229 if (match_wanted_ref(refname
, pe
->path
))
1236 static const struct got_error
*
1237 create_wanted_ref(const char *refname
, struct got_object_id
*id
,
1238 const char *remote_repo_name
, int verbosity
, struct got_repository
*repo
)
1240 const struct got_error
*err
;
1241 char *remote_refname
;
1243 if (strncmp("refs/", refname
, 5) == 0)
1246 if (asprintf(&remote_refname
, "refs/remotes/%s/%s",
1247 remote_repo_name
, refname
) == -1)
1248 return got_error_from_errno("asprintf");
1250 err
= create_ref(remote_refname
, id
, verbosity
, repo
);
1251 free(remote_refname
);
1255 static const struct got_error
*
1256 create_gotconfig(const char *proto
, const char *host
, const char *port
,
1257 const char *remote_repo_path
, const char *default_branch
,
1258 int fetch_all_branches
, struct got_pathlist_head
*wanted_branches
,
1259 struct got_pathlist_head
*wanted_refs
, int mirror_references
,
1260 struct got_repository
*repo
)
1262 const struct got_error
*err
= NULL
;
1263 char *gotconfig_path
= NULL
;
1264 char *gotconfig
= NULL
;
1265 FILE *gotconfig_file
= NULL
;
1266 const char *branchname
= NULL
;
1267 char *branches
= NULL
, *refs
= NULL
;
1270 if (!fetch_all_branches
&& !TAILQ_EMPTY(wanted_branches
)) {
1271 struct got_pathlist_entry
*pe
;
1272 TAILQ_FOREACH(pe
, wanted_branches
, entry
) {
1274 branchname
= pe
->path
;
1275 if (strncmp(branchname
, "refs/heads/", 11) == 0)
1277 if (asprintf(&s
, "%s\"%s\" ",
1278 branches
? branches
: "", branchname
) == -1) {
1279 err
= got_error_from_errno("asprintf");
1285 } else if (!fetch_all_branches
&& default_branch
) {
1286 branchname
= default_branch
;
1287 if (strncmp(branchname
, "refs/heads/", 11) == 0)
1289 if (asprintf(&branches
, "\"%s\" ", branchname
) == -1) {
1290 err
= got_error_from_errno("asprintf");
1294 if (!TAILQ_EMPTY(wanted_refs
)) {
1295 struct got_pathlist_entry
*pe
;
1296 TAILQ_FOREACH(pe
, wanted_refs
, entry
) {
1298 const char *refname
= pe
->path
;
1299 if (strncmp(refname
, "refs/", 5) == 0)
1301 if (asprintf(&s
, "%s\"%s\" ",
1302 refs
? refs
: "", refname
) == -1) {
1303 err
= got_error_from_errno("asprintf");
1311 /* Create got.conf(5). */
1312 gotconfig_path
= got_repo_get_path_gotconfig(repo
);
1313 if (gotconfig_path
== NULL
) {
1314 err
= got_error_from_errno("got_repo_get_path_gotconfig");
1317 gotconfig_file
= fopen(gotconfig_path
, "ae");
1318 if (gotconfig_file
== NULL
) {
1319 err
= got_error_from_errno2("fopen", gotconfig_path
);
1322 if (asprintf(&gotconfig
,
1327 "\trepository \"%s\"\n"
1333 GOT_FETCH_DEFAULT_REMOTE_NAME
, host
, proto
,
1334 port
? "\tport " : "", port
? port
: "", port
? "\n" : "",
1335 remote_repo_path
, branches
? "\tbranch { " : "",
1336 branches
? branches
: "", branches
? "}\n" : "",
1337 refs
? "\treference { " : "", refs
? refs
: "", refs
? "}\n" : "",
1338 mirror_references
? "\tmirror_references yes\n" : "",
1339 fetch_all_branches
? "\tfetch_all_branches yes\n" : "") == -1) {
1340 err
= got_error_from_errno("asprintf");
1343 n
= fwrite(gotconfig
, 1, strlen(gotconfig
), gotconfig_file
);
1344 if (n
!= strlen(gotconfig
)) {
1345 err
= got_ferror(gotconfig_file
, GOT_ERR_IO
);
1350 if (gotconfig_file
&& fclose(gotconfig_file
) == EOF
&& err
== NULL
)
1351 err
= got_error_from_errno2("fclose", gotconfig_path
);
1352 free(gotconfig_path
);
1357 static const struct got_error
*
1358 create_gitconfig(const char *git_url
, const char *default_branch
,
1359 int fetch_all_branches
, struct got_pathlist_head
*wanted_branches
,
1360 struct got_pathlist_head
*wanted_refs
, int mirror_references
,
1361 struct got_repository
*repo
)
1363 const struct got_error
*err
= NULL
;
1364 char *gitconfig_path
= NULL
;
1365 char *gitconfig
= NULL
;
1366 FILE *gitconfig_file
= NULL
;
1367 char *branches
= NULL
, *refs
= NULL
;
1368 const char *branchname
;
1371 /* Create a config file Git can understand. */
1372 gitconfig_path
= got_repo_get_path_gitconfig(repo
);
1373 if (gitconfig_path
== NULL
) {
1374 err
= got_error_from_errno("got_repo_get_path_gitconfig");
1377 gitconfig_file
= fopen(gitconfig_path
, "ae");
1378 if (gitconfig_file
== NULL
) {
1379 err
= got_error_from_errno2("fopen", gitconfig_path
);
1382 if (fetch_all_branches
) {
1383 if (mirror_references
) {
1384 if (asprintf(&branches
,
1385 "\tfetch = refs/heads/*:refs/heads/*\n") == -1) {
1386 err
= got_error_from_errno("asprintf");
1389 } else if (asprintf(&branches
,
1390 "\tfetch = refs/heads/*:refs/remotes/%s/*\n",
1391 GOT_FETCH_DEFAULT_REMOTE_NAME
) == -1) {
1392 err
= got_error_from_errno("asprintf");
1395 } else if (!TAILQ_EMPTY(wanted_branches
)) {
1396 struct got_pathlist_entry
*pe
;
1397 TAILQ_FOREACH(pe
, wanted_branches
, entry
) {
1399 branchname
= pe
->path
;
1400 if (strncmp(branchname
, "refs/heads/", 11) == 0)
1402 if (mirror_references
) {
1404 "%s\tfetch = refs/heads/%s:refs/heads/%s\n",
1405 branches
? branches
: "",
1406 branchname
, branchname
) == -1) {
1407 err
= got_error_from_errno("asprintf");
1410 } else if (asprintf(&s
,
1411 "%s\tfetch = refs/heads/%s:refs/remotes/%s/%s\n",
1412 branches
? branches
: "",
1413 branchname
, GOT_FETCH_DEFAULT_REMOTE_NAME
,
1414 branchname
) == -1) {
1415 err
= got_error_from_errno("asprintf");
1423 * If the server specified a default branch, use just that one.
1424 * Otherwise fall back to fetching all branches on next fetch.
1426 if (default_branch
) {
1427 branchname
= default_branch
;
1428 if (strncmp(branchname
, "refs/heads/", 11) == 0)
1431 branchname
= "*"; /* fall back to all branches */
1432 if (mirror_references
) {
1433 if (asprintf(&branches
,
1434 "\tfetch = refs/heads/%s:refs/heads/%s\n",
1435 branchname
, branchname
) == -1) {
1436 err
= got_error_from_errno("asprintf");
1439 } else if (asprintf(&branches
,
1440 "\tfetch = refs/heads/%s:refs/remotes/%s/%s\n",
1441 branchname
, GOT_FETCH_DEFAULT_REMOTE_NAME
,
1442 branchname
) == -1) {
1443 err
= got_error_from_errno("asprintf");
1447 if (!TAILQ_EMPTY(wanted_refs
)) {
1448 struct got_pathlist_entry
*pe
;
1449 TAILQ_FOREACH(pe
, wanted_refs
, entry
) {
1451 const char *refname
= pe
->path
;
1452 if (strncmp(refname
, "refs/", 5) == 0)
1454 if (mirror_references
) {
1456 "%s\tfetch = refs/%s:refs/%s\n",
1457 refs
? refs
: "", refname
, refname
) == -1) {
1458 err
= got_error_from_errno("asprintf");
1461 } else if (asprintf(&s
,
1462 "%s\tfetch = refs/%s:refs/remotes/%s/%s\n",
1464 refname
, GOT_FETCH_DEFAULT_REMOTE_NAME
,
1466 err
= got_error_from_errno("asprintf");
1474 if (asprintf(&gitconfig
,
1479 "\tfetch = refs/tags/*:refs/tags/*\n",
1480 GOT_FETCH_DEFAULT_REMOTE_NAME
, git_url
, branches
? branches
: "",
1481 refs
? refs
: "") == -1) {
1482 err
= got_error_from_errno("asprintf");
1485 n
= fwrite(gitconfig
, 1, strlen(gitconfig
), gitconfig_file
);
1486 if (n
!= strlen(gitconfig
)) {
1487 err
= got_ferror(gitconfig_file
, GOT_ERR_IO
);
1491 if (gitconfig_file
&& fclose(gitconfig_file
) == EOF
&& err
== NULL
)
1492 err
= got_error_from_errno2("fclose", gitconfig_path
);
1493 free(gitconfig_path
);
1498 static const struct got_error
*
1499 create_config_files(const char *proto
, const char *host
, const char *port
,
1500 const char *remote_repo_path
, const char *git_url
, int fetch_all_branches
,
1501 int mirror_references
, struct got_pathlist_head
*symrefs
,
1502 struct got_pathlist_head
*wanted_branches
,
1503 struct got_pathlist_head
*wanted_refs
, struct got_repository
*repo
)
1505 const struct got_error
*err
= NULL
;
1506 const char *default_branch
= NULL
;
1507 struct got_pathlist_entry
*pe
;
1510 * If we asked for a set of wanted branches then use the first
1513 if (!TAILQ_EMPTY(wanted_branches
)) {
1514 pe
= TAILQ_FIRST(wanted_branches
);
1515 default_branch
= pe
->path
;
1517 /* First HEAD ref listed by server is the default branch. */
1518 TAILQ_FOREACH(pe
, symrefs
, entry
) {
1519 const char *refname
= pe
->path
;
1520 const char *target
= pe
->data
;
1522 if (strcmp(refname
, GOT_REF_HEAD
) != 0)
1525 default_branch
= target
;
1530 /* Create got.conf(5). */
1531 err
= create_gotconfig(proto
, host
, port
, remote_repo_path
,
1532 default_branch
, fetch_all_branches
, wanted_branches
,
1533 wanted_refs
, mirror_references
, repo
);
1537 /* Create a config file Git can understand. */
1538 return create_gitconfig(git_url
, default_branch
, fetch_all_branches
,
1539 wanted_branches
, wanted_refs
, mirror_references
, repo
);
1542 static const struct got_error
*
1543 cmd_clone(int argc
, char *argv
[])
1545 const struct got_error
*error
= NULL
;
1546 const char *uri
, *dirname
;
1547 char *proto
, *host
, *port
, *repo_name
, *server_path
;
1548 char *default_destdir
= NULL
, *id_str
= NULL
;
1549 const char *repo_path
;
1550 struct got_repository
*repo
= NULL
;
1551 struct got_pathlist_head refs
, symrefs
, wanted_branches
, wanted_refs
;
1552 struct got_pathlist_entry
*pe
;
1553 struct got_object_id
*pack_hash
= NULL
;
1554 int ch
, fetchfd
= -1, fetchstatus
;
1555 pid_t fetchpid
= -1;
1556 struct got_fetch_progress_arg fpa
;
1557 char *git_url
= NULL
;
1558 int verbosity
= 0, fetch_all_branches
= 0, mirror_references
= 0;
1559 int bflag
= 0, list_refs_only
= 0;
1560 int *pack_fds
= NULL
;
1563 TAILQ_INIT(&symrefs
);
1564 TAILQ_INIT(&wanted_branches
);
1565 TAILQ_INIT(&wanted_refs
);
1567 while ((ch
= getopt(argc
, argv
, "ab:lmqR:v")) != -1) {
1570 fetch_all_branches
= 1;
1573 error
= got_pathlist_append(&wanted_branches
,
1583 mirror_references
= 1;
1589 error
= got_pathlist_append(&wanted_refs
,
1597 else if (verbosity
< 3)
1608 if (fetch_all_branches
&& !TAILQ_EMPTY(&wanted_branches
))
1609 option_conflict('a', 'b');
1610 if (list_refs_only
) {
1611 if (!TAILQ_EMPTY(&wanted_branches
))
1612 option_conflict('l', 'b');
1613 if (fetch_all_branches
)
1614 option_conflict('l', 'a');
1615 if (mirror_references
)
1616 option_conflict('l', 'm');
1617 if (!TAILQ_EMPTY(&wanted_refs
))
1618 option_conflict('l', 'R');
1630 error
= got_dial_parse_uri(&proto
, &host
, &port
, &server_path
,
1635 if (asprintf(&git_url
, "%s://%s%s%s%s%s", proto
,
1636 host
, port
? ":" : "", port
? port
: "",
1637 server_path
[0] != '/' ? "/" : "", server_path
) == -1) {
1638 error
= got_error_from_errno("asprintf");
1642 if (strcmp(proto
, "git") == 0) {
1644 if (pledge("stdio rpath wpath cpath fattr flock proc exec "
1645 "sendfd dns inet unveil", NULL
) == -1)
1648 } else if (strcmp(proto
, "git+ssh") == 0 ||
1649 strcmp(proto
, "ssh") == 0) {
1651 if (pledge("stdio rpath wpath cpath fattr flock proc exec "
1652 "sendfd unveil", NULL
) == -1)
1655 } else if (strcmp(proto
, "http") == 0 ||
1656 strcmp(proto
, "git+http") == 0) {
1657 error
= got_error_path(proto
, GOT_ERR_NOT_IMPL
);
1660 error
= got_error_path(proto
, GOT_ERR_BAD_PROTO
);
1663 if (dirname
== NULL
) {
1664 if (asprintf(&default_destdir
, "%s.git", repo_name
) == -1) {
1665 error
= got_error_from_errno("asprintf");
1668 repo_path
= default_destdir
;
1670 repo_path
= dirname
;
1672 if (!list_refs_only
) {
1673 error
= got_path_mkdir(repo_path
);
1675 (!(error
->code
== GOT_ERR_ERRNO
&& errno
== EISDIR
) &&
1676 !(error
->code
== GOT_ERR_ERRNO
&& errno
== EEXIST
)))
1678 if (!got_path_dir_is_empty(repo_path
)) {
1679 error
= got_error_path(repo_path
,
1680 GOT_ERR_DIR_NOT_EMPTY
);
1685 error
= got_dial_apply_unveil(proto
);
1689 error
= apply_unveil(repo_path
, 0, NULL
);
1694 printf("Connecting to %s\n", git_url
);
1696 error
= got_fetch_connect(&fetchpid
, &fetchfd
, proto
, host
, port
,
1697 server_path
, verbosity
);
1701 if (!list_refs_only
) {
1702 error
= got_repo_init(repo_path
, NULL
);
1705 error
= got_repo_pack_fds_open(&pack_fds
);
1708 error
= got_repo_open(&repo
, repo_path
, NULL
, pack_fds
);
1713 fpa
.last_scaled_size
[0] = '\0';
1714 fpa
.last_p_indexed
= -1;
1715 fpa
.last_p_resolved
= -1;
1716 fpa
.verbosity
= verbosity
;
1717 fpa
.create_configs
= 1;
1718 fpa
.configs_created
= 0;
1720 fpa
.config_info
.symrefs
= &symrefs
;
1721 fpa
.config_info
.wanted_branches
= &wanted_branches
;
1722 fpa
.config_info
.wanted_refs
= &wanted_refs
;
1723 fpa
.config_info
.proto
= proto
;
1724 fpa
.config_info
.host
= host
;
1725 fpa
.config_info
.port
= port
;
1726 fpa
.config_info
.remote_repo_path
= server_path
;
1727 fpa
.config_info
.git_url
= git_url
;
1728 fpa
.config_info
.fetch_all_branches
= fetch_all_branches
;
1729 fpa
.config_info
.mirror_references
= mirror_references
;
1730 error
= got_fetch_pack(&pack_hash
, &refs
, &symrefs
,
1731 GOT_FETCH_DEFAULT_REMOTE_NAME
, mirror_references
,
1732 fetch_all_branches
, &wanted_branches
, &wanted_refs
,
1733 list_refs_only
, verbosity
, fetchfd
, repo
, NULL
, NULL
, bflag
,
1734 fetch_progress
, &fpa
);
1738 if (list_refs_only
) {
1739 error
= list_remote_refs(&symrefs
, &refs
);
1743 if (pack_hash
== NULL
) {
1744 error
= got_error_fmt(GOT_ERR_FETCH_FAILED
, "%s",
1745 "server sent an empty pack file");
1748 error
= got_object_id_str(&id_str
, pack_hash
);
1752 printf("\nFetched %s.pack\n", id_str
);
1755 /* Set up references provided with the pack file. */
1756 TAILQ_FOREACH(pe
, &refs
, entry
) {
1757 const char *refname
= pe
->path
;
1758 struct got_object_id
*id
= pe
->data
;
1759 char *remote_refname
;
1761 if (is_wanted_ref(&wanted_refs
, refname
) &&
1762 !mirror_references
) {
1763 error
= create_wanted_ref(refname
, id
,
1764 GOT_FETCH_DEFAULT_REMOTE_NAME
,
1765 verbosity
- 1, repo
);
1771 error
= create_ref(refname
, id
, verbosity
- 1, repo
);
1775 if (mirror_references
)
1778 if (strncmp("refs/heads/", refname
, 11) != 0)
1781 if (asprintf(&remote_refname
,
1782 "refs/remotes/%s/%s", GOT_FETCH_DEFAULT_REMOTE_NAME
,
1783 refname
+ 11) == -1) {
1784 error
= got_error_from_errno("asprintf");
1787 error
= create_ref(remote_refname
, id
, verbosity
- 1, repo
);
1788 free(remote_refname
);
1793 /* Set the HEAD reference if the server provided one. */
1794 TAILQ_FOREACH(pe
, &symrefs
, entry
) {
1795 struct got_reference
*target_ref
;
1796 const char *refname
= pe
->path
;
1797 const char *target
= pe
->data
;
1798 char *remote_refname
= NULL
, *remote_target
= NULL
;
1800 if (strcmp(refname
, GOT_REF_HEAD
) != 0)
1803 error
= got_ref_open(&target_ref
, repo
, target
, 0);
1805 if (error
->code
== GOT_ERR_NOT_REF
) {
1812 error
= create_symref(refname
, target_ref
, verbosity
, repo
);
1813 got_ref_close(target_ref
);
1817 if (mirror_references
)
1820 if (strncmp("refs/heads/", target
, 11) != 0)
1823 if (asprintf(&remote_refname
,
1824 "refs/remotes/%s/%s", GOT_FETCH_DEFAULT_REMOTE_NAME
,
1826 error
= got_error_from_errno("asprintf");
1829 if (asprintf(&remote_target
,
1830 "refs/remotes/%s/%s", GOT_FETCH_DEFAULT_REMOTE_NAME
,
1831 target
+ 11) == -1) {
1832 error
= got_error_from_errno("asprintf");
1833 free(remote_refname
);
1836 error
= got_ref_open(&target_ref
, repo
, remote_target
, 0);
1838 free(remote_refname
);
1839 free(remote_target
);
1840 if (error
->code
== GOT_ERR_NOT_REF
) {
1846 error
= create_symref(remote_refname
, target_ref
,
1847 verbosity
- 1, repo
);
1848 free(remote_refname
);
1849 free(remote_target
);
1850 got_ref_close(target_ref
);
1856 * We failed to set the HEAD reference. If we asked for
1857 * a set of wanted branches use the first of one of those
1858 * which could be fetched instead.
1860 TAILQ_FOREACH(pe
, &wanted_branches
, entry
) {
1861 const char *target
= pe
->path
;
1862 struct got_reference
*target_ref
;
1864 error
= got_ref_open(&target_ref
, repo
, target
, 0);
1866 if (error
->code
== GOT_ERR_NOT_REF
) {
1873 error
= create_symref(GOT_REF_HEAD
, target_ref
,
1875 got_ref_close(target_ref
);
1881 if (!fpa
.configs_created
&& pe
!= NULL
) {
1882 error
= create_config_files(fpa
.config_info
.proto
,
1883 fpa
.config_info
.host
, fpa
.config_info
.port
,
1884 fpa
.config_info
.remote_repo_path
,
1885 fpa
.config_info
.git_url
,
1886 fpa
.config_info
.fetch_all_branches
,
1887 fpa
.config_info
.mirror_references
,
1888 fpa
.config_info
.symrefs
,
1889 fpa
.config_info
.wanted_branches
,
1890 fpa
.config_info
.wanted_refs
, fpa
.repo
);
1897 printf("Created %s repository '%s'\n",
1898 mirror_references
? "mirrored" : "cloned", repo_path
);
1901 const struct got_error
*pack_err
=
1902 got_repo_pack_fds_close(pack_fds
);
1907 if (kill(fetchpid
, SIGTERM
) == -1)
1908 error
= got_error_from_errno("kill");
1909 if (waitpid(fetchpid
, &fetchstatus
, 0) == -1 && error
== NULL
)
1910 error
= got_error_from_errno("waitpid");
1912 if (fetchfd
!= -1 && close(fetchfd
) == -1 && error
== NULL
)
1913 error
= got_error_from_errno("close");
1915 const struct got_error
*close_err
= got_repo_close(repo
);
1919 got_pathlist_free(&refs
, GOT_PATHLIST_FREE_ALL
);
1920 got_pathlist_free(&symrefs
, GOT_PATHLIST_FREE_ALL
);
1921 got_pathlist_free(&wanted_branches
, GOT_PATHLIST_FREE_NONE
);
1922 got_pathlist_free(&wanted_refs
, GOT_PATHLIST_FREE_NONE
);
1929 free(default_destdir
);
1934 static const struct got_error
*
1935 update_ref(struct got_reference
*ref
, struct got_object_id
*new_id
,
1936 int replace_tags
, int verbosity
, struct got_repository
*repo
)
1938 const struct got_error
*err
= NULL
;
1939 char *new_id_str
= NULL
;
1940 struct got_object_id
*old_id
= NULL
;
1942 err
= got_object_id_str(&new_id_str
, new_id
);
1946 if (!replace_tags
&&
1947 strncmp(got_ref_get_name(ref
), "refs/tags/", 10) == 0) {
1948 err
= got_ref_resolve(&old_id
, repo
, ref
);
1951 if (got_object_id_cmp(old_id
, new_id
) == 0)
1953 if (verbosity
>= 0) {
1954 printf("Rejecting update of existing tag %s: %s\n",
1955 got_ref_get_name(ref
), new_id_str
);
1960 if (got_ref_is_symbolic(ref
)) {
1961 if (verbosity
>= 0) {
1962 printf("Replacing reference %s: %s\n",
1963 got_ref_get_name(ref
),
1964 got_ref_get_symref_target(ref
));
1966 err
= got_ref_change_symref_to_ref(ref
, new_id
);
1969 err
= got_ref_write(ref
, repo
);
1973 err
= got_ref_resolve(&old_id
, repo
, ref
);
1976 if (got_object_id_cmp(old_id
, new_id
) == 0)
1979 err
= got_ref_change_ref(ref
, new_id
);
1982 err
= got_ref_write(ref
, repo
);
1988 printf("Updated %s: %s\n", got_ref_get_name(ref
),
1996 static const struct got_error
*
1997 update_symref(const char *refname
, struct got_reference
*target_ref
,
1998 int verbosity
, struct got_repository
*repo
)
2000 const struct got_error
*err
= NULL
, *unlock_err
;
2001 struct got_reference
*symref
;
2002 int symref_is_locked
= 0;
2004 err
= got_ref_open(&symref
, repo
, refname
, 1);
2006 if (err
->code
!= GOT_ERR_NOT_REF
)
2008 err
= got_ref_alloc_symref(&symref
, refname
, target_ref
);
2012 err
= got_ref_write(symref
, repo
);
2017 printf("Created reference %s: %s\n",
2018 got_ref_get_name(symref
),
2019 got_ref_get_symref_target(symref
));
2021 symref_is_locked
= 1;
2023 if (strcmp(got_ref_get_symref_target(symref
),
2024 got_ref_get_name(target_ref
)) == 0)
2027 err
= got_ref_change_symref(symref
,
2028 got_ref_get_name(target_ref
));
2032 err
= got_ref_write(symref
, repo
);
2037 printf("Updated %s: %s\n", got_ref_get_name(symref
),
2038 got_ref_get_symref_target(symref
));
2042 if (symref_is_locked
) {
2043 unlock_err
= got_ref_unlock(symref
);
2044 if (unlock_err
&& err
== NULL
)
2047 got_ref_close(symref
);
2054 fprintf(stderr
, "usage: %s fetch [-adlqtvX] [-b branch] "
2055 "[-R reference] [-r repository-path] [remote-repository]\n",
2060 static const struct got_error
*
2061 delete_missing_ref(struct got_reference
*ref
,
2062 int verbosity
, struct got_repository
*repo
)
2064 const struct got_error
*err
= NULL
;
2065 struct got_object_id
*id
= NULL
;
2066 char *id_str
= NULL
;
2068 if (got_ref_is_symbolic(ref
)) {
2069 err
= got_ref_delete(ref
, repo
);
2072 if (verbosity
>= 0) {
2073 printf("Deleted %s: %s\n",
2074 got_ref_get_name(ref
),
2075 got_ref_get_symref_target(ref
));
2078 err
= got_ref_resolve(&id
, repo
, ref
);
2081 err
= got_object_id_str(&id_str
, id
);
2085 err
= got_ref_delete(ref
, repo
);
2088 if (verbosity
>= 0) {
2089 printf("Deleted %s: %s\n",
2090 got_ref_get_name(ref
), id_str
);
2099 static const struct got_error
*
2100 delete_missing_refs(struct got_pathlist_head
*their_refs
,
2101 struct got_pathlist_head
*their_symrefs
,
2102 const struct got_remote_repo
*remote
,
2103 int verbosity
, struct got_repository
*repo
)
2105 const struct got_error
*err
= NULL
, *unlock_err
;
2106 struct got_reflist_head my_refs
;
2107 struct got_reflist_entry
*re
;
2108 struct got_pathlist_entry
*pe
;
2109 char *remote_namespace
= NULL
;
2110 char *local_refname
= NULL
;
2112 TAILQ_INIT(&my_refs
);
2114 if (asprintf(&remote_namespace
, "refs/remotes/%s/", remote
->name
)
2116 return got_error_from_errno("asprintf");
2118 err
= got_ref_list(&my_refs
, repo
, NULL
, got_ref_cmp_by_name
, NULL
);
2122 TAILQ_FOREACH(re
, &my_refs
, entry
) {
2123 const char *refname
= got_ref_get_name(re
->ref
);
2124 const char *their_refname
;
2126 if (remote
->mirror_references
) {
2127 their_refname
= refname
;
2129 if (strncmp(refname
, remote_namespace
,
2130 strlen(remote_namespace
)) == 0) {
2131 if (strcmp(refname
+ strlen(remote_namespace
),
2134 if (asprintf(&local_refname
, "refs/heads/%s",
2135 refname
+ strlen(remote_namespace
)) == -1) {
2136 err
= got_error_from_errno("asprintf");
2139 } else if (strncmp(refname
, "refs/tags/", 10) != 0)
2142 their_refname
= local_refname
;
2145 TAILQ_FOREACH(pe
, their_refs
, entry
) {
2146 if (strcmp(their_refname
, pe
->path
) == 0)
2152 TAILQ_FOREACH(pe
, their_symrefs
, entry
) {
2153 if (strcmp(their_refname
, pe
->path
) == 0)
2159 err
= delete_missing_ref(re
->ref
, verbosity
, repo
);
2163 if (local_refname
) {
2164 struct got_reference
*ref
;
2165 err
= got_ref_open(&ref
, repo
, local_refname
, 1);
2167 if (err
->code
!= GOT_ERR_NOT_REF
)
2169 free(local_refname
);
2170 local_refname
= NULL
;
2173 err
= delete_missing_ref(ref
, verbosity
, repo
);
2176 unlock_err
= got_ref_unlock(ref
);
2178 if (unlock_err
&& err
== NULL
) {
2183 free(local_refname
);
2184 local_refname
= NULL
;
2188 got_ref_list_free(&my_refs
);
2189 free(remote_namespace
);
2190 free(local_refname
);
2194 static const struct got_error
*
2195 update_wanted_ref(const char *refname
, struct got_object_id
*id
,
2196 const char *remote_repo_name
, int verbosity
, struct got_repository
*repo
)
2198 const struct got_error
*err
, *unlock_err
;
2199 char *remote_refname
;
2200 struct got_reference
*ref
;
2202 if (strncmp("refs/", refname
, 5) == 0)
2205 if (asprintf(&remote_refname
, "refs/remotes/%s/%s",
2206 remote_repo_name
, refname
) == -1)
2207 return got_error_from_errno("asprintf");
2209 err
= got_ref_open(&ref
, repo
, remote_refname
, 1);
2211 if (err
->code
!= GOT_ERR_NOT_REF
)
2213 err
= create_ref(remote_refname
, id
, verbosity
, repo
);
2215 err
= update_ref(ref
, id
, 0, verbosity
, repo
);
2216 unlock_err
= got_ref_unlock(ref
);
2217 if (unlock_err
&& err
== NULL
)
2222 free(remote_refname
);
2226 static const struct got_error
*
2227 delete_ref(struct got_repository
*repo
, struct got_reference
*ref
)
2229 const struct got_error
*err
= NULL
;
2230 struct got_object_id
*id
= NULL
;
2231 char *id_str
= NULL
;
2234 if (got_ref_is_symbolic(ref
)) {
2235 target
= got_ref_get_symref_target(ref
);
2237 err
= got_ref_resolve(&id
, repo
, ref
);
2240 err
= got_object_id_str(&id_str
, id
);
2246 err
= got_ref_delete(ref
, repo
);
2250 printf("Deleted %s: %s\n", got_ref_get_name(ref
), target
);
2257 static const struct got_error
*
2258 delete_refs_for_remote(struct got_repository
*repo
, const char *remote_name
)
2260 const struct got_error
*err
= NULL
;
2261 struct got_reflist_head refs
;
2262 struct got_reflist_entry
*re
;
2267 if (asprintf(&prefix
, "refs/remotes/%s", remote_name
) == -1) {
2268 err
= got_error_from_errno("asprintf");
2271 err
= got_ref_list(&refs
, repo
, prefix
, got_ref_cmp_by_name
, NULL
);
2275 TAILQ_FOREACH(re
, &refs
, entry
)
2276 delete_ref(repo
, re
->ref
);
2278 got_ref_list_free(&refs
);
2282 static const struct got_error
*
2283 cmd_fetch(int argc
, char *argv
[])
2285 const struct got_error
*error
= NULL
, *unlock_err
;
2286 char *cwd
= NULL
, *repo_path
= NULL
;
2287 const char *remote_name
;
2288 char *proto
= NULL
, *host
= NULL
, *port
= NULL
;
2289 char *repo_name
= NULL
, *server_path
= NULL
;
2290 const struct got_remote_repo
*remotes
;
2291 struct got_remote_repo
*remote
= NULL
;
2293 char *id_str
= NULL
;
2294 struct got_repository
*repo
= NULL
;
2295 struct got_worktree
*worktree
= NULL
;
2296 const struct got_gotconfig
*repo_conf
= NULL
, *worktree_conf
= NULL
;
2297 struct got_pathlist_head refs
, symrefs
, wanted_branches
, wanted_refs
;
2298 char *head_refname
= NULL
;
2299 struct got_pathlist_entry
*pe
;
2300 struct got_reflist_head remote_refs
;
2301 struct got_reflist_entry
*re
;
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
, have_bflag
= 0;
2309 const char *remote_head
= NULL
, *worktree_branch
= NULL
;
2312 TAILQ_INIT(&symrefs
);
2313 TAILQ_INIT(&remote_refs
);
2314 TAILQ_INIT(&wanted_branches
);
2315 TAILQ_INIT(&wanted_refs
);
2317 while ((ch
= getopt(argc
, argv
, "ab:dlqR:r:tvX")) != -1) {
2320 fetch_all_branches
= 1;
2323 error
= got_pathlist_append(&wanted_branches
,
2339 error
= got_pathlist_append(&wanted_refs
,
2345 repo_path
= realpath(optarg
, NULL
);
2346 if (repo_path
== NULL
)
2347 return got_error_from_errno2("realpath",
2349 got_path_strip_trailing_slashes(repo_path
);
2357 else if (verbosity
< 3)
2371 if (fetch_all_branches
&& !TAILQ_EMPTY(&wanted_branches
))
2372 option_conflict('a', 'b');
2373 if (list_refs_only
) {
2374 if (!TAILQ_EMPTY(&wanted_branches
))
2375 option_conflict('l', 'b');
2376 if (fetch_all_branches
)
2377 option_conflict('l', 'a');
2379 option_conflict('l', 'd');
2381 option_conflict('l', 'X');
2383 if (delete_remote
) {
2384 if (fetch_all_branches
)
2385 option_conflict('X', 'a');
2386 if (!TAILQ_EMPTY(&wanted_branches
))
2387 option_conflict('X', 'b');
2389 option_conflict('X', 'd');
2391 option_conflict('X', 't');
2392 if (!TAILQ_EMPTY(&wanted_refs
))
2393 option_conflict('X', 'R');
2398 errx(1, "-X option requires a remote name");
2399 remote_name
= GOT_FETCH_DEFAULT_REMOTE_NAME
;
2400 } else if (argc
== 1)
2401 remote_name
= argv
[0];
2405 cwd
= getcwd(NULL
, 0);
2407 error
= got_error_from_errno("getcwd");
2411 error
= got_repo_pack_fds_open(&pack_fds
);
2415 if (repo_path
== NULL
) {
2416 error
= got_worktree_open(&worktree
, cwd
, GOT_WORKTREE_GOT_DIR
);
2417 if (error
&& error
->code
!= GOT_ERR_NOT_WORKTREE
)
2423 strdup(got_worktree_get_repo_path(worktree
));
2424 if (repo_path
== NULL
)
2425 error
= got_error_from_errno("strdup");
2429 repo_path
= strdup(cwd
);
2430 if (repo_path
== NULL
) {
2431 error
= got_error_from_errno("strdup");
2437 error
= got_repo_open(&repo
, repo_path
, NULL
, pack_fds
);
2441 if (delete_remote
) {
2442 error
= delete_refs_for_remote(repo
, remote_name
);
2443 goto done
; /* nothing else to do */
2447 worktree_conf
= got_worktree_get_gotconfig(worktree
);
2448 if (worktree_conf
) {
2449 got_gotconfig_get_remotes(&nremotes
, &remotes
,
2451 for (i
= 0; i
< nremotes
; i
++) {
2452 if (strcmp(remotes
[i
].name
, remote_name
) == 0) {
2453 error
= got_repo_remote_repo_dup(&remote
,
2462 if (remote
== NULL
) {
2463 repo_conf
= got_repo_get_gotconfig(repo
);
2465 got_gotconfig_get_remotes(&nremotes
, &remotes
,
2467 for (i
= 0; i
< nremotes
; i
++) {
2468 if (strcmp(remotes
[i
].name
, remote_name
) == 0) {
2469 error
= got_repo_remote_repo_dup(&remote
,
2478 if (remote
== NULL
) {
2479 got_repo_get_gitconfig_remotes(&nremotes
, &remotes
, repo
);
2480 for (i
= 0; i
< nremotes
; i
++) {
2481 if (strcmp(remotes
[i
].name
, remote_name
) == 0) {
2482 error
= got_repo_remote_repo_dup(&remote
,
2490 if (remote
== NULL
) {
2491 error
= got_error_path(remote_name
, GOT_ERR_NO_REMOTE
);
2495 if (TAILQ_EMPTY(&wanted_branches
)) {
2496 if (!fetch_all_branches
)
2497 fetch_all_branches
= remote
->fetch_all_branches
;
2498 for (i
= 0; i
< remote
->nfetch_branches
; i
++) {
2499 error
= got_pathlist_append(&wanted_branches
,
2500 remote
->fetch_branches
[i
], NULL
);
2505 if (TAILQ_EMPTY(&wanted_refs
)) {
2506 for (i
= 0; i
< remote
->nfetch_refs
; i
++) {
2507 error
= got_pathlist_append(&wanted_refs
,
2508 remote
->fetch_refs
[i
], NULL
);
2514 error
= got_dial_parse_uri(&proto
, &host
, &port
, &server_path
,
2515 &repo_name
, remote
->fetch_url
);
2519 if (strcmp(proto
, "git") == 0) {
2521 if (pledge("stdio rpath wpath cpath fattr flock proc exec "
2522 "sendfd dns inet unveil", NULL
) == -1)
2525 } else if (strcmp(proto
, "git+ssh") == 0 ||
2526 strcmp(proto
, "ssh") == 0) {
2528 if (pledge("stdio rpath wpath cpath fattr flock proc exec "
2529 "sendfd unveil", NULL
) == -1)
2532 } else if (strcmp(proto
, "http") == 0 ||
2533 strcmp(proto
, "git+http") == 0) {
2534 error
= got_error_path(proto
, GOT_ERR_NOT_IMPL
);
2537 error
= got_error_path(proto
, GOT_ERR_BAD_PROTO
);
2541 error
= got_dial_apply_unveil(proto
);
2545 error
= apply_unveil(got_repo_get_path(repo
), 0, NULL
);
2550 head_refname
= strdup(got_worktree_get_head_ref_name(worktree
));
2551 if (head_refname
== NULL
) {
2552 error
= got_error_from_errno("strdup");
2556 /* Release work tree lock. */
2557 got_worktree_close(worktree
);
2561 if (verbosity
>= 0) {
2562 printf("Connecting to \"%s\" %s://%s%s%s%s%s\n",
2563 remote
->name
, proto
, host
,
2564 port
? ":" : "", port
? port
: "",
2565 *server_path
== '/' ? "" : "/", server_path
);
2568 error
= got_fetch_connect(&fetchpid
, &fetchfd
, proto
, host
, port
,
2569 server_path
, verbosity
);
2575 * If set, get this remote's HEAD ref target so
2576 * if it has changed on the server we can fetch it.
2578 error
= got_ref_list(&remote_refs
, repo
, "refs/remotes",
2579 got_ref_cmp_by_name
, repo
);
2583 TAILQ_FOREACH(re
, &remote_refs
, entry
) {
2584 const char *remote_refname
, *remote_target
;
2585 size_t remote_name_len
;
2587 if (!got_ref_is_symbolic(re
->ref
))
2590 remote_name_len
= strlen(remote
->name
);
2591 remote_refname
= got_ref_get_name(re
->ref
);
2593 /* we only want refs/remotes/$remote->name/HEAD */
2594 if (strncmp(remote_refname
+ 13, remote
->name
,
2595 remote_name_len
) != 0)
2598 if (strcmp(remote_refname
+ remote_name_len
+ 14,
2603 * Take the name itself because we already
2604 * only match with refs/heads/ in fetch_pack().
2606 remote_target
= got_ref_get_symref_target(re
->ref
);
2607 remote_head
= remote_target
+ remote_name_len
+ 14;
2612 strncmp(head_refname
, "refs/heads/", 11) == 0)
2613 worktree_branch
= head_refname
;
2616 fpa
.last_scaled_size
[0] = '\0';
2617 fpa
.last_p_indexed
= -1;
2618 fpa
.last_p_resolved
= -1;
2619 fpa
.verbosity
= verbosity
;
2621 fpa
.create_configs
= 0;
2622 fpa
.configs_created
= 0;
2623 memset(&fpa
.config_info
, 0, sizeof(fpa
.config_info
));
2625 error
= got_fetch_pack(&pack_hash
, &refs
, &symrefs
, remote
->name
,
2626 remote
->mirror_references
, fetch_all_branches
, &wanted_branches
,
2627 &wanted_refs
, list_refs_only
, verbosity
, fetchfd
, repo
,
2628 worktree_branch
, remote_head
, have_bflag
, fetch_progress
, &fpa
);
2632 if (list_refs_only
) {
2633 error
= list_remote_refs(&symrefs
, &refs
);
2637 if (pack_hash
== NULL
) {
2639 printf("Already up-to-date\n");
2640 } else if (verbosity
>= 0) {
2641 error
= got_object_id_str(&id_str
, pack_hash
);
2644 printf("\nFetched %s.pack\n", id_str
);
2649 /* Update references provided with the pack file. */
2650 TAILQ_FOREACH(pe
, &refs
, entry
) {
2651 const char *refname
= pe
->path
;
2652 struct got_object_id
*id
= pe
->data
;
2653 struct got_reference
*ref
;
2654 char *remote_refname
;
2656 if (is_wanted_ref(&wanted_refs
, refname
) &&
2657 !remote
->mirror_references
) {
2658 error
= update_wanted_ref(refname
, id
,
2659 remote
->name
, verbosity
, repo
);
2665 if (remote
->mirror_references
||
2666 strncmp("refs/tags/", refname
, 10) == 0) {
2667 error
= got_ref_open(&ref
, repo
, refname
, 1);
2669 if (error
->code
!= GOT_ERR_NOT_REF
)
2671 error
= create_ref(refname
, id
, verbosity
,
2676 error
= update_ref(ref
, id
, replace_tags
,
2678 unlock_err
= got_ref_unlock(ref
);
2679 if (unlock_err
&& error
== NULL
)
2685 } else if (strncmp("refs/heads/", refname
, 11) == 0) {
2686 if (asprintf(&remote_refname
, "refs/remotes/%s/%s",
2687 remote_name
, refname
+ 11) == -1) {
2688 error
= got_error_from_errno("asprintf");
2692 error
= got_ref_open(&ref
, repo
, remote_refname
, 1);
2694 if (error
->code
!= GOT_ERR_NOT_REF
)
2696 error
= create_ref(remote_refname
, id
,
2701 error
= update_ref(ref
, id
, replace_tags
,
2703 unlock_err
= got_ref_unlock(ref
);
2704 if (unlock_err
&& error
== NULL
)
2711 /* Also create a local branch if none exists yet. */
2712 error
= got_ref_open(&ref
, repo
, refname
, 1);
2714 if (error
->code
!= GOT_ERR_NOT_REF
)
2716 error
= create_ref(refname
, id
, verbosity
,
2721 unlock_err
= got_ref_unlock(ref
);
2722 if (unlock_err
&& error
== NULL
)
2729 error
= delete_missing_refs(&refs
, &symrefs
, remote
,
2735 if (!remote
->mirror_references
) {
2736 /* Update remote HEAD reference if the server provided one. */
2737 TAILQ_FOREACH(pe
, &symrefs
, entry
) {
2738 struct got_reference
*target_ref
;
2739 const char *refname
= pe
->path
;
2740 const char *target
= pe
->data
;
2741 char *remote_refname
= NULL
, *remote_target
= NULL
;
2743 if (strcmp(refname
, GOT_REF_HEAD
) != 0)
2746 if (strncmp("refs/heads/", target
, 11) != 0)
2749 if (asprintf(&remote_refname
, "refs/remotes/%s/%s",
2750 remote
->name
, refname
) == -1) {
2751 error
= got_error_from_errno("asprintf");
2754 if (asprintf(&remote_target
, "refs/remotes/%s/%s",
2755 remote
->name
, target
+ 11) == -1) {
2756 error
= got_error_from_errno("asprintf");
2757 free(remote_refname
);
2761 error
= got_ref_open(&target_ref
, repo
, remote_target
,
2764 free(remote_refname
);
2765 free(remote_target
);
2766 if (error
->code
== GOT_ERR_NOT_REF
) {
2772 error
= update_symref(remote_refname
, target_ref
,
2774 free(remote_refname
);
2775 free(remote_target
);
2776 got_ref_close(target_ref
);
2783 if (kill(fetchpid
, SIGTERM
) == -1)
2784 error
= got_error_from_errno("kill");
2785 if (waitpid(fetchpid
, &fetchstatus
, 0) == -1 && error
== NULL
)
2786 error
= got_error_from_errno("waitpid");
2788 if (fetchfd
!= -1 && close(fetchfd
) == -1 && error
== NULL
)
2789 error
= got_error_from_errno("close");
2791 const struct got_error
*close_err
= got_repo_close(repo
);
2796 got_worktree_close(worktree
);
2798 const struct got_error
*pack_err
=
2799 got_repo_pack_fds_close(pack_fds
);
2803 got_pathlist_free(&refs
, GOT_PATHLIST_FREE_ALL
);
2804 got_pathlist_free(&symrefs
, GOT_PATHLIST_FREE_ALL
);
2805 got_pathlist_free(&wanted_branches
, GOT_PATHLIST_FREE_NONE
);
2806 got_pathlist_free(&wanted_refs
, GOT_PATHLIST_FREE_NONE
);
2807 got_ref_list_free(&remote_refs
);
2808 got_repo_free_remote_repo_data(remote
);
2825 usage_checkout(void)
2827 fprintf(stderr
, "usage: %s checkout [-Eq] [-b branch] [-c commit] "
2828 "[-p path-prefix] repository-path [work-tree-path]\n",
2834 show_worktree_base_ref_warning(void)
2836 fprintf(stderr
, "%s: warning: could not create a reference "
2837 "to the work tree's base commit; the commit could be "
2838 "garbage-collected by Git or 'gotadmin cleanup'; making the "
2839 "repository writable and running 'got update' will prevent this\n",
2843 struct got_checkout_progress_arg
{
2844 const char *worktree_path
;
2845 int had_base_commit_ref_error
;
2849 static const struct got_error
*
2850 checkout_progress(void *arg
, unsigned char status
, const char *path
)
2852 struct got_checkout_progress_arg
*a
= arg
;
2854 /* Base commit bump happens silently. */
2855 if (status
== GOT_STATUS_BUMP_BASE
)
2858 if (status
== GOT_STATUS_BASE_REF_ERR
) {
2859 a
->had_base_commit_ref_error
= 1;
2863 while (path
[0] == '/')
2866 if (a
->verbosity
>= 0)
2867 printf("%c %s/%s\n", status
, a
->worktree_path
, path
);
2872 static const struct got_error
*
2873 check_cancelled(void *arg
)
2875 if (sigint_received
|| sigpipe_received
)
2876 return got_error(GOT_ERR_CANCELLED
);
2880 static const struct got_error
*
2881 check_linear_ancestry(struct got_object_id
*commit_id
,
2882 struct got_object_id
*base_commit_id
, int allow_forwards_in_time_only
,
2883 struct got_repository
*repo
)
2885 const struct got_error
*err
= NULL
;
2886 struct got_object_id
*yca_id
;
2888 err
= got_commit_graph_find_youngest_common_ancestor(&yca_id
,
2889 commit_id
, base_commit_id
, 1, repo
, check_cancelled
, NULL
);
2894 return got_error(GOT_ERR_ANCESTRY
);
2897 * Require a straight line of history between the target commit
2898 * and the work tree's base commit.
2900 * Non-linear situations such as this require a rebase:
2902 * (commit) D F (base_commit)
2910 * 'got update' only handles linear cases:
2911 * Update forwards in time: A (base/yca) - B - C - D (commit)
2912 * Update backwards in time: D (base) - C - B - A (commit/yca)
2914 if (allow_forwards_in_time_only
) {
2915 if (got_object_id_cmp(base_commit_id
, yca_id
) != 0)
2916 return got_error(GOT_ERR_ANCESTRY
);
2917 } else if (got_object_id_cmp(commit_id
, yca_id
) != 0 &&
2918 got_object_id_cmp(base_commit_id
, yca_id
) != 0)
2919 return got_error(GOT_ERR_ANCESTRY
);
2925 static const struct got_error
*
2926 check_same_branch(struct got_object_id
*commit_id
,
2927 struct got_reference
*head_ref
, struct got_repository
*repo
)
2929 const struct got_error
*err
= NULL
;
2930 struct got_commit_graph
*graph
= NULL
;
2931 struct got_object_id
*head_commit_id
= NULL
;
2933 err
= got_ref_resolve(&head_commit_id
, repo
, head_ref
);
2937 if (got_object_id_cmp(head_commit_id
, commit_id
) == 0)
2940 err
= got_commit_graph_open(&graph
, "/", 1);
2944 err
= got_commit_graph_iter_start(graph
, head_commit_id
, repo
,
2945 check_cancelled
, NULL
);
2950 struct got_object_id id
;
2952 err
= got_commit_graph_iter_next(&id
, graph
, repo
,
2953 check_cancelled
, NULL
);
2955 if (err
->code
== GOT_ERR_ITER_COMPLETED
)
2956 err
= got_error(GOT_ERR_ANCESTRY
);
2960 if (got_object_id_cmp(&id
, commit_id
) == 0)
2965 got_commit_graph_close(graph
);
2966 free(head_commit_id
);
2970 static const struct got_error
*
2971 checkout_ancestry_error(struct got_reference
*ref
, const char *commit_id_str
)
2973 static char msg
[512];
2974 const char *branch_name
;
2976 if (got_ref_is_symbolic(ref
))
2977 branch_name
= got_ref_get_symref_target(ref
);
2979 branch_name
= got_ref_get_name(ref
);
2981 if (strncmp("refs/heads/", branch_name
, 11) == 0)
2984 snprintf(msg
, sizeof(msg
),
2985 "target commit is not contained in branch '%s'; "
2986 "the branch to use must be specified with -b; "
2987 "if necessary a new branch can be created for "
2988 "this commit with 'got branch -c %s BRANCH_NAME'",
2989 branch_name
, commit_id_str
);
2991 return got_error_msg(GOT_ERR_ANCESTRY
, msg
);
2994 static const struct got_error
*
2995 cmd_checkout(int argc
, char *argv
[])
2997 const struct got_error
*error
= NULL
;
2998 struct got_repository
*repo
= NULL
;
2999 struct got_reference
*head_ref
= NULL
, *ref
= NULL
;
3000 struct got_worktree
*worktree
= NULL
;
3001 char *repo_path
= NULL
;
3002 char *worktree_path
= NULL
;
3003 const char *path_prefix
= "";
3004 const char *branch_name
= GOT_REF_HEAD
, *refname
= NULL
;
3005 char *commit_id_str
= NULL
, *keyword_idstr
= NULL
;
3006 struct got_object_id
*commit_id
= NULL
;
3008 int ch
, same_path_prefix
, allow_nonempty
= 0, verbosity
= 0;
3009 struct got_pathlist_head paths
;
3010 struct got_checkout_progress_arg cpa
;
3011 int *pack_fds
= NULL
;
3016 if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd "
3017 "unveil", NULL
) == -1)
3021 while ((ch
= getopt(argc
, argv
, "b:c:Ep:q")) != -1) {
3024 branch_name
= optarg
;
3027 commit_id_str
= strdup(optarg
);
3028 if (commit_id_str
== NULL
)
3029 return got_error_from_errno("strdup");
3035 path_prefix
= optarg
;
3050 char *base
, *dotgit
;
3052 repo_path
= realpath(argv
[0], NULL
);
3053 if (repo_path
== NULL
)
3054 return got_error_from_errno2("realpath", argv
[0]);
3055 cwd
= getcwd(NULL
, 0);
3057 error
= got_error_from_errno("getcwd");
3064 error
= got_path_basename(&base
, path
);
3067 dotgit
= strstr(base
, ".git");
3070 if (asprintf(&worktree_path
, "%s/%s", cwd
, base
) == -1) {
3071 error
= got_error_from_errno("asprintf");
3076 } else if (argc
== 2) {
3077 repo_path
= realpath(argv
[0], NULL
);
3078 if (repo_path
== NULL
) {
3079 error
= got_error_from_errno2("realpath", argv
[0]);
3082 worktree_path
= realpath(argv
[1], NULL
);
3083 if (worktree_path
== NULL
) {
3084 if (errno
!= ENOENT
) {
3085 error
= got_error_from_errno2("realpath",
3089 worktree_path
= strdup(argv
[1]);
3090 if (worktree_path
== NULL
) {
3091 error
= got_error_from_errno("strdup");
3098 got_path_strip_trailing_slashes(repo_path
);
3099 got_path_strip_trailing_slashes(worktree_path
);
3101 if (got_path_is_child(worktree_path
, repo_path
, strlen(repo_path
)) ||
3102 got_path_is_child(repo_path
, worktree_path
,
3103 strlen(worktree_path
))) {
3104 error
= got_error_fmt(GOT_ERR_BAD_PATH
,
3105 "work tree and repository paths may not overlap: %s",
3110 error
= got_repo_pack_fds_open(&pack_fds
);
3114 error
= got_repo_open(&repo
, repo_path
, NULL
, pack_fds
);
3118 /* Pre-create work tree path for unveil(2) */
3119 error
= got_path_mkdir(worktree_path
);
3121 if (!(error
->code
== GOT_ERR_ERRNO
&& errno
== EISDIR
) &&
3122 !(error
->code
== GOT_ERR_ERRNO
&& errno
== EEXIST
))
3124 if (!allow_nonempty
&&
3125 !got_path_dir_is_empty(worktree_path
)) {
3126 error
= got_error_path(worktree_path
,
3127 GOT_ERR_DIR_NOT_EMPTY
);
3132 error
= apply_unveil(got_repo_get_path(repo
), 0, worktree_path
);
3136 error
= got_ref_open(&head_ref
, repo
, branch_name
, 0);
3140 error
= got_worktree_init(worktree_path
, head_ref
, path_prefix
,
3141 GOT_WORKTREE_GOT_DIR
, repo
);
3142 if (error
!= NULL
&& !(error
->code
== GOT_ERR_ERRNO
&& errno
== EEXIST
))
3145 error
= got_worktree_open(&worktree
, worktree_path
,
3146 GOT_WORKTREE_GOT_DIR
);
3150 error
= got_worktree_match_path_prefix(&same_path_prefix
, worktree
,
3154 if (!same_path_prefix
) {
3155 error
= got_error(GOT_ERR_PATH_PREFIX
);
3159 if (commit_id_str
) {
3160 struct got_reflist_head refs
;
3162 error
= got_ref_list(&refs
, repo
, NULL
, got_ref_cmp_by_name
,
3167 error
= got_keyword_to_idstr(&keyword_idstr
, commit_id_str
,
3171 if (keyword_idstr
!= NULL
) {
3172 free(commit_id_str
);
3173 commit_id_str
= keyword_idstr
;
3176 error
= got_repo_match_object_id(&commit_id
, NULL
,
3177 commit_id_str
, GOT_OBJ_TYPE_COMMIT
, &refs
, repo
);
3178 got_ref_list_free(&refs
);
3181 error
= check_linear_ancestry(commit_id
,
3182 got_worktree_get_base_commit_id(worktree
), 0, repo
);
3183 if (error
!= NULL
) {
3184 if (error
->code
== GOT_ERR_ANCESTRY
) {
3185 error
= checkout_ancestry_error(
3186 head_ref
, commit_id_str
);
3190 error
= check_same_branch(commit_id
, head_ref
, repo
);
3192 if (error
->code
== GOT_ERR_ANCESTRY
) {
3193 error
= checkout_ancestry_error(
3194 head_ref
, commit_id_str
);
3198 error
= got_worktree_set_base_commit_id(worktree
, repo
,
3202 /* Expand potentially abbreviated commit ID string. */
3203 free(commit_id_str
);
3204 error
= got_object_id_str(&commit_id_str
, commit_id
);
3208 commit_id
= got_object_id_dup(
3209 got_worktree_get_base_commit_id(worktree
));
3210 if (commit_id
== NULL
) {
3211 error
= got_error_from_errno("got_object_id_dup");
3214 error
= got_object_id_str(&commit_id_str
, commit_id
);
3219 error
= got_pathlist_append(&paths
, "", NULL
);
3222 cpa
.worktree_path
= worktree_path
;
3223 cpa
.had_base_commit_ref_error
= 0;
3224 cpa
.verbosity
= verbosity
;
3225 error
= got_worktree_checkout_files(worktree
, &paths
, repo
,
3226 checkout_progress
, &cpa
, check_cancelled
, NULL
);
3230 if (got_ref_is_symbolic(head_ref
)) {
3231 error
= got_ref_resolve_symbolic(&ref
, repo
, head_ref
);
3234 refname
= got_ref_get_name(ref
);
3236 refname
= got_ref_get_name(head_ref
);
3237 printf("Checked out %s: %s\n", refname
, commit_id_str
);
3238 printf("Now shut up and hack\n");
3239 if (cpa
.had_base_commit_ref_error
)
3240 show_worktree_base_ref_warning();
3243 const struct got_error
*pack_err
=
3244 got_repo_pack_fds_close(pack_fds
);
3249 got_ref_close(head_ref
);
3253 const struct got_error
*close_err
= got_repo_close(repo
);
3257 got_pathlist_free(&paths
, GOT_PATHLIST_FREE_NONE
);
3258 free(commit_id_str
);
3261 free(worktree_path
);
3266 struct got_update_progress_arg
{
3278 print_update_progress_stats(struct got_update_progress_arg
*upa
)
3280 if (!upa
->did_something
)
3283 if (upa
->conflicts
> 0)
3284 printf("Files with new merge conflicts: %d\n", upa
->conflicts
);
3285 if (upa
->obstructed
> 0)
3286 printf("File paths obstructed by a non-regular file: %d\n",
3288 if (upa
->not_updated
> 0)
3289 printf("Files not updated because of existing merge "
3290 "conflicts: %d\n", upa
->not_updated
);
3294 * The meaning of some status codes differs between merge-style operations and
3295 * update operations. For example, the ! status code means "file was missing"
3296 * if changes were merged into the work tree, and "missing file was restored"
3297 * if the work tree was updated. This function should be used by any operation
3298 * which merges changes into the work tree without updating the work tree.
3301 print_merge_progress_stats(struct got_update_progress_arg
*upa
)
3303 if (!upa
->did_something
)
3306 if (upa
->conflicts
> 0)
3307 printf("Files with new merge conflicts: %d\n", upa
->conflicts
);
3308 if (upa
->obstructed
> 0)
3309 printf("File paths obstructed by a non-regular file: %d\n",
3311 if (upa
->missing
> 0)
3312 printf("Files which had incoming changes but could not be "
3313 "found in the work tree: %d\n", upa
->missing
);
3314 if (upa
->not_deleted
> 0)
3315 printf("Files not deleted due to differences in deleted "
3316 "content: %d\n", upa
->not_deleted
);
3317 if (upa
->unversioned
> 0)
3318 printf("Files not merged because an unversioned file was "
3319 "found in the work tree: %d\n", upa
->unversioned
);
3325 fprintf(stderr
, "usage: %s update [-q] [-b branch] [-c commit] "
3326 "[path ...]\n", getprogname());
3330 static const struct got_error
*
3331 update_progress(void *arg
, unsigned char status
, const char *path
)
3333 struct got_update_progress_arg
*upa
= arg
;
3335 if (status
== GOT_STATUS_EXISTS
||
3336 status
== GOT_STATUS_BASE_REF_ERR
)
3339 upa
->did_something
= 1;
3341 /* Base commit bump happens silently. */
3342 if (status
== GOT_STATUS_BUMP_BASE
)
3345 if (status
== GOT_STATUS_CONFLICT
)
3347 if (status
== GOT_STATUS_OBSTRUCTED
)
3349 if (status
== GOT_STATUS_CANNOT_UPDATE
)
3351 if (status
== GOT_STATUS_MISSING
)
3353 if (status
== GOT_STATUS_CANNOT_DELETE
)
3355 if (status
== GOT_STATUS_UNVERSIONED
)
3358 while (path
[0] == '/')
3360 if (upa
->verbosity
>= 0)
3361 printf("%c %s\n", status
, path
);
3366 static const struct got_error
*
3367 switch_head_ref(struct got_reference
*head_ref
,
3368 struct got_object_id
*commit_id
, struct got_worktree
*worktree
,
3369 struct got_repository
*repo
)
3371 const struct got_error
*err
= NULL
;
3373 int ref_has_moved
= 0;
3375 /* Trivial case: switching between two different references. */
3376 if (strcmp(got_ref_get_name(head_ref
),
3377 got_worktree_get_head_ref_name(worktree
)) != 0) {
3378 printf("Switching work tree from %s to %s\n",
3379 got_worktree_get_head_ref_name(worktree
),
3380 got_ref_get_name(head_ref
));
3381 return got_worktree_set_head_ref(worktree
, head_ref
);
3384 err
= check_linear_ancestry(commit_id
,
3385 got_worktree_get_base_commit_id(worktree
), 0, repo
);
3387 if (err
->code
!= GOT_ERR_ANCESTRY
)
3394 /* Switching to a rebased branch with the same reference name. */
3395 err
= got_object_id_str(&base_id_str
,
3396 got_worktree_get_base_commit_id(worktree
));
3399 printf("Reference %s now points at a different branch\n",
3400 got_worktree_get_head_ref_name(worktree
));
3401 printf("Switching work tree from %s to %s\n", base_id_str
,
3402 got_worktree_get_head_ref_name(worktree
));
3406 static const struct got_error
*
3407 check_rebase_or_histedit_in_progress(struct got_worktree
*worktree
)
3409 const struct got_error
*err
;
3412 err
= got_worktree_rebase_in_progress(&in_progress
, worktree
);
3416 return got_error(GOT_ERR_REBASING
);
3418 err
= got_worktree_histedit_in_progress(&in_progress
, worktree
);
3422 return got_error(GOT_ERR_HISTEDIT_BUSY
);
3427 static const struct got_error
*
3428 check_merge_in_progress(struct got_worktree
*worktree
,
3429 struct got_repository
*repo
)
3431 const struct got_error
*err
;
3434 err
= got_worktree_merge_in_progress(&in_progress
, worktree
, repo
);
3438 return got_error(GOT_ERR_MERGE_BUSY
);
3443 static const struct got_error
*
3444 get_worktree_paths_from_argv(struct got_pathlist_head
*paths
, int argc
,
3445 char *argv
[], struct got_worktree
*worktree
)
3447 const struct got_error
*err
= NULL
;
3449 struct got_pathlist_entry
*new;
3455 return got_error_from_errno("strdup");
3456 return got_pathlist_append(paths
, path
, NULL
);
3459 for (i
= 0; i
< argc
; i
++) {
3460 err
= got_worktree_resolve_path(&path
, worktree
, argv
[i
]);
3463 err
= got_pathlist_insert(&new, paths
, path
, NULL
);
3464 if (err
|| new == NULL
/* duplicate */) {
3474 static const struct got_error
*
3475 wrap_not_worktree_error(const struct got_error
*orig_err
,
3476 const char *cmdname
, const char *path
)
3478 const struct got_error
*err
;
3479 struct got_repository
*repo
;
3480 static char msg
[512];
3481 int *pack_fds
= NULL
;
3483 err
= got_repo_pack_fds_open(&pack_fds
);
3487 err
= got_repo_open(&repo
, path
, NULL
, pack_fds
);
3491 snprintf(msg
, sizeof(msg
),
3492 "'got %s' needs a work tree in addition to a git repository\n"
3493 "Work trees can be checked out from this Git repository with "
3495 "The got(1) manual page contains more information.", cmdname
);
3496 err
= got_error_msg(GOT_ERR_NOT_WORKTREE
, msg
);
3498 const struct got_error
*close_err
= got_repo_close(repo
);
3503 const struct got_error
*pack_err
=
3504 got_repo_pack_fds_close(pack_fds
);
3511 static const struct got_error
*
3512 cmd_update(int argc
, char *argv
[])
3514 const struct got_error
*error
= NULL
;
3515 struct got_repository
*repo
= NULL
;
3516 struct got_worktree
*worktree
= NULL
;
3517 char *worktree_path
= NULL
;
3518 struct got_object_id
*commit_id
= NULL
;
3519 char *commit_id_str
= NULL
;
3520 const char *branch_name
= NULL
;
3521 struct got_reference
*head_ref
= NULL
;
3522 struct got_pathlist_head paths
;
3523 struct got_pathlist_entry
*pe
;
3524 int ch
, verbosity
= 0;
3525 struct got_update_progress_arg upa
;
3526 int *pack_fds
= NULL
;
3531 if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd "
3532 "unveil", NULL
) == -1)
3536 while ((ch
= getopt(argc
, argv
, "b:c:q")) != -1) {
3539 branch_name
= optarg
;
3542 commit_id_str
= strdup(optarg
);
3543 if (commit_id_str
== NULL
)
3544 return got_error_from_errno("strdup");
3558 worktree_path
= getcwd(NULL
, 0);
3559 if (worktree_path
== NULL
) {
3560 error
= got_error_from_errno("getcwd");
3564 error
= got_repo_pack_fds_open(&pack_fds
);
3568 error
= got_worktree_open(&worktree
, worktree_path
,
3569 GOT_WORKTREE_GOT_DIR
);
3571 if (error
->code
== GOT_ERR_NOT_WORKTREE
)
3572 error
= wrap_not_worktree_error(error
, "update",
3577 error
= check_rebase_or_histedit_in_progress(worktree
);
3581 error
= got_repo_open(&repo
, got_worktree_get_repo_path(worktree
),
3586 error
= apply_unveil(got_repo_get_path(repo
), 0,
3587 got_worktree_get_root_path(worktree
));
3591 error
= check_merge_in_progress(worktree
, repo
);
3595 error
= get_worktree_paths_from_argv(&paths
, argc
, argv
, worktree
);
3599 error
= got_ref_open(&head_ref
, repo
, branch_name
? branch_name
:
3600 got_worktree_get_head_ref_name(worktree
), 0);
3603 if (commit_id_str
== NULL
) {
3604 error
= got_ref_resolve(&commit_id
, repo
, head_ref
);
3607 error
= got_object_id_str(&commit_id_str
, commit_id
);
3611 struct got_reflist_head refs
;
3612 char *keyword_idstr
= NULL
;
3616 error
= got_ref_list(&refs
, repo
, NULL
, got_ref_cmp_by_name
,
3621 error
= got_keyword_to_idstr(&keyword_idstr
, commit_id_str
,
3625 if (keyword_idstr
!= NULL
) {
3626 free(commit_id_str
);
3627 commit_id_str
= keyword_idstr
;
3630 error
= got_repo_match_object_id(&commit_id
, NULL
,
3631 commit_id_str
, GOT_OBJ_TYPE_COMMIT
, &refs
, repo
);
3632 got_ref_list_free(&refs
);
3633 free(commit_id_str
);
3634 commit_id_str
= NULL
;
3637 error
= got_object_id_str(&commit_id_str
, commit_id
);
3643 struct got_object_id
*head_commit_id
;
3644 TAILQ_FOREACH(pe
, &paths
, entry
) {
3645 if (pe
->path_len
== 0)
3647 error
= got_error_msg(GOT_ERR_BAD_PATH
,
3648 "switching between branches requires that "
3649 "the entire work tree gets updated");
3652 error
= got_ref_resolve(&head_commit_id
, repo
, head_ref
);
3655 error
= check_linear_ancestry(commit_id
, head_commit_id
, 0,
3657 free(head_commit_id
);
3660 error
= check_same_branch(commit_id
, head_ref
, repo
);
3663 error
= switch_head_ref(head_ref
, commit_id
, worktree
, repo
);
3667 error
= check_linear_ancestry(commit_id
,
3668 got_worktree_get_base_commit_id(worktree
), 0, repo
);
3669 if (error
!= NULL
) {
3670 if (error
->code
== GOT_ERR_ANCESTRY
)
3671 error
= got_error(GOT_ERR_BRANCH_MOVED
);
3674 error
= check_same_branch(commit_id
, head_ref
, repo
);
3679 if (got_object_id_cmp(got_worktree_get_base_commit_id(worktree
),
3681 error
= got_worktree_set_base_commit_id(worktree
, repo
,
3687 memset(&upa
, 0, sizeof(upa
));
3688 upa
.verbosity
= verbosity
;
3689 error
= got_worktree_checkout_files(worktree
, &paths
, repo
,
3690 update_progress
, &upa
, check_cancelled
, NULL
);
3694 if (upa
.did_something
) {
3695 printf("Updated to %s: %s\n",
3696 got_worktree_get_head_ref_name(worktree
), commit_id_str
);
3698 printf("Already up-to-date\n");
3700 print_update_progress_stats(&upa
);
3703 const struct got_error
*pack_err
=
3704 got_repo_pack_fds_close(pack_fds
);
3709 const struct got_error
*close_err
= got_repo_close(repo
);
3713 if (head_ref
!= NULL
)
3714 got_ref_close(head_ref
);
3715 free(worktree_path
);
3716 got_pathlist_free(&paths
, GOT_PATHLIST_FREE_PATH
);
3718 free(commit_id_str
);
3722 static const struct got_error
*
3723 diff_blobs(struct got_object_id
*blob_id1
, struct got_object_id
*blob_id2
,
3724 const char *path
, int diff_context
, int ignore_whitespace
,
3725 int force_text_diff
, struct got_diffstat_cb_arg
*dsa
,
3726 struct got_repository
*repo
, FILE *outfile
)
3728 const struct got_error
*err
= NULL
;
3729 struct got_blob_object
*blob1
= NULL
, *blob2
= NULL
;
3730 FILE *f1
= NULL
, *f2
= NULL
;
3731 int fd1
= -1, fd2
= -1;
3733 fd1
= got_opentempfd();
3735 return got_error_from_errno("got_opentempfd");
3736 fd2
= got_opentempfd();
3738 err
= got_error_from_errno("got_opentempfd");
3743 err
= got_object_open_as_blob(&blob1
, repo
, blob_id1
, 8192,
3749 err
= got_object_open_as_blob(&blob2
, repo
, blob_id2
, 8192, fd2
);
3753 f1
= got_opentemp();
3755 err
= got_error_from_errno("got_opentemp");
3758 f2
= got_opentemp();
3760 err
= got_error_from_errno("got_opentemp");
3764 while (path
[0] == '/')
3766 err
= got_diff_blob(NULL
, NULL
, blob1
, blob2
, f1
, f2
, path
, path
,
3767 GOT_DIFF_ALGORITHM_PATIENCE
, diff_context
, ignore_whitespace
,
3768 force_text_diff
, dsa
, outfile
);
3770 if (fd1
!= -1 && close(fd1
) == -1 && err
== NULL
)
3771 err
= got_error_from_errno("close");
3773 got_object_blob_close(blob1
);
3774 if (fd2
!= -1 && close(fd2
) == -1 && err
== NULL
)
3775 err
= got_error_from_errno("close");
3777 got_object_blob_close(blob2
);
3778 if (f1
&& fclose(f1
) == EOF
&& err
== NULL
)
3779 err
= got_error_from_errno("fclose");
3780 if (f2
&& fclose(f2
) == EOF
&& err
== NULL
)
3781 err
= got_error_from_errno("fclose");
3785 static const struct got_error
*
3786 diff_trees(struct got_object_id
*tree_id1
, struct got_object_id
*tree_id2
,
3787 const char *path
, int diff_context
, int ignore_whitespace
,
3788 int force_text_diff
, struct got_diffstat_cb_arg
*dsa
,
3789 struct got_repository
*repo
, FILE *outfile
)
3791 const struct got_error
*err
= NULL
;
3792 struct got_tree_object
*tree1
= NULL
, *tree2
= NULL
;
3793 struct got_diff_blob_output_unidiff_arg arg
;
3794 FILE *f1
= NULL
, *f2
= NULL
;
3795 int fd1
= -1, fd2
= -1;
3798 err
= got_object_open_as_tree(&tree1
, repo
, tree_id1
);
3801 fd1
= got_opentempfd();
3803 err
= got_error_from_errno("got_opentempfd");
3808 err
= got_object_open_as_tree(&tree2
, repo
, tree_id2
);
3812 f1
= got_opentemp();
3814 err
= got_error_from_errno("got_opentemp");
3818 f2
= got_opentemp();
3820 err
= got_error_from_errno("got_opentemp");
3823 fd2
= got_opentempfd();
3825 err
= got_error_from_errno("got_opentempfd");
3828 arg
.diff_context
= diff_context
;
3829 arg
.ignore_whitespace
= ignore_whitespace
;
3830 arg
.force_text_diff
= force_text_diff
;
3832 arg
.diff_algo
= GOT_DIFF_ALGORITHM_PATIENCE
;
3833 arg
.outfile
= outfile
;
3836 while (path
[0] == '/')
3838 err
= got_diff_tree(tree1
, tree2
, f1
, f2
, fd1
, fd2
, path
, path
, repo
,
3839 got_diff_blob_output_unidiff
, &arg
, 1);
3842 got_object_tree_close(tree1
);
3844 got_object_tree_close(tree2
);
3845 if (f1
&& fclose(f1
) == EOF
&& err
== NULL
)
3846 err
= got_error_from_errno("fclose");
3847 if (f2
&& fclose(f2
) == EOF
&& err
== NULL
)
3848 err
= got_error_from_errno("fclose");
3849 if (fd1
!= -1 && close(fd1
) == -1 && err
== NULL
)
3850 err
= got_error_from_errno("close");
3851 if (fd2
!= -1 && close(fd2
) == -1 && err
== NULL
)
3852 err
= got_error_from_errno("close");
3856 static const struct got_error
*
3857 get_changed_paths(struct got_pathlist_head
*paths
,
3858 struct got_commit_object
*commit
, struct got_repository
*repo
,
3859 struct got_diffstat_cb_arg
*dsa
)
3861 const struct got_error
*err
= NULL
;
3862 struct got_object_id
*tree_id1
= NULL
, *tree_id2
= NULL
;
3863 struct got_tree_object
*tree1
= NULL
, *tree2
= NULL
;
3864 struct got_object_qid
*qid
;
3865 got_diff_blob_cb cb
= got_diff_tree_collect_changed_paths
;
3866 FILE *f1
= NULL
, *f2
= NULL
;
3867 int fd1
= -1, fd2
= -1;
3870 cb
= got_diff_tree_compute_diffstat
;
3872 f1
= got_opentemp();
3874 err
= got_error_from_errno("got_opentemp");
3877 f2
= got_opentemp();
3879 err
= got_error_from_errno("got_opentemp");
3882 fd1
= got_opentempfd();
3884 err
= got_error_from_errno("got_opentempfd");
3887 fd2
= got_opentempfd();
3889 err
= got_error_from_errno("got_opentempfd");
3894 qid
= STAILQ_FIRST(got_object_commit_get_parent_ids(commit
));
3896 struct got_commit_object
*pcommit
;
3897 err
= got_object_open_as_commit(&pcommit
, repo
,
3902 tree_id1
= got_object_id_dup(
3903 got_object_commit_get_tree_id(pcommit
));
3904 if (tree_id1
== NULL
) {
3905 got_object_commit_close(pcommit
);
3906 return got_error_from_errno("got_object_id_dup");
3908 got_object_commit_close(pcommit
);
3913 err
= got_object_open_as_tree(&tree1
, repo
, tree_id1
);
3918 tree_id2
= got_object_commit_get_tree_id(commit
);
3919 err
= got_object_open_as_tree(&tree2
, repo
, tree_id2
);
3923 err
= got_diff_tree(tree1
, tree2
, f1
, f2
, fd1
, fd2
, "", "", repo
,
3924 cb
, dsa
? (void *)dsa
: paths
, dsa
? 1 : 0);
3927 got_object_tree_close(tree1
);
3929 got_object_tree_close(tree2
);
3930 if (fd1
!= -1 && close(fd1
) == -1 && err
== NULL
)
3931 err
= got_error_from_errno("close");
3932 if (fd2
!= -1 && close(fd2
) == -1 && err
== NULL
)
3933 err
= got_error_from_errno("close");
3934 if (f1
&& fclose(f1
) == EOF
&& err
== NULL
)
3935 err
= got_error_from_errno("fclose");
3936 if (f2
&& fclose(f2
) == EOF
&& err
== NULL
)
3937 err
= got_error_from_errno("fclose");
3942 static const struct got_error
*
3943 print_patch(struct got_commit_object
*commit
, struct got_object_id
*id
,
3944 const char *path
, int diff_context
, struct got_diffstat_cb_arg
*dsa
,
3945 struct got_repository
*repo
, FILE *outfile
)
3947 const struct got_error
*err
= NULL
;
3948 struct got_commit_object
*pcommit
= NULL
;
3949 char *id_str1
= NULL
, *id_str2
= NULL
;
3950 struct got_object_id
*obj_id1
= NULL
, *obj_id2
= NULL
;
3951 struct got_object_qid
*qid
;
3953 qid
= STAILQ_FIRST(got_object_commit_get_parent_ids(commit
));
3955 err
= got_object_open_as_commit(&pcommit
, repo
,
3959 err
= got_object_id_str(&id_str1
, &qid
->id
);
3964 err
= got_object_id_str(&id_str2
, id
);
3968 if (path
&& path
[0] != '\0') {
3970 err
= got_object_id_by_path(&obj_id2
, repo
, commit
, path
);
3974 err
= got_object_id_by_path(&obj_id1
, repo
,
3977 if (err
->code
!= GOT_ERR_NO_TREE_ENTRY
) {
3983 err
= got_object_get_type(&obj_type
, repo
, obj_id2
);
3989 "diff %s %s\n", id_str1
? id_str1
: "/dev/null", id_str2
);
3990 fprintf(outfile
, "commit - %s\n",
3991 id_str1
? id_str1
: "/dev/null");
3992 fprintf(outfile
, "commit + %s\n", id_str2
);
3994 case GOT_OBJ_TYPE_BLOB
:
3995 err
= diff_blobs(obj_id1
, obj_id2
, path
, diff_context
,
3996 0, 0, dsa
, repo
, outfile
);
3998 case GOT_OBJ_TYPE_TREE
:
3999 err
= diff_trees(obj_id1
, obj_id2
, path
, diff_context
,
4000 0, 0, dsa
, repo
, outfile
);
4003 err
= got_error(GOT_ERR_OBJ_TYPE
);
4009 obj_id2
= got_object_commit_get_tree_id(commit
);
4011 obj_id1
= got_object_commit_get_tree_id(pcommit
);
4013 "diff %s %s\n", id_str1
? id_str1
: "/dev/null", id_str2
);
4014 fprintf(outfile
, "commit - %s\n",
4015 id_str1
? id_str1
: "/dev/null");
4016 fprintf(outfile
, "commit + %s\n", id_str2
);
4017 err
= diff_trees(obj_id1
, obj_id2
, "", diff_context
, 0, 0,
4018 dsa
, repo
, outfile
);
4024 got_object_commit_close(pcommit
);
4029 get_datestr(time_t *time
, char *datebuf
)
4031 struct tm mytm
, *tm
;
4034 tm
= gmtime_r(time
, &mytm
);
4037 s
= asctime_r(tm
, datebuf
);
4040 p
= strchr(s
, '\n');
4046 static const struct got_error
*
4047 match_commit(int *have_match
, struct got_object_id
*id
,
4048 struct got_commit_object
*commit
, regex_t
*regex
)
4050 const struct got_error
*err
= NULL
;
4051 regmatch_t regmatch
;
4052 char *id_str
= NULL
, *logmsg
= NULL
;
4056 err
= got_object_id_str(&id_str
, id
);
4060 err
= got_object_commit_get_logmsg(&logmsg
, commit
);
4064 if (regexec(regex
, got_object_commit_get_author(commit
), 1,
4065 ®match
, 0) == 0 ||
4066 regexec(regex
, got_object_commit_get_committer(commit
), 1,
4067 ®match
, 0) == 0 ||
4068 regexec(regex
, id_str
, 1, ®match
, 0) == 0 ||
4069 regexec(regex
, logmsg
, 1, ®match
, 0) == 0)
4078 match_changed_paths(int *have_match
, struct got_pathlist_head
*changed_paths
,
4081 regmatch_t regmatch
;
4082 struct got_pathlist_entry
*pe
;
4086 TAILQ_FOREACH(pe
, changed_paths
, entry
) {
4087 if (regexec(regex
, pe
->path
, 1, ®match
, 0) == 0) {
4094 static const struct got_error
*
4095 match_patch(int *have_match
, struct got_commit_object
*commit
,
4096 struct got_object_id
*id
, const char *path
, int diff_context
,
4097 struct got_repository
*repo
, regex_t
*regex
, FILE *f
)
4099 const struct got_error
*err
= NULL
;
4101 size_t linesize
= 0;
4102 regmatch_t regmatch
;
4106 err
= got_opentemp_truncate(f
);
4110 err
= print_patch(commit
, id
, path
, diff_context
, NULL
, repo
, f
);
4114 if (fseeko(f
, 0L, SEEK_SET
) == -1) {
4115 err
= got_error_from_errno("fseeko");
4119 while (getline(&line
, &linesize
, f
) != -1) {
4120 if (regexec(regex
, line
, 1, ®match
, 0) == 0) {
4130 #define GOT_COMMIT_SEP_STR "-----------------------------------------------\n"
4132 static const struct got_error
*
4133 build_refs_str(char **refs_str
, struct got_reflist_head
*refs
,
4134 struct got_object_id
*id
, struct got_repository
*repo
,
4137 static const struct got_error
*err
= NULL
;
4138 struct got_reflist_entry
*re
;
4144 TAILQ_FOREACH(re
, refs
, entry
) {
4145 struct got_tag_object
*tag
= NULL
;
4146 struct got_object_id
*ref_id
;
4149 name
= got_ref_get_name(re
->ref
);
4150 if (strcmp(name
, GOT_REF_HEAD
) == 0)
4152 if (strncmp(name
, "refs/", 5) == 0)
4154 if (strncmp(name
, "got/", 4) == 0)
4156 if (strncmp(name
, "heads/", 6) == 0)
4158 if (strncmp(name
, "remotes/", 8) == 0) {
4162 s
= strstr(name
, "/" GOT_REF_HEAD
);
4163 if (s
!= NULL
&& strcmp(s
, "/" GOT_REF_HEAD
) == 0)
4166 err
= got_ref_resolve(&ref_id
, repo
, re
->ref
);
4169 if (strncmp(name
, "tags/", 5) == 0) {
4170 err
= got_object_open_as_tag(&tag
, repo
, ref_id
);
4172 if (err
->code
!= GOT_ERR_OBJ_TYPE
) {
4176 /* Ref points at something other than a tag. */
4181 cmp
= got_object_id_cmp(tag
?
4182 got_object_tag_get_object_id(tag
) : ref_id
, id
);
4185 got_object_tag_close(tag
);
4189 if (asprintf(refs_str
, "%s%s%s", s
? s
: "",
4190 s
? ", " : "", name
) == -1) {
4191 err
= got_error_from_errno("asprintf");
4202 static const struct got_error
*
4203 print_commit_oneline(struct got_commit_object
*commit
, struct got_object_id
*id
,
4204 struct got_repository
*repo
, struct got_reflist_object_id_map
*refs_idmap
)
4206 const struct got_error
*err
= NULL
;
4207 char *ref_str
= NULL
, *id_str
= NULL
, *logmsg0
= NULL
;
4208 char *comma
, *s
, *nl
;
4209 struct got_reflist_head
*refs
;
4210 char datebuf
[12]; /* YYYY-MM-DD + SPACE + NUL */
4212 time_t committer_time
;
4214 refs
= got_reflist_object_id_map_lookup(refs_idmap
, id
);
4216 err
= build_refs_str(&ref_str
, refs
, id
, repo
, 1);
4220 /* Display the first matching ref only. */
4221 if (ref_str
&& (comma
= strchr(ref_str
, ',')) != NULL
)
4225 if (ref_str
== NULL
) {
4226 err
= got_object_id_str(&id_str
, id
);
4231 committer_time
= got_object_commit_get_committer_time(commit
);
4232 if (gmtime_r(&committer_time
, &tm
) == NULL
) {
4233 err
= got_error_from_errno("gmtime_r");
4236 if (strftime(datebuf
, sizeof(datebuf
), "%G-%m-%d ", &tm
) == 0) {
4237 err
= got_error(GOT_ERR_NO_SPACE
);
4241 err
= got_object_commit_get_logmsg(&logmsg0
, commit
);
4246 while (isspace((unsigned char)s
[0]))
4249 nl
= strchr(s
, '\n');
4255 printf("%s%-7s %s\n", datebuf
, ref_str
, s
);
4257 printf("%s%.7s %s\n", datebuf
, id_str
, s
);
4259 if (fflush(stdout
) != 0 && err
== NULL
)
4260 err
= got_error_from_errno("fflush");
4268 static const struct got_error
*
4269 print_diffstat(struct got_diffstat_cb_arg
*dsa
, const char *header
)
4271 struct got_pathlist_entry
*pe
;
4274 printf("%s\n", header
);
4276 TAILQ_FOREACH(pe
, dsa
->paths
, entry
) {
4277 struct got_diff_changed_path
*cp
= pe
->data
;
4278 int pad
= dsa
->max_path_len
- pe
->path_len
+ 1;
4280 printf(" %c %s%*c | %*d+ %*d-\n", cp
->status
, pe
->path
, pad
,
4281 ' ', dsa
->add_cols
+ 1, cp
->add
, dsa
->rm_cols
+ 1, cp
->rm
);
4283 printf("\n%d file%s changed, %d insertion%s(+), %d deletion%s(-)\n\n",
4284 dsa
->nfiles
, dsa
->nfiles
> 1 ? "s" : "", dsa
->ins
,
4285 dsa
->ins
!= 1 ? "s" : "", dsa
->del
, dsa
->del
!= 1 ? "s" : "");
4287 if (fflush(stdout
) != 0)
4288 return got_error_from_errno("fflush");
4293 static const struct got_error
*
4299 if (fseeko(f
, 0L, SEEK_SET
) == -1)
4300 return got_error_from_errno("fseek");
4303 r
= fread(buf
, 1, sizeof(buf
), f
);
4306 return got_error_from_errno("fread");
4310 if (fwrite(buf
, 1, r
, stdout
) != r
)
4311 return got_ferror(stdout
, GOT_ERR_IO
);
4317 static const struct got_error
*
4318 print_commit(struct got_commit_object
*commit
, struct got_object_id
*id
,
4319 struct got_repository
*repo
, const char *path
,
4320 struct got_pathlist_head
*changed_paths
,
4321 struct got_diffstat_cb_arg
*diffstat
, int show_patch
, int diff_context
,
4322 struct got_reflist_object_id_map
*refs_idmap
, const char *custom_refs_str
,
4325 const struct got_error
*err
= NULL
;
4327 char *id_str
, *datestr
, *logmsg0
, *logmsg
, *line
;
4329 time_t committer_time
;
4330 const char *author
, *committer
;
4331 char *refs_str
= NULL
;
4333 err
= got_object_id_str(&id_str
, id
);
4337 if (custom_refs_str
== NULL
) {
4338 struct got_reflist_head
*refs
;
4339 refs
= got_reflist_object_id_map_lookup(refs_idmap
, id
);
4341 err
= build_refs_str(&refs_str
, refs
, id
, repo
, 0);
4347 printf(GOT_COMMIT_SEP_STR
);
4348 if (custom_refs_str
)
4349 printf("%s %s (%s)\n", prefix
? prefix
: "commit", id_str
,
4352 printf("%s %s%s%s%s\n", prefix
? prefix
: "commit", id_str
,
4353 refs_str
? " (" : "", refs_str
? refs_str
: "",
4354 refs_str
? ")" : "");
4359 printf("from: %s\n", got_object_commit_get_author(commit
));
4360 author
= got_object_commit_get_author(commit
);
4361 committer
= got_object_commit_get_committer(commit
);
4362 if (strcmp(author
, committer
) != 0)
4363 printf("via: %s\n", committer
);
4364 committer_time
= got_object_commit_get_committer_time(commit
);
4365 datestr
= get_datestr(&committer_time
, datebuf
);
4367 printf("date: %s UTC\n", datestr
);
4368 if (got_object_commit_get_nparents(commit
) > 1) {
4369 const struct got_object_id_queue
*parent_ids
;
4370 struct got_object_qid
*qid
;
4372 parent_ids
= got_object_commit_get_parent_ids(commit
);
4373 STAILQ_FOREACH(qid
, parent_ids
, entry
) {
4374 err
= got_object_id_str(&id_str
, &qid
->id
);
4377 printf("parent %d: %s\n", n
++, id_str
);
4383 err
= got_object_commit_get_logmsg(&logmsg0
, commit
);
4389 line
= strsep(&logmsg
, "\n");
4391 printf(" %s\n", line
);
4395 if (changed_paths
&& diffstat
== NULL
) {
4396 struct got_pathlist_entry
*pe
;
4398 TAILQ_FOREACH(pe
, changed_paths
, entry
) {
4399 struct got_diff_changed_path
*cp
= pe
->data
;
4401 printf(" %c %s\n", cp
->status
, pe
->path
);
4409 err
= got_error_from_errno("got_opentemp");
4414 err
= print_patch(commit
, id
, path
, diff_context
, diffstat
,
4415 repo
, diffstat
== NULL
? stdout
: f
);
4420 err
= print_diffstat(diffstat
, NULL
);
4432 if (fflush(stdout
) != 0 && err
== NULL
)
4433 err
= got_error_from_errno("fflush");
4435 if (f
&& fclose(f
) == EOF
&& err
== NULL
)
4436 err
= got_error_from_errno("fclose");
4442 static const struct got_error
*
4443 print_commits(struct got_object_id
*root_id
, struct got_object_id
*end_id
,
4444 struct got_repository
*repo
, const char *path
, int show_changed_paths
,
4445 int show_diffstat
, int show_patch
, const char *search_pattern
,
4446 int diff_context
, int limit
, int log_branches
, int reverse_display_order
,
4447 struct got_reflist_object_id_map
*refs_idmap
, int one_line
,
4450 const struct got_error
*err
;
4451 struct got_commit_graph
*graph
;
4454 struct got_object_id_queue reversed_commits
;
4455 struct got_object_qid
*qid
;
4456 struct got_commit_object
*commit
;
4457 struct got_pathlist_head changed_paths
;
4459 STAILQ_INIT(&reversed_commits
);
4460 TAILQ_INIT(&changed_paths
);
4462 if (search_pattern
&& regcomp(®ex
, search_pattern
,
4463 REG_EXTENDED
| REG_NOSUB
| REG_NEWLINE
))
4464 return got_error_msg(GOT_ERR_REGEX
, search_pattern
);
4466 err
= got_commit_graph_open(&graph
, path
, !log_branches
);
4469 err
= got_commit_graph_iter_start(graph
, root_id
, repo
,
4470 check_cancelled
, NULL
);
4474 struct got_object_id id
;
4475 struct got_diffstat_cb_arg dsa
= { 0, 0, 0, 0, 0, 0,
4476 &changed_paths
, 0, 0, GOT_DIFF_ALGORITHM_PATIENCE
};
4478 if (sigint_received
|| sigpipe_received
)
4481 err
= got_commit_graph_iter_next(&id
, graph
, repo
,
4482 check_cancelled
, NULL
);
4484 if (err
->code
== GOT_ERR_ITER_COMPLETED
)
4489 err
= got_object_open_as_commit(&commit
, repo
, &id
);
4493 if (((show_changed_paths
&& !show_diffstat
) ||
4494 (show_diffstat
&& !show_patch
))
4495 && !reverse_display_order
) {
4496 err
= get_changed_paths(&changed_paths
, commit
, repo
,
4497 show_diffstat
? &dsa
: NULL
);
4502 if (search_pattern
) {
4503 err
= match_commit(&have_match
, &id
, commit
, ®ex
);
4505 got_object_commit_close(commit
);
4508 if (have_match
== 0 && show_changed_paths
)
4509 match_changed_paths(&have_match
,
4510 &changed_paths
, ®ex
);
4511 if (have_match
== 0 && show_patch
) {
4512 err
= match_patch(&have_match
, commit
, &id
,
4513 path
, diff_context
, repo
, ®ex
, tmpfile
);
4517 if (have_match
== 0) {
4518 got_object_commit_close(commit
);
4519 got_pathlist_free(&changed_paths
,
4520 GOT_PATHLIST_FREE_ALL
);
4525 if (reverse_display_order
) {
4526 err
= got_object_qid_alloc(&qid
, &id
);
4529 STAILQ_INSERT_HEAD(&reversed_commits
, qid
, entry
);
4530 got_object_commit_close(commit
);
4533 err
= print_commit_oneline(commit
, &id
,
4536 err
= print_commit(commit
, &id
, repo
, path
,
4537 (show_changed_paths
|| show_diffstat
) ?
4538 &changed_paths
: NULL
,
4539 show_diffstat
? &dsa
: NULL
, show_patch
,
4540 diff_context
, refs_idmap
, NULL
, NULL
);
4541 got_object_commit_close(commit
);
4545 if ((limit
&& --limit
== 0) ||
4546 (end_id
&& got_object_id_cmp(&id
, end_id
) == 0))
4549 got_pathlist_free(&changed_paths
, GOT_PATHLIST_FREE_ALL
);
4551 if (reverse_display_order
) {
4552 STAILQ_FOREACH(qid
, &reversed_commits
, entry
) {
4553 struct got_diffstat_cb_arg dsa
= { 0, 0, 0, 0, 0, 0,
4554 &changed_paths
, 0, 0, GOT_DIFF_ALGORITHM_PATIENCE
};
4556 err
= got_object_open_as_commit(&commit
, repo
,
4560 if ((show_changed_paths
&& !show_diffstat
) ||
4561 (show_diffstat
&& !show_patch
)) {
4562 err
= get_changed_paths(&changed_paths
, commit
,
4563 repo
, show_diffstat
? &dsa
: NULL
);
4568 err
= print_commit_oneline(commit
, &qid
->id
,
4571 err
= print_commit(commit
, &qid
->id
, repo
, path
,
4572 (show_changed_paths
|| show_diffstat
) ?
4573 &changed_paths
: NULL
,
4574 show_diffstat
? &dsa
: NULL
, show_patch
,
4575 diff_context
, refs_idmap
, NULL
, NULL
);
4576 got_object_commit_close(commit
);
4579 got_pathlist_free(&changed_paths
, GOT_PATHLIST_FREE_ALL
);
4583 while (!STAILQ_EMPTY(&reversed_commits
)) {
4584 qid
= STAILQ_FIRST(&reversed_commits
);
4585 STAILQ_REMOVE_HEAD(&reversed_commits
, entry
);
4586 got_object_qid_free(qid
);
4588 got_pathlist_free(&changed_paths
, GOT_PATHLIST_FREE_ALL
);
4591 got_commit_graph_close(graph
);
4598 fprintf(stderr
, "usage: %s log [-bdPpRs] [-C number] [-c commit] "
4599 "[-l N] [-r repository-path] [-S search-pattern] [-x commit] "
4600 "[path]\n", getprogname());
4605 get_default_log_limit(void)
4607 const char *got_default_log_limit
;
4611 got_default_log_limit
= getenv("GOT_LOG_DEFAULT_LIMIT");
4612 if (got_default_log_limit
== NULL
)
4614 n
= strtonum(got_default_log_limit
, 0, INT_MAX
, &errstr
);
4620 static const struct got_error
*
4621 cmd_log(int argc
, char *argv
[])
4623 const struct got_error
*error
;
4624 struct got_repository
*repo
= NULL
;
4625 struct got_worktree
*worktree
= NULL
;
4626 struct got_object_id
*start_id
= NULL
, *end_id
= NULL
;
4627 char *repo_path
= NULL
, *path
= NULL
, *cwd
= NULL
, *in_repo_path
= NULL
;
4628 char *keyword_idstr
= NULL
;
4629 const char *start_commit
= NULL
, *end_commit
= NULL
;
4630 const char *search_pattern
= NULL
;
4631 int diff_context
= -1, ch
;
4632 int show_changed_paths
= 0, show_patch
= 0, limit
= 0, log_branches
= 0;
4633 int show_diffstat
= 0, reverse_display_order
= 0, one_line
= 0;
4635 struct got_reflist_head refs
;
4636 struct got_reflist_object_id_map
*refs_idmap
= NULL
;
4637 FILE *tmpfile
= NULL
;
4638 int *pack_fds
= NULL
;
4643 if (pledge("stdio rpath wpath cpath flock proc exec sendfd unveil",
4649 limit
= get_default_log_limit();
4651 while ((ch
= getopt(argc
, argv
, "bC:c:dl:PpRr:S:sx:")) != -1) {
4657 diff_context
= strtonum(optarg
, 0, GOT_DIFF_MAX_CONTEXT
,
4660 errx(1, "number of context lines is %s: %s",
4664 start_commit
= optarg
;
4670 limit
= strtonum(optarg
, 0, INT_MAX
, &errstr
);
4672 errx(1, "number of commits is %s: %s",
4676 show_changed_paths
= 1;
4682 reverse_display_order
= 1;
4685 repo_path
= realpath(optarg
, NULL
);
4686 if (repo_path
== NULL
)
4687 return got_error_from_errno2("realpath",
4689 got_path_strip_trailing_slashes(repo_path
);
4692 search_pattern
= optarg
;
4698 end_commit
= optarg
;
4709 if (diff_context
== -1)
4711 else if (!show_patch
)
4712 errx(1, "-C requires -p");
4714 if (one_line
&& (show_patch
|| show_changed_paths
|| show_diffstat
))
4715 errx(1, "cannot use -s with -d, -p or -P");
4717 cwd
= getcwd(NULL
, 0);
4719 error
= got_error_from_errno("getcwd");
4723 error
= got_repo_pack_fds_open(&pack_fds
);
4727 if (repo_path
== NULL
) {
4728 error
= got_worktree_open(&worktree
, cwd
,
4729 GOT_WORKTREE_GOT_DIR
);
4730 if (error
&& error
->code
!= GOT_ERR_NOT_WORKTREE
)
4737 error
= got_worktree_resolve_path(&path
, worktree
,
4742 path
= strdup(argv
[0]);
4744 error
= got_error_from_errno("strdup");
4748 } else if (argc
!= 0)
4751 if (repo_path
== NULL
) {
4752 repo_path
= worktree
?
4753 strdup(got_worktree_get_repo_path(worktree
)) : strdup(cwd
);
4755 if (repo_path
== NULL
) {
4756 error
= got_error_from_errno("strdup");
4760 error
= got_repo_open(&repo
, repo_path
, NULL
, pack_fds
);
4764 error
= apply_unveil(got_repo_get_path(repo
), 1,
4765 worktree
? got_worktree_get_root_path(worktree
) : NULL
);
4769 error
= got_ref_list(&refs
, repo
, NULL
, got_ref_cmp_by_name
, NULL
);
4773 error
= got_reflist_object_id_map_create(&refs_idmap
, &refs
, repo
);
4777 if (start_commit
== NULL
) {
4778 struct got_reference
*head_ref
;
4779 struct got_commit_object
*commit
= NULL
;
4780 error
= got_ref_open(&head_ref
, repo
,
4781 worktree
? got_worktree_get_head_ref_name(worktree
)
4785 error
= got_ref_resolve(&start_id
, repo
, head_ref
);
4786 got_ref_close(head_ref
);
4789 error
= got_object_open_as_commit(&commit
, repo
,
4793 got_object_commit_close(commit
);
4795 error
= got_keyword_to_idstr(&keyword_idstr
, start_commit
,
4799 if (keyword_idstr
!= NULL
)
4800 start_commit
= keyword_idstr
;
4802 error
= got_repo_match_object_id(&start_id
, NULL
,
4803 start_commit
, GOT_OBJ_TYPE_COMMIT
, &refs
, repo
);
4807 if (end_commit
!= NULL
) {
4808 error
= got_keyword_to_idstr(&keyword_idstr
, end_commit
,
4812 if (keyword_idstr
!= NULL
)
4813 end_commit
= keyword_idstr
;
4815 error
= got_repo_match_object_id(&end_id
, NULL
,
4816 end_commit
, GOT_OBJ_TYPE_COMMIT
, &refs
, repo
);
4823 * If a path was specified on the command line it was resolved
4824 * to a path in the work tree above. Prepend the work tree's
4825 * path prefix to obtain the corresponding in-repository path.
4829 prefix
= got_worktree_get_path_prefix(worktree
);
4830 if (asprintf(&in_repo_path
, "%s%s%s", prefix
,
4831 (path
[0] != '\0') ? "/" : "", path
) == -1) {
4832 error
= got_error_from_errno("asprintf");
4837 error
= got_repo_map_path(&in_repo_path
, repo
,
4843 path
= in_repo_path
;
4847 /* Release work tree lock. */
4848 got_worktree_close(worktree
);
4852 if (search_pattern
&& show_patch
) {
4853 tmpfile
= got_opentemp();
4854 if (tmpfile
== NULL
) {
4855 error
= got_error_from_errno("got_opentemp");
4860 error
= print_commits(start_id
, end_id
, repo
, path
? path
: "",
4861 show_changed_paths
, show_diffstat
, show_patch
, search_pattern
,
4862 diff_context
, limit
, log_branches
, reverse_display_order
,
4863 refs_idmap
, one_line
, tmpfile
);
4870 free(keyword_idstr
);
4872 got_worktree_close(worktree
);
4874 const struct got_error
*close_err
= got_repo_close(repo
);
4879 const struct got_error
*pack_err
=
4880 got_repo_pack_fds_close(pack_fds
);
4885 got_reflist_object_id_map_free(refs_idmap
);
4886 if (tmpfile
&& fclose(tmpfile
) == EOF
&& error
== NULL
)
4887 error
= got_error_from_errno("fclose");
4888 got_ref_list_free(&refs
);
4895 fprintf(stderr
, "usage: %s diff [-adPsw] [-C number] [-c commit] "
4896 "[-r repository-path] [object1 object2 | path ...]\n",
4901 struct print_diff_arg
{
4902 struct got_repository
*repo
;
4903 struct got_worktree
*worktree
;
4904 struct got_diffstat_cb_arg
*diffstat
;
4909 enum got_diff_algorithm diff_algo
;
4910 int ignore_whitespace
;
4911 int force_text_diff
;
4918 * Create a file which contains the target path of a symlink so we can feed
4919 * it as content to the diff engine.
4921 static const struct got_error
*
4922 get_symlink_target_file(int *fd
, int dirfd
, const char *de_name
,
4923 const char *abspath
)
4925 const struct got_error
*err
= NULL
;
4926 char target_path
[PATH_MAX
];
4927 ssize_t target_len
, outlen
;
4932 target_len
= readlinkat(dirfd
, de_name
, target_path
, PATH_MAX
);
4933 if (target_len
== -1)
4934 return got_error_from_errno2("readlinkat", abspath
);
4936 target_len
= readlink(abspath
, target_path
, PATH_MAX
);
4937 if (target_len
== -1)
4938 return got_error_from_errno2("readlink", abspath
);
4941 *fd
= got_opentempfd();
4943 return got_error_from_errno("got_opentempfd");
4945 outlen
= write(*fd
, target_path
, target_len
);
4947 err
= got_error_from_errno("got_opentempfd");
4951 if (lseek(*fd
, 0, SEEK_SET
) == -1) {
4952 err
= got_error_from_errno2("lseek", abspath
);
4963 static const struct got_error
*
4964 print_diff(void *arg
, unsigned char status
, unsigned char staged_status
,
4965 const char *path
, struct got_object_id
*blob_id
,
4966 struct got_object_id
*staged_blob_id
, struct got_object_id
*commit_id
,
4967 int dirfd
, const char *de_name
)
4969 struct print_diff_arg
*a
= arg
;
4970 const struct got_error
*err
= NULL
;
4971 struct got_blob_object
*blob1
= NULL
;
4972 int fd
= -1, fd1
= -1, fd2
= -1;
4974 char *abspath
= NULL
, *label1
= NULL
;
4979 memset(&sb
, 0, sizeof(sb
));
4981 if (a
->diff_staged
) {
4982 if (staged_status
!= GOT_STATUS_MODIFY
&&
4983 staged_status
!= GOT_STATUS_ADD
&&
4984 staged_status
!= GOT_STATUS_DELETE
)
4987 if (staged_status
== GOT_STATUS_DELETE
)
4989 if (status
== GOT_STATUS_NONEXISTENT
)
4990 return got_error_set_errno(ENOENT
, path
);
4991 if (status
!= GOT_STATUS_MODIFY
&&
4992 status
!= GOT_STATUS_ADD
&&
4993 status
!= GOT_STATUS_DELETE
&&
4994 status
!= GOT_STATUS_CONFLICT
)
4998 err
= got_opentemp_truncate(a
->f1
);
5000 return got_error_from_errno("got_opentemp_truncate");
5001 err
= got_opentemp_truncate(a
->f2
);
5003 return got_error_from_errno("got_opentemp_truncate");
5005 if (!a
->header_shown
) {
5006 if (fprintf(a
->outfile
, "diff %s%s\n",
5007 a
->diff_staged
? "-s " : "",
5008 got_worktree_get_root_path(a
->worktree
)) < 0) {
5009 err
= got_error_from_errno("fprintf");
5012 if (fprintf(a
->outfile
, "commit - %s\n", a
->id_str
) < 0) {
5013 err
= got_error_from_errno("fprintf");
5016 if (fprintf(a
->outfile
, "path + %s%s\n",
5017 got_worktree_get_root_path(a
->worktree
),
5018 a
->diff_staged
? " (staged changes)" : "") < 0) {
5019 err
= got_error_from_errno("fprintf");
5022 a
->header_shown
= 1;
5025 if (a
->diff_staged
) {
5026 const char *label1
= NULL
, *label2
= NULL
;
5027 switch (staged_status
) {
5028 case GOT_STATUS_MODIFY
:
5032 case GOT_STATUS_ADD
:
5035 case GOT_STATUS_DELETE
:
5039 return got_error(GOT_ERR_FILE_STATUS
);
5041 fd1
= got_opentempfd();
5043 err
= got_error_from_errno("got_opentempfd");
5046 fd2
= got_opentempfd();
5048 err
= got_error_from_errno("got_opentempfd");
5051 err
= got_diff_objects_as_blobs(NULL
, NULL
, a
->f1
, a
->f2
,
5052 fd1
, fd2
, blob_id
, staged_blob_id
, label1
, label2
,
5053 a
->diff_algo
, a
->diff_context
, a
->ignore_whitespace
,
5054 a
->force_text_diff
, a
->diffstat
, a
->repo
, a
->outfile
);
5058 fd1
= got_opentempfd();
5060 err
= got_error_from_errno("got_opentempfd");
5064 if (staged_status
== GOT_STATUS_ADD
||
5065 staged_status
== GOT_STATUS_MODIFY
) {
5067 err
= got_object_open_as_blob(&blob1
, a
->repo
, staged_blob_id
,
5071 err
= got_object_id_str(&id_str
, staged_blob_id
);
5074 if (asprintf(&label1
, "%s (staged)", id_str
) == -1) {
5075 err
= got_error_from_errno("asprintf");
5080 } else if (status
!= GOT_STATUS_ADD
) {
5081 err
= got_object_open_as_blob(&blob1
, a
->repo
, blob_id
, 8192,
5087 if (status
!= GOT_STATUS_DELETE
) {
5088 if (asprintf(&abspath
, "%s/%s",
5089 got_worktree_get_root_path(a
->worktree
), path
) == -1) {
5090 err
= got_error_from_errno("asprintf");
5095 fd
= openat(dirfd
, de_name
,
5096 O_RDONLY
| O_NOFOLLOW
| O_CLOEXEC
);
5098 if (!got_err_open_nofollow_on_symlink()) {
5099 err
= got_error_from_errno2("openat",
5103 err
= get_symlink_target_file(&fd
, dirfd
,
5109 fd
= open(abspath
, O_RDONLY
| O_NOFOLLOW
| O_CLOEXEC
);
5111 if (!got_err_open_nofollow_on_symlink()) {
5112 err
= got_error_from_errno2("open",
5116 err
= get_symlink_target_file(&fd
, dirfd
,
5122 if (fstatat(fd
, abspath
, &sb
, AT_SYMLINK_NOFOLLOW
) == -1) {
5123 err
= got_error_from_errno2("fstatat", abspath
);
5126 f2
= fdopen(fd
, "r");
5128 err
= got_error_from_errno2("fdopen", abspath
);
5136 err
= got_object_blob_dump_to_file(&size1
, NULL
, NULL
,
5142 err
= got_diff_blob_file(blob1
, a
->f1
, size1
, label1
, f2
? f2
: a
->f2
,
5143 f2_exists
, &sb
, path
, GOT_DIFF_ALGORITHM_PATIENCE
, a
->diff_context
,
5144 a
->ignore_whitespace
, a
->force_text_diff
, a
->diffstat
, a
->outfile
);
5146 if (fd1
!= -1 && close(fd1
) == -1 && err
== NULL
)
5147 err
= got_error_from_errno("close");
5148 if (fd2
!= -1 && close(fd2
) == -1 && err
== NULL
)
5149 err
= got_error_from_errno("close");
5151 got_object_blob_close(blob1
);
5152 if (fd
!= -1 && close(fd
) == -1 && err
== NULL
)
5153 err
= got_error_from_errno("close");
5154 if (f2
&& fclose(f2
) == EOF
&& err
== NULL
)
5155 err
= got_error_from_errno("fclose");
5160 static const struct got_error
*
5161 cmd_diff(int argc
, char *argv
[])
5163 const struct got_error
*error
;
5164 struct got_repository
*repo
= NULL
;
5165 struct got_worktree
*worktree
= NULL
;
5166 char *cwd
= NULL
, *repo_path
= NULL
;
5167 const char *commit_args
[2] = { NULL
, NULL
};
5168 int ncommit_args
= 0;
5169 struct got_object_id
*ids
[2] = { NULL
, NULL
};
5170 char *labels
[2] = { NULL
, NULL
};
5171 int type1
= GOT_OBJ_TYPE_ANY
, type2
= GOT_OBJ_TYPE_ANY
;
5172 int diff_context
= 3, diff_staged
= 0, ignore_whitespace
= 0, ch
, i
;
5173 int force_text_diff
= 0, force_path
= 0, rflag
= 0, show_diffstat
= 0;
5175 struct got_reflist_head refs
;
5176 struct got_pathlist_head diffstat_paths
, paths
;
5177 FILE *f1
= NULL
, *f2
= NULL
, *outfile
= NULL
;
5178 int fd1
= -1, fd2
= -1;
5179 int *pack_fds
= NULL
;
5180 struct got_diffstat_cb_arg dsa
;
5182 memset(&dsa
, 0, sizeof(dsa
));
5186 TAILQ_INIT(&diffstat_paths
);
5189 if (pledge("stdio rpath wpath cpath flock proc exec sendfd unveil",
5194 while ((ch
= getopt(argc
, argv
, "aC:c:dPr:sw")) != -1) {
5197 force_text_diff
= 1;
5200 diff_context
= strtonum(optarg
, 0, GOT_DIFF_MAX_CONTEXT
,
5203 errx(1, "number of context lines is %s: %s",
5207 if (ncommit_args
>= 2)
5208 errx(1, "too many -c options used");
5209 commit_args
[ncommit_args
++] = optarg
;
5218 repo_path
= realpath(optarg
, NULL
);
5219 if (repo_path
== NULL
)
5220 return got_error_from_errno2("realpath",
5222 got_path_strip_trailing_slashes(repo_path
);
5229 ignore_whitespace
= 1;
5240 cwd
= getcwd(NULL
, 0);
5242 error
= got_error_from_errno("getcwd");
5246 error
= got_repo_pack_fds_open(&pack_fds
);
5250 if (repo_path
== NULL
) {
5251 error
= got_worktree_open(&worktree
, cwd
,
5252 GOT_WORKTREE_GOT_DIR
);
5253 if (error
&& error
->code
!= GOT_ERR_NOT_WORKTREE
)
5259 strdup(got_worktree_get_repo_path(worktree
));
5260 if (repo_path
== NULL
) {
5261 error
= got_error_from_errno("strdup");
5265 repo_path
= strdup(cwd
);
5266 if (repo_path
== NULL
) {
5267 error
= got_error_from_errno("strdup");
5273 error
= got_repo_open(&repo
, repo_path
, NULL
, pack_fds
);
5278 if (show_diffstat
) {
5279 dsa
.paths
= &diffstat_paths
;
5280 dsa
.force_text
= force_text_diff
;
5281 dsa
.ignore_ws
= ignore_whitespace
;
5282 dsa
.diff_algo
= GOT_DIFF_ALGORITHM_PATIENCE
;
5285 if (rflag
|| worktree
== NULL
|| ncommit_args
> 0) {
5287 error
= got_error_msg(GOT_ERR_NOT_IMPL
,
5288 "-P option can only be used when diffing "
5293 error
= got_error_msg(GOT_ERR_NOT_IMPL
,
5294 "-s option can only be used when diffing "
5300 error
= apply_unveil(got_repo_get_path(repo
), 1,
5301 worktree
? got_worktree_get_root_path(worktree
) : NULL
);
5305 if ((!force_path
&& argc
== 2) || ncommit_args
> 0) {
5306 int obj_type
= (ncommit_args
> 0 ?
5307 GOT_OBJ_TYPE_COMMIT
: GOT_OBJ_TYPE_ANY
);
5308 error
= got_ref_list(&refs
, repo
, NULL
, got_ref_cmp_by_name
,
5312 for (i
= 0; i
< (ncommit_args
> 0 ? ncommit_args
: argc
); i
++) {
5314 char *keyword_idstr
= NULL
;
5316 if (ncommit_args
> 0)
5317 arg
= commit_args
[i
];
5321 error
= got_keyword_to_idstr(&keyword_idstr
, arg
,
5325 if (keyword_idstr
!= NULL
)
5326 arg
= keyword_idstr
;
5328 error
= got_repo_match_object_id(&ids
[i
], &labels
[i
],
5329 arg
, obj_type
, &refs
, repo
);
5330 free(keyword_idstr
);
5332 if (error
->code
!= GOT_ERR_NOT_REF
&&
5333 error
->code
!= GOT_ERR_NO_OBJ
)
5335 if (ncommit_args
> 0)
5343 f1
= got_opentemp();
5345 error
= got_error_from_errno("got_opentemp");
5349 f2
= got_opentemp();
5351 error
= got_error_from_errno("got_opentemp");
5355 outfile
= got_opentemp();
5356 if (outfile
== NULL
) {
5357 error
= got_error_from_errno("got_opentemp");
5361 if (ncommit_args
== 0 && (ids
[0] == NULL
|| ids
[1] == NULL
)) {
5362 struct print_diff_arg arg
;
5365 if (worktree
== NULL
) {
5366 if (argc
== 2 && ids
[0] == NULL
) {
5367 error
= got_error_path(argv
[0], GOT_ERR_NO_OBJ
);
5369 } else if (argc
== 2 && ids
[1] == NULL
) {
5370 error
= got_error_path(argv
[1], GOT_ERR_NO_OBJ
);
5372 } else if (argc
> 0) {
5373 error
= got_error_fmt(GOT_ERR_NOT_WORKTREE
,
5374 "%s", "specified paths cannot be resolved");
5377 error
= got_error(GOT_ERR_NOT_WORKTREE
);
5382 error
= get_worktree_paths_from_argv(&paths
, argc
, argv
,
5387 error
= got_object_id_str(&id_str
,
5388 got_worktree_get_base_commit_id(worktree
));
5392 arg
.worktree
= worktree
;
5393 arg
.diff_algo
= GOT_DIFF_ALGORITHM_PATIENCE
;
5394 arg
.diff_context
= diff_context
;
5395 arg
.id_str
= id_str
;
5396 arg
.header_shown
= 0;
5397 arg
.diff_staged
= diff_staged
;
5398 arg
.ignore_whitespace
= ignore_whitespace
;
5399 arg
.force_text_diff
= force_text_diff
;
5400 arg
.diffstat
= show_diffstat
? &dsa
: NULL
;
5403 arg
.outfile
= outfile
;
5405 error
= got_worktree_status(worktree
, &paths
, repo
, 0,
5406 print_diff
, &arg
, check_cancelled
, NULL
);
5411 if (show_diffstat
&& dsa
.nfiles
> 0) {
5414 if (asprintf(&header
, "diffstat %s%s",
5415 diff_staged
? "-s " : "",
5416 got_worktree_get_root_path(worktree
)) == -1) {
5417 error
= got_error_from_errno("asprintf");
5421 error
= print_diffstat(&dsa
, header
);
5427 error
= printfile(outfile
);
5431 if (ncommit_args
== 1) {
5432 struct got_commit_object
*commit
;
5433 error
= got_object_open_as_commit(&commit
, repo
, ids
[0]);
5437 labels
[1] = labels
[0];
5439 if (got_object_commit_get_nparents(commit
) > 0) {
5440 const struct got_object_id_queue
*pids
;
5441 struct got_object_qid
*pid
;
5442 pids
= got_object_commit_get_parent_ids(commit
);
5443 pid
= STAILQ_FIRST(pids
);
5444 ids
[0] = got_object_id_dup(&pid
->id
);
5445 if (ids
[0] == NULL
) {
5446 error
= got_error_from_errno(
5447 "got_object_id_dup");
5448 got_object_commit_close(commit
);
5451 error
= got_object_id_str(&labels
[0], ids
[0]);
5453 got_object_commit_close(commit
);
5458 labels
[0] = strdup("/dev/null");
5459 if (labels
[0] == NULL
) {
5460 error
= got_error_from_errno("strdup");
5461 got_object_commit_close(commit
);
5466 got_object_commit_close(commit
);
5469 if (ncommit_args
== 0 && argc
> 2) {
5470 error
= got_error_msg(GOT_ERR_BAD_PATH
,
5471 "path arguments cannot be used when diffing two objects");
5476 error
= got_object_get_type(&type1
, repo
, ids
[0]);
5481 error
= got_object_get_type(&type2
, repo
, ids
[1]);
5484 if (type1
!= GOT_OBJ_TYPE_ANY
&& type1
!= type2
) {
5485 error
= got_error(GOT_ERR_OBJ_TYPE
);
5488 if (type1
== GOT_OBJ_TYPE_BLOB
&& argc
> 2) {
5489 error
= got_error_msg(GOT_ERR_OBJ_TYPE
,
5490 "path arguments cannot be used when diffing blobs");
5494 for (i
= 0; ncommit_args
> 0 && i
< argc
; i
++) {
5496 struct got_pathlist_entry
*new;
5500 error
= got_worktree_resolve_path(&p
, worktree
,
5504 prefix
= got_worktree_get_path_prefix(worktree
);
5505 while (prefix
[0] == '/')
5507 if (asprintf(&in_repo_path
, "%s%s%s", prefix
,
5508 (p
[0] != '\0' && prefix
[0] != '\0') ? "/" : "",
5510 error
= got_error_from_errno("asprintf");
5516 char *mapped_path
, *s
;
5517 error
= got_repo_map_path(&mapped_path
, repo
, argv
[i
]);
5523 in_repo_path
= strdup(s
);
5524 if (in_repo_path
== NULL
) {
5525 error
= got_error_from_errno("asprintf");
5532 error
= got_pathlist_insert(&new, &paths
, in_repo_path
, NULL
);
5533 if (error
|| new == NULL
/* duplicate */)
5540 /* Release work tree lock. */
5541 got_worktree_close(worktree
);
5545 fd1
= got_opentempfd();
5547 error
= got_error_from_errno("got_opentempfd");
5551 fd2
= got_opentempfd();
5553 error
= got_error_from_errno("got_opentempfd");
5557 switch (type1
== GOT_OBJ_TYPE_ANY
? type2
: type1
) {
5558 case GOT_OBJ_TYPE_BLOB
:
5559 error
= got_diff_objects_as_blobs(NULL
, NULL
, f1
, f2
,
5560 fd1
, fd2
, ids
[0], ids
[1], NULL
, NULL
,
5561 GOT_DIFF_ALGORITHM_PATIENCE
, diff_context
,
5562 ignore_whitespace
, force_text_diff
,
5563 show_diffstat
? &dsa
: NULL
, repo
, outfile
);
5565 case GOT_OBJ_TYPE_TREE
:
5566 error
= got_diff_objects_as_trees(NULL
, NULL
, f1
, f2
, fd1
, fd2
,
5567 ids
[0], ids
[1], &paths
, "", "",
5568 GOT_DIFF_ALGORITHM_PATIENCE
, diff_context
,
5569 ignore_whitespace
, force_text_diff
,
5570 show_diffstat
? &dsa
: NULL
, repo
, outfile
);
5572 case GOT_OBJ_TYPE_COMMIT
:
5573 fprintf(outfile
, "diff %s %s\n", labels
[0], labels
[1]);
5574 error
= got_diff_objects_as_commits(NULL
, NULL
, f1
, f2
,
5575 fd1
, fd2
, ids
[0], ids
[1], &paths
,
5576 GOT_DIFF_ALGORITHM_PATIENCE
, diff_context
,
5577 ignore_whitespace
, force_text_diff
,
5578 show_diffstat
? &dsa
: NULL
, repo
, outfile
);
5581 error
= got_error(GOT_ERR_OBJ_TYPE
);
5586 if (show_diffstat
&& dsa
.nfiles
> 0) {
5587 char *header
= NULL
;
5589 if (asprintf(&header
, "diffstat %s %s",
5590 labels
[0], labels
[1]) == -1) {
5591 error
= got_error_from_errno("asprintf");
5595 error
= print_diffstat(&dsa
, header
);
5601 error
= printfile(outfile
);
5609 got_worktree_close(worktree
);
5611 const struct got_error
*close_err
= got_repo_close(repo
);
5616 const struct got_error
*pack_err
=
5617 got_repo_pack_fds_close(pack_fds
);
5621 got_pathlist_free(&paths
, GOT_PATHLIST_FREE_PATH
);
5622 got_pathlist_free(&diffstat_paths
, GOT_PATHLIST_FREE_ALL
);
5623 got_ref_list_free(&refs
);
5624 if (outfile
&& fclose(outfile
) == EOF
&& error
== NULL
)
5625 error
= got_error_from_errno("fclose");
5626 if (f1
&& fclose(f1
) == EOF
&& error
== NULL
)
5627 error
= got_error_from_errno("fclose");
5628 if (f2
&& fclose(f2
) == EOF
&& error
== NULL
)
5629 error
= got_error_from_errno("fclose");
5630 if (fd1
!= -1 && close(fd1
) == -1 && error
== NULL
)
5631 error
= got_error_from_errno("close");
5632 if (fd2
!= -1 && close(fd2
) == -1 && error
== NULL
)
5633 error
= got_error_from_errno("close");
5641 "usage: %s blame [-c commit] [-r repository-path] path\n",
5650 char datebuf
[11]; /* YYYY-MM-DD + NUL */
5653 struct blame_cb_args
{
5654 struct blame_line
*lines
;
5658 off_t
*line_offsets
;
5660 struct got_repository
*repo
;
5663 static const struct got_error
*
5664 blame_cb(void *arg
, int nlines
, int lineno
,
5665 struct got_commit_object
*commit
, struct got_object_id
*id
)
5667 const struct got_error
*err
= NULL
;
5668 struct blame_cb_args
*a
= arg
;
5669 struct blame_line
*bline
;
5671 size_t linesize
= 0;
5674 time_t committer_time
;
5676 if (nlines
!= a
->nlines
||
5677 (lineno
!= -1 && lineno
< 1) || lineno
> a
->nlines
)
5678 return got_error(GOT_ERR_RANGE
);
5680 if (sigint_received
)
5681 return got_error(GOT_ERR_ITER_COMPLETED
);
5684 return NULL
; /* no change in this commit */
5686 /* Annotate this line. */
5687 bline
= &a
->lines
[lineno
- 1];
5688 if (bline
->annotated
)
5690 err
= got_object_id_str(&bline
->id_str
, id
);
5694 bline
->committer
= strdup(got_object_commit_get_committer(commit
));
5695 if (bline
->committer
== NULL
) {
5696 err
= got_error_from_errno("strdup");
5700 committer_time
= got_object_commit_get_committer_time(commit
);
5701 if (gmtime_r(&committer_time
, &tm
) == NULL
)
5702 return got_error_from_errno("gmtime_r");
5703 if (strftime(bline
->datebuf
, sizeof(bline
->datebuf
), "%G-%m-%d",
5705 err
= got_error(GOT_ERR_NO_SPACE
);
5708 bline
->annotated
= 1;
5710 /* Print lines annotated so far. */
5711 bline
= &a
->lines
[a
->lineno_cur
- 1];
5712 if (!bline
->annotated
)
5715 offset
= a
->line_offsets
[a
->lineno_cur
- 1];
5716 if (fseeko(a
->f
, offset
, SEEK_SET
) == -1) {
5717 err
= got_error_from_errno("fseeko");
5721 while (a
->lineno_cur
<= a
->nlines
&& bline
->annotated
) {
5722 char *smallerthan
, *at
, *nl
, *committer
;
5725 if (getline(&line
, &linesize
, a
->f
) == -1) {
5727 err
= got_error_from_errno("getline");
5731 committer
= bline
->committer
;
5732 smallerthan
= strchr(committer
, '<');
5733 if (smallerthan
&& smallerthan
[1] != '\0')
5734 committer
= smallerthan
+ 1;
5735 at
= strchr(committer
, '@');
5738 len
= strlen(committer
);
5740 committer
[8] = '\0';
5742 nl
= strchr(line
, '\n');
5745 printf("%.*d) %.8s %s %-8s %s\n", a
->nlines_prec
, a
->lineno_cur
,
5746 bline
->id_str
, bline
->datebuf
, committer
, line
);
5749 bline
= &a
->lines
[a
->lineno_cur
- 1];
5756 static const struct got_error
*
5757 cmd_blame(int argc
, char *argv
[])
5759 const struct got_error
*error
;
5760 struct got_repository
*repo
= NULL
;
5761 struct got_worktree
*worktree
= NULL
;
5762 char *path
, *cwd
= NULL
, *repo_path
= NULL
, *in_repo_path
= NULL
;
5763 char *link_target
= NULL
;
5764 struct got_object_id
*obj_id
= NULL
;
5765 struct got_object_id
*commit_id
= NULL
;
5766 struct got_commit_object
*commit
= NULL
;
5767 struct got_blob_object
*blob
= NULL
;
5768 char *commit_id_str
= NULL
, *keyword_idstr
= NULL
;
5769 struct blame_cb_args bca
;
5770 int ch
, obj_type
, i
, fd1
= -1, fd2
= -1, fd3
= -1;
5772 int *pack_fds
= NULL
;
5773 FILE *f1
= NULL
, *f2
= NULL
;
5775 fd1
= got_opentempfd();
5777 return got_error_from_errno("got_opentempfd");
5779 memset(&bca
, 0, sizeof(bca
));
5782 if (pledge("stdio rpath wpath cpath flock proc exec sendfd unveil",
5787 while ((ch
= getopt(argc
, argv
, "c:r:")) != -1) {
5790 commit_id_str
= optarg
;
5793 repo_path
= realpath(optarg
, NULL
);
5794 if (repo_path
== NULL
)
5795 return got_error_from_errno2("realpath",
5797 got_path_strip_trailing_slashes(repo_path
);
5813 cwd
= getcwd(NULL
, 0);
5815 error
= got_error_from_errno("getcwd");
5819 error
= got_repo_pack_fds_open(&pack_fds
);
5823 if (repo_path
== NULL
) {
5824 error
= got_worktree_open(&worktree
, cwd
,
5825 GOT_WORKTREE_GOT_DIR
);
5826 if (error
&& error
->code
!= GOT_ERR_NOT_WORKTREE
)
5832 strdup(got_worktree_get_repo_path(worktree
));
5833 if (repo_path
== NULL
) {
5834 error
= got_error_from_errno("strdup");
5839 repo_path
= strdup(cwd
);
5840 if (repo_path
== NULL
) {
5841 error
= got_error_from_errno("strdup");
5847 error
= got_repo_open(&repo
, repo_path
, NULL
, pack_fds
);
5852 const char *prefix
= got_worktree_get_path_prefix(worktree
);
5855 error
= got_worktree_resolve_path(&p
, worktree
, path
);
5858 if (asprintf(&in_repo_path
, "%s%s%s", prefix
,
5859 (p
[0] != '\0' && !got_path_is_root_dir(prefix
)) ? "/" : "",
5861 error
= got_error_from_errno("asprintf");
5866 error
= apply_unveil(got_repo_get_path(repo
), 1, NULL
);
5868 error
= apply_unveil(got_repo_get_path(repo
), 1, NULL
);
5871 error
= got_repo_map_path(&in_repo_path
, repo
, path
);
5876 if (commit_id_str
== NULL
) {
5877 struct got_reference
*head_ref
;
5878 error
= got_ref_open(&head_ref
, repo
, worktree
?
5879 got_worktree_get_head_ref_name(worktree
) : GOT_REF_HEAD
, 0);
5882 error
= got_ref_resolve(&commit_id
, repo
, head_ref
);
5883 got_ref_close(head_ref
);
5887 struct got_reflist_head refs
;
5890 error
= got_ref_list(&refs
, repo
, NULL
, got_ref_cmp_by_name
,
5895 error
= got_keyword_to_idstr(&keyword_idstr
, commit_id_str
,
5899 if (keyword_idstr
!= NULL
)
5900 commit_id_str
= keyword_idstr
;
5902 error
= got_repo_match_object_id(&commit_id
, NULL
,
5903 commit_id_str
, GOT_OBJ_TYPE_COMMIT
, &refs
, repo
);
5904 got_ref_list_free(&refs
);
5910 /* Release work tree lock. */
5911 got_worktree_close(worktree
);
5915 error
= got_object_open_as_commit(&commit
, repo
, commit_id
);
5919 error
= got_object_resolve_symlinks(&link_target
, in_repo_path
,
5924 error
= got_object_id_by_path(&obj_id
, repo
, commit
,
5925 link_target
? link_target
: in_repo_path
);
5929 error
= got_object_get_type(&obj_type
, repo
, obj_id
);
5933 if (obj_type
!= GOT_OBJ_TYPE_BLOB
) {
5934 error
= got_error_path(link_target
? link_target
: in_repo_path
,
5939 error
= got_object_open_as_blob(&blob
, repo
, obj_id
, 8192, fd1
);
5942 bca
.f
= got_opentemp();
5943 if (bca
.f
== NULL
) {
5944 error
= got_error_from_errno("got_opentemp");
5947 error
= got_object_blob_dump_to_file(&filesize
, &bca
.nlines
,
5948 &bca
.line_offsets
, bca
.f
, blob
);
5949 if (error
|| bca
.nlines
== 0)
5952 /* Don't include \n at EOF in the blame line count. */
5953 if (bca
.line_offsets
[bca
.nlines
- 1] == filesize
)
5956 bca
.lines
= calloc(bca
.nlines
, sizeof(*bca
.lines
));
5957 if (bca
.lines
== NULL
) {
5958 error
= got_error_from_errno("calloc");
5962 bca
.nlines_prec
= 0;
5970 fd2
= got_opentempfd();
5972 error
= got_error_from_errno("got_opentempfd");
5975 fd3
= got_opentempfd();
5977 error
= got_error_from_errno("got_opentempfd");
5980 f1
= got_opentemp();
5982 error
= got_error_from_errno("got_opentemp");
5985 f2
= got_opentemp();
5987 error
= got_error_from_errno("got_opentemp");
5990 error
= got_blame(link_target
? link_target
: in_repo_path
, commit_id
,
5991 repo
, GOT_DIFF_ALGORITHM_PATIENCE
, blame_cb
, &bca
,
5992 check_cancelled
, NULL
, fd2
, fd3
, f1
, f2
);
5994 free(keyword_idstr
);
6002 got_object_commit_close(commit
);
6004 if (fd1
!= -1 && close(fd1
) == -1 && error
== NULL
)
6005 error
= got_error_from_errno("close");
6006 if (fd2
!= -1 && close(fd2
) == -1 && error
== NULL
)
6007 error
= got_error_from_errno("close");
6008 if (fd3
!= -1 && close(fd3
) == -1 && error
== NULL
)
6009 error
= got_error_from_errno("close");
6010 if (f1
&& fclose(f1
) == EOF
&& error
== NULL
)
6011 error
= got_error_from_errno("fclose");
6012 if (f2
&& fclose(f2
) == EOF
&& error
== NULL
)
6013 error
= got_error_from_errno("fclose");
6016 got_object_blob_close(blob
);
6018 got_worktree_close(worktree
);
6020 const struct got_error
*close_err
= got_repo_close(repo
);
6025 const struct got_error
*pack_err
=
6026 got_repo_pack_fds_close(pack_fds
);
6031 for (i
= 0; i
< bca
.nlines
; i
++) {
6032 struct blame_line
*bline
= &bca
.lines
[i
];
6033 free(bline
->id_str
);
6034 free(bline
->committer
);
6038 free(bca
.line_offsets
);
6039 if (bca
.f
&& fclose(bca
.f
) == EOF
&& error
== NULL
)
6040 error
= got_error_from_errno("fclose");
6047 fprintf(stderr
, "usage: %s tree [-iR] [-c commit] [-r repository-path] "
6048 "[path]\n", getprogname());
6052 static const struct got_error
*
6053 print_entry(struct got_tree_entry
*te
, const char *id
, const char *path
,
6054 const char *root_path
, struct got_repository
*repo
)
6056 const struct got_error
*err
= NULL
;
6057 int is_root_path
= (strcmp(path
, root_path
) == 0);
6058 const char *modestr
= "";
6059 mode_t mode
= got_tree_entry_get_mode(te
);
6060 char *link_target
= NULL
;
6062 path
+= strlen(root_path
);
6063 while (path
[0] == '/')
6066 if (got_object_tree_entry_is_submodule(te
))
6068 else if (S_ISLNK(mode
)) {
6071 err
= got_tree_entry_get_symlink_target(&link_target
, te
, repo
);
6074 for (i
= 0; link_target
[i
] != '\0'; i
++) {
6075 if (!isprint((unsigned char)link_target
[i
]))
6076 link_target
[i
] = '?';
6081 else if (S_ISDIR(mode
))
6083 else if (mode
& S_IXUSR
)
6086 printf("%s%s%s%s%s%s%s\n", id
? id
: "", path
,
6087 is_root_path
? "" : "/", got_tree_entry_get_name(te
), modestr
,
6088 link_target
? " -> ": "", link_target
? link_target
: "");
6094 static const struct got_error
*
6095 print_tree(const char *path
, struct got_commit_object
*commit
,
6096 int show_ids
, int recurse
, const char *root_path
,
6097 struct got_repository
*repo
)
6099 const struct got_error
*err
= NULL
;
6100 struct got_object_id
*tree_id
= NULL
;
6101 struct got_tree_object
*tree
= NULL
;
6104 err
= got_object_id_by_path(&tree_id
, repo
, commit
, path
);
6108 err
= got_object_open_as_tree(&tree
, repo
, tree_id
);
6111 nentries
= got_object_tree_get_nentries(tree
);
6112 for (i
= 0; i
< nentries
; i
++) {
6113 struct got_tree_entry
*te
;
6116 if (sigint_received
|| sigpipe_received
)
6119 te
= got_object_tree_get_entry(tree
, i
);
6122 err
= got_object_id_str(&id_str
,
6123 got_tree_entry_get_id(te
));
6126 if (asprintf(&id
, "%s ", id_str
) == -1) {
6127 err
= got_error_from_errno("asprintf");
6133 err
= print_entry(te
, id
, path
, root_path
, repo
);
6138 if (recurse
&& S_ISDIR(got_tree_entry_get_mode(te
))) {
6140 if (asprintf(&child_path
, "%s%s%s", path
,
6141 path
[0] == '/' && path
[1] == '\0' ? "" : "/",
6142 got_tree_entry_get_name(te
)) == -1) {
6143 err
= got_error_from_errno("asprintf");
6146 err
= print_tree(child_path
, commit
, show_ids
, 1,
6155 got_object_tree_close(tree
);
6160 static const struct got_error
*
6161 cmd_tree(int argc
, char *argv
[])
6163 const struct got_error
*error
;
6164 struct got_repository
*repo
= NULL
;
6165 struct got_worktree
*worktree
= NULL
;
6166 const char *path
, *refname
= NULL
;
6167 char *cwd
= NULL
, *repo_path
= NULL
, *in_repo_path
= NULL
;
6168 struct got_object_id
*commit_id
= NULL
;
6169 struct got_commit_object
*commit
= NULL
;
6170 char *commit_id_str
= NULL
, *keyword_idstr
= NULL
;
6171 int show_ids
= 0, recurse
= 0;
6173 int *pack_fds
= NULL
;
6176 if (pledge("stdio rpath wpath cpath flock proc exec sendfd unveil",
6181 while ((ch
= getopt(argc
, argv
, "c:iRr:")) != -1) {
6184 commit_id_str
= optarg
;
6193 repo_path
= realpath(optarg
, NULL
);
6194 if (repo_path
== NULL
)
6195 return got_error_from_errno2("realpath",
6197 got_path_strip_trailing_slashes(repo_path
);
6215 cwd
= getcwd(NULL
, 0);
6217 error
= got_error_from_errno("getcwd");
6221 error
= got_repo_pack_fds_open(&pack_fds
);
6225 if (repo_path
== NULL
) {
6226 error
= got_worktree_open(&worktree
, cwd
,
6227 GOT_WORKTREE_GOT_DIR
);
6228 if (error
&& error
->code
!= GOT_ERR_NOT_WORKTREE
)
6234 strdup(got_worktree_get_repo_path(worktree
));
6235 if (repo_path
== NULL
)
6236 error
= got_error_from_errno("strdup");
6240 repo_path
= strdup(cwd
);
6241 if (repo_path
== NULL
) {
6242 error
= got_error_from_errno("strdup");
6248 error
= got_repo_open(&repo
, repo_path
, NULL
, pack_fds
);
6253 const char *prefix
= got_worktree_get_path_prefix(worktree
);
6256 if (path
== NULL
|| got_path_is_root_dir(path
))
6258 error
= got_worktree_resolve_path(&p
, worktree
, path
);
6261 if (asprintf(&in_repo_path
, "%s%s%s", prefix
,
6262 (p
[0] != '\0' && !got_path_is_root_dir(prefix
)) ? "/" : "",
6264 error
= got_error_from_errno("asprintf");
6269 error
= apply_unveil(got_repo_get_path(repo
), 1, NULL
);
6273 error
= apply_unveil(got_repo_get_path(repo
), 1, NULL
);
6278 error
= got_repo_map_path(&in_repo_path
, repo
, path
);
6283 if (commit_id_str
== NULL
) {
6284 struct got_reference
*head_ref
;
6286 refname
= got_worktree_get_head_ref_name(worktree
);
6288 refname
= GOT_REF_HEAD
;
6289 error
= got_ref_open(&head_ref
, repo
, refname
, 0);
6292 error
= got_ref_resolve(&commit_id
, repo
, head_ref
);
6293 got_ref_close(head_ref
);
6297 struct got_reflist_head refs
;
6300 error
= got_ref_list(&refs
, repo
, NULL
, got_ref_cmp_by_name
,
6305 error
= got_keyword_to_idstr(&keyword_idstr
, commit_id_str
,
6309 if (keyword_idstr
!= NULL
)
6310 commit_id_str
= keyword_idstr
;
6312 error
= got_repo_match_object_id(&commit_id
, NULL
,
6313 commit_id_str
, GOT_OBJ_TYPE_COMMIT
, &refs
, repo
);
6314 got_ref_list_free(&refs
);
6320 /* Release work tree lock. */
6321 got_worktree_close(worktree
);
6325 error
= got_object_open_as_commit(&commit
, repo
, commit_id
);
6329 error
= print_tree(in_repo_path
, commit
, show_ids
, recurse
,
6330 in_repo_path
, repo
);
6332 free(keyword_idstr
);
6338 got_object_commit_close(commit
);
6340 got_worktree_close(worktree
);
6342 const struct got_error
*close_err
= got_repo_close(repo
);
6347 const struct got_error
*pack_err
=
6348 got_repo_pack_fds_close(pack_fds
);
6358 fprintf(stderr
, "usage: %s status [-I] [-S status-codes] "
6359 "[-s status-codes] [path ...]\n", getprogname());
6363 struct got_status_arg
{
6368 static const struct got_error
*
6369 print_status(void *arg
, unsigned char status
, unsigned char staged_status
,
6370 const char *path
, struct got_object_id
*blob_id
,
6371 struct got_object_id
*staged_blob_id
, struct got_object_id
*commit_id
,
6372 int dirfd
, const char *de_name
)
6374 struct got_status_arg
*st
= arg
;
6376 if (status
== staged_status
&& (status
== GOT_STATUS_DELETE
))
6377 status
= GOT_STATUS_NO_CHANGE
;
6378 if (st
!= NULL
&& st
->status_codes
) {
6379 size_t ncodes
= strlen(st
->status_codes
);
6382 for (i
= 0; i
< ncodes
; i
++) {
6384 if (status
== st
->status_codes
[i
] ||
6385 staged_status
== st
->status_codes
[i
]) {
6390 if (status
== st
->status_codes
[i
] ||
6391 staged_status
== st
->status_codes
[i
])
6396 if (st
->suppress
&& j
== 0)
6403 printf("%c%c %s\n", status
, staged_status
, path
);
6407 static const struct got_error
*
6408 cmd_status(int argc
, char *argv
[])
6410 const struct got_error
*error
= NULL
;
6411 struct got_repository
*repo
= NULL
;
6412 struct got_worktree
*worktree
= NULL
;
6413 struct got_status_arg st
;
6415 struct got_pathlist_head paths
;
6416 int ch
, i
, no_ignores
= 0;
6417 int *pack_fds
= NULL
;
6421 memset(&st
, 0, sizeof(st
));
6422 st
.status_codes
= NULL
;
6426 if (pledge("stdio rpath wpath cpath flock proc exec sendfd unveil",
6431 while ((ch
= getopt(argc
, argv
, "IS:s:")) != -1) {
6437 if (st
.status_codes
!= NULL
&& st
.suppress
== 0)
6438 option_conflict('S', 's');
6442 for (i
= 0; optarg
[i
] != '\0'; i
++) {
6443 switch (optarg
[i
]) {
6444 case GOT_STATUS_MODIFY
:
6445 case GOT_STATUS_ADD
:
6446 case GOT_STATUS_DELETE
:
6447 case GOT_STATUS_CONFLICT
:
6448 case GOT_STATUS_MISSING
:
6449 case GOT_STATUS_OBSTRUCTED
:
6450 case GOT_STATUS_UNVERSIONED
:
6451 case GOT_STATUS_MODE_CHANGE
:
6452 case GOT_STATUS_NONEXISTENT
:
6455 errx(1, "invalid status code '%c'",
6459 if (ch
== 's' && st
.suppress
)
6460 option_conflict('s', 'S');
6461 st
.status_codes
= optarg
;
6472 cwd
= getcwd(NULL
, 0);
6474 error
= got_error_from_errno("getcwd");
6478 error
= got_repo_pack_fds_open(&pack_fds
);
6482 error
= got_worktree_open(&worktree
, cwd
,
6483 GOT_WORKTREE_GOT_DIR
);
6485 if (error
->code
== GOT_ERR_NOT_WORKTREE
)
6486 error
= wrap_not_worktree_error(error
, "status", cwd
);
6490 error
= got_repo_open(&repo
, got_worktree_get_repo_path(worktree
),
6495 error
= apply_unveil(got_repo_get_path(repo
), 1,
6496 got_worktree_get_root_path(worktree
));
6500 error
= get_worktree_paths_from_argv(&paths
, argc
, argv
, worktree
);
6504 error
= got_worktree_status(worktree
, &paths
, repo
, no_ignores
,
6505 print_status
, &st
, check_cancelled
, NULL
);
6508 const struct got_error
*pack_err
=
6509 got_repo_pack_fds_close(pack_fds
);
6514 const struct got_error
*close_err
= got_repo_close(repo
);
6519 got_pathlist_free(&paths
, GOT_PATHLIST_FREE_PATH
);
6527 fprintf(stderr
, "usage: %s ref [-dlt] [-c object] [-r repository-path] "
6528 "[-s reference] [name]\n", getprogname());
6532 static const struct got_error
*
6533 list_refs(struct got_repository
*repo
, const char *refname
, int sort_by_time
)
6535 static const struct got_error
*err
= NULL
;
6536 struct got_reflist_head refs
;
6537 struct got_reflist_entry
*re
;
6540 err
= got_ref_list(&refs
, repo
, refname
, sort_by_time
?
6541 got_ref_cmp_by_commit_timestamp_descending
: got_ref_cmp_by_name
,
6546 TAILQ_FOREACH(re
, &refs
, entry
) {
6548 refstr
= got_ref_to_str(re
->ref
);
6549 if (refstr
== NULL
) {
6550 err
= got_error_from_errno("got_ref_to_str");
6553 printf("%s: %s\n", got_ref_get_name(re
->ref
), refstr
);
6557 got_ref_list_free(&refs
);
6561 static const struct got_error
*
6562 delete_ref_by_name(struct got_repository
*repo
, const char *refname
)
6564 const struct got_error
*err
;
6565 struct got_reference
*ref
;
6567 err
= got_ref_open(&ref
, repo
, refname
, 0);
6571 err
= delete_ref(repo
, ref
);
6576 static const struct got_error
*
6577 add_ref(struct got_repository
*repo
, const char *refname
, const char *target
)
6579 const struct got_error
*err
= NULL
;
6580 struct got_object_id
*id
= NULL
;
6581 struct got_reference
*ref
= NULL
;
6582 struct got_reflist_head refs
;
6585 * Don't let the user create a reference name with a leading '-'.
6586 * While technically a valid reference name, this case is usually
6587 * an unintended typo.
6589 if (refname
[0] == '-')
6590 return got_error_path(refname
, GOT_ERR_REF_NAME_MINUS
);
6593 err
= got_ref_list(&refs
, repo
, NULL
, got_ref_cmp_by_name
, NULL
);
6596 err
= got_repo_match_object_id(&id
, NULL
, target
, GOT_OBJ_TYPE_ANY
,
6598 got_ref_list_free(&refs
);
6602 err
= got_ref_alloc(&ref
, refname
, id
);
6606 err
= got_ref_write(ref
, repo
);
6614 static const struct got_error
*
6615 add_symref(struct got_repository
*repo
, const char *refname
, const char *target
)
6617 const struct got_error
*err
= NULL
;
6618 struct got_reference
*ref
= NULL
;
6619 struct got_reference
*target_ref
= NULL
;
6622 * Don't let the user create a reference name with a leading '-'.
6623 * While technically a valid reference name, this case is usually
6624 * an unintended typo.
6626 if (refname
[0] == '-')
6627 return got_error_path(refname
, GOT_ERR_REF_NAME_MINUS
);
6629 err
= got_ref_open(&target_ref
, repo
, target
, 0);
6633 err
= got_ref_alloc_symref(&ref
, refname
, target_ref
);
6637 err
= got_ref_write(ref
, repo
);
6640 got_ref_close(target_ref
);
6646 static const struct got_error
*
6647 cmd_ref(int argc
, char *argv
[])
6649 const struct got_error
*error
= NULL
;
6650 struct got_repository
*repo
= NULL
;
6651 struct got_worktree
*worktree
= NULL
;
6652 char *cwd
= NULL
, *repo_path
= NULL
;
6653 int ch
, do_list
= 0, do_delete
= 0, sort_by_time
= 0;
6654 const char *obj_arg
= NULL
, *symref_target
= NULL
;
6655 char *refname
= NULL
, *keyword_idstr
= NULL
;
6656 int *pack_fds
= NULL
;
6659 if (pledge("stdio rpath wpath cpath fattr flock proc exec "
6660 "sendfd unveil", NULL
) == -1)
6664 while ((ch
= getopt(argc
, argv
, "c:dlr:s:t")) != -1) {
6676 repo_path
= realpath(optarg
, NULL
);
6677 if (repo_path
== NULL
)
6678 return got_error_from_errno2("realpath",
6680 got_path_strip_trailing_slashes(repo_path
);
6683 symref_target
= optarg
;
6694 if (obj_arg
&& do_list
)
6695 option_conflict('c', 'l');
6696 if (obj_arg
&& do_delete
)
6697 option_conflict('c', 'd');
6698 if (obj_arg
&& symref_target
)
6699 option_conflict('c', 's');
6700 if (symref_target
&& do_delete
)
6701 option_conflict('s', 'd');
6702 if (symref_target
&& do_list
)
6703 option_conflict('s', 'l');
6704 if (do_delete
&& do_list
)
6705 option_conflict('d', 'l');
6706 if (sort_by_time
&& !do_list
)
6707 errx(1, "-t option requires -l option");
6713 if (argc
!= 0 && argc
!= 1)
6716 refname
= strdup(argv
[0]);
6717 if (refname
== NULL
) {
6718 error
= got_error_from_errno("strdup");
6725 refname
= strdup(argv
[0]);
6726 if (refname
== NULL
) {
6727 error
= got_error_from_errno("strdup");
6733 got_path_strip_trailing_slashes(refname
);
6735 cwd
= getcwd(NULL
, 0);
6737 error
= got_error_from_errno("getcwd");
6741 error
= got_repo_pack_fds_open(&pack_fds
);
6745 if (repo_path
== NULL
) {
6746 error
= got_worktree_open(&worktree
, cwd
,
6747 GOT_WORKTREE_GOT_DIR
);
6748 if (error
&& error
->code
!= GOT_ERR_NOT_WORKTREE
)
6754 strdup(got_worktree_get_repo_path(worktree
));
6755 if (repo_path
== NULL
)
6756 error
= got_error_from_errno("strdup");
6760 repo_path
= strdup(cwd
);
6761 if (repo_path
== NULL
) {
6762 error
= got_error_from_errno("strdup");
6768 error
= got_repo_open(&repo
, repo_path
, NULL
, pack_fds
);
6774 /* Remove "cpath" promise. */
6775 if (pledge("stdio rpath wpath flock proc exec sendfd unveil",
6781 error
= apply_unveil(got_repo_get_path(repo
), do_list
,
6782 worktree
? got_worktree_get_root_path(worktree
) : NULL
);
6787 error
= list_refs(repo
, refname
, sort_by_time
);
6789 error
= delete_ref_by_name(repo
, refname
);
6790 else if (symref_target
)
6791 error
= add_symref(repo
, refname
, symref_target
);
6793 if (obj_arg
== NULL
)
6796 error
= got_keyword_to_idstr(&keyword_idstr
, obj_arg
,
6800 if (keyword_idstr
!= NULL
)
6801 obj_arg
= keyword_idstr
;
6803 error
= add_ref(repo
, refname
, obj_arg
);
6808 const struct got_error
*close_err
= got_repo_close(repo
);
6813 got_worktree_close(worktree
);
6815 const struct got_error
*pack_err
=
6816 got_repo_pack_fds_close(pack_fds
);
6822 free(keyword_idstr
);
6829 fprintf(stderr
, "usage: %s branch [-lnt] [-c commit] [-d name] "
6830 "[-r repository-path] [name]\n", getprogname());
6834 static const struct got_error
*
6835 list_branch(struct got_repository
*repo
, struct got_worktree
*worktree
,
6836 struct got_reference
*ref
)
6838 const struct got_error
*err
= NULL
;
6839 const char *refname
;
6843 refname
= got_ref_get_name(ref
);
6844 if (worktree
&& strcmp(refname
,
6845 got_worktree_get_head_ref_name(worktree
)) == 0) {
6846 err
= got_worktree_get_state(&marker
, repo
, worktree
,
6847 check_cancelled
, NULL
);
6852 if (strncmp(refname
, "refs/heads/", 11) == 0)
6854 if (strncmp(refname
, "refs/got/worktree/", 18) == 0)
6856 if (strncmp(refname
, "refs/remotes/", 13) == 0)
6859 refstr
= got_ref_to_str(ref
);
6861 return got_error_from_errno("got_ref_to_str");
6863 printf("%c %s: %s\n", marker
, refname
, refstr
);
6868 static const struct got_error
*
6869 show_current_branch(struct got_repository
*repo
, struct got_worktree
*worktree
)
6871 const char *refname
;
6873 if (worktree
== NULL
)
6874 return got_error(GOT_ERR_NOT_WORKTREE
);
6876 refname
= got_worktree_get_head_ref_name(worktree
);
6878 if (strncmp(refname
, "refs/heads/", 11) == 0)
6880 if (strncmp(refname
, "refs/got/worktree/", 18) == 0)
6883 printf("%s\n", refname
);
6888 static const struct got_error
*
6889 list_branches(struct got_repository
*repo
, struct got_worktree
*worktree
,
6892 static const struct got_error
*err
= NULL
;
6893 struct got_reflist_head refs
;
6894 struct got_reflist_entry
*re
;
6895 struct got_reference
*temp_ref
= NULL
;
6896 int rebase_in_progress
, histedit_in_progress
;
6901 err
= got_worktree_rebase_in_progress(&rebase_in_progress
,
6906 err
= got_worktree_histedit_in_progress(&histedit_in_progress
,
6911 if (rebase_in_progress
|| histedit_in_progress
) {
6912 err
= got_ref_open(&temp_ref
, repo
,
6913 got_worktree_get_head_ref_name(worktree
), 0);
6916 list_branch(repo
, worktree
, temp_ref
);
6917 got_ref_close(temp_ref
);
6921 err
= got_ref_list(&refs
, repo
, "refs/heads", sort_by_time
?
6922 got_ref_cmp_by_commit_timestamp_descending
: got_ref_cmp_by_name
,
6927 TAILQ_FOREACH(re
, &refs
, entry
)
6928 list_branch(repo
, worktree
, re
->ref
);
6930 got_ref_list_free(&refs
);
6932 err
= got_ref_list(&refs
, repo
, "refs/remotes", sort_by_time
?
6933 got_ref_cmp_by_commit_timestamp_descending
: got_ref_cmp_by_name
,
6938 TAILQ_FOREACH(re
, &refs
, entry
)
6939 list_branch(repo
, worktree
, re
->ref
);
6941 got_ref_list_free(&refs
);
6946 static const struct got_error
*
6947 delete_branch(struct got_repository
*repo
, struct got_worktree
*worktree
,
6948 const char *branch_name
)
6950 const struct got_error
*err
= NULL
;
6951 struct got_reference
*ref
= NULL
;
6952 char *refname
, *remote_refname
= NULL
;
6954 if (strncmp(branch_name
, "refs/", 5) == 0)
6956 if (strncmp(branch_name
, "heads/", 6) == 0)
6958 else if (strncmp(branch_name
, "remotes/", 8) == 0)
6961 if (asprintf(&refname
, "refs/heads/%s", branch_name
) == -1)
6962 return got_error_from_errno("asprintf");
6964 if (asprintf(&remote_refname
, "refs/remotes/%s",
6965 branch_name
) == -1) {
6966 err
= got_error_from_errno("asprintf");
6970 err
= got_ref_open(&ref
, repo
, refname
, 0);
6972 const struct got_error
*err2
;
6973 if (err
->code
!= GOT_ERR_NOT_REF
)
6976 * Keep 'err' intact such that if neither branch exists
6977 * we report "refs/heads" rather than "refs/remotes" in
6978 * our error message.
6980 err2
= got_ref_open(&ref
, repo
, remote_refname
, 0);
6987 strcmp(got_worktree_get_head_ref_name(worktree
),
6988 got_ref_get_name(ref
)) == 0) {
6989 err
= got_error_msg(GOT_ERR_SAME_BRANCH
,
6990 "will not delete this work tree's current branch");
6994 err
= delete_ref(repo
, ref
);
6999 free(remote_refname
);
7003 static const struct got_error
*
7004 add_branch(struct got_repository
*repo
, const char *branch_name
,
7005 struct got_object_id
*base_commit_id
)
7007 const struct got_error
*err
= NULL
;
7008 struct got_reference
*ref
= NULL
;
7009 char *refname
= NULL
;
7012 * Don't let the user create a branch name with a leading '-'.
7013 * While technically a valid reference name, this case is usually
7014 * an unintended typo.
7016 if (branch_name
[0] == '-')
7017 return got_error_path(branch_name
, GOT_ERR_REF_NAME_MINUS
);
7019 if (strncmp(branch_name
, "refs/heads/", 11) == 0)
7022 if (asprintf(&refname
, "refs/heads/%s", branch_name
) == -1) {
7023 err
= got_error_from_errno("asprintf");
7027 err
= got_ref_open(&ref
, repo
, refname
, 0);
7029 err
= got_error(GOT_ERR_BRANCH_EXISTS
);
7031 } else if (err
->code
!= GOT_ERR_NOT_REF
)
7034 err
= got_ref_alloc(&ref
, refname
, base_commit_id
);
7038 err
= got_ref_write(ref
, repo
);
7046 static const struct got_error
*
7047 cmd_branch(int argc
, char *argv
[])
7049 const struct got_error
*error
= NULL
;
7050 struct got_repository
*repo
= NULL
;
7051 struct got_worktree
*worktree
= NULL
;
7052 char *cwd
= NULL
, *repo_path
= NULL
;
7053 int ch
, do_list
= 0, do_show
= 0, do_update
= 1, sort_by_time
= 0;
7054 const char *delref
= NULL
, *commit_id_arg
= NULL
;
7055 struct got_reference
*ref
= NULL
;
7056 struct got_pathlist_head paths
;
7057 struct got_object_id
*commit_id
= NULL
;
7058 char *commit_id_str
= NULL
, *keyword_idstr
= NULL
;;
7059 int *pack_fds
= NULL
;
7064 if (pledge("stdio rpath wpath cpath fattr flock proc exec "
7065 "sendfd unveil", NULL
) == -1)
7069 while ((ch
= getopt(argc
, argv
, "c:d:lnr:t")) != -1) {
7072 commit_id_arg
= optarg
;
7084 repo_path
= realpath(optarg
, NULL
);
7085 if (repo_path
== NULL
)
7086 return got_error_from_errno2("realpath",
7088 got_path_strip_trailing_slashes(repo_path
);
7099 if (do_list
&& delref
)
7100 option_conflict('l', 'd');
7101 if (sort_by_time
&& !do_list
)
7102 errx(1, "-t option requires -l option");
7107 if (!do_list
&& !delref
&& argc
== 0)
7110 if ((do_list
|| delref
|| do_show
) && commit_id_arg
!= NULL
)
7111 errx(1, "-c option can only be used when creating a branch");
7113 if (do_list
|| delref
) {
7116 } else if (!do_show
&& argc
!= 1)
7119 cwd
= getcwd(NULL
, 0);
7121 error
= got_error_from_errno("getcwd");
7125 error
= got_repo_pack_fds_open(&pack_fds
);
7129 if (repo_path
== NULL
) {
7130 error
= got_worktree_open(&worktree
, cwd
,
7131 GOT_WORKTREE_GOT_DIR
);
7132 if (error
&& error
->code
!= GOT_ERR_NOT_WORKTREE
)
7138 strdup(got_worktree_get_repo_path(worktree
));
7139 if (repo_path
== NULL
)
7140 error
= got_error_from_errno("strdup");
7144 repo_path
= strdup(cwd
);
7145 if (repo_path
== NULL
) {
7146 error
= got_error_from_errno("strdup");
7152 error
= got_repo_open(&repo
, repo_path
, NULL
, pack_fds
);
7157 if (do_list
|| do_show
) {
7158 /* Remove "cpath" promise. */
7159 if (pledge("stdio rpath wpath flock proc exec sendfd unveil",
7165 error
= apply_unveil(got_repo_get_path(repo
), do_list
,
7166 worktree
? got_worktree_get_root_path(worktree
) : NULL
);
7171 error
= show_current_branch(repo
, worktree
);
7173 error
= list_branches(repo
, worktree
, sort_by_time
);
7175 error
= delete_branch(repo
, worktree
, delref
);
7177 struct got_reflist_head refs
;
7179 error
= got_ref_list(&refs
, repo
, NULL
, got_ref_cmp_by_name
,
7183 if (commit_id_arg
== NULL
)
7184 commit_id_arg
= worktree
?
7185 got_worktree_get_head_ref_name(worktree
) :
7188 error
= got_keyword_to_idstr(&keyword_idstr
,
7189 commit_id_arg
, repo
, worktree
);
7192 if (keyword_idstr
!= NULL
)
7193 commit_id_arg
= keyword_idstr
;
7195 error
= got_repo_match_object_id(&commit_id
, NULL
,
7196 commit_id_arg
, GOT_OBJ_TYPE_COMMIT
, &refs
, repo
);
7197 got_ref_list_free(&refs
);
7200 error
= add_branch(repo
, argv
[0], commit_id
);
7203 if (worktree
&& do_update
) {
7204 struct got_update_progress_arg upa
;
7205 char *branch_refname
= NULL
;
7207 error
= got_object_id_str(&commit_id_str
, commit_id
);
7210 error
= get_worktree_paths_from_argv(&paths
, 0, NULL
,
7214 if (asprintf(&branch_refname
, "refs/heads/%s", argv
[0])
7216 error
= got_error_from_errno("asprintf");
7219 error
= got_ref_open(&ref
, repo
, branch_refname
, 0);
7220 free(branch_refname
);
7223 error
= switch_head_ref(ref
, commit_id
, worktree
,
7227 error
= got_worktree_set_base_commit_id(worktree
, repo
,
7231 memset(&upa
, 0, sizeof(upa
));
7232 error
= got_worktree_checkout_files(worktree
, &paths
,
7233 repo
, update_progress
, &upa
, check_cancelled
,
7237 if (upa
.did_something
) {
7238 printf("Updated to %s: %s\n",
7239 got_worktree_get_head_ref_name(worktree
),
7242 print_update_progress_stats(&upa
);
7246 free(keyword_idstr
);
7250 const struct got_error
*close_err
= got_repo_close(repo
);
7255 got_worktree_close(worktree
);
7257 const struct got_error
*pack_err
=
7258 got_repo_pack_fds_close(pack_fds
);
7265 free(commit_id_str
);
7266 got_pathlist_free(&paths
, GOT_PATHLIST_FREE_PATH
);
7274 fprintf(stderr
, "usage: %s tag [-lVv] [-c commit] [-m message] "
7275 "[-r repository-path] [-s signer-id] name\n", getprogname());
7280 static const struct got_error
*
7281 sort_tags(struct got_reflist_head
*sorted
, struct got_reflist_head
*tags
)
7283 const struct got_error
*err
= NULL
;
7284 struct got_reflist_entry
*re
, *se
, *new;
7285 struct got_object_id
*re_id
, *se_id
;
7286 struct got_tag_object
*re_tag
, *se_tag
;
7287 time_t re_time
, se_time
;
7289 STAILQ_FOREACH(re
, tags
, entry
) {
7290 se
= STAILQ_FIRST(sorted
);
7292 err
= got_reflist_entry_dup(&new, re
);
7295 STAILQ_INSERT_HEAD(sorted
, new, entry
);
7298 err
= got_ref_resolve(&re_id
, repo
, re
->ref
);
7301 err
= got_object_open_as_tag(&re_tag
, repo
, re_id
);
7305 re_time
= got_object_tag_get_tagger_time(re_tag
);
7306 got_object_tag_close(re_tag
);
7310 err
= got_ref_resolve(&se_id
, repo
, re
->ref
);
7313 err
= got_object_open_as_tag(&se_tag
, repo
, se_id
);
7317 se_time
= got_object_tag_get_tagger_time(se_tag
);
7318 got_object_tag_close(se_tag
);
7320 if (se_time
> re_time
) {
7321 err
= got_reflist_entry_dup(&new, re
);
7324 STAILQ_INSERT_AFTER(sorted
, se
, new, entry
);
7327 se
= STAILQ_NEXT(se
, entry
);
7336 static const struct got_error
*
7337 get_tag_refname(char **refname
, const char *tag_name
)
7339 const struct got_error
*err
;
7341 if (strncmp("refs/tags/", tag_name
, 10) == 0) {
7342 *refname
= strdup(tag_name
);
7343 if (*refname
== NULL
)
7344 return got_error_from_errno("strdup");
7345 } else if (asprintf(refname
, "refs/tags/%s", tag_name
) == -1) {
7346 err
= got_error_from_errno("asprintf");
7354 static const struct got_error
*
7355 list_tags(struct got_repository
*repo
, const char *tag_name
, int verify_tags
,
7356 const char *allowed_signers
, const char *revoked_signers
, int verbosity
)
7358 static const struct got_error
*err
= NULL
;
7359 struct got_reflist_head refs
;
7360 struct got_reflist_entry
*re
;
7361 char *wanted_refname
= NULL
;
7366 err
= got_ref_list(&refs
, repo
, "refs/tags", got_ref_cmp_tags
, repo
);
7371 struct got_reference
*ref
;
7372 err
= get_tag_refname(&wanted_refname
, tag_name
);
7375 /* Wanted tag reference should exist. */
7376 err
= got_ref_open(&ref
, repo
, wanted_refname
, 0);
7382 TAILQ_FOREACH(re
, &refs
, entry
) {
7383 const char *refname
;
7384 char *refstr
, *tagmsg0
, *tagmsg
, *line
, *id_str
, *datestr
;
7386 const char *tagger
, *ssh_sig
= NULL
;
7387 char *sig_msg
= NULL
;
7389 struct got_object_id
*id
;
7390 struct got_tag_object
*tag
;
7391 struct got_commit_object
*commit
= NULL
;
7393 refname
= got_ref_get_name(re
->ref
);
7394 if (strncmp(refname
, "refs/tags/", 10) != 0 ||
7395 (wanted_refname
&& strcmp(refname
, wanted_refname
) != 0))
7398 refstr
= got_ref_to_str(re
->ref
);
7399 if (refstr
== NULL
) {
7400 err
= got_error_from_errno("got_ref_to_str");
7404 err
= got_ref_resolve(&id
, repo
, re
->ref
);
7407 err
= got_object_open_as_tag(&tag
, repo
, id
);
7409 if (err
->code
!= GOT_ERR_OBJ_TYPE
) {
7413 /* "lightweight" tag */
7414 err
= got_object_open_as_commit(&commit
, repo
, id
);
7419 tagger
= got_object_commit_get_committer(commit
);
7421 got_object_commit_get_committer_time(commit
);
7422 err
= got_object_id_str(&id_str
, id
);
7428 tagger
= got_object_tag_get_tagger(tag
);
7429 tagger_time
= got_object_tag_get_tagger_time(tag
);
7430 err
= got_object_id_str(&id_str
,
7431 got_object_tag_get_object_id(tag
));
7436 if (tag
&& verify_tags
) {
7437 ssh_sig
= got_sigs_get_tagmsg_ssh_signature(
7438 got_object_tag_get_message(tag
));
7439 if (ssh_sig
&& allowed_signers
== NULL
) {
7440 err
= got_error_msg(
7441 GOT_ERR_VERIFY_TAG_SIGNATURE
,
7442 "SSH signature verification requires "
7443 "setting allowed_signers in "
7449 printf("%stag %s %s\n", GOT_COMMIT_SEP_STR
, refname
, refstr
);
7451 printf("from: %s\n", tagger
);
7452 datestr
= get_datestr(&tagger_time
, datebuf
);
7454 printf("date: %s UTC\n", datestr
);
7456 printf("object: %s %s\n", GOT_OBJ_LABEL_COMMIT
, id_str
);
7458 switch (got_object_tag_get_object_type(tag
)) {
7459 case GOT_OBJ_TYPE_BLOB
:
7460 printf("object: %s %s\n", GOT_OBJ_LABEL_BLOB
,
7463 case GOT_OBJ_TYPE_TREE
:
7464 printf("object: %s %s\n", GOT_OBJ_LABEL_TREE
,
7467 case GOT_OBJ_TYPE_COMMIT
:
7468 printf("object: %s %s\n", GOT_OBJ_LABEL_COMMIT
,
7471 case GOT_OBJ_TYPE_TAG
:
7472 printf("object: %s %s\n", GOT_OBJ_LABEL_TAG
,
7482 err
= got_sigs_verify_tag_ssh(&sig_msg
, tag
, ssh_sig
,
7483 allowed_signers
, revoked_signers
, verbosity
);
7484 if (err
&& err
->code
== GOT_ERR_BAD_TAG_SIGNATURE
)
7488 printf("signature: %s", sig_msg
);
7494 err
= got_object_commit_get_logmsg(&tagmsg0
, commit
);
7497 got_object_commit_close(commit
);
7499 tagmsg0
= strdup(got_object_tag_get_message(tag
));
7500 got_object_tag_close(tag
);
7501 if (tagmsg0
== NULL
) {
7502 err
= got_error_from_errno("strdup");
7509 line
= strsep(&tagmsg
, "\n");
7511 printf(" %s\n", line
);
7516 got_ref_list_free(&refs
);
7517 free(wanted_refname
);
7519 if (err
== NULL
&& bad_sigs
)
7520 err
= got_error(GOT_ERR_BAD_TAG_SIGNATURE
);
7524 static const struct got_error
*
7525 get_tag_message(char **tagmsg
, char **tagmsg_path
, const char *commit_id_str
,
7526 const char *tag_name
, const char *repo_path
)
7528 const struct got_error
*err
= NULL
;
7529 char *template = NULL
, *initial_content
= NULL
;
7530 char *editor
= NULL
;
7531 int initial_content_len
;
7534 if (asprintf(&template, GOT_TMPDIR_STR
"/got-tagmsg") == -1) {
7535 err
= got_error_from_errno("asprintf");
7539 initial_content_len
= asprintf(&initial_content
,
7540 "\n# tagging commit %s as %s\n",
7541 commit_id_str
, tag_name
);
7542 if (initial_content_len
== -1) {
7543 err
= got_error_from_errno("asprintf");
7547 err
= got_opentemp_named_fd(tagmsg_path
, &fd
, template, "");
7551 if (write(fd
, initial_content
, initial_content_len
) == -1) {
7552 err
= got_error_from_errno2("write", *tagmsg_path
);
7555 if (close(fd
) == -1) {
7556 err
= got_error_from_errno2("close", *tagmsg_path
);
7561 err
= get_editor(&editor
);
7564 err
= edit_logmsg(tagmsg
, editor
, *tagmsg_path
, initial_content
,
7565 initial_content_len
, 1);
7567 free(initial_content
);
7571 if (fd
!= -1 && close(fd
) == -1 && err
== NULL
)
7572 err
= got_error_from_errno2("close", *tagmsg_path
);
7581 static const struct got_error
*
7582 add_tag(struct got_repository
*repo
, const char *tagger
,
7583 const char *tag_name
, const char *commit_arg
, const char *tagmsg_arg
,
7584 const char *signer_id
, int verbosity
)
7586 const struct got_error
*err
= NULL
;
7587 struct got_object_id
*commit_id
= NULL
, *tag_id
= NULL
;
7588 char *label
= NULL
, *commit_id_str
= NULL
;
7589 struct got_reference
*ref
= NULL
;
7590 char *refname
= NULL
, *tagmsg
= NULL
;
7591 char *tagmsg_path
= NULL
, *tag_id_str
= NULL
;
7592 int preserve_tagmsg
= 0;
7593 struct got_reflist_head refs
;
7598 * Don't let the user create a tag name with a leading '-'.
7599 * While technically a valid reference name, this case is usually
7600 * an unintended typo.
7602 if (tag_name
[0] == '-')
7603 return got_error_path(tag_name
, GOT_ERR_REF_NAME_MINUS
);
7605 err
= got_ref_list(&refs
, repo
, NULL
, got_ref_cmp_by_name
, NULL
);
7609 err
= got_repo_match_object_id(&commit_id
, &label
, commit_arg
,
7610 GOT_OBJ_TYPE_COMMIT
, &refs
, repo
);
7614 err
= got_object_id_str(&commit_id_str
, commit_id
);
7618 err
= get_tag_refname(&refname
, tag_name
);
7621 if (strncmp("refs/tags/", tag_name
, 10) == 0)
7624 err
= got_ref_open(&ref
, repo
, refname
, 0);
7626 err
= got_error(GOT_ERR_TAG_EXISTS
);
7628 } else if (err
->code
!= GOT_ERR_NOT_REF
)
7631 if (tagmsg_arg
== NULL
) {
7632 err
= get_tag_message(&tagmsg
, &tagmsg_path
, commit_id_str
,
7633 tag_name
, got_repo_get_path(repo
));
7635 if (err
->code
!= GOT_ERR_COMMIT_MSG_EMPTY
&&
7636 tagmsg_path
!= NULL
)
7637 preserve_tagmsg
= 1;
7640 /* Editor is done; we can now apply unveil(2) */
7641 err
= got_sigs_apply_unveil();
7644 err
= apply_unveil(got_repo_get_path(repo
), 0, NULL
);
7649 err
= got_object_tag_create(&tag_id
, tag_name
, commit_id
,
7650 tagger
, time(NULL
), tagmsg
? tagmsg
: tagmsg_arg
, signer_id
, repo
,
7654 preserve_tagmsg
= 1;
7658 err
= got_ref_alloc(&ref
, refname
, tag_id
);
7661 preserve_tagmsg
= 1;
7665 err
= got_ref_write(ref
, repo
);
7668 preserve_tagmsg
= 1;
7672 err
= got_object_id_str(&tag_id_str
, tag_id
);
7675 preserve_tagmsg
= 1;
7678 printf("Created tag %s\n", tag_id_str
);
7680 if (preserve_tagmsg
) {
7681 fprintf(stderr
, "%s: tag message preserved in %s\n",
7682 getprogname(), tagmsg_path
);
7683 } else if (tagmsg_path
&& unlink(tagmsg_path
) == -1 && err
== NULL
)
7684 err
= got_error_from_errno2("unlink", tagmsg_path
);
7689 free(commit_id_str
);
7693 got_ref_list_free(&refs
);
7697 static const struct got_error
*
7698 cmd_tag(int argc
, char *argv
[])
7700 const struct got_error
*error
= NULL
;
7701 struct got_repository
*repo
= NULL
;
7702 struct got_worktree
*worktree
= NULL
;
7703 char *cwd
= NULL
, *repo_path
= NULL
, *commit_id_str
= NULL
;
7704 char *gitconfig_path
= NULL
, *tagger
= NULL
, *keyword_idstr
= NULL
;
7705 char *allowed_signers
= NULL
, *revoked_signers
= NULL
;
7706 const char *signer_id
= NULL
;
7707 const char *tag_name
= NULL
, *commit_id_arg
= NULL
, *tagmsg
= NULL
;
7708 int ch
, do_list
= 0, verify_tags
= 0, verbosity
= 0;
7709 int *pack_fds
= NULL
;
7712 if (pledge("stdio rpath wpath cpath fattr flock proc exec "
7713 "sendfd unveil", NULL
) == -1)
7717 while ((ch
= getopt(argc
, argv
, "c:lm:r:s:Vv")) != -1) {
7720 commit_id_arg
= optarg
;
7729 repo_path
= realpath(optarg
, NULL
);
7730 if (repo_path
== NULL
) {
7731 error
= got_error_from_errno2("realpath",
7735 got_path_strip_trailing_slashes(repo_path
);
7746 else if (verbosity
< 3)
7758 if (do_list
|| verify_tags
) {
7759 if (commit_id_arg
!= NULL
)
7761 "-c option can only be used when creating a tag");
7764 option_conflict('l', 'm');
7766 option_conflict('V', 'm');
7770 option_conflict('l', 's');
7772 option_conflict('V', 's');
7776 } else if (argc
!= 1)
7782 cwd
= getcwd(NULL
, 0);
7784 error
= got_error_from_errno("getcwd");
7788 error
= got_repo_pack_fds_open(&pack_fds
);
7792 if (repo_path
== NULL
) {
7793 error
= got_worktree_open(&worktree
, cwd
,
7794 GOT_WORKTREE_GOT_DIR
);
7795 if (error
&& error
->code
!= GOT_ERR_NOT_WORKTREE
)
7801 strdup(got_worktree_get_repo_path(worktree
));
7802 if (repo_path
== NULL
)
7803 error
= got_error_from_errno("strdup");
7807 repo_path
= strdup(cwd
);
7808 if (repo_path
== NULL
) {
7809 error
= got_error_from_errno("strdup");
7815 if (do_list
|| verify_tags
) {
7816 error
= got_repo_open(&repo
, repo_path
, NULL
, pack_fds
);
7819 error
= get_allowed_signers(&allowed_signers
, repo
, worktree
);
7822 error
= get_revoked_signers(&revoked_signers
, repo
, worktree
);
7826 /* Release work tree lock. */
7827 got_worktree_close(worktree
);
7832 * Remove "cpath" promise unless needed for signature tmpfile
7836 got_sigs_apply_unveil();
7839 if (pledge("stdio rpath wpath flock proc exec sendfd "
7840 "unveil", NULL
) == -1)
7844 error
= apply_unveil(got_repo_get_path(repo
), 1, NULL
);
7847 error
= list_tags(repo
, tag_name
, verify_tags
, allowed_signers
,
7848 revoked_signers
, verbosity
);
7850 error
= get_gitconfig_path(&gitconfig_path
);
7853 error
= got_repo_open(&repo
, repo_path
, gitconfig_path
,
7858 error
= get_author(&tagger
, repo
, worktree
);
7861 if (signer_id
== NULL
)
7862 signer_id
= get_signer_id(repo
, worktree
);
7866 error
= got_sigs_apply_unveil();
7870 error
= apply_unveil(got_repo_get_path(repo
), 0, NULL
);
7875 if (commit_id_arg
== NULL
) {
7876 struct got_reference
*head_ref
;
7877 struct got_object_id
*commit_id
;
7878 error
= got_ref_open(&head_ref
, repo
,
7879 worktree
? got_worktree_get_head_ref_name(worktree
)
7883 error
= got_ref_resolve(&commit_id
, repo
, head_ref
);
7884 got_ref_close(head_ref
);
7887 error
= got_object_id_str(&commit_id_str
, commit_id
);
7892 error
= got_keyword_to_idstr(&keyword_idstr
,
7893 commit_id_arg
, repo
, worktree
);
7896 commit_id_str
= keyword_idstr
;
7900 /* Release work tree lock. */
7901 got_worktree_close(worktree
);
7905 error
= add_tag(repo
, tagger
, tag_name
,
7906 commit_id_str
? commit_id_str
: commit_id_arg
, tagmsg
,
7907 signer_id
, verbosity
);
7911 const struct got_error
*close_err
= got_repo_close(repo
);
7916 got_worktree_close(worktree
);
7918 const struct got_error
*pack_err
=
7919 got_repo_pack_fds_close(pack_fds
);
7925 free(gitconfig_path
);
7926 free(commit_id_str
);
7928 free(allowed_signers
);
7929 free(revoked_signers
);
7936 fprintf(stderr
, "usage: %s add [-IR] path ...\n", getprogname());
7940 static const struct got_error
*
7941 add_progress(void *arg
, unsigned char status
, const char *path
)
7943 while (path
[0] == '/')
7945 printf("%c %s\n", status
, path
);
7949 static const struct got_error
*
7950 cmd_add(int argc
, char *argv
[])
7952 const struct got_error
*error
= NULL
;
7953 struct got_repository
*repo
= NULL
;
7954 struct got_worktree
*worktree
= NULL
;
7956 struct got_pathlist_head paths
;
7957 struct got_pathlist_entry
*pe
;
7958 int ch
, can_recurse
= 0, no_ignores
= 0;
7959 int *pack_fds
= NULL
;
7964 if (pledge("stdio rpath wpath cpath flock proc exec sendfd unveil",
7969 while ((ch
= getopt(argc
, argv
, "IR")) != -1) {
7989 cwd
= getcwd(NULL
, 0);
7991 error
= got_error_from_errno("getcwd");
7995 error
= got_repo_pack_fds_open(&pack_fds
);
7999 error
= got_worktree_open(&worktree
, cwd
, GOT_WORKTREE_GOT_DIR
);
8001 if (error
->code
== GOT_ERR_NOT_WORKTREE
)
8002 error
= wrap_not_worktree_error(error
, "add", cwd
);
8006 error
= got_repo_open(&repo
, got_worktree_get_repo_path(worktree
),
8011 error
= apply_unveil(got_repo_get_path(repo
), 1,
8012 got_worktree_get_root_path(worktree
));
8016 error
= get_worktree_paths_from_argv(&paths
, argc
, argv
, worktree
);
8023 TAILQ_FOREACH(pe
, &paths
, entry
) {
8024 if (asprintf(&ondisk_path
, "%s/%s",
8025 got_worktree_get_root_path(worktree
),
8027 error
= got_error_from_errno("asprintf");
8030 if (lstat(ondisk_path
, &sb
) == -1) {
8031 if (errno
== ENOENT
) {
8035 error
= got_error_from_errno2("lstat",
8041 if (S_ISDIR(sb
.st_mode
)) {
8042 error
= got_error_msg(GOT_ERR_BAD_PATH
,
8043 "adding directories requires -R option");
8049 error
= got_worktree_schedule_add(worktree
, &paths
, add_progress
,
8050 NULL
, repo
, no_ignores
);
8053 const struct got_error
*close_err
= got_repo_close(repo
);
8058 got_worktree_close(worktree
);
8060 const struct got_error
*pack_err
=
8061 got_repo_pack_fds_close(pack_fds
);
8065 got_pathlist_free(&paths
, GOT_PATHLIST_FREE_PATH
);
8073 fprintf(stderr
, "usage: %s remove [-fkR] [-s status-codes] path ...\n",
8078 static const struct got_error
*
8079 print_remove_status(void *arg
, unsigned char status
,
8080 unsigned char staged_status
, const char *path
)
8082 while (path
[0] == '/')
8084 if (status
== GOT_STATUS_NONEXISTENT
)
8086 if (status
== staged_status
&& (status
== GOT_STATUS_DELETE
))
8087 status
= GOT_STATUS_NO_CHANGE
;
8088 printf("%c%c %s\n", status
, staged_status
, path
);
8092 static const struct got_error
*
8093 cmd_remove(int argc
, char *argv
[])
8095 const struct got_error
*error
= NULL
;
8096 struct got_worktree
*worktree
= NULL
;
8097 struct got_repository
*repo
= NULL
;
8098 const char *status_codes
= NULL
;
8100 struct got_pathlist_head paths
;
8101 struct got_pathlist_entry
*pe
;
8102 int ch
, delete_local_mods
= 0, can_recurse
= 0, keep_on_disk
= 0, i
;
8103 int ignore_missing_paths
= 0;
8104 int *pack_fds
= NULL
;
8109 if (pledge("stdio rpath wpath cpath flock proc exec sendfd unveil",
8114 while ((ch
= getopt(argc
, argv
, "fkRs:")) != -1) {
8117 delete_local_mods
= 1;
8118 ignore_missing_paths
= 1;
8127 for (i
= 0; optarg
[i
] != '\0'; i
++) {
8128 switch (optarg
[i
]) {
8129 case GOT_STATUS_MODIFY
:
8130 delete_local_mods
= 1;
8132 case GOT_STATUS_MISSING
:
8133 ignore_missing_paths
= 1;
8136 errx(1, "invalid status code '%c'",
8140 status_codes
= optarg
;
8154 cwd
= getcwd(NULL
, 0);
8156 error
= got_error_from_errno("getcwd");
8160 error
= got_repo_pack_fds_open(&pack_fds
);
8164 error
= got_worktree_open(&worktree
, cwd
, GOT_WORKTREE_GOT_DIR
);
8166 if (error
->code
== GOT_ERR_NOT_WORKTREE
)
8167 error
= wrap_not_worktree_error(error
, "remove", cwd
);
8171 error
= got_repo_open(&repo
, got_worktree_get_repo_path(worktree
),
8176 error
= apply_unveil(got_repo_get_path(repo
), 1,
8177 got_worktree_get_root_path(worktree
));
8181 error
= get_worktree_paths_from_argv(&paths
, argc
, argv
, worktree
);
8188 TAILQ_FOREACH(pe
, &paths
, entry
) {
8189 if (asprintf(&ondisk_path
, "%s/%s",
8190 got_worktree_get_root_path(worktree
),
8192 error
= got_error_from_errno("asprintf");
8195 if (lstat(ondisk_path
, &sb
) == -1) {
8196 if (errno
== ENOENT
) {
8200 error
= got_error_from_errno2("lstat",
8206 if (S_ISDIR(sb
.st_mode
)) {
8207 error
= got_error_msg(GOT_ERR_BAD_PATH
,
8208 "removing directories requires -R option");
8214 error
= got_worktree_schedule_delete(worktree
, &paths
,
8215 delete_local_mods
, status_codes
, print_remove_status
, NULL
,
8216 repo
, keep_on_disk
, ignore_missing_paths
);
8219 const struct got_error
*close_err
= got_repo_close(repo
);
8224 got_worktree_close(worktree
);
8226 const struct got_error
*pack_err
=
8227 got_repo_pack_fds_close(pack_fds
);
8231 got_pathlist_free(&paths
, GOT_PATHLIST_FREE_PATH
);
8239 fprintf(stderr
, "usage: %s patch [-nR] [-c commit] [-p strip-count] "
8240 "[patchfile]\n", getprogname());
8244 static const struct got_error
*
8245 patch_from_stdin(int *patchfd
)
8247 const struct got_error
*err
= NULL
;
8250 sig_t sighup
, sigint
, sigquit
;
8252 *patchfd
= got_opentempfd();
8254 return got_error_from_errno("got_opentempfd");
8256 sighup
= signal(SIGHUP
, SIG_DFL
);
8257 sigint
= signal(SIGINT
, SIG_DFL
);
8258 sigquit
= signal(SIGQUIT
, SIG_DFL
);
8261 r
= read(0, buf
, sizeof(buf
));
8263 err
= got_error_from_errno("read");
8268 if (write(*patchfd
, buf
, r
) == -1) {
8269 err
= got_error_from_errno("write");
8274 signal(SIGHUP
, sighup
);
8275 signal(SIGINT
, sigint
);
8276 signal(SIGQUIT
, sigquit
);
8278 if (err
== NULL
&& lseek(*patchfd
, 0, SEEK_SET
) == -1)
8279 err
= got_error_from_errno("lseek");
8289 struct got_patch_progress_arg
{
8295 static const struct got_error
*
8296 patch_progress(void *arg
, const char *old
, const char *new,
8297 unsigned char status
, const struct got_error
*error
, int old_from
,
8298 int old_lines
, int new_from
, int new_lines
, int offset
,
8299 int ws_mangled
, const struct got_error
*hunk_err
)
8301 const char *path
= new == NULL
? old
: new;
8302 struct got_patch_progress_arg
*a
= arg
;
8304 while (*path
== '/')
8307 if (status
!= GOT_STATUS_NO_CHANGE
&&
8308 status
!= 0 /* per-hunk progress */) {
8309 printf("%c %s\n", status
, path
);
8310 a
->did_something
= 1;
8313 if (hunk_err
== NULL
) {
8314 if (status
== GOT_STATUS_CANNOT_UPDATE
)
8316 else if (status
== GOT_STATUS_CONFLICT
)
8321 fprintf(stderr
, "%s: %s\n", getprogname(), error
->msg
);
8323 if (offset
!= 0 || hunk_err
!= NULL
|| ws_mangled
) {
8324 printf("@@ -%d,%d +%d,%d @@ ", old_from
,
8325 old_lines
, new_from
, new_lines
);
8326 if (hunk_err
!= NULL
)
8327 printf("%s\n", hunk_err
->msg
);
8328 else if (offset
!= 0)
8329 printf("applied with offset %d\n", offset
);
8331 printf("hunk contains mangled whitespace\n");
8338 print_patch_progress_stats(struct got_patch_progress_arg
*ppa
)
8340 if (!ppa
->did_something
)
8343 if (ppa
->conflicts
> 0)
8344 printf("Files with merge conflicts: %d\n", ppa
->conflicts
);
8346 if (ppa
->rejects
> 0) {
8347 printf("Files where patch failed to apply: %d\n",
8352 static const struct got_error
*
8353 cmd_patch(int argc
, char *argv
[])
8355 const struct got_error
*error
= NULL
, *close_error
= NULL
;
8356 struct got_worktree
*worktree
= NULL
;
8357 struct got_repository
*repo
= NULL
;
8358 struct got_reflist_head refs
;
8359 struct got_object_id
*commit_id
= NULL
;
8360 const char *commit_id_str
= NULL
;
8363 char *cwd
= NULL
, *keyword_idstr
= NULL
;
8364 int ch
, nop
= 0, strip
= -1, reverse
= 0;
8366 int *pack_fds
= NULL
;
8367 struct got_patch_progress_arg ppa
;
8372 if (pledge("stdio rpath wpath cpath fattr proc exec sendfd flock "
8373 "unveil", NULL
) == -1)
8377 while ((ch
= getopt(argc
, argv
, "c:np:R")) != -1) {
8380 commit_id_str
= optarg
;
8386 strip
= strtonum(optarg
, 0, INT_MAX
, &errstr
);
8388 errx(1, "pathname strip count is %s: %s",
8404 error
= patch_from_stdin(&patchfd
);
8407 } else if (argc
== 1) {
8408 patchfd
= open(argv
[0], O_RDONLY
);
8409 if (patchfd
== -1) {
8410 error
= got_error_from_errno2("open", argv
[0]);
8413 if (fstat(patchfd
, &sb
) == -1) {
8414 error
= got_error_from_errno2("fstat", argv
[0]);
8417 if (!S_ISREG(sb
.st_mode
)) {
8418 error
= got_error_path(argv
[0], GOT_ERR_BAD_FILETYPE
);
8424 if ((cwd
= getcwd(NULL
, 0)) == NULL
) {
8425 error
= got_error_from_errno("getcwd");
8429 error
= got_repo_pack_fds_open(&pack_fds
);
8433 error
= got_worktree_open(&worktree
, cwd
, GOT_WORKTREE_GOT_DIR
);
8437 const char *repo_path
= got_worktree_get_repo_path(worktree
);
8438 error
= got_repo_open(&repo
, repo_path
, NULL
, pack_fds
);
8442 error
= apply_unveil(got_repo_get_path(repo
), 0,
8443 got_worktree_get_root_path(worktree
));
8447 error
= got_ref_list(&refs
, repo
, NULL
, got_ref_cmp_by_name
, NULL
);
8451 if (commit_id_str
!= NULL
) {
8452 error
= got_keyword_to_idstr(&keyword_idstr
, commit_id_str
,
8457 error
= got_repo_match_object_id(&commit_id
, NULL
,
8458 keyword_idstr
!= NULL
? keyword_idstr
: commit_id_str
,
8459 GOT_OBJ_TYPE_COMMIT
, &refs
, repo
);
8464 memset(&ppa
, 0, sizeof(ppa
));
8465 error
= got_patch(patchfd
, worktree
, repo
, nop
, strip
, reverse
,
8466 commit_id
, patch_progress
, &ppa
, check_cancelled
, NULL
);
8467 print_patch_progress_stats(&ppa
);
8469 got_ref_list_free(&refs
);
8470 free(keyword_idstr
);
8473 close_error
= got_repo_close(repo
);
8475 error
= close_error
;
8477 if (worktree
!= NULL
) {
8478 close_error
= got_worktree_close(worktree
);
8480 error
= close_error
;
8483 const struct got_error
*pack_err
=
8484 got_repo_pack_fds_close(pack_fds
);
8495 fprintf(stderr
, "usage: %s revert [-pR] [-F response-script] path ...\n",
8500 static const struct got_error
*
8501 revert_progress(void *arg
, unsigned char status
, const char *path
)
8503 if (status
== GOT_STATUS_UNVERSIONED
)
8506 while (path
[0] == '/')
8508 printf("%c %s\n", status
, path
);
8512 struct choose_patch_arg
{
8513 FILE *patch_script_file
;
8517 static const struct got_error
*
8518 show_change(unsigned char status
, const char *path
, FILE *patch_file
, int n
,
8519 int nchanges
, const char *action
)
8521 const struct got_error
*err
;
8523 size_t linesize
= 0;
8527 case GOT_STATUS_ADD
:
8528 printf("A %s\n%s this addition? [y/n] ", path
, action
);
8530 case GOT_STATUS_DELETE
:
8531 printf("D %s\n%s this deletion? [y/n] ", path
, action
);
8533 case GOT_STATUS_MODIFY
:
8534 if (fseek(patch_file
, 0L, SEEK_SET
) == -1)
8535 return got_error_from_errno("fseek");
8536 printf(GOT_COMMIT_SEP_STR
);
8537 while ((linelen
= getline(&line
, &linesize
, patch_file
)) != -1)
8539 if (linelen
== -1 && ferror(patch_file
)) {
8540 err
= got_error_from_errno("getline");
8545 printf(GOT_COMMIT_SEP_STR
);
8546 printf("M %s (change %d of %d)\n%s this change? [y/n/q] ",
8547 path
, n
, nchanges
, action
);
8550 return got_error_path(path
, GOT_ERR_FILE_STATUS
);
8557 static const struct got_error
*
8558 choose_patch(int *choice
, void *arg
, unsigned char status
, const char *path
,
8559 FILE *patch_file
, int n
, int nchanges
)
8561 const struct got_error
*err
= NULL
;
8563 size_t linesize
= 0;
8566 struct choose_patch_arg
*a
= arg
;
8568 *choice
= GOT_PATCH_CHOICE_NONE
;
8570 if (a
->patch_script_file
) {
8572 err
= show_change(status
, path
, patch_file
, n
, nchanges
,
8576 linelen
= getline(&line
, &linesize
, a
->patch_script_file
);
8577 if (linelen
== -1) {
8578 if (ferror(a
->patch_script_file
))
8579 return got_error_from_errno("getline");
8582 nl
= strchr(line
, '\n');
8585 if (strcmp(line
, "y") == 0) {
8586 *choice
= GOT_PATCH_CHOICE_YES
;
8588 } else if (strcmp(line
, "n") == 0) {
8589 *choice
= GOT_PATCH_CHOICE_NO
;
8591 } else if (strcmp(line
, "q") == 0 &&
8592 status
== GOT_STATUS_MODIFY
) {
8593 *choice
= GOT_PATCH_CHOICE_QUIT
;
8596 printf("invalid response '%s'\n", line
);
8601 while (resp
!= 'y' && resp
!= 'n' && resp
!= 'q') {
8602 err
= show_change(status
, path
, patch_file
, n
, nchanges
,
8609 if (status
== GOT_STATUS_MODIFY
) {
8610 if (resp
!= 'y' && resp
!= 'n' && resp
!= 'q') {
8611 printf("invalid response '%c'\n", resp
);
8614 } else if (resp
!= 'y' && resp
!= 'n') {
8615 printf("invalid response '%c'\n", resp
);
8621 *choice
= GOT_PATCH_CHOICE_YES
;
8622 else if (resp
== 'n')
8623 *choice
= GOT_PATCH_CHOICE_NO
;
8624 else if (resp
== 'q' && status
== GOT_STATUS_MODIFY
)
8625 *choice
= GOT_PATCH_CHOICE_QUIT
;
8630 struct wt_commitable_path_arg
{
8631 struct got_pathlist_head
*commit_paths
;
8636 * Shortcut work tree status callback to determine if the set of paths scanned
8637 * has at least one versioned path that is being modified and, if not NULL, is
8638 * in the arg->commit_paths list. Set arg and return GOT_ERR_FILE_MODIFIED as
8639 * soon as a path is passed with a status that satisfies this criteria.
8641 static const struct got_error
*
8642 worktree_has_commitable_path(void *arg
, unsigned char status
,
8643 unsigned char staged_status
, const char *path
,
8644 struct got_object_id
*blob_id
, struct got_object_id
*staged_blob_id
,
8645 struct got_object_id
*commit_id
, int dirfd
, const char *de_name
)
8647 struct wt_commitable_path_arg
*a
= arg
;
8649 if (status
== staged_status
&& (status
== GOT_STATUS_DELETE
))
8650 status
= GOT_STATUS_NO_CHANGE
;
8652 if (!(status
== GOT_STATUS_NO_CHANGE
||
8653 status
== GOT_STATUS_UNVERSIONED
) ||
8654 staged_status
!= GOT_STATUS_NO_CHANGE
) {
8655 if (a
->commit_paths
!= NULL
) {
8656 struct got_pathlist_entry
*pe
;
8658 TAILQ_FOREACH(pe
, a
->commit_paths
, entry
) {
8659 if (strncmp(path
, pe
->path
,
8660 pe
->path_len
) == 0) {
8661 *a
->has_changes
= 1;
8666 *a
->has_changes
= 1;
8668 if (*a
->has_changes
)
8669 return got_error(GOT_ERR_FILE_MODIFIED
);
8676 * Check that the changeset of the commit identified by id is
8677 * comprised of at least one modified path that is being committed.
8679 static const struct got_error
*
8680 commit_path_changed_in_worktree(struct wt_commitable_path_arg
*wcpa
,
8681 struct got_object_id
*id
, struct got_worktree
*worktree
,
8682 struct got_repository
*repo
)
8684 const struct got_error
*err
;
8685 struct got_pathlist_head paths
;
8686 struct got_commit_object
*commit
= NULL
, *pcommit
= NULL
;
8687 struct got_tree_object
*tree
= NULL
, *ptree
= NULL
;
8688 struct got_object_qid
*pid
;
8692 err
= got_object_open_as_commit(&commit
, repo
, id
);
8696 err
= got_object_open_as_tree(&tree
, repo
,
8697 got_object_commit_get_tree_id(commit
));
8701 pid
= STAILQ_FIRST(got_object_commit_get_parent_ids(commit
));
8703 err
= got_object_open_as_commit(&pcommit
, repo
, &pid
->id
);
8707 err
= got_object_open_as_tree(&ptree
, repo
,
8708 got_object_commit_get_tree_id(pcommit
));
8713 err
= got_diff_tree(ptree
, tree
, NULL
, NULL
, -1, -1, "", "", repo
,
8714 got_diff_tree_collect_changed_paths
, &paths
, 0);
8718 err
= got_worktree_status(worktree
, &paths
, repo
, 0,
8719 worktree_has_commitable_path
, wcpa
, check_cancelled
, NULL
);
8720 if (err
&& err
->code
== GOT_ERR_FILE_MODIFIED
) {
8722 * At least one changed path in the referenced commit is
8723 * modified in the work tree, that's all we need to know!
8729 got_pathlist_free(&paths
, GOT_PATHLIST_FREE_ALL
);
8731 got_object_commit_close(commit
);
8733 got_object_commit_close(pcommit
);
8735 got_object_tree_close(tree
);
8737 got_object_tree_close(ptree
);
8742 * Remove any "logmsg" reference comprised entirely of paths that have
8743 * been reverted in this work tree. If any path in the logmsg ref changeset
8744 * remains in a changed state in the worktree, do not remove the reference.
8746 static const struct got_error
*
8747 rm_logmsg_ref(struct got_worktree
*worktree
, struct got_repository
*repo
)
8749 const struct got_error
*err
;
8750 struct got_reflist_head refs
;
8751 struct got_reflist_entry
*re
;
8752 struct got_commit_object
*commit
= NULL
;
8753 struct got_object_id
*commit_id
= NULL
;
8754 struct wt_commitable_path_arg wcpa
;
8755 char *uuidstr
= NULL
;
8759 err
= got_worktree_get_uuid(&uuidstr
, worktree
);
8763 err
= got_ref_list(&refs
, repo
, "refs/got/worktree",
8764 got_ref_cmp_by_name
, repo
);
8768 TAILQ_FOREACH(re
, &refs
, entry
) {
8769 const char *refname
;
8770 int has_changes
= 0;
8772 refname
= got_ref_get_name(re
->ref
);
8774 if (!strncmp(refname
, GOT_WORKTREE_CHERRYPICK_REF_PREFIX
,
8775 GOT_WORKTREE_CHERRYPICK_REF_PREFIX_LEN
))
8776 refname
+= GOT_WORKTREE_CHERRYPICK_REF_PREFIX_LEN
+ 1;
8777 else if (!strncmp(refname
, GOT_WORKTREE_BACKOUT_REF_PREFIX
,
8778 GOT_WORKTREE_BACKOUT_REF_PREFIX_LEN
))
8779 refname
+= GOT_WORKTREE_BACKOUT_REF_PREFIX_LEN
+ 1;
8783 if (strncmp(refname
, uuidstr
, GOT_WORKTREE_UUID_STRLEN
) == 0)
8784 refname
+= GOT_WORKTREE_UUID_STRLEN
+ 1; /* skip '-' */
8788 err
= got_repo_match_object_id(&commit_id
, NULL
, refname
,
8789 GOT_OBJ_TYPE_COMMIT
, NULL
, repo
);
8793 err
= got_object_open_as_commit(&commit
, repo
, commit_id
);
8797 wcpa
.commit_paths
= NULL
;
8798 wcpa
.has_changes
= &has_changes
;
8800 err
= commit_path_changed_in_worktree(&wcpa
, commit_id
,
8806 err
= got_ref_delete(re
->ref
, repo
);
8811 got_object_commit_close(commit
);
8820 got_ref_list_free(&refs
);
8822 got_object_commit_close(commit
);
8826 static const struct got_error
*
8827 cmd_revert(int argc
, char *argv
[])
8829 const struct got_error
*error
= NULL
;
8830 struct got_worktree
*worktree
= NULL
;
8831 struct got_repository
*repo
= NULL
;
8832 char *cwd
= NULL
, *path
= NULL
;
8833 struct got_pathlist_head paths
;
8834 struct got_pathlist_entry
*pe
;
8835 int ch
, can_recurse
= 0, pflag
= 0;
8836 FILE *patch_script_file
= NULL
;
8837 const char *patch_script_path
= NULL
;
8838 struct choose_patch_arg cpa
;
8839 int *pack_fds
= NULL
;
8844 if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd "
8845 "unveil", NULL
) == -1)
8849 while ((ch
= getopt(argc
, argv
, "F:pR")) != -1) {
8852 patch_script_path
= optarg
;
8871 if (patch_script_path
&& !pflag
)
8872 errx(1, "-F option can only be used together with -p option");
8874 cwd
= getcwd(NULL
, 0);
8876 error
= got_error_from_errno("getcwd");
8880 error
= got_repo_pack_fds_open(&pack_fds
);
8884 error
= got_worktree_open(&worktree
, cwd
, GOT_WORKTREE_GOT_DIR
);
8886 if (error
->code
== GOT_ERR_NOT_WORKTREE
)
8887 error
= wrap_not_worktree_error(error
, "revert", cwd
);
8891 error
= got_repo_open(&repo
, got_worktree_get_repo_path(worktree
),
8896 if (patch_script_path
) {
8897 patch_script_file
= fopen(patch_script_path
, "re");
8898 if (patch_script_file
== NULL
) {
8899 error
= got_error_from_errno2("fopen",
8906 * XXX "c" perm needed on repo dir to delete merge references.
8908 error
= apply_unveil(got_repo_get_path(repo
), 0,
8909 got_worktree_get_root_path(worktree
));
8913 error
= get_worktree_paths_from_argv(&paths
, argc
, argv
, worktree
);
8920 TAILQ_FOREACH(pe
, &paths
, entry
) {
8921 if (asprintf(&ondisk_path
, "%s/%s",
8922 got_worktree_get_root_path(worktree
),
8924 error
= got_error_from_errno("asprintf");
8927 if (lstat(ondisk_path
, &sb
) == -1) {
8928 if (errno
== ENOENT
) {
8932 error
= got_error_from_errno2("lstat",
8938 if (S_ISDIR(sb
.st_mode
)) {
8939 error
= got_error_msg(GOT_ERR_BAD_PATH
,
8940 "reverting directories requires -R option");
8946 cpa
.patch_script_file
= patch_script_file
;
8947 cpa
.action
= "revert";
8948 error
= got_worktree_revert(worktree
, &paths
, revert_progress
, NULL
,
8949 pflag
? choose_patch
: NULL
, &cpa
, repo
);
8951 error
= rm_logmsg_ref(worktree
, repo
);
8953 if (patch_script_file
&& fclose(patch_script_file
) == EOF
&&
8955 error
= got_error_from_errno2("fclose", patch_script_path
);
8957 const struct got_error
*close_err
= got_repo_close(repo
);
8962 got_worktree_close(worktree
);
8964 const struct got_error
*pack_err
=
8965 got_repo_pack_fds_close(pack_fds
);
8969 got_pathlist_free(&paths
, GOT_PATHLIST_FREE_PATH
);
8978 fprintf(stderr
, "usage: %s commit [-CNnS] [-A author] [-F path] "
8979 "[-m message] [path ...]\n", getprogname());
8983 struct collect_commit_logmsg_arg
{
8984 const char *cmdline_log
;
8985 const char *prepared_log
;
8986 const char *merged_log
;
8987 int non_interactive
;
8989 const char *worktree_path
;
8990 const char *branch_name
;
8991 const char *repo_path
;
8996 static const struct got_error
*
8997 read_prepared_logmsg(char **logmsg
, const char *path
)
8999 const struct got_error
*err
= NULL
;
9005 memset(&sb
, 0, sizeof(sb
));
9007 f
= fopen(path
, "re");
9009 return got_error_from_errno2("fopen", path
);
9011 if (fstat(fileno(f
), &sb
) == -1) {
9012 err
= got_error_from_errno2("fstat", path
);
9015 if (sb
.st_size
== 0) {
9016 err
= got_error(GOT_ERR_COMMIT_MSG_EMPTY
);
9020 *logmsg
= malloc(sb
.st_size
+ 1);
9021 if (*logmsg
== NULL
) {
9022 err
= got_error_from_errno("malloc");
9026 r
= fread(*logmsg
, 1, sb
.st_size
, f
);
9027 if (r
!= sb
.st_size
) {
9029 err
= got_error_from_errno2("fread", path
);
9031 err
= got_error(GOT_ERR_IO
);
9034 (*logmsg
)[sb
.st_size
] = '\0';
9036 if (fclose(f
) == EOF
&& err
== NULL
)
9037 err
= got_error_from_errno2("fclose", path
);
9045 static const struct got_error
*
9046 collect_commit_logmsg(struct got_pathlist_head
*commitable_paths
,
9047 const char *diff_path
, char **logmsg
, void *arg
)
9049 char *initial_content
= NULL
;
9050 struct got_pathlist_entry
*pe
;
9051 const struct got_error
*err
= NULL
;
9052 char *template = NULL
;
9053 char *prepared_msg
= NULL
, *merged_msg
= NULL
;
9054 struct collect_commit_logmsg_arg
*a
= arg
;
9055 int initial_content_len
;
9059 /* if a message was specified on the command line, just use it */
9060 if (a
->cmdline_log
!= NULL
&& *a
->cmdline_log
!= '\0') {
9061 len
= strlen(a
->cmdline_log
) + 1;
9062 *logmsg
= malloc(len
+ 1);
9063 if (*logmsg
== NULL
)
9064 return got_error_from_errno("malloc");
9065 strlcpy(*logmsg
, a
->cmdline_log
, len
);
9067 } else if (a
->prepared_log
!= NULL
&& a
->non_interactive
)
9068 return read_prepared_logmsg(logmsg
, a
->prepared_log
);
9070 if (asprintf(&template, "%s/logmsg", a
->worktree_path
) == -1)
9071 return got_error_from_errno("asprintf");
9073 err
= got_opentemp_named_fd(&a
->logmsg_path
, &fd
, template, "");
9077 if (a
->prepared_log
) {
9078 err
= read_prepared_logmsg(&prepared_msg
, a
->prepared_log
);
9081 } else if (a
->merged_log
) {
9082 err
= read_prepared_logmsg(&merged_msg
, a
->merged_log
);
9087 initial_content_len
= asprintf(&initial_content
,
9088 "%s%s\n# changes to be committed on branch %s:\n",
9089 prepared_msg
? prepared_msg
: "",
9090 merged_msg
? merged_msg
: "", a
->branch_name
);
9091 if (initial_content_len
== -1) {
9092 err
= got_error_from_errno("asprintf");
9096 if (write(fd
, initial_content
, initial_content_len
) == -1) {
9097 err
= got_error_from_errno2("write", a
->logmsg_path
);
9101 TAILQ_FOREACH(pe
, commitable_paths
, entry
) {
9102 struct got_commitable
*ct
= pe
->data
;
9103 dprintf(fd
, "# %c %s\n",
9104 got_commitable_get_status(ct
),
9105 got_commitable_get_path(ct
));
9109 dprintf(fd
, "# detailed changes can be viewed in %s\n",
9113 if (close(fd
) == -1) {
9114 err
= got_error_from_errno2("close", a
->logmsg_path
);
9119 err
= edit_logmsg(logmsg
, a
->editor
, a
->logmsg_path
, initial_content
,
9120 initial_content_len
, a
->prepared_log
? 0 : 1);
9122 free(initial_content
);
9127 if (fd
!= -1 && close(fd
) == -1 && err
== NULL
)
9128 err
= got_error_from_errno2("close", a
->logmsg_path
);
9130 /* Editor is done; we can now apply unveil(2) */
9132 err
= apply_unveil(a
->repo_path
, 0, a
->worktree_path
);
9140 static const struct got_error
*
9141 cat_logmsg(FILE *f
, struct got_commit_object
*commit
, const char *idstr
,
9142 const char *type
, int has_content
)
9144 const struct got_error
*err
= NULL
;
9145 char *logmsg
= NULL
;
9147 err
= got_object_commit_get_logmsg(&logmsg
, commit
);
9151 if (fprintf(f
, "%s# log message of %s commit %s:%s",
9152 has_content
? "\n" : "", type
, idstr
, logmsg
) < 0)
9153 err
= got_ferror(f
, GOT_ERR_IO
);
9160 * Lookup "logmsg" references of backed-out and cherrypicked commits
9161 * belonging to the current work tree. If found, and the worktree has
9162 * at least one modified file that was changed in the referenced commit,
9163 * add its log message to a new temporary file at *logmsg_path.
9164 * Add all refs found to matched_refs to be scheduled for removal on
9165 * successful commit.
9167 static const struct got_error
*
9168 lookup_logmsg_ref(char **logmsg_path
, struct got_pathlist_head
*paths
,
9169 struct got_reflist_head
*matched_refs
, struct got_worktree
*worktree
,
9170 struct got_repository
*repo
)
9172 const struct got_error
*err
;
9173 struct got_commit_object
*commit
= NULL
;
9174 struct got_object_id
*id
= NULL
;
9175 struct got_reflist_head refs
;
9176 struct got_reflist_entry
*re
, *re_match
;
9178 char *uuidstr
= NULL
;
9179 int added_logmsg
= 0;
9183 *logmsg_path
= NULL
;
9185 err
= got_worktree_get_uuid(&uuidstr
, worktree
);
9189 err
= got_ref_list(&refs
, repo
, "refs/got/worktree",
9190 got_ref_cmp_by_name
, repo
);
9194 TAILQ_FOREACH(re
, &refs
, entry
) {
9195 const char *refname
, *type
;
9196 struct wt_commitable_path_arg wcpa
;
9199 refname
= got_ref_get_name(re
->ref
);
9201 if (strncmp(refname
, GOT_WORKTREE_CHERRYPICK_REF_PREFIX
,
9202 GOT_WORKTREE_CHERRYPICK_REF_PREFIX_LEN
) == 0) {
9203 refname
+= GOT_WORKTREE_CHERRYPICK_REF_PREFIX_LEN
+ 1;
9204 type
= "cherrypicked";
9205 } else if (strncmp(refname
, GOT_WORKTREE_BACKOUT_REF_PREFIX
,
9206 GOT_WORKTREE_BACKOUT_REF_PREFIX_LEN
) == 0) {
9207 refname
+= GOT_WORKTREE_BACKOUT_REF_PREFIX_LEN
+ 1;
9208 type
= "backed-out";
9212 if (strncmp(refname
, uuidstr
, GOT_WORKTREE_UUID_STRLEN
) == 0)
9213 refname
+= GOT_WORKTREE_UUID_STRLEN
+ 1; /* skip '-' */
9217 err
= got_repo_match_object_id(&id
, NULL
, refname
,
9218 GOT_OBJ_TYPE_COMMIT
, NULL
, repo
);
9222 err
= got_object_open_as_commit(&commit
, repo
, id
);
9226 wcpa
.commit_paths
= paths
;
9227 wcpa
.has_changes
= &add_logmsg
;
9229 err
= commit_path_changed_in_worktree(&wcpa
, id
,
9236 err
= got_opentemp_named(logmsg_path
, &f
,
9237 "got-commit-logmsg", "");
9241 err
= cat_logmsg(f
, commit
, refname
, type
,
9248 err
= got_reflist_entry_dup(&re_match
, re
);
9251 TAILQ_INSERT_HEAD(matched_refs
, re_match
, entry
);
9254 got_object_commit_close(commit
);
9263 got_ref_list_free(&refs
);
9265 got_object_commit_close(commit
);
9266 if (f
&& fclose(f
) == EOF
&& err
== NULL
)
9267 err
= got_error_from_errno("fclose");
9268 if (!added_logmsg
) {
9269 if (*logmsg_path
&& unlink(*logmsg_path
) != 0 && err
== NULL
)
9270 err
= got_error_from_errno2("unlink", *logmsg_path
);
9271 *logmsg_path
= NULL
;
9276 static const struct got_error
*
9277 cmd_commit(int argc
, char *argv
[])
9279 const struct got_error
*error
= NULL
;
9280 struct got_worktree
*worktree
= NULL
;
9281 struct got_repository
*repo
= NULL
;
9282 char *cwd
= NULL
, *id_str
= NULL
;
9283 struct got_object_id
*id
= NULL
;
9284 const char *logmsg
= NULL
;
9285 char *prepared_logmsg
= NULL
, *merged_logmsg
= NULL
;
9286 struct collect_commit_logmsg_arg cl_arg
;
9287 const char *author
= NULL
;
9288 char *gitconfig_path
= NULL
, *editor
= NULL
, *committer
= NULL
;
9289 int ch
, rebase_in_progress
, histedit_in_progress
, preserve_logmsg
= 0;
9290 int allow_bad_symlinks
= 0, non_interactive
= 0, merge_in_progress
= 0;
9291 int show_diff
= 1, commit_conflicts
= 0;
9292 struct got_pathlist_head paths
;
9293 struct got_reflist_head refs
;
9294 struct got_reflist_entry
*re
;
9295 int *pack_fds
= NULL
;
9299 cl_arg
.logmsg_path
= NULL
;
9302 if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd "
9303 "unveil", NULL
) == -1)
9307 while ((ch
= getopt(argc
, argv
, "A:CF:m:NnS")) != -1) {
9311 error
= valid_author(author
);
9316 commit_conflicts
= 1;
9320 option_conflict('F', 'm');
9321 prepared_logmsg
= realpath(optarg
, NULL
);
9322 if (prepared_logmsg
== NULL
)
9323 return got_error_from_errno2("realpath",
9327 if (prepared_logmsg
)
9328 option_conflict('m', 'F');
9332 non_interactive
= 1;
9338 allow_bad_symlinks
= 1;
9349 cwd
= getcwd(NULL
, 0);
9351 error
= got_error_from_errno("getcwd");
9355 error
= got_repo_pack_fds_open(&pack_fds
);
9359 error
= got_worktree_open(&worktree
, cwd
, GOT_WORKTREE_GOT_DIR
);
9361 if (error
->code
== GOT_ERR_NOT_WORKTREE
)
9362 error
= wrap_not_worktree_error(error
, "commit", cwd
);
9366 error
= got_worktree_rebase_in_progress(&rebase_in_progress
, worktree
);
9369 if (rebase_in_progress
) {
9370 error
= got_error(GOT_ERR_REBASING
);
9374 error
= got_worktree_histedit_in_progress(&histedit_in_progress
,
9379 error
= get_gitconfig_path(&gitconfig_path
);
9382 error
= got_repo_open(&repo
, got_worktree_get_repo_path(worktree
),
9383 gitconfig_path
, pack_fds
);
9387 error
= got_worktree_merge_in_progress(&merge_in_progress
, worktree
, repo
);
9390 if (merge_in_progress
) {
9391 error
= got_error(GOT_ERR_MERGE_BUSY
);
9395 error
= get_author(&committer
, repo
, worktree
);
9403 * unveil(2) traverses exec(2); if an editor is used we have
9404 * to apply unveil after the log message has been written.
9406 if (logmsg
== NULL
|| strlen(logmsg
) == 0)
9407 error
= get_editor(&editor
);
9409 error
= apply_unveil(got_repo_get_path(repo
), 0,
9410 got_worktree_get_root_path(worktree
));
9414 error
= get_worktree_paths_from_argv(&paths
, argc
, argv
, worktree
);
9418 if (prepared_logmsg
== NULL
) {
9419 error
= lookup_logmsg_ref(&merged_logmsg
,
9420 argc
> 0 ? &paths
: NULL
, &refs
, worktree
, repo
);
9425 cl_arg
.editor
= editor
;
9426 cl_arg
.cmdline_log
= logmsg
;
9427 cl_arg
.prepared_log
= prepared_logmsg
;
9428 cl_arg
.merged_log
= merged_logmsg
;
9429 cl_arg
.non_interactive
= non_interactive
;
9430 cl_arg
.worktree_path
= got_worktree_get_root_path(worktree
);
9431 cl_arg
.branch_name
= got_worktree_get_head_ref_name(worktree
);
9432 if (!histedit_in_progress
) {
9433 if (strncmp(cl_arg
.branch_name
, "refs/heads/", 11) != 0) {
9434 error
= got_error(GOT_ERR_COMMIT_BRANCH
);
9437 cl_arg
.branch_name
+= 11;
9439 cl_arg
.repo_path
= got_repo_get_path(repo
);
9440 error
= got_worktree_commit(&id
, worktree
, &paths
, author
, committer
,
9441 allow_bad_symlinks
, show_diff
, commit_conflicts
,
9442 collect_commit_logmsg
, &cl_arg
, print_status
, NULL
, repo
);
9444 if (error
->code
!= GOT_ERR_COMMIT_MSG_EMPTY
&&
9445 cl_arg
.logmsg_path
!= NULL
)
9446 preserve_logmsg
= 1;
9450 error
= got_object_id_str(&id_str
, id
);
9453 printf("Created commit %s\n", id_str
);
9455 TAILQ_FOREACH(re
, &refs
, entry
) {
9456 error
= got_ref_delete(re
->ref
, repo
);
9462 if (preserve_logmsg
) {
9463 fprintf(stderr
, "%s: log message preserved in %s\n",
9464 getprogname(), cl_arg
.logmsg_path
);
9465 } else if (cl_arg
.logmsg_path
&& unlink(cl_arg
.logmsg_path
) == -1 &&
9467 error
= got_error_from_errno2("unlink", cl_arg
.logmsg_path
);
9468 free(cl_arg
.logmsg_path
);
9469 if (merged_logmsg
&& unlink(merged_logmsg
) == -1 && error
== NULL
)
9470 error
= got_error_from_errno2("unlink", merged_logmsg
);
9471 free(merged_logmsg
);
9473 const struct got_error
*close_err
= got_repo_close(repo
);
9478 got_worktree_close(worktree
);
9480 const struct got_error
*pack_err
=
9481 got_repo_pack_fds_close(pack_fds
);
9485 got_ref_list_free(&refs
);
9486 got_pathlist_free(&paths
, GOT_PATHLIST_FREE_PATH
);
9489 free(gitconfig_path
);
9492 free(prepared_logmsg
);
9499 fprintf(stderr
, "usage: %s send [-afqTv] [-b branch] [-d branch] "
9500 "[-r repository-path] [-t tag] [remote-repository]\n",
9506 print_load_info(int print_colored
, int print_found
, int print_trees
,
9507 int ncolored
, int nfound
, int ntrees
)
9509 if (print_colored
) {
9510 printf("%d commit%s colored", ncolored
,
9511 ncolored
== 1 ? "" : "s");
9514 printf("%s%d object%s found",
9515 ncolored
> 0 ? "; " : "",
9516 nfound
, nfound
== 1 ? "" : "s");
9519 printf("; %d tree%s scanned", ntrees
,
9520 ntrees
== 1 ? "" : "s");
9524 struct got_send_progress_arg
{
9525 char last_scaled_packsize
[FMT_SCALED_STRSIZE
];
9532 int last_nobj_total
;
9536 int printed_something
;
9538 struct got_pathlist_head
*delete_branches
;
9541 static const struct got_error
*
9542 send_progress(void *arg
, int ncolored
, int nfound
, int ntrees
,
9543 off_t packfile_size
, int ncommits
, int nobj_total
, int nobj_deltify
,
9544 int nobj_written
, off_t bytes_sent
, const char *refname
,
9545 const char *errmsg
, int success
)
9547 struct got_send_progress_arg
*a
= arg
;
9548 char scaled_packsize
[FMT_SCALED_STRSIZE
];
9549 char scaled_sent
[FMT_SCALED_STRSIZE
];
9550 int p_deltify
= 0, p_written
= 0, p_sent
= 0;
9551 int print_colored
= 0, print_found
= 0, print_trees
= 0;
9552 int print_searching
= 0, print_total
= 0;
9553 int print_deltify
= 0, print_written
= 0, print_sent
= 0;
9555 if (a
->verbosity
< 0)
9559 const char *status
= success
? "accepted" : "rejected";
9562 struct got_pathlist_entry
*pe
;
9563 TAILQ_FOREACH(pe
, a
->delete_branches
, entry
) {
9564 const char *branchname
= pe
->path
;
9565 if (got_path_cmp(branchname
, refname
,
9566 strlen(branchname
), strlen(refname
)) == 0) {
9568 a
->sent_something
= 1;
9574 if (a
->printed_something
)
9576 printf("Server has %s %s", status
, refname
);
9578 printf(": %s", errmsg
);
9579 a
->printed_something
= 1;
9583 if (a
->last_ncolored
!= ncolored
) {
9585 a
->last_ncolored
= ncolored
;
9588 if (a
->last_nfound
!= nfound
) {
9591 a
->last_nfound
= nfound
;
9594 if (a
->last_ntrees
!= ntrees
) {
9598 a
->last_ntrees
= ntrees
;
9601 if ((print_colored
|| print_found
|| print_trees
) &&
9604 print_load_info(print_colored
, print_found
, print_trees
,
9605 ncolored
, nfound
, ntrees
);
9606 a
->printed_something
= 1;
9609 } else if (!a
->loading_done
) {
9611 print_load_info(1, 1, 1, ncolored
, nfound
, ntrees
);
9613 a
->loading_done
= 1;
9616 if (fmt_scaled(packfile_size
, scaled_packsize
) == -1)
9617 return got_error_from_errno("fmt_scaled");
9618 if (fmt_scaled(bytes_sent
, scaled_sent
) == -1)
9619 return got_error_from_errno("fmt_scaled");
9621 if (a
->last_ncommits
!= ncommits
) {
9622 print_searching
= 1;
9623 a
->last_ncommits
= ncommits
;
9626 if (a
->last_nobj_total
!= nobj_total
) {
9627 print_searching
= 1;
9629 a
->last_nobj_total
= nobj_total
;
9632 if (packfile_size
> 0 && (a
->last_scaled_packsize
[0] == '\0' ||
9633 strcmp(scaled_packsize
, a
->last_scaled_packsize
)) != 0) {
9634 if (strlcpy(a
->last_scaled_packsize
, scaled_packsize
,
9635 FMT_SCALED_STRSIZE
) >= FMT_SCALED_STRSIZE
)
9636 return got_error(GOT_ERR_NO_SPACE
);
9639 if (nobj_deltify
> 0 || nobj_written
> 0) {
9640 if (nobj_deltify
> 0) {
9641 p_deltify
= (nobj_deltify
* 100) / nobj_total
;
9642 if (p_deltify
!= a
->last_p_deltify
) {
9643 a
->last_p_deltify
= p_deltify
;
9644 print_searching
= 1;
9649 if (nobj_written
> 0) {
9650 p_written
= (nobj_written
* 100) / nobj_total
;
9651 if (p_written
!= a
->last_p_written
) {
9652 a
->last_p_written
= p_written
;
9653 print_searching
= 1;
9661 if (bytes_sent
> 0) {
9662 p_sent
= (bytes_sent
* 100) / packfile_size
;
9663 if (p_sent
!= a
->last_p_sent
) {
9664 a
->last_p_sent
= p_sent
;
9665 print_searching
= 1;
9671 a
->sent_something
= 1;
9674 if (print_searching
|| print_total
|| print_deltify
|| print_written
||
9677 if (print_searching
)
9678 printf("packing %d reference%s", ncommits
,
9679 ncommits
== 1 ? "" : "s");
9681 printf("; %d object%s", nobj_total
,
9682 nobj_total
== 1 ? "" : "s");
9684 printf("; deltify: %d%%", p_deltify
);
9686 printf("; uploading pack: %*s %d%%", FMT_SCALED_STRSIZE
- 2,
9687 scaled_packsize
, p_sent
);
9688 else if (print_written
)
9689 printf("; writing pack: %*s %d%%", FMT_SCALED_STRSIZE
- 2,
9690 scaled_packsize
, p_written
);
9691 if (print_searching
|| print_total
|| print_deltify
||
9692 print_written
|| print_sent
) {
9693 a
->printed_something
= 1;
9699 static const struct got_error
*
9700 cmd_send(int argc
, char *argv
[])
9702 const struct got_error
*error
= NULL
;
9703 char *cwd
= NULL
, *repo_path
= NULL
;
9704 const char *remote_name
;
9705 char *proto
= NULL
, *host
= NULL
, *port
= NULL
;
9706 char *repo_name
= NULL
, *server_path
= NULL
;
9707 const struct got_remote_repo
*remotes
;
9708 struct got_remote_repo
*remote
= NULL
;
9709 int nremotes
, nbranches
= 0, ndelete_branches
= 0;
9710 struct got_repository
*repo
= NULL
;
9711 struct got_worktree
*worktree
= NULL
;
9712 const struct got_gotconfig
*repo_conf
= NULL
, *worktree_conf
= NULL
;
9713 struct got_pathlist_head branches
;
9714 struct got_pathlist_head tags
;
9715 struct got_reflist_head all_branches
;
9716 struct got_reflist_head all_tags
;
9717 struct got_pathlist_head delete_args
;
9718 struct got_pathlist_head delete_branches
;
9719 struct got_reflist_entry
*re
;
9720 struct got_pathlist_entry
*pe
;
9721 int i
, ch
, sendfd
= -1, sendstatus
;
9723 struct got_send_progress_arg spa
;
9724 int verbosity
= 0, overwrite_refs
= 0;
9725 int send_all_branches
= 0, send_all_tags
= 0;
9726 struct got_reference
*ref
= NULL
;
9727 int *pack_fds
= NULL
;
9729 TAILQ_INIT(&branches
);
9731 TAILQ_INIT(&all_branches
);
9732 TAILQ_INIT(&all_tags
);
9733 TAILQ_INIT(&delete_args
);
9734 TAILQ_INIT(&delete_branches
);
9736 while ((ch
= getopt(argc
, argv
, "ab:d:fqr:Tt:v")) != -1) {
9739 send_all_branches
= 1;
9742 error
= got_pathlist_append(&branches
, optarg
, NULL
);
9748 error
= got_pathlist_append(&delete_args
, optarg
, NULL
);
9759 repo_path
= realpath(optarg
, NULL
);
9760 if (repo_path
== NULL
)
9761 return got_error_from_errno2("realpath",
9763 got_path_strip_trailing_slashes(repo_path
);
9769 error
= got_pathlist_append(&tags
, optarg
, NULL
);
9776 else if (verbosity
< 3)
9787 if (send_all_branches
&& !TAILQ_EMPTY(&branches
))
9788 option_conflict('a', 'b');
9789 if (send_all_tags
&& !TAILQ_EMPTY(&tags
))
9790 option_conflict('T', 't');
9794 remote_name
= GOT_SEND_DEFAULT_REMOTE_NAME
;
9796 remote_name
= argv
[0];
9800 cwd
= getcwd(NULL
, 0);
9802 error
= got_error_from_errno("getcwd");
9806 error
= got_repo_pack_fds_open(&pack_fds
);
9810 if (repo_path
== NULL
) {
9811 error
= got_worktree_open(&worktree
, cwd
, GOT_WORKTREE_GOT_DIR
);
9812 if (error
&& error
->code
!= GOT_ERR_NOT_WORKTREE
)
9818 strdup(got_worktree_get_repo_path(worktree
));
9819 if (repo_path
== NULL
)
9820 error
= got_error_from_errno("strdup");
9824 repo_path
= strdup(cwd
);
9825 if (repo_path
== NULL
) {
9826 error
= got_error_from_errno("strdup");
9832 error
= got_repo_open(&repo
, repo_path
, NULL
, pack_fds
);
9837 worktree_conf
= got_worktree_get_gotconfig(worktree
);
9838 if (worktree_conf
) {
9839 got_gotconfig_get_remotes(&nremotes
, &remotes
,
9841 for (i
= 0; i
< nremotes
; i
++) {
9842 if (strcmp(remotes
[i
].name
, remote_name
) == 0) {
9843 error
= got_repo_remote_repo_dup(&remote
,
9852 if (remote
== NULL
) {
9853 repo_conf
= got_repo_get_gotconfig(repo
);
9855 got_gotconfig_get_remotes(&nremotes
, &remotes
,
9857 for (i
= 0; i
< nremotes
; i
++) {
9858 if (strcmp(remotes
[i
].name
, remote_name
) == 0) {
9859 error
= got_repo_remote_repo_dup(&remote
,
9868 if (remote
== NULL
) {
9869 got_repo_get_gitconfig_remotes(&nremotes
, &remotes
, repo
);
9870 for (i
= 0; i
< nremotes
; i
++) {
9871 if (strcmp(remotes
[i
].name
, remote_name
) == 0) {
9872 error
= got_repo_remote_repo_dup(&remote
,
9880 if (remote
== NULL
) {
9881 error
= got_error_path(remote_name
, GOT_ERR_NO_REMOTE
);
9885 error
= got_dial_parse_uri(&proto
, &host
, &port
, &server_path
,
9886 &repo_name
, remote
->send_url
);
9890 if (strcmp(proto
, "git") == 0) {
9892 if (pledge("stdio rpath wpath cpath fattr flock proc exec "
9893 "sendfd dns inet unveil", NULL
) == -1)
9896 } else if (strcmp(proto
, "git+ssh") == 0 ||
9897 strcmp(proto
, "ssh") == 0) {
9899 if (pledge("stdio rpath wpath cpath fattr flock proc exec "
9900 "sendfd unveil", NULL
) == -1)
9903 } else if (strcmp(proto
, "http") == 0 ||
9904 strcmp(proto
, "git+http") == 0) {
9905 error
= got_error_path(proto
, GOT_ERR_NOT_IMPL
);
9908 error
= got_error_path(proto
, GOT_ERR_BAD_PROTO
);
9912 error
= got_dial_apply_unveil(proto
);
9916 error
= apply_unveil(got_repo_get_path(repo
), 0, NULL
);
9920 if (send_all_branches
) {
9921 error
= got_ref_list(&all_branches
, repo
, "refs/heads",
9922 got_ref_cmp_by_name
, NULL
);
9925 TAILQ_FOREACH(re
, &all_branches
, entry
) {
9926 const char *branchname
= got_ref_get_name(re
->ref
);
9927 error
= got_pathlist_append(&branches
,
9933 } else if (nbranches
== 0) {
9934 for (i
= 0; i
< remote
->nsend_branches
; i
++) {
9935 error
= got_pathlist_append(&branches
,
9936 remote
->send_branches
[i
], NULL
);
9942 if (send_all_tags
) {
9943 error
= got_ref_list(&all_tags
, repo
, "refs/tags",
9944 got_ref_cmp_by_name
, NULL
);
9947 TAILQ_FOREACH(re
, &all_tags
, entry
) {
9948 const char *tagname
= got_ref_get_name(re
->ref
);
9949 error
= got_pathlist_append(&tags
,
9957 * To prevent accidents only branches in refs/heads/ can be deleted
9958 * with 'got send -d'.
9959 * Deleting anything else requires local repository access or Git.
9961 TAILQ_FOREACH(pe
, &delete_args
, entry
) {
9962 const char *branchname
= pe
->path
;
9964 struct got_pathlist_entry
*new;
9965 if (strncmp(branchname
, "refs/heads/", 11) == 0) {
9966 s
= strdup(branchname
);
9968 error
= got_error_from_errno("strdup");
9972 if (asprintf(&s
, "refs/heads/%s", branchname
) == -1) {
9973 error
= got_error_from_errno("asprintf");
9977 error
= got_pathlist_insert(&new, &delete_branches
, s
, NULL
);
9978 if (error
|| new == NULL
/* duplicate */)
9985 if (nbranches
== 0 && ndelete_branches
== 0) {
9986 struct got_reference
*head_ref
;
9988 error
= got_ref_open(&head_ref
, repo
,
9989 got_worktree_get_head_ref_name(worktree
), 0);
9991 error
= got_ref_open(&head_ref
, repo
, GOT_REF_HEAD
, 0);
9994 if (got_ref_is_symbolic(head_ref
)) {
9995 error
= got_ref_resolve_symbolic(&ref
, repo
, head_ref
);
9996 got_ref_close(head_ref
);
10001 error
= got_pathlist_append(&branches
, got_ref_get_name(ref
),
10009 /* Release work tree lock. */
10010 got_worktree_close(worktree
);
10014 if (verbosity
>= 0) {
10015 printf("Connecting to \"%s\" %s://%s%s%s%s%s\n",
10016 remote
->name
, proto
, host
,
10017 port
? ":" : "", port
? port
: "",
10018 *server_path
== '/' ? "" : "/", server_path
);
10021 error
= got_send_connect(&sendpid
, &sendfd
, proto
, host
, port
,
10022 server_path
, verbosity
);
10026 memset(&spa
, 0, sizeof(spa
));
10027 spa
.last_scaled_packsize
[0] = '\0';
10028 spa
.last_p_deltify
= -1;
10029 spa
.last_p_written
= -1;
10030 spa
.verbosity
= verbosity
;
10031 spa
.delete_branches
= &delete_branches
;
10032 error
= got_send_pack(remote_name
, &branches
, &tags
, &delete_branches
,
10033 verbosity
, overwrite_refs
, sendfd
, repo
, send_progress
, &spa
,
10034 check_cancelled
, NULL
);
10035 if (spa
.printed_something
)
10039 if (!spa
.sent_something
&& verbosity
>= 0)
10040 printf("Already up-to-date\n");
10043 if (kill(sendpid
, SIGTERM
) == -1)
10044 error
= got_error_from_errno("kill");
10045 if (waitpid(sendpid
, &sendstatus
, 0) == -1 && error
== NULL
)
10046 error
= got_error_from_errno("waitpid");
10048 if (sendfd
!= -1 && close(sendfd
) == -1 && error
== NULL
)
10049 error
= got_error_from_errno("close");
10051 const struct got_error
*close_err
= got_repo_close(repo
);
10056 got_worktree_close(worktree
);
10058 const struct got_error
*pack_err
=
10059 got_repo_pack_fds_close(pack_fds
);
10064 got_ref_close(ref
);
10065 got_repo_free_remote_repo_data(remote
);
10067 got_pathlist_free(&branches
, GOT_PATHLIST_FREE_NONE
);
10068 got_pathlist_free(&tags
, GOT_PATHLIST_FREE_NONE
);
10069 got_ref_list_free(&all_branches
);
10070 got_ref_list_free(&all_tags
);
10071 got_pathlist_free(&delete_args
, GOT_PATHLIST_FREE_NONE
);
10072 got_pathlist_free(&delete_branches
, GOT_PATHLIST_FREE_PATH
);
10084 * Print and if delete is set delete all ref_prefix references.
10085 * If wanted_ref is not NULL, only print or delete this reference.
10087 static const struct got_error
*
10088 process_logmsg_refs(const char *ref_prefix
, size_t prefix_len
,
10089 const char *wanted_ref
, int delete, struct got_worktree
*worktree
,
10090 struct got_repository
*repo
)
10092 const struct got_error
*err
;
10093 struct got_pathlist_head paths
;
10094 struct got_reflist_head refs
;
10095 struct got_reflist_entry
*re
;
10096 struct got_reflist_object_id_map
*refs_idmap
= NULL
;
10097 struct got_commit_object
*commit
= NULL
;
10098 struct got_object_id
*id
= NULL
;
10099 const char *header_prefix
;
10100 char *uuidstr
= NULL
;
10104 TAILQ_INIT(&paths
);
10106 err
= got_ref_list(&refs
, repo
, NULL
, got_ref_cmp_by_name
, repo
);
10110 err
= got_reflist_object_id_map_create(&refs_idmap
, &refs
, repo
);
10114 if (worktree
!= NULL
) {
10115 err
= got_worktree_get_uuid(&uuidstr
, worktree
);
10121 if (strncmp(wanted_ref
, "refs/heads/", 11) == 0)
10125 if (strcmp(ref_prefix
, GOT_WORKTREE_BACKOUT_REF_PREFIX
) == 0)
10126 header_prefix
= "backout";
10128 header_prefix
= "cherrypick";
10130 TAILQ_FOREACH(re
, &refs
, entry
) {
10131 const char *refname
, *wt
;
10133 refname
= got_ref_get_name(re
->ref
);
10135 err
= check_cancelled(NULL
);
10139 if (strncmp(refname
, ref_prefix
, prefix_len
) == 0)
10140 refname
+= prefix_len
+ 1; /* skip '-' delimiter */
10146 if (worktree
== NULL
|| strncmp(refname
, uuidstr
,
10147 GOT_WORKTREE_UUID_STRLEN
) == 0)
10148 refname
+= GOT_WORKTREE_UUID_STRLEN
+ 1; /* skip '-' */
10152 err
= got_repo_match_object_id(&id
, NULL
, refname
,
10153 GOT_OBJ_TYPE_COMMIT
, NULL
, repo
);
10157 err
= got_object_open_as_commit(&commit
, repo
, id
);
10162 found
= strncmp(wanted_ref
, refname
,
10163 strlen(wanted_ref
)) == 0;
10164 if (wanted_ref
&& !found
) {
10165 struct got_reflist_head
*ci_refs
;
10167 ci_refs
= got_reflist_object_id_map_lookup(refs_idmap
,
10171 char *refs_str
= NULL
;
10172 char const *r
= NULL
;
10174 err
= build_refs_str(&refs_str
, ci_refs
, id
,
10181 if (strncmp(r
, wanted_ref
,
10182 strlen(wanted_ref
)) == 0) {
10186 r
= strchr(r
, ' ');
10194 if (wanted_ref
== NULL
|| found
) {
10196 err
= got_ref_delete(re
->ref
, repo
);
10199 printf("Deleted: ");
10200 err
= print_commit_oneline(commit
, id
, repo
,
10204 * Print paths modified by commit to help
10205 * associate commits with worktree changes.
10207 err
= get_changed_paths(&paths
, commit
,
10212 err
= print_commit(commit
, id
, repo
, NULL
,
10213 &paths
, NULL
, 0, 0, refs_idmap
, NULL
,
10215 got_pathlist_free(&paths
,
10216 GOT_PATHLIST_FREE_ALL
);
10218 if (worktree
== NULL
)
10219 printf("work tree: %.*s\n\n",
10220 GOT_WORKTREE_UUID_STRLEN
, wt
);
10226 got_object_commit_close(commit
);
10232 if (wanted_ref
!= NULL
&& !found
)
10233 err
= got_error_fmt(GOT_ERR_NOT_REF
, "%s", wanted_ref
);
10238 got_ref_list_free(&refs
);
10239 got_pathlist_free(&paths
, GOT_PATHLIST_FREE_ALL
);
10241 got_reflist_object_id_map_free(refs_idmap
);
10243 got_object_commit_close(commit
);
10248 * Create new temp "logmsg" ref of the backed-out or cherrypicked commit
10249 * identified by id for log messages to prepopulate the editor on commit.
10251 static const struct got_error
*
10252 logmsg_ref(struct got_object_id
*id
, const char *prefix
,
10253 struct got_worktree
*worktree
, struct got_repository
*repo
)
10255 const struct got_error
*err
= NULL
;
10256 char *idstr
, *ref
= NULL
, *refname
= NULL
;
10257 int histedit_in_progress
;
10258 int rebase_in_progress
, merge_in_progress
;
10261 * Silenty refuse to create merge reference if any histedit, merge,
10262 * or rebase operation is in progress.
10264 err
= got_worktree_histedit_in_progress(&histedit_in_progress
,
10268 if (histedit_in_progress
)
10271 err
= got_worktree_rebase_in_progress(&rebase_in_progress
, worktree
);
10274 if (rebase_in_progress
)
10277 err
= got_worktree_merge_in_progress(&merge_in_progress
, worktree
,
10281 if (merge_in_progress
)
10284 err
= got_object_id_str(&idstr
, id
);
10288 err
= got_worktree_get_logmsg_ref_name(&refname
, worktree
, prefix
);
10292 if (asprintf(&ref
, "%s-%s", refname
, idstr
) == -1) {
10293 err
= got_error_from_errno("asprintf");
10297 err
= create_ref(ref
, got_worktree_get_base_commit_id(worktree
),
10307 usage_cherrypick(void)
10309 fprintf(stderr
, "usage: %s cherrypick [-lX] [commit-id]\n",
10314 static const struct got_error
*
10315 cmd_cherrypick(int argc
, char *argv
[])
10317 const struct got_error
*error
= NULL
;
10318 struct got_worktree
*worktree
= NULL
;
10319 struct got_repository
*repo
= NULL
;
10320 char *cwd
= NULL
, *commit_id_str
= NULL
, *keyword_idstr
= NULL
;
10321 struct got_object_id
*commit_id
= NULL
;
10322 struct got_commit_object
*commit
= NULL
;
10323 struct got_object_qid
*pid
;
10324 int ch
, list_refs
= 0, remove_refs
= 0;
10325 struct got_update_progress_arg upa
;
10326 int *pack_fds
= NULL
;
10329 if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd "
10330 "unveil", NULL
) == -1)
10334 while ((ch
= getopt(argc
, argv
, "lX")) != -1) {
10343 usage_cherrypick();
10351 if (list_refs
|| remove_refs
) {
10352 if (argc
!= 0 && argc
!= 1)
10353 usage_cherrypick();
10354 } else if (argc
!= 1)
10355 usage_cherrypick();
10356 if (list_refs
&& remove_refs
)
10357 option_conflict('l', 'X');
10359 cwd
= getcwd(NULL
, 0);
10361 error
= got_error_from_errno("getcwd");
10365 error
= got_repo_pack_fds_open(&pack_fds
);
10369 error
= got_worktree_open(&worktree
, cwd
, GOT_WORKTREE_GOT_DIR
);
10371 if (list_refs
|| remove_refs
) {
10372 if (error
->code
!= GOT_ERR_NOT_WORKTREE
)
10375 if (error
->code
== GOT_ERR_NOT_WORKTREE
)
10376 error
= wrap_not_worktree_error(error
,
10377 "cherrypick", cwd
);
10382 error
= got_repo_open(&repo
,
10383 worktree
? got_worktree_get_repo_path(worktree
) : cwd
,
10388 error
= apply_unveil(got_repo_get_path(repo
), 0,
10389 worktree
? got_worktree_get_root_path(worktree
) : NULL
);
10393 if (list_refs
|| remove_refs
) {
10394 error
= process_logmsg_refs(GOT_WORKTREE_CHERRYPICK_REF_PREFIX
,
10395 GOT_WORKTREE_CHERRYPICK_REF_PREFIX_LEN
,
10396 argc
== 1 ? argv
[0] : NULL
, remove_refs
, worktree
, repo
);
10400 error
= got_keyword_to_idstr(&keyword_idstr
, argv
[0], repo
, worktree
);
10404 error
= got_repo_match_object_id(&commit_id
, NULL
,
10405 keyword_idstr
!= NULL
? keyword_idstr
: argv
[0],
10406 GOT_OBJ_TYPE_COMMIT
, NULL
, repo
);
10409 error
= got_object_id_str(&commit_id_str
, commit_id
);
10413 error
= got_object_open_as_commit(&commit
, repo
, commit_id
);
10416 pid
= STAILQ_FIRST(got_object_commit_get_parent_ids(commit
));
10417 memset(&upa
, 0, sizeof(upa
));
10418 error
= got_worktree_merge_files(worktree
, pid
? &pid
->id
: NULL
,
10419 commit_id
, repo
, update_progress
, &upa
, check_cancelled
,
10424 if (upa
.did_something
) {
10425 error
= logmsg_ref(commit_id
,
10426 GOT_WORKTREE_CHERRYPICK_REF_PREFIX
, worktree
, repo
);
10429 printf("Merged commit %s\n", commit_id_str
);
10431 print_merge_progress_stats(&upa
);
10434 free(keyword_idstr
);
10436 got_object_commit_close(commit
);
10437 free(commit_id_str
);
10439 got_worktree_close(worktree
);
10441 const struct got_error
*close_err
= got_repo_close(repo
);
10446 const struct got_error
*pack_err
=
10447 got_repo_pack_fds_close(pack_fds
);
10456 usage_backout(void)
10458 fprintf(stderr
, "usage: %s backout [-lX] [commit-id]\n", getprogname());
10462 static const struct got_error
*
10463 cmd_backout(int argc
, char *argv
[])
10465 const struct got_error
*error
= NULL
;
10466 struct got_worktree
*worktree
= NULL
;
10467 struct got_repository
*repo
= NULL
;
10468 char *cwd
= NULL
, *commit_id_str
= NULL
, *keyword_idstr
= NULL
;
10469 struct got_object_id
*commit_id
= NULL
;
10470 struct got_commit_object
*commit
= NULL
;
10471 struct got_object_qid
*pid
;
10472 int ch
, list_refs
= 0, remove_refs
= 0;
10473 struct got_update_progress_arg upa
;
10474 int *pack_fds
= NULL
;
10477 if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd "
10478 "unveil", NULL
) == -1)
10482 while ((ch
= getopt(argc
, argv
, "lX")) != -1) {
10499 if (list_refs
|| remove_refs
) {
10500 if (argc
!= 0 && argc
!= 1)
10502 } else if (argc
!= 1)
10504 if (list_refs
&& remove_refs
)
10505 option_conflict('l', 'X');
10507 cwd
= getcwd(NULL
, 0);
10509 error
= got_error_from_errno("getcwd");
10513 error
= got_repo_pack_fds_open(&pack_fds
);
10517 error
= got_worktree_open(&worktree
, cwd
, GOT_WORKTREE_GOT_DIR
);
10519 if (list_refs
|| remove_refs
) {
10520 if (error
->code
!= GOT_ERR_NOT_WORKTREE
)
10523 if (error
->code
== GOT_ERR_NOT_WORKTREE
)
10524 error
= wrap_not_worktree_error(error
,
10530 error
= got_repo_open(&repo
,
10531 worktree
? got_worktree_get_repo_path(worktree
) : cwd
,
10536 error
= apply_unveil(got_repo_get_path(repo
), 0,
10537 worktree
? got_worktree_get_root_path(worktree
) : NULL
);
10541 if (list_refs
|| remove_refs
) {
10542 error
= process_logmsg_refs(GOT_WORKTREE_BACKOUT_REF_PREFIX
,
10543 GOT_WORKTREE_BACKOUT_REF_PREFIX_LEN
,
10544 argc
== 1 ? argv
[0] : NULL
, remove_refs
, worktree
, repo
);
10548 error
= got_keyword_to_idstr(&keyword_idstr
, argv
[0], repo
, worktree
);
10552 error
= got_repo_match_object_id(&commit_id
, NULL
,
10553 keyword_idstr
!= NULL
? keyword_idstr
: argv
[0],
10554 GOT_OBJ_TYPE_COMMIT
, NULL
, repo
);
10557 error
= got_object_id_str(&commit_id_str
, commit_id
);
10561 error
= got_object_open_as_commit(&commit
, repo
, commit_id
);
10564 pid
= STAILQ_FIRST(got_object_commit_get_parent_ids(commit
));
10566 error
= got_error(GOT_ERR_ROOT_COMMIT
);
10570 memset(&upa
, 0, sizeof(upa
));
10571 error
= got_worktree_merge_files(worktree
, commit_id
, &pid
->id
,
10572 repo
, update_progress
, &upa
, check_cancelled
, NULL
);
10576 if (upa
.did_something
) {
10577 error
= logmsg_ref(commit_id
, GOT_WORKTREE_BACKOUT_REF_PREFIX
,
10581 printf("Backed out commit %s\n", commit_id_str
);
10583 print_merge_progress_stats(&upa
);
10586 free(keyword_idstr
);
10588 got_object_commit_close(commit
);
10589 free(commit_id_str
);
10591 got_worktree_close(worktree
);
10593 const struct got_error
*close_err
= got_repo_close(repo
);
10598 const struct got_error
*pack_err
=
10599 got_repo_pack_fds_close(pack_fds
);
10609 fprintf(stderr
, "usage: %s rebase [-aCclX] [branch]\n", getprogname());
10614 trim_logmsg(char *logmsg
, int limit
)
10619 len
= strlen(logmsg
);
10622 logmsg
[len
] = '\0';
10623 nl
= strchr(logmsg
, '\n');
10628 static const struct got_error
*
10629 get_short_logmsg(char **logmsg
, int limit
, struct got_commit_object
*commit
)
10631 const struct got_error
*err
;
10632 char *logmsg0
= NULL
;
10635 err
= got_object_commit_get_logmsg(&logmsg0
, commit
);
10640 while (isspace((unsigned char)s
[0]))
10643 *logmsg
= strdup(s
);
10644 if (*logmsg
== NULL
) {
10645 err
= got_error_from_errno("strdup");
10649 trim_logmsg(*logmsg
, limit
);
10655 static const struct got_error
*
10656 show_rebase_merge_conflict(struct got_object_id
*id
,
10657 struct got_repository
*repo
)
10659 const struct got_error
*err
;
10660 struct got_commit_object
*commit
= NULL
;
10661 char *id_str
= NULL
, *logmsg
= NULL
;
10663 err
= got_object_open_as_commit(&commit
, repo
, id
);
10667 err
= got_object_id_str(&id_str
, id
);
10673 err
= get_short_logmsg(&logmsg
, 42, commit
);
10677 printf("%s -> merge conflict: %s\n", id_str
, logmsg
);
10680 got_object_commit_close(commit
);
10685 static const struct got_error
*
10686 show_rebase_progress(struct got_commit_object
*commit
,
10687 struct got_object_id
*old_id
, struct got_object_id
*new_id
)
10689 const struct got_error
*err
;
10690 char *old_id_str
= NULL
, *new_id_str
= NULL
, *logmsg
= NULL
;
10692 err
= got_object_id_str(&old_id_str
, old_id
);
10697 err
= got_object_id_str(&new_id_str
, new_id
);
10702 old_id_str
[12] = '\0';
10704 new_id_str
[12] = '\0';
10706 err
= get_short_logmsg(&logmsg
, 42, commit
);
10710 printf("%s -> %s: %s\n", old_id_str
,
10711 new_id_str
? new_id_str
: "no-op change", logmsg
);
10719 static const struct got_error
*
10720 rebase_complete(struct got_worktree
*worktree
, struct got_fileindex
*fileindex
,
10721 struct got_reference
*branch
, struct got_reference
*tmp_branch
,
10722 struct got_repository
*repo
, int create_backup
)
10724 printf("Switching work tree to %s\n", got_ref_get_name(branch
));
10725 return got_worktree_rebase_complete(worktree
, fileindex
,
10726 tmp_branch
, branch
, repo
, create_backup
);
10729 static const struct got_error
*
10730 rebase_commit(struct got_pathlist_head
*merged_paths
,
10731 struct got_worktree
*worktree
, struct got_fileindex
*fileindex
,
10732 struct got_reference
*tmp_branch
, const char *committer
,
10733 struct got_object_id
*commit_id
, int allow_conflict
,
10734 struct got_repository
*repo
)
10736 const struct got_error
*error
;
10737 struct got_commit_object
*commit
;
10738 struct got_object_id
*new_commit_id
;
10740 error
= got_object_open_as_commit(&commit
, repo
, commit_id
);
10744 error
= got_worktree_rebase_commit(&new_commit_id
, merged_paths
,
10745 worktree
, fileindex
, tmp_branch
, committer
, commit
, commit_id
,
10746 allow_conflict
, repo
);
10748 if (error
->code
!= GOT_ERR_COMMIT_NO_CHANGES
)
10750 error
= show_rebase_progress(commit
, commit_id
, NULL
);
10752 error
= show_rebase_progress(commit
, commit_id
, new_commit_id
);
10753 free(new_commit_id
);
10756 got_object_commit_close(commit
);
10760 struct check_path_prefix_arg
{
10761 const char *path_prefix
;
10766 static const struct got_error
*
10767 check_path_prefix_in_diff(void *arg
, struct got_blob_object
*blob1
,
10768 struct got_blob_object
*blob2
, FILE *f1
, FILE *f2
,
10769 struct got_object_id
*id1
, struct got_object_id
*id2
,
10770 const char *path1
, const char *path2
,
10771 mode_t mode1
, mode_t mode2
, struct got_repository
*repo
)
10773 struct check_path_prefix_arg
*a
= arg
;
10775 if ((path1
&& !got_path_is_child(path1
, a
->path_prefix
, a
->len
)) ||
10776 (path2
&& !got_path_is_child(path2
, a
->path_prefix
, a
->len
)))
10777 return got_error(a
->errcode
);
10782 static const struct got_error
*
10783 check_path_prefix(struct got_object_id
*parent_id
,
10784 struct got_object_id
*commit_id
, const char *path_prefix
,
10785 int errcode
, struct got_repository
*repo
)
10787 const struct got_error
*err
;
10788 struct got_tree_object
*tree1
= NULL
, *tree2
= NULL
;
10789 struct got_commit_object
*commit
= NULL
, *parent_commit
= NULL
;
10790 struct check_path_prefix_arg cpp_arg
;
10792 if (got_path_is_root_dir(path_prefix
))
10795 err
= got_object_open_as_commit(&commit
, repo
, commit_id
);
10799 err
= got_object_open_as_commit(&parent_commit
, repo
, parent_id
);
10803 err
= got_object_open_as_tree(&tree1
, repo
,
10804 got_object_commit_get_tree_id(parent_commit
));
10808 err
= got_object_open_as_tree(&tree2
, repo
,
10809 got_object_commit_get_tree_id(commit
));
10813 cpp_arg
.path_prefix
= path_prefix
;
10814 while (cpp_arg
.path_prefix
[0] == '/')
10815 cpp_arg
.path_prefix
++;
10816 cpp_arg
.len
= strlen(cpp_arg
.path_prefix
);
10817 cpp_arg
.errcode
= errcode
;
10818 err
= got_diff_tree(tree1
, tree2
, NULL
, NULL
, -1, -1, "", "", repo
,
10819 check_path_prefix_in_diff
, &cpp_arg
, 0);
10822 got_object_tree_close(tree1
);
10824 got_object_tree_close(tree2
);
10826 got_object_commit_close(commit
);
10828 got_object_commit_close(parent_commit
);
10832 static const struct got_error
*
10833 collect_commits(struct got_object_id_queue
*commits
,
10834 struct got_object_id
*initial_commit_id
,
10835 struct got_object_id
*iter_start_id
, struct got_object_id
*iter_stop_id
,
10836 const char *path_prefix
, int path_prefix_errcode
,
10837 struct got_repository
*repo
)
10839 const struct got_error
*err
= NULL
;
10840 struct got_commit_graph
*graph
= NULL
;
10841 struct got_object_id parent_id
, commit_id
;
10842 struct got_object_qid
*qid
;
10844 err
= got_commit_graph_open(&graph
, "/", 1);
10848 err
= got_commit_graph_iter_start(graph
, iter_start_id
, repo
,
10849 check_cancelled
, NULL
);
10853 memcpy(&commit_id
, initial_commit_id
, sizeof(commit_id
));
10854 while (got_object_id_cmp(&commit_id
, iter_stop_id
) != 0) {
10855 err
= got_commit_graph_iter_next(&parent_id
, graph
, repo
,
10856 check_cancelled
, NULL
);
10858 if (err
->code
== GOT_ERR_ITER_COMPLETED
) {
10859 err
= got_error_msg(GOT_ERR_ANCESTRY
,
10860 "ran out of commits to rebase before "
10861 "youngest common ancestor commit has "
10862 "been reached?!?");
10866 err
= check_path_prefix(&parent_id
, &commit_id
,
10867 path_prefix
, path_prefix_errcode
, repo
);
10871 err
= got_object_qid_alloc(&qid
, &commit_id
);
10874 STAILQ_INSERT_HEAD(commits
, qid
, entry
);
10876 memcpy(&commit_id
, &parent_id
, sizeof(commit_id
));
10880 got_commit_graph_close(graph
);
10884 static const struct got_error
*
10885 get_commit_brief_str(char **brief_str
, struct got_commit_object
*commit
)
10887 const struct got_error
*err
= NULL
;
10888 time_t committer_time
;
10890 char datebuf
[11]; /* YYYY-MM-DD + NUL */
10891 char *author0
= NULL
, *author
, *smallerthan
;
10892 char *logmsg0
= NULL
, *logmsg
, *newline
;
10894 committer_time
= got_object_commit_get_committer_time(commit
);
10895 if (gmtime_r(&committer_time
, &tm
) == NULL
)
10896 return got_error_from_errno("gmtime_r");
10897 if (strftime(datebuf
, sizeof(datebuf
), "%G-%m-%d", &tm
) == 0)
10898 return got_error(GOT_ERR_NO_SPACE
);
10900 author0
= strdup(got_object_commit_get_author(commit
));
10901 if (author0
== NULL
)
10902 return got_error_from_errno("strdup");
10904 smallerthan
= strchr(author
, '<');
10905 if (smallerthan
&& smallerthan
[1] != '\0')
10906 author
= smallerthan
+ 1;
10907 author
[strcspn(author
, "@>")] = '\0';
10909 err
= got_object_commit_get_logmsg(&logmsg0
, commit
);
10913 while (*logmsg
== '\n')
10915 newline
= strchr(logmsg
, '\n');
10919 if (asprintf(brief_str
, "%s %s %s",
10920 datebuf
, author
, logmsg
) == -1)
10921 err
= got_error_from_errno("asprintf");
10928 static const struct got_error
*
10929 delete_backup_ref(struct got_reference
*ref
, struct got_object_id
*id
,
10930 struct got_repository
*repo
)
10932 const struct got_error
*err
;
10935 err
= got_object_id_str(&id_str
, id
);
10939 err
= got_ref_delete(ref
, repo
);
10943 printf("Deleted %s: %s\n", got_ref_get_name(ref
), id_str
);
10949 static const struct got_error
*
10950 print_backup_ref(const char *branch_name
, const char *new_id_str
,
10951 struct got_object_id
*old_commit_id
, struct got_commit_object
*old_commit
,
10952 struct got_reflist_object_id_map
*refs_idmap
,
10953 struct got_repository
*repo
)
10955 const struct got_error
*err
= NULL
;
10956 struct got_reflist_head
*refs
;
10957 char *refs_str
= NULL
;
10958 struct got_object_id
*new_commit_id
= NULL
;
10959 struct got_commit_object
*new_commit
= NULL
;
10960 char *new_commit_brief_str
= NULL
;
10961 struct got_object_id
*yca_id
= NULL
;
10962 struct got_commit_object
*yca_commit
= NULL
;
10963 char *yca_id_str
= NULL
, *yca_brief_str
= NULL
;
10964 char *custom_refs_str
;
10966 if (asprintf(&custom_refs_str
, "formerly %s", branch_name
) == -1)
10967 return got_error_from_errno("asprintf");
10969 err
= print_commit(old_commit
, old_commit_id
, repo
, NULL
, NULL
, NULL
,
10970 0, 0, refs_idmap
, custom_refs_str
, NULL
);
10974 err
= got_object_resolve_id_str(&new_commit_id
, repo
, new_id_str
);
10978 refs
= got_reflist_object_id_map_lookup(refs_idmap
, new_commit_id
);
10980 err
= build_refs_str(&refs_str
, refs
, new_commit_id
, repo
, 0);
10985 err
= got_object_open_as_commit(&new_commit
, repo
, new_commit_id
);
10989 err
= get_commit_brief_str(&new_commit_brief_str
, new_commit
);
10993 err
= got_commit_graph_find_youngest_common_ancestor(&yca_id
,
10994 old_commit_id
, new_commit_id
, 1, repo
, check_cancelled
, NULL
);
10998 printf("has become commit %s%s%s%s\n %s\n", new_id_str
,
10999 refs_str
? " (" : "", refs_str
? refs_str
: "",
11000 refs_str
? ")" : "", new_commit_brief_str
);
11001 if (yca_id
&& got_object_id_cmp(yca_id
, new_commit_id
) != 0 &&
11002 got_object_id_cmp(yca_id
, old_commit_id
) != 0) {
11006 err
= got_object_open_as_commit(&yca_commit
, repo
, yca_id
);
11010 err
= get_commit_brief_str(&yca_brief_str
, yca_commit
);
11014 err
= got_object_id_str(&yca_id_str
, yca_id
);
11018 refs
= got_reflist_object_id_map_lookup(refs_idmap
, yca_id
);
11020 err
= build_refs_str(&refs_str
, refs
, yca_id
, repo
, 0);
11024 printf("history forked at %s%s%s%s\n %s\n",
11026 refs_str
? " (" : "", refs_str
? refs_str
: "",
11027 refs_str
? ")" : "", yca_brief_str
);
11030 free(custom_refs_str
);
11031 free(new_commit_id
);
11035 free(yca_brief_str
);
11037 got_object_commit_close(new_commit
);
11039 got_object_commit_close(yca_commit
);
11044 static const struct got_error
*
11045 worktree_has_logmsg_ref(const char *caller
, struct got_worktree
*worktree
,
11046 struct got_repository
*repo
)
11048 const struct got_error
*err
;
11049 struct got_reflist_head refs
;
11050 struct got_reflist_entry
*re
;
11051 char *uuidstr
= NULL
;
11052 static char msg
[160];
11056 err
= got_worktree_get_uuid(&uuidstr
, worktree
);
11060 err
= got_ref_list(&refs
, repo
, "refs/got/worktree",
11061 got_ref_cmp_by_name
, repo
);
11065 TAILQ_FOREACH(re
, &refs
, entry
) {
11066 const char *cmd
, *refname
, *type
;
11068 refname
= got_ref_get_name(re
->ref
);
11070 if (strncmp(refname
, GOT_WORKTREE_CHERRYPICK_REF_PREFIX
,
11071 GOT_WORKTREE_CHERRYPICK_REF_PREFIX_LEN
) == 0) {
11072 refname
+= GOT_WORKTREE_CHERRYPICK_REF_PREFIX_LEN
+ 1;
11073 cmd
= "cherrypick";
11074 type
= "cherrypicked";
11075 } else if (strncmp(refname
, GOT_WORKTREE_BACKOUT_REF_PREFIX
,
11076 GOT_WORKTREE_BACKOUT_REF_PREFIX_LEN
) == 0) {
11077 refname
+= GOT_WORKTREE_BACKOUT_REF_PREFIX_LEN
+ 1;
11079 type
= "backed-out";
11083 if (strncmp(refname
, uuidstr
, GOT_WORKTREE_UUID_STRLEN
) != 0)
11086 snprintf(msg
, sizeof(msg
),
11087 "work tree has references created by %s commits which "
11088 "must be removed with 'got %s -X' before running the %s "
11089 "command", type
, cmd
, caller
);
11090 err
= got_error_msg(GOT_ERR_WORKTREE_META
, msg
);
11096 got_ref_list_free(&refs
);
11100 static const struct got_error
*
11101 process_backup_refs(const char *backup_ref_prefix
,
11102 const char *wanted_branch_name
,
11103 int delete, struct got_repository
*repo
)
11105 const struct got_error
*err
;
11106 struct got_reflist_head refs
, backup_refs
;
11107 struct got_reflist_entry
*re
;
11108 const size_t backup_ref_prefix_len
= strlen(backup_ref_prefix
);
11109 struct got_object_id
*old_commit_id
= NULL
;
11110 char *branch_name
= NULL
;
11111 struct got_commit_object
*old_commit
= NULL
;
11112 struct got_reflist_object_id_map
*refs_idmap
= NULL
;
11113 int wanted_branch_found
= 0;
11116 TAILQ_INIT(&backup_refs
);
11118 err
= got_ref_list(&refs
, repo
, NULL
, got_ref_cmp_by_name
, NULL
);
11122 err
= got_reflist_object_id_map_create(&refs_idmap
, &refs
, repo
);
11126 if (wanted_branch_name
) {
11127 if (strncmp(wanted_branch_name
, "refs/heads/", 11) == 0)
11128 wanted_branch_name
+= 11;
11131 err
= got_ref_list(&backup_refs
, repo
, backup_ref_prefix
,
11132 got_ref_cmp_by_commit_timestamp_descending
, repo
);
11136 TAILQ_FOREACH(re
, &backup_refs
, entry
) {
11137 const char *refname
= got_ref_get_name(re
->ref
);
11140 err
= check_cancelled(NULL
);
11144 err
= got_ref_resolve(&old_commit_id
, repo
, re
->ref
);
11148 err
= got_object_open_as_commit(&old_commit
, repo
,
11153 if (strncmp(backup_ref_prefix
, refname
,
11154 backup_ref_prefix_len
) == 0)
11155 refname
+= backup_ref_prefix_len
;
11157 while (refname
[0] == '/')
11160 branch_name
= strdup(refname
);
11161 if (branch_name
== NULL
) {
11162 err
= got_error_from_errno("strdup");
11165 slash
= strrchr(branch_name
, '/');
11168 refname
+= strlen(branch_name
) + 1;
11171 if (wanted_branch_name
== NULL
||
11172 strcmp(wanted_branch_name
, branch_name
) == 0) {
11173 wanted_branch_found
= 1;
11175 err
= delete_backup_ref(re
->ref
,
11176 old_commit_id
, repo
);
11178 err
= print_backup_ref(branch_name
, refname
,
11179 old_commit_id
, old_commit
, refs_idmap
,
11186 free(old_commit_id
);
11187 old_commit_id
= NULL
;
11189 branch_name
= NULL
;
11190 got_object_commit_close(old_commit
);
11194 if (wanted_branch_name
&& !wanted_branch_found
) {
11195 err
= got_error_fmt(GOT_ERR_NOT_REF
,
11196 "%s/%s/", backup_ref_prefix
, wanted_branch_name
);
11200 got_reflist_object_id_map_free(refs_idmap
);
11201 got_ref_list_free(&refs
);
11202 got_ref_list_free(&backup_refs
);
11203 free(old_commit_id
);
11206 got_object_commit_close(old_commit
);
11210 static const struct got_error
*
11211 abort_progress(void *arg
, unsigned char status
, const char *path
)
11214 * Unversioned files should not clutter progress output when
11215 * an operation is aborted.
11217 if (status
== GOT_STATUS_UNVERSIONED
)
11220 return update_progress(arg
, status
, path
);
11223 static const struct got_error
*
11224 cmd_rebase(int argc
, char *argv
[])
11226 const struct got_error
*error
= NULL
;
11227 struct got_worktree
*worktree
= NULL
;
11228 struct got_repository
*repo
= NULL
;
11229 struct got_fileindex
*fileindex
= NULL
;
11230 char *cwd
= NULL
, *committer
= NULL
, *gitconfig_path
= NULL
;
11231 struct got_reference
*branch
= NULL
;
11232 struct got_reference
*new_base_branch
= NULL
, *tmp_branch
= NULL
;
11233 struct got_object_id
*commit_id
= NULL
, *parent_id
= NULL
;
11234 struct got_object_id
*resume_commit_id
= NULL
;
11235 struct got_object_id
*branch_head_commit_id
= NULL
, *yca_id
= NULL
;
11236 struct got_object_id
*head_commit_id
= NULL
;
11237 struct got_reference
*head_ref
= NULL
;
11238 struct got_commit_object
*commit
= NULL
;
11239 int ch
, rebase_in_progress
= 0, abort_rebase
= 0, continue_rebase
= 0;
11240 int histedit_in_progress
= 0, merge_in_progress
= 0;
11241 int create_backup
= 1, list_backups
= 0, delete_backups
= 0;
11242 int allow_conflict
= 0;
11243 struct got_object_id_queue commits
;
11244 struct got_pathlist_head merged_paths
;
11245 const struct got_object_id_queue
*parent_ids
;
11246 struct got_object_qid
*qid
, *pid
;
11247 struct got_update_progress_arg upa
;
11248 int *pack_fds
= NULL
;
11250 STAILQ_INIT(&commits
);
11251 TAILQ_INIT(&merged_paths
);
11252 memset(&upa
, 0, sizeof(upa
));
11255 if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd "
11256 "unveil", NULL
) == -1)
11260 while ((ch
= getopt(argc
, argv
, "aCclX")) != -1) {
11266 allow_conflict
= 1;
11269 continue_rebase
= 1;
11275 delete_backups
= 1;
11286 if (list_backups
) {
11288 option_conflict('l', 'a');
11289 if (allow_conflict
)
11290 option_conflict('l', 'C');
11291 if (continue_rebase
)
11292 option_conflict('l', 'c');
11293 if (delete_backups
)
11294 option_conflict('l', 'X');
11295 if (argc
!= 0 && argc
!= 1)
11297 } else if (delete_backups
) {
11299 option_conflict('X', 'a');
11300 if (allow_conflict
)
11301 option_conflict('X', 'C');
11302 if (continue_rebase
)
11303 option_conflict('X', 'c');
11305 option_conflict('l', 'X');
11306 if (argc
!= 0 && argc
!= 1)
11308 } else if (allow_conflict
) {
11310 option_conflict('C', 'a');
11311 if (!continue_rebase
)
11312 errx(1, "-C option requires -c");
11314 if (abort_rebase
&& continue_rebase
)
11316 else if (abort_rebase
|| continue_rebase
) {
11319 } else if (argc
!= 1)
11323 cwd
= getcwd(NULL
, 0);
11325 error
= got_error_from_errno("getcwd");
11329 error
= got_repo_pack_fds_open(&pack_fds
);
11333 error
= got_worktree_open(&worktree
, cwd
, GOT_WORKTREE_GOT_DIR
);
11335 if (list_backups
|| delete_backups
) {
11336 if (error
->code
!= GOT_ERR_NOT_WORKTREE
)
11339 if (error
->code
== GOT_ERR_NOT_WORKTREE
)
11340 error
= wrap_not_worktree_error(error
,
11346 error
= get_gitconfig_path(&gitconfig_path
);
11349 error
= got_repo_open(&repo
,
11350 worktree
? got_worktree_get_repo_path(worktree
) : cwd
,
11351 gitconfig_path
, pack_fds
);
11355 if (worktree
!= NULL
&& !list_backups
&& !delete_backups
) {
11356 error
= worktree_has_logmsg_ref("rebase", worktree
, repo
);
11361 error
= get_author(&committer
, repo
, worktree
);
11362 if (error
&& error
->code
!= GOT_ERR_COMMIT_NO_AUTHOR
)
11365 error
= apply_unveil(got_repo_get_path(repo
), 0,
11366 worktree
? got_worktree_get_root_path(worktree
) : NULL
);
11370 if (list_backups
|| delete_backups
) {
11371 error
= process_backup_refs(
11372 GOT_WORKTREE_REBASE_BACKUP_REF_PREFIX
,
11373 argc
== 1 ? argv
[0] : NULL
, delete_backups
, repo
);
11374 goto done
; /* nothing else to do */
11377 error
= got_worktree_histedit_in_progress(&histedit_in_progress
,
11381 if (histedit_in_progress
) {
11382 error
= got_error(GOT_ERR_HISTEDIT_BUSY
);
11386 error
= got_worktree_merge_in_progress(&merge_in_progress
,
11390 if (merge_in_progress
) {
11391 error
= got_error(GOT_ERR_MERGE_BUSY
);
11395 error
= got_worktree_rebase_in_progress(&rebase_in_progress
, worktree
);
11399 if (abort_rebase
) {
11400 if (!rebase_in_progress
) {
11401 error
= got_error(GOT_ERR_NOT_REBASING
);
11404 error
= got_worktree_rebase_continue(&resume_commit_id
,
11405 &new_base_branch
, &tmp_branch
, &branch
, &fileindex
,
11409 printf("Switching work tree to %s\n",
11410 got_ref_get_symref_target(new_base_branch
));
11411 error
= got_worktree_rebase_abort(worktree
, fileindex
, repo
,
11412 new_base_branch
, abort_progress
, &upa
);
11415 printf("Rebase of %s aborted\n", got_ref_get_name(branch
));
11416 print_merge_progress_stats(&upa
);
11417 goto done
; /* nothing else to do */
11420 if (continue_rebase
) {
11421 if (!rebase_in_progress
) {
11422 error
= got_error(GOT_ERR_NOT_REBASING
);
11425 error
= got_worktree_rebase_continue(&resume_commit_id
,
11426 &new_base_branch
, &tmp_branch
, &branch
, &fileindex
,
11431 error
= rebase_commit(NULL
, worktree
, fileindex
, tmp_branch
,
11432 committer
, resume_commit_id
, allow_conflict
, repo
);
11436 yca_id
= got_object_id_dup(resume_commit_id
);
11437 if (yca_id
== NULL
) {
11438 error
= got_error_from_errno("got_object_id_dup");
11442 error
= got_ref_open(&branch
, repo
, argv
[0], 0);
11445 if (strncmp(got_ref_get_name(branch
), "refs/heads/", 11) != 0) {
11446 error
= got_error_msg(GOT_ERR_COMMIT_BRANCH
,
11447 "will not rebase a branch which lives outside "
11448 "the \"refs/heads/\" reference namespace");
11453 error
= got_ref_resolve(&branch_head_commit_id
, repo
, branch
);
11457 if (!continue_rebase
) {
11458 struct got_object_id
*base_commit_id
;
11460 error
= got_ref_open(&head_ref
, repo
,
11461 got_worktree_get_head_ref_name(worktree
), 0);
11464 error
= got_ref_resolve(&head_commit_id
, repo
, head_ref
);
11467 base_commit_id
= got_worktree_get_base_commit_id(worktree
);
11468 if (got_object_id_cmp(base_commit_id
, head_commit_id
) != 0) {
11469 error
= got_error(GOT_ERR_REBASE_OUT_OF_DATE
);
11473 error
= got_commit_graph_find_youngest_common_ancestor(&yca_id
,
11474 base_commit_id
, branch_head_commit_id
, 1, repo
,
11475 check_cancelled
, NULL
);
11477 if (error
->code
== GOT_ERR_ANCESTRY
) {
11478 error
= got_error_msg(GOT_ERR_ANCESTRY
,
11479 "specified branch shares no common "
11480 "ancestry with work tree's branch");
11485 if (got_object_id_cmp(base_commit_id
, yca_id
) == 0) {
11486 struct got_pathlist_head paths
;
11487 printf("%s is already based on %s\n",
11488 got_ref_get_name(branch
),
11489 got_worktree_get_head_ref_name(worktree
));
11490 error
= switch_head_ref(branch
, branch_head_commit_id
,
11494 error
= got_worktree_set_base_commit_id(worktree
, repo
,
11495 branch_head_commit_id
);
11498 TAILQ_INIT(&paths
);
11499 error
= got_pathlist_append(&paths
, "", NULL
);
11502 error
= got_worktree_checkout_files(worktree
,
11503 &paths
, repo
, update_progress
, &upa
,
11504 check_cancelled
, NULL
);
11505 got_pathlist_free(&paths
, GOT_PATHLIST_FREE_NONE
);
11508 if (upa
.did_something
) {
11510 error
= got_object_id_str(&id_str
,
11511 branch_head_commit_id
);
11514 printf("Updated to %s: %s\n",
11515 got_worktree_get_head_ref_name(worktree
),
11519 printf("Already up-to-date\n");
11520 print_update_progress_stats(&upa
);
11525 commit_id
= branch_head_commit_id
;
11526 error
= got_object_open_as_commit(&commit
, repo
, commit_id
);
11530 parent_ids
= got_object_commit_get_parent_ids(commit
);
11531 pid
= STAILQ_FIRST(parent_ids
);
11533 error
= collect_commits(&commits
, commit_id
, &pid
->id
,
11534 yca_id
, got_worktree_get_path_prefix(worktree
),
11535 GOT_ERR_REBASE_PATH
, repo
);
11540 got_object_commit_close(commit
);
11543 if (!continue_rebase
) {
11544 error
= got_worktree_rebase_prepare(&new_base_branch
,
11545 &tmp_branch
, &fileindex
, worktree
, branch
, repo
);
11550 if (STAILQ_EMPTY(&commits
)) {
11551 if (continue_rebase
) {
11552 error
= rebase_complete(worktree
, fileindex
,
11553 branch
, tmp_branch
, repo
, create_backup
);
11556 /* Fast-forward the reference of the branch. */
11557 struct got_object_id
*new_head_commit_id
;
11559 error
= got_ref_resolve(&new_head_commit_id
, repo
,
11563 error
= got_object_id_str(&id_str
, new_head_commit_id
);
11566 printf("Forwarding %s to commit %s\n",
11567 got_ref_get_name(branch
), id_str
);
11569 error
= got_ref_change_ref(branch
,
11570 new_head_commit_id
);
11573 /* No backup needed since objects did not change. */
11579 STAILQ_FOREACH(qid
, &commits
, entry
) {
11581 commit_id
= &qid
->id
;
11582 parent_id
= pid
? &pid
->id
: yca_id
;
11585 memset(&upa
, 0, sizeof(upa
));
11586 error
= got_worktree_rebase_merge_files(&merged_paths
,
11587 worktree
, fileindex
, parent_id
, commit_id
, repo
,
11588 update_progress
, &upa
, check_cancelled
, NULL
);
11592 print_merge_progress_stats(&upa
);
11593 if (upa
.conflicts
> 0 || upa
.missing
> 0 ||
11594 upa
.not_deleted
> 0 || upa
.unversioned
> 0) {
11595 if (upa
.conflicts
> 0) {
11596 error
= show_rebase_merge_conflict(&qid
->id
,
11601 got_pathlist_free(&merged_paths
, GOT_PATHLIST_FREE_PATH
);
11605 error
= rebase_commit(&merged_paths
, worktree
, fileindex
,
11606 tmp_branch
, committer
, commit_id
, 0, repo
);
11607 got_pathlist_free(&merged_paths
, GOT_PATHLIST_FREE_PATH
);
11612 if (upa
.conflicts
> 0 || upa
.missing
> 0 ||
11613 upa
.not_deleted
> 0 || upa
.unversioned
> 0) {
11614 error
= got_worktree_rebase_postpone(worktree
, fileindex
);
11617 if (upa
.conflicts
> 0 && upa
.missing
== 0 &&
11618 upa
.not_deleted
== 0 && upa
.unversioned
== 0) {
11619 error
= got_error_msg(GOT_ERR_CONFLICTS
,
11620 "conflicts must be resolved before rebasing "
11622 } else if (upa
.conflicts
> 0) {
11623 error
= got_error_msg(GOT_ERR_CONFLICTS
,
11624 "conflicts must be resolved before rebasing "
11625 "can continue; changes destined for some "
11626 "files were not yet merged and should be "
11627 "merged manually if required before the "
11628 "rebase operation is continued");
11630 error
= got_error_msg(GOT_ERR_CONFLICTS
,
11631 "changes destined for some files were not "
11632 "yet merged and should be merged manually "
11633 "if required before the rebase operation "
11637 error
= rebase_complete(worktree
, fileindex
, branch
,
11638 tmp_branch
, repo
, create_backup
);
11642 free(gitconfig_path
);
11643 got_object_id_queue_free(&commits
);
11644 free(branch_head_commit_id
);
11645 free(resume_commit_id
);
11646 free(head_commit_id
);
11649 got_object_commit_close(commit
);
11651 got_ref_close(branch
);
11652 if (new_base_branch
)
11653 got_ref_close(new_base_branch
);
11655 got_ref_close(tmp_branch
);
11657 got_ref_close(head_ref
);
11659 got_worktree_close(worktree
);
11661 const struct got_error
*close_err
= got_repo_close(repo
);
11666 const struct got_error
*pack_err
=
11667 got_repo_pack_fds_close(pack_fds
);
11675 usage_histedit(void)
11677 fprintf(stderr
, "usage: %s histedit [-aCcdeflmX] [-F histedit-script] "
11678 "[branch]\n", getprogname());
11682 #define GOT_HISTEDIT_PICK 'p'
11683 #define GOT_HISTEDIT_EDIT 'e'
11684 #define GOT_HISTEDIT_FOLD 'f'
11685 #define GOT_HISTEDIT_DROP 'd'
11686 #define GOT_HISTEDIT_MESG 'm'
11688 static const struct got_histedit_cmd
{
11689 unsigned char code
;
11692 } got_histedit_cmds
[] = {
11693 { GOT_HISTEDIT_PICK
, "pick", "use commit" },
11694 { GOT_HISTEDIT_EDIT
, "edit", "use commit but stop for amending" },
11695 { GOT_HISTEDIT_FOLD
, "fold", "combine with next commit that will "
11697 { GOT_HISTEDIT_DROP
, "drop", "remove commit from history" },
11698 { GOT_HISTEDIT_MESG
, "mesg", "open editor to edit the log message" },
11701 struct got_histedit_list_entry
{
11702 TAILQ_ENTRY(got_histedit_list_entry
) entry
;
11703 struct got_object_id
*commit_id
;
11704 const struct got_histedit_cmd
*cmd
;
11707 TAILQ_HEAD(got_histedit_list
, got_histedit_list_entry
);
11709 static const struct got_error
*
11710 histedit_write_commit(struct got_object_id
*commit_id
, const char *cmdname
,
11711 FILE *f
, struct got_repository
*repo
)
11713 const struct got_error
*err
= NULL
;
11714 char *logmsg
= NULL
, *id_str
= NULL
;
11715 struct got_commit_object
*commit
= NULL
;
11718 err
= got_object_open_as_commit(&commit
, repo
, commit_id
);
11722 err
= get_short_logmsg(&logmsg
, 34, commit
);
11726 err
= got_object_id_str(&id_str
, commit_id
);
11730 n
= fprintf(f
, "%s %s %s\n", cmdname
, id_str
, logmsg
);
11732 err
= got_ferror(f
, GOT_ERR_IO
);
11735 got_object_commit_close(commit
);
11741 static const struct got_error
*
11742 histedit_write_commit_list(struct got_object_id_queue
*commits
,
11743 FILE *f
, int edit_logmsg_only
, int fold_only
, int drop_only
,
11744 int edit_only
, struct got_repository
*repo
)
11746 const struct got_error
*err
= NULL
;
11747 struct got_object_qid
*qid
;
11748 const char *histedit_cmd
= NULL
;
11750 if (STAILQ_EMPTY(commits
))
11751 return got_error(GOT_ERR_EMPTY_HISTEDIT
);
11753 STAILQ_FOREACH(qid
, commits
, entry
) {
11754 histedit_cmd
= got_histedit_cmds
[0].name
;
11756 histedit_cmd
= "drop";
11757 else if (edit_only
)
11758 histedit_cmd
= "edit";
11759 else if (fold_only
&& STAILQ_NEXT(qid
, entry
) != NULL
)
11760 histedit_cmd
= "fold";
11761 else if (edit_logmsg_only
)
11762 histedit_cmd
= "mesg";
11763 err
= histedit_write_commit(&qid
->id
, histedit_cmd
, f
, repo
);
11771 static const struct got_error
*
11772 write_cmd_list(FILE *f
, const char *branch_name
,
11773 struct got_object_id_queue
*commits
)
11775 const struct got_error
*err
= NULL
;
11779 struct got_object_qid
*qid
;
11781 qid
= STAILQ_FIRST(commits
);
11782 err
= got_object_id_str(&id_str
, &qid
->id
);
11787 "# Editing the history of branch '%s' starting at\n"
11789 "# Commits will be processed in order from top to "
11790 "bottom of this file.\n", branch_name
, id_str
);
11792 err
= got_ferror(f
, GOT_ERR_IO
);
11796 n
= fprintf(f
, "# Available histedit commands:\n");
11798 err
= got_ferror(f
, GOT_ERR_IO
);
11802 for (i
= 0; i
< nitems(got_histedit_cmds
); i
++) {
11803 const struct got_histedit_cmd
*cmd
= &got_histedit_cmds
[i
];
11804 n
= fprintf(f
, "# %s (%c): %s\n", cmd
->name
, cmd
->code
,
11807 err
= got_ferror(f
, GOT_ERR_IO
);
11816 static const struct got_error
*
11817 histedit_syntax_error(int lineno
)
11819 static char msg
[42];
11822 ret
= snprintf(msg
, sizeof(msg
), "histedit syntax error on line %d",
11824 if (ret
< 0 || (size_t)ret
>= sizeof(msg
))
11825 return got_error(GOT_ERR_HISTEDIT_SYNTAX
);
11827 return got_error_msg(GOT_ERR_HISTEDIT_SYNTAX
, msg
);
11830 static const struct got_error
*
11831 append_folded_commit_msg(char **new_msg
, struct got_histedit_list_entry
*hle
,
11832 char *logmsg
, struct got_repository
*repo
)
11834 const struct got_error
*err
;
11835 struct got_commit_object
*folded_commit
= NULL
;
11836 char *id_str
, *folded_logmsg
= NULL
;
11838 err
= got_object_id_str(&id_str
, hle
->commit_id
);
11842 err
= got_object_open_as_commit(&folded_commit
, repo
, hle
->commit_id
);
11846 err
= got_object_commit_get_logmsg(&folded_logmsg
, folded_commit
);
11849 if (asprintf(new_msg
, "%s%s# log message of folded commit %s: %s",
11850 logmsg
? logmsg
: "", logmsg
? "\n" : "", id_str
,
11851 folded_logmsg
) == -1) {
11852 err
= got_error_from_errno("asprintf");
11856 got_object_commit_close(folded_commit
);
11858 free(folded_logmsg
);
11862 static struct got_histedit_list_entry
*
11863 get_folded_commits(struct got_histedit_list_entry
*hle
)
11865 struct got_histedit_list_entry
*prev
, *folded
= NULL
;
11867 prev
= TAILQ_PREV(hle
, got_histedit_list
, entry
);
11868 while (prev
&& (prev
->cmd
->code
== GOT_HISTEDIT_FOLD
||
11869 prev
->cmd
->code
== GOT_HISTEDIT_DROP
)) {
11870 if (prev
->cmd
->code
== GOT_HISTEDIT_FOLD
)
11872 prev
= TAILQ_PREV(prev
, got_histedit_list
, entry
);
11878 static const struct got_error
*
11879 histedit_edit_logmsg(struct got_histedit_list_entry
*hle
,
11880 struct got_repository
*repo
)
11882 char *logmsg_path
= NULL
, *id_str
= NULL
, *orig_logmsg
= NULL
;
11883 char *logmsg
= NULL
, *new_msg
= NULL
, *editor
= NULL
;
11884 const struct got_error
*err
= NULL
;
11885 struct got_commit_object
*commit
= NULL
;
11888 struct got_histedit_list_entry
*folded
= NULL
;
11890 err
= got_object_open_as_commit(&commit
, repo
, hle
->commit_id
);
11894 folded
= get_folded_commits(hle
);
11896 while (folded
!= hle
) {
11897 if (folded
->cmd
->code
== GOT_HISTEDIT_DROP
) {
11898 folded
= TAILQ_NEXT(folded
, entry
);
11901 err
= append_folded_commit_msg(&new_msg
, folded
,
11907 folded
= TAILQ_NEXT(folded
, entry
);
11911 err
= got_object_id_str(&id_str
, hle
->commit_id
);
11914 err
= got_object_commit_get_logmsg(&orig_logmsg
, commit
);
11917 logmsg_len
= asprintf(&new_msg
,
11918 "%s\n# original log message of commit %s: %s",
11919 logmsg
? logmsg
: "", id_str
, orig_logmsg
);
11920 if (logmsg_len
== -1) {
11921 err
= got_error_from_errno("asprintf");
11927 err
= got_object_id_str(&id_str
, hle
->commit_id
);
11931 err
= got_opentemp_named_fd(&logmsg_path
, &fd
,
11932 GOT_TMPDIR_STR
"/got-logmsg", "");
11936 if (write(fd
, logmsg
, logmsg_len
) == -1) {
11937 err
= got_error_from_errno2("write", logmsg_path
);
11940 if (close(fd
) == -1) {
11941 err
= got_error_from_errno2("close", logmsg_path
);
11946 err
= get_editor(&editor
);
11950 err
= edit_logmsg(&hle
->logmsg
, editor
, logmsg_path
, logmsg
,
11953 if (err
->code
!= GOT_ERR_COMMIT_MSG_EMPTY
)
11956 hle
->logmsg
= strdup(new_msg
);
11957 if (hle
->logmsg
== NULL
)
11958 err
= got_error_from_errno("strdup");
11961 if (fd
!= -1 && close(fd
) == -1 && err
== NULL
)
11962 err
= got_error_from_errno2("close", logmsg_path
);
11963 if (logmsg_path
&& unlink(logmsg_path
) != 0 && err
== NULL
)
11964 err
= got_error_from_errno2("unlink", logmsg_path
);
11970 got_object_commit_close(commit
);
11974 static const struct got_error
*
11975 histedit_parse_list(struct got_histedit_list
*histedit_cmds
,
11976 FILE *f
, struct got_repository
*repo
)
11978 const struct got_error
*err
= NULL
;
11979 char *line
= NULL
, *p
, *end
;
11980 size_t i
, linesize
= 0;
11983 const struct got_histedit_cmd
*cmd
;
11984 struct got_object_id
*commit_id
= NULL
;
11985 struct got_histedit_list_entry
*hle
= NULL
;
11988 linelen
= getline(&line
, &linesize
, f
);
11989 if (linelen
== -1) {
11990 const struct got_error
*getline_err
;
11993 getline_err
= got_error_from_errno("getline");
11994 err
= got_ferror(f
, getline_err
->code
);
11999 while (isspace((unsigned char)p
[0]))
12001 if (p
[0] == '#' || p
[0] == '\0')
12004 for (i
= 0; i
< nitems(got_histedit_cmds
); i
++) {
12005 cmd
= &got_histedit_cmds
[i
];
12006 if (strncmp(cmd
->name
, p
, strlen(cmd
->name
)) == 0 &&
12007 isspace((unsigned char)p
[strlen(cmd
->name
)])) {
12008 p
+= strlen(cmd
->name
);
12011 if (p
[0] == cmd
->code
&& isspace((unsigned char)p
[1])) {
12016 if (i
== nitems(got_histedit_cmds
)) {
12017 err
= histedit_syntax_error(lineno
);
12020 while (isspace((unsigned char)p
[0]))
12023 while (end
[0] && !isspace((unsigned char)end
[0]))
12026 err
= got_object_resolve_id_str(&commit_id
, repo
, p
);
12028 /* override error code */
12029 err
= histedit_syntax_error(lineno
);
12032 hle
= malloc(sizeof(*hle
));
12034 err
= got_error_from_errno("malloc");
12038 hle
->commit_id
= commit_id
;
12039 hle
->logmsg
= NULL
;
12041 TAILQ_INSERT_TAIL(histedit_cmds
, hle
, entry
);
12049 static const struct got_error
*
12050 histedit_check_script(struct got_histedit_list
*histedit_cmds
,
12051 struct got_object_id_queue
*commits
, struct got_repository
*repo
)
12053 const struct got_error
*err
= NULL
;
12054 struct got_object_qid
*qid
;
12055 struct got_histedit_list_entry
*hle
;
12056 static char msg
[92];
12059 if (TAILQ_EMPTY(histedit_cmds
))
12060 return got_error_msg(GOT_ERR_EMPTY_HISTEDIT
,
12061 "histedit script contains no commands");
12062 if (STAILQ_EMPTY(commits
))
12063 return got_error(GOT_ERR_EMPTY_HISTEDIT
);
12065 TAILQ_FOREACH(hle
, histedit_cmds
, entry
) {
12066 struct got_histedit_list_entry
*hle2
;
12067 TAILQ_FOREACH(hle2
, histedit_cmds
, entry
) {
12070 if (got_object_id_cmp(hle
->commit_id
,
12071 hle2
->commit_id
) != 0)
12073 err
= got_object_id_str(&id_str
, hle
->commit_id
);
12076 snprintf(msg
, sizeof(msg
), "commit %s is listed "
12077 "more than once in histedit script", id_str
);
12079 return got_error_msg(GOT_ERR_HISTEDIT_CMD
, msg
);
12083 STAILQ_FOREACH(qid
, commits
, entry
) {
12084 TAILQ_FOREACH(hle
, histedit_cmds
, entry
) {
12085 if (got_object_id_cmp(&qid
->id
, hle
->commit_id
) == 0)
12089 err
= got_object_id_str(&id_str
, &qid
->id
);
12092 snprintf(msg
, sizeof(msg
),
12093 "commit %s missing from histedit script", id_str
);
12095 return got_error_msg(GOT_ERR_HISTEDIT_CMD
, msg
);
12099 hle
= TAILQ_LAST(histedit_cmds
, got_histedit_list
);
12100 if (hle
&& hle
->cmd
->code
== GOT_HISTEDIT_FOLD
)
12101 return got_error_msg(GOT_ERR_HISTEDIT_CMD
,
12102 "last commit in histedit script cannot be folded");
12107 static const struct got_error
*
12108 histedit_run_editor(struct got_histedit_list
*histedit_cmds
,
12109 const char *path
, struct got_object_id_queue
*commits
,
12110 struct got_repository
*repo
)
12112 const struct got_error
*err
= NULL
;
12113 struct stat st
, st2
;
12114 struct timespec timeout
;
12118 err
= get_editor(&editor
);
12122 if (stat(path
, &st
) == -1) {
12123 err
= got_error_from_errno2("stat", path
);
12127 if (spawn_editor(editor
, path
) == -1) {
12128 err
= got_error_from_errno("failed spawning editor");
12132 timeout
.tv_sec
= 0;
12133 timeout
.tv_nsec
= 1;
12134 nanosleep(&timeout
, NULL
);
12136 if (stat(path
, &st2
) == -1) {
12137 err
= got_error_from_errno2("stat", path
);
12141 if (st
.st_size
== st2
.st_size
&&
12142 timespeccmp(&st
.st_mtim
, &st2
.st_mtim
, ==)) {
12143 err
= got_error_msg(GOT_ERR_EMPTY_HISTEDIT
,
12144 "no changes made to histedit script, aborting");
12148 f
= fopen(path
, "re");
12150 err
= got_error_from_errno("fopen");
12153 err
= histedit_parse_list(histedit_cmds
, f
, repo
);
12157 err
= histedit_check_script(histedit_cmds
, commits
, repo
);
12159 if (f
&& fclose(f
) == EOF
&& err
== NULL
)
12160 err
= got_error_from_errno("fclose");
12165 static const struct got_error
*
12166 histedit_edit_list_retry(struct got_histedit_list
*, const struct got_error
*,
12167 struct got_object_id_queue
*, const char *, const char *,
12168 struct got_repository
*);
12170 static const struct got_error
*
12171 histedit_edit_script(struct got_histedit_list
*histedit_cmds
,
12172 struct got_object_id_queue
*commits
, const char *branch_name
,
12173 int edit_logmsg_only
, int fold_only
, int drop_only
, int edit_only
,
12174 struct got_repository
*repo
)
12176 const struct got_error
*err
;
12180 err
= got_opentemp_named(&path
, &f
, "got-histedit", "");
12184 err
= write_cmd_list(f
, branch_name
, commits
);
12188 err
= histedit_write_commit_list(commits
, f
, edit_logmsg_only
,
12189 fold_only
, drop_only
, edit_only
, repo
);
12193 if (drop_only
|| edit_logmsg_only
|| fold_only
|| edit_only
) {
12195 err
= histedit_parse_list(histedit_cmds
, f
, repo
);
12197 if (fclose(f
) == EOF
) {
12198 err
= got_error_from_errno("fclose");
12202 err
= histedit_run_editor(histedit_cmds
, path
, commits
, repo
);
12204 if (err
->code
!= GOT_ERR_HISTEDIT_SYNTAX
&&
12205 err
->code
!= GOT_ERR_HISTEDIT_CMD
)
12207 err
= histedit_edit_list_retry(histedit_cmds
, err
,
12208 commits
, path
, branch_name
, repo
);
12212 if (f
&& fclose(f
) == EOF
&& err
== NULL
)
12213 err
= got_error_from_errno("fclose");
12214 if (path
&& unlink(path
) != 0 && err
== NULL
)
12215 err
= got_error_from_errno2("unlink", path
);
12220 static const struct got_error
*
12221 histedit_save_list(struct got_histedit_list
*histedit_cmds
,
12222 struct got_worktree
*worktree
, struct got_repository
*repo
)
12224 const struct got_error
*err
= NULL
;
12227 struct got_histedit_list_entry
*hle
;
12229 err
= got_worktree_get_histedit_script_path(&path
, worktree
);
12233 f
= fopen(path
, "we");
12235 err
= got_error_from_errno2("fopen", path
);
12238 TAILQ_FOREACH(hle
, histedit_cmds
, entry
) {
12239 err
= histedit_write_commit(hle
->commit_id
, hle
->cmd
->name
, f
,
12245 if (f
&& fclose(f
) == EOF
&& err
== NULL
)
12246 err
= got_error_from_errno("fclose");
12252 histedit_free_list(struct got_histedit_list
*histedit_cmds
)
12254 struct got_histedit_list_entry
*hle
;
12256 while ((hle
= TAILQ_FIRST(histedit_cmds
))) {
12257 TAILQ_REMOVE(histedit_cmds
, hle
, entry
);
12262 static const struct got_error
*
12263 histedit_load_list(struct got_histedit_list
*histedit_cmds
,
12264 const char *path
, struct got_repository
*repo
)
12266 const struct got_error
*err
= NULL
;
12269 f
= fopen(path
, "re");
12271 err
= got_error_from_errno2("fopen", path
);
12275 err
= histedit_parse_list(histedit_cmds
, f
, repo
);
12277 if (f
&& fclose(f
) == EOF
&& err
== NULL
)
12278 err
= got_error_from_errno("fclose");
12282 static const struct got_error
*
12283 histedit_edit_list_retry(struct got_histedit_list
*histedit_cmds
,
12284 const struct got_error
*edit_err
, struct got_object_id_queue
*commits
,
12285 const char *path
, const char *branch_name
, struct got_repository
*repo
)
12287 const struct got_error
*err
= NULL
, *prev_err
= edit_err
;
12290 while (resp
!= 'c' && resp
!= 'r' && resp
!= 'a') {
12291 printf("%s: %s\n(c)ontinue editing, (r)estart editing, "
12292 "or (a)bort: ", getprogname(), prev_err
->msg
);
12297 histedit_free_list(histedit_cmds
);
12298 err
= histedit_run_editor(histedit_cmds
, path
, commits
,
12301 if (err
->code
!= GOT_ERR_HISTEDIT_SYNTAX
&&
12302 err
->code
!= GOT_ERR_HISTEDIT_CMD
)
12309 } else if (resp
== 'r') {
12310 histedit_free_list(histedit_cmds
);
12311 err
= histedit_edit_script(histedit_cmds
,
12312 commits
, branch_name
, 0, 0, 0, 0, repo
);
12314 if (err
->code
!= GOT_ERR_HISTEDIT_SYNTAX
&&
12315 err
->code
!= GOT_ERR_HISTEDIT_CMD
)
12322 } else if (resp
== 'a') {
12323 err
= got_error(GOT_ERR_HISTEDIT_CANCEL
);
12326 printf("invalid response '%c'\n", resp
);
12332 static const struct got_error
*
12333 histedit_complete(struct got_worktree
*worktree
,
12334 struct got_fileindex
*fileindex
, struct got_reference
*tmp_branch
,
12335 struct got_reference
*branch
, struct got_repository
*repo
)
12337 printf("Switching work tree to %s\n",
12338 got_ref_get_symref_target(branch
));
12339 return got_worktree_histedit_complete(worktree
, fileindex
, tmp_branch
,
12343 static const struct got_error
*
12344 show_histedit_progress(struct got_commit_object
*commit
,
12345 struct got_histedit_list_entry
*hle
, struct got_object_id
*new_id
)
12347 const struct got_error
*err
;
12348 char *old_id_str
= NULL
, *new_id_str
= NULL
, *logmsg
= NULL
;
12350 err
= got_object_id_str(&old_id_str
, hle
->commit_id
);
12355 err
= got_object_id_str(&new_id_str
, new_id
);
12360 old_id_str
[12] = '\0';
12362 new_id_str
[12] = '\0';
12365 logmsg
= strdup(hle
->logmsg
);
12366 if (logmsg
== NULL
) {
12367 err
= got_error_from_errno("strdup");
12370 trim_logmsg(logmsg
, 42);
12372 err
= get_short_logmsg(&logmsg
, 42, commit
);
12377 switch (hle
->cmd
->code
) {
12378 case GOT_HISTEDIT_PICK
:
12379 case GOT_HISTEDIT_EDIT
:
12380 case GOT_HISTEDIT_MESG
:
12381 printf("%s -> %s: %s\n", old_id_str
,
12382 new_id_str
? new_id_str
: "no-op change", logmsg
);
12384 case GOT_HISTEDIT_DROP
:
12385 case GOT_HISTEDIT_FOLD
:
12386 printf("%s -> %s commit: %s\n", old_id_str
, hle
->cmd
->name
,
12398 static const struct got_error
*
12399 histedit_commit(struct got_pathlist_head
*merged_paths
,
12400 struct got_worktree
*worktree
, struct got_fileindex
*fileindex
,
12401 struct got_reference
*tmp_branch
, struct got_histedit_list_entry
*hle
,
12402 const char *committer
, int allow_conflict
, struct got_repository
*repo
)
12404 const struct got_error
*err
;
12405 struct got_commit_object
*commit
;
12406 struct got_object_id
*new_commit_id
;
12408 if ((hle
->cmd
->code
== GOT_HISTEDIT_EDIT
|| get_folded_commits(hle
))
12409 && hle
->logmsg
== NULL
) {
12410 err
= histedit_edit_logmsg(hle
, repo
);
12415 err
= got_object_open_as_commit(&commit
, repo
, hle
->commit_id
);
12419 err
= got_worktree_histedit_commit(&new_commit_id
, merged_paths
,
12420 worktree
, fileindex
, tmp_branch
, committer
, commit
, hle
->commit_id
,
12421 hle
->logmsg
, allow_conflict
, repo
);
12423 if (err
->code
!= GOT_ERR_COMMIT_NO_CHANGES
)
12425 err
= show_histedit_progress(commit
, hle
, NULL
);
12427 err
= show_histedit_progress(commit
, hle
, new_commit_id
);
12428 free(new_commit_id
);
12431 got_object_commit_close(commit
);
12435 static const struct got_error
*
12436 histedit_skip_commit(struct got_histedit_list_entry
*hle
,
12437 struct got_worktree
*worktree
, struct got_repository
*repo
)
12439 const struct got_error
*error
;
12440 struct got_commit_object
*commit
;
12442 error
= got_worktree_histedit_skip_commit(worktree
, hle
->commit_id
,
12447 error
= got_object_open_as_commit(&commit
, repo
, hle
->commit_id
);
12451 error
= show_histedit_progress(commit
, hle
, NULL
);
12452 got_object_commit_close(commit
);
12456 static const struct got_error
*
12457 check_local_changes(void *arg
, unsigned char status
,
12458 unsigned char staged_status
, const char *path
,
12459 struct got_object_id
*blob_id
, struct got_object_id
*staged_blob_id
,
12460 struct got_object_id
*commit_id
, int dirfd
, const char *de_name
)
12462 int *have_local_changes
= arg
;
12465 case GOT_STATUS_ADD
:
12466 case GOT_STATUS_DELETE
:
12467 case GOT_STATUS_MODIFY
:
12468 case GOT_STATUS_CONFLICT
:
12469 *have_local_changes
= 1;
12470 return got_error(GOT_ERR_CANCELLED
);
12475 switch (staged_status
) {
12476 case GOT_STATUS_ADD
:
12477 case GOT_STATUS_DELETE
:
12478 case GOT_STATUS_MODIFY
:
12479 *have_local_changes
= 1;
12480 return got_error(GOT_ERR_CANCELLED
);
12488 static const struct got_error
*
12489 cmd_histedit(int argc
, char *argv
[])
12491 const struct got_error
*error
= NULL
;
12492 struct got_worktree
*worktree
= NULL
;
12493 struct got_fileindex
*fileindex
= NULL
;
12494 struct got_repository
*repo
= NULL
;
12495 char *cwd
= NULL
, *committer
= NULL
, *gitconfig_path
= NULL
;
12496 struct got_reference
*branch
= NULL
;
12497 struct got_reference
*tmp_branch
= NULL
;
12498 struct got_object_id
*resume_commit_id
= NULL
;
12499 struct got_object_id
*base_commit_id
= NULL
;
12500 struct got_object_id
*head_commit_id
= NULL
;
12501 struct got_commit_object
*commit
= NULL
;
12502 int ch
, rebase_in_progress
= 0, merge_in_progress
= 0;
12503 struct got_update_progress_arg upa
;
12504 int edit_in_progress
= 0, abort_edit
= 0, continue_edit
= 0;
12505 int drop_only
= 0, edit_logmsg_only
= 0, fold_only
= 0, edit_only
= 0;
12506 int allow_conflict
= 0, list_backups
= 0, delete_backups
= 0;
12507 const char *edit_script_path
= NULL
;
12508 struct got_object_id_queue commits
;
12509 struct got_pathlist_head merged_paths
;
12510 const struct got_object_id_queue
*parent_ids
;
12511 struct got_object_qid
*pid
;
12512 struct got_histedit_list histedit_cmds
;
12513 struct got_histedit_list_entry
*hle
;
12514 int *pack_fds
= NULL
;
12516 STAILQ_INIT(&commits
);
12517 TAILQ_INIT(&histedit_cmds
);
12518 TAILQ_INIT(&merged_paths
);
12519 memset(&upa
, 0, sizeof(upa
));
12522 if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd "
12523 "unveil", NULL
) == -1)
12527 while ((ch
= getopt(argc
, argv
, "aCcdeF:flmX")) != -1) {
12533 allow_conflict
= 1;
12545 edit_script_path
= optarg
;
12554 edit_logmsg_only
= 1;
12557 delete_backups
= 1;
12568 if (abort_edit
&& allow_conflict
)
12569 option_conflict('a', 'C');
12570 if (abort_edit
&& continue_edit
)
12571 option_conflict('a', 'c');
12572 if (edit_script_path
&& allow_conflict
)
12573 option_conflict('F', 'C');
12574 if (edit_script_path
&& edit_logmsg_only
)
12575 option_conflict('F', 'm');
12576 if (abort_edit
&& edit_logmsg_only
)
12577 option_conflict('a', 'm');
12578 if (edit_logmsg_only
&& allow_conflict
)
12579 option_conflict('m', 'C');
12580 if (continue_edit
&& edit_logmsg_only
)
12581 option_conflict('c', 'm');
12582 if (abort_edit
&& fold_only
)
12583 option_conflict('a', 'f');
12584 if (fold_only
&& allow_conflict
)
12585 option_conflict('f', 'C');
12586 if (continue_edit
&& fold_only
)
12587 option_conflict('c', 'f');
12588 if (fold_only
&& edit_logmsg_only
)
12589 option_conflict('f', 'm');
12590 if (edit_script_path
&& fold_only
)
12591 option_conflict('F', 'f');
12592 if (abort_edit
&& edit_only
)
12593 option_conflict('a', 'e');
12594 if (continue_edit
&& edit_only
)
12595 option_conflict('c', 'e');
12596 if (edit_only
&& edit_logmsg_only
)
12597 option_conflict('e', 'm');
12598 if (edit_script_path
&& edit_only
)
12599 option_conflict('F', 'e');
12600 if (fold_only
&& edit_only
)
12601 option_conflict('f', 'e');
12602 if (drop_only
&& abort_edit
)
12603 option_conflict('d', 'a');
12604 if (drop_only
&& allow_conflict
)
12605 option_conflict('d', 'C');
12606 if (drop_only
&& continue_edit
)
12607 option_conflict('d', 'c');
12608 if (drop_only
&& edit_logmsg_only
)
12609 option_conflict('d', 'm');
12610 if (drop_only
&& edit_only
)
12611 option_conflict('d', 'e');
12612 if (drop_only
&& edit_script_path
)
12613 option_conflict('d', 'F');
12614 if (drop_only
&& fold_only
)
12615 option_conflict('d', 'f');
12616 if (list_backups
) {
12618 option_conflict('l', 'a');
12619 if (allow_conflict
)
12620 option_conflict('l', 'C');
12622 option_conflict('l', 'c');
12623 if (edit_script_path
)
12624 option_conflict('l', 'F');
12625 if (edit_logmsg_only
)
12626 option_conflict('l', 'm');
12628 option_conflict('l', 'd');
12630 option_conflict('l', 'f');
12632 option_conflict('l', 'e');
12633 if (delete_backups
)
12634 option_conflict('l', 'X');
12635 if (argc
!= 0 && argc
!= 1)
12637 } else if (delete_backups
) {
12639 option_conflict('X', 'a');
12640 if (allow_conflict
)
12641 option_conflict('X', 'C');
12643 option_conflict('X', 'c');
12645 option_conflict('X', 'd');
12646 if (edit_script_path
)
12647 option_conflict('X', 'F');
12648 if (edit_logmsg_only
)
12649 option_conflict('X', 'm');
12651 option_conflict('X', 'f');
12653 option_conflict('X', 'e');
12655 option_conflict('X', 'l');
12656 if (argc
!= 0 && argc
!= 1)
12658 } else if (allow_conflict
&& !continue_edit
)
12659 errx(1, "-C option requires -c");
12660 else if (argc
!= 0)
12664 * This command cannot apply unveil(2) in all cases because the
12665 * user may choose to run an editor to edit the histedit script
12666 * and to edit individual commit log messages.
12667 * unveil(2) traverses exec(2); if an editor is used we have to
12668 * apply unveil after edit script and log messages have been written.
12669 * XXX TODO: Make use of unveil(2) where possible.
12672 cwd
= getcwd(NULL
, 0);
12674 error
= got_error_from_errno("getcwd");
12678 error
= got_repo_pack_fds_open(&pack_fds
);
12682 error
= got_worktree_open(&worktree
, cwd
, GOT_WORKTREE_GOT_DIR
);
12684 if (list_backups
|| delete_backups
) {
12685 if (error
->code
!= GOT_ERR_NOT_WORKTREE
)
12688 if (error
->code
== GOT_ERR_NOT_WORKTREE
)
12689 error
= wrap_not_worktree_error(error
,
12695 if (list_backups
|| delete_backups
) {
12696 error
= got_repo_open(&repo
,
12697 worktree
? got_worktree_get_repo_path(worktree
) : cwd
,
12701 error
= apply_unveil(got_repo_get_path(repo
), 0,
12702 worktree
? got_worktree_get_root_path(worktree
) : NULL
);
12705 error
= process_backup_refs(
12706 GOT_WORKTREE_HISTEDIT_BACKUP_REF_PREFIX
,
12707 argc
== 1 ? argv
[0] : NULL
, delete_backups
, repo
);
12708 goto done
; /* nothing else to do */
12711 error
= get_gitconfig_path(&gitconfig_path
);
12714 error
= got_repo_open(&repo
, got_worktree_get_repo_path(worktree
),
12715 gitconfig_path
, pack_fds
);
12719 if (worktree
!= NULL
&& !list_backups
&& !delete_backups
) {
12720 error
= worktree_has_logmsg_ref("histedit", worktree
, repo
);
12725 error
= got_worktree_rebase_in_progress(&rebase_in_progress
, worktree
);
12728 if (rebase_in_progress
) {
12729 error
= got_error(GOT_ERR_REBASING
);
12733 error
= got_worktree_merge_in_progress(&merge_in_progress
, worktree
,
12737 if (merge_in_progress
) {
12738 error
= got_error(GOT_ERR_MERGE_BUSY
);
12742 error
= got_worktree_histedit_in_progress(&edit_in_progress
, worktree
);
12746 if (edit_in_progress
&& edit_logmsg_only
) {
12747 error
= got_error_msg(GOT_ERR_HISTEDIT_BUSY
,
12748 "histedit operation is in progress in this "
12749 "work tree and must be continued or aborted "
12750 "before the -m option can be used");
12753 if (edit_in_progress
&& drop_only
) {
12754 error
= got_error_msg(GOT_ERR_HISTEDIT_BUSY
,
12755 "histedit operation is in progress in this "
12756 "work tree and must be continued or aborted "
12757 "before the -d option can be used");
12760 if (edit_in_progress
&& fold_only
) {
12761 error
= got_error_msg(GOT_ERR_HISTEDIT_BUSY
,
12762 "histedit operation is in progress in this "
12763 "work tree and must be continued or aborted "
12764 "before the -f option can be used");
12767 if (edit_in_progress
&& edit_only
) {
12768 error
= got_error_msg(GOT_ERR_HISTEDIT_BUSY
,
12769 "histedit operation is in progress in this "
12770 "work tree and must be continued or aborted "
12771 "before the -e option can be used");
12775 if (edit_in_progress
&& abort_edit
) {
12776 error
= got_worktree_histedit_continue(&resume_commit_id
,
12777 &tmp_branch
, &branch
, &base_commit_id
, &fileindex
,
12781 printf("Switching work tree to %s\n",
12782 got_ref_get_symref_target(branch
));
12783 error
= got_worktree_histedit_abort(worktree
, fileindex
, repo
,
12784 branch
, base_commit_id
, abort_progress
, &upa
);
12787 printf("Histedit of %s aborted\n",
12788 got_ref_get_symref_target(branch
));
12789 print_merge_progress_stats(&upa
);
12790 goto done
; /* nothing else to do */
12791 } else if (abort_edit
) {
12792 error
= got_error(GOT_ERR_NOT_HISTEDIT
);
12796 error
= get_author(&committer
, repo
, worktree
);
12800 if (continue_edit
) {
12803 if (!edit_in_progress
) {
12804 error
= got_error(GOT_ERR_NOT_HISTEDIT
);
12808 error
= got_worktree_get_histedit_script_path(&path
, worktree
);
12812 error
= histedit_load_list(&histedit_cmds
, path
, repo
);
12817 error
= got_worktree_histedit_continue(&resume_commit_id
,
12818 &tmp_branch
, &branch
, &base_commit_id
, &fileindex
,
12823 error
= got_ref_resolve(&head_commit_id
, repo
, branch
);
12827 error
= got_object_open_as_commit(&commit
, repo
,
12831 parent_ids
= got_object_commit_get_parent_ids(commit
);
12832 pid
= STAILQ_FIRST(parent_ids
);
12834 error
= got_error(GOT_ERR_EMPTY_HISTEDIT
);
12837 error
= collect_commits(&commits
, head_commit_id
, &pid
->id
,
12838 base_commit_id
, got_worktree_get_path_prefix(worktree
),
12839 GOT_ERR_HISTEDIT_PATH
, repo
);
12840 got_object_commit_close(commit
);
12845 if (edit_in_progress
) {
12846 error
= got_error(GOT_ERR_HISTEDIT_BUSY
);
12850 error
= got_ref_open(&branch
, repo
,
12851 got_worktree_get_head_ref_name(worktree
), 0);
12855 if (strncmp(got_ref_get_name(branch
), "refs/heads/", 11) != 0) {
12856 error
= got_error_msg(GOT_ERR_COMMIT_BRANCH
,
12857 "will not edit commit history of a branch outside "
12858 "the \"refs/heads/\" reference namespace");
12862 error
= got_ref_resolve(&head_commit_id
, repo
, branch
);
12863 got_ref_close(branch
);
12868 error
= got_object_open_as_commit(&commit
, repo
,
12872 parent_ids
= got_object_commit_get_parent_ids(commit
);
12873 pid
= STAILQ_FIRST(parent_ids
);
12875 error
= got_error(GOT_ERR_EMPTY_HISTEDIT
);
12878 error
= collect_commits(&commits
, head_commit_id
, &pid
->id
,
12879 got_worktree_get_base_commit_id(worktree
),
12880 got_worktree_get_path_prefix(worktree
),
12881 GOT_ERR_HISTEDIT_PATH
, repo
);
12882 got_object_commit_close(commit
);
12887 if (STAILQ_EMPTY(&commits
)) {
12888 error
= got_error(GOT_ERR_EMPTY_HISTEDIT
);
12892 error
= got_worktree_histedit_prepare(&tmp_branch
, &branch
,
12893 &base_commit_id
, &fileindex
, worktree
, repo
);
12897 if (edit_script_path
) {
12898 error
= histedit_load_list(&histedit_cmds
,
12899 edit_script_path
, repo
);
12901 got_worktree_histedit_abort(worktree
, fileindex
,
12902 repo
, branch
, base_commit_id
,
12903 abort_progress
, &upa
);
12904 print_merge_progress_stats(&upa
);
12908 const char *branch_name
;
12909 branch_name
= got_ref_get_symref_target(branch
);
12910 if (strncmp(branch_name
, "refs/heads/", 11) == 0)
12912 error
= histedit_edit_script(&histedit_cmds
, &commits
,
12913 branch_name
, edit_logmsg_only
, fold_only
,
12914 drop_only
, edit_only
, repo
);
12916 got_worktree_histedit_abort(worktree
, fileindex
,
12917 repo
, branch
, base_commit_id
,
12918 abort_progress
, &upa
);
12919 print_merge_progress_stats(&upa
);
12925 error
= histedit_save_list(&histedit_cmds
, worktree
,
12928 got_worktree_histedit_abort(worktree
, fileindex
,
12929 repo
, branch
, base_commit_id
,
12930 abort_progress
, &upa
);
12931 print_merge_progress_stats(&upa
);
12937 error
= histedit_check_script(&histedit_cmds
, &commits
, repo
);
12941 TAILQ_FOREACH(hle
, &histedit_cmds
, entry
) {
12942 if (resume_commit_id
) {
12943 if (got_object_id_cmp(hle
->commit_id
,
12944 resume_commit_id
) != 0)
12947 resume_commit_id
= NULL
;
12948 if (hle
->cmd
->code
== GOT_HISTEDIT_DROP
||
12949 hle
->cmd
->code
== GOT_HISTEDIT_FOLD
) {
12950 error
= histedit_skip_commit(hle
, worktree
,
12955 struct got_pathlist_head paths
;
12956 int have_changes
= 0;
12958 TAILQ_INIT(&paths
);
12959 error
= got_pathlist_append(&paths
, "", NULL
);
12962 error
= got_worktree_status(worktree
, &paths
,
12963 repo
, 0, check_local_changes
, &have_changes
,
12964 check_cancelled
, NULL
);
12965 got_pathlist_free(&paths
,
12966 GOT_PATHLIST_FREE_NONE
);
12968 if (error
->code
!= GOT_ERR_CANCELLED
)
12970 if (sigint_received
|| sigpipe_received
)
12973 if (have_changes
) {
12974 error
= histedit_commit(NULL
, worktree
,
12975 fileindex
, tmp_branch
, hle
,
12976 committer
, allow_conflict
, repo
);
12980 error
= got_object_open_as_commit(
12981 &commit
, repo
, hle
->commit_id
);
12984 error
= show_histedit_progress(commit
,
12986 got_object_commit_close(commit
);
12995 if (hle
->cmd
->code
== GOT_HISTEDIT_DROP
) {
12996 error
= histedit_skip_commit(hle
, worktree
, repo
);
13001 error
= got_object_open_as_commit(&commit
, repo
,
13005 parent_ids
= got_object_commit_get_parent_ids(commit
);
13006 pid
= STAILQ_FIRST(parent_ids
);
13008 error
= got_worktree_histedit_merge_files(&merged_paths
,
13009 worktree
, fileindex
, &pid
->id
, hle
->commit_id
, repo
,
13010 update_progress
, &upa
, check_cancelled
, NULL
);
13013 got_object_commit_close(commit
);
13016 print_merge_progress_stats(&upa
);
13017 if (upa
.conflicts
> 0 || upa
.missing
> 0 ||
13018 upa
.not_deleted
> 0 || upa
.unversioned
> 0) {
13019 if (upa
.conflicts
> 0) {
13020 error
= show_rebase_merge_conflict(
13021 hle
->commit_id
, repo
);
13025 got_pathlist_free(&merged_paths
, GOT_PATHLIST_FREE_PATH
);
13029 if (hle
->cmd
->code
== GOT_HISTEDIT_EDIT
) {
13031 error
= got_object_id_str(&id_str
, hle
->commit_id
);
13034 printf("Stopping histedit for amending commit %s\n",
13037 got_pathlist_free(&merged_paths
, GOT_PATHLIST_FREE_PATH
);
13038 error
= got_worktree_histedit_postpone(worktree
,
13041 } else if (hle
->cmd
->code
== GOT_HISTEDIT_FOLD
) {
13042 error
= histedit_skip_commit(hle
, worktree
, repo
);
13046 } else if (hle
->cmd
->code
== GOT_HISTEDIT_MESG
) {
13047 error
= histedit_edit_logmsg(hle
, repo
);
13052 error
= histedit_commit(&merged_paths
, worktree
, fileindex
,
13053 tmp_branch
, hle
, committer
, allow_conflict
, repo
);
13054 got_pathlist_free(&merged_paths
, GOT_PATHLIST_FREE_PATH
);
13059 if (upa
.conflicts
> 0 || upa
.missing
> 0 ||
13060 upa
.not_deleted
> 0 || upa
.unversioned
> 0) {
13061 error
= got_worktree_histedit_postpone(worktree
, fileindex
);
13064 if (upa
.conflicts
> 0 && upa
.missing
== 0 &&
13065 upa
.not_deleted
== 0 && upa
.unversioned
== 0) {
13066 error
= got_error_msg(GOT_ERR_CONFLICTS
,
13067 "conflicts must be resolved before histedit "
13069 } else if (upa
.conflicts
> 0) {
13070 error
= got_error_msg(GOT_ERR_CONFLICTS
,
13071 "conflicts must be resolved before histedit "
13072 "can continue; changes destined for some "
13073 "files were not yet merged and should be "
13074 "merged manually if required before the "
13075 "histedit operation is continued");
13077 error
= got_error_msg(GOT_ERR_CONFLICTS
,
13078 "changes destined for some files were not "
13079 "yet merged and should be merged manually "
13080 "if required before the histedit operation "
13084 error
= histedit_complete(worktree
, fileindex
, tmp_branch
,
13089 free(gitconfig_path
);
13090 got_object_id_queue_free(&commits
);
13091 histedit_free_list(&histedit_cmds
);
13092 free(head_commit_id
);
13093 free(base_commit_id
);
13094 free(resume_commit_id
);
13096 got_object_commit_close(commit
);
13098 got_ref_close(branch
);
13100 got_ref_close(tmp_branch
);
13102 got_worktree_close(worktree
);
13104 const struct got_error
*close_err
= got_repo_close(repo
);
13109 const struct got_error
*pack_err
=
13110 got_repo_pack_fds_close(pack_fds
);
13118 usage_integrate(void)
13120 fprintf(stderr
, "usage: %s integrate branch\n", getprogname());
13124 static const struct got_error
*
13125 cmd_integrate(int argc
, char *argv
[])
13127 const struct got_error
*error
= NULL
;
13128 struct got_repository
*repo
= NULL
;
13129 struct got_worktree
*worktree
= NULL
;
13130 char *cwd
= NULL
, *refname
= NULL
, *base_refname
= NULL
;
13131 const char *branch_arg
= NULL
;
13132 struct got_reference
*branch_ref
= NULL
, *base_branch_ref
= NULL
;
13133 struct got_fileindex
*fileindex
= NULL
;
13134 struct got_object_id
*commit_id
= NULL
, *base_commit_id
= NULL
;
13136 struct got_update_progress_arg upa
;
13137 int *pack_fds
= NULL
;
13140 if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd "
13141 "unveil", NULL
) == -1)
13145 while ((ch
= getopt(argc
, argv
, "")) != -1) {
13158 branch_arg
= argv
[0];
13160 cwd
= getcwd(NULL
, 0);
13162 error
= got_error_from_errno("getcwd");
13166 error
= got_repo_pack_fds_open(&pack_fds
);
13170 error
= got_worktree_open(&worktree
, cwd
, GOT_WORKTREE_GOT_DIR
);
13172 if (error
->code
== GOT_ERR_NOT_WORKTREE
)
13173 error
= wrap_not_worktree_error(error
, "integrate",
13178 error
= check_rebase_or_histedit_in_progress(worktree
);
13182 error
= got_repo_open(&repo
, got_worktree_get_repo_path(worktree
),
13187 error
= apply_unveil(got_repo_get_path(repo
), 0,
13188 got_worktree_get_root_path(worktree
));
13192 error
= check_merge_in_progress(worktree
, repo
);
13196 if (asprintf(&refname
, "refs/heads/%s", branch_arg
) == -1) {
13197 error
= got_error_from_errno("asprintf");
13201 error
= got_worktree_integrate_prepare(&fileindex
, &branch_ref
,
13202 &base_branch_ref
, worktree
, refname
, repo
);
13206 refname
= strdup(got_ref_get_name(branch_ref
));
13207 if (refname
== NULL
) {
13208 error
= got_error_from_errno("strdup");
13209 got_worktree_integrate_abort(worktree
, fileindex
, repo
,
13210 branch_ref
, base_branch_ref
);
13213 base_refname
= strdup(got_ref_get_name(base_branch_ref
));
13214 if (base_refname
== NULL
) {
13215 error
= got_error_from_errno("strdup");
13216 got_worktree_integrate_abort(worktree
, fileindex
, repo
,
13217 branch_ref
, base_branch_ref
);
13220 if (strncmp(base_refname
, "refs/heads/", 11) != 0) {
13221 error
= got_error(GOT_ERR_INTEGRATE_BRANCH
);
13222 got_worktree_integrate_abort(worktree
, fileindex
, repo
,
13223 branch_ref
, base_branch_ref
);
13227 error
= got_ref_resolve(&commit_id
, repo
, branch_ref
);
13231 error
= got_ref_resolve(&base_commit_id
, repo
, base_branch_ref
);
13235 if (got_object_id_cmp(commit_id
, base_commit_id
) == 0) {
13236 error
= got_error_msg(GOT_ERR_SAME_BRANCH
,
13237 "specified branch has already been integrated");
13238 got_worktree_integrate_abort(worktree
, fileindex
, repo
,
13239 branch_ref
, base_branch_ref
);
13243 error
= check_linear_ancestry(commit_id
, base_commit_id
, 1, repo
);
13245 if (error
->code
== GOT_ERR_ANCESTRY
)
13246 error
= got_error(GOT_ERR_REBASE_REQUIRED
);
13247 got_worktree_integrate_abort(worktree
, fileindex
, repo
,
13248 branch_ref
, base_branch_ref
);
13252 memset(&upa
, 0, sizeof(upa
));
13253 error
= got_worktree_integrate_continue(worktree
, fileindex
, repo
,
13254 branch_ref
, base_branch_ref
, update_progress
, &upa
,
13255 check_cancelled
, NULL
);
13259 printf("Integrated %s into %s\n", refname
, base_refname
);
13260 print_update_progress_stats(&upa
);
13263 const struct got_error
*close_err
= got_repo_close(repo
);
13268 got_worktree_close(worktree
);
13270 const struct got_error
*pack_err
=
13271 got_repo_pack_fds_close(pack_fds
);
13276 free(base_commit_id
);
13279 free(base_refname
);
13286 fprintf(stderr
, "usage: %s merge [-aCcn] [branch]\n", getprogname());
13290 static const struct got_error
*
13291 cmd_merge(int argc
, char *argv
[])
13293 const struct got_error
*error
= NULL
;
13294 struct got_worktree
*worktree
= NULL
;
13295 struct got_repository
*repo
= NULL
;
13296 struct got_fileindex
*fileindex
= NULL
;
13297 char *cwd
= NULL
, *id_str
= NULL
, *author
= NULL
;
13298 char *gitconfig_path
= NULL
;
13299 struct got_reference
*branch
= NULL
, *wt_branch
= NULL
;
13300 struct got_object_id
*branch_tip
= NULL
, *yca_id
= NULL
;
13301 struct got_object_id
*wt_branch_tip
= NULL
;
13302 int ch
, merge_in_progress
= 0, abort_merge
= 0, continue_merge
= 0;
13303 int allow_conflict
= 0, prefer_fast_forward
= 1, interrupt_merge
= 0;
13304 struct got_update_progress_arg upa
;
13305 struct got_object_id
*merge_commit_id
= NULL
;
13306 char *branch_name
= NULL
;
13307 int *pack_fds
= NULL
;
13309 memset(&upa
, 0, sizeof(upa
));
13312 if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd "
13313 "unveil", NULL
) == -1)
13317 while ((ch
= getopt(argc
, argv
, "aCcMn")) != -1) {
13323 allow_conflict
= 1;
13326 continue_merge
= 1;
13329 prefer_fast_forward
= 0;
13332 interrupt_merge
= 1;
13344 if (continue_merge
)
13345 option_conflict('a', 'c');
13346 if (!prefer_fast_forward
)
13347 option_conflict('a', 'M');
13348 if (interrupt_merge
)
13349 option_conflict('a', 'n');
13350 } else if (continue_merge
) {
13351 if (!prefer_fast_forward
)
13352 option_conflict('c', 'M');
13353 if (interrupt_merge
)
13354 option_conflict('c', 'n');
13356 if (allow_conflict
) {
13357 if (!continue_merge
)
13358 errx(1, "-C option requires -c");
13360 if (abort_merge
|| continue_merge
) {
13363 } else if (argc
!= 1)
13366 cwd
= getcwd(NULL
, 0);
13368 error
= got_error_from_errno("getcwd");
13372 error
= got_repo_pack_fds_open(&pack_fds
);
13376 error
= got_worktree_open(&worktree
, cwd
, GOT_WORKTREE_GOT_DIR
);
13378 if (error
->code
== GOT_ERR_NOT_WORKTREE
)
13379 error
= wrap_not_worktree_error(error
,
13384 error
= get_gitconfig_path(&gitconfig_path
);
13387 error
= got_repo_open(&repo
,
13388 worktree
? got_worktree_get_repo_path(worktree
) : cwd
,
13389 gitconfig_path
, pack_fds
);
13393 if (worktree
!= NULL
) {
13394 error
= worktree_has_logmsg_ref("merge", worktree
, repo
);
13399 error
= apply_unveil(got_repo_get_path(repo
), 0,
13400 worktree
? got_worktree_get_root_path(worktree
) : NULL
);
13404 error
= check_rebase_or_histedit_in_progress(worktree
);
13408 error
= got_worktree_merge_in_progress(&merge_in_progress
, worktree
,
13413 if (merge_in_progress
&& !(abort_merge
|| continue_merge
)) {
13414 error
= got_error(GOT_ERR_MERGE_BUSY
);
13418 if (!merge_in_progress
&& (abort_merge
|| continue_merge
)) {
13419 error
= got_error(GOT_ERR_NOT_MERGING
);
13424 error
= got_worktree_merge_continue(&branch_name
,
13425 &branch_tip
, &fileindex
, worktree
, repo
);
13428 error
= got_worktree_merge_abort(worktree
, fileindex
, repo
,
13429 abort_progress
, &upa
);
13432 printf("Merge of %s aborted\n", branch_name
);
13433 goto done
; /* nothing else to do */
13436 if (strncmp(got_worktree_get_head_ref_name(worktree
),
13437 "refs/heads/", 11) != 0) {
13438 error
= got_error_fmt(GOT_ERR_COMMIT_BRANCH
,
13439 "work tree's current branch %s is outside the "
13440 "\"refs/heads/\" reference namespace; "
13441 "update -b required",
13442 got_worktree_get_head_ref_name(worktree
));
13446 error
= get_author(&author
, repo
, worktree
);
13450 error
= got_ref_open(&wt_branch
, repo
,
13451 got_worktree_get_head_ref_name(worktree
), 0);
13454 error
= got_ref_resolve(&wt_branch_tip
, repo
, wt_branch
);
13458 if (continue_merge
) {
13459 struct got_object_id
*base_commit_id
;
13460 base_commit_id
= got_worktree_get_base_commit_id(worktree
);
13461 if (got_object_id_cmp(wt_branch_tip
, base_commit_id
) != 0) {
13462 error
= got_error(GOT_ERR_MERGE_COMMIT_OUT_OF_DATE
);
13465 error
= got_worktree_merge_continue(&branch_name
,
13466 &branch_tip
, &fileindex
, worktree
, repo
);
13470 error
= got_ref_open(&branch
, repo
, argv
[0], 0);
13473 branch_name
= strdup(got_ref_get_name(branch
));
13474 if (branch_name
== NULL
) {
13475 error
= got_error_from_errno("strdup");
13478 error
= got_ref_resolve(&branch_tip
, repo
, branch
);
13483 error
= got_commit_graph_find_youngest_common_ancestor(&yca_id
,
13484 wt_branch_tip
, branch_tip
, 0, repo
,
13485 check_cancelled
, NULL
);
13486 if (error
&& error
->code
!= GOT_ERR_ANCESTRY
)
13489 if (!continue_merge
) {
13490 error
= check_path_prefix(wt_branch_tip
, branch_tip
,
13491 got_worktree_get_path_prefix(worktree
),
13492 GOT_ERR_MERGE_PATH
, repo
);
13495 error
= got_worktree_merge_prepare(&fileindex
, worktree
, repo
);
13498 if (prefer_fast_forward
&& yca_id
&&
13499 got_object_id_cmp(wt_branch_tip
, yca_id
) == 0) {
13500 struct got_pathlist_head paths
;
13501 if (interrupt_merge
) {
13502 error
= got_error_fmt(GOT_ERR_BAD_OPTION
,
13503 "there are no changes to merge since %s "
13504 "is already based on %s; merge cannot be "
13505 "interrupted for amending; -n",
13506 branch_name
, got_ref_get_name(wt_branch
));
13509 printf("Forwarding %s to %s\n",
13510 got_ref_get_name(wt_branch
), branch_name
);
13511 error
= got_ref_change_ref(wt_branch
, branch_tip
);
13514 error
= got_ref_write(wt_branch
, repo
);
13517 error
= got_worktree_set_base_commit_id(worktree
, repo
,
13521 TAILQ_INIT(&paths
);
13522 error
= got_pathlist_append(&paths
, "", NULL
);
13525 error
= got_worktree_checkout_files(worktree
,
13526 &paths
, repo
, update_progress
, &upa
,
13527 check_cancelled
, NULL
);
13528 got_pathlist_free(&paths
, GOT_PATHLIST_FREE_NONE
);
13531 if (upa
.did_something
) {
13533 error
= got_object_id_str(&id_str
, branch_tip
);
13536 printf("Updated to commit %s\n", id_str
);
13539 printf("Already up-to-date\n");
13540 print_update_progress_stats(&upa
);
13543 error
= got_worktree_merge_write_refs(worktree
, branch
, repo
);
13547 error
= got_worktree_merge_branch(worktree
, fileindex
,
13548 yca_id
, branch_tip
, repo
, update_progress
, &upa
,
13549 check_cancelled
, NULL
);
13552 print_merge_progress_stats(&upa
);
13553 if (!upa
.did_something
) {
13554 error
= got_worktree_merge_abort(worktree
, fileindex
,
13555 repo
, abort_progress
, &upa
);
13558 printf("Already up-to-date\n");
13563 if (interrupt_merge
) {
13564 error
= got_worktree_merge_postpone(worktree
, fileindex
);
13567 printf("Merge of %s interrupted on request\n", branch_name
);
13568 } else if (upa
.conflicts
> 0 || upa
.missing
> 0 ||
13569 upa
.not_deleted
> 0 || upa
.unversioned
> 0) {
13570 error
= got_worktree_merge_postpone(worktree
, fileindex
);
13573 if (upa
.conflicts
> 0 && upa
.missing
== 0 &&
13574 upa
.not_deleted
== 0 && upa
.unversioned
== 0) {
13575 error
= got_error_msg(GOT_ERR_CONFLICTS
,
13576 "conflicts must be resolved before merging "
13578 } else if (upa
.conflicts
> 0) {
13579 error
= got_error_msg(GOT_ERR_CONFLICTS
,
13580 "conflicts must be resolved before merging "
13581 "can continue; changes destined for some "
13582 "files were not yet merged and "
13583 "should be merged manually if required before the "
13584 "merge operation is continued");
13586 error
= got_error_msg(GOT_ERR_CONFLICTS
,
13587 "changes destined for some "
13588 "files were not yet merged and should be "
13589 "merged manually if required before the "
13590 "merge operation is continued");
13594 error
= got_worktree_merge_commit(&merge_commit_id
, worktree
,
13595 fileindex
, author
, NULL
, 1, branch_tip
, branch_name
,
13596 allow_conflict
, repo
, continue_merge
? print_status
: NULL
,
13600 error
= got_worktree_merge_complete(worktree
, fileindex
, repo
);
13603 error
= got_object_id_str(&id_str
, merge_commit_id
);
13606 printf("Merged %s into %s: %s\n", branch_name
,
13607 got_worktree_get_head_ref_name(worktree
),
13612 free(gitconfig_path
);
13614 free(merge_commit_id
);
13620 got_ref_close(branch
);
13622 got_ref_close(wt_branch
);
13624 got_worktree_close(worktree
);
13626 const struct got_error
*close_err
= got_repo_close(repo
);
13631 const struct got_error
*pack_err
=
13632 got_repo_pack_fds_close(pack_fds
);
13642 fprintf(stderr
, "usage: %s stage [-lpS] [-F response-script] "
13643 "[path ...]\n", getprogname());
13647 static const struct got_error
*
13648 print_stage(void *arg
, unsigned char status
, unsigned char staged_status
,
13649 const char *path
, struct got_object_id
*blob_id
,
13650 struct got_object_id
*staged_blob_id
, struct got_object_id
*commit_id
,
13651 int dirfd
, const char *de_name
)
13653 const struct got_error
*err
= NULL
;
13654 char *id_str
= NULL
;
13656 if (staged_status
!= GOT_STATUS_ADD
&&
13657 staged_status
!= GOT_STATUS_MODIFY
&&
13658 staged_status
!= GOT_STATUS_DELETE
)
13661 if (staged_status
== GOT_STATUS_ADD
||
13662 staged_status
== GOT_STATUS_MODIFY
)
13663 err
= got_object_id_str(&id_str
, staged_blob_id
);
13665 err
= got_object_id_str(&id_str
, blob_id
);
13669 printf("%s %c %s\n", id_str
, staged_status
, path
);
13674 static const struct got_error
*
13675 cmd_stage(int argc
, char *argv
[])
13677 const struct got_error
*error
= NULL
;
13678 struct got_repository
*repo
= NULL
;
13679 struct got_worktree
*worktree
= NULL
;
13681 struct got_pathlist_head paths
;
13682 int ch
, list_stage
= 0, pflag
= 0, allow_bad_symlinks
= 0;
13683 FILE *patch_script_file
= NULL
;
13684 const char *patch_script_path
= NULL
;
13685 struct choose_patch_arg cpa
;
13686 int *pack_fds
= NULL
;
13688 TAILQ_INIT(&paths
);
13691 if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd "
13692 "unveil", NULL
) == -1)
13696 while ((ch
= getopt(argc
, argv
, "F:lpS")) != -1) {
13699 patch_script_path
= optarg
;
13708 allow_bad_symlinks
= 1;
13719 if (list_stage
&& (pflag
|| patch_script_path
))
13720 errx(1, "-l option cannot be used with other options");
13721 if (patch_script_path
&& !pflag
)
13722 errx(1, "-F option can only be used together with -p option");
13724 cwd
= getcwd(NULL
, 0);
13726 error
= got_error_from_errno("getcwd");
13730 error
= got_repo_pack_fds_open(&pack_fds
);
13734 error
= got_worktree_open(&worktree
, cwd
, GOT_WORKTREE_GOT_DIR
);
13736 if (error
->code
== GOT_ERR_NOT_WORKTREE
)
13737 error
= wrap_not_worktree_error(error
, "stage", cwd
);
13741 error
= got_repo_open(&repo
, got_worktree_get_repo_path(worktree
),
13746 if (patch_script_path
) {
13747 patch_script_file
= fopen(patch_script_path
, "re");
13748 if (patch_script_file
== NULL
) {
13749 error
= got_error_from_errno2("fopen",
13750 patch_script_path
);
13754 error
= apply_unveil(got_repo_get_path(repo
), 0,
13755 got_worktree_get_root_path(worktree
));
13759 error
= check_merge_in_progress(worktree
, repo
);
13763 error
= get_worktree_paths_from_argv(&paths
, argc
, argv
, worktree
);
13768 error
= got_worktree_status(worktree
, &paths
, repo
, 0,
13769 print_stage
, NULL
, check_cancelled
, NULL
);
13771 cpa
.patch_script_file
= patch_script_file
;
13772 cpa
.action
= "stage";
13773 error
= got_worktree_stage(worktree
, &paths
,
13774 pflag
? NULL
: print_status
, NULL
,
13775 pflag
? choose_patch
: NULL
, &cpa
,
13776 allow_bad_symlinks
, repo
);
13779 if (patch_script_file
&& fclose(patch_script_file
) == EOF
&&
13781 error
= got_error_from_errno2("fclose", patch_script_path
);
13783 const struct got_error
*close_err
= got_repo_close(repo
);
13788 got_worktree_close(worktree
);
13790 const struct got_error
*pack_err
=
13791 got_repo_pack_fds_close(pack_fds
);
13795 got_pathlist_free(&paths
, GOT_PATHLIST_FREE_PATH
);
13801 usage_unstage(void)
13803 fprintf(stderr
, "usage: %s unstage [-p] [-F response-script] "
13804 "[path ...]\n", getprogname());
13809 static const struct got_error
*
13810 cmd_unstage(int argc
, char *argv
[])
13812 const struct got_error
*error
= NULL
;
13813 struct got_repository
*repo
= NULL
;
13814 struct got_worktree
*worktree
= NULL
;
13816 struct got_pathlist_head paths
;
13818 struct got_update_progress_arg upa
;
13819 FILE *patch_script_file
= NULL
;
13820 const char *patch_script_path
= NULL
;
13821 struct choose_patch_arg cpa
;
13822 int *pack_fds
= NULL
;
13824 TAILQ_INIT(&paths
);
13827 if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd "
13828 "unveil", NULL
) == -1)
13832 while ((ch
= getopt(argc
, argv
, "F:p")) != -1) {
13835 patch_script_path
= optarg
;
13849 if (patch_script_path
&& !pflag
)
13850 errx(1, "-F option can only be used together with -p option");
13852 cwd
= getcwd(NULL
, 0);
13854 error
= got_error_from_errno("getcwd");
13858 error
= got_repo_pack_fds_open(&pack_fds
);
13862 error
= got_worktree_open(&worktree
, cwd
, GOT_WORKTREE_GOT_DIR
);
13864 if (error
->code
== GOT_ERR_NOT_WORKTREE
)
13865 error
= wrap_not_worktree_error(error
, "unstage", cwd
);
13869 error
= got_repo_open(&repo
, got_worktree_get_repo_path(worktree
),
13874 if (patch_script_path
) {
13875 patch_script_file
= fopen(patch_script_path
, "re");
13876 if (patch_script_file
== NULL
) {
13877 error
= got_error_from_errno2("fopen",
13878 patch_script_path
);
13883 error
= apply_unveil(got_repo_get_path(repo
), 0,
13884 got_worktree_get_root_path(worktree
));
13888 error
= get_worktree_paths_from_argv(&paths
, argc
, argv
, worktree
);
13892 cpa
.patch_script_file
= patch_script_file
;
13893 cpa
.action
= "unstage";
13894 memset(&upa
, 0, sizeof(upa
));
13895 error
= got_worktree_unstage(worktree
, &paths
, update_progress
,
13896 &upa
, pflag
? choose_patch
: NULL
, &cpa
, repo
);
13898 print_merge_progress_stats(&upa
);
13900 if (patch_script_file
&& fclose(patch_script_file
) == EOF
&&
13902 error
= got_error_from_errno2("fclose", patch_script_path
);
13904 const struct got_error
*close_err
= got_repo_close(repo
);
13909 got_worktree_close(worktree
);
13911 const struct got_error
*pack_err
=
13912 got_repo_pack_fds_close(pack_fds
);
13916 got_pathlist_free(&paths
, GOT_PATHLIST_FREE_PATH
);
13924 fprintf(stderr
, "usage: %s cat [-P] [-c commit] [-r repository-path] "
13925 "arg ...\n", getprogname());
13929 static const struct got_error
*
13930 cat_blob(struct got_object_id
*id
, struct got_repository
*repo
, FILE *outfile
)
13932 const struct got_error
*err
;
13933 struct got_blob_object
*blob
;
13936 fd
= got_opentempfd();
13938 return got_error_from_errno("got_opentempfd");
13940 err
= got_object_open_as_blob(&blob
, repo
, id
, 8192, fd
);
13944 err
= got_object_blob_dump_to_file(NULL
, NULL
, NULL
, outfile
, blob
);
13946 if (fd
!= -1 && close(fd
) == -1 && err
== NULL
)
13947 err
= got_error_from_errno("close");
13949 got_object_blob_close(blob
);
13953 static const struct got_error
*
13954 cat_tree(struct got_object_id
*id
, struct got_repository
*repo
, FILE *outfile
)
13956 const struct got_error
*err
;
13957 struct got_tree_object
*tree
;
13960 err
= got_object_open_as_tree(&tree
, repo
, id
);
13964 nentries
= got_object_tree_get_nentries(tree
);
13965 for (i
= 0; i
< nentries
; i
++) {
13966 struct got_tree_entry
*te
;
13968 if (sigint_received
|| sigpipe_received
)
13970 te
= got_object_tree_get_entry(tree
, i
);
13971 err
= got_object_id_str(&id_str
, got_tree_entry_get_id(te
));
13974 fprintf(outfile
, "%s %.7o %s\n", id_str
,
13975 got_tree_entry_get_mode(te
),
13976 got_tree_entry_get_name(te
));
13980 got_object_tree_close(tree
);
13984 static const struct got_error
*
13985 cat_commit(struct got_object_id
*id
, struct got_repository
*repo
, FILE *outfile
)
13987 const struct got_error
*err
;
13988 struct got_commit_object
*commit
;
13989 const struct got_object_id_queue
*parent_ids
;
13990 struct got_object_qid
*pid
;
13991 char *id_str
= NULL
;
13992 const char *logmsg
= NULL
;
13995 err
= got_object_open_as_commit(&commit
, repo
, id
);
13999 err
= got_object_id_str(&id_str
, got_object_commit_get_tree_id(commit
));
14003 fprintf(outfile
, "%s%s\n", GOT_COMMIT_LABEL_TREE
, id_str
);
14004 parent_ids
= got_object_commit_get_parent_ids(commit
);
14005 fprintf(outfile
, "numparents %d\n",
14006 got_object_commit_get_nparents(commit
));
14007 STAILQ_FOREACH(pid
, parent_ids
, entry
) {
14009 err
= got_object_id_str(&pid_str
, &pid
->id
);
14012 fprintf(outfile
, "%s%s\n", GOT_COMMIT_LABEL_PARENT
, pid_str
);
14015 got_date_format_gmtoff(gmtoff
, sizeof(gmtoff
),
14016 got_object_commit_get_author_gmtoff(commit
));
14017 fprintf(outfile
, "%s%s %lld %s\n", GOT_COMMIT_LABEL_AUTHOR
,
14018 got_object_commit_get_author(commit
),
14019 (long long)got_object_commit_get_author_time(commit
),
14022 got_date_format_gmtoff(gmtoff
, sizeof(gmtoff
),
14023 got_object_commit_get_committer_gmtoff(commit
));
14024 fprintf(outfile
, "%s%s %lld %s\n", GOT_COMMIT_LABEL_COMMITTER
,
14025 got_object_commit_get_committer(commit
),
14026 (long long)got_object_commit_get_committer_time(commit
),
14029 logmsg
= got_object_commit_get_logmsg_raw(commit
);
14030 fprintf(outfile
, "messagelen %zd\n", strlen(logmsg
));
14031 fprintf(outfile
, "%s", logmsg
);
14034 got_object_commit_close(commit
);
14038 static const struct got_error
*
14039 cat_tag(struct got_object_id
*id
, struct got_repository
*repo
, FILE *outfile
)
14041 const struct got_error
*err
;
14042 struct got_tag_object
*tag
;
14043 char *id_str
= NULL
;
14044 const char *tagmsg
= NULL
;
14047 err
= got_object_open_as_tag(&tag
, repo
, id
);
14051 err
= got_object_id_str(&id_str
, got_object_tag_get_object_id(tag
));
14055 fprintf(outfile
, "%s%s\n", GOT_TAG_LABEL_OBJECT
, id_str
);
14057 switch (got_object_tag_get_object_type(tag
)) {
14058 case GOT_OBJ_TYPE_BLOB
:
14059 fprintf(outfile
, "%s%s\n", GOT_TAG_LABEL_TYPE
,
14060 GOT_OBJ_LABEL_BLOB
);
14062 case GOT_OBJ_TYPE_TREE
:
14063 fprintf(outfile
, "%s%s\n", GOT_TAG_LABEL_TYPE
,
14064 GOT_OBJ_LABEL_TREE
);
14066 case GOT_OBJ_TYPE_COMMIT
:
14067 fprintf(outfile
, "%s%s\n", GOT_TAG_LABEL_TYPE
,
14068 GOT_OBJ_LABEL_COMMIT
);
14070 case GOT_OBJ_TYPE_TAG
:
14071 fprintf(outfile
, "%s%s\n", GOT_TAG_LABEL_TYPE
,
14072 GOT_OBJ_LABEL_TAG
);
14078 fprintf(outfile
, "%s%s\n", GOT_TAG_LABEL_TAG
,
14079 got_object_tag_get_name(tag
));
14081 got_date_format_gmtoff(gmtoff
, sizeof(gmtoff
),
14082 got_object_tag_get_tagger_gmtoff(tag
));
14083 fprintf(outfile
, "%s%s %lld %s\n", GOT_TAG_LABEL_TAGGER
,
14084 got_object_tag_get_tagger(tag
),
14085 (long long)got_object_tag_get_tagger_time(tag
),
14088 tagmsg
= got_object_tag_get_message(tag
);
14089 fprintf(outfile
, "messagelen %zd\n", strlen(tagmsg
));
14090 fprintf(outfile
, "%s", tagmsg
);
14093 got_object_tag_close(tag
);
14097 static const struct got_error
*
14098 cmd_cat(int argc
, char *argv
[])
14100 const struct got_error
*error
;
14101 struct got_repository
*repo
= NULL
;
14102 struct got_worktree
*worktree
= NULL
;
14103 char *cwd
= NULL
, *repo_path
= NULL
, *label
= NULL
;
14104 char *keyword_idstr
= NULL
;
14105 const char *commit_id_str
= NULL
;
14106 struct got_object_id
*id
= NULL
, *commit_id
= NULL
;
14107 struct got_commit_object
*commit
= NULL
;
14108 int ch
, obj_type
, i
, force_path
= 0;
14109 struct got_reflist_head refs
;
14110 int *pack_fds
= NULL
;
14115 if (pledge("stdio rpath wpath cpath flock proc exec sendfd unveil",
14120 while ((ch
= getopt(argc
, argv
, "c:Pr:")) != -1) {
14123 commit_id_str
= optarg
;
14129 repo_path
= realpath(optarg
, NULL
);
14130 if (repo_path
== NULL
)
14131 return got_error_from_errno2("realpath",
14133 got_path_strip_trailing_slashes(repo_path
);
14144 cwd
= getcwd(NULL
, 0);
14146 error
= got_error_from_errno("getcwd");
14150 error
= got_repo_pack_fds_open(&pack_fds
);
14154 if (repo_path
== NULL
) {
14155 error
= got_worktree_open(&worktree
, cwd
, GOT_WORKTREE_GOT_DIR
);
14156 if (error
&& error
->code
!= GOT_ERR_NOT_WORKTREE
)
14159 repo_path
= strdup(
14160 got_worktree_get_repo_path(worktree
));
14161 if (repo_path
== NULL
) {
14162 error
= got_error_from_errno("strdup");
14166 if (commit_id_str
== NULL
) {
14167 /* Release work tree lock. */
14168 got_worktree_close(worktree
);
14174 if (repo_path
== NULL
) {
14175 repo_path
= strdup(cwd
);
14176 if (repo_path
== NULL
)
14177 return got_error_from_errno("strdup");
14180 error
= got_repo_open(&repo
, repo_path
, NULL
, pack_fds
);
14185 error
= apply_unveil(got_repo_get_path(repo
), 1, NULL
);
14189 error
= got_ref_list(&refs
, repo
, NULL
, got_ref_cmp_by_name
, NULL
);
14193 if (commit_id_str
!= NULL
) {
14194 error
= got_keyword_to_idstr(&keyword_idstr
, commit_id_str
,
14198 if (keyword_idstr
!= NULL
)
14199 commit_id_str
= keyword_idstr
;
14200 if (worktree
!= NULL
) {
14201 got_worktree_close(worktree
);
14205 commit_id_str
= GOT_REF_HEAD
;
14206 error
= got_repo_match_object_id(&commit_id
, NULL
,
14207 commit_id_str
, GOT_OBJ_TYPE_COMMIT
, &refs
, repo
);
14211 error
= got_object_open_as_commit(&commit
, repo
, commit_id
);
14215 for (i
= 0; i
< argc
; i
++) {
14217 error
= got_object_id_by_path(&id
, repo
, commit
,
14222 error
= got_repo_match_object_id(&id
, &label
, argv
[i
],
14223 GOT_OBJ_TYPE_ANY
, NULL
/* do not resolve tags */,
14226 if (error
->code
!= GOT_ERR_BAD_OBJ_ID_STR
&&
14227 error
->code
!= GOT_ERR_NOT_REF
)
14229 error
= got_object_id_by_path(&id
, repo
,
14236 error
= got_object_get_type(&obj_type
, repo
, id
);
14240 switch (obj_type
) {
14241 case GOT_OBJ_TYPE_BLOB
:
14242 error
= cat_blob(id
, repo
, stdout
);
14244 case GOT_OBJ_TYPE_TREE
:
14245 error
= cat_tree(id
, repo
, stdout
);
14247 case GOT_OBJ_TYPE_COMMIT
:
14248 error
= cat_commit(id
, repo
, stdout
);
14250 case GOT_OBJ_TYPE_TAG
:
14251 error
= cat_tag(id
, repo
, stdout
);
14254 error
= got_error(GOT_ERR_OBJ_TYPE
);
14268 free(keyword_idstr
);
14270 got_object_commit_close(commit
);
14272 got_worktree_close(worktree
);
14274 const struct got_error
*close_err
= got_repo_close(repo
);
14279 const struct got_error
*pack_err
=
14280 got_repo_pack_fds_close(pack_fds
);
14285 got_ref_list_free(&refs
);
14292 fprintf(stderr
, "usage: %s info [path ...]\n",
14297 static const struct got_error
*
14298 print_path_info(void *arg
, const char *path
, mode_t mode
, time_t mtime
,
14299 struct got_object_id
*blob_id
, struct got_object_id
*staged_blob_id
,
14300 struct got_object_id
*commit_id
)
14302 const struct got_error
*err
= NULL
;
14303 char *id_str
= NULL
;
14305 struct tm mytm
, *tm
;
14306 struct got_pathlist_head
*paths
= arg
;
14307 struct got_pathlist_entry
*pe
;
14310 * Clear error indication from any of the path arguments which
14311 * would cause this file index entry to be displayed.
14313 TAILQ_FOREACH(pe
, paths
, entry
) {
14314 if (got_path_cmp(path
, pe
->path
, strlen(path
),
14315 pe
->path_len
) == 0 ||
14316 got_path_is_child(path
, pe
->path
, pe
->path_len
))
14317 pe
->data
= NULL
; /* no error */
14320 printf(GOT_COMMIT_SEP_STR
);
14322 printf("symlink: %s\n", path
);
14323 else if (S_ISREG(mode
)) {
14324 printf("file: %s\n", path
);
14325 printf("mode: %o\n", mode
& (S_IRWXU
| S_IRWXG
| S_IRWXO
));
14326 } else if (S_ISDIR(mode
))
14327 printf("directory: %s\n", path
);
14329 printf("something: %s\n", path
);
14331 tm
= localtime_r(&mtime
, &mytm
);
14334 if (strftime(datebuf
, sizeof(datebuf
), "%c %Z", tm
) == 0)
14335 return got_error(GOT_ERR_NO_SPACE
);
14336 printf("timestamp: %s\n", datebuf
);
14339 err
= got_object_id_str(&id_str
, blob_id
);
14342 printf("based on blob: %s\n", id_str
);
14346 if (staged_blob_id
) {
14347 err
= got_object_id_str(&id_str
, staged_blob_id
);
14350 printf("based on staged blob: %s\n", id_str
);
14355 err
= got_object_id_str(&id_str
, commit_id
);
14358 printf("based on commit: %s\n", id_str
);
14365 static const struct got_error
*
14366 cmd_info(int argc
, char *argv
[])
14368 const struct got_error
*error
= NULL
;
14369 struct got_worktree
*worktree
= NULL
;
14370 char *cwd
= NULL
, *id_str
= NULL
;
14371 struct got_pathlist_head paths
;
14372 char *uuidstr
= NULL
;
14373 int ch
, show_files
= 0;
14375 TAILQ_INIT(&paths
);
14378 if (pledge("stdio rpath wpath cpath flock proc exec sendfd unveil",
14383 while ((ch
= getopt(argc
, argv
, "")) != -1) {
14394 cwd
= getcwd(NULL
, 0);
14396 error
= got_error_from_errno("getcwd");
14400 error
= got_worktree_open(&worktree
, cwd
, GOT_WORKTREE_GOT_DIR
);
14402 if (error
->code
== GOT_ERR_NOT_WORKTREE
)
14403 error
= wrap_not_worktree_error(error
, "info", cwd
);
14408 /* Remove "wpath cpath proc exec sendfd" promises. */
14409 if (pledge("stdio rpath flock unveil", NULL
) == -1)
14412 error
= apply_unveil(NULL
, 0, got_worktree_get_root_path(worktree
));
14417 error
= get_worktree_paths_from_argv(&paths
, argc
, argv
,
14424 error
= got_object_id_str(&id_str
,
14425 got_worktree_get_base_commit_id(worktree
));
14429 error
= got_worktree_get_uuid(&uuidstr
, worktree
);
14433 printf("work tree: %s\n", got_worktree_get_root_path(worktree
));
14434 printf("work tree base commit: %s\n", id_str
);
14435 printf("work tree path prefix: %s\n",
14436 got_worktree_get_path_prefix(worktree
));
14437 printf("work tree branch reference: %s\n",
14438 got_worktree_get_head_ref_name(worktree
));
14439 printf("work tree UUID: %s\n", uuidstr
);
14440 printf("repository: %s\n", got_worktree_get_repo_path(worktree
));
14443 struct got_pathlist_entry
*pe
;
14444 TAILQ_FOREACH(pe
, &paths
, entry
) {
14445 if (pe
->path_len
== 0)
14448 * Assume this path will fail. This will be corrected
14449 * in print_path_info() in case the path does suceeed.
14451 pe
->data
= (void *)got_error(GOT_ERR_BAD_PATH
);
14453 error
= got_worktree_path_info(worktree
, &paths
,
14454 print_path_info
, &paths
, check_cancelled
, NULL
);
14457 TAILQ_FOREACH(pe
, &paths
, entry
) {
14458 if (pe
->data
!= NULL
) {
14459 const struct got_error
*perr
;
14462 error
= got_error_fmt(perr
->code
, "%s",
14470 got_worktree_close(worktree
);
14471 got_pathlist_free(&paths
, GOT_PATHLIST_FREE_PATH
);