2 624411d2 2023-07-08 jrick * Copyright (c) 2017 Martin Pieuchot <mpi@openbsd.org>
3 624411d2 2023-07-08 jrick * Copyright (c) 2018, 2019, 2020 Stefan Sperling <stsp@openbsd.org>
4 624411d2 2023-07-08 jrick * Copyright (c) 2020 Ori Bernstein <ori@openbsd.org>
5 3d1b16d1 2023-07-08 jrick * Copyright (C) 2023 Josh Rickmar <jrick@zettaport.com>
7 624411d2 2023-07-08 jrick * Permission to use, copy, modify, and distribute this software for any
8 624411d2 2023-07-08 jrick * purpose with or without fee is hereby granted, provided that the above
9 624411d2 2023-07-08 jrick * copyright notice and this permission notice appear in all copies.
11 624411d2 2023-07-08 jrick * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 624411d2 2023-07-08 jrick * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 624411d2 2023-07-08 jrick * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 624411d2 2023-07-08 jrick * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 624411d2 2023-07-08 jrick * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 624411d2 2023-07-08 jrick * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 624411d2 2023-07-08 jrick * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20 624411d2 2023-07-08 jrick #include <sys/queue.h>
21 624411d2 2023-07-08 jrick #include <sys/time.h>
22 624411d2 2023-07-08 jrick #include <sys/types.h>
23 624411d2 2023-07-08 jrick #include <sys/stat.h>
24 624411d2 2023-07-08 jrick #include <sys/wait.h>
26 624411d2 2023-07-08 jrick #include <err.h>
27 624411d2 2023-07-08 jrick #include <errno.h>
28 624411d2 2023-07-08 jrick #include <fcntl.h>
29 624411d2 2023-07-08 jrick #include <limits.h>
30 624411d2 2023-07-08 jrick #include <locale.h>
31 624411d2 2023-07-08 jrick #include <ctype.h>
32 624411d2 2023-07-08 jrick #include <sha1.h>
33 624411d2 2023-07-08 jrick #include <sha2.h>
34 624411d2 2023-07-08 jrick #include <signal.h>
35 624411d2 2023-07-08 jrick #include <stdio.h>
36 624411d2 2023-07-08 jrick #include <stdlib.h>
37 624411d2 2023-07-08 jrick #include <string.h>
38 624411d2 2023-07-08 jrick #include <unistd.h>
39 624411d2 2023-07-08 jrick #include <libgen.h>
40 624411d2 2023-07-08 jrick #include <time.h>
41 624411d2 2023-07-08 jrick #include <paths.h>
42 624411d2 2023-07-08 jrick #include <regex.h>
43 624411d2 2023-07-08 jrick #include <getopt.h>
44 624411d2 2023-07-08 jrick #include <util.h>
46 624411d2 2023-07-08 jrick #include "got_version.h"
47 624411d2 2023-07-08 jrick #include "got_error.h"
48 624411d2 2023-07-08 jrick #include "got_object.h"
49 624411d2 2023-07-08 jrick #include "got_reference.h"
50 624411d2 2023-07-08 jrick #include "got_repository.h"
51 624411d2 2023-07-08 jrick #include "got_path.h"
52 624411d2 2023-07-08 jrick #include "got_cancel.h"
53 624411d2 2023-07-08 jrick #include "got_worktree.h"
54 3d1b16d1 2023-07-08 jrick #include "got_worktree_cvg.h"
55 624411d2 2023-07-08 jrick #include "got_diff.h"
56 624411d2 2023-07-08 jrick #include "got_commit_graph.h"
57 624411d2 2023-07-08 jrick #include "got_fetch.h"
58 624411d2 2023-07-08 jrick #include "got_send.h"
59 624411d2 2023-07-08 jrick #include "got_blame.h"
60 624411d2 2023-07-08 jrick #include "got_privsep.h"
61 624411d2 2023-07-08 jrick #include "got_opentemp.h"
62 624411d2 2023-07-08 jrick #include "got_gotconfig.h"
63 624411d2 2023-07-08 jrick #include "got_dial.h"
64 624411d2 2023-07-08 jrick #include "got_patch.h"
65 624411d2 2023-07-08 jrick #include "got_sigs.h"
66 624411d2 2023-07-08 jrick #include "got_date.h"
68 624411d2 2023-07-08 jrick #ifndef nitems
69 624411d2 2023-07-08 jrick #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0]))
72 624411d2 2023-07-08 jrick static volatile sig_atomic_t sigint_received;
73 624411d2 2023-07-08 jrick static volatile sig_atomic_t sigpipe_received;
75 624411d2 2023-07-08 jrick static void
76 624411d2 2023-07-08 jrick catch_sigint(int signo)
78 624411d2 2023-07-08 jrick sigint_received = 1;
81 624411d2 2023-07-08 jrick static void
82 624411d2 2023-07-08 jrick catch_sigpipe(int signo)
84 624411d2 2023-07-08 jrick sigpipe_received = 1;
88 624411d2 2023-07-08 jrick struct got_cmd {
89 624411d2 2023-07-08 jrick const char *cmd_name;
90 624411d2 2023-07-08 jrick const struct got_error *(*cmd_main)(int, char *[]);
91 624411d2 2023-07-08 jrick void (*cmd_usage)(void);
92 624411d2 2023-07-08 jrick const char *cmd_alias;
95 624411d2 2023-07-08 jrick __dead static void usage(int, int);
96 624411d2 2023-07-08 jrick __dead static void usage_import(void);
97 624411d2 2023-07-08 jrick __dead static void usage_clone(void);
98 624411d2 2023-07-08 jrick __dead static void usage_fetch(void);
99 624411d2 2023-07-08 jrick __dead static void usage_checkout(void);
100 624411d2 2023-07-08 jrick __dead static void usage_update(void);
101 624411d2 2023-07-08 jrick __dead static void usage_log(void);
102 624411d2 2023-07-08 jrick __dead static void usage_diff(void);
103 624411d2 2023-07-08 jrick __dead static void usage_blame(void);
104 624411d2 2023-07-08 jrick __dead static void usage_tree(void);
105 624411d2 2023-07-08 jrick __dead static void usage_status(void);
106 624411d2 2023-07-08 jrick __dead static void usage_ref(void);
107 624411d2 2023-07-08 jrick __dead static void usage_branch(void);
108 624411d2 2023-07-08 jrick __dead static void usage_tag(void);
109 624411d2 2023-07-08 jrick __dead static void usage_add(void);
110 624411d2 2023-07-08 jrick __dead static void usage_remove(void);
111 624411d2 2023-07-08 jrick __dead static void usage_patch(void);
112 624411d2 2023-07-08 jrick __dead static void usage_revert(void);
113 624411d2 2023-07-08 jrick __dead static void usage_commit(void);
114 624411d2 2023-07-08 jrick __dead static void usage_send(void);
115 624411d2 2023-07-08 jrick __dead static void usage_cherrypick(void);
116 624411d2 2023-07-08 jrick __dead static void usage_backout(void);
117 624411d2 2023-07-08 jrick __dead static void usage_rebase(void);
118 624411d2 2023-07-08 jrick __dead static void usage_histedit(void);
119 624411d2 2023-07-08 jrick __dead static void usage_integrate(void);
120 624411d2 2023-07-08 jrick __dead static void usage_merge(void);
121 624411d2 2023-07-08 jrick __dead static void usage_stage(void);
122 624411d2 2023-07-08 jrick __dead static void usage_unstage(void);
123 624411d2 2023-07-08 jrick __dead static void usage_cat(void);
124 624411d2 2023-07-08 jrick __dead static void usage_info(void);
126 624411d2 2023-07-08 jrick static const struct got_error* cmd_import(int, char *[]);
127 624411d2 2023-07-08 jrick static const struct got_error* cmd_clone(int, char *[]);
128 624411d2 2023-07-08 jrick static const struct got_error* cmd_fetch(int, char *[]);
129 624411d2 2023-07-08 jrick static const struct got_error* cmd_checkout(int, char *[]);
130 624411d2 2023-07-08 jrick static const struct got_error* cmd_update(int, char *[]);
131 624411d2 2023-07-08 jrick static const struct got_error* cmd_log(int, char *[]);
132 624411d2 2023-07-08 jrick static const struct got_error* cmd_diff(int, char *[]);
133 624411d2 2023-07-08 jrick static const struct got_error* cmd_blame(int, char *[]);
134 624411d2 2023-07-08 jrick static const struct got_error* cmd_tree(int, char *[]);
135 624411d2 2023-07-08 jrick static const struct got_error* cmd_status(int, char *[]);
136 624411d2 2023-07-08 jrick static const struct got_error* cmd_ref(int, char *[]);
137 624411d2 2023-07-08 jrick static const struct got_error* cmd_branch(int, char *[]);
138 624411d2 2023-07-08 jrick static const struct got_error* cmd_tag(int, char *[]);
139 624411d2 2023-07-08 jrick static const struct got_error* cmd_add(int, char *[]);
140 624411d2 2023-07-08 jrick static const struct got_error* cmd_remove(int, char *[]);
141 624411d2 2023-07-08 jrick static const struct got_error* cmd_patch(int, char *[]);
142 624411d2 2023-07-08 jrick static const struct got_error* cmd_revert(int, char *[]);
143 624411d2 2023-07-08 jrick static const struct got_error* cmd_commit(int, char *[]);
144 624411d2 2023-07-08 jrick static const struct got_error* cmd_send(int, char *[]);
145 624411d2 2023-07-08 jrick static const struct got_error* cmd_cherrypick(int, char *[]);
146 624411d2 2023-07-08 jrick static const struct got_error* cmd_backout(int, char *[]);
147 624411d2 2023-07-08 jrick static const struct got_error* cmd_rebase(int, char *[]);
148 624411d2 2023-07-08 jrick static const struct got_error* cmd_histedit(int, char *[]);
149 624411d2 2023-07-08 jrick static const struct got_error* cmd_integrate(int, char *[]);
150 624411d2 2023-07-08 jrick static const struct got_error* cmd_merge(int, char *[]);
151 624411d2 2023-07-08 jrick static const struct got_error* cmd_stage(int, char *[]);
152 624411d2 2023-07-08 jrick static const struct got_error* cmd_unstage(int, char *[]);
153 624411d2 2023-07-08 jrick static const struct got_error* cmd_cat(int, char *[]);
154 624411d2 2023-07-08 jrick static const struct got_error* cmd_info(int, char *[]);
156 624411d2 2023-07-08 jrick static const struct got_cmd got_commands[] = {
157 624411d2 2023-07-08 jrick { "import", cmd_import, usage_import, "im" },
158 624411d2 2023-07-08 jrick { "clone", cmd_clone, usage_clone, "cl" },
159 3d1b16d1 2023-07-08 jrick /*{ "fetch", cmd_fetch, usage_fetch, "fe" },*/ /* rolled into update */
160 624411d2 2023-07-08 jrick { "checkout", cmd_checkout, usage_checkout, "co" },
161 624411d2 2023-07-08 jrick { "update", cmd_update, usage_update, "up" },
162 624411d2 2023-07-08 jrick { "log", cmd_log, usage_log, "" },
163 624411d2 2023-07-08 jrick { "diff", cmd_diff, usage_diff, "di" },
164 624411d2 2023-07-08 jrick { "blame", cmd_blame, usage_blame, "bl" },
165 624411d2 2023-07-08 jrick { "tree", cmd_tree, usage_tree, "tr" },
166 624411d2 2023-07-08 jrick { "status", cmd_status, usage_status, "st" },
167 624411d2 2023-07-08 jrick { "ref", cmd_ref, usage_ref, "" },
168 3d1b16d1 2023-07-08 jrick /*{ "branch", cmd_branch, usage_branch, "br" },*/
169 624411d2 2023-07-08 jrick { "tag", cmd_tag, usage_tag, "" },
170 624411d2 2023-07-08 jrick { "add", cmd_add, usage_add, "" },
171 624411d2 2023-07-08 jrick { "remove", cmd_remove, usage_remove, "rm" },
172 624411d2 2023-07-08 jrick { "patch", cmd_patch, usage_patch, "pa" },
173 624411d2 2023-07-08 jrick { "revert", cmd_revert, usage_revert, "rv" },
174 624411d2 2023-07-08 jrick { "commit", cmd_commit, usage_commit, "ci" },
175 3d1b16d1 2023-07-08 jrick /*{ "send", cmd_send, usage_send, "se" },*/ /* part of commit */
176 624411d2 2023-07-08 jrick { "cherrypick", cmd_cherrypick, usage_cherrypick, "cy" },
177 624411d2 2023-07-08 jrick { "backout", cmd_backout, usage_backout, "bo" },
178 3d1b16d1 2023-07-08 jrick /*{ "rebase", cmd_rebase, usage_rebase, "rb" },*/
179 3d1b16d1 2023-07-08 jrick /*{ "histedit", cmd_histedit, usage_histedit, "he" },*/
180 3d1b16d1 2023-07-08 jrick /*{ "integrate", cmd_integrate, usage_integrate,"ig" },*/
181 3d1b16d1 2023-07-08 jrick /*{ "merge", cmd_merge, usage_merge, "mg" },*/
182 3d1b16d1 2023-07-08 jrick /*{ "stage", cmd_stage, usage_stage, "sg" },*/
183 3d1b16d1 2023-07-08 jrick /*{ "unstage", cmd_unstage, usage_unstage, "ug" },*/
184 624411d2 2023-07-08 jrick { "cat", cmd_cat, usage_cat, "" },
185 624411d2 2023-07-08 jrick { "info", cmd_info, usage_info, "" },
188 624411d2 2023-07-08 jrick static void
189 624411d2 2023-07-08 jrick list_commands(FILE *fp)
193 624411d2 2023-07-08 jrick fprintf(fp, "commands:");
194 624411d2 2023-07-08 jrick for (i = 0; i < nitems(got_commands); i++) {
195 624411d2 2023-07-08 jrick const struct got_cmd *cmd = &got_commands[i];
196 624411d2 2023-07-08 jrick fprintf(fp, " %s", cmd->cmd_name);
198 624411d2 2023-07-08 jrick fputc('\n', fp);
201 624411d2 2023-07-08 jrick __dead static void
202 624411d2 2023-07-08 jrick option_conflict(char a, char b)
204 624411d2 2023-07-08 jrick errx(1, "-%c and -%c options are mutually exclusive", a, b);
208 624411d2 2023-07-08 jrick main(int argc, char *argv[])
210 624411d2 2023-07-08 jrick const struct got_cmd *cmd;
213 624411d2 2023-07-08 jrick int hflag = 0, Vflag = 0;
214 624411d2 2023-07-08 jrick static const struct option longopts[] = {
215 624411d2 2023-07-08 jrick { "version", no_argument, NULL, 'V' },
216 624411d2 2023-07-08 jrick { NULL, 0, NULL, 0 }
219 624411d2 2023-07-08 jrick setlocale(LC_CTYPE, "");
221 624411d2 2023-07-08 jrick while ((ch = getopt_long(argc, argv, "+hV", longopts, NULL)) != -1) {
222 624411d2 2023-07-08 jrick switch (ch) {
224 624411d2 2023-07-08 jrick hflag = 1;
227 624411d2 2023-07-08 jrick Vflag = 1;
230 624411d2 2023-07-08 jrick usage(hflag, 1);
231 624411d2 2023-07-08 jrick /* NOTREACHED */
235 624411d2 2023-07-08 jrick argc -= optind;
236 624411d2 2023-07-08 jrick argv += optind;
237 624411d2 2023-07-08 jrick optind = 1;
238 624411d2 2023-07-08 jrick optreset = 1;
240 624411d2 2023-07-08 jrick if (Vflag) {
241 624411d2 2023-07-08 jrick got_version_print_str();
245 624411d2 2023-07-08 jrick if (argc <= 0)
246 624411d2 2023-07-08 jrick usage(hflag, hflag ? 0 : 1);
248 624411d2 2023-07-08 jrick signal(SIGINT, catch_sigint);
249 624411d2 2023-07-08 jrick signal(SIGPIPE, catch_sigpipe);
251 624411d2 2023-07-08 jrick for (i = 0; i < nitems(got_commands); i++) {
252 624411d2 2023-07-08 jrick const struct got_error *error;
254 624411d2 2023-07-08 jrick cmd = &got_commands[i];
256 624411d2 2023-07-08 jrick if (strcmp(cmd->cmd_name, argv[0]) != 0 &&
257 624411d2 2023-07-08 jrick strcmp(cmd->cmd_alias, argv[0]) != 0)
260 624411d2 2023-07-08 jrick if (hflag)
261 624411d2 2023-07-08 jrick cmd->cmd_usage();
263 624411d2 2023-07-08 jrick error = cmd->cmd_main(argc, argv);
264 624411d2 2023-07-08 jrick if (error && error->code != GOT_ERR_CANCELLED &&
265 624411d2 2023-07-08 jrick error->code != GOT_ERR_PRIVSEP_EXIT &&
266 624411d2 2023-07-08 jrick !(sigpipe_received &&
267 624411d2 2023-07-08 jrick error->code == GOT_ERR_ERRNO && errno == EPIPE) &&
268 624411d2 2023-07-08 jrick !(sigint_received &&
269 624411d2 2023-07-08 jrick error->code == GOT_ERR_ERRNO && errno == EINTR)) {
270 624411d2 2023-07-08 jrick fflush(stdout);
271 624411d2 2023-07-08 jrick fprintf(stderr, "%s: %s\n", getprogname(), error->msg);
278 624411d2 2023-07-08 jrick fprintf(stderr, "%s: unknown command '%s'\n", getprogname(), argv[0]);
279 624411d2 2023-07-08 jrick list_commands(stderr);
283 624411d2 2023-07-08 jrick __dead static void
284 624411d2 2023-07-08 jrick usage(int hflag, int status)
286 624411d2 2023-07-08 jrick FILE *fp = (status == 0) ? stdout : stderr;
288 624411d2 2023-07-08 jrick fprintf(fp, "usage: %s [-hV] command [arg ...]\n",
289 624411d2 2023-07-08 jrick getprogname());
290 624411d2 2023-07-08 jrick if (hflag)
291 624411d2 2023-07-08 jrick list_commands(fp);
292 624411d2 2023-07-08 jrick exit(status);
295 624411d2 2023-07-08 jrick static const struct got_error *
296 624411d2 2023-07-08 jrick get_editor(char **abspath)
298 624411d2 2023-07-08 jrick const struct got_error *err = NULL;
299 624411d2 2023-07-08 jrick const char *editor;
301 624411d2 2023-07-08 jrick *abspath = NULL;
303 624411d2 2023-07-08 jrick editor = getenv("VISUAL");
304 624411d2 2023-07-08 jrick if (editor == NULL)
305 624411d2 2023-07-08 jrick editor = getenv("EDITOR");
307 624411d2 2023-07-08 jrick if (editor) {
308 624411d2 2023-07-08 jrick err = got_path_find_prog(abspath, editor);
310 624411d2 2023-07-08 jrick return err;
313 624411d2 2023-07-08 jrick if (*abspath == NULL) {
314 624411d2 2023-07-08 jrick *abspath = strdup("/usr/bin/vi");
315 624411d2 2023-07-08 jrick if (*abspath == NULL)
316 624411d2 2023-07-08 jrick return got_error_from_errno("strdup");
319 624411d2 2023-07-08 jrick return NULL;
322 624411d2 2023-07-08 jrick static const struct got_error *
323 624411d2 2023-07-08 jrick apply_unveil(const char *repo_path, int repo_read_only,
324 624411d2 2023-07-08 jrick const char *worktree_path)
326 624411d2 2023-07-08 jrick const struct got_error *err;
328 624411d2 2023-07-08 jrick #ifdef PROFILE
329 624411d2 2023-07-08 jrick if (unveil("gmon.out", "rwc") != 0)
330 624411d2 2023-07-08 jrick return got_error_from_errno2("unveil", "gmon.out");
332 624411d2 2023-07-08 jrick if (repo_path && unveil(repo_path, repo_read_only ? "r" : "rwc") != 0)
333 624411d2 2023-07-08 jrick return got_error_from_errno2("unveil", repo_path);
335 624411d2 2023-07-08 jrick if (worktree_path && unveil(worktree_path, "rwc") != 0)
336 624411d2 2023-07-08 jrick return got_error_from_errno2("unveil", worktree_path);
338 624411d2 2023-07-08 jrick if (unveil(GOT_TMPDIR_STR, "rwc") != 0)
339 624411d2 2023-07-08 jrick return got_error_from_errno2("unveil", GOT_TMPDIR_STR);
341 624411d2 2023-07-08 jrick err = got_privsep_unveil_exec_helpers();
342 624411d2 2023-07-08 jrick if (err != NULL)
343 624411d2 2023-07-08 jrick return err;
345 624411d2 2023-07-08 jrick if (unveil(NULL, NULL) != 0)
346 624411d2 2023-07-08 jrick return got_error_from_errno("unveil");
348 624411d2 2023-07-08 jrick return NULL;
351 624411d2 2023-07-08 jrick __dead static void
352 624411d2 2023-07-08 jrick usage_import(void)
354 624411d2 2023-07-08 jrick fprintf(stderr, "usage: %s import [-b branch] [-I pattern] [-m message] "
355 624411d2 2023-07-08 jrick "[-r repository-path] directory\n", getprogname());
359 624411d2 2023-07-08 jrick static int
360 624411d2 2023-07-08 jrick spawn_editor(const char *editor, const char *file)
362 624411d2 2023-07-08 jrick pid_t pid;
363 624411d2 2023-07-08 jrick sig_t sighup, sigint, sigquit;
364 624411d2 2023-07-08 jrick int st = -1;
366 624411d2 2023-07-08 jrick sighup = signal(SIGHUP, SIG_IGN);
367 624411d2 2023-07-08 jrick sigint = signal(SIGINT, SIG_IGN);
368 624411d2 2023-07-08 jrick sigquit = signal(SIGQUIT, SIG_IGN);
370 624411d2 2023-07-08 jrick switch (pid = fork()) {
372 624411d2 2023-07-08 jrick goto doneediting;
374 624411d2 2023-07-08 jrick execl(editor, editor, file, (char *)NULL);
375 624411d2 2023-07-08 jrick _exit(127);
378 624411d2 2023-07-08 jrick while (waitpid(pid, &st, 0) == -1)
379 624411d2 2023-07-08 jrick if (errno != EINTR)
382 624411d2 2023-07-08 jrick doneediting:
383 624411d2 2023-07-08 jrick (void)signal(SIGHUP, sighup);
384 624411d2 2023-07-08 jrick (void)signal(SIGINT, sigint);
385 624411d2 2023-07-08 jrick (void)signal(SIGQUIT, sigquit);
387 624411d2 2023-07-08 jrick if (!WIFEXITED(st)) {
388 624411d2 2023-07-08 jrick errno = EINTR;
389 624411d2 2023-07-08 jrick return -1;
392 624411d2 2023-07-08 jrick return WEXITSTATUS(st);
395 624411d2 2023-07-08 jrick static const struct got_error *
396 624411d2 2023-07-08 jrick read_logmsg(char **logmsg, size_t *len, FILE *fp, size_t filesize)
398 624411d2 2023-07-08 jrick const struct got_error *err = NULL;
399 624411d2 2023-07-08 jrick char *line = NULL;
400 624411d2 2023-07-08 jrick size_t linesize = 0;
402 624411d2 2023-07-08 jrick *logmsg = NULL;
405 624411d2 2023-07-08 jrick if (fseeko(fp, 0L, SEEK_SET) == -1)
406 624411d2 2023-07-08 jrick return got_error_from_errno("fseeko");
408 624411d2 2023-07-08 jrick *logmsg = malloc(filesize + 1);
409 624411d2 2023-07-08 jrick if (*logmsg == NULL)
410 624411d2 2023-07-08 jrick return got_error_from_errno("malloc");
411 624411d2 2023-07-08 jrick (*logmsg)[0] = '\0';
413 624411d2 2023-07-08 jrick while (getline(&line, &linesize, fp) != -1) {
414 624411d2 2023-07-08 jrick if (line[0] == '#' || (*len == 0 && line[0] == '\n'))
415 624411d2 2023-07-08 jrick continue; /* remove comments and leading empty lines */
416 624411d2 2023-07-08 jrick *len = strlcat(*logmsg, line, filesize + 1);
417 624411d2 2023-07-08 jrick if (*len >= filesize + 1) {
418 624411d2 2023-07-08 jrick err = got_error(GOT_ERR_NO_SPACE);
419 624411d2 2023-07-08 jrick goto done;
422 624411d2 2023-07-08 jrick if (ferror(fp)) {
423 624411d2 2023-07-08 jrick err = got_ferror(fp, GOT_ERR_IO);
424 624411d2 2023-07-08 jrick goto done;
427 624411d2 2023-07-08 jrick while (*len > 0 && (*logmsg)[*len - 1] == '\n') {
428 624411d2 2023-07-08 jrick (*logmsg)[*len - 1] = '\0';
432 624411d2 2023-07-08 jrick free(line);
433 624411d2 2023-07-08 jrick if (err) {
434 624411d2 2023-07-08 jrick free(*logmsg);
435 624411d2 2023-07-08 jrick *logmsg = NULL;
438 624411d2 2023-07-08 jrick return err;
441 624411d2 2023-07-08 jrick static const struct got_error *
442 624411d2 2023-07-08 jrick edit_logmsg(char **logmsg, const char *editor, const char *logmsg_path,
443 624411d2 2023-07-08 jrick const char *initial_content, size_t initial_content_len,
444 624411d2 2023-07-08 jrick int require_modification)
446 624411d2 2023-07-08 jrick const struct got_error *err = NULL;
447 624411d2 2023-07-08 jrick struct stat st, st2;
448 624411d2 2023-07-08 jrick FILE *fp = NULL;
449 624411d2 2023-07-08 jrick size_t logmsg_len;
451 624411d2 2023-07-08 jrick *logmsg = NULL;
453 624411d2 2023-07-08 jrick if (stat(logmsg_path, &st) == -1)
454 624411d2 2023-07-08 jrick return got_error_from_errno2("stat", logmsg_path);
456 624411d2 2023-07-08 jrick if (spawn_editor(editor, logmsg_path) == -1)
457 624411d2 2023-07-08 jrick return got_error_from_errno("failed spawning editor");
459 624411d2 2023-07-08 jrick if (require_modification) {
460 624411d2 2023-07-08 jrick struct timespec timeout;
462 624411d2 2023-07-08 jrick timeout.tv_sec = 0;
463 624411d2 2023-07-08 jrick timeout.tv_nsec = 1;
464 624411d2 2023-07-08 jrick nanosleep(&timeout, NULL);
467 624411d2 2023-07-08 jrick if (stat(logmsg_path, &st2) == -1)
468 624411d2 2023-07-08 jrick return got_error_from_errno("stat");
470 624411d2 2023-07-08 jrick if (require_modification && st.st_size == st2.st_size &&
471 624411d2 2023-07-08 jrick timespeccmp(&st.st_mtim, &st2.st_mtim, ==))
472 624411d2 2023-07-08 jrick return got_error_msg(GOT_ERR_COMMIT_MSG_EMPTY,
473 624411d2 2023-07-08 jrick "no changes made to commit message, aborting");
475 624411d2 2023-07-08 jrick fp = fopen(logmsg_path, "re");
476 624411d2 2023-07-08 jrick if (fp == NULL) {
477 624411d2 2023-07-08 jrick err = got_error_from_errno("fopen");
478 624411d2 2023-07-08 jrick goto done;
481 624411d2 2023-07-08 jrick /* strip comments and leading/trailing newlines */
482 624411d2 2023-07-08 jrick err = read_logmsg(logmsg, &logmsg_len, fp, st2.st_size);
484 624411d2 2023-07-08 jrick goto done;
485 624411d2 2023-07-08 jrick if (logmsg_len == 0) {
486 624411d2 2023-07-08 jrick err = got_error_msg(GOT_ERR_COMMIT_MSG_EMPTY,
487 624411d2 2023-07-08 jrick "commit message cannot be empty, aborting");
488 624411d2 2023-07-08 jrick goto done;
491 624411d2 2023-07-08 jrick if (fp && fclose(fp) == EOF && err == NULL)
492 624411d2 2023-07-08 jrick err = got_error_from_errno("fclose");
493 624411d2 2023-07-08 jrick if (err) {
494 624411d2 2023-07-08 jrick free(*logmsg);
495 624411d2 2023-07-08 jrick *logmsg = NULL;
497 624411d2 2023-07-08 jrick return err;
500 624411d2 2023-07-08 jrick static const struct got_error *
501 624411d2 2023-07-08 jrick collect_import_msg(char **logmsg, char **logmsg_path, const char *editor,
502 624411d2 2023-07-08 jrick const char *path_dir, const char *branch_name)
504 624411d2 2023-07-08 jrick char *initial_content = NULL;
505 624411d2 2023-07-08 jrick const struct got_error *err = NULL;
506 624411d2 2023-07-08 jrick int initial_content_len;
507 624411d2 2023-07-08 jrick int fd = -1;
509 624411d2 2023-07-08 jrick initial_content_len = asprintf(&initial_content,
510 624411d2 2023-07-08 jrick "\n# %s to be imported to branch %s\n", path_dir,
511 624411d2 2023-07-08 jrick branch_name);
512 624411d2 2023-07-08 jrick if (initial_content_len == -1)
513 624411d2 2023-07-08 jrick return got_error_from_errno("asprintf");
515 624411d2 2023-07-08 jrick err = got_opentemp_named_fd(logmsg_path, &fd,
516 624411d2 2023-07-08 jrick GOT_TMPDIR_STR "/got-importmsg", "");
518 624411d2 2023-07-08 jrick goto done;
520 624411d2 2023-07-08 jrick if (write(fd, initial_content, initial_content_len) == -1) {
521 624411d2 2023-07-08 jrick err = got_error_from_errno2("write", *logmsg_path);
522 624411d2 2023-07-08 jrick goto done;
524 624411d2 2023-07-08 jrick if (close(fd) == -1) {
525 624411d2 2023-07-08 jrick err = got_error_from_errno2("close", *logmsg_path);
526 624411d2 2023-07-08 jrick goto done;
530 624411d2 2023-07-08 jrick err = edit_logmsg(logmsg, editor, *logmsg_path, initial_content,
531 624411d2 2023-07-08 jrick initial_content_len, 1);
533 624411d2 2023-07-08 jrick if (fd != -1 && close(fd) == -1 && err == NULL)
534 624411d2 2023-07-08 jrick err = got_error_from_errno2("close", *logmsg_path);
535 624411d2 2023-07-08 jrick free(initial_content);
536 624411d2 2023-07-08 jrick if (err) {
537 624411d2 2023-07-08 jrick free(*logmsg_path);
538 624411d2 2023-07-08 jrick *logmsg_path = NULL;
540 624411d2 2023-07-08 jrick return err;
543 624411d2 2023-07-08 jrick static const struct got_error *
544 624411d2 2023-07-08 jrick import_progress(void *arg, const char *path)
546 624411d2 2023-07-08 jrick printf("A %s\n", path);
547 624411d2 2023-07-08 jrick return NULL;
550 624411d2 2023-07-08 jrick static const struct got_error *
551 624411d2 2023-07-08 jrick valid_author(const char *author)
553 624411d2 2023-07-08 jrick const char *email = author;
556 624411d2 2023-07-08 jrick * Git' expects the author (or committer) to be in the form
557 624411d2 2023-07-08 jrick * "name <email>", which are mostly free form (see the
558 624411d2 2023-07-08 jrick * "committer" description in git-fast-import(1)). We're only
559 624411d2 2023-07-08 jrick * doing this to avoid git's object parser breaking on commits
560 624411d2 2023-07-08 jrick * we create.
563 624411d2 2023-07-08 jrick while (*author && *author != '\n' && *author != '<' && *author != '>')
565 624411d2 2023-07-08 jrick if (author != email && *author == '<' && *(author - 1) != ' ')
566 624411d2 2023-07-08 jrick return got_error_fmt(GOT_ERR_COMMIT_BAD_AUTHOR, "%s: space "
567 624411d2 2023-07-08 jrick "between author name and email required", email);
568 624411d2 2023-07-08 jrick if (*author++ != '<')
569 624411d2 2023-07-08 jrick return got_error_fmt(GOT_ERR_COMMIT_NO_EMAIL, "%s", email);
570 624411d2 2023-07-08 jrick while (*author && *author != '\n' && *author != '<' && *author != '>')
572 624411d2 2023-07-08 jrick if (strcmp(author, ">") != 0)
573 624411d2 2023-07-08 jrick return got_error_fmt(GOT_ERR_COMMIT_NO_EMAIL, "%s", email);
574 624411d2 2023-07-08 jrick return NULL;
577 624411d2 2023-07-08 jrick static const struct got_error *
578 624411d2 2023-07-08 jrick get_author(char **author, struct got_repository *repo,
579 624411d2 2023-07-08 jrick struct got_worktree *worktree)
581 624411d2 2023-07-08 jrick const struct got_error *err = NULL;
582 624411d2 2023-07-08 jrick const char *got_author = NULL, *name, *email;
583 624411d2 2023-07-08 jrick const struct got_gotconfig *worktree_conf = NULL, *repo_conf = NULL;
585 624411d2 2023-07-08 jrick *author = NULL;
587 624411d2 2023-07-08 jrick if (worktree)
588 624411d2 2023-07-08 jrick worktree_conf = got_worktree_get_gotconfig(worktree);
589 624411d2 2023-07-08 jrick repo_conf = got_repo_get_gotconfig(repo);
592 624411d2 2023-07-08 jrick * Priority of potential author information sources, from most
593 624411d2 2023-07-08 jrick * significant to least significant:
594 624411d2 2023-07-08 jrick * 1) work tree's .got/got.conf file
595 624411d2 2023-07-08 jrick * 2) repository's got.conf file
596 624411d2 2023-07-08 jrick * 3) repository's git config file
597 624411d2 2023-07-08 jrick * 4) environment variables
598 624411d2 2023-07-08 jrick * 5) global git config files (in user's home directory or /etc)
601 624411d2 2023-07-08 jrick if (worktree_conf)
602 624411d2 2023-07-08 jrick got_author = got_gotconfig_get_author(worktree_conf);
603 624411d2 2023-07-08 jrick if (got_author == NULL)
604 624411d2 2023-07-08 jrick got_author = got_gotconfig_get_author(repo_conf);
605 624411d2 2023-07-08 jrick if (got_author == NULL) {
606 624411d2 2023-07-08 jrick name = got_repo_get_gitconfig_author_name(repo);
607 624411d2 2023-07-08 jrick email = got_repo_get_gitconfig_author_email(repo);
608 624411d2 2023-07-08 jrick if (name && email) {
609 624411d2 2023-07-08 jrick if (asprintf(author, "%s <%s>", name, email) == -1)
610 624411d2 2023-07-08 jrick return got_error_from_errno("asprintf");
611 624411d2 2023-07-08 jrick return NULL;
614 624411d2 2023-07-08 jrick got_author = getenv("GOT_AUTHOR");
615 624411d2 2023-07-08 jrick if (got_author == NULL) {
616 624411d2 2023-07-08 jrick name = got_repo_get_global_gitconfig_author_name(repo);
617 624411d2 2023-07-08 jrick email = got_repo_get_global_gitconfig_author_email(
619 624411d2 2023-07-08 jrick if (name && email) {
620 624411d2 2023-07-08 jrick if (asprintf(author, "%s <%s>", name, email)
622 624411d2 2023-07-08 jrick return got_error_from_errno("asprintf");
623 624411d2 2023-07-08 jrick return NULL;
625 624411d2 2023-07-08 jrick /* TODO: Look up user in password database? */
626 624411d2 2023-07-08 jrick return got_error(GOT_ERR_COMMIT_NO_AUTHOR);
630 624411d2 2023-07-08 jrick *author = strdup(got_author);
631 624411d2 2023-07-08 jrick if (*author == NULL)
632 624411d2 2023-07-08 jrick return got_error_from_errno("strdup");
634 624411d2 2023-07-08 jrick err = valid_author(*author);
635 624411d2 2023-07-08 jrick if (err) {
636 624411d2 2023-07-08 jrick free(*author);
637 624411d2 2023-07-08 jrick *author = NULL;
639 624411d2 2023-07-08 jrick return err;
642 624411d2 2023-07-08 jrick static const struct got_error *
643 624411d2 2023-07-08 jrick get_allowed_signers(char **allowed_signers, struct got_repository *repo,
644 624411d2 2023-07-08 jrick struct got_worktree *worktree)
646 624411d2 2023-07-08 jrick const char *got_allowed_signers = NULL;
647 624411d2 2023-07-08 jrick const struct got_gotconfig *worktree_conf = NULL, *repo_conf = NULL;
649 624411d2 2023-07-08 jrick *allowed_signers = NULL;
651 624411d2 2023-07-08 jrick if (worktree)
652 624411d2 2023-07-08 jrick worktree_conf = got_worktree_get_gotconfig(worktree);
653 624411d2 2023-07-08 jrick repo_conf = got_repo_get_gotconfig(repo);
656 624411d2 2023-07-08 jrick * Priority of potential author information sources, from most
657 624411d2 2023-07-08 jrick * significant to least significant:
658 624411d2 2023-07-08 jrick * 1) work tree's .got/got.conf file
659 624411d2 2023-07-08 jrick * 2) repository's got.conf file
662 624411d2 2023-07-08 jrick if (worktree_conf)
663 624411d2 2023-07-08 jrick got_allowed_signers = got_gotconfig_get_allowed_signers_file(
664 624411d2 2023-07-08 jrick worktree_conf);
665 624411d2 2023-07-08 jrick if (got_allowed_signers == NULL)
666 624411d2 2023-07-08 jrick got_allowed_signers = got_gotconfig_get_allowed_signers_file(
667 624411d2 2023-07-08 jrick repo_conf);
669 624411d2 2023-07-08 jrick if (got_allowed_signers) {
670 624411d2 2023-07-08 jrick *allowed_signers = strdup(got_allowed_signers);
671 624411d2 2023-07-08 jrick if (*allowed_signers == NULL)
672 624411d2 2023-07-08 jrick return got_error_from_errno("strdup");
674 624411d2 2023-07-08 jrick return NULL;
677 624411d2 2023-07-08 jrick static const struct got_error *
678 624411d2 2023-07-08 jrick get_revoked_signers(char **revoked_signers, struct got_repository *repo,
679 624411d2 2023-07-08 jrick struct got_worktree *worktree)
681 624411d2 2023-07-08 jrick const char *got_revoked_signers = NULL;
682 624411d2 2023-07-08 jrick const struct got_gotconfig *worktree_conf = NULL, *repo_conf = NULL;
684 624411d2 2023-07-08 jrick *revoked_signers = NULL;
686 624411d2 2023-07-08 jrick if (worktree)
687 624411d2 2023-07-08 jrick worktree_conf = got_worktree_get_gotconfig(worktree);
688 624411d2 2023-07-08 jrick repo_conf = got_repo_get_gotconfig(repo);
691 624411d2 2023-07-08 jrick * Priority of potential author information sources, from most
692 624411d2 2023-07-08 jrick * significant to least significant:
693 624411d2 2023-07-08 jrick * 1) work tree's .got/got.conf file
694 624411d2 2023-07-08 jrick * 2) repository's got.conf file
697 624411d2 2023-07-08 jrick if (worktree_conf)
698 624411d2 2023-07-08 jrick got_revoked_signers = got_gotconfig_get_revoked_signers_file(
699 624411d2 2023-07-08 jrick worktree_conf);
700 624411d2 2023-07-08 jrick if (got_revoked_signers == NULL)
701 624411d2 2023-07-08 jrick got_revoked_signers = got_gotconfig_get_revoked_signers_file(
702 624411d2 2023-07-08 jrick repo_conf);
704 624411d2 2023-07-08 jrick if (got_revoked_signers) {
705 624411d2 2023-07-08 jrick *revoked_signers = strdup(got_revoked_signers);
706 624411d2 2023-07-08 jrick if (*revoked_signers == NULL)
707 624411d2 2023-07-08 jrick return got_error_from_errno("strdup");
709 624411d2 2023-07-08 jrick return NULL;
712 624411d2 2023-07-08 jrick static const char *
713 624411d2 2023-07-08 jrick get_signer_id(struct got_repository *repo, struct got_worktree *worktree)
715 624411d2 2023-07-08 jrick const char *got_signer_id = NULL;
716 624411d2 2023-07-08 jrick const struct got_gotconfig *worktree_conf = NULL, *repo_conf = NULL;
718 624411d2 2023-07-08 jrick if (worktree)
719 624411d2 2023-07-08 jrick worktree_conf = got_worktree_get_gotconfig(worktree);
720 624411d2 2023-07-08 jrick repo_conf = got_repo_get_gotconfig(repo);
723 624411d2 2023-07-08 jrick * Priority of potential author information sources, from most
724 624411d2 2023-07-08 jrick * significant to least significant:
725 624411d2 2023-07-08 jrick * 1) work tree's .got/got.conf file
726 624411d2 2023-07-08 jrick * 2) repository's got.conf file
729 624411d2 2023-07-08 jrick if (worktree_conf)
730 624411d2 2023-07-08 jrick got_signer_id = got_gotconfig_get_signer_id(worktree_conf);
731 624411d2 2023-07-08 jrick if (got_signer_id == NULL)
732 624411d2 2023-07-08 jrick got_signer_id = got_gotconfig_get_signer_id(repo_conf);
734 624411d2 2023-07-08 jrick return got_signer_id;
737 624411d2 2023-07-08 jrick static const struct got_error *
738 624411d2 2023-07-08 jrick get_gitconfig_path(char **gitconfig_path)
740 624411d2 2023-07-08 jrick const char *homedir = getenv("HOME");
742 624411d2 2023-07-08 jrick *gitconfig_path = NULL;
743 624411d2 2023-07-08 jrick if (homedir) {
744 624411d2 2023-07-08 jrick if (asprintf(gitconfig_path, "%s/.gitconfig", homedir) == -1)
745 624411d2 2023-07-08 jrick return got_error_from_errno("asprintf");
748 624411d2 2023-07-08 jrick return NULL;
751 624411d2 2023-07-08 jrick static const struct got_error *
752 624411d2 2023-07-08 jrick cmd_import(int argc, char *argv[])
754 624411d2 2023-07-08 jrick const struct got_error *error = NULL;
755 624411d2 2023-07-08 jrick char *path_dir = NULL, *repo_path = NULL, *logmsg = NULL;
756 624411d2 2023-07-08 jrick char *gitconfig_path = NULL, *editor = NULL, *author = NULL;
757 624411d2 2023-07-08 jrick const char *branch_name = NULL;
758 624411d2 2023-07-08 jrick char *id_str = NULL, *logmsg_path = NULL;
759 624411d2 2023-07-08 jrick char refname[PATH_MAX] = "refs/heads/";
760 624411d2 2023-07-08 jrick struct got_repository *repo = NULL;
761 624411d2 2023-07-08 jrick struct got_reference *branch_ref = NULL, *head_ref = NULL;
762 624411d2 2023-07-08 jrick struct got_object_id *new_commit_id = NULL;
763 624411d2 2023-07-08 jrick int ch, n = 0;
764 624411d2 2023-07-08 jrick struct got_pathlist_head ignores;
765 624411d2 2023-07-08 jrick struct got_pathlist_entry *pe;
766 624411d2 2023-07-08 jrick int preserve_logmsg = 0;
767 624411d2 2023-07-08 jrick int *pack_fds = NULL;
769 624411d2 2023-07-08 jrick TAILQ_INIT(&ignores);
771 624411d2 2023-07-08 jrick #ifndef PROFILE
772 624411d2 2023-07-08 jrick if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd "
774 624411d2 2023-07-08 jrick NULL) == -1)
775 624411d2 2023-07-08 jrick err(1, "pledge");
778 624411d2 2023-07-08 jrick while ((ch = getopt(argc, argv, "b:I:m:r:")) != -1) {
779 624411d2 2023-07-08 jrick switch (ch) {
781 624411d2 2023-07-08 jrick branch_name = optarg;
784 624411d2 2023-07-08 jrick if (optarg[0] == '\0')
786 624411d2 2023-07-08 jrick error = got_pathlist_insert(&pe, &ignores, optarg,
788 624411d2 2023-07-08 jrick if (error)
789 624411d2 2023-07-08 jrick goto done;
792 624411d2 2023-07-08 jrick logmsg = strdup(optarg);
793 624411d2 2023-07-08 jrick if (logmsg == NULL) {
794 624411d2 2023-07-08 jrick error = got_error_from_errno("strdup");
795 624411d2 2023-07-08 jrick goto done;
799 624411d2 2023-07-08 jrick repo_path = realpath(optarg, NULL);
800 624411d2 2023-07-08 jrick if (repo_path == NULL) {
801 624411d2 2023-07-08 jrick error = got_error_from_errno2("realpath",
803 624411d2 2023-07-08 jrick goto done;
807 624411d2 2023-07-08 jrick usage_import();
808 624411d2 2023-07-08 jrick /* NOTREACHED */
812 624411d2 2023-07-08 jrick argc -= optind;
813 624411d2 2023-07-08 jrick argv += optind;
815 624411d2 2023-07-08 jrick if (argc != 1)
816 624411d2 2023-07-08 jrick usage_import();
818 624411d2 2023-07-08 jrick if (repo_path == NULL) {
819 624411d2 2023-07-08 jrick repo_path = getcwd(NULL, 0);
820 624411d2 2023-07-08 jrick if (repo_path == NULL)
821 624411d2 2023-07-08 jrick return got_error_from_errno("getcwd");
823 624411d2 2023-07-08 jrick got_path_strip_trailing_slashes(repo_path);
824 624411d2 2023-07-08 jrick error = get_gitconfig_path(&gitconfig_path);
825 624411d2 2023-07-08 jrick if (error)
826 624411d2 2023-07-08 jrick goto done;
827 624411d2 2023-07-08 jrick error = got_repo_pack_fds_open(&pack_fds);
828 624411d2 2023-07-08 jrick if (error != NULL)
829 624411d2 2023-07-08 jrick goto done;
830 624411d2 2023-07-08 jrick error = got_repo_open(&repo, repo_path, gitconfig_path, pack_fds);
831 624411d2 2023-07-08 jrick if (error)
832 624411d2 2023-07-08 jrick goto done;
834 624411d2 2023-07-08 jrick error = get_author(&author, repo, NULL);
835 624411d2 2023-07-08 jrick if (error)
836 624411d2 2023-07-08 jrick return error;
839 624411d2 2023-07-08 jrick * Don't let the user create a branch name with a leading '-'.
840 624411d2 2023-07-08 jrick * While technically a valid reference name, this case is usually
841 624411d2 2023-07-08 jrick * an unintended typo.
843 624411d2 2023-07-08 jrick if (branch_name && branch_name[0] == '-')
844 624411d2 2023-07-08 jrick return got_error_path(branch_name, GOT_ERR_REF_NAME_MINUS);
846 624411d2 2023-07-08 jrick error = got_ref_open(&head_ref, repo, GOT_REF_HEAD, 0);
847 624411d2 2023-07-08 jrick if (error && error->code != GOT_ERR_NOT_REF)
848 624411d2 2023-07-08 jrick goto done;
850 624411d2 2023-07-08 jrick if (branch_name)
851 624411d2 2023-07-08 jrick n = strlcat(refname, branch_name, sizeof(refname));
852 624411d2 2023-07-08 jrick else if (head_ref && got_ref_is_symbolic(head_ref))
853 624411d2 2023-07-08 jrick n = strlcpy(refname, got_ref_get_symref_target(head_ref),
854 624411d2 2023-07-08 jrick sizeof(refname));
856 624411d2 2023-07-08 jrick n = strlcat(refname, "main", sizeof(refname));
857 624411d2 2023-07-08 jrick if (n >= sizeof(refname)) {
858 624411d2 2023-07-08 jrick error = got_error(GOT_ERR_NO_SPACE);
859 624411d2 2023-07-08 jrick goto done;
862 624411d2 2023-07-08 jrick error = got_ref_open(&branch_ref, repo, refname, 0);
863 624411d2 2023-07-08 jrick if (error) {
864 624411d2 2023-07-08 jrick if (error->code != GOT_ERR_NOT_REF)
865 624411d2 2023-07-08 jrick goto done;
867 624411d2 2023-07-08 jrick error = got_error_msg(GOT_ERR_BRANCH_EXISTS,
868 624411d2 2023-07-08 jrick "import target branch already exists");
869 624411d2 2023-07-08 jrick goto done;
872 624411d2 2023-07-08 jrick path_dir = realpath(argv[0], NULL);
873 624411d2 2023-07-08 jrick if (path_dir == NULL) {
874 624411d2 2023-07-08 jrick error = got_error_from_errno2("realpath", argv[0]);
875 624411d2 2023-07-08 jrick goto done;
877 624411d2 2023-07-08 jrick got_path_strip_trailing_slashes(path_dir);
880 624411d2 2023-07-08 jrick * unveil(2) traverses exec(2); if an editor is used we have
881 624411d2 2023-07-08 jrick * to apply unveil after the log message has been written.
883 624411d2 2023-07-08 jrick if (logmsg == NULL || *logmsg == '\0') {
884 624411d2 2023-07-08 jrick error = get_editor(&editor);
885 624411d2 2023-07-08 jrick if (error)
886 624411d2 2023-07-08 jrick goto done;
887 624411d2 2023-07-08 jrick free(logmsg);
888 624411d2 2023-07-08 jrick error = collect_import_msg(&logmsg, &logmsg_path, editor,
889 624411d2 2023-07-08 jrick path_dir, refname);
890 624411d2 2023-07-08 jrick if (error) {
891 624411d2 2023-07-08 jrick if (error->code != GOT_ERR_COMMIT_MSG_EMPTY &&
892 624411d2 2023-07-08 jrick logmsg_path != NULL)
893 624411d2 2023-07-08 jrick preserve_logmsg = 1;
894 624411d2 2023-07-08 jrick goto done;
898 624411d2 2023-07-08 jrick if (unveil(path_dir, "r") != 0) {
899 624411d2 2023-07-08 jrick error = got_error_from_errno2("unveil", path_dir);
900 624411d2 2023-07-08 jrick if (logmsg_path)
901 624411d2 2023-07-08 jrick preserve_logmsg = 1;
902 624411d2 2023-07-08 jrick goto done;
905 624411d2 2023-07-08 jrick error = apply_unveil(got_repo_get_path(repo), 0, NULL);
906 624411d2 2023-07-08 jrick if (error) {
907 624411d2 2023-07-08 jrick if (logmsg_path)
908 624411d2 2023-07-08 jrick preserve_logmsg = 1;
909 624411d2 2023-07-08 jrick goto done;
912 624411d2 2023-07-08 jrick error = got_repo_import(&new_commit_id, path_dir, logmsg,
913 624411d2 2023-07-08 jrick author, &ignores, repo, import_progress, NULL);
914 624411d2 2023-07-08 jrick if (error) {
915 624411d2 2023-07-08 jrick if (logmsg_path)
916 624411d2 2023-07-08 jrick preserve_logmsg = 1;
917 624411d2 2023-07-08 jrick goto done;
920 624411d2 2023-07-08 jrick error = got_ref_alloc(&branch_ref, refname, new_commit_id);
921 624411d2 2023-07-08 jrick if (error) {
922 624411d2 2023-07-08 jrick if (logmsg_path)
923 624411d2 2023-07-08 jrick preserve_logmsg = 1;
924 624411d2 2023-07-08 jrick goto done;
927 624411d2 2023-07-08 jrick error = got_ref_write(branch_ref, repo);
928 624411d2 2023-07-08 jrick if (error) {
929 624411d2 2023-07-08 jrick if (logmsg_path)
930 624411d2 2023-07-08 jrick preserve_logmsg = 1;
931 624411d2 2023-07-08 jrick goto done;
934 624411d2 2023-07-08 jrick error = got_object_id_str(&id_str, new_commit_id);
935 624411d2 2023-07-08 jrick if (error) {
936 624411d2 2023-07-08 jrick if (logmsg_path)
937 624411d2 2023-07-08 jrick preserve_logmsg = 1;
938 624411d2 2023-07-08 jrick goto done;
941 624411d2 2023-07-08 jrick error = got_ref_open(&head_ref, repo, GOT_REF_HEAD, 0);
942 624411d2 2023-07-08 jrick if (error) {
943 624411d2 2023-07-08 jrick if (error->code != GOT_ERR_NOT_REF) {
944 624411d2 2023-07-08 jrick if (logmsg_path)
945 624411d2 2023-07-08 jrick preserve_logmsg = 1;
946 624411d2 2023-07-08 jrick goto done;
949 624411d2 2023-07-08 jrick error = got_ref_alloc_symref(&head_ref, GOT_REF_HEAD,
950 624411d2 2023-07-08 jrick branch_ref);
951 624411d2 2023-07-08 jrick if (error) {
952 624411d2 2023-07-08 jrick if (logmsg_path)
953 624411d2 2023-07-08 jrick preserve_logmsg = 1;
954 624411d2 2023-07-08 jrick goto done;
957 624411d2 2023-07-08 jrick error = got_ref_write(head_ref, repo);
958 624411d2 2023-07-08 jrick if (error) {
959 624411d2 2023-07-08 jrick if (logmsg_path)
960 624411d2 2023-07-08 jrick preserve_logmsg = 1;
961 624411d2 2023-07-08 jrick goto done;
965 624411d2 2023-07-08 jrick printf("Created branch %s with commit %s\n",
966 624411d2 2023-07-08 jrick got_ref_get_name(branch_ref), id_str);
968 624411d2 2023-07-08 jrick if (pack_fds) {
969 624411d2 2023-07-08 jrick const struct got_error *pack_err =
970 624411d2 2023-07-08 jrick got_repo_pack_fds_close(pack_fds);
971 624411d2 2023-07-08 jrick if (error == NULL)
972 624411d2 2023-07-08 jrick error = pack_err;
974 624411d2 2023-07-08 jrick if (repo) {
975 624411d2 2023-07-08 jrick const struct got_error *close_err = got_repo_close(repo);
976 624411d2 2023-07-08 jrick if (error == NULL)
977 624411d2 2023-07-08 jrick error = close_err;
979 624411d2 2023-07-08 jrick if (preserve_logmsg) {
980 624411d2 2023-07-08 jrick fprintf(stderr, "%s: log message preserved in %s\n",
981 624411d2 2023-07-08 jrick getprogname(), logmsg_path);
982 624411d2 2023-07-08 jrick } else if (logmsg_path && unlink(logmsg_path) == -1 && error == NULL)
983 624411d2 2023-07-08 jrick error = got_error_from_errno2("unlink", logmsg_path);
984 624411d2 2023-07-08 jrick free(logmsg);
985 624411d2 2023-07-08 jrick free(logmsg_path);
986 624411d2 2023-07-08 jrick free(repo_path);
987 624411d2 2023-07-08 jrick free(editor);
988 624411d2 2023-07-08 jrick free(new_commit_id);
989 624411d2 2023-07-08 jrick free(id_str);
990 624411d2 2023-07-08 jrick free(author);
991 624411d2 2023-07-08 jrick free(gitconfig_path);
992 624411d2 2023-07-08 jrick if (branch_ref)
993 624411d2 2023-07-08 jrick got_ref_close(branch_ref);
994 624411d2 2023-07-08 jrick if (head_ref)
995 624411d2 2023-07-08 jrick got_ref_close(head_ref);
996 624411d2 2023-07-08 jrick return error;
999 624411d2 2023-07-08 jrick __dead static void
1000 624411d2 2023-07-08 jrick usage_clone(void)
1002 624411d2 2023-07-08 jrick fprintf(stderr, "usage: %s clone [-almqv] [-b branch] [-R reference] "
1003 624411d2 2023-07-08 jrick "repository-URL [directory]\n", getprogname());
1007 624411d2 2023-07-08 jrick struct got_fetch_progress_arg {
1008 624411d2 2023-07-08 jrick char last_scaled_size[FMT_SCALED_STRSIZE];
1009 624411d2 2023-07-08 jrick int last_p_indexed;
1010 624411d2 2023-07-08 jrick int last_p_resolved;
1011 624411d2 2023-07-08 jrick int verbosity;
1013 624411d2 2023-07-08 jrick struct got_repository *repo;
1015 624411d2 2023-07-08 jrick int create_configs;
1016 624411d2 2023-07-08 jrick int configs_created;
1018 624411d2 2023-07-08 jrick struct got_pathlist_head *symrefs;
1019 624411d2 2023-07-08 jrick struct got_pathlist_head *wanted_branches;
1020 624411d2 2023-07-08 jrick struct got_pathlist_head *wanted_refs;
1021 624411d2 2023-07-08 jrick const char *proto;
1022 624411d2 2023-07-08 jrick const char *host;
1023 624411d2 2023-07-08 jrick const char *port;
1024 624411d2 2023-07-08 jrick const char *remote_repo_path;
1025 624411d2 2023-07-08 jrick const char *git_url;
1026 624411d2 2023-07-08 jrick int fetch_all_branches;
1027 624411d2 2023-07-08 jrick int mirror_references;
1028 624411d2 2023-07-08 jrick } config_info;
1031 624411d2 2023-07-08 jrick /* XXX forward declaration */
1032 624411d2 2023-07-08 jrick static const struct got_error *
1033 624411d2 2023-07-08 jrick create_config_files(const char *proto, const char *host, const char *port,
1034 624411d2 2023-07-08 jrick const char *remote_repo_path, const char *git_url, int fetch_all_branches,
1035 624411d2 2023-07-08 jrick int mirror_references, struct got_pathlist_head *symrefs,
1036 624411d2 2023-07-08 jrick struct got_pathlist_head *wanted_branches,
1037 624411d2 2023-07-08 jrick struct got_pathlist_head *wanted_refs, struct got_repository *repo);
1039 624411d2 2023-07-08 jrick static const struct got_error *
1040 624411d2 2023-07-08 jrick fetch_progress(void *arg, const char *message, off_t packfile_size,
1041 624411d2 2023-07-08 jrick int nobj_total, int nobj_indexed, int nobj_loose, int nobj_resolved)
1043 624411d2 2023-07-08 jrick const struct got_error *err = NULL;
1044 624411d2 2023-07-08 jrick struct got_fetch_progress_arg *a = arg;
1045 624411d2 2023-07-08 jrick char scaled_size[FMT_SCALED_STRSIZE];
1046 624411d2 2023-07-08 jrick int p_indexed, p_resolved;
1047 624411d2 2023-07-08 jrick int print_size = 0, print_indexed = 0, print_resolved = 0;
1050 624411d2 2023-07-08 jrick * In order to allow a failed clone to be resumed with 'got fetch'
1051 624411d2 2023-07-08 jrick * we try to create configuration files as soon as possible.
1052 624411d2 2023-07-08 jrick * Once the server has sent information about its default branch
1053 624411d2 2023-07-08 jrick * we have all required information.
1055 624411d2 2023-07-08 jrick if (a->create_configs && !a->configs_created &&
1056 624411d2 2023-07-08 jrick !TAILQ_EMPTY(a->config_info.symrefs)) {
1057 624411d2 2023-07-08 jrick err = create_config_files(a->config_info.proto,
1058 624411d2 2023-07-08 jrick a->config_info.host, a->config_info.port,
1059 624411d2 2023-07-08 jrick a->config_info.remote_repo_path,
1060 624411d2 2023-07-08 jrick a->config_info.git_url,
1061 624411d2 2023-07-08 jrick a->config_info.fetch_all_branches,
1062 624411d2 2023-07-08 jrick a->config_info.mirror_references,
1063 624411d2 2023-07-08 jrick a->config_info.symrefs,
1064 624411d2 2023-07-08 jrick a->config_info.wanted_branches,
1065 624411d2 2023-07-08 jrick a->config_info.wanted_refs, a->repo);
1067 624411d2 2023-07-08 jrick return err;
1068 624411d2 2023-07-08 jrick a->configs_created = 1;
1071 624411d2 2023-07-08 jrick if (a->verbosity < 0)
1072 624411d2 2023-07-08 jrick return NULL;
1074 624411d2 2023-07-08 jrick if (message && message[0] != '\0') {
1075 624411d2 2023-07-08 jrick printf("\rserver: %s", message);
1076 624411d2 2023-07-08 jrick fflush(stdout);
1077 624411d2 2023-07-08 jrick return NULL;
1080 624411d2 2023-07-08 jrick if (packfile_size > 0 || nobj_indexed > 0) {
1081 624411d2 2023-07-08 jrick if (fmt_scaled(packfile_size, scaled_size) == 0 &&
1082 624411d2 2023-07-08 jrick (a->last_scaled_size[0] == '\0' ||
1083 624411d2 2023-07-08 jrick strcmp(scaled_size, a->last_scaled_size)) != 0) {
1084 624411d2 2023-07-08 jrick print_size = 1;
1085 624411d2 2023-07-08 jrick if (strlcpy(a->last_scaled_size, scaled_size,
1086 624411d2 2023-07-08 jrick FMT_SCALED_STRSIZE) >= FMT_SCALED_STRSIZE)
1087 624411d2 2023-07-08 jrick return got_error(GOT_ERR_NO_SPACE);
1089 624411d2 2023-07-08 jrick if (nobj_indexed > 0) {
1090 624411d2 2023-07-08 jrick p_indexed = (nobj_indexed * 100) / nobj_total;
1091 624411d2 2023-07-08 jrick if (p_indexed != a->last_p_indexed) {
1092 624411d2 2023-07-08 jrick a->last_p_indexed = p_indexed;
1093 624411d2 2023-07-08 jrick print_indexed = 1;
1094 624411d2 2023-07-08 jrick print_size = 1;
1097 624411d2 2023-07-08 jrick if (nobj_resolved > 0) {
1098 624411d2 2023-07-08 jrick p_resolved = (nobj_resolved * 100) /
1099 624411d2 2023-07-08 jrick (nobj_total - nobj_loose);
1100 624411d2 2023-07-08 jrick if (p_resolved != a->last_p_resolved) {
1101 624411d2 2023-07-08 jrick a->last_p_resolved = p_resolved;
1102 624411d2 2023-07-08 jrick print_resolved = 1;
1103 624411d2 2023-07-08 jrick print_indexed = 1;
1104 624411d2 2023-07-08 jrick print_size = 1;
1109 624411d2 2023-07-08 jrick if (print_size || print_indexed || print_resolved)
1110 624411d2 2023-07-08 jrick printf("\r");
1111 624411d2 2023-07-08 jrick if (print_size)
1112 624411d2 2023-07-08 jrick printf("%*s fetched", FMT_SCALED_STRSIZE - 2, scaled_size);
1113 624411d2 2023-07-08 jrick if (print_indexed)
1114 624411d2 2023-07-08 jrick printf("; indexing %d%%", p_indexed);
1115 624411d2 2023-07-08 jrick if (print_resolved)
1116 624411d2 2023-07-08 jrick printf("; resolving deltas %d%%", p_resolved);
1117 624411d2 2023-07-08 jrick if (print_size || print_indexed || print_resolved)
1118 624411d2 2023-07-08 jrick fflush(stdout);
1120 624411d2 2023-07-08 jrick return NULL;
1123 624411d2 2023-07-08 jrick static const struct got_error *
1124 624411d2 2023-07-08 jrick create_symref(const char *refname, struct got_reference *target_ref,
1125 624411d2 2023-07-08 jrick int verbosity, struct got_repository *repo)
1127 624411d2 2023-07-08 jrick const struct got_error *err;
1128 624411d2 2023-07-08 jrick struct got_reference *head_symref;
1130 624411d2 2023-07-08 jrick err = got_ref_alloc_symref(&head_symref, refname, target_ref);
1132 624411d2 2023-07-08 jrick return err;
1134 624411d2 2023-07-08 jrick err = got_ref_write(head_symref, repo);
1135 624411d2 2023-07-08 jrick if (err == NULL && verbosity > 0) {
1136 624411d2 2023-07-08 jrick printf("Created reference %s: %s\n", GOT_REF_HEAD,
1137 624411d2 2023-07-08 jrick got_ref_get_name(target_ref));
1139 624411d2 2023-07-08 jrick got_ref_close(head_symref);
1140 624411d2 2023-07-08 jrick return err;
1143 624411d2 2023-07-08 jrick static const struct got_error *
1144 624411d2 2023-07-08 jrick list_remote_refs(struct got_pathlist_head *symrefs,
1145 624411d2 2023-07-08 jrick struct got_pathlist_head *refs)
1147 624411d2 2023-07-08 jrick const struct got_error *err;
1148 624411d2 2023-07-08 jrick struct got_pathlist_entry *pe;
1150 624411d2 2023-07-08 jrick TAILQ_FOREACH(pe, symrefs, entry) {
1151 624411d2 2023-07-08 jrick const char *refname = pe->path;
1152 624411d2 2023-07-08 jrick const char *targetref = pe->data;
1154 624411d2 2023-07-08 jrick printf("%s: %s\n", refname, targetref);
1157 624411d2 2023-07-08 jrick TAILQ_FOREACH(pe, refs, entry) {
1158 624411d2 2023-07-08 jrick const char *refname = pe->path;
1159 624411d2 2023-07-08 jrick struct got_object_id *id = pe->data;
1160 624411d2 2023-07-08 jrick char *id_str;
1162 624411d2 2023-07-08 jrick err = got_object_id_str(&id_str, id);
1164 624411d2 2023-07-08 jrick return err;
1165 624411d2 2023-07-08 jrick printf("%s: %s\n", refname, id_str);
1166 624411d2 2023-07-08 jrick free(id_str);
1169 624411d2 2023-07-08 jrick return NULL;
1172 624411d2 2023-07-08 jrick static const struct got_error *
1173 624411d2 2023-07-08 jrick create_ref(const char *refname, struct got_object_id *id,
1174 624411d2 2023-07-08 jrick int verbosity, struct got_repository *repo)
1176 624411d2 2023-07-08 jrick const struct got_error *err = NULL;
1177 624411d2 2023-07-08 jrick struct got_reference *ref;
1178 624411d2 2023-07-08 jrick char *id_str;
1180 624411d2 2023-07-08 jrick err = got_object_id_str(&id_str, id);
1182 624411d2 2023-07-08 jrick return err;
1184 624411d2 2023-07-08 jrick err = got_ref_alloc(&ref, refname, id);
1186 624411d2 2023-07-08 jrick goto done;
1188 624411d2 2023-07-08 jrick err = got_ref_write(ref, repo);
1189 624411d2 2023-07-08 jrick got_ref_close(ref);
1191 624411d2 2023-07-08 jrick if (err == NULL && verbosity >= 0)
1192 624411d2 2023-07-08 jrick printf("Created reference %s: %s\n", refname, id_str);
1194 624411d2 2023-07-08 jrick free(id_str);
1195 624411d2 2023-07-08 jrick return err;
1198 624411d2 2023-07-08 jrick static int
1199 624411d2 2023-07-08 jrick match_wanted_ref(const char *refname, const char *wanted_ref)
1201 624411d2 2023-07-08 jrick if (strncmp(refname, "refs/", 5) != 0)
1202 624411d2 2023-07-08 jrick return 0;
1203 624411d2 2023-07-08 jrick refname += 5;
1206 624411d2 2023-07-08 jrick * Prevent fetching of references that won't make any
1207 624411d2 2023-07-08 jrick * sense outside of the remote repository's context.
1209 624411d2 2023-07-08 jrick if (strncmp(refname, "got/", 4) == 0)
1210 624411d2 2023-07-08 jrick return 0;
1211 624411d2 2023-07-08 jrick if (strncmp(refname, "remotes/", 8) == 0)
1212 624411d2 2023-07-08 jrick return 0;
1214 624411d2 2023-07-08 jrick if (strncmp(wanted_ref, "refs/", 5) == 0)
1215 624411d2 2023-07-08 jrick wanted_ref += 5;
1217 624411d2 2023-07-08 jrick /* Allow prefix match. */
1218 624411d2 2023-07-08 jrick if (got_path_is_child(refname, wanted_ref, strlen(wanted_ref)))
1219 624411d2 2023-07-08 jrick return 1;
1221 624411d2 2023-07-08 jrick /* Allow exact match. */
1222 624411d2 2023-07-08 jrick return (strcmp(refname, wanted_ref) == 0);
1225 624411d2 2023-07-08 jrick static int
1226 624411d2 2023-07-08 jrick is_wanted_ref(struct got_pathlist_head *wanted_refs, const char *refname)
1228 624411d2 2023-07-08 jrick struct got_pathlist_entry *pe;
1230 624411d2 2023-07-08 jrick TAILQ_FOREACH(pe, wanted_refs, entry) {
1231 624411d2 2023-07-08 jrick if (match_wanted_ref(refname, pe->path))
1232 624411d2 2023-07-08 jrick return 1;
1235 624411d2 2023-07-08 jrick return 0;
1238 624411d2 2023-07-08 jrick static const struct got_error *
1239 624411d2 2023-07-08 jrick create_wanted_ref(const char *refname, struct got_object_id *id,
1240 624411d2 2023-07-08 jrick const char *remote_repo_name, int verbosity, struct got_repository *repo)
1242 624411d2 2023-07-08 jrick const struct got_error *err;
1243 624411d2 2023-07-08 jrick char *remote_refname;
1245 624411d2 2023-07-08 jrick if (strncmp("refs/", refname, 5) == 0)
1246 624411d2 2023-07-08 jrick refname += 5;
1248 624411d2 2023-07-08 jrick if (asprintf(&remote_refname, "refs/remotes/%s/%s",
1249 624411d2 2023-07-08 jrick remote_repo_name, refname) == -1)
1250 624411d2 2023-07-08 jrick return got_error_from_errno("asprintf");
1252 624411d2 2023-07-08 jrick err = create_ref(remote_refname, id, verbosity, repo);
1253 624411d2 2023-07-08 jrick free(remote_refname);
1254 624411d2 2023-07-08 jrick return err;
1257 624411d2 2023-07-08 jrick static const struct got_error *
1258 624411d2 2023-07-08 jrick create_gotconfig(const char *proto, const char *host, const char *port,
1259 624411d2 2023-07-08 jrick const char *remote_repo_path, const char *default_branch,
1260 624411d2 2023-07-08 jrick int fetch_all_branches, struct got_pathlist_head *wanted_branches,
1261 624411d2 2023-07-08 jrick struct got_pathlist_head *wanted_refs, int mirror_references,
1262 624411d2 2023-07-08 jrick struct got_repository *repo)
1264 624411d2 2023-07-08 jrick const struct got_error *err = NULL;
1265 624411d2 2023-07-08 jrick char *gotconfig_path = NULL;
1266 624411d2 2023-07-08 jrick char *gotconfig = NULL;
1267 624411d2 2023-07-08 jrick FILE *gotconfig_file = NULL;
1268 624411d2 2023-07-08 jrick const char *branchname = NULL;
1269 624411d2 2023-07-08 jrick char *branches = NULL, *refs = NULL;
1270 624411d2 2023-07-08 jrick ssize_t n;
1272 624411d2 2023-07-08 jrick if (!fetch_all_branches && !TAILQ_EMPTY(wanted_branches)) {
1273 624411d2 2023-07-08 jrick struct got_pathlist_entry *pe;
1274 624411d2 2023-07-08 jrick TAILQ_FOREACH(pe, wanted_branches, entry) {
1276 624411d2 2023-07-08 jrick branchname = pe->path;
1277 624411d2 2023-07-08 jrick if (strncmp(branchname, "refs/heads/", 11) == 0)
1278 624411d2 2023-07-08 jrick branchname += 11;
1279 624411d2 2023-07-08 jrick if (asprintf(&s, "%s\"%s\" ",
1280 624411d2 2023-07-08 jrick branches ? branches : "", branchname) == -1) {
1281 624411d2 2023-07-08 jrick err = got_error_from_errno("asprintf");
1282 624411d2 2023-07-08 jrick goto done;
1284 624411d2 2023-07-08 jrick free(branches);
1285 624411d2 2023-07-08 jrick branches = s;
1287 624411d2 2023-07-08 jrick } else if (!fetch_all_branches && default_branch) {
1288 624411d2 2023-07-08 jrick branchname = default_branch;
1289 624411d2 2023-07-08 jrick if (strncmp(branchname, "refs/heads/", 11) == 0)
1290 624411d2 2023-07-08 jrick branchname += 11;
1291 624411d2 2023-07-08 jrick if (asprintf(&branches, "\"%s\" ", branchname) == -1) {
1292 624411d2 2023-07-08 jrick err = got_error_from_errno("asprintf");
1293 624411d2 2023-07-08 jrick goto done;
1296 624411d2 2023-07-08 jrick if (!TAILQ_EMPTY(wanted_refs)) {
1297 624411d2 2023-07-08 jrick struct got_pathlist_entry *pe;
1298 624411d2 2023-07-08 jrick TAILQ_FOREACH(pe, wanted_refs, entry) {
1300 624411d2 2023-07-08 jrick const char *refname = pe->path;
1301 624411d2 2023-07-08 jrick if (strncmp(refname, "refs/", 5) == 0)
1302 624411d2 2023-07-08 jrick branchname += 5;
1303 624411d2 2023-07-08 jrick if (asprintf(&s, "%s\"%s\" ",
1304 624411d2 2023-07-08 jrick refs ? refs : "", refname) == -1) {
1305 624411d2 2023-07-08 jrick err = got_error_from_errno("asprintf");
1306 624411d2 2023-07-08 jrick goto done;
1308 624411d2 2023-07-08 jrick free(refs);
1309 624411d2 2023-07-08 jrick refs = s;
1313 624411d2 2023-07-08 jrick /* Create got.conf(5). */
1314 624411d2 2023-07-08 jrick gotconfig_path = got_repo_get_path_gotconfig(repo);
1315 624411d2 2023-07-08 jrick if (gotconfig_path == NULL) {
1316 624411d2 2023-07-08 jrick err = got_error_from_errno("got_repo_get_path_gotconfig");
1317 624411d2 2023-07-08 jrick goto done;
1319 624411d2 2023-07-08 jrick gotconfig_file = fopen(gotconfig_path, "ae");
1320 624411d2 2023-07-08 jrick if (gotconfig_file == NULL) {
1321 624411d2 2023-07-08 jrick err = got_error_from_errno2("fopen", gotconfig_path);
1322 624411d2 2023-07-08 jrick goto done;
1324 624411d2 2023-07-08 jrick if (asprintf(&gotconfig,
1325 624411d2 2023-07-08 jrick "remote \"%s\" {\n"
1326 624411d2 2023-07-08 jrick "\tserver %s\n"
1327 624411d2 2023-07-08 jrick "\tprotocol %s\n"
1329 624411d2 2023-07-08 jrick "\trepository \"%s\"\n"
1335 624411d2 2023-07-08 jrick GOT_FETCH_DEFAULT_REMOTE_NAME, host, proto,
1336 624411d2 2023-07-08 jrick port ? "\tport " : "", port ? port : "", port ? "\n" : "",
1337 624411d2 2023-07-08 jrick remote_repo_path, branches ? "\tbranch { " : "",
1338 624411d2 2023-07-08 jrick branches ? branches : "", branches ? "}\n" : "",
1339 624411d2 2023-07-08 jrick refs ? "\treference { " : "", refs ? refs : "", refs ? "}\n" : "",
1340 624411d2 2023-07-08 jrick mirror_references ? "\tmirror_references yes\n" : "",
1341 624411d2 2023-07-08 jrick fetch_all_branches ? "\tfetch_all_branches yes\n" : "") == -1) {
1342 624411d2 2023-07-08 jrick err = got_error_from_errno("asprintf");
1343 624411d2 2023-07-08 jrick goto done;
1345 624411d2 2023-07-08 jrick n = fwrite(gotconfig, 1, strlen(gotconfig), gotconfig_file);
1346 624411d2 2023-07-08 jrick if (n != strlen(gotconfig)) {
1347 624411d2 2023-07-08 jrick err = got_ferror(gotconfig_file, GOT_ERR_IO);
1348 624411d2 2023-07-08 jrick goto done;
1352 624411d2 2023-07-08 jrick if (gotconfig_file && fclose(gotconfig_file) == EOF && err == NULL)
1353 624411d2 2023-07-08 jrick err = got_error_from_errno2("fclose", gotconfig_path);
1354 624411d2 2023-07-08 jrick free(gotconfig_path);
1355 624411d2 2023-07-08 jrick free(branches);
1356 624411d2 2023-07-08 jrick return err;
1359 624411d2 2023-07-08 jrick static const struct got_error *
1360 624411d2 2023-07-08 jrick create_gitconfig(const char *git_url, const char *default_branch,
1361 624411d2 2023-07-08 jrick int fetch_all_branches, struct got_pathlist_head *wanted_branches,
1362 624411d2 2023-07-08 jrick struct got_pathlist_head *wanted_refs, int mirror_references,
1363 624411d2 2023-07-08 jrick struct got_repository *repo)
1365 624411d2 2023-07-08 jrick const struct got_error *err = NULL;
1366 624411d2 2023-07-08 jrick char *gitconfig_path = NULL;
1367 624411d2 2023-07-08 jrick char *gitconfig = NULL;
1368 624411d2 2023-07-08 jrick FILE *gitconfig_file = NULL;
1369 624411d2 2023-07-08 jrick char *branches = NULL, *refs = NULL;
1370 624411d2 2023-07-08 jrick const char *branchname;
1371 624411d2 2023-07-08 jrick ssize_t n;
1373 624411d2 2023-07-08 jrick /* Create a config file Git can understand. */
1374 624411d2 2023-07-08 jrick gitconfig_path = got_repo_get_path_gitconfig(repo);
1375 624411d2 2023-07-08 jrick if (gitconfig_path == NULL) {
1376 624411d2 2023-07-08 jrick err = got_error_from_errno("got_repo_get_path_gitconfig");
1377 624411d2 2023-07-08 jrick goto done;
1379 624411d2 2023-07-08 jrick gitconfig_file = fopen(gitconfig_path, "ae");
1380 624411d2 2023-07-08 jrick if (gitconfig_file == NULL) {
1381 624411d2 2023-07-08 jrick err = got_error_from_errno2("fopen", gitconfig_path);
1382 624411d2 2023-07-08 jrick goto done;
1384 624411d2 2023-07-08 jrick if (fetch_all_branches) {
1385 624411d2 2023-07-08 jrick if (mirror_references) {
1386 624411d2 2023-07-08 jrick if (asprintf(&branches,
1387 624411d2 2023-07-08 jrick "\tfetch = refs/heads/*:refs/heads/*\n") == -1) {
1388 624411d2 2023-07-08 jrick err = got_error_from_errno("asprintf");
1389 624411d2 2023-07-08 jrick goto done;
1391 624411d2 2023-07-08 jrick } else if (asprintf(&branches,
1392 624411d2 2023-07-08 jrick "\tfetch = refs/heads/*:refs/remotes/%s/*\n",
1393 624411d2 2023-07-08 jrick GOT_FETCH_DEFAULT_REMOTE_NAME) == -1) {
1394 624411d2 2023-07-08 jrick err = got_error_from_errno("asprintf");
1395 624411d2 2023-07-08 jrick goto done;
1397 624411d2 2023-07-08 jrick } else if (!TAILQ_EMPTY(wanted_branches)) {
1398 624411d2 2023-07-08 jrick struct got_pathlist_entry *pe;
1399 624411d2 2023-07-08 jrick TAILQ_FOREACH(pe, wanted_branches, entry) {
1401 624411d2 2023-07-08 jrick branchname = pe->path;
1402 624411d2 2023-07-08 jrick if (strncmp(branchname, "refs/heads/", 11) == 0)
1403 624411d2 2023-07-08 jrick branchname += 11;
1404 624411d2 2023-07-08 jrick if (mirror_references) {
1405 624411d2 2023-07-08 jrick if (asprintf(&s,
1406 624411d2 2023-07-08 jrick "%s\tfetch = refs/heads/%s:refs/heads/%s\n",
1407 624411d2 2023-07-08 jrick branches ? branches : "",
1408 624411d2 2023-07-08 jrick branchname, branchname) == -1) {
1409 624411d2 2023-07-08 jrick err = got_error_from_errno("asprintf");
1410 624411d2 2023-07-08 jrick goto done;
1412 624411d2 2023-07-08 jrick } else if (asprintf(&s,
1413 624411d2 2023-07-08 jrick "%s\tfetch = refs/heads/%s:refs/remotes/%s/%s\n",
1414 624411d2 2023-07-08 jrick branches ? branches : "",
1415 624411d2 2023-07-08 jrick branchname, GOT_FETCH_DEFAULT_REMOTE_NAME,
1416 624411d2 2023-07-08 jrick branchname) == -1) {
1417 624411d2 2023-07-08 jrick err = got_error_from_errno("asprintf");
1418 624411d2 2023-07-08 jrick goto done;
1420 624411d2 2023-07-08 jrick free(branches);
1421 624411d2 2023-07-08 jrick branches = s;
1425 624411d2 2023-07-08 jrick * If the server specified a default branch, use just that one.
1426 624411d2 2023-07-08 jrick * Otherwise fall back to fetching all branches on next fetch.
1428 624411d2 2023-07-08 jrick if (default_branch) {
1429 624411d2 2023-07-08 jrick branchname = default_branch;
1430 624411d2 2023-07-08 jrick if (strncmp(branchname, "refs/heads/", 11) == 0)
1431 624411d2 2023-07-08 jrick branchname += 11;
1433 624411d2 2023-07-08 jrick branchname = "*"; /* fall back to all branches */
1434 624411d2 2023-07-08 jrick if (mirror_references) {
1435 624411d2 2023-07-08 jrick if (asprintf(&branches,
1436 624411d2 2023-07-08 jrick "\tfetch = refs/heads/%s:refs/heads/%s\n",
1437 624411d2 2023-07-08 jrick branchname, branchname) == -1) {
1438 624411d2 2023-07-08 jrick err = got_error_from_errno("asprintf");
1439 624411d2 2023-07-08 jrick goto done;
1441 624411d2 2023-07-08 jrick } else if (asprintf(&branches,
1442 624411d2 2023-07-08 jrick "\tfetch = refs/heads/%s:refs/remotes/%s/%s\n",
1443 624411d2 2023-07-08 jrick branchname, GOT_FETCH_DEFAULT_REMOTE_NAME,
1444 624411d2 2023-07-08 jrick branchname) == -1) {
1445 624411d2 2023-07-08 jrick err = got_error_from_errno("asprintf");
1446 624411d2 2023-07-08 jrick goto done;
1449 624411d2 2023-07-08 jrick if (!TAILQ_EMPTY(wanted_refs)) {
1450 624411d2 2023-07-08 jrick struct got_pathlist_entry *pe;
1451 624411d2 2023-07-08 jrick TAILQ_FOREACH(pe, wanted_refs, entry) {
1453 624411d2 2023-07-08 jrick const char *refname = pe->path;
1454 624411d2 2023-07-08 jrick if (strncmp(refname, "refs/", 5) == 0)
1455 624411d2 2023-07-08 jrick refname += 5;
1456 624411d2 2023-07-08 jrick if (mirror_references) {
1457 624411d2 2023-07-08 jrick if (asprintf(&s,
1458 624411d2 2023-07-08 jrick "%s\tfetch = refs/%s:refs/%s\n",
1459 624411d2 2023-07-08 jrick refs ? refs : "", refname, refname) == -1) {
1460 624411d2 2023-07-08 jrick err = got_error_from_errno("asprintf");
1461 624411d2 2023-07-08 jrick goto done;
1463 624411d2 2023-07-08 jrick } else if (asprintf(&s,
1464 624411d2 2023-07-08 jrick "%s\tfetch = refs/%s:refs/remotes/%s/%s\n",
1465 624411d2 2023-07-08 jrick refs ? refs : "",
1466 624411d2 2023-07-08 jrick refname, GOT_FETCH_DEFAULT_REMOTE_NAME,
1467 624411d2 2023-07-08 jrick refname) == -1) {
1468 624411d2 2023-07-08 jrick err = got_error_from_errno("asprintf");
1469 624411d2 2023-07-08 jrick goto done;
1471 624411d2 2023-07-08 jrick free(refs);
1472 624411d2 2023-07-08 jrick refs = s;
1476 624411d2 2023-07-08 jrick if (asprintf(&gitconfig,
1477 624411d2 2023-07-08 jrick "[remote \"%s\"]\n"
1478 624411d2 2023-07-08 jrick "\turl = %s\n"
1481 624411d2 2023-07-08 jrick "\tfetch = refs/tags/*:refs/tags/*\n",
1482 624411d2 2023-07-08 jrick GOT_FETCH_DEFAULT_REMOTE_NAME, git_url, branches ? branches : "",
1483 624411d2 2023-07-08 jrick refs ? refs : "") == -1) {
1484 624411d2 2023-07-08 jrick err = got_error_from_errno("asprintf");
1485 624411d2 2023-07-08 jrick goto done;
1487 624411d2 2023-07-08 jrick n = fwrite(gitconfig, 1, strlen(gitconfig), gitconfig_file);
1488 624411d2 2023-07-08 jrick if (n != strlen(gitconfig)) {
1489 624411d2 2023-07-08 jrick err = got_ferror(gitconfig_file, GOT_ERR_IO);
1490 624411d2 2023-07-08 jrick goto done;
1493 624411d2 2023-07-08 jrick if (gitconfig_file && fclose(gitconfig_file) == EOF && err == NULL)
1494 624411d2 2023-07-08 jrick err = got_error_from_errno2("fclose", gitconfig_path);
1495 624411d2 2023-07-08 jrick free(gitconfig_path);
1496 624411d2 2023-07-08 jrick free(branches);
1497 624411d2 2023-07-08 jrick return err;
1500 624411d2 2023-07-08 jrick static const struct got_error *
1501 624411d2 2023-07-08 jrick create_config_files(const char *proto, const char *host, const char *port,
1502 624411d2 2023-07-08 jrick const char *remote_repo_path, const char *git_url, int fetch_all_branches,
1503 624411d2 2023-07-08 jrick int mirror_references, struct got_pathlist_head *symrefs,
1504 624411d2 2023-07-08 jrick struct got_pathlist_head *wanted_branches,
1505 624411d2 2023-07-08 jrick struct got_pathlist_head *wanted_refs, struct got_repository *repo)
1507 624411d2 2023-07-08 jrick const struct got_error *err = NULL;
1508 624411d2 2023-07-08 jrick const char *default_branch = NULL;
1509 624411d2 2023-07-08 jrick struct got_pathlist_entry *pe;
1512 624411d2 2023-07-08 jrick * If we asked for a set of wanted branches then use the first
1513 624411d2 2023-07-08 jrick * one of those.
1515 624411d2 2023-07-08 jrick if (!TAILQ_EMPTY(wanted_branches)) {
1516 624411d2 2023-07-08 jrick pe = TAILQ_FIRST(wanted_branches);
1517 624411d2 2023-07-08 jrick default_branch = pe->path;
1519 624411d2 2023-07-08 jrick /* First HEAD ref listed by server is the default branch. */
1520 624411d2 2023-07-08 jrick TAILQ_FOREACH(pe, symrefs, entry) {
1521 624411d2 2023-07-08 jrick const char *refname = pe->path;
1522 624411d2 2023-07-08 jrick const char *target = pe->data;
1524 624411d2 2023-07-08 jrick if (strcmp(refname, GOT_REF_HEAD) != 0)
1525 624411d2 2023-07-08 jrick continue;
1527 624411d2 2023-07-08 jrick default_branch = target;
1532 624411d2 2023-07-08 jrick /* Create got.conf(5). */
1533 624411d2 2023-07-08 jrick err = create_gotconfig(proto, host, port, remote_repo_path,
1534 624411d2 2023-07-08 jrick default_branch, fetch_all_branches, wanted_branches,
1535 624411d2 2023-07-08 jrick wanted_refs, mirror_references, repo);
1537 624411d2 2023-07-08 jrick return err;
1539 624411d2 2023-07-08 jrick /* Create a config file Git can understand. */
1540 624411d2 2023-07-08 jrick return create_gitconfig(git_url, default_branch, fetch_all_branches,
1541 624411d2 2023-07-08 jrick wanted_branches, wanted_refs, mirror_references, repo);
1544 624411d2 2023-07-08 jrick static const struct got_error *
1545 624411d2 2023-07-08 jrick cmd_clone(int argc, char *argv[])
1547 624411d2 2023-07-08 jrick const struct got_error *error = NULL;
1548 624411d2 2023-07-08 jrick const char *uri, *dirname;
1549 624411d2 2023-07-08 jrick char *proto, *host, *port, *repo_name, *server_path;
1550 624411d2 2023-07-08 jrick char *default_destdir = NULL, *id_str = NULL;
1551 624411d2 2023-07-08 jrick const char *repo_path;
1552 624411d2 2023-07-08 jrick struct got_repository *repo = NULL;
1553 624411d2 2023-07-08 jrick struct got_pathlist_head refs, symrefs, wanted_branches, wanted_refs;
1554 624411d2 2023-07-08 jrick struct got_pathlist_entry *pe;
1555 624411d2 2023-07-08 jrick struct got_object_id *pack_hash = NULL;
1556 624411d2 2023-07-08 jrick int ch, fetchfd = -1, fetchstatus;
1557 624411d2 2023-07-08 jrick pid_t fetchpid = -1;
1558 624411d2 2023-07-08 jrick struct got_fetch_progress_arg fpa;
1559 624411d2 2023-07-08 jrick char *git_url = NULL;
1560 624411d2 2023-07-08 jrick int verbosity = 0, fetch_all_branches = 0, mirror_references = 0;
1561 624411d2 2023-07-08 jrick int bflag = 0, list_refs_only = 0;
1562 624411d2 2023-07-08 jrick int *pack_fds = NULL;
1564 624411d2 2023-07-08 jrick TAILQ_INIT(&refs);
1565 624411d2 2023-07-08 jrick TAILQ_INIT(&symrefs);
1566 624411d2 2023-07-08 jrick TAILQ_INIT(&wanted_branches);
1567 624411d2 2023-07-08 jrick TAILQ_INIT(&wanted_refs);
1569 624411d2 2023-07-08 jrick while ((ch = getopt(argc, argv, "ab:lmqR:v")) != -1) {
1570 624411d2 2023-07-08 jrick switch (ch) {
1571 624411d2 2023-07-08 jrick case 'a':
1572 624411d2 2023-07-08 jrick fetch_all_branches = 1;
1574 624411d2 2023-07-08 jrick case 'b':
1575 624411d2 2023-07-08 jrick error = got_pathlist_append(&wanted_branches,
1576 624411d2 2023-07-08 jrick optarg, NULL);
1577 624411d2 2023-07-08 jrick if (error)
1578 624411d2 2023-07-08 jrick return error;
1579 624411d2 2023-07-08 jrick bflag = 1;
1581 624411d2 2023-07-08 jrick case 'l':
1582 624411d2 2023-07-08 jrick list_refs_only = 1;
1584 624411d2 2023-07-08 jrick case 'm':
1585 624411d2 2023-07-08 jrick mirror_references = 1;
1587 624411d2 2023-07-08 jrick case 'q':
1588 624411d2 2023-07-08 jrick verbosity = -1;
1590 624411d2 2023-07-08 jrick case 'R':
1591 624411d2 2023-07-08 jrick error = got_pathlist_append(&wanted_refs,
1592 624411d2 2023-07-08 jrick optarg, NULL);
1593 624411d2 2023-07-08 jrick if (error)
1594 624411d2 2023-07-08 jrick return error;
1596 624411d2 2023-07-08 jrick case 'v':
1597 624411d2 2023-07-08 jrick if (verbosity < 0)
1598 624411d2 2023-07-08 jrick verbosity = 0;
1599 624411d2 2023-07-08 jrick else if (verbosity < 3)
1600 624411d2 2023-07-08 jrick verbosity++;
1603 624411d2 2023-07-08 jrick usage_clone();
1607 624411d2 2023-07-08 jrick argc -= optind;
1608 624411d2 2023-07-08 jrick argv += optind;
1610 624411d2 2023-07-08 jrick if (fetch_all_branches && !TAILQ_EMPTY(&wanted_branches))
1611 624411d2 2023-07-08 jrick option_conflict('a', 'b');
1612 624411d2 2023-07-08 jrick if (list_refs_only) {
1613 624411d2 2023-07-08 jrick if (!TAILQ_EMPTY(&wanted_branches))
1614 624411d2 2023-07-08 jrick option_conflict('l', 'b');
1615 624411d2 2023-07-08 jrick if (fetch_all_branches)
1616 624411d2 2023-07-08 jrick option_conflict('l', 'a');
1617 624411d2 2023-07-08 jrick if (mirror_references)
1618 624411d2 2023-07-08 jrick option_conflict('l', 'm');
1619 624411d2 2023-07-08 jrick if (!TAILQ_EMPTY(&wanted_refs))
1620 624411d2 2023-07-08 jrick option_conflict('l', 'R');
1623 624411d2 2023-07-08 jrick uri = argv[0];
1625 624411d2 2023-07-08 jrick if (argc == 1)
1626 624411d2 2023-07-08 jrick dirname = NULL;
1627 624411d2 2023-07-08 jrick else if (argc == 2)
1628 624411d2 2023-07-08 jrick dirname = argv[1];
1630 624411d2 2023-07-08 jrick usage_clone();
1632 624411d2 2023-07-08 jrick error = got_dial_parse_uri(&proto, &host, &port, &server_path,
1633 624411d2 2023-07-08 jrick &repo_name, uri);
1634 624411d2 2023-07-08 jrick if (error)
1635 624411d2 2023-07-08 jrick goto done;
1637 624411d2 2023-07-08 jrick if (asprintf(&git_url, "%s://%s%s%s%s%s", proto,
1638 624411d2 2023-07-08 jrick host, port ? ":" : "", port ? port : "",
1639 624411d2 2023-07-08 jrick server_path[0] != '/' ? "/" : "", server_path) == -1) {
1640 624411d2 2023-07-08 jrick error = got_error_from_errno("asprintf");
1641 624411d2 2023-07-08 jrick goto done;
1644 624411d2 2023-07-08 jrick if (strcmp(proto, "git") == 0) {
1645 624411d2 2023-07-08 jrick #ifndef PROFILE
1646 624411d2 2023-07-08 jrick if (pledge("stdio rpath wpath cpath fattr flock proc exec "
1647 624411d2 2023-07-08 jrick "sendfd dns inet unveil", NULL) == -1)
1648 624411d2 2023-07-08 jrick err(1, "pledge");
1650 624411d2 2023-07-08 jrick } else if (strcmp(proto, "git+ssh") == 0 ||
1651 624411d2 2023-07-08 jrick strcmp(proto, "ssh") == 0) {
1652 624411d2 2023-07-08 jrick #ifndef PROFILE
1653 624411d2 2023-07-08 jrick if (pledge("stdio rpath wpath cpath fattr flock proc exec "
1654 624411d2 2023-07-08 jrick "sendfd unveil", NULL) == -1)
1655 624411d2 2023-07-08 jrick err(1, "pledge");
1657 624411d2 2023-07-08 jrick } else if (strcmp(proto, "http") == 0 ||
1658 624411d2 2023-07-08 jrick strcmp(proto, "git+http") == 0) {
1659 624411d2 2023-07-08 jrick error = got_error_path(proto, GOT_ERR_NOT_IMPL);
1660 624411d2 2023-07-08 jrick goto done;
1662 624411d2 2023-07-08 jrick error = got_error_path(proto, GOT_ERR_BAD_PROTO);
1663 624411d2 2023-07-08 jrick goto done;
1665 624411d2 2023-07-08 jrick if (dirname == NULL) {
1666 624411d2 2023-07-08 jrick if (asprintf(&default_destdir, "%s.git", repo_name) == -1) {
1667 624411d2 2023-07-08 jrick error = got_error_from_errno("asprintf");
1668 624411d2 2023-07-08 jrick goto done;
1670 624411d2 2023-07-08 jrick repo_path = default_destdir;
1672 624411d2 2023-07-08 jrick repo_path = dirname;
1674 624411d2 2023-07-08 jrick if (!list_refs_only) {
1675 624411d2 2023-07-08 jrick error = got_path_mkdir(repo_path);
1676 624411d2 2023-07-08 jrick if (error &&
1677 624411d2 2023-07-08 jrick (!(error->code == GOT_ERR_ERRNO && errno == EISDIR) &&
1678 624411d2 2023-07-08 jrick !(error->code == GOT_ERR_ERRNO && errno == EEXIST)))
1679 624411d2 2023-07-08 jrick goto done;
1680 624411d2 2023-07-08 jrick if (!got_path_dir_is_empty(repo_path)) {
1681 624411d2 2023-07-08 jrick error = got_error_path(repo_path,
1682 624411d2 2023-07-08 jrick GOT_ERR_DIR_NOT_EMPTY);
1683 624411d2 2023-07-08 jrick goto done;
1687 624411d2 2023-07-08 jrick error = got_dial_apply_unveil(proto);
1688 624411d2 2023-07-08 jrick if (error)
1689 624411d2 2023-07-08 jrick goto done;
1691 624411d2 2023-07-08 jrick error = apply_unveil(repo_path, 0, NULL);
1692 624411d2 2023-07-08 jrick if (error)
1693 624411d2 2023-07-08 jrick goto done;
1695 624411d2 2023-07-08 jrick if (verbosity >= 0)
1696 624411d2 2023-07-08 jrick printf("Connecting to %s\n", git_url);
1698 624411d2 2023-07-08 jrick error = got_fetch_connect(&fetchpid, &fetchfd, proto, host, port,
1699 624411d2 2023-07-08 jrick server_path, verbosity);
1700 624411d2 2023-07-08 jrick if (error)
1701 624411d2 2023-07-08 jrick goto done;
1703 624411d2 2023-07-08 jrick if (!list_refs_only) {
1704 624411d2 2023-07-08 jrick error = got_repo_init(repo_path, NULL);
1705 624411d2 2023-07-08 jrick if (error)
1706 624411d2 2023-07-08 jrick goto done;
1707 624411d2 2023-07-08 jrick error = got_repo_pack_fds_open(&pack_fds);
1708 624411d2 2023-07-08 jrick if (error != NULL)
1709 624411d2 2023-07-08 jrick goto done;
1710 624411d2 2023-07-08 jrick error = got_repo_open(&repo, repo_path, NULL, pack_fds);
1711 624411d2 2023-07-08 jrick if (error)
1712 624411d2 2023-07-08 jrick goto done;
1715 624411d2 2023-07-08 jrick fpa.last_scaled_size[0] = '\0';
1716 624411d2 2023-07-08 jrick fpa.last_p_indexed = -1;
1717 624411d2 2023-07-08 jrick fpa.last_p_resolved = -1;
1718 624411d2 2023-07-08 jrick fpa.verbosity = verbosity;
1719 624411d2 2023-07-08 jrick fpa.create_configs = 1;
1720 624411d2 2023-07-08 jrick fpa.configs_created = 0;
1721 624411d2 2023-07-08 jrick fpa.repo = repo;
1722 624411d2 2023-07-08 jrick fpa.config_info.symrefs = &symrefs;
1723 624411d2 2023-07-08 jrick fpa.config_info.wanted_branches = &wanted_branches;
1724 624411d2 2023-07-08 jrick fpa.config_info.wanted_refs = &wanted_refs;
1725 624411d2 2023-07-08 jrick fpa.config_info.proto = proto;
1726 624411d2 2023-07-08 jrick fpa.config_info.host = host;
1727 624411d2 2023-07-08 jrick fpa.config_info.port = port;
1728 624411d2 2023-07-08 jrick fpa.config_info.remote_repo_path = server_path;
1729 624411d2 2023-07-08 jrick fpa.config_info.git_url = git_url;
1730 624411d2 2023-07-08 jrick fpa.config_info.fetch_all_branches = fetch_all_branches;
1731 624411d2 2023-07-08 jrick fpa.config_info.mirror_references = mirror_references;
1732 624411d2 2023-07-08 jrick error = got_fetch_pack(&pack_hash, &refs, &symrefs,
1733 624411d2 2023-07-08 jrick GOT_FETCH_DEFAULT_REMOTE_NAME, mirror_references,
1734 624411d2 2023-07-08 jrick fetch_all_branches, &wanted_branches, &wanted_refs,
1735 624411d2 2023-07-08 jrick list_refs_only, verbosity, fetchfd, repo, NULL, NULL, bflag,
1736 624411d2 2023-07-08 jrick fetch_progress, &fpa);
1737 624411d2 2023-07-08 jrick if (error)
1738 624411d2 2023-07-08 jrick goto done;
1740 624411d2 2023-07-08 jrick if (list_refs_only) {
1741 624411d2 2023-07-08 jrick error = list_remote_refs(&symrefs, &refs);
1742 624411d2 2023-07-08 jrick goto done;
1745 624411d2 2023-07-08 jrick if (pack_hash == NULL) {
1746 624411d2 2023-07-08 jrick error = got_error_fmt(GOT_ERR_FETCH_FAILED, "%s",
1747 624411d2 2023-07-08 jrick "server sent an empty pack file");
1748 624411d2 2023-07-08 jrick goto done;
1750 624411d2 2023-07-08 jrick error = got_object_id_str(&id_str, pack_hash);
1751 624411d2 2023-07-08 jrick if (error)
1752 624411d2 2023-07-08 jrick goto done;
1753 624411d2 2023-07-08 jrick if (verbosity >= 0)
1754 624411d2 2023-07-08 jrick printf("\nFetched %s.pack\n", id_str);
1755 624411d2 2023-07-08 jrick free(id_str);
1757 624411d2 2023-07-08 jrick /* Set up references provided with the pack file. */
1758 624411d2 2023-07-08 jrick TAILQ_FOREACH(pe, &refs, entry) {
1759 624411d2 2023-07-08 jrick const char *refname = pe->path;
1760 624411d2 2023-07-08 jrick struct got_object_id *id = pe->data;
1761 624411d2 2023-07-08 jrick char *remote_refname;
1763 624411d2 2023-07-08 jrick if (is_wanted_ref(&wanted_refs, refname) &&
1764 624411d2 2023-07-08 jrick !mirror_references) {
1765 624411d2 2023-07-08 jrick error = create_wanted_ref(refname, id,
1766 624411d2 2023-07-08 jrick GOT_FETCH_DEFAULT_REMOTE_NAME,
1767 624411d2 2023-07-08 jrick verbosity - 1, repo);
1768 624411d2 2023-07-08 jrick if (error)
1769 624411d2 2023-07-08 jrick goto done;
1770 624411d2 2023-07-08 jrick continue;
1773 624411d2 2023-07-08 jrick error = create_ref(refname, id, verbosity - 1, repo);
1774 624411d2 2023-07-08 jrick if (error)
1775 624411d2 2023-07-08 jrick goto done;
1777 624411d2 2023-07-08 jrick if (mirror_references)
1778 624411d2 2023-07-08 jrick continue;
1780 624411d2 2023-07-08 jrick if (strncmp("refs/heads/", refname, 11) != 0)
1781 624411d2 2023-07-08 jrick continue;
1783 624411d2 2023-07-08 jrick if (asprintf(&remote_refname,
1784 624411d2 2023-07-08 jrick "refs/remotes/%s/%s", GOT_FETCH_DEFAULT_REMOTE_NAME,
1785 624411d2 2023-07-08 jrick refname + 11) == -1) {
1786 624411d2 2023-07-08 jrick error = got_error_from_errno("asprintf");
1787 624411d2 2023-07-08 jrick goto done;
1789 624411d2 2023-07-08 jrick error = create_ref(remote_refname, id, verbosity - 1, repo);
1790 624411d2 2023-07-08 jrick free(remote_refname);
1791 624411d2 2023-07-08 jrick if (error)
1792 624411d2 2023-07-08 jrick goto done;
1795 624411d2 2023-07-08 jrick /* Set the HEAD reference if the server provided one. */
1796 624411d2 2023-07-08 jrick TAILQ_FOREACH(pe, &symrefs, entry) {
1797 624411d2 2023-07-08 jrick struct got_reference *target_ref;
1798 624411d2 2023-07-08 jrick const char *refname = pe->path;
1799 624411d2 2023-07-08 jrick const char *target = pe->data;
1800 624411d2 2023-07-08 jrick char *remote_refname = NULL, *remote_target = NULL;
1802 624411d2 2023-07-08 jrick if (strcmp(refname, GOT_REF_HEAD) != 0)
1803 624411d2 2023-07-08 jrick continue;
1805 624411d2 2023-07-08 jrick error = got_ref_open(&target_ref, repo, target, 0);
1806 624411d2 2023-07-08 jrick if (error) {
1807 624411d2 2023-07-08 jrick if (error->code == GOT_ERR_NOT_REF) {
1808 624411d2 2023-07-08 jrick error = NULL;
1809 624411d2 2023-07-08 jrick continue;
1811 624411d2 2023-07-08 jrick goto done;
1814 624411d2 2023-07-08 jrick error = create_symref(refname, target_ref, verbosity, repo);
1815 624411d2 2023-07-08 jrick got_ref_close(target_ref);
1816 624411d2 2023-07-08 jrick if (error)
1817 624411d2 2023-07-08 jrick goto done;
1819 624411d2 2023-07-08 jrick if (mirror_references)
1820 624411d2 2023-07-08 jrick continue;
1822 624411d2 2023-07-08 jrick if (strncmp("refs/heads/", target, 11) != 0)
1823 624411d2 2023-07-08 jrick continue;
1825 624411d2 2023-07-08 jrick if (asprintf(&remote_refname,
1826 624411d2 2023-07-08 jrick "refs/remotes/%s/%s", GOT_FETCH_DEFAULT_REMOTE_NAME,
1827 624411d2 2023-07-08 jrick refname) == -1) {
1828 624411d2 2023-07-08 jrick error = got_error_from_errno("asprintf");
1829 624411d2 2023-07-08 jrick goto done;
1831 624411d2 2023-07-08 jrick if (asprintf(&remote_target,
1832 624411d2 2023-07-08 jrick "refs/remotes/%s/%s", GOT_FETCH_DEFAULT_REMOTE_NAME,
1833 624411d2 2023-07-08 jrick target + 11) == -1) {
1834 624411d2 2023-07-08 jrick error = got_error_from_errno("asprintf");
1835 624411d2 2023-07-08 jrick free(remote_refname);
1836 624411d2 2023-07-08 jrick goto done;
1838 624411d2 2023-07-08 jrick error = got_ref_open(&target_ref, repo, remote_target, 0);
1839 624411d2 2023-07-08 jrick if (error) {
1840 624411d2 2023-07-08 jrick free(remote_refname);
1841 624411d2 2023-07-08 jrick free(remote_target);
1842 624411d2 2023-07-08 jrick if (error->code == GOT_ERR_NOT_REF) {
1843 624411d2 2023-07-08 jrick error = NULL;
1844 624411d2 2023-07-08 jrick continue;
1846 624411d2 2023-07-08 jrick goto done;
1848 624411d2 2023-07-08 jrick error = create_symref(remote_refname, target_ref,
1849 624411d2 2023-07-08 jrick verbosity - 1, repo);
1850 624411d2 2023-07-08 jrick free(remote_refname);
1851 624411d2 2023-07-08 jrick free(remote_target);
1852 624411d2 2023-07-08 jrick got_ref_close(target_ref);
1853 624411d2 2023-07-08 jrick if (error)
1854 624411d2 2023-07-08 jrick goto done;
1856 624411d2 2023-07-08 jrick if (pe == NULL) {
1858 624411d2 2023-07-08 jrick * We failed to set the HEAD reference. If we asked for
1859 624411d2 2023-07-08 jrick * a set of wanted branches use the first of one of those
1860 624411d2 2023-07-08 jrick * which could be fetched instead.
1862 624411d2 2023-07-08 jrick TAILQ_FOREACH(pe, &wanted_branches, entry) {
1863 624411d2 2023-07-08 jrick const char *target = pe->path;
1864 624411d2 2023-07-08 jrick struct got_reference *target_ref;
1866 624411d2 2023-07-08 jrick error = got_ref_open(&target_ref, repo, target, 0);
1867 624411d2 2023-07-08 jrick if (error) {
1868 624411d2 2023-07-08 jrick if (error->code == GOT_ERR_NOT_REF) {
1869 624411d2 2023-07-08 jrick error = NULL;
1870 624411d2 2023-07-08 jrick continue;
1872 624411d2 2023-07-08 jrick goto done;
1875 624411d2 2023-07-08 jrick error = create_symref(GOT_REF_HEAD, target_ref,
1876 624411d2 2023-07-08 jrick verbosity, repo);
1877 624411d2 2023-07-08 jrick got_ref_close(target_ref);
1878 624411d2 2023-07-08 jrick if (error)
1879 624411d2 2023-07-08 jrick goto done;
1883 624411d2 2023-07-08 jrick if (!fpa.configs_created && pe != NULL) {
1884 624411d2 2023-07-08 jrick error = create_config_files(fpa.config_info.proto,
1885 624411d2 2023-07-08 jrick fpa.config_info.host, fpa.config_info.port,
1886 624411d2 2023-07-08 jrick fpa.config_info.remote_repo_path,
1887 624411d2 2023-07-08 jrick fpa.config_info.git_url,
1888 624411d2 2023-07-08 jrick fpa.config_info.fetch_all_branches,
1889 624411d2 2023-07-08 jrick fpa.config_info.mirror_references,
1890 624411d2 2023-07-08 jrick fpa.config_info.symrefs,
1891 624411d2 2023-07-08 jrick fpa.config_info.wanted_branches,
1892 624411d2 2023-07-08 jrick fpa.config_info.wanted_refs, fpa.repo);
1893 624411d2 2023-07-08 jrick if (error)
1894 624411d2 2023-07-08 jrick goto done;
1898 624411d2 2023-07-08 jrick if (verbosity >= 0)
1899 624411d2 2023-07-08 jrick printf("Created %s repository '%s'\n",
1900 624411d2 2023-07-08 jrick mirror_references ? "mirrored" : "cloned", repo_path);
1902 624411d2 2023-07-08 jrick if (pack_fds) {
1903 624411d2 2023-07-08 jrick const struct got_error *pack_err =
1904 624411d2 2023-07-08 jrick got_repo_pack_fds_close(pack_fds);
1905 624411d2 2023-07-08 jrick if (error == NULL)
1906 624411d2 2023-07-08 jrick error = pack_err;
1908 624411d2 2023-07-08 jrick if (fetchpid > 0) {
1909 624411d2 2023-07-08 jrick if (kill(fetchpid, SIGTERM) == -1)
1910 624411d2 2023-07-08 jrick error = got_error_from_errno("kill");
1911 624411d2 2023-07-08 jrick if (waitpid(fetchpid, &fetchstatus, 0) == -1 && error == NULL)
1912 624411d2 2023-07-08 jrick error = got_error_from_errno("waitpid");
1914 624411d2 2023-07-08 jrick if (fetchfd != -1 && close(fetchfd) == -1 && error == NULL)
1915 624411d2 2023-07-08 jrick error = got_error_from_errno("close");
1916 624411d2 2023-07-08 jrick if (repo) {
1917 624411d2 2023-07-08 jrick const struct got_error *close_err = got_repo_close(repo);
1918 624411d2 2023-07-08 jrick if (error == NULL)
1919 624411d2 2023-07-08 jrick error = close_err;
1921 624411d2 2023-07-08 jrick got_pathlist_free(&refs, GOT_PATHLIST_FREE_ALL);
1922 624411d2 2023-07-08 jrick got_pathlist_free(&symrefs, GOT_PATHLIST_FREE_ALL);
1923 624411d2 2023-07-08 jrick got_pathlist_free(&wanted_branches, GOT_PATHLIST_FREE_NONE);
1924 624411d2 2023-07-08 jrick got_pathlist_free(&wanted_refs, GOT_PATHLIST_FREE_NONE);
1925 624411d2 2023-07-08 jrick free(pack_hash);
1926 624411d2 2023-07-08 jrick free(proto);
1927 624411d2 2023-07-08 jrick free(host);
1928 624411d2 2023-07-08 jrick free(port);
1929 624411d2 2023-07-08 jrick free(server_path);
1930 624411d2 2023-07-08 jrick free(repo_name);
1931 624411d2 2023-07-08 jrick free(default_destdir);
1932 624411d2 2023-07-08 jrick free(git_url);
1933 624411d2 2023-07-08 jrick return error;
1936 624411d2 2023-07-08 jrick static const struct got_error *
1937 624411d2 2023-07-08 jrick update_ref(struct got_reference *ref, struct got_object_id *new_id,
1938 624411d2 2023-07-08 jrick int replace_tags, int verbosity, struct got_repository *repo)
1940 624411d2 2023-07-08 jrick const struct got_error *err = NULL;
1941 624411d2 2023-07-08 jrick char *new_id_str = NULL;
1942 624411d2 2023-07-08 jrick struct got_object_id *old_id = NULL;
1944 624411d2 2023-07-08 jrick err = got_object_id_str(&new_id_str, new_id);
1946 624411d2 2023-07-08 jrick goto done;
1948 624411d2 2023-07-08 jrick if (!replace_tags &&
1949 624411d2 2023-07-08 jrick strncmp(got_ref_get_name(ref), "refs/tags/", 10) == 0) {
1950 624411d2 2023-07-08 jrick err = got_ref_resolve(&old_id, repo, ref);
1952 624411d2 2023-07-08 jrick goto done;
1953 624411d2 2023-07-08 jrick if (got_object_id_cmp(old_id, new_id) == 0)
1954 624411d2 2023-07-08 jrick goto done;
1955 624411d2 2023-07-08 jrick if (verbosity >= 0) {
1956 624411d2 2023-07-08 jrick printf("Rejecting update of existing tag %s: %s\n",
1957 624411d2 2023-07-08 jrick got_ref_get_name(ref), new_id_str);
1959 624411d2 2023-07-08 jrick goto done;
1962 624411d2 2023-07-08 jrick if (got_ref_is_symbolic(ref)) {
1963 624411d2 2023-07-08 jrick if (verbosity >= 0) {
1964 624411d2 2023-07-08 jrick printf("Replacing reference %s: %s\n",
1965 624411d2 2023-07-08 jrick got_ref_get_name(ref),
1966 624411d2 2023-07-08 jrick got_ref_get_symref_target(ref));
1968 624411d2 2023-07-08 jrick err = got_ref_change_symref_to_ref(ref, new_id);
1970 624411d2 2023-07-08 jrick goto done;
1971 624411d2 2023-07-08 jrick err = got_ref_write(ref, repo);
1973 624411d2 2023-07-08 jrick goto done;
1975 624411d2 2023-07-08 jrick err = got_ref_resolve(&old_id, repo, ref);
1977 624411d2 2023-07-08 jrick goto done;
1978 624411d2 2023-07-08 jrick if (got_object_id_cmp(old_id, new_id) == 0)
1979 624411d2 2023-07-08 jrick goto done;
1981 624411d2 2023-07-08 jrick err = got_ref_change_ref(ref, new_id);
1983 624411d2 2023-07-08 jrick goto done;
1984 624411d2 2023-07-08 jrick err = got_ref_write(ref, repo);
1986 624411d2 2023-07-08 jrick goto done;
1989 624411d2 2023-07-08 jrick if (verbosity >= 0)
1990 624411d2 2023-07-08 jrick printf("Updated %s: %s\n", got_ref_get_name(ref),
1991 624411d2 2023-07-08 jrick new_id_str);
1993 624411d2 2023-07-08 jrick free(old_id);
1994 624411d2 2023-07-08 jrick free(new_id_str);
1995 624411d2 2023-07-08 jrick return err;
1998 624411d2 2023-07-08 jrick static const struct got_error *
1999 624411d2 2023-07-08 jrick update_symref(const char *refname, struct got_reference *target_ref,
2000 624411d2 2023-07-08 jrick int verbosity, struct got_repository *repo)
2002 624411d2 2023-07-08 jrick const struct got_error *err = NULL, *unlock_err;
2003 624411d2 2023-07-08 jrick struct got_reference *symref;
2004 624411d2 2023-07-08 jrick int symref_is_locked = 0;
2006 624411d2 2023-07-08 jrick err = got_ref_open(&symref, repo, refname, 1);
2007 624411d2 2023-07-08 jrick if (err) {
2008 624411d2 2023-07-08 jrick if (err->code != GOT_ERR_NOT_REF)
2009 624411d2 2023-07-08 jrick return err;
2010 624411d2 2023-07-08 jrick err = got_ref_alloc_symref(&symref, refname, target_ref);
2012 624411d2 2023-07-08 jrick goto done;
2014 624411d2 2023-07-08 jrick err = got_ref_write(symref, repo);
2016 624411d2 2023-07-08 jrick goto done;
2018 624411d2 2023-07-08 jrick if (verbosity >= 0)
2019 624411d2 2023-07-08 jrick printf("Created reference %s: %s\n",
2020 624411d2 2023-07-08 jrick got_ref_get_name(symref),
2021 624411d2 2023-07-08 jrick got_ref_get_symref_target(symref));
2023 624411d2 2023-07-08 jrick symref_is_locked = 1;
2025 624411d2 2023-07-08 jrick if (strcmp(got_ref_get_symref_target(symref),
2026 624411d2 2023-07-08 jrick got_ref_get_name(target_ref)) == 0)
2027 624411d2 2023-07-08 jrick goto done;
2029 624411d2 2023-07-08 jrick err = got_ref_change_symref(symref,
2030 624411d2 2023-07-08 jrick got_ref_get_name(target_ref));
2032 624411d2 2023-07-08 jrick goto done;
2034 624411d2 2023-07-08 jrick err = got_ref_write(symref, repo);
2036 624411d2 2023-07-08 jrick goto done;
2038 624411d2 2023-07-08 jrick if (verbosity >= 0)
2039 624411d2 2023-07-08 jrick printf("Updated %s: %s\n", got_ref_get_name(symref),
2040 624411d2 2023-07-08 jrick got_ref_get_symref_target(symref));
2044 624411d2 2023-07-08 jrick if (symref_is_locked) {
2045 624411d2 2023-07-08 jrick unlock_err = got_ref_unlock(symref);
2046 624411d2 2023-07-08 jrick if (unlock_err && err == NULL)
2047 624411d2 2023-07-08 jrick err = unlock_err;
2049 624411d2 2023-07-08 jrick got_ref_close(symref);
2050 624411d2 2023-07-08 jrick return err;
2053 624411d2 2023-07-08 jrick __dead static void
2054 624411d2 2023-07-08 jrick usage_fetch(void)
2056 624411d2 2023-07-08 jrick fprintf(stderr, "usage: %s fetch [-adlqtvX] [-b branch] "
2057 624411d2 2023-07-08 jrick "[-R reference] [-r repository-path] [remote-repository]\n",
2058 624411d2 2023-07-08 jrick getprogname());
2062 624411d2 2023-07-08 jrick static const struct got_error *
2063 624411d2 2023-07-08 jrick delete_missing_ref(struct got_reference *ref,
2064 624411d2 2023-07-08 jrick int verbosity, struct got_repository *repo)
2066 624411d2 2023-07-08 jrick const struct got_error *err = NULL;
2067 624411d2 2023-07-08 jrick struct got_object_id *id = NULL;
2068 624411d2 2023-07-08 jrick char *id_str = NULL;
2070 624411d2 2023-07-08 jrick if (got_ref_is_symbolic(ref)) {
2071 624411d2 2023-07-08 jrick err = got_ref_delete(ref, repo);
2073 624411d2 2023-07-08 jrick return err;
2074 624411d2 2023-07-08 jrick if (verbosity >= 0) {
2075 624411d2 2023-07-08 jrick printf("Deleted %s: %s\n",
2076 624411d2 2023-07-08 jrick got_ref_get_name(ref),
2077 624411d2 2023-07-08 jrick got_ref_get_symref_target(ref));
2080 624411d2 2023-07-08 jrick err = got_ref_resolve(&id, repo, ref);
2082 624411d2 2023-07-08 jrick return err;
2083 624411d2 2023-07-08 jrick err = got_object_id_str(&id_str, id);
2085 624411d2 2023-07-08 jrick goto done;
2087 624411d2 2023-07-08 jrick err = got_ref_delete(ref, repo);
2089 624411d2 2023-07-08 jrick goto done;
2090 624411d2 2023-07-08 jrick if (verbosity >= 0) {
2091 624411d2 2023-07-08 jrick printf("Deleted %s: %s\n",
2092 624411d2 2023-07-08 jrick got_ref_get_name(ref), id_str);
2096 624411d2 2023-07-08 jrick free(id);
2097 624411d2 2023-07-08 jrick free(id_str);
2098 624411d2 2023-07-08 jrick return err;
2101 624411d2 2023-07-08 jrick static const struct got_error *
2102 624411d2 2023-07-08 jrick delete_missing_refs(struct got_pathlist_head *their_refs,
2103 624411d2 2023-07-08 jrick struct got_pathlist_head *their_symrefs,
2104 624411d2 2023-07-08 jrick const struct got_remote_repo *remote,
2105 624411d2 2023-07-08 jrick int verbosity, struct got_repository *repo)
2107 624411d2 2023-07-08 jrick const struct got_error *err = NULL, *unlock_err;
2108 624411d2 2023-07-08 jrick struct got_reflist_head my_refs;
2109 624411d2 2023-07-08 jrick struct got_reflist_entry *re;
2110 624411d2 2023-07-08 jrick struct got_pathlist_entry *pe;
2111 624411d2 2023-07-08 jrick char *remote_namespace = NULL;
2112 624411d2 2023-07-08 jrick char *local_refname = NULL;
2114 624411d2 2023-07-08 jrick TAILQ_INIT(&my_refs);
2116 624411d2 2023-07-08 jrick if (asprintf(&remote_namespace, "refs/remotes/%s/", remote->name)
2118 624411d2 2023-07-08 jrick return got_error_from_errno("asprintf");
2120 624411d2 2023-07-08 jrick err = got_ref_list(&my_refs, repo, NULL, got_ref_cmp_by_name, NULL);
2122 624411d2 2023-07-08 jrick goto done;
2124 624411d2 2023-07-08 jrick TAILQ_FOREACH(re, &my_refs, entry) {
2125 624411d2 2023-07-08 jrick const char *refname = got_ref_get_name(re->ref);
2126 624411d2 2023-07-08 jrick const char *their_refname;
2128 624411d2 2023-07-08 jrick if (remote->mirror_references) {
2129 624411d2 2023-07-08 jrick their_refname = refname;
2131 624411d2 2023-07-08 jrick if (strncmp(refname, remote_namespace,
2132 624411d2 2023-07-08 jrick strlen(remote_namespace)) == 0) {
2133 624411d2 2023-07-08 jrick if (strcmp(refname + strlen(remote_namespace),
2134 624411d2 2023-07-08 jrick GOT_REF_HEAD) == 0)
2135 624411d2 2023-07-08 jrick continue;
2136 624411d2 2023-07-08 jrick if (asprintf(&local_refname, "refs/heads/%s",
2137 624411d2 2023-07-08 jrick refname + strlen(remote_namespace)) == -1) {
2138 624411d2 2023-07-08 jrick err = got_error_from_errno("asprintf");
2139 624411d2 2023-07-08 jrick goto done;
2141 624411d2 2023-07-08 jrick } else if (strncmp(refname, "refs/tags/", 10) != 0)
2142 624411d2 2023-07-08 jrick continue;
2144 624411d2 2023-07-08 jrick their_refname = local_refname;
2147 624411d2 2023-07-08 jrick TAILQ_FOREACH(pe, their_refs, entry) {
2148 624411d2 2023-07-08 jrick if (strcmp(their_refname, pe->path) == 0)
2151 624411d2 2023-07-08 jrick if (pe != NULL)
2152 624411d2 2023-07-08 jrick continue;
2154 624411d2 2023-07-08 jrick TAILQ_FOREACH(pe, their_symrefs, entry) {
2155 624411d2 2023-07-08 jrick if (strcmp(their_refname, pe->path) == 0)
2158 624411d2 2023-07-08 jrick if (pe != NULL)
2159 624411d2 2023-07-08 jrick continue;
2161 624411d2 2023-07-08 jrick err = delete_missing_ref(re->ref, verbosity, repo);
2165 624411d2 2023-07-08 jrick if (local_refname) {
2166 624411d2 2023-07-08 jrick struct got_reference *ref;
2167 624411d2 2023-07-08 jrick err = got_ref_open(&ref, repo, local_refname, 1);
2168 624411d2 2023-07-08 jrick if (err) {
2169 624411d2 2023-07-08 jrick if (err->code != GOT_ERR_NOT_REF)
2171 624411d2 2023-07-08 jrick free(local_refname);
2172 624411d2 2023-07-08 jrick local_refname = NULL;
2173 624411d2 2023-07-08 jrick continue;
2175 624411d2 2023-07-08 jrick err = delete_missing_ref(ref, verbosity, repo);
2178 624411d2 2023-07-08 jrick unlock_err = got_ref_unlock(ref);
2179 624411d2 2023-07-08 jrick got_ref_close(ref);
2180 624411d2 2023-07-08 jrick if (unlock_err && err == NULL) {
2181 624411d2 2023-07-08 jrick err = unlock_err;
2185 624411d2 2023-07-08 jrick free(local_refname);
2186 624411d2 2023-07-08 jrick local_refname = NULL;
2190 624411d2 2023-07-08 jrick got_ref_list_free(&my_refs);
2191 624411d2 2023-07-08 jrick free(remote_namespace);
2192 624411d2 2023-07-08 jrick free(local_refname);
2193 624411d2 2023-07-08 jrick return err;
2196 624411d2 2023-07-08 jrick static const struct got_error *
2197 624411d2 2023-07-08 jrick update_wanted_ref(const char *refname, struct got_object_id *id,
2198 624411d2 2023-07-08 jrick const char *remote_repo_name, int verbosity, struct got_repository *repo)
2200 624411d2 2023-07-08 jrick const struct got_error *err, *unlock_err;
2201 624411d2 2023-07-08 jrick char *remote_refname;
2202 624411d2 2023-07-08 jrick struct got_reference *ref;
2204 624411d2 2023-07-08 jrick if (strncmp("refs/", refname, 5) == 0)
2205 624411d2 2023-07-08 jrick refname += 5;
2207 624411d2 2023-07-08 jrick if (asprintf(&remote_refname, "refs/remotes/%s/%s",
2208 624411d2 2023-07-08 jrick remote_repo_name, refname) == -1)
2209 624411d2 2023-07-08 jrick return got_error_from_errno("asprintf");
2211 624411d2 2023-07-08 jrick err = got_ref_open(&ref, repo, remote_refname, 1);
2212 624411d2 2023-07-08 jrick if (err) {
2213 624411d2 2023-07-08 jrick if (err->code != GOT_ERR_NOT_REF)
2214 624411d2 2023-07-08 jrick goto done;
2215 624411d2 2023-07-08 jrick err = create_ref(remote_refname, id, verbosity, repo);
2217 624411d2 2023-07-08 jrick err = update_ref(ref, id, 0, verbosity, repo);
2218 624411d2 2023-07-08 jrick unlock_err = got_ref_unlock(ref);
2219 624411d2 2023-07-08 jrick if (unlock_err && err == NULL)
2220 624411d2 2023-07-08 jrick err = unlock_err;
2221 624411d2 2023-07-08 jrick got_ref_close(ref);
2224 624411d2 2023-07-08 jrick free(remote_refname);
2225 624411d2 2023-07-08 jrick return err;
2228 624411d2 2023-07-08 jrick static const struct got_error *
2229 624411d2 2023-07-08 jrick delete_ref(struct got_repository *repo, struct got_reference *ref)
2231 624411d2 2023-07-08 jrick const struct got_error *err = NULL;
2232 624411d2 2023-07-08 jrick struct got_object_id *id = NULL;
2233 624411d2 2023-07-08 jrick char *id_str = NULL;
2234 624411d2 2023-07-08 jrick const char *target;
2236 624411d2 2023-07-08 jrick if (got_ref_is_symbolic(ref)) {
2237 624411d2 2023-07-08 jrick target = got_ref_get_symref_target(ref);
2239 624411d2 2023-07-08 jrick err = got_ref_resolve(&id, repo, ref);
2241 624411d2 2023-07-08 jrick goto done;
2242 624411d2 2023-07-08 jrick err = got_object_id_str(&id_str, id);
2244 624411d2 2023-07-08 jrick goto done;
2245 624411d2 2023-07-08 jrick target = id_str;
2248 624411d2 2023-07-08 jrick err = got_ref_delete(ref, repo);
2250 624411d2 2023-07-08 jrick goto done;
2252 624411d2 2023-07-08 jrick printf("Deleted %s: %s\n", got_ref_get_name(ref), target);
2254 624411d2 2023-07-08 jrick free(id);
2255 624411d2 2023-07-08 jrick free(id_str);
2256 624411d2 2023-07-08 jrick return err;
2259 624411d2 2023-07-08 jrick static const struct got_error *
2260 624411d2 2023-07-08 jrick delete_refs_for_remote(struct got_repository *repo, const char *remote_name)
2262 624411d2 2023-07-08 jrick const struct got_error *err = NULL;
2263 624411d2 2023-07-08 jrick struct got_reflist_head refs;
2264 624411d2 2023-07-08 jrick struct got_reflist_entry *re;
2265 624411d2 2023-07-08 jrick char *prefix;
2267 624411d2 2023-07-08 jrick TAILQ_INIT(&refs);
2269 624411d2 2023-07-08 jrick if (asprintf(&prefix, "refs/remotes/%s", remote_name) == -1) {
2270 624411d2 2023-07-08 jrick err = got_error_from_errno("asprintf");
2271 624411d2 2023-07-08 jrick goto done;
2273 624411d2 2023-07-08 jrick err = got_ref_list(&refs, repo, prefix, got_ref_cmp_by_name, NULL);
2275 624411d2 2023-07-08 jrick goto done;
2277 624411d2 2023-07-08 jrick TAILQ_FOREACH(re, &refs, entry)
2278 624411d2 2023-07-08 jrick delete_ref(repo, re->ref);
2280 624411d2 2023-07-08 jrick got_ref_list_free(&refs);
2281 624411d2 2023-07-08 jrick return err;
2286 624411d2 2023-07-08 jrick __dead static void
2287 624411d2 2023-07-08 jrick usage_checkout(void)
2289 624411d2 2023-07-08 jrick fprintf(stderr, "usage: %s checkout [-Eq] [-b branch] [-c commit] "
2290 624411d2 2023-07-08 jrick "[-p path-prefix] repository-path [work-tree-path]\n",
2291 624411d2 2023-07-08 jrick getprogname());
2295 624411d2 2023-07-08 jrick static void
2296 624411d2 2023-07-08 jrick show_worktree_base_ref_warning(void)
2298 624411d2 2023-07-08 jrick fprintf(stderr, "%s: warning: could not create a reference "
2299 624411d2 2023-07-08 jrick "to the work tree's base commit; the commit could be "
2300 624411d2 2023-07-08 jrick "garbage-collected by Git or 'gotadmin cleanup'; making the "
2301 624411d2 2023-07-08 jrick "repository writable and running 'got update' will prevent this\n",
2302 624411d2 2023-07-08 jrick getprogname());
2305 624411d2 2023-07-08 jrick struct got_checkout_progress_arg {
2306 624411d2 2023-07-08 jrick const char *worktree_path;
2307 624411d2 2023-07-08 jrick int had_base_commit_ref_error;
2308 624411d2 2023-07-08 jrick int verbosity;
2311 624411d2 2023-07-08 jrick static const struct got_error *
2312 624411d2 2023-07-08 jrick checkout_progress(void *arg, unsigned char status, const char *path)
2314 624411d2 2023-07-08 jrick struct got_checkout_progress_arg *a = arg;
2316 624411d2 2023-07-08 jrick /* Base commit bump happens silently. */
2317 624411d2 2023-07-08 jrick if (status == GOT_STATUS_BUMP_BASE)
2318 624411d2 2023-07-08 jrick return NULL;
2320 624411d2 2023-07-08 jrick if (status == GOT_STATUS_BASE_REF_ERR) {
2321 624411d2 2023-07-08 jrick a->had_base_commit_ref_error = 1;
2322 624411d2 2023-07-08 jrick return NULL;
2325 624411d2 2023-07-08 jrick while (path[0] == '/')
2328 624411d2 2023-07-08 jrick if (a->verbosity >= 0)
2329 624411d2 2023-07-08 jrick printf("%c %s/%s\n", status, a->worktree_path, path);
2331 624411d2 2023-07-08 jrick return NULL;
2334 624411d2 2023-07-08 jrick static const struct got_error *
2335 624411d2 2023-07-08 jrick check_cancelled(void *arg)
2337 624411d2 2023-07-08 jrick if (sigint_received || sigpipe_received)
2338 624411d2 2023-07-08 jrick return got_error(GOT_ERR_CANCELLED);
2339 624411d2 2023-07-08 jrick return NULL;
2342 624411d2 2023-07-08 jrick static const struct got_error *
2343 624411d2 2023-07-08 jrick check_linear_ancestry(struct got_object_id *commit_id,
2344 624411d2 2023-07-08 jrick struct got_object_id *base_commit_id, int allow_forwards_in_time_only,
2345 624411d2 2023-07-08 jrick struct got_repository *repo)
2347 624411d2 2023-07-08 jrick const struct got_error *err = NULL;
2348 624411d2 2023-07-08 jrick struct got_object_id *yca_id;
2350 624411d2 2023-07-08 jrick err = got_commit_graph_find_youngest_common_ancestor(&yca_id,
2351 624411d2 2023-07-08 jrick commit_id, base_commit_id, 1, repo, check_cancelled, NULL);
2353 624411d2 2023-07-08 jrick return err;
2355 624411d2 2023-07-08 jrick if (yca_id == NULL)
2356 624411d2 2023-07-08 jrick return got_error(GOT_ERR_ANCESTRY);
2359 624411d2 2023-07-08 jrick * Require a straight line of history between the target commit
2360 624411d2 2023-07-08 jrick * and the work tree's base commit.
2362 624411d2 2023-07-08 jrick * Non-linear situations such as this require a rebase:
2364 624411d2 2023-07-08 jrick * (commit) D F (base_commit)
2368 624411d2 2023-07-08 jrick * B (yca)
2372 624411d2 2023-07-08 jrick * 'got update' only handles linear cases:
2373 624411d2 2023-07-08 jrick * Update forwards in time: A (base/yca) - B - C - D (commit)
2374 624411d2 2023-07-08 jrick * Update backwards in time: D (base) - C - B - A (commit/yca)
2376 624411d2 2023-07-08 jrick if (allow_forwards_in_time_only) {
2377 624411d2 2023-07-08 jrick if (got_object_id_cmp(base_commit_id, yca_id) != 0)
2378 624411d2 2023-07-08 jrick return got_error(GOT_ERR_ANCESTRY);
2379 624411d2 2023-07-08 jrick } else if (got_object_id_cmp(commit_id, yca_id) != 0 &&
2380 624411d2 2023-07-08 jrick got_object_id_cmp(base_commit_id, yca_id) != 0)
2381 624411d2 2023-07-08 jrick return got_error(GOT_ERR_ANCESTRY);
2383 624411d2 2023-07-08 jrick free(yca_id);
2384 624411d2 2023-07-08 jrick return NULL;
2387 624411d2 2023-07-08 jrick static const struct got_error *
2388 624411d2 2023-07-08 jrick check_same_branch(struct got_object_id *commit_id,
2389 624411d2 2023-07-08 jrick struct got_reference *head_ref, struct got_repository *repo)
2391 624411d2 2023-07-08 jrick const struct got_error *err = NULL;
2392 624411d2 2023-07-08 jrick struct got_commit_graph *graph = NULL;
2393 624411d2 2023-07-08 jrick struct got_object_id *head_commit_id = NULL;
2395 624411d2 2023-07-08 jrick err = got_ref_resolve(&head_commit_id, repo, head_ref);
2397 624411d2 2023-07-08 jrick goto done;
2399 624411d2 2023-07-08 jrick if (got_object_id_cmp(head_commit_id, commit_id) == 0)
2400 624411d2 2023-07-08 jrick goto done;
2402 624411d2 2023-07-08 jrick err = got_commit_graph_open(&graph, "/", 1);
2404 624411d2 2023-07-08 jrick goto done;
2406 624411d2 2023-07-08 jrick err = got_commit_graph_iter_start(graph, head_commit_id, repo,
2407 624411d2 2023-07-08 jrick check_cancelled, NULL);
2409 624411d2 2023-07-08 jrick goto done;
2411 624411d2 2023-07-08 jrick for (;;) {
2412 624411d2 2023-07-08 jrick struct got_object_id id;
2414 624411d2 2023-07-08 jrick err = got_commit_graph_iter_next(&id, graph, repo,
2415 624411d2 2023-07-08 jrick check_cancelled, NULL);
2416 624411d2 2023-07-08 jrick if (err) {
2417 624411d2 2023-07-08 jrick if (err->code == GOT_ERR_ITER_COMPLETED)
2418 624411d2 2023-07-08 jrick err = got_error(GOT_ERR_ANCESTRY);
2422 624411d2 2023-07-08 jrick if (got_object_id_cmp(&id, commit_id) == 0)
2426 624411d2 2023-07-08 jrick if (graph)
2427 624411d2 2023-07-08 jrick got_commit_graph_close(graph);
2428 624411d2 2023-07-08 jrick free(head_commit_id);
2429 624411d2 2023-07-08 jrick return err;
2432 624411d2 2023-07-08 jrick static const struct got_error *
2433 624411d2 2023-07-08 jrick checkout_ancestry_error(struct got_reference *ref, const char *commit_id_str)
2435 624411d2 2023-07-08 jrick static char msg[512];
2436 624411d2 2023-07-08 jrick const char *branch_name;
2438 624411d2 2023-07-08 jrick if (got_ref_is_symbolic(ref))
2439 624411d2 2023-07-08 jrick branch_name = got_ref_get_symref_target(ref);
2441 624411d2 2023-07-08 jrick branch_name = got_ref_get_name(ref);
2443 624411d2 2023-07-08 jrick if (strncmp("refs/heads/", branch_name, 11) == 0)
2444 624411d2 2023-07-08 jrick branch_name += 11;
2446 624411d2 2023-07-08 jrick snprintf(msg, sizeof(msg),
2447 624411d2 2023-07-08 jrick "target commit is not contained in branch '%s'; "
2448 624411d2 2023-07-08 jrick "the branch to use must be specified with -b; "
2449 624411d2 2023-07-08 jrick "if necessary a new branch can be created for "
2450 624411d2 2023-07-08 jrick "this commit with 'got branch -c %s BRANCH_NAME'",
2451 624411d2 2023-07-08 jrick branch_name, commit_id_str);
2453 624411d2 2023-07-08 jrick return got_error_msg(GOT_ERR_ANCESTRY, msg);
2456 624411d2 2023-07-08 jrick static const struct got_error *
2457 624411d2 2023-07-08 jrick cmd_checkout(int argc, char *argv[])
2459 624411d2 2023-07-08 jrick const struct got_error *error = NULL;
2460 624411d2 2023-07-08 jrick struct got_repository *repo = NULL;
2461 624411d2 2023-07-08 jrick struct got_reference *head_ref = NULL, *ref = NULL;
2462 624411d2 2023-07-08 jrick struct got_worktree *worktree = NULL;
2463 624411d2 2023-07-08 jrick char *repo_path = NULL;
2464 624411d2 2023-07-08 jrick char *worktree_path = NULL;
2465 624411d2 2023-07-08 jrick const char *path_prefix = "";
2466 624411d2 2023-07-08 jrick const char *branch_name = GOT_REF_HEAD, *refname = NULL;
2467 624411d2 2023-07-08 jrick char *commit_id_str = NULL;
2468 624411d2 2023-07-08 jrick struct got_object_id *commit_id = NULL;
2469 624411d2 2023-07-08 jrick char *cwd = NULL;
2470 624411d2 2023-07-08 jrick int ch, same_path_prefix, allow_nonempty = 0, verbosity = 0;
2471 624411d2 2023-07-08 jrick struct got_pathlist_head paths;
2472 624411d2 2023-07-08 jrick struct got_checkout_progress_arg cpa;
2473 624411d2 2023-07-08 jrick int *pack_fds = NULL;
2475 624411d2 2023-07-08 jrick TAILQ_INIT(&paths);
2477 624411d2 2023-07-08 jrick #ifndef PROFILE
2478 624411d2 2023-07-08 jrick if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd "
2479 624411d2 2023-07-08 jrick "unveil", NULL) == -1)
2480 624411d2 2023-07-08 jrick err(1, "pledge");
2483 624411d2 2023-07-08 jrick while ((ch = getopt(argc, argv, "b:c:Ep:q")) != -1) {
2484 624411d2 2023-07-08 jrick switch (ch) {
2485 624411d2 2023-07-08 jrick case 'b':
2486 624411d2 2023-07-08 jrick branch_name = optarg;
2488 624411d2 2023-07-08 jrick case 'c':
2489 624411d2 2023-07-08 jrick commit_id_str = strdup(optarg);
2490 624411d2 2023-07-08 jrick if (commit_id_str == NULL)
2491 624411d2 2023-07-08 jrick return got_error_from_errno("strdup");
2493 624411d2 2023-07-08 jrick case 'E':
2494 624411d2 2023-07-08 jrick allow_nonempty = 1;
2496 624411d2 2023-07-08 jrick case 'p':
2497 624411d2 2023-07-08 jrick path_prefix = optarg;
2499 624411d2 2023-07-08 jrick case 'q':
2500 624411d2 2023-07-08 jrick verbosity = -1;
2503 624411d2 2023-07-08 jrick usage_checkout();
2504 624411d2 2023-07-08 jrick /* NOTREACHED */
2508 624411d2 2023-07-08 jrick argc -= optind;
2509 624411d2 2023-07-08 jrick argv += optind;
2511 624411d2 2023-07-08 jrick if (argc == 1) {
2512 624411d2 2023-07-08 jrick char *base, *dotgit;
2513 624411d2 2023-07-08 jrick const char *path;
2514 624411d2 2023-07-08 jrick repo_path = realpath(argv[0], NULL);
2515 624411d2 2023-07-08 jrick if (repo_path == NULL)
2516 624411d2 2023-07-08 jrick return got_error_from_errno2("realpath", argv[0]);
2517 624411d2 2023-07-08 jrick cwd = getcwd(NULL, 0);
2518 624411d2 2023-07-08 jrick if (cwd == NULL) {
2519 624411d2 2023-07-08 jrick error = got_error_from_errno("getcwd");
2520 624411d2 2023-07-08 jrick goto done;
2522 624411d2 2023-07-08 jrick if (path_prefix[0])
2523 624411d2 2023-07-08 jrick path = path_prefix;
2525 624411d2 2023-07-08 jrick path = repo_path;
2526 624411d2 2023-07-08 jrick error = got_path_basename(&base, path);
2527 624411d2 2023-07-08 jrick if (error)
2528 624411d2 2023-07-08 jrick goto done;
2529 624411d2 2023-07-08 jrick dotgit = strstr(base, ".git");
2530 624411d2 2023-07-08 jrick if (dotgit)
2531 624411d2 2023-07-08 jrick *dotgit = '\0';
2532 624411d2 2023-07-08 jrick if (asprintf(&worktree_path, "%s/%s", cwd, base) == -1) {
2533 624411d2 2023-07-08 jrick error = got_error_from_errno("asprintf");
2534 624411d2 2023-07-08 jrick free(base);
2535 624411d2 2023-07-08 jrick goto done;
2537 624411d2 2023-07-08 jrick free(base);
2538 624411d2 2023-07-08 jrick } else if (argc == 2) {
2539 624411d2 2023-07-08 jrick repo_path = realpath(argv[0], NULL);
2540 624411d2 2023-07-08 jrick if (repo_path == NULL) {
2541 624411d2 2023-07-08 jrick error = got_error_from_errno2("realpath", argv[0]);
2542 624411d2 2023-07-08 jrick goto done;
2544 624411d2 2023-07-08 jrick worktree_path = realpath(argv[1], NULL);
2545 624411d2 2023-07-08 jrick if (worktree_path == NULL) {
2546 624411d2 2023-07-08 jrick if (errno != ENOENT) {
2547 624411d2 2023-07-08 jrick error = got_error_from_errno2("realpath",
2548 624411d2 2023-07-08 jrick argv[1]);
2549 624411d2 2023-07-08 jrick goto done;
2551 624411d2 2023-07-08 jrick worktree_path = strdup(argv[1]);
2552 624411d2 2023-07-08 jrick if (worktree_path == NULL) {
2553 624411d2 2023-07-08 jrick error = got_error_from_errno("strdup");
2554 624411d2 2023-07-08 jrick goto done;
2558 624411d2 2023-07-08 jrick usage_checkout();
2560 624411d2 2023-07-08 jrick got_path_strip_trailing_slashes(repo_path);
2561 624411d2 2023-07-08 jrick got_path_strip_trailing_slashes(worktree_path);
2563 624411d2 2023-07-08 jrick error = got_repo_pack_fds_open(&pack_fds);
2564 624411d2 2023-07-08 jrick if (error != NULL)
2565 624411d2 2023-07-08 jrick goto done;
2567 624411d2 2023-07-08 jrick error = got_repo_open(&repo, repo_path, NULL, pack_fds);
2568 624411d2 2023-07-08 jrick if (error != NULL)
2569 624411d2 2023-07-08 jrick goto done;
2571 624411d2 2023-07-08 jrick /* Pre-create work tree path for unveil(2) */
2572 624411d2 2023-07-08 jrick error = got_path_mkdir(worktree_path);
2573 624411d2 2023-07-08 jrick if (error) {
2574 624411d2 2023-07-08 jrick if (!(error->code == GOT_ERR_ERRNO && errno == EISDIR) &&
2575 624411d2 2023-07-08 jrick !(error->code == GOT_ERR_ERRNO && errno == EEXIST))
2576 624411d2 2023-07-08 jrick goto done;
2577 624411d2 2023-07-08 jrick if (!allow_nonempty &&
2578 624411d2 2023-07-08 jrick !got_path_dir_is_empty(worktree_path)) {
2579 624411d2 2023-07-08 jrick error = got_error_path(worktree_path,
2580 624411d2 2023-07-08 jrick GOT_ERR_DIR_NOT_EMPTY);
2581 624411d2 2023-07-08 jrick goto done;
2585 624411d2 2023-07-08 jrick error = apply_unveil(got_repo_get_path(repo), 0, worktree_path);
2586 624411d2 2023-07-08 jrick if (error)
2587 624411d2 2023-07-08 jrick goto done;
2589 624411d2 2023-07-08 jrick error = got_ref_open(&head_ref, repo, branch_name, 0);
2590 624411d2 2023-07-08 jrick if (error != NULL)
2591 624411d2 2023-07-08 jrick goto done;
2593 624411d2 2023-07-08 jrick error = got_worktree_init(worktree_path, head_ref, path_prefix, repo);
2594 624411d2 2023-07-08 jrick if (error != NULL && !(error->code == GOT_ERR_ERRNO && errno == EEXIST))
2595 624411d2 2023-07-08 jrick goto done;
2597 624411d2 2023-07-08 jrick error = got_worktree_open(&worktree, worktree_path);
2598 624411d2 2023-07-08 jrick if (error != NULL)
2599 624411d2 2023-07-08 jrick goto done;
2601 624411d2 2023-07-08 jrick error = got_worktree_match_path_prefix(&same_path_prefix, worktree,
2602 624411d2 2023-07-08 jrick path_prefix);
2603 624411d2 2023-07-08 jrick if (error != NULL)
2604 624411d2 2023-07-08 jrick goto done;
2605 624411d2 2023-07-08 jrick if (!same_path_prefix) {
2606 624411d2 2023-07-08 jrick error = got_error(GOT_ERR_PATH_PREFIX);
2607 624411d2 2023-07-08 jrick goto done;
2610 624411d2 2023-07-08 jrick if (commit_id_str) {
2611 624411d2 2023-07-08 jrick struct got_reflist_head refs;
2612 624411d2 2023-07-08 jrick TAILQ_INIT(&refs);
2613 624411d2 2023-07-08 jrick error = got_ref_list(&refs, repo, NULL, got_ref_cmp_by_name,
2615 624411d2 2023-07-08 jrick if (error)
2616 624411d2 2023-07-08 jrick goto done;
2617 624411d2 2023-07-08 jrick error = got_repo_match_object_id(&commit_id, NULL,
2618 624411d2 2023-07-08 jrick commit_id_str, GOT_OBJ_TYPE_COMMIT, &refs, repo);
2619 624411d2 2023-07-08 jrick got_ref_list_free(&refs);
2620 624411d2 2023-07-08 jrick if (error)
2621 624411d2 2023-07-08 jrick goto done;
2622 624411d2 2023-07-08 jrick error = check_linear_ancestry(commit_id,
2623 624411d2 2023-07-08 jrick got_worktree_get_base_commit_id(worktree), 0, repo);
2624 624411d2 2023-07-08 jrick if (error != NULL) {
2625 624411d2 2023-07-08 jrick if (error->code == GOT_ERR_ANCESTRY) {
2626 624411d2 2023-07-08 jrick error = checkout_ancestry_error(
2627 624411d2 2023-07-08 jrick head_ref, commit_id_str);
2629 624411d2 2023-07-08 jrick goto done;
2631 624411d2 2023-07-08 jrick error = check_same_branch(commit_id, head_ref, repo);
2632 624411d2 2023-07-08 jrick if (error) {
2633 624411d2 2023-07-08 jrick if (error->code == GOT_ERR_ANCESTRY) {
2634 624411d2 2023-07-08 jrick error = checkout_ancestry_error(
2635 624411d2 2023-07-08 jrick head_ref, commit_id_str);
2637 624411d2 2023-07-08 jrick goto done;
2639 624411d2 2023-07-08 jrick error = got_worktree_set_base_commit_id(worktree, repo,
2640 624411d2 2023-07-08 jrick commit_id);
2641 624411d2 2023-07-08 jrick if (error)
2642 624411d2 2023-07-08 jrick goto done;
2643 624411d2 2023-07-08 jrick /* Expand potentially abbreviated commit ID string. */
2644 624411d2 2023-07-08 jrick free(commit_id_str);
2645 624411d2 2023-07-08 jrick error = got_object_id_str(&commit_id_str, commit_id);
2646 624411d2 2023-07-08 jrick if (error)
2647 624411d2 2023-07-08 jrick goto done;
2649 624411d2 2023-07-08 jrick commit_id = got_object_id_dup(
2650 624411d2 2023-07-08 jrick got_worktree_get_base_commit_id(worktree));
2651 624411d2 2023-07-08 jrick if (commit_id == NULL) {
2652 624411d2 2023-07-08 jrick error = got_error_from_errno("got_object_id_dup");
2653 624411d2 2023-07-08 jrick goto done;
2655 624411d2 2023-07-08 jrick error = got_object_id_str(&commit_id_str, commit_id);
2656 624411d2 2023-07-08 jrick if (error)
2657 624411d2 2023-07-08 jrick goto done;
2660 624411d2 2023-07-08 jrick error = got_pathlist_append(&paths, "", NULL);
2661 624411d2 2023-07-08 jrick if (error)
2662 624411d2 2023-07-08 jrick goto done;
2663 624411d2 2023-07-08 jrick cpa.worktree_path = worktree_path;
2664 624411d2 2023-07-08 jrick cpa.had_base_commit_ref_error = 0;
2665 624411d2 2023-07-08 jrick cpa.verbosity = verbosity;
2666 624411d2 2023-07-08 jrick error = got_worktree_checkout_files(worktree, &paths, repo,
2667 624411d2 2023-07-08 jrick checkout_progress, &cpa, check_cancelled, NULL);
2668 624411d2 2023-07-08 jrick if (error != NULL)
2669 624411d2 2023-07-08 jrick goto done;
2671 624411d2 2023-07-08 jrick if (got_ref_is_symbolic(head_ref)) {
2672 624411d2 2023-07-08 jrick error = got_ref_resolve_symbolic(&ref, repo, head_ref);
2673 624411d2 2023-07-08 jrick if (error)
2674 624411d2 2023-07-08 jrick goto done;
2675 624411d2 2023-07-08 jrick refname = got_ref_get_name(ref);
2677 624411d2 2023-07-08 jrick refname = got_ref_get_name(head_ref);
2678 624411d2 2023-07-08 jrick printf("Checked out %s: %s\n", refname, commit_id_str);
2679 624411d2 2023-07-08 jrick printf("Now shut up and hack\n");
2680 624411d2 2023-07-08 jrick if (cpa.had_base_commit_ref_error)
2681 624411d2 2023-07-08 jrick show_worktree_base_ref_warning();
2683 624411d2 2023-07-08 jrick if (pack_fds) {
2684 624411d2 2023-07-08 jrick const struct got_error *pack_err =
2685 624411d2 2023-07-08 jrick got_repo_pack_fds_close(pack_fds);
2686 624411d2 2023-07-08 jrick if (error == NULL)
2687 624411d2 2023-07-08 jrick error = pack_err;
2689 624411d2 2023-07-08 jrick if (head_ref)
2690 624411d2 2023-07-08 jrick got_ref_close(head_ref);
2692 624411d2 2023-07-08 jrick got_ref_close(ref);
2693 624411d2 2023-07-08 jrick if (repo) {
2694 624411d2 2023-07-08 jrick const struct got_error *close_err = got_repo_close(repo);
2695 624411d2 2023-07-08 jrick if (error == NULL)
2696 624411d2 2023-07-08 jrick error = close_err;
2698 624411d2 2023-07-08 jrick got_pathlist_free(&paths, GOT_PATHLIST_FREE_NONE);
2699 624411d2 2023-07-08 jrick free(commit_id_str);
2700 624411d2 2023-07-08 jrick free(commit_id);
2701 624411d2 2023-07-08 jrick free(repo_path);
2702 624411d2 2023-07-08 jrick free(worktree_path);
2703 624411d2 2023-07-08 jrick free(cwd);
2704 624411d2 2023-07-08 jrick return error;
2707 624411d2 2023-07-08 jrick struct got_update_progress_arg {
2708 624411d2 2023-07-08 jrick int did_something;
2709 624411d2 2023-07-08 jrick int conflicts;
2710 624411d2 2023-07-08 jrick int obstructed;
2711 624411d2 2023-07-08 jrick int not_updated;
2712 624411d2 2023-07-08 jrick int missing;
2713 624411d2 2023-07-08 jrick int not_deleted;
2714 624411d2 2023-07-08 jrick int unversioned;
2715 624411d2 2023-07-08 jrick int verbosity;
2718 624411d2 2023-07-08 jrick static void
2719 624411d2 2023-07-08 jrick print_update_progress_stats(struct got_update_progress_arg *upa)
2721 624411d2 2023-07-08 jrick if (!upa->did_something)
2724 624411d2 2023-07-08 jrick if (upa->conflicts > 0)
2725 624411d2 2023-07-08 jrick printf("Files with new merge conflicts: %d\n", upa->conflicts);
2726 624411d2 2023-07-08 jrick if (upa->obstructed > 0)
2727 624411d2 2023-07-08 jrick printf("File paths obstructed by a non-regular file: %d\n",
2728 624411d2 2023-07-08 jrick upa->obstructed);
2729 624411d2 2023-07-08 jrick if (upa->not_updated > 0)
2730 624411d2 2023-07-08 jrick printf("Files not updated because of existing merge "
2731 624411d2 2023-07-08 jrick "conflicts: %d\n", upa->not_updated);
2735 624411d2 2023-07-08 jrick * The meaning of some status codes differs between merge-style operations and
2736 624411d2 2023-07-08 jrick * update operations. For example, the ! status code means "file was missing"
2737 624411d2 2023-07-08 jrick * if changes were merged into the work tree, and "missing file was restored"
2738 624411d2 2023-07-08 jrick * if the work tree was updated. This function should be used by any operation
2739 624411d2 2023-07-08 jrick * which merges changes into the work tree without updating the work tree.
2741 624411d2 2023-07-08 jrick static void
2742 624411d2 2023-07-08 jrick print_merge_progress_stats(struct got_update_progress_arg *upa)
2744 624411d2 2023-07-08 jrick if (!upa->did_something)
2747 624411d2 2023-07-08 jrick if (upa->conflicts > 0)
2748 624411d2 2023-07-08 jrick printf("Files with new merge conflicts: %d\n", upa->conflicts);
2749 624411d2 2023-07-08 jrick if (upa->obstructed > 0)
2750 624411d2 2023-07-08 jrick printf("File paths obstructed by a non-regular file: %d\n",
2751 624411d2 2023-07-08 jrick upa->obstructed);
2752 624411d2 2023-07-08 jrick if (upa->missing > 0)
2753 624411d2 2023-07-08 jrick printf("Files which had incoming changes but could not be "
2754 624411d2 2023-07-08 jrick "found in the work tree: %d\n", upa->missing);
2755 624411d2 2023-07-08 jrick if (upa->not_deleted > 0)
2756 624411d2 2023-07-08 jrick printf("Files not deleted due to differences in deleted "
2757 624411d2 2023-07-08 jrick "content: %d\n", upa->not_deleted);
2758 624411d2 2023-07-08 jrick if (upa->unversioned > 0)
2759 624411d2 2023-07-08 jrick printf("Files not merged because an unversioned file was "
2760 624411d2 2023-07-08 jrick "found in the work tree: %d\n", upa->unversioned);
2763 624411d2 2023-07-08 jrick __dead static void
2764 624411d2 2023-07-08 jrick usage_update(void)
2766 3d1b16d1 2023-07-08 jrick fprintf(stderr, "usage: %s update [-qtvX] [-c commit] [-r remote] "
2767 624411d2 2023-07-08 jrick "[path ...]\n", getprogname());
2771 624411d2 2023-07-08 jrick static const struct got_error *
2772 624411d2 2023-07-08 jrick update_progress(void *arg, unsigned char status, const char *path)
2774 624411d2 2023-07-08 jrick struct got_update_progress_arg *upa = arg;
2776 624411d2 2023-07-08 jrick if (status == GOT_STATUS_EXISTS ||
2777 624411d2 2023-07-08 jrick status == GOT_STATUS_BASE_REF_ERR)
2778 624411d2 2023-07-08 jrick return NULL;
2780 624411d2 2023-07-08 jrick upa->did_something = 1;
2782 624411d2 2023-07-08 jrick /* Base commit bump happens silently. */
2783 624411d2 2023-07-08 jrick if (status == GOT_STATUS_BUMP_BASE)
2784 624411d2 2023-07-08 jrick return NULL;
2786 624411d2 2023-07-08 jrick if (status == GOT_STATUS_CONFLICT)
2787 624411d2 2023-07-08 jrick upa->conflicts++;
2788 624411d2 2023-07-08 jrick if (status == GOT_STATUS_OBSTRUCTED)
2789 624411d2 2023-07-08 jrick upa->obstructed++;
2790 624411d2 2023-07-08 jrick if (status == GOT_STATUS_CANNOT_UPDATE)
2791 624411d2 2023-07-08 jrick upa->not_updated++;
2792 624411d2 2023-07-08 jrick if (status == GOT_STATUS_MISSING)
2793 624411d2 2023-07-08 jrick upa->missing++;
2794 624411d2 2023-07-08 jrick if (status == GOT_STATUS_CANNOT_DELETE)
2795 624411d2 2023-07-08 jrick upa->not_deleted++;
2796 624411d2 2023-07-08 jrick if (status == GOT_STATUS_UNVERSIONED)
2797 624411d2 2023-07-08 jrick upa->unversioned++;
2799 624411d2 2023-07-08 jrick while (path[0] == '/')
2801 624411d2 2023-07-08 jrick if (upa->verbosity >= 0)
2802 624411d2 2023-07-08 jrick printf("%c %s\n", status, path);
2804 624411d2 2023-07-08 jrick return NULL;
2807 624411d2 2023-07-08 jrick static const struct got_error *
2808 624411d2 2023-07-08 jrick switch_head_ref(struct got_reference *head_ref,
2809 624411d2 2023-07-08 jrick struct got_object_id *commit_id, struct got_worktree *worktree,
2810 624411d2 2023-07-08 jrick struct got_repository *repo)
2812 624411d2 2023-07-08 jrick const struct got_error *err = NULL;
2813 624411d2 2023-07-08 jrick char *base_id_str;
2814 624411d2 2023-07-08 jrick int ref_has_moved = 0;
2816 624411d2 2023-07-08 jrick /* Trivial case: switching between two different references. */
2817 624411d2 2023-07-08 jrick if (strcmp(got_ref_get_name(head_ref),
2818 624411d2 2023-07-08 jrick got_worktree_get_head_ref_name(worktree)) != 0) {
2819 624411d2 2023-07-08 jrick printf("Switching work tree from %s to %s\n",
2820 624411d2 2023-07-08 jrick got_worktree_get_head_ref_name(worktree),
2821 624411d2 2023-07-08 jrick got_ref_get_name(head_ref));
2822 624411d2 2023-07-08 jrick return got_worktree_set_head_ref(worktree, head_ref);
2825 624411d2 2023-07-08 jrick err = check_linear_ancestry(commit_id,
2826 624411d2 2023-07-08 jrick got_worktree_get_base_commit_id(worktree), 0, repo);
2827 624411d2 2023-07-08 jrick if (err) {
2828 624411d2 2023-07-08 jrick if (err->code != GOT_ERR_ANCESTRY)
2829 624411d2 2023-07-08 jrick return err;
2830 624411d2 2023-07-08 jrick ref_has_moved = 1;
2832 624411d2 2023-07-08 jrick if (!ref_has_moved)
2833 624411d2 2023-07-08 jrick return NULL;
2835 624411d2 2023-07-08 jrick /* Switching to a rebased branch with the same reference name. */
2836 624411d2 2023-07-08 jrick err = got_object_id_str(&base_id_str,
2837 624411d2 2023-07-08 jrick got_worktree_get_base_commit_id(worktree));
2839 624411d2 2023-07-08 jrick return err;
2840 624411d2 2023-07-08 jrick printf("Reference %s now points at a different branch\n",
2841 624411d2 2023-07-08 jrick got_worktree_get_head_ref_name(worktree));
2842 624411d2 2023-07-08 jrick printf("Switching work tree from %s to %s\n", base_id_str,
2843 624411d2 2023-07-08 jrick got_worktree_get_head_ref_name(worktree));
2844 624411d2 2023-07-08 jrick return NULL;
2847 624411d2 2023-07-08 jrick static const struct got_error *
2848 624411d2 2023-07-08 jrick check_rebase_or_histedit_in_progress(struct got_worktree *worktree)
2850 624411d2 2023-07-08 jrick const struct got_error *err;
2851 624411d2 2023-07-08 jrick int in_progress;
2853 624411d2 2023-07-08 jrick err = got_worktree_rebase_in_progress(&in_progress, worktree);
2855 624411d2 2023-07-08 jrick return err;
2856 624411d2 2023-07-08 jrick if (in_progress)
2857 624411d2 2023-07-08 jrick return got_error(GOT_ERR_REBASING);
2859 624411d2 2023-07-08 jrick err = got_worktree_histedit_in_progress(&in_progress, worktree);
2861 624411d2 2023-07-08 jrick return err;
2862 624411d2 2023-07-08 jrick if (in_progress)
2863 624411d2 2023-07-08 jrick return got_error(GOT_ERR_HISTEDIT_BUSY);
2865 624411d2 2023-07-08 jrick return NULL;
2868 624411d2 2023-07-08 jrick static const struct got_error *
2869 624411d2 2023-07-08 jrick check_merge_in_progress(struct got_worktree *worktree,
2870 624411d2 2023-07-08 jrick struct got_repository *repo)
2872 624411d2 2023-07-08 jrick const struct got_error *err;
2873 624411d2 2023-07-08 jrick int in_progress;
2875 624411d2 2023-07-08 jrick err = got_worktree_merge_in_progress(&in_progress, worktree, repo);
2877 624411d2 2023-07-08 jrick return err;
2878 624411d2 2023-07-08 jrick if (in_progress)
2879 624411d2 2023-07-08 jrick return got_error(GOT_ERR_MERGE_BUSY);
2881 624411d2 2023-07-08 jrick return NULL;
2884 624411d2 2023-07-08 jrick static const struct got_error *
2885 624411d2 2023-07-08 jrick get_worktree_paths_from_argv(struct got_pathlist_head *paths, int argc,
2886 624411d2 2023-07-08 jrick char *argv[], struct got_worktree *worktree)
2888 624411d2 2023-07-08 jrick const struct got_error *err = NULL;
2889 624411d2 2023-07-08 jrick char *path;
2890 624411d2 2023-07-08 jrick struct got_pathlist_entry *new;
2893 624411d2 2023-07-08 jrick if (argc == 0) {
2894 624411d2 2023-07-08 jrick path = strdup("");
2895 624411d2 2023-07-08 jrick if (path == NULL)
2896 624411d2 2023-07-08 jrick return got_error_from_errno("strdup");
2897 624411d2 2023-07-08 jrick return got_pathlist_append(paths, path, NULL);
2900 624411d2 2023-07-08 jrick for (i = 0; i < argc; i++) {
2901 624411d2 2023-07-08 jrick err = got_worktree_resolve_path(&path, worktree, argv[i]);
2904 624411d2 2023-07-08 jrick err = got_pathlist_insert(&new, paths, path, NULL);
2905 624411d2 2023-07-08 jrick if (err || new == NULL /* duplicate */) {
2906 624411d2 2023-07-08 jrick free(path);
2912 624411d2 2023-07-08 jrick return err;
2915 624411d2 2023-07-08 jrick static const struct got_error *
2916 624411d2 2023-07-08 jrick wrap_not_worktree_error(const struct got_error *orig_err,
2917 624411d2 2023-07-08 jrick const char *cmdname, const char *path)
2919 624411d2 2023-07-08 jrick const struct got_error *err;
2920 624411d2 2023-07-08 jrick struct got_repository *repo;
2921 624411d2 2023-07-08 jrick static char msg[512];
2922 624411d2 2023-07-08 jrick int *pack_fds = NULL;
2924 624411d2 2023-07-08 jrick err = got_repo_pack_fds_open(&pack_fds);
2926 624411d2 2023-07-08 jrick return err;
2928 624411d2 2023-07-08 jrick err = got_repo_open(&repo, path, NULL, pack_fds);
2930 624411d2 2023-07-08 jrick return orig_err;
2932 624411d2 2023-07-08 jrick snprintf(msg, sizeof(msg),
2933 624411d2 2023-07-08 jrick "'got %s' needs a work tree in addition to a git repository\n"
2934 624411d2 2023-07-08 jrick "Work trees can be checked out from this Git repository with "
2935 624411d2 2023-07-08 jrick "'got checkout'.\n"
2936 624411d2 2023-07-08 jrick "The got(1) manual page contains more information.", cmdname);
2937 624411d2 2023-07-08 jrick err = got_error_msg(GOT_ERR_NOT_WORKTREE, msg);
2938 624411d2 2023-07-08 jrick if (repo) {
2939 624411d2 2023-07-08 jrick const struct got_error *close_err = got_repo_close(repo);
2940 624411d2 2023-07-08 jrick if (err == NULL)
2941 624411d2 2023-07-08 jrick err = close_err;
2943 624411d2 2023-07-08 jrick if (pack_fds) {
2944 624411d2 2023-07-08 jrick const struct got_error *pack_err =
2945 624411d2 2023-07-08 jrick got_repo_pack_fds_close(pack_fds);
2946 624411d2 2023-07-08 jrick if (err == NULL)
2947 624411d2 2023-07-08 jrick err = pack_err;
2949 624411d2 2023-07-08 jrick return err;
2952 624411d2 2023-07-08 jrick static const struct got_error *
2953 624411d2 2023-07-08 jrick cmd_update(int argc, char *argv[])
2955 3d1b16d1 2023-07-08 jrick const struct got_error *error = NULL, *unlock_err;
2956 3d1b16d1 2023-07-08 jrick char *worktree_path = NULL;
2957 3d1b16d1 2023-07-08 jrick const char *repo_path = NULL;
2958 3d1b16d1 2023-07-08 jrick const char *remote_name = NULL;
2959 3d1b16d1 2023-07-08 jrick char *proto = NULL, *host = NULL, *port = NULL;
2960 3d1b16d1 2023-07-08 jrick char *repo_name = NULL, *server_path = NULL;
2961 3d1b16d1 2023-07-08 jrick const struct got_remote_repo *remotes, *remote = NULL;
2962 3d1b16d1 2023-07-08 jrick int nremotes;
2963 3d1b16d1 2023-07-08 jrick char *id_str = NULL;
2964 624411d2 2023-07-08 jrick struct got_repository *repo = NULL;
2965 624411d2 2023-07-08 jrick struct got_worktree *worktree = NULL;
2966 3d1b16d1 2023-07-08 jrick const struct got_gotconfig *repo_conf = NULL, *worktree_conf = NULL;
2967 3d1b16d1 2023-07-08 jrick struct got_pathlist_head paths, refs, symrefs;
2968 3d1b16d1 2023-07-08 jrick struct got_pathlist_head wanted_branches, wanted_refs;
2969 624411d2 2023-07-08 jrick struct got_pathlist_entry *pe;
2970 3d1b16d1 2023-07-08 jrick struct got_reflist_head remote_refs;
2971 3d1b16d1 2023-07-08 jrick struct got_reflist_entry *re;
2972 3d1b16d1 2023-07-08 jrick struct got_object_id *pack_hash = NULL;
2973 3d1b16d1 2023-07-08 jrick int i, ch, fetchfd = -1, fetchstatus;
2974 3d1b16d1 2023-07-08 jrick pid_t fetchpid = -1;
2975 3d1b16d1 2023-07-08 jrick struct got_fetch_progress_arg fpa;
2976 624411d2 2023-07-08 jrick struct got_update_progress_arg upa;
2977 3d1b16d1 2023-07-08 jrick int verbosity = 0;
2978 3d1b16d1 2023-07-08 jrick int delete_remote = 0;
2979 3d1b16d1 2023-07-08 jrick int replace_tags = 0;
2980 624411d2 2023-07-08 jrick int *pack_fds = NULL;
2981 3d1b16d1 2023-07-08 jrick const char *remote_head = NULL, *worktree_branch = NULL;
2982 3d1b16d1 2023-07-08 jrick struct got_object_id *commit_id = NULL;
2983 3d1b16d1 2023-07-08 jrick char *commit_id_str = NULL;
2984 3d1b16d1 2023-07-08 jrick const char *refname;
2985 3d1b16d1 2023-07-08 jrick struct got_reference *head_ref = NULL;
2987 624411d2 2023-07-08 jrick TAILQ_INIT(&paths);
2988 3d1b16d1 2023-07-08 jrick TAILQ_INIT(&refs);
2989 3d1b16d1 2023-07-08 jrick TAILQ_INIT(&symrefs);
2990 3d1b16d1 2023-07-08 jrick TAILQ_INIT(&remote_refs);
2991 3d1b16d1 2023-07-08 jrick TAILQ_INIT(&wanted_branches);
2992 3d1b16d1 2023-07-08 jrick TAILQ_INIT(&wanted_refs);
2994 3d1b16d1 2023-07-08 jrick while ((ch = getopt(argc, argv, "c:qr:vX")) != -1) {
2995 624411d2 2023-07-08 jrick switch (ch) {
2996 624411d2 2023-07-08 jrick case 'c':
2997 624411d2 2023-07-08 jrick commit_id_str = strdup(optarg);
2998 624411d2 2023-07-08 jrick if (commit_id_str == NULL)
2999 624411d2 2023-07-08 jrick return got_error_from_errno("strdup");
3001 3d1b16d1 2023-07-08 jrick case 't':
3002 3d1b16d1 2023-07-08 jrick replace_tags = 1;
3004 624411d2 2023-07-08 jrick case 'q':
3005 624411d2 2023-07-08 jrick verbosity = -1;
3007 3d1b16d1 2023-07-08 jrick case 'r':
3008 3d1b16d1 2023-07-08 jrick remote_name = optarg;
3010 3d1b16d1 2023-07-08 jrick case 'v':
3011 3d1b16d1 2023-07-08 jrick if (verbosity < 0)
3012 3d1b16d1 2023-07-08 jrick verbosity = 0;
3013 3d1b16d1 2023-07-08 jrick else if (verbosity < 3)
3014 3d1b16d1 2023-07-08 jrick verbosity++;
3016 3d1b16d1 2023-07-08 jrick case 'X':
3017 3d1b16d1 2023-07-08 jrick delete_remote = 1;
3020 624411d2 2023-07-08 jrick usage_update();
3024 624411d2 2023-07-08 jrick argc -= optind;
3025 624411d2 2023-07-08 jrick argv += optind;
3027 3d1b16d1 2023-07-08 jrick if (delete_remote) {
3028 3d1b16d1 2023-07-08 jrick if (replace_tags)
3029 3d1b16d1 2023-07-08 jrick option_conflict('X', 't');
3030 3d1b16d1 2023-07-08 jrick if (remote_name == NULL)
3031 3d1b16d1 2023-07-08 jrick errx(1, "-X option requires a remote name");
3033 3d1b16d1 2023-07-08 jrick if (remote_name == NULL)
3034 3d1b16d1 2023-07-08 jrick remote_name = GOT_FETCH_DEFAULT_REMOTE_NAME;
3036 624411d2 2023-07-08 jrick worktree_path = getcwd(NULL, 0);
3037 624411d2 2023-07-08 jrick if (worktree_path == NULL) {
3038 624411d2 2023-07-08 jrick error = got_error_from_errno("getcwd");
3039 624411d2 2023-07-08 jrick goto done;
3041 624411d2 2023-07-08 jrick error = got_worktree_open(&worktree, worktree_path);
3042 624411d2 2023-07-08 jrick if (error) {
3043 624411d2 2023-07-08 jrick if (error->code == GOT_ERR_NOT_WORKTREE)
3044 624411d2 2023-07-08 jrick error = wrap_not_worktree_error(error, "update",
3045 624411d2 2023-07-08 jrick worktree_path);
3046 624411d2 2023-07-08 jrick goto done;
3048 3d1b16d1 2023-07-08 jrick repo_path = got_worktree_get_repo_path(worktree);
3050 3d1b16d1 2023-07-08 jrick error = got_repo_pack_fds_open(&pack_fds);
3051 3d1b16d1 2023-07-08 jrick if (error != NULL)
3052 3d1b16d1 2023-07-08 jrick goto done;
3054 3d1b16d1 2023-07-08 jrick error = got_repo_open(&repo, repo_path, NULL, pack_fds);
3055 3d1b16d1 2023-07-08 jrick if (error)
3056 3d1b16d1 2023-07-08 jrick goto done;
3058 624411d2 2023-07-08 jrick error = check_rebase_or_histedit_in_progress(worktree);
3059 624411d2 2023-07-08 jrick if (error)
3060 624411d2 2023-07-08 jrick goto done;
3061 3d1b16d1 2023-07-08 jrick error = check_merge_in_progress(worktree, repo);
3062 3d1b16d1 2023-07-08 jrick if (error)
3063 3d1b16d1 2023-07-08 jrick goto done;
3065 3d1b16d1 2023-07-08 jrick error = get_worktree_paths_from_argv(&paths, argc, argv, worktree);
3066 3d1b16d1 2023-07-08 jrick if (error)
3067 624411d2 2023-07-08 jrick goto done;
3069 3d1b16d1 2023-07-08 jrick worktree_conf = got_worktree_get_gotconfig(worktree);
3070 3d1b16d1 2023-07-08 jrick if (worktree_conf) {
3071 3d1b16d1 2023-07-08 jrick got_gotconfig_get_remotes(&nremotes, &remotes,
3072 3d1b16d1 2023-07-08 jrick worktree_conf);
3073 3d1b16d1 2023-07-08 jrick for (i = 0; i < nremotes; i++) {
3074 3d1b16d1 2023-07-08 jrick if (strcmp(remotes[i].name, remote_name) == 0) {
3075 3d1b16d1 2023-07-08 jrick remote = &remotes[i];
3081 3d1b16d1 2023-07-08 jrick if (remote == NULL) {
3082 3d1b16d1 2023-07-08 jrick repo_conf = got_repo_get_gotconfig(repo);
3083 3d1b16d1 2023-07-08 jrick if (repo_conf) {
3084 3d1b16d1 2023-07-08 jrick got_gotconfig_get_remotes(&nremotes, &remotes,
3085 3d1b16d1 2023-07-08 jrick repo_conf);
3086 3d1b16d1 2023-07-08 jrick for (i = 0; i < nremotes; i++) {
3087 3d1b16d1 2023-07-08 jrick if (strcmp(remotes[i].name, remote_name) == 0) {
3088 3d1b16d1 2023-07-08 jrick remote = &remotes[i];
3094 3d1b16d1 2023-07-08 jrick if (remote == NULL) {
3095 3d1b16d1 2023-07-08 jrick got_repo_get_gitconfig_remotes(&nremotes, &remotes, repo);
3096 3d1b16d1 2023-07-08 jrick for (i = 0; i < nremotes; i++) {
3097 3d1b16d1 2023-07-08 jrick if (strcmp(remotes[i].name, remote_name) == 0) {
3098 3d1b16d1 2023-07-08 jrick remote = &remotes[i];
3103 3d1b16d1 2023-07-08 jrick if (remote == NULL) {
3104 3d1b16d1 2023-07-08 jrick error = got_error_path(remote_name, GOT_ERR_NO_REMOTE);
3105 3d1b16d1 2023-07-08 jrick goto done;
3108 3d1b16d1 2023-07-08 jrick error = got_dial_parse_uri(&proto, &host, &port, &server_path,
3109 3d1b16d1 2023-07-08 jrick &repo_name, remote->fetch_url);
3110 3d1b16d1 2023-07-08 jrick if (error)
3111 3d1b16d1 2023-07-08 jrick goto done;
3113 3d1b16d1 2023-07-08 jrick if (strcmp(proto, "git") == 0) {
3114 3d1b16d1 2023-07-08 jrick #ifndef PROFILE
3115 3d1b16d1 2023-07-08 jrick if (pledge("stdio rpath wpath cpath fattr flock proc exec "
3116 3d1b16d1 2023-07-08 jrick "sendfd dns inet unveil", NULL) == -1)
3117 3d1b16d1 2023-07-08 jrick err(1, "pledge");
3119 3d1b16d1 2023-07-08 jrick } else if (strcmp(proto, "git+ssh") == 0 ||
3120 3d1b16d1 2023-07-08 jrick strcmp(proto, "ssh") == 0) {
3121 3d1b16d1 2023-07-08 jrick #ifndef PROFILE
3122 3d1b16d1 2023-07-08 jrick if (pledge("stdio rpath wpath cpath fattr flock proc exec "
3123 3d1b16d1 2023-07-08 jrick "sendfd unveil", NULL) == -1)
3124 3d1b16d1 2023-07-08 jrick err(1, "pledge");
3126 3d1b16d1 2023-07-08 jrick } else if (strcmp(proto, "http") == 0 ||
3127 3d1b16d1 2023-07-08 jrick strcmp(proto, "git+http") == 0) {
3128 3d1b16d1 2023-07-08 jrick error = got_error_path(proto, GOT_ERR_NOT_IMPL);
3129 3d1b16d1 2023-07-08 jrick goto done;
3131 3d1b16d1 2023-07-08 jrick error = got_error_path(proto, GOT_ERR_BAD_PROTO);
3132 3d1b16d1 2023-07-08 jrick goto done;
3135 3d1b16d1 2023-07-08 jrick error = got_dial_apply_unveil(proto);
3136 3d1b16d1 2023-07-08 jrick if (error)
3137 3d1b16d1 2023-07-08 jrick goto done;
3139 624411d2 2023-07-08 jrick error = apply_unveil(got_repo_get_path(repo), 0,
3140 624411d2 2023-07-08 jrick got_worktree_get_root_path(worktree));
3141 624411d2 2023-07-08 jrick if (error)
3142 624411d2 2023-07-08 jrick goto done;
3144 3d1b16d1 2023-07-08 jrick if (verbosity >= 0) {
3145 3d1b16d1 2023-07-08 jrick printf("Connecting to \"%s\" %s://%s%s%s%s%s\n",
3146 3d1b16d1 2023-07-08 jrick remote->name, proto, host,
3147 3d1b16d1 2023-07-08 jrick port ? ":" : "", port ? port : "",
3148 3d1b16d1 2023-07-08 jrick *server_path == '/' ? "" : "/", server_path);
3151 3d1b16d1 2023-07-08 jrick error = got_fetch_connect(&fetchpid, &fetchfd, proto, host, port,
3152 3d1b16d1 2023-07-08 jrick server_path, verbosity);
3153 624411d2 2023-07-08 jrick if (error)
3154 624411d2 2023-07-08 jrick goto done;
3157 3d1b16d1 2023-07-08 jrick * If set, get this remote's HEAD ref target so
3158 3d1b16d1 2023-07-08 jrick * if it has changed on the server we can fetch it.
3160 3d1b16d1 2023-07-08 jrick error = got_ref_list(&remote_refs, repo, "refs/remotes",
3161 3d1b16d1 2023-07-08 jrick got_ref_cmp_by_name, repo);
3162 624411d2 2023-07-08 jrick if (error)
3163 624411d2 2023-07-08 jrick goto done;
3165 3d1b16d1 2023-07-08 jrick TAILQ_FOREACH(re, &remote_refs, entry) {
3166 3d1b16d1 2023-07-08 jrick const char *remote_refname, *remote_target;
3167 3d1b16d1 2023-07-08 jrick size_t remote_name_len;
3169 3d1b16d1 2023-07-08 jrick if (!got_ref_is_symbolic(re->ref))
3170 3d1b16d1 2023-07-08 jrick continue;
3172 3d1b16d1 2023-07-08 jrick remote_name_len = strlen(remote->name);
3173 3d1b16d1 2023-07-08 jrick remote_refname = got_ref_get_name(re->ref);
3175 3d1b16d1 2023-07-08 jrick /* we only want refs/remotes/$remote->name/HEAD */
3176 3d1b16d1 2023-07-08 jrick if (strncmp(remote_refname + 13, remote->name,
3177 3d1b16d1 2023-07-08 jrick remote_name_len) != 0)
3178 3d1b16d1 2023-07-08 jrick continue;
3180 3d1b16d1 2023-07-08 jrick if (strcmp(remote_refname + remote_name_len + 14,
3181 3d1b16d1 2023-07-08 jrick GOT_REF_HEAD) != 0)
3182 3d1b16d1 2023-07-08 jrick continue;
3185 3d1b16d1 2023-07-08 jrick * Take the name itself because we already
3186 3d1b16d1 2023-07-08 jrick * only match with refs/heads/ in fetch_pack().
3188 3d1b16d1 2023-07-08 jrick remote_target = got_ref_get_symref_target(re->ref);
3189 3d1b16d1 2023-07-08 jrick remote_head = remote_target + remote_name_len + 14;
3193 3d1b16d1 2023-07-08 jrick refname = got_worktree_get_head_ref_name(worktree);
3194 3d1b16d1 2023-07-08 jrick if (strncmp(refname, "refs/heads/", 11) == 0)
3195 3d1b16d1 2023-07-08 jrick worktree_branch = refname;
3197 3d1b16d1 2023-07-08 jrick fpa.last_scaled_size[0] = '\0';
3198 3d1b16d1 2023-07-08 jrick fpa.last_p_indexed = -1;
3199 3d1b16d1 2023-07-08 jrick fpa.last_p_resolved = -1;
3200 3d1b16d1 2023-07-08 jrick fpa.verbosity = verbosity;
3201 3d1b16d1 2023-07-08 jrick fpa.repo = repo;
3202 3d1b16d1 2023-07-08 jrick fpa.create_configs = 0;
3203 3d1b16d1 2023-07-08 jrick fpa.configs_created = 0;
3204 3d1b16d1 2023-07-08 jrick memset(&fpa.config_info, 0, sizeof(fpa.config_info));
3206 3d1b16d1 2023-07-08 jrick error = got_fetch_pack(&pack_hash, &refs, &symrefs, remote->name,
3207 3d1b16d1 2023-07-08 jrick remote->mirror_references, 0, &wanted_branches, &wanted_refs,
3208 3d1b16d1 2023-07-08 jrick 0, verbosity, fetchfd, repo, worktree_branch, remote_head,
3209 3d1b16d1 2023-07-08 jrick 0, fetch_progress, &fpa);
3210 3d1b16d1 2023-07-08 jrick if (error)
3211 3d1b16d1 2023-07-08 jrick goto done;
3213 3d1b16d1 2023-07-08 jrick if (pack_hash != NULL && verbosity >= 0) {
3214 3d1b16d1 2023-07-08 jrick error = got_object_id_str(&id_str, pack_hash);
3215 3d1b16d1 2023-07-08 jrick if (error)
3216 3d1b16d1 2023-07-08 jrick goto done;
3217 3d1b16d1 2023-07-08 jrick printf("\nFetched %s.pack\n", id_str);
3218 3d1b16d1 2023-07-08 jrick free(id_str);
3219 3d1b16d1 2023-07-08 jrick id_str = NULL;
3222 3d1b16d1 2023-07-08 jrick /* Update references provided with the pack file. */
3223 3d1b16d1 2023-07-08 jrick TAILQ_FOREACH(pe, &refs, entry) {
3224 3d1b16d1 2023-07-08 jrick const char *refname = pe->path;
3225 3d1b16d1 2023-07-08 jrick struct got_object_id *id = pe->data;
3226 3d1b16d1 2023-07-08 jrick struct got_reference *ref;
3228 3d1b16d1 2023-07-08 jrick if (is_wanted_ref(&wanted_refs, refname)) {
3229 3d1b16d1 2023-07-08 jrick error = update_wanted_ref(refname, id,
3230 3d1b16d1 2023-07-08 jrick remote->name, verbosity, repo);
3231 3d1b16d1 2023-07-08 jrick if (error)
3232 3d1b16d1 2023-07-08 jrick goto done;
3233 3d1b16d1 2023-07-08 jrick continue;
3236 3d1b16d1 2023-07-08 jrick error = got_ref_open(&ref, repo, refname, 1);
3237 3d1b16d1 2023-07-08 jrick if (error) {
3238 3d1b16d1 2023-07-08 jrick if (error->code != GOT_ERR_NOT_REF)
3239 3d1b16d1 2023-07-08 jrick goto done;
3240 3d1b16d1 2023-07-08 jrick error = create_ref(refname, id, verbosity,
3242 3d1b16d1 2023-07-08 jrick if (error)
3243 3d1b16d1 2023-07-08 jrick goto done;
3245 3d1b16d1 2023-07-08 jrick error = update_ref(ref, id, replace_tags,
3246 3d1b16d1 2023-07-08 jrick verbosity-1, repo);
3247 3d1b16d1 2023-07-08 jrick unlock_err = got_ref_unlock(ref);
3248 3d1b16d1 2023-07-08 jrick if (unlock_err && error == NULL)
3249 3d1b16d1 2023-07-08 jrick error = unlock_err;
3250 3d1b16d1 2023-07-08 jrick got_ref_close(ref);
3251 3d1b16d1 2023-07-08 jrick if (error)
3252 3d1b16d1 2023-07-08 jrick goto done;
3256 3d1b16d1 2023-07-08 jrick /* Update worktree */
3257 3d1b16d1 2023-07-08 jrick error = got_ref_open(&head_ref, repo,
3258 624411d2 2023-07-08 jrick got_worktree_get_head_ref_name(worktree), 0);
3259 624411d2 2023-07-08 jrick if (error != NULL)
3260 624411d2 2023-07-08 jrick goto done;
3261 624411d2 2023-07-08 jrick if (commit_id_str == NULL) {
3262 624411d2 2023-07-08 jrick error = got_ref_resolve(&commit_id, repo, head_ref);
3263 624411d2 2023-07-08 jrick if (error != NULL)
3264 624411d2 2023-07-08 jrick goto done;
3265 624411d2 2023-07-08 jrick error = got_object_id_str(&commit_id_str, commit_id);
3266 624411d2 2023-07-08 jrick if (error != NULL)
3267 624411d2 2023-07-08 jrick goto done;
3269 624411d2 2023-07-08 jrick struct got_reflist_head refs;
3270 624411d2 2023-07-08 jrick TAILQ_INIT(&refs);
3271 624411d2 2023-07-08 jrick error = got_ref_list(&refs, repo, NULL, got_ref_cmp_by_name,
3273 624411d2 2023-07-08 jrick if (error)
3274 624411d2 2023-07-08 jrick goto done;
3275 624411d2 2023-07-08 jrick error = got_repo_match_object_id(&commit_id, NULL,
3276 624411d2 2023-07-08 jrick commit_id_str, GOT_OBJ_TYPE_COMMIT, &refs, repo);
3277 624411d2 2023-07-08 jrick got_ref_list_free(&refs);
3278 624411d2 2023-07-08 jrick free(commit_id_str);
3279 624411d2 2023-07-08 jrick commit_id_str = NULL;
3280 624411d2 2023-07-08 jrick if (error)
3281 624411d2 2023-07-08 jrick goto done;
3282 624411d2 2023-07-08 jrick error = got_object_id_str(&commit_id_str, commit_id);
3283 624411d2 2023-07-08 jrick if (error)
3284 624411d2 2023-07-08 jrick goto done;
3288 3d1b16d1 2023-07-08 jrick error = check_linear_ancestry(commit_id,
3289 3d1b16d1 2023-07-08 jrick got_worktree_get_base_commit_id(worktree), 0, repo);
3290 3d1b16d1 2023-07-08 jrick if (error != NULL) {
3291 3d1b16d1 2023-07-08 jrick if (error->code == GOT_ERR_ANCESTRY)
3292 3d1b16d1 2023-07-08 jrick error = got_error(GOT_ERR_BRANCH_MOVED);
3293 3d1b16d1 2023-07-08 jrick goto done;
3295 3d1b16d1 2023-07-08 jrick error = check_same_branch(commit_id, head_ref, repo);
3296 3d1b16d1 2023-07-08 jrick if (error)
3297 3d1b16d1 2023-07-08 jrick goto done;
3299 624411d2 2023-07-08 jrick if (got_object_id_cmp(got_worktree_get_base_commit_id(worktree),
3300 624411d2 2023-07-08 jrick commit_id) != 0) {
3301 624411d2 2023-07-08 jrick error = got_worktree_set_base_commit_id(worktree, repo,
3302 624411d2 2023-07-08 jrick commit_id);
3303 624411d2 2023-07-08 jrick if (error)
3304 624411d2 2023-07-08 jrick goto done;
3307 624411d2 2023-07-08 jrick memset(&upa, 0, sizeof(upa));
3308 624411d2 2023-07-08 jrick upa.verbosity = verbosity;
3309 624411d2 2023-07-08 jrick error = got_worktree_checkout_files(worktree, &paths, repo,
3310 624411d2 2023-07-08 jrick update_progress, &upa, check_cancelled, NULL);
3311 624411d2 2023-07-08 jrick if (error != NULL)
3312 624411d2 2023-07-08 jrick goto done;
3314 624411d2 2023-07-08 jrick if (upa.did_something) {
3315 624411d2 2023-07-08 jrick printf("Updated to %s: %s\n",
3316 624411d2 2023-07-08 jrick got_worktree_get_head_ref_name(worktree), commit_id_str);
3318 624411d2 2023-07-08 jrick printf("Already up-to-date\n");
3320 624411d2 2023-07-08 jrick print_update_progress_stats(&upa);
3322 3d1b16d1 2023-07-08 jrick if (fetchpid > 0) {
3323 3d1b16d1 2023-07-08 jrick if (kill(fetchpid, SIGTERM) == -1)
3324 3d1b16d1 2023-07-08 jrick error = got_error_from_errno("kill");
3325 3d1b16d1 2023-07-08 jrick if (waitpid(fetchpid, &fetchstatus, 0) == -1 && error == NULL)
3326 3d1b16d1 2023-07-08 jrick error = got_error_from_errno("waitpid");
3328 3d1b16d1 2023-07-08 jrick if (fetchfd != -1 && close(fetchfd) == -1 && error == NULL)
3329 3d1b16d1 2023-07-08 jrick error = got_error_from_errno("close");
3330 624411d2 2023-07-08 jrick if (repo) {
3331 624411d2 2023-07-08 jrick const struct got_error *close_err = got_repo_close(repo);
3332 624411d2 2023-07-08 jrick if (error == NULL)
3333 624411d2 2023-07-08 jrick error = close_err;
3335 3d1b16d1 2023-07-08 jrick if (worktree)
3336 3d1b16d1 2023-07-08 jrick got_worktree_close(worktree);
3337 3d1b16d1 2023-07-08 jrick if (pack_fds) {
3338 3d1b16d1 2023-07-08 jrick const struct got_error *pack_err =
3339 3d1b16d1 2023-07-08 jrick got_repo_pack_fds_close(pack_fds);
3340 3d1b16d1 2023-07-08 jrick if (error == NULL)
3341 3d1b16d1 2023-07-08 jrick error = pack_err;
3343 624411d2 2023-07-08 jrick got_pathlist_free(&paths, GOT_PATHLIST_FREE_PATH);
3344 3d1b16d1 2023-07-08 jrick got_pathlist_free(&refs, GOT_PATHLIST_FREE_ALL);
3345 3d1b16d1 2023-07-08 jrick got_pathlist_free(&symrefs, GOT_PATHLIST_FREE_ALL);
3346 3d1b16d1 2023-07-08 jrick got_pathlist_free(&wanted_branches, GOT_PATHLIST_FREE_NONE);
3347 3d1b16d1 2023-07-08 jrick got_pathlist_free(&wanted_refs, GOT_PATHLIST_FREE_NONE);
3348 3d1b16d1 2023-07-08 jrick got_ref_list_free(&remote_refs);
3349 3d1b16d1 2023-07-08 jrick free(id_str);
3350 3d1b16d1 2023-07-08 jrick free(worktree_path);
3351 3d1b16d1 2023-07-08 jrick free(pack_hash);
3352 3d1b16d1 2023-07-08 jrick free(proto);
3353 3d1b16d1 2023-07-08 jrick free(host);
3354 3d1b16d1 2023-07-08 jrick free(port);
3355 3d1b16d1 2023-07-08 jrick free(server_path);
3356 3d1b16d1 2023-07-08 jrick free(repo_name);
3357 624411d2 2023-07-08 jrick free(commit_id);
3358 624411d2 2023-07-08 jrick free(commit_id_str);
3359 624411d2 2023-07-08 jrick return error;
3362 624411d2 2023-07-08 jrick static const struct got_error *
3363 624411d2 2023-07-08 jrick diff_blobs(struct got_object_id *blob_id1, struct got_object_id *blob_id2,
3364 624411d2 2023-07-08 jrick const char *path, int diff_context, int ignore_whitespace,
3365 624411d2 2023-07-08 jrick int force_text_diff, struct got_diffstat_cb_arg *dsa,
3366 624411d2 2023-07-08 jrick struct got_repository *repo, FILE *outfile)
3368 624411d2 2023-07-08 jrick const struct got_error *err = NULL;
3369 624411d2 2023-07-08 jrick struct got_blob_object *blob1 = NULL, *blob2 = NULL;
3370 624411d2 2023-07-08 jrick FILE *f1 = NULL, *f2 = NULL;
3371 624411d2 2023-07-08 jrick int fd1 = -1, fd2 = -1;
3373 624411d2 2023-07-08 jrick fd1 = got_opentempfd();
3374 624411d2 2023-07-08 jrick if (fd1 == -1)
3375 624411d2 2023-07-08 jrick return got_error_from_errno("got_opentempfd");
3376 624411d2 2023-07-08 jrick fd2 = got_opentempfd();
3377 624411d2 2023-07-08 jrick if (fd2 == -1) {
3378 624411d2 2023-07-08 jrick err = got_error_from_errno("got_opentempfd");
3379 624411d2 2023-07-08 jrick goto done;
3382 624411d2 2023-07-08 jrick if (blob_id1) {
3383 624411d2 2023-07-08 jrick err = got_object_open_as_blob(&blob1, repo, blob_id1, 8192,
3386 624411d2 2023-07-08 jrick goto done;
3389 624411d2 2023-07-08 jrick err = got_object_open_as_blob(&blob2, repo, blob_id2, 8192, fd2);
3391 624411d2 2023-07-08 jrick goto done;
3393 624411d2 2023-07-08 jrick f1 = got_opentemp();
3394 624411d2 2023-07-08 jrick if (f1 == NULL) {
3395 624411d2 2023-07-08 jrick err = got_error_from_errno("got_opentemp");
3396 624411d2 2023-07-08 jrick goto done;
3398 624411d2 2023-07-08 jrick f2 = got_opentemp();
3399 624411d2 2023-07-08 jrick if (f2 == NULL) {
3400 624411d2 2023-07-08 jrick err = got_error_from_errno("got_opentemp");
3401 624411d2 2023-07-08 jrick goto done;
3404 624411d2 2023-07-08 jrick while (path[0] == '/')
3406 624411d2 2023-07-08 jrick err = got_diff_blob(NULL, NULL, blob1, blob2, f1, f2, path, path,
3407 624411d2 2023-07-08 jrick GOT_DIFF_ALGORITHM_PATIENCE, diff_context, ignore_whitespace,
3408 624411d2 2023-07-08 jrick force_text_diff, dsa, outfile);
3410 624411d2 2023-07-08 jrick if (fd1 != -1 && close(fd1) == -1 && err == NULL)
3411 624411d2 2023-07-08 jrick err = got_error_from_errno("close");
3412 624411d2 2023-07-08 jrick if (blob1)
3413 624411d2 2023-07-08 jrick got_object_blob_close(blob1);
3414 624411d2 2023-07-08 jrick if (fd2 != -1 && close(fd2) == -1 && err == NULL)
3415 624411d2 2023-07-08 jrick err = got_error_from_errno("close");
3416 624411d2 2023-07-08 jrick if (blob2)
3417 624411d2 2023-07-08 jrick got_object_blob_close(blob2);
3418 624411d2 2023-07-08 jrick if (f1 && fclose(f1) == EOF && err == NULL)
3419 624411d2 2023-07-08 jrick err = got_error_from_errno("fclose");
3420 624411d2 2023-07-08 jrick if (f2 && fclose(f2) == EOF && err == NULL)
3421 624411d2 2023-07-08 jrick err = got_error_from_errno("fclose");
3422 624411d2 2023-07-08 jrick return err;
3425 624411d2 2023-07-08 jrick static const struct got_error *
3426 624411d2 2023-07-08 jrick diff_trees(struct got_object_id *tree_id1, struct got_object_id *tree_id2,
3427 624411d2 2023-07-08 jrick const char *path, int diff_context, int ignore_whitespace,
3428 624411d2 2023-07-08 jrick int force_text_diff, struct got_diffstat_cb_arg *dsa,
3429 624411d2 2023-07-08 jrick struct got_repository *repo, FILE *outfile)
3431 624411d2 2023-07-08 jrick const struct got_error *err = NULL;
3432 624411d2 2023-07-08 jrick struct got_tree_object *tree1 = NULL, *tree2 = NULL;
3433 624411d2 2023-07-08 jrick struct got_diff_blob_output_unidiff_arg arg;
3434 624411d2 2023-07-08 jrick FILE *f1 = NULL, *f2 = NULL;
3435 624411d2 2023-07-08 jrick int fd1 = -1, fd2 = -1;
3437 624411d2 2023-07-08 jrick if (tree_id1) {
3438 624411d2 2023-07-08 jrick err = got_object_open_as_tree(&tree1, repo, tree_id1);
3440 624411d2 2023-07-08 jrick goto done;
3441 624411d2 2023-07-08 jrick fd1 = got_opentempfd();
3442 624411d2 2023-07-08 jrick if (fd1 == -1) {
3443 624411d2 2023-07-08 jrick err = got_error_from_errno("got_opentempfd");
3444 624411d2 2023-07-08 jrick goto done;
3448 624411d2 2023-07-08 jrick err = got_object_open_as_tree(&tree2, repo, tree_id2);
3450 624411d2 2023-07-08 jrick goto done;
3452 624411d2 2023-07-08 jrick f1 = got_opentemp();
3453 624411d2 2023-07-08 jrick if (f1 == NULL) {
3454 624411d2 2023-07-08 jrick err = got_error_from_errno("got_opentemp");
3455 624411d2 2023-07-08 jrick goto done;
3458 624411d2 2023-07-08 jrick f2 = got_opentemp();
3459 624411d2 2023-07-08 jrick if (f2 == NULL) {
3460 624411d2 2023-07-08 jrick err = got_error_from_errno("got_opentemp");
3461 624411d2 2023-07-08 jrick goto done;
3463 624411d2 2023-07-08 jrick fd2 = got_opentempfd();
3464 624411d2 2023-07-08 jrick if (fd2 == -1) {
3465 624411d2 2023-07-08 jrick err = got_error_from_errno("got_opentempfd");
3466 624411d2 2023-07-08 jrick goto done;
3468 624411d2 2023-07-08 jrick arg.diff_context = diff_context;
3469 624411d2 2023-07-08 jrick arg.ignore_whitespace = ignore_whitespace;
3470 624411d2 2023-07-08 jrick arg.force_text_diff = force_text_diff;
3471 624411d2 2023-07-08 jrick arg.diffstat = dsa;
3472 624411d2 2023-07-08 jrick arg.diff_algo = GOT_DIFF_ALGORITHM_PATIENCE;
3473 624411d2 2023-07-08 jrick arg.outfile = outfile;
3474 624411d2 2023-07-08 jrick arg.lines = NULL;
3475 624411d2 2023-07-08 jrick arg.nlines = 0;
3476 624411d2 2023-07-08 jrick while (path[0] == '/')
3478 624411d2 2023-07-08 jrick err = got_diff_tree(tree1, tree2, f1, f2, fd1, fd2, path, path, repo,
3479 624411d2 2023-07-08 jrick got_diff_blob_output_unidiff, &arg, 1);
3481 624411d2 2023-07-08 jrick if (tree1)
3482 624411d2 2023-07-08 jrick got_object_tree_close(tree1);
3483 624411d2 2023-07-08 jrick if (tree2)
3484 624411d2 2023-07-08 jrick got_object_tree_close(tree2);
3485 624411d2 2023-07-08 jrick if (f1 && fclose(f1) == EOF && err == NULL)
3486 624411d2 2023-07-08 jrick err = got_error_from_errno("fclose");
3487 624411d2 2023-07-08 jrick if (f2 && fclose(f2) == EOF && err == NULL)
3488 624411d2 2023-07-08 jrick err = got_error_from_errno("fclose");
3489 624411d2 2023-07-08 jrick if (fd1 != -1 && close(fd1) == -1 && err == NULL)
3490 624411d2 2023-07-08 jrick err = got_error_from_errno("close");
3491 624411d2 2023-07-08 jrick if (fd2 != -1 && close(fd2) == -1 && err == NULL)
3492 624411d2 2023-07-08 jrick err = got_error_from_errno("close");
3493 624411d2 2023-07-08 jrick return err;
3496 624411d2 2023-07-08 jrick static const struct got_error *
3497 624411d2 2023-07-08 jrick get_changed_paths(struct got_pathlist_head *paths,
3498 624411d2 2023-07-08 jrick struct got_commit_object *commit, struct got_repository *repo,
3499 624411d2 2023-07-08 jrick struct got_diffstat_cb_arg *dsa)
3501 624411d2 2023-07-08 jrick const struct got_error *err = NULL;
3502 624411d2 2023-07-08 jrick struct got_object_id *tree_id1 = NULL, *tree_id2 = NULL;
3503 624411d2 2023-07-08 jrick struct got_tree_object *tree1 = NULL, *tree2 = NULL;
3504 624411d2 2023-07-08 jrick struct got_object_qid *qid;
3505 624411d2 2023-07-08 jrick got_diff_blob_cb cb = got_diff_tree_collect_changed_paths;
3506 624411d2 2023-07-08 jrick FILE *f1 = NULL, *f2 = NULL;
3507 624411d2 2023-07-08 jrick int fd1 = -1, fd2 = -1;
3509 624411d2 2023-07-08 jrick if (dsa) {
3510 624411d2 2023-07-08 jrick cb = got_diff_tree_compute_diffstat;
3512 624411d2 2023-07-08 jrick f1 = got_opentemp();
3513 624411d2 2023-07-08 jrick if (f1 == NULL) {
3514 624411d2 2023-07-08 jrick err = got_error_from_errno("got_opentemp");
3515 624411d2 2023-07-08 jrick goto done;
3517 624411d2 2023-07-08 jrick f2 = got_opentemp();
3518 624411d2 2023-07-08 jrick if (f2 == NULL) {
3519 624411d2 2023-07-08 jrick err = got_error_from_errno("got_opentemp");
3520 624411d2 2023-07-08 jrick goto done;
3522 624411d2 2023-07-08 jrick fd1 = got_opentempfd();
3523 624411d2 2023-07-08 jrick if (fd1 == -1) {
3524 624411d2 2023-07-08 jrick err = got_error_from_errno("got_opentempfd");
3525 624411d2 2023-07-08 jrick goto done;
3527 624411d2 2023-07-08 jrick fd2 = got_opentempfd();
3528 624411d2 2023-07-08 jrick if (fd2 == -1) {
3529 624411d2 2023-07-08 jrick err = got_error_from_errno("got_opentempfd");
3530 624411d2 2023-07-08 jrick goto done;
3534 624411d2 2023-07-08 jrick qid = STAILQ_FIRST(got_object_commit_get_parent_ids(commit));
3535 624411d2 2023-07-08 jrick if (qid != NULL) {
3536 624411d2 2023-07-08 jrick struct got_commit_object *pcommit;
3537 624411d2 2023-07-08 jrick err = got_object_open_as_commit(&pcommit, repo,
3538 624411d2 2023-07-08 jrick &qid->id);
3540 624411d2 2023-07-08 jrick return err;
3542 624411d2 2023-07-08 jrick tree_id1 = got_object_id_dup(
3543 624411d2 2023-07-08 jrick got_object_commit_get_tree_id(pcommit));
3544 624411d2 2023-07-08 jrick if (tree_id1 == NULL) {
3545 624411d2 2023-07-08 jrick got_object_commit_close(pcommit);
3546 624411d2 2023-07-08 jrick return got_error_from_errno("got_object_id_dup");
3548 624411d2 2023-07-08 jrick got_object_commit_close(pcommit);
3552 624411d2 2023-07-08 jrick if (tree_id1) {
3553 624411d2 2023-07-08 jrick err = got_object_open_as_tree(&tree1, repo, tree_id1);
3555 624411d2 2023-07-08 jrick goto done;
3558 624411d2 2023-07-08 jrick tree_id2 = got_object_commit_get_tree_id(commit);
3559 624411d2 2023-07-08 jrick err = got_object_open_as_tree(&tree2, repo, tree_id2);
3561 624411d2 2023-07-08 jrick goto done;
3563 624411d2 2023-07-08 jrick err = got_diff_tree(tree1, tree2, f1, f2, fd1, fd2, "", "", repo,
3564 624411d2 2023-07-08 jrick cb, dsa ? (void *)dsa : paths, dsa ? 1 : 0);
3566 624411d2 2023-07-08 jrick if (tree1)
3567 624411d2 2023-07-08 jrick got_object_tree_close(tree1);
3568 624411d2 2023-07-08 jrick if (tree2)
3569 624411d2 2023-07-08 jrick got_object_tree_close(tree2);
3570 624411d2 2023-07-08 jrick if (fd1 != -1 && close(fd1) == -1 && err == NULL)
3571 624411d2 2023-07-08 jrick err = got_error_from_errno("close");
3572 624411d2 2023-07-08 jrick if (fd2 != -1 && close(fd2) == -1 && err == NULL)
3573 624411d2 2023-07-08 jrick err = got_error_from_errno("close");
3574 624411d2 2023-07-08 jrick if (f1 && fclose(f1) == EOF && err == NULL)
3575 624411d2 2023-07-08 jrick err = got_error_from_errno("fclose");
3576 624411d2 2023-07-08 jrick if (f2 && fclose(f2) == EOF && err == NULL)
3577 624411d2 2023-07-08 jrick err = got_error_from_errno("fclose");
3578 624411d2 2023-07-08 jrick free(tree_id1);
3579 624411d2 2023-07-08 jrick return err;
3582 624411d2 2023-07-08 jrick static const struct got_error *
3583 624411d2 2023-07-08 jrick print_patch(struct got_commit_object *commit, struct got_object_id *id,
3584 624411d2 2023-07-08 jrick const char *path, int diff_context, struct got_diffstat_cb_arg *dsa,
3585 624411d2 2023-07-08 jrick struct got_repository *repo, FILE *outfile)
3587 624411d2 2023-07-08 jrick const struct got_error *err = NULL;
3588 624411d2 2023-07-08 jrick struct got_commit_object *pcommit = NULL;
3589 624411d2 2023-07-08 jrick char *id_str1 = NULL, *id_str2 = NULL;
3590 624411d2 2023-07-08 jrick struct got_object_id *obj_id1 = NULL, *obj_id2 = NULL;
3591 624411d2 2023-07-08 jrick struct got_object_qid *qid;
3593 624411d2 2023-07-08 jrick qid = STAILQ_FIRST(got_object_commit_get_parent_ids(commit));
3594 624411d2 2023-07-08 jrick if (qid != NULL) {
3595 624411d2 2023-07-08 jrick err = got_object_open_as_commit(&pcommit, repo,
3596 624411d2 2023-07-08 jrick &qid->id);
3598 624411d2 2023-07-08 jrick return err;
3599 624411d2 2023-07-08 jrick err = got_object_id_str(&id_str1, &qid->id);
3601 624411d2 2023-07-08 jrick goto done;
3604 624411d2 2023-07-08 jrick err = got_object_id_str(&id_str2, id);
3606 624411d2 2023-07-08 jrick goto done;
3608 624411d2 2023-07-08 jrick if (path && path[0] != '\0') {
3609 624411d2 2023-07-08 jrick int obj_type;
3610 624411d2 2023-07-08 jrick err = got_object_id_by_path(&obj_id2, repo, commit, path);
3612 624411d2 2023-07-08 jrick goto done;
3613 624411d2 2023-07-08 jrick if (pcommit) {
3614 624411d2 2023-07-08 jrick err = got_object_id_by_path(&obj_id1, repo,
3615 624411d2 2023-07-08 jrick pcommit, path);
3616 624411d2 2023-07-08 jrick if (err) {
3617 624411d2 2023-07-08 jrick if (err->code != GOT_ERR_NO_TREE_ENTRY) {
3618 624411d2 2023-07-08 jrick free(obj_id2);
3619 624411d2 2023-07-08 jrick goto done;
3623 624411d2 2023-07-08 jrick err = got_object_get_type(&obj_type, repo, obj_id2);
3624 624411d2 2023-07-08 jrick if (err) {
3625 624411d2 2023-07-08 jrick free(obj_id2);
3626 624411d2 2023-07-08 jrick goto done;
3628 624411d2 2023-07-08 jrick fprintf(outfile,
3629 624411d2 2023-07-08 jrick "diff %s %s\n", id_str1 ? id_str1 : "/dev/null", id_str2);
3630 624411d2 2023-07-08 jrick fprintf(outfile, "commit - %s\n",
3631 624411d2 2023-07-08 jrick id_str1 ? id_str1 : "/dev/null");
3632 624411d2 2023-07-08 jrick fprintf(outfile, "commit + %s\n", id_str2);
3633 624411d2 2023-07-08 jrick switch (obj_type) {
3634 624411d2 2023-07-08 jrick case GOT_OBJ_TYPE_BLOB:
3635 624411d2 2023-07-08 jrick err = diff_blobs(obj_id1, obj_id2, path, diff_context,
3636 624411d2 2023-07-08 jrick 0, 0, dsa, repo, outfile);
3638 624411d2 2023-07-08 jrick case GOT_OBJ_TYPE_TREE:
3639 624411d2 2023-07-08 jrick err = diff_trees(obj_id1, obj_id2, path, diff_context,
3640 624411d2 2023-07-08 jrick 0, 0, dsa, repo, outfile);
3643 624411d2 2023-07-08 jrick err = got_error(GOT_ERR_OBJ_TYPE);
3646 624411d2 2023-07-08 jrick free(obj_id1);
3647 624411d2 2023-07-08 jrick free(obj_id2);
3649 624411d2 2023-07-08 jrick obj_id2 = got_object_commit_get_tree_id(commit);
3650 624411d2 2023-07-08 jrick if (pcommit)
3651 624411d2 2023-07-08 jrick obj_id1 = got_object_commit_get_tree_id(pcommit);
3652 624411d2 2023-07-08 jrick fprintf(outfile,
3653 624411d2 2023-07-08 jrick "diff %s %s\n", id_str1 ? id_str1 : "/dev/null", id_str2);
3654 624411d2 2023-07-08 jrick fprintf(outfile, "commit - %s\n",
3655 624411d2 2023-07-08 jrick id_str1 ? id_str1 : "/dev/null");
3656 624411d2 2023-07-08 jrick fprintf(outfile, "commit + %s\n", id_str2);
3657 624411d2 2023-07-08 jrick err = diff_trees(obj_id1, obj_id2, "", diff_context, 0, 0,
3658 624411d2 2023-07-08 jrick dsa, repo, outfile);
3661 624411d2 2023-07-08 jrick free(id_str1);
3662 624411d2 2023-07-08 jrick free(id_str2);
3663 624411d2 2023-07-08 jrick if (pcommit)
3664 624411d2 2023-07-08 jrick got_object_commit_close(pcommit);
3665 624411d2 2023-07-08 jrick return err;
3668 624411d2 2023-07-08 jrick static char *
3669 624411d2 2023-07-08 jrick get_datestr(time_t *time, char *datebuf)
3671 624411d2 2023-07-08 jrick struct tm mytm, *tm;
3672 624411d2 2023-07-08 jrick char *p, *s;
3674 624411d2 2023-07-08 jrick tm = gmtime_r(time, &mytm);
3675 624411d2 2023-07-08 jrick if (tm == NULL)
3676 624411d2 2023-07-08 jrick return NULL;
3677 624411d2 2023-07-08 jrick s = asctime_r(tm, datebuf);
3678 624411d2 2023-07-08 jrick if (s == NULL)
3679 624411d2 2023-07-08 jrick return NULL;
3680 624411d2 2023-07-08 jrick p = strchr(s, '\n');
3682 624411d2 2023-07-08 jrick *p = '\0';
3683 624411d2 2023-07-08 jrick return s;
3686 624411d2 2023-07-08 jrick static const struct got_error *
3687 624411d2 2023-07-08 jrick match_commit(int *have_match, struct got_object_id *id,
3688 624411d2 2023-07-08 jrick struct got_commit_object *commit, regex_t *regex)
3690 624411d2 2023-07-08 jrick const struct got_error *err = NULL;
3691 624411d2 2023-07-08 jrick regmatch_t regmatch;
3692 624411d2 2023-07-08 jrick char *id_str = NULL, *logmsg = NULL;
3694 624411d2 2023-07-08 jrick *have_match = 0;
3696 624411d2 2023-07-08 jrick err = got_object_id_str(&id_str, id);
3698 624411d2 2023-07-08 jrick return err;
3700 624411d2 2023-07-08 jrick err = got_object_commit_get_logmsg(&logmsg, commit);
3702 624411d2 2023-07-08 jrick goto done;
3704 624411d2 2023-07-08 jrick if (regexec(regex, got_object_commit_get_author(commit), 1,
3705 624411d2 2023-07-08 jrick ®match, 0) == 0 ||
3706 624411d2 2023-07-08 jrick regexec(regex, got_object_commit_get_committer(commit), 1,
3707 624411d2 2023-07-08 jrick ®match, 0) == 0 ||
3708 624411d2 2023-07-08 jrick regexec(regex, id_str, 1, ®match, 0) == 0 ||
3709 624411d2 2023-07-08 jrick regexec(regex, logmsg, 1, ®match, 0) == 0)
3710 624411d2 2023-07-08 jrick *have_match = 1;
3712 624411d2 2023-07-08 jrick free(id_str);
3713 624411d2 2023-07-08 jrick free(logmsg);
3714 624411d2 2023-07-08 jrick return err;
3717 624411d2 2023-07-08 jrick static void
3718 624411d2 2023-07-08 jrick match_changed_paths(int *have_match, struct got_pathlist_head *changed_paths,
3719 624411d2 2023-07-08 jrick regex_t *regex)
3721 624411d2 2023-07-08 jrick regmatch_t regmatch;
3722 624411d2 2023-07-08 jrick struct got_pathlist_entry *pe;
3724 624411d2 2023-07-08 jrick *have_match = 0;
3726 624411d2 2023-07-08 jrick TAILQ_FOREACH(pe, changed_paths, entry) {
3727 624411d2 2023-07-08 jrick if (regexec(regex, pe->path, 1, ®match, 0) == 0) {
3728 624411d2 2023-07-08 jrick *have_match = 1;
3734 624411d2 2023-07-08 jrick static const struct got_error *
3735 624411d2 2023-07-08 jrick match_patch(int *have_match, struct got_commit_object *commit,
3736 624411d2 2023-07-08 jrick struct got_object_id *id, const char *path, int diff_context,
3737 624411d2 2023-07-08 jrick struct got_repository *repo, regex_t *regex, FILE *f)
3739 624411d2 2023-07-08 jrick const struct got_error *err = NULL;
3740 624411d2 2023-07-08 jrick char *line = NULL;
3741 624411d2 2023-07-08 jrick size_t linesize = 0;
3742 624411d2 2023-07-08 jrick regmatch_t regmatch;
3744 624411d2 2023-07-08 jrick *have_match = 0;
3746 624411d2 2023-07-08 jrick err = got_opentemp_truncate(f);
3748 624411d2 2023-07-08 jrick return err;
3750 624411d2 2023-07-08 jrick err = print_patch(commit, id, path, diff_context, NULL, repo, f);
3752 624411d2 2023-07-08 jrick goto done;
3754 624411d2 2023-07-08 jrick if (fseeko(f, 0L, SEEK_SET) == -1) {
3755 624411d2 2023-07-08 jrick err = got_error_from_errno("fseeko");
3756 624411d2 2023-07-08 jrick goto done;
3759 624411d2 2023-07-08 jrick while (getline(&line, &linesize, f) != -1) {
3760 624411d2 2023-07-08 jrick if (regexec(regex, line, 1, ®match, 0) == 0) {
3761 624411d2 2023-07-08 jrick *have_match = 1;
3766 624411d2 2023-07-08 jrick free(line);
3767 624411d2 2023-07-08 jrick return err;
3770 624411d2 2023-07-08 jrick #define GOT_COMMIT_SEP_STR "-----------------------------------------------\n"
3772 624411d2 2023-07-08 jrick static const struct got_error*
3773 624411d2 2023-07-08 jrick build_refs_str(char **refs_str, struct got_reflist_head *refs,
3774 624411d2 2023-07-08 jrick struct got_object_id *id, struct got_repository *repo,
3775 624411d2 2023-07-08 jrick int local_only)
3777 624411d2 2023-07-08 jrick static const struct got_error *err = NULL;
3778 624411d2 2023-07-08 jrick struct got_reflist_entry *re;
3780 624411d2 2023-07-08 jrick const char *name;
3782 624411d2 2023-07-08 jrick *refs_str = NULL;
3784 624411d2 2023-07-08 jrick TAILQ_FOREACH(re, refs, entry) {
3785 624411d2 2023-07-08 jrick struct got_tag_object *tag = NULL;
3786 624411d2 2023-07-08 jrick struct got_object_id *ref_id;
3789 624411d2 2023-07-08 jrick name = got_ref_get_name(re->ref);
3790 624411d2 2023-07-08 jrick if (strcmp(name, GOT_REF_HEAD) == 0)
3791 624411d2 2023-07-08 jrick continue;
3792 624411d2 2023-07-08 jrick if (strncmp(name, "refs/", 5) == 0)
3793 624411d2 2023-07-08 jrick name += 5;
3794 624411d2 2023-07-08 jrick if (strncmp(name, "got/", 4) == 0)
3795 624411d2 2023-07-08 jrick continue;
3796 624411d2 2023-07-08 jrick if (strncmp(name, "heads/", 6) == 0)
3797 624411d2 2023-07-08 jrick name += 6;
3798 624411d2 2023-07-08 jrick if (strncmp(name, "remotes/", 8) == 0) {
3799 624411d2 2023-07-08 jrick if (local_only)
3800 624411d2 2023-07-08 jrick continue;
3801 624411d2 2023-07-08 jrick name += 8;
3802 624411d2 2023-07-08 jrick s = strstr(name, "/" GOT_REF_HEAD);
3803 624411d2 2023-07-08 jrick if (s != NULL && strcmp(s, "/" GOT_REF_HEAD) == 0)
3804 624411d2 2023-07-08 jrick continue;
3806 624411d2 2023-07-08 jrick err = got_ref_resolve(&ref_id, repo, re->ref);
3809 624411d2 2023-07-08 jrick if (strncmp(name, "tags/", 5) == 0) {
3810 624411d2 2023-07-08 jrick err = got_object_open_as_tag(&tag, repo, ref_id);
3811 624411d2 2023-07-08 jrick if (err) {
3812 624411d2 2023-07-08 jrick if (err->code != GOT_ERR_OBJ_TYPE) {
3813 624411d2 2023-07-08 jrick free(ref_id);
3816 624411d2 2023-07-08 jrick /* Ref points at something other than a tag. */
3817 624411d2 2023-07-08 jrick err = NULL;
3818 624411d2 2023-07-08 jrick tag = NULL;
3821 624411d2 2023-07-08 jrick cmp = got_object_id_cmp(tag ?
3822 624411d2 2023-07-08 jrick got_object_tag_get_object_id(tag) : ref_id, id);
3823 624411d2 2023-07-08 jrick free(ref_id);
3825 624411d2 2023-07-08 jrick got_object_tag_close(tag);
3826 624411d2 2023-07-08 jrick if (cmp != 0)
3827 624411d2 2023-07-08 jrick continue;
3828 624411d2 2023-07-08 jrick s = *refs_str;
3829 624411d2 2023-07-08 jrick if (asprintf(refs_str, "%s%s%s", s ? s : "",
3830 624411d2 2023-07-08 jrick s ? ", " : "", name) == -1) {
3831 624411d2 2023-07-08 jrick err = got_error_from_errno("asprintf");
3833 624411d2 2023-07-08 jrick *refs_str = NULL;
3839 624411d2 2023-07-08 jrick return err;
3842 624411d2 2023-07-08 jrick static const struct got_error *
3843 624411d2 2023-07-08 jrick print_commit_oneline(struct got_commit_object *commit, struct got_object_id *id,
3844 624411d2 2023-07-08 jrick struct got_repository *repo, struct got_reflist_object_id_map *refs_idmap)
3846 624411d2 2023-07-08 jrick const struct got_error *err = NULL;
3847 624411d2 2023-07-08 jrick char *ref_str = NULL, *id_str = NULL, *logmsg0 = NULL;
3848 624411d2 2023-07-08 jrick char *comma, *s, *nl;
3849 624411d2 2023-07-08 jrick struct got_reflist_head *refs;
3850 624411d2 2023-07-08 jrick char datebuf[12]; /* YYYY-MM-DD + SPACE + NUL */
3851 624411d2 2023-07-08 jrick struct tm tm;
3852 624411d2 2023-07-08 jrick time_t committer_time;
3854 624411d2 2023-07-08 jrick refs = got_reflist_object_id_map_lookup(refs_idmap, id);
3855 624411d2 2023-07-08 jrick if (refs) {
3856 624411d2 2023-07-08 jrick err = build_refs_str(&ref_str, refs, id, repo, 1);
3858 624411d2 2023-07-08 jrick return err;
3860 624411d2 2023-07-08 jrick /* Display the first matching ref only. */
3861 624411d2 2023-07-08 jrick if (ref_str && (comma = strchr(ref_str, ',')) != NULL)
3862 624411d2 2023-07-08 jrick *comma = '\0';
3865 624411d2 2023-07-08 jrick if (ref_str == NULL) {
3866 624411d2 2023-07-08 jrick err = got_object_id_str(&id_str, id);
3868 624411d2 2023-07-08 jrick return err;
3871 624411d2 2023-07-08 jrick committer_time = got_object_commit_get_committer_time(commit);
3872 624411d2 2023-07-08 jrick if (gmtime_r(&committer_time, &tm) == NULL) {
3873 624411d2 2023-07-08 jrick err = got_error_from_errno("gmtime_r");
3874 624411d2 2023-07-08 jrick goto done;
3876 624411d2 2023-07-08 jrick if (strftime(datebuf, sizeof(datebuf), "%G-%m-%d ", &tm) == 0) {
3877 624411d2 2023-07-08 jrick err = got_error(GOT_ERR_NO_SPACE);
3878 624411d2 2023-07-08 jrick goto done;
3881 624411d2 2023-07-08 jrick err = got_object_commit_get_logmsg(&logmsg0, commit);
3883 624411d2 2023-07-08 jrick goto done;
3885 624411d2 2023-07-08 jrick s = logmsg0;
3886 624411d2 2023-07-08 jrick while (isspace((unsigned char)s[0]))
3889 624411d2 2023-07-08 jrick nl = strchr(s, '\n');
3890 624411d2 2023-07-08 jrick if (nl) {
3891 624411d2 2023-07-08 jrick *nl = '\0';
3894 624411d2 2023-07-08 jrick if (ref_str)
3895 624411d2 2023-07-08 jrick printf("%s%-7s %s\n", datebuf, ref_str, s);
3897 624411d2 2023-07-08 jrick printf("%s%.7s %s\n", datebuf, id_str, s);
3899 624411d2 2023-07-08 jrick if (fflush(stdout) != 0 && err == NULL)
3900 624411d2 2023-07-08 jrick err = got_error_from_errno("fflush");
3902 624411d2 2023-07-08 jrick free(id_str);
3903 624411d2 2023-07-08 jrick free(ref_str);
3904 624411d2 2023-07-08 jrick free(logmsg0);
3905 624411d2 2023-07-08 jrick return err;
3908 624411d2 2023-07-08 jrick static const struct got_error *
3909 624411d2 2023-07-08 jrick print_diffstat(struct got_diffstat_cb_arg *dsa, const char *header)
3911 624411d2 2023-07-08 jrick struct got_pathlist_entry *pe;
3913 624411d2 2023-07-08 jrick if (header != NULL)
3914 624411d2 2023-07-08 jrick printf("%s\n", header);
3916 624411d2 2023-07-08 jrick TAILQ_FOREACH(pe, dsa->paths, entry) {
3917 624411d2 2023-07-08 jrick struct got_diff_changed_path *cp = pe->data;
3918 624411d2 2023-07-08 jrick int pad = dsa->max_path_len - pe->path_len + 1;
3920 624411d2 2023-07-08 jrick printf(" %c %s%*c | %*d+ %*d-\n", cp->status, pe->path, pad,
3921 624411d2 2023-07-08 jrick ' ', dsa->add_cols + 1, cp->add, dsa->rm_cols + 1, cp->rm);
3923 624411d2 2023-07-08 jrick printf("\n%d file%s changed, %d insertion%s(+), %d deletion%s(-)\n\n",
3924 624411d2 2023-07-08 jrick dsa->nfiles, dsa->nfiles > 1 ? "s" : "", dsa->ins,
3925 624411d2 2023-07-08 jrick dsa->ins != 1 ? "s" : "", dsa->del, dsa->del != 1 ? "s" : "");
3927 624411d2 2023-07-08 jrick if (fflush(stdout) != 0)
3928 624411d2 2023-07-08 jrick return got_error_from_errno("fflush");
3930 624411d2 2023-07-08 jrick return NULL;
3933 624411d2 2023-07-08 jrick static const struct got_error *
3934 624411d2 2023-07-08 jrick printfile(FILE *f)
3936 624411d2 2023-07-08 jrick char buf[8192];
3937 624411d2 2023-07-08 jrick size_t r;
3939 624411d2 2023-07-08 jrick if (fseeko(f, 0L, SEEK_SET) == -1)
3940 624411d2 2023-07-08 jrick return got_error_from_errno("fseek");
3942 624411d2 2023-07-08 jrick for (;;) {
3943 624411d2 2023-07-08 jrick r = fread(buf, 1, sizeof(buf), f);
3944 624411d2 2023-07-08 jrick if (r == 0) {
3945 624411d2 2023-07-08 jrick if (ferror(f))
3946 624411d2 2023-07-08 jrick return got_error_from_errno("fread");
3947 624411d2 2023-07-08 jrick if (feof(f))
3950 624411d2 2023-07-08 jrick if (fwrite(buf, 1, r, stdout) != r)
3951 624411d2 2023-07-08 jrick return got_ferror(stdout, GOT_ERR_IO);
3954 624411d2 2023-07-08 jrick return NULL;
3957 624411d2 2023-07-08 jrick static const struct got_error *
3958 624411d2 2023-07-08 jrick print_commit(struct got_commit_object *commit, struct got_object_id *id,
3959 624411d2 2023-07-08 jrick struct got_repository *repo, const char *path,
3960 624411d2 2023-07-08 jrick struct got_pathlist_head *changed_paths,
3961 624411d2 2023-07-08 jrick struct got_diffstat_cb_arg *diffstat, int show_patch, int diff_context,
3962 624411d2 2023-07-08 jrick struct got_reflist_object_id_map *refs_idmap, const char *custom_refs_str,
3963 624411d2 2023-07-08 jrick const char *prefix)
3965 624411d2 2023-07-08 jrick const struct got_error *err = NULL;
3966 624411d2 2023-07-08 jrick FILE *f = NULL;
3967 624411d2 2023-07-08 jrick char *id_str, *datestr, *logmsg0, *logmsg, *line;
3968 624411d2 2023-07-08 jrick char datebuf[26];
3969 624411d2 2023-07-08 jrick time_t committer_time;
3970 624411d2 2023-07-08 jrick const char *author, *committer;
3971 624411d2 2023-07-08 jrick char *refs_str = NULL;
3973 624411d2 2023-07-08 jrick err = got_object_id_str(&id_str, id);
3975 624411d2 2023-07-08 jrick return err;
3977 624411d2 2023-07-08 jrick if (custom_refs_str == NULL) {
3978 624411d2 2023-07-08 jrick struct got_reflist_head *refs;
3979 624411d2 2023-07-08 jrick refs = got_reflist_object_id_map_lookup(refs_idmap, id);
3980 624411d2 2023-07-08 jrick if (refs) {
3981 624411d2 2023-07-08 jrick err = build_refs_str(&refs_str, refs, id, repo, 0);
3983 624411d2 2023-07-08 jrick goto done;
3987 624411d2 2023-07-08 jrick printf(GOT_COMMIT_SEP_STR);
3988 624411d2 2023-07-08 jrick if (custom_refs_str)
3989 624411d2 2023-07-08 jrick printf("%s %s (%s)\n", prefix ? prefix : "commit", id_str,
3990 624411d2 2023-07-08 jrick custom_refs_str);
3992 624411d2 2023-07-08 jrick printf("%s %s%s%s%s\n", prefix ? prefix : "commit", id_str,
3993 624411d2 2023-07-08 jrick refs_str ? " (" : "", refs_str ? refs_str : "",
3994 624411d2 2023-07-08 jrick refs_str ? ")" : "");
3995 624411d2 2023-07-08 jrick free(id_str);
3996 624411d2 2023-07-08 jrick id_str = NULL;
3997 624411d2 2023-07-08 jrick free(refs_str);
3998 624411d2 2023-07-08 jrick refs_str = NULL;
3999 624411d2 2023-07-08 jrick printf("from: %s\n", got_object_commit_get_author(commit));
4000 624411d2 2023-07-08 jrick author = got_object_commit_get_author(commit);
4001 624411d2 2023-07-08 jrick committer = got_object_commit_get_committer(commit);
4002 624411d2 2023-07-08 jrick if (strcmp(author, committer) != 0)
4003 624411d2 2023-07-08 jrick printf("via: %s\n", committer);
4004 624411d2 2023-07-08 jrick committer_time = got_object_commit_get_committer_time(commit);
4005 624411d2 2023-07-08 jrick datestr = get_datestr(&committer_time, datebuf);
4006 624411d2 2023-07-08 jrick if (datestr)
4007 624411d2 2023-07-08 jrick printf("date: %s UTC\n", datestr);
4008 624411d2 2023-07-08 jrick if (got_object_commit_get_nparents(commit) > 1) {
4009 624411d2 2023-07-08 jrick const struct got_object_id_queue *parent_ids;
4010 624411d2 2023-07-08 jrick struct got_object_qid *qid;
4011 624411d2 2023-07-08 jrick int n = 1;
4012 624411d2 2023-07-08 jrick parent_ids = got_object_commit_get_parent_ids(commit);
4013 624411d2 2023-07-08 jrick STAILQ_FOREACH(qid, parent_ids, entry) {
4014 624411d2 2023-07-08 jrick err = got_object_id_str(&id_str, &qid->id);
4016 624411d2 2023-07-08 jrick goto done;
4017 624411d2 2023-07-08 jrick printf("parent %d: %s\n", n++, id_str);
4018 624411d2 2023-07-08 jrick free(id_str);
4019 624411d2 2023-07-08 jrick id_str = NULL;
4023 624411d2 2023-07-08 jrick err = got_object_commit_get_logmsg(&logmsg0, commit);
4025 624411d2 2023-07-08 jrick goto done;
4027 624411d2 2023-07-08 jrick logmsg = logmsg0;
4029 624411d2 2023-07-08 jrick line = strsep(&logmsg, "\n");
4030 624411d2 2023-07-08 jrick if (line)
4031 624411d2 2023-07-08 jrick printf(" %s\n", line);
4032 624411d2 2023-07-08 jrick } while (line);
4033 624411d2 2023-07-08 jrick free(logmsg0);
4035 624411d2 2023-07-08 jrick if (changed_paths && diffstat == NULL) {
4036 624411d2 2023-07-08 jrick struct got_pathlist_entry *pe;
4038 624411d2 2023-07-08 jrick TAILQ_FOREACH(pe, changed_paths, entry) {
4039 624411d2 2023-07-08 jrick struct got_diff_changed_path *cp = pe->data;
4041 624411d2 2023-07-08 jrick printf(" %c %s\n", cp->status, pe->path);
4043 624411d2 2023-07-08 jrick printf("\n");
4045 624411d2 2023-07-08 jrick if (show_patch) {
4046 624411d2 2023-07-08 jrick if (diffstat) {
4047 624411d2 2023-07-08 jrick f = got_opentemp();
4048 624411d2 2023-07-08 jrick if (f == NULL) {
4049 624411d2 2023-07-08 jrick err = got_error_from_errno("got_opentemp");
4050 624411d2 2023-07-08 jrick goto done;
4054 624411d2 2023-07-08 jrick err = print_patch(commit, id, path, diff_context, diffstat,
4055 624411d2 2023-07-08 jrick repo, diffstat == NULL ? stdout : f);
4057 624411d2 2023-07-08 jrick goto done;
4059 624411d2 2023-07-08 jrick if (diffstat) {
4060 624411d2 2023-07-08 jrick err = print_diffstat(diffstat, NULL);
4062 624411d2 2023-07-08 jrick goto done;
4063 624411d2 2023-07-08 jrick if (show_patch) {
4064 624411d2 2023-07-08 jrick err = printfile(f);
4066 624411d2 2023-07-08 jrick goto done;
4069 624411d2 2023-07-08 jrick if (show_patch)
4070 624411d2 2023-07-08 jrick printf("\n");
4072 624411d2 2023-07-08 jrick if (fflush(stdout) != 0 && err == NULL)
4073 624411d2 2023-07-08 jrick err = got_error_from_errno("fflush");
4075 624411d2 2023-07-08 jrick if (f && fclose(f) == EOF && err == NULL)
4076 624411d2 2023-07-08 jrick err = got_error_from_errno("fclose");
4077 624411d2 2023-07-08 jrick free(id_str);
4078 624411d2 2023-07-08 jrick free(refs_str);
4079 624411d2 2023-07-08 jrick return err;
4082 624411d2 2023-07-08 jrick static const struct got_error *
4083 624411d2 2023-07-08 jrick print_commits(struct got_object_id *root_id, struct got_object_id *end_id,
4084 624411d2 2023-07-08 jrick struct got_repository *repo, const char *path, int show_changed_paths,
4085 624411d2 2023-07-08 jrick int show_diffstat, int show_patch, const char *search_pattern,
4086 624411d2 2023-07-08 jrick int diff_context, int limit, int log_branches, int reverse_display_order,
4087 624411d2 2023-07-08 jrick struct got_reflist_object_id_map *refs_idmap, int one_line,
4088 624411d2 2023-07-08 jrick FILE *tmpfile)
4090 624411d2 2023-07-08 jrick const struct got_error *err;
4091 624411d2 2023-07-08 jrick struct got_commit_graph *graph;
4092 624411d2 2023-07-08 jrick regex_t regex;
4093 624411d2 2023-07-08 jrick int have_match;
4094 624411d2 2023-07-08 jrick struct got_object_id_queue reversed_commits;
4095 624411d2 2023-07-08 jrick struct got_object_qid *qid;
4096 624411d2 2023-07-08 jrick struct got_commit_object *commit;
4097 624411d2 2023-07-08 jrick struct got_pathlist_head changed_paths;
4099 624411d2 2023-07-08 jrick STAILQ_INIT(&reversed_commits);
4100 624411d2 2023-07-08 jrick TAILQ_INIT(&changed_paths);
4102 624411d2 2023-07-08 jrick if (search_pattern && regcomp(®ex, search_pattern,
4103 624411d2 2023-07-08 jrick REG_EXTENDED | REG_NOSUB | REG_NEWLINE))
4104 624411d2 2023-07-08 jrick return got_error_msg(GOT_ERR_REGEX, search_pattern);
4106 624411d2 2023-07-08 jrick err = got_commit_graph_open(&graph, path, !log_branches);
4108 624411d2 2023-07-08 jrick return err;
4109 624411d2 2023-07-08 jrick err = got_commit_graph_iter_start(graph, root_id, repo,
4110 624411d2 2023-07-08 jrick check_cancelled, NULL);
4112 624411d2 2023-07-08 jrick goto done;
4113 624411d2 2023-07-08 jrick for (;;) {
4114 624411d2 2023-07-08 jrick struct got_object_id id;
4115 624411d2 2023-07-08 jrick struct got_diffstat_cb_arg dsa = { 0, 0, 0, 0, 0, 0,
4116 624411d2 2023-07-08 jrick &changed_paths, 0, 0, GOT_DIFF_ALGORITHM_PATIENCE };
4118 624411d2 2023-07-08 jrick if (sigint_received || sigpipe_received)
4121 624411d2 2023-07-08 jrick err = got_commit_graph_iter_next(&id, graph, repo,
4122 624411d2 2023-07-08 jrick check_cancelled, NULL);
4123 624411d2 2023-07-08 jrick if (err) {
4124 624411d2 2023-07-08 jrick if (err->code == GOT_ERR_ITER_COMPLETED)
4125 624411d2 2023-07-08 jrick err = NULL;
4129 624411d2 2023-07-08 jrick err = got_object_open_as_commit(&commit, repo, &id);
4133 624411d2 2023-07-08 jrick if ((show_changed_paths || (show_diffstat && !show_patch))
4134 624411d2 2023-07-08 jrick && !reverse_display_order) {
4135 624411d2 2023-07-08 jrick err = get_changed_paths(&changed_paths, commit, repo,
4136 624411d2 2023-07-08 jrick show_diffstat ? &dsa : NULL);
4141 624411d2 2023-07-08 jrick if (search_pattern) {
4142 624411d2 2023-07-08 jrick err = match_commit(&have_match, &id, commit, ®ex);
4143 624411d2 2023-07-08 jrick if (err) {
4144 624411d2 2023-07-08 jrick got_object_commit_close(commit);
4147 624411d2 2023-07-08 jrick if (have_match == 0 && show_changed_paths)
4148 624411d2 2023-07-08 jrick match_changed_paths(&have_match,
4149 624411d2 2023-07-08 jrick &changed_paths, ®ex);
4150 624411d2 2023-07-08 jrick if (have_match == 0 && show_patch) {
4151 624411d2 2023-07-08 jrick err = match_patch(&have_match, commit, &id,
4152 624411d2 2023-07-08 jrick path, diff_context, repo, ®ex, tmpfile);
4156 624411d2 2023-07-08 jrick if (have_match == 0) {
4157 624411d2 2023-07-08 jrick got_object_commit_close(commit);
4158 624411d2 2023-07-08 jrick got_pathlist_free(&changed_paths,
4159 624411d2 2023-07-08 jrick GOT_PATHLIST_FREE_ALL);
4160 624411d2 2023-07-08 jrick continue;
4164 624411d2 2023-07-08 jrick if (reverse_display_order) {
4165 624411d2 2023-07-08 jrick err = got_object_qid_alloc(&qid, &id);
4168 624411d2 2023-07-08 jrick STAILQ_INSERT_HEAD(&reversed_commits, qid, entry);
4169 624411d2 2023-07-08 jrick got_object_commit_close(commit);
4171 624411d2 2023-07-08 jrick if (one_line)
4172 624411d2 2023-07-08 jrick err = print_commit_oneline(commit, &id,
4173 624411d2 2023-07-08 jrick repo, refs_idmap);
4175 624411d2 2023-07-08 jrick err = print_commit(commit, &id, repo, path,
4176 624411d2 2023-07-08 jrick (show_changed_paths || show_diffstat) ?
4177 624411d2 2023-07-08 jrick &changed_paths : NULL,
4178 624411d2 2023-07-08 jrick show_diffstat ? &dsa : NULL, show_patch,
4179 624411d2 2023-07-08 jrick diff_context, refs_idmap, NULL, NULL);
4180 624411d2 2023-07-08 jrick got_object_commit_close(commit);
4184 624411d2 2023-07-08 jrick if ((limit && --limit == 0) ||
4185 624411d2 2023-07-08 jrick (end_id && got_object_id_cmp(&id, end_id) == 0))
4188 624411d2 2023-07-08 jrick got_pathlist_free(&changed_paths, GOT_PATHLIST_FREE_ALL);
4190 624411d2 2023-07-08 jrick if (reverse_display_order) {
4191 624411d2 2023-07-08 jrick STAILQ_FOREACH(qid, &reversed_commits, entry) {
4192 624411d2 2023-07-08 jrick struct got_diffstat_cb_arg dsa = { 0, 0, 0, 0, 0, 0,
4193 624411d2 2023-07-08 jrick &changed_paths, 0, 0, GOT_DIFF_ALGORITHM_PATIENCE };
4195 624411d2 2023-07-08 jrick err = got_object_open_as_commit(&commit, repo,
4196 624411d2 2023-07-08 jrick &qid->id);
4199 624411d2 2023-07-08 jrick if (show_changed_paths ||
4200 624411d2 2023-07-08 jrick (show_diffstat && !show_patch)) {
4201 624411d2 2023-07-08 jrick err = get_changed_paths(&changed_paths, commit,
4202 624411d2 2023-07-08 jrick repo, show_diffstat ? &dsa : NULL);
4206 624411d2 2023-07-08 jrick if (one_line)
4207 624411d2 2023-07-08 jrick err = print_commit_oneline(commit, &qid->id,
4208 624411d2 2023-07-08 jrick repo, refs_idmap);
4210 624411d2 2023-07-08 jrick err = print_commit(commit, &qid->id, repo, path,
4211 624411d2 2023-07-08 jrick (show_changed_paths || show_diffstat) ?
4212 624411d2 2023-07-08 jrick &changed_paths : NULL,
4213 624411d2 2023-07-08 jrick show_diffstat ? &dsa : NULL, show_patch,
4214 624411d2 2023-07-08 jrick diff_context, refs_idmap, NULL, NULL);
4215 624411d2 2023-07-08 jrick got_object_commit_close(commit);
4218 624411d2 2023-07-08 jrick got_pathlist_free(&changed_paths, GOT_PATHLIST_FREE_ALL);
4222 624411d2 2023-07-08 jrick while (!STAILQ_EMPTY(&reversed_commits)) {
4223 624411d2 2023-07-08 jrick qid = STAILQ_FIRST(&reversed_commits);
4224 624411d2 2023-07-08 jrick STAILQ_REMOVE_HEAD(&reversed_commits, entry);
4225 624411d2 2023-07-08 jrick got_object_qid_free(qid);
4227 624411d2 2023-07-08 jrick got_pathlist_free(&changed_paths, GOT_PATHLIST_FREE_ALL);
4228 624411d2 2023-07-08 jrick if (search_pattern)
4229 624411d2 2023-07-08 jrick regfree(®ex);
4230 624411d2 2023-07-08 jrick got_commit_graph_close(graph);
4231 624411d2 2023-07-08 jrick return err;
4234 624411d2 2023-07-08 jrick __dead static void
4235 624411d2 2023-07-08 jrick usage_log(void)
4237 624411d2 2023-07-08 jrick fprintf(stderr, "usage: %s log [-bdPpRs] [-C number] [-c commit] "
4238 624411d2 2023-07-08 jrick "[-l N] [-r repository-path] [-S search-pattern] [-x commit] "
4239 624411d2 2023-07-08 jrick "[path]\n", getprogname());
4243 624411d2 2023-07-08 jrick static int
4244 624411d2 2023-07-08 jrick get_default_log_limit(void)
4246 624411d2 2023-07-08 jrick const char *got_default_log_limit;
4247 624411d2 2023-07-08 jrick long long n;
4248 624411d2 2023-07-08 jrick const char *errstr;
4250 624411d2 2023-07-08 jrick got_default_log_limit = getenv("GOT_LOG_DEFAULT_LIMIT");
4251 624411d2 2023-07-08 jrick if (got_default_log_limit == NULL)
4252 624411d2 2023-07-08 jrick return 0;
4253 624411d2 2023-07-08 jrick n = strtonum(got_default_log_limit, 0, INT_MAX, &errstr);
4254 624411d2 2023-07-08 jrick if (errstr != NULL)
4255 624411d2 2023-07-08 jrick return 0;
4256 624411d2 2023-07-08 jrick return n;
4259 624411d2 2023-07-08 jrick static const struct got_error *
4260 624411d2 2023-07-08 jrick cmd_log(int argc, char *argv[])
4262 624411d2 2023-07-08 jrick const struct got_error *error;
4263 624411d2 2023-07-08 jrick struct got_repository *repo = NULL;
4264 624411d2 2023-07-08 jrick struct got_worktree *worktree = NULL;
4265 624411d2 2023-07-08 jrick struct got_object_id *start_id = NULL, *end_id = NULL;
4266 624411d2 2023-07-08 jrick char *repo_path = NULL, *path = NULL, *cwd = NULL, *in_repo_path = NULL;
4267 624411d2 2023-07-08 jrick const char *start_commit = NULL, *end_commit = NULL;
4268 624411d2 2023-07-08 jrick const char *search_pattern = NULL;
4269 624411d2 2023-07-08 jrick int diff_context = -1, ch;
4270 624411d2 2023-07-08 jrick int show_changed_paths = 0, show_patch = 0, limit = 0, log_branches = 0;
4271 624411d2 2023-07-08 jrick int show_diffstat = 0, reverse_display_order = 0, one_line = 0;
4272 624411d2 2023-07-08 jrick const char *errstr;
4273 624411d2 2023-07-08 jrick struct got_reflist_head refs;
4274 624411d2 2023-07-08 jrick struct got_reflist_object_id_map *refs_idmap = NULL;
4275 624411d2 2023-07-08 jrick FILE *tmpfile = NULL;
4276 624411d2 2023-07-08 jrick int *pack_fds = NULL;
4278 624411d2 2023-07-08 jrick TAILQ_INIT(&refs);
4280 624411d2 2023-07-08 jrick #ifndef PROFILE
4281 624411d2 2023-07-08 jrick if (pledge("stdio rpath wpath cpath flock proc exec sendfd unveil",
4284 624411d2 2023-07-08 jrick err(1, "pledge");
4287 624411d2 2023-07-08 jrick limit = get_default_log_limit();
4289 624411d2 2023-07-08 jrick while ((ch = getopt(argc, argv, "bC:c:dl:PpRr:S:sx:")) != -1) {
4290 624411d2 2023-07-08 jrick switch (ch) {
4291 624411d2 2023-07-08 jrick case 'b':
4292 624411d2 2023-07-08 jrick log_branches = 1;
4294 624411d2 2023-07-08 jrick case 'C':
4295 624411d2 2023-07-08 jrick diff_context = strtonum(optarg, 0, GOT_DIFF_MAX_CONTEXT,
4296 624411d2 2023-07-08 jrick &errstr);
4297 624411d2 2023-07-08 jrick if (errstr != NULL)
4298 624411d2 2023-07-08 jrick errx(1, "number of context lines is %s: %s",
4299 624411d2 2023-07-08 jrick errstr, optarg);
4301 624411d2 2023-07-08 jrick case 'c':
4302 624411d2 2023-07-08 jrick start_commit = optarg;
4304 624411d2 2023-07-08 jrick case 'd':
4305 624411d2 2023-07-08 jrick show_diffstat = 1;
4307 624411d2 2023-07-08 jrick case 'l':
4308 624411d2 2023-07-08 jrick limit = strtonum(optarg, 0, INT_MAX, &errstr);
4309 624411d2 2023-07-08 jrick if (errstr != NULL)
4310 624411d2 2023-07-08 jrick errx(1, "number of commits is %s: %s",
4311 624411d2 2023-07-08 jrick errstr, optarg);
4313 624411d2 2023-07-08 jrick case 'P':
4314 624411d2 2023-07-08 jrick show_changed_paths = 1;
4316 624411d2 2023-07-08 jrick case 'p':
4317 624411d2 2023-07-08 jrick show_patch = 1;
4319 624411d2 2023-07-08 jrick case 'R':
4320 624411d2 2023-07-08 jrick reverse_display_order = 1;
4322 624411d2 2023-07-08 jrick case 'r':
4323 624411d2 2023-07-08 jrick repo_path = realpath(optarg, NULL);
4324 624411d2 2023-07-08 jrick if (repo_path == NULL)
4325 624411d2 2023-07-08 jrick return got_error_from_errno2("realpath",
4327 624411d2 2023-07-08 jrick got_path_strip_trailing_slashes(repo_path);
4329 624411d2 2023-07-08 jrick case 'S':
4330 624411d2 2023-07-08 jrick search_pattern = optarg;
4332 624411d2 2023-07-08 jrick case 's':
4333 624411d2 2023-07-08 jrick one_line = 1;
4335 624411d2 2023-07-08 jrick case 'x':
4336 624411d2 2023-07-08 jrick end_commit = optarg;
4339 624411d2 2023-07-08 jrick usage_log();
4340 624411d2 2023-07-08 jrick /* NOTREACHED */
4344 624411d2 2023-07-08 jrick argc -= optind;
4345 624411d2 2023-07-08 jrick argv += optind;
4347 624411d2 2023-07-08 jrick if (diff_context == -1)
4348 624411d2 2023-07-08 jrick diff_context = 3;
4349 624411d2 2023-07-08 jrick else if (!show_patch)
4350 624411d2 2023-07-08 jrick errx(1, "-C requires -p");
4352 624411d2 2023-07-08 jrick if (one_line && (show_patch || show_changed_paths || show_diffstat))
4353 624411d2 2023-07-08 jrick errx(1, "cannot use -s with -d, -p or -P");
4355 624411d2 2023-07-08 jrick cwd = getcwd(NULL, 0);
4356 624411d2 2023-07-08 jrick if (cwd == NULL) {
4357 624411d2 2023-07-08 jrick error = got_error_from_errno("getcwd");
4358 624411d2 2023-07-08 jrick goto done;
4361 624411d2 2023-07-08 jrick error = got_repo_pack_fds_open(&pack_fds);
4362 624411d2 2023-07-08 jrick if (error != NULL)
4363 624411d2 2023-07-08 jrick goto done;
4365 624411d2 2023-07-08 jrick if (repo_path == NULL) {
4366 624411d2 2023-07-08 jrick error = got_worktree_open(&worktree, cwd);
4367 624411d2 2023-07-08 jrick if (error && error->code != GOT_ERR_NOT_WORKTREE)
4368 624411d2 2023-07-08 jrick goto done;
4369 624411d2 2023-07-08 jrick error = NULL;
4372 624411d2 2023-07-08 jrick if (argc == 1) {
4373 624411d2 2023-07-08 jrick if (worktree) {
4374 624411d2 2023-07-08 jrick error = got_worktree_resolve_path(&path, worktree,
4375 624411d2 2023-07-08 jrick argv[0]);
4376 624411d2 2023-07-08 jrick if (error)
4377 624411d2 2023-07-08 jrick goto done;
4379 624411d2 2023-07-08 jrick path = strdup(argv[0]);
4380 624411d2 2023-07-08 jrick if (path == NULL) {
4381 624411d2 2023-07-08 jrick error = got_error_from_errno("strdup");
4382 624411d2 2023-07-08 jrick goto done;
4385 624411d2 2023-07-08 jrick } else if (argc != 0)
4386 624411d2 2023-07-08 jrick usage_log();
4388 624411d2 2023-07-08 jrick if (repo_path == NULL) {
4389 624411d2 2023-07-08 jrick repo_path = worktree ?
4390 624411d2 2023-07-08 jrick strdup(got_worktree_get_repo_path(worktree)) : strdup(cwd);
4392 624411d2 2023-07-08 jrick if (repo_path == NULL) {
4393 624411d2 2023-07-08 jrick error = got_error_from_errno("strdup");
4394 624411d2 2023-07-08 jrick goto done;
4397 624411d2 2023-07-08 jrick error = got_repo_open(&repo, repo_path, NULL, pack_fds);
4398 624411d2 2023-07-08 jrick if (error != NULL)
4399 624411d2 2023-07-08 jrick goto done;
4401 624411d2 2023-07-08 jrick error = apply_unveil(got_repo_get_path(repo), 1,
4402 624411d2 2023-07-08 jrick worktree ? got_worktree_get_root_path(worktree) : NULL);
4403 624411d2 2023-07-08 jrick if (error)
4404 624411d2 2023-07-08 jrick goto done;
4406 624411d2 2023-07-08 jrick error = got_ref_list(&refs, repo, NULL, got_ref_cmp_by_name, NULL);
4407 624411d2 2023-07-08 jrick if (error)
4408 624411d2 2023-07-08 jrick goto done;
4410 624411d2 2023-07-08 jrick error = got_reflist_object_id_map_create(&refs_idmap, &refs, repo);
4411 624411d2 2023-07-08 jrick if (error)
4412 624411d2 2023-07-08 jrick goto done;
4414 624411d2 2023-07-08 jrick if (start_commit == NULL) {
4415 624411d2 2023-07-08 jrick struct got_reference *head_ref;
4416 624411d2 2023-07-08 jrick struct got_commit_object *commit = NULL;
4417 624411d2 2023-07-08 jrick error = got_ref_open(&head_ref, repo,
4418 624411d2 2023-07-08 jrick worktree ? got_worktree_get_head_ref_name(worktree)
4419 624411d2 2023-07-08 jrick : GOT_REF_HEAD, 0);
4420 624411d2 2023-07-08 jrick if (error != NULL)
4421 624411d2 2023-07-08 jrick goto done;
4422 624411d2 2023-07-08 jrick error = got_ref_resolve(&start_id, repo, head_ref);
4423 624411d2 2023-07-08 jrick got_ref_close(head_ref);
4424 624411d2 2023-07-08 jrick if (error != NULL)
4425 624411d2 2023-07-08 jrick goto done;
4426 624411d2 2023-07-08 jrick error = got_object_open_as_commit(&commit, repo,
4427 624411d2 2023-07-08 jrick start_id);
4428 624411d2 2023-07-08 jrick if (error != NULL)
4429 624411d2 2023-07-08 jrick goto done;
4430 624411d2 2023-07-08 jrick got_object_commit_close(commit);
4432 624411d2 2023-07-08 jrick error = got_repo_match_object_id(&start_id, NULL,
4433 624411d2 2023-07-08 jrick start_commit, GOT_OBJ_TYPE_COMMIT, &refs, repo);
4434 624411d2 2023-07-08 jrick if (error != NULL)
4435 624411d2 2023-07-08 jrick goto done;
4437 624411d2 2023-07-08 jrick if (end_commit != NULL) {
4438 624411d2 2023-07-08 jrick error = got_repo_match_object_id(&end_id, NULL,
4439 624411d2 2023-07-08 jrick end_commit, GOT_OBJ_TYPE_COMMIT, &refs, repo);
4440 624411d2 2023-07-08 jrick if (error != NULL)
4441 624411d2 2023-07-08 jrick goto done;
4444 624411d2 2023-07-08 jrick if (worktree) {
4446 624411d2 2023-07-08 jrick * If a path was specified on the command line it was resolved
4447 624411d2 2023-07-08 jrick * to a path in the work tree above. Prepend the work tree's
4448 624411d2 2023-07-08 jrick * path prefix to obtain the corresponding in-repository path.
4450 624411d2 2023-07-08 jrick if (path) {
4451 624411d2 2023-07-08 jrick const char *prefix;
4452 624411d2 2023-07-08 jrick prefix = got_worktree_get_path_prefix(worktree);
4453 624411d2 2023-07-08 jrick if (asprintf(&in_repo_path, "%s%s%s", prefix,
4454 624411d2 2023-07-08 jrick (path[0] != '\0') ? "/" : "", path) == -1) {
4455 624411d2 2023-07-08 jrick error = got_error_from_errno("asprintf");
4456 624411d2 2023-07-08 jrick goto done;
4460 624411d2 2023-07-08 jrick error = got_repo_map_path(&in_repo_path, repo,
4461 624411d2 2023-07-08 jrick path ? path : "");
4462 624411d2 2023-07-08 jrick if (error != NULL)
4463 624411d2 2023-07-08 jrick goto done;
4464 624411d2 2023-07-08 jrick if (in_repo_path) {
4465 624411d2 2023-07-08 jrick free(path);
4466 624411d2 2023-07-08 jrick path = in_repo_path;
4469 624411d2 2023-07-08 jrick if (worktree) {
4470 624411d2 2023-07-08 jrick /* Release work tree lock. */
4471 624411d2 2023-07-08 jrick got_worktree_close(worktree);
4472 624411d2 2023-07-08 jrick worktree = NULL;
4475 624411d2 2023-07-08 jrick if (search_pattern && show_patch) {
4476 624411d2 2023-07-08 jrick tmpfile = got_opentemp();
4477 624411d2 2023-07-08 jrick if (tmpfile == NULL) {
4478 624411d2 2023-07-08 jrick error = got_error_from_errno("got_opentemp");
4479 624411d2 2023-07-08 jrick goto done;
4483 624411d2 2023-07-08 jrick error = print_commits(start_id, end_id, repo, path ? path : "",
4484 624411d2 2023-07-08 jrick show_changed_paths, show_diffstat, show_patch, search_pattern,
4485 624411d2 2023-07-08 jrick diff_context, limit, log_branches, reverse_display_order,
4486 624411d2 2023-07-08 jrick refs_idmap, one_line, tmpfile);
4488 624411d2 2023-07-08 jrick free(path);
4489 624411d2 2023-07-08 jrick free(repo_path);
4490 624411d2 2023-07-08 jrick free(cwd);
4491 624411d2 2023-07-08 jrick if (worktree)
4492 624411d2 2023-07-08 jrick got_worktree_close(worktree);
4493 624411d2 2023-07-08 jrick if (repo) {
4494 624411d2 2023-07-08 jrick const struct got_error *close_err = got_repo_close(repo);
4495 624411d2 2023-07-08 jrick if (error == NULL)
4496 624411d2 2023-07-08 jrick error = close_err;
4498 624411d2 2023-07-08 jrick if (pack_fds) {
4499 624411d2 2023-07-08 jrick const struct got_error *pack_err =
4500 624411d2 2023-07-08 jrick got_repo_pack_fds_close(pack_fds);
4501 624411d2 2023-07-08 jrick if (error == NULL)
4502 624411d2 2023-07-08 jrick error = pack_err;
4504 624411d2 2023-07-08 jrick if (refs_idmap)
4505 624411d2 2023-07-08 jrick got_reflist_object_id_map_free(refs_idmap);
4506 624411d2 2023-07-08 jrick if (tmpfile && fclose(tmpfile) == EOF && error == NULL)
4507 624411d2 2023-07-08 jrick error = got_error_from_errno("fclose");
4508 624411d2 2023-07-08 jrick got_ref_list_free(&refs);
4509 624411d2 2023-07-08 jrick return error;
4512 624411d2 2023-07-08 jrick __dead static void
4513 624411d2 2023-07-08 jrick usage_diff(void)
4515 624411d2 2023-07-08 jrick fprintf(stderr, "usage: %s diff [-adPsw] [-C number] [-c commit] "
4516 624411d2 2023-07-08 jrick "[-r repository-path] [object1 object2 | path ...]\n",
4517 624411d2 2023-07-08 jrick getprogname());
4521 624411d2 2023-07-08 jrick struct print_diff_arg {
4522 624411d2 2023-07-08 jrick struct got_repository *repo;
4523 624411d2 2023-07-08 jrick struct got_worktree *worktree;
4524 624411d2 2023-07-08 jrick struct got_diffstat_cb_arg *diffstat;
4525 624411d2 2023-07-08 jrick int diff_context;
4526 624411d2 2023-07-08 jrick const char *id_str;
4527 624411d2 2023-07-08 jrick int header_shown;
4528 624411d2 2023-07-08 jrick int diff_staged;
4529 624411d2 2023-07-08 jrick enum got_diff_algorithm diff_algo;
4530 624411d2 2023-07-08 jrick int ignore_whitespace;
4531 624411d2 2023-07-08 jrick int force_text_diff;
4532 624411d2 2023-07-08 jrick FILE *f1;
4533 624411d2 2023-07-08 jrick FILE *f2;
4534 624411d2 2023-07-08 jrick FILE *outfile;
4538 624411d2 2023-07-08 jrick * Create a file which contains the target path of a symlink so we can feed
4539 624411d2 2023-07-08 jrick * it as content to the diff engine.
4541 624411d2 2023-07-08 jrick static const struct got_error *
4542 624411d2 2023-07-08 jrick get_symlink_target_file(int *fd, int dirfd, const char *de_name,
4543 624411d2 2023-07-08 jrick const char *abspath)
4545 624411d2 2023-07-08 jrick const struct got_error *err = NULL;
4546 624411d2 2023-07-08 jrick char target_path[PATH_MAX];
4547 624411d2 2023-07-08 jrick ssize_t target_len, outlen;
4549 624411d2 2023-07-08 jrick *fd = -1;
4551 624411d2 2023-07-08 jrick if (dirfd != -1) {
4552 624411d2 2023-07-08 jrick target_len = readlinkat(dirfd, de_name, target_path, PATH_MAX);
4553 624411d2 2023-07-08 jrick if (target_len == -1)
4554 624411d2 2023-07-08 jrick return got_error_from_errno2("readlinkat", abspath);
4556 624411d2 2023-07-08 jrick target_len = readlink(abspath, target_path, PATH_MAX);
4557 624411d2 2023-07-08 jrick if (target_len == -1)
4558 624411d2 2023-07-08 jrick return got_error_from_errno2("readlink", abspath);
4561 624411d2 2023-07-08 jrick *fd = got_opentempfd();
4562 624411d2 2023-07-08 jrick if (*fd == -1)
4563 624411d2 2023-07-08 jrick return got_error_from_errno("got_opentempfd");
4565 624411d2 2023-07-08 jrick outlen = write(*fd, target_path, target_len);
4566 624411d2 2023-07-08 jrick if (outlen == -1) {
4567 624411d2 2023-07-08 jrick err = got_error_from_errno("got_opentempfd");
4568 624411d2 2023-07-08 jrick goto done;
4571 624411d2 2023-07-08 jrick if (lseek(*fd, 0, SEEK_SET) == -1) {
4572 624411d2 2023-07-08 jrick err = got_error_from_errno2("lseek", abspath);
4573 624411d2 2023-07-08 jrick goto done;
4576 624411d2 2023-07-08 jrick if (err) {
4577 624411d2 2023-07-08 jrick close(*fd);
4578 624411d2 2023-07-08 jrick *fd = -1;
4580 624411d2 2023-07-08 jrick return err;
4583 624411d2 2023-07-08 jrick static const struct got_error *
4584 624411d2 2023-07-08 jrick print_diff(void *arg, unsigned char status, unsigned char staged_status,
4585 624411d2 2023-07-08 jrick const char *path, struct got_object_id *blob_id,
4586 624411d2 2023-07-08 jrick struct got_object_id *staged_blob_id, struct got_object_id *commit_id,
4587 624411d2 2023-07-08 jrick int dirfd, const char *de_name)
4589 624411d2 2023-07-08 jrick struct print_diff_arg *a = arg;
4590 624411d2 2023-07-08 jrick const struct got_error *err = NULL;
4591 624411d2 2023-07-08 jrick struct got_blob_object *blob1 = NULL;
4592 624411d2 2023-07-08 jrick int fd = -1, fd1 = -1, fd2 = -1;
4593 624411d2 2023-07-08 jrick FILE *f2 = NULL;
4594 624411d2 2023-07-08 jrick char *abspath = NULL, *label1 = NULL;
4595 624411d2 2023-07-08 jrick struct stat sb;
4596 624411d2 2023-07-08 jrick off_t size1 = 0;
4597 624411d2 2023-07-08 jrick int f2_exists = 0;
4599 624411d2 2023-07-08 jrick memset(&sb, 0, sizeof(sb));
4601 624411d2 2023-07-08 jrick if (a->diff_staged) {
4602 624411d2 2023-07-08 jrick if (staged_status != GOT_STATUS_MODIFY &&
4603 624411d2 2023-07-08 jrick staged_status != GOT_STATUS_ADD &&
4604 624411d2 2023-07-08 jrick staged_status != GOT_STATUS_DELETE)
4605 624411d2 2023-07-08 jrick return NULL;
4607 624411d2 2023-07-08 jrick if (staged_status == GOT_STATUS_DELETE)
4608 624411d2 2023-07-08 jrick return NULL;
4609 624411d2 2023-07-08 jrick if (status == GOT_STATUS_NONEXISTENT)
4610 624411d2 2023-07-08 jrick return got_error_set_errno(ENOENT, path);
4611 624411d2 2023-07-08 jrick if (status != GOT_STATUS_MODIFY &&
4612 624411d2 2023-07-08 jrick status != GOT_STATUS_ADD &&
4613 624411d2 2023-07-08 jrick status != GOT_STATUS_DELETE &&
4614 624411d2 2023-07-08 jrick status != GOT_STATUS_CONFLICT)
4615 624411d2 2023-07-08 jrick return NULL;
4618 624411d2 2023-07-08 jrick err = got_opentemp_truncate(a->f1);
4620 624411d2 2023-07-08 jrick return got_error_from_errno("got_opentemp_truncate");
4621 624411d2 2023-07-08 jrick err = got_opentemp_truncate(a->f2);
4623 624411d2 2023-07-08 jrick return got_error_from_errno("got_opentemp_truncate");
4625 624411d2 2023-07-08 jrick if (!a->header_shown) {
4626 624411d2 2023-07-08 jrick if (fprintf(a->outfile, "diff %s%s\n",
4627 624411d2 2023-07-08 jrick a->diff_staged ? "-s " : "",
4628 624411d2 2023-07-08 jrick got_worktree_get_root_path(a->worktree)) < 0) {
4629 624411d2 2023-07-08 jrick err = got_error_from_errno("fprintf");
4630 624411d2 2023-07-08 jrick goto done;
4632 624411d2 2023-07-08 jrick if (fprintf(a->outfile, "commit - %s\n", a->id_str) < 0) {
4633 624411d2 2023-07-08 jrick err = got_error_from_errno("fprintf");
4634 624411d2 2023-07-08 jrick goto done;
4636 624411d2 2023-07-08 jrick if (fprintf(a->outfile, "path + %s%s\n",
4637 624411d2 2023-07-08 jrick got_worktree_get_root_path(a->worktree),
4638 624411d2 2023-07-08 jrick a->diff_staged ? " (staged changes)" : "") < 0) {
4639 624411d2 2023-07-08 jrick err = got_error_from_errno("fprintf");
4640 624411d2 2023-07-08 jrick goto done;
4642 624411d2 2023-07-08 jrick a->header_shown = 1;
4645 624411d2 2023-07-08 jrick if (a->diff_staged) {
4646 624411d2 2023-07-08 jrick const char *label1 = NULL, *label2 = NULL;
4647 624411d2 2023-07-08 jrick switch (staged_status) {
4648 624411d2 2023-07-08 jrick case GOT_STATUS_MODIFY:
4649 624411d2 2023-07-08 jrick label1 = path;
4650 624411d2 2023-07-08 jrick label2 = path;
4652 624411d2 2023-07-08 jrick case GOT_STATUS_ADD:
4653 624411d2 2023-07-08 jrick label2 = path;
4655 624411d2 2023-07-08 jrick case GOT_STATUS_DELETE:
4656 624411d2 2023-07-08 jrick label1 = path;
4659 624411d2 2023-07-08 jrick return got_error(GOT_ERR_FILE_STATUS);
4661 624411d2 2023-07-08 jrick fd1 = got_opentempfd();
4662 624411d2 2023-07-08 jrick if (fd1 == -1) {
4663 624411d2 2023-07-08 jrick err = got_error_from_errno("got_opentempfd");
4664 624411d2 2023-07-08 jrick goto done;
4666 624411d2 2023-07-08 jrick fd2 = got_opentempfd();
4667 624411d2 2023-07-08 jrick if (fd2 == -1) {
4668 624411d2 2023-07-08 jrick err = got_error_from_errno("got_opentempfd");
4669 624411d2 2023-07-08 jrick goto done;
4671 624411d2 2023-07-08 jrick err = got_diff_objects_as_blobs(NULL, NULL, a->f1, a->f2,
4672 624411d2 2023-07-08 jrick fd1, fd2, blob_id, staged_blob_id, label1, label2,
4673 624411d2 2023-07-08 jrick a->diff_algo, a->diff_context, a->ignore_whitespace,
4674 624411d2 2023-07-08 jrick a->force_text_diff, a->diffstat, a->repo, a->outfile);
4675 624411d2 2023-07-08 jrick goto done;
4678 624411d2 2023-07-08 jrick fd1 = got_opentempfd();
4679 624411d2 2023-07-08 jrick if (fd1 == -1) {
4680 624411d2 2023-07-08 jrick err = got_error_from_errno("got_opentempfd");
4681 624411d2 2023-07-08 jrick goto done;
4684 624411d2 2023-07-08 jrick if (staged_status == GOT_STATUS_ADD ||
4685 624411d2 2023-07-08 jrick staged_status == GOT_STATUS_MODIFY) {
4686 624411d2 2023-07-08 jrick char *id_str;
4687 624411d2 2023-07-08 jrick err = got_object_open_as_blob(&blob1, a->repo, staged_blob_id,
4688 624411d2 2023-07-08 jrick 8192, fd1);
4690 624411d2 2023-07-08 jrick goto done;
4691 624411d2 2023-07-08 jrick err = got_object_id_str(&id_str, staged_blob_id);
4693 624411d2 2023-07-08 jrick goto done;
4694 624411d2 2023-07-08 jrick if (asprintf(&label1, "%s (staged)", id_str) == -1) {
4695 624411d2 2023-07-08 jrick err = got_error_from_errno("asprintf");
4696 624411d2 2023-07-08 jrick free(id_str);
4697 624411d2 2023-07-08 jrick goto done;
4699 624411d2 2023-07-08 jrick free(id_str);
4700 624411d2 2023-07-08 jrick } else if (status != GOT_STATUS_ADD) {
4701 624411d2 2023-07-08 jrick err = got_object_open_as_blob(&blob1, a->repo, blob_id, 8192,
4704 624411d2 2023-07-08 jrick goto done;
4707 624411d2 2023-07-08 jrick if (status != GOT_STATUS_DELETE) {
4708 624411d2 2023-07-08 jrick if (asprintf(&abspath, "%s/%s",
4709 624411d2 2023-07-08 jrick got_worktree_get_root_path(a->worktree), path) == -1) {
4710 624411d2 2023-07-08 jrick err = got_error_from_errno("asprintf");
4711 624411d2 2023-07-08 jrick goto done;
4714 624411d2 2023-07-08 jrick if (dirfd != -1) {
4715 624411d2 2023-07-08 jrick fd = openat(dirfd, de_name,
4716 624411d2 2023-07-08 jrick O_RDONLY | O_NOFOLLOW | O_CLOEXEC);
4717 624411d2 2023-07-08 jrick if (fd == -1) {
4718 624411d2 2023-07-08 jrick if (!got_err_open_nofollow_on_symlink()) {
4719 624411d2 2023-07-08 jrick err = got_error_from_errno2("openat",
4720 624411d2 2023-07-08 jrick abspath);
4721 624411d2 2023-07-08 jrick goto done;
4723 624411d2 2023-07-08 jrick err = get_symlink_target_file(&fd, dirfd,
4724 624411d2 2023-07-08 jrick de_name, abspath);
4726 624411d2 2023-07-08 jrick goto done;
4729 624411d2 2023-07-08 jrick fd = open(abspath, O_RDONLY | O_NOFOLLOW | O_CLOEXEC);
4730 624411d2 2023-07-08 jrick if (fd == -1) {
4731 624411d2 2023-07-08 jrick if (!got_err_open_nofollow_on_symlink()) {
4732 624411d2 2023-07-08 jrick err = got_error_from_errno2("open",
4733 624411d2 2023-07-08 jrick abspath);
4734 624411d2 2023-07-08 jrick goto done;
4736 624411d2 2023-07-08 jrick err = get_symlink_target_file(&fd, dirfd,
4737 624411d2 2023-07-08 jrick de_name, abspath);
4739 624411d2 2023-07-08 jrick goto done;
4742 624411d2 2023-07-08 jrick if (fstatat(fd, abspath, &sb, AT_SYMLINK_NOFOLLOW) == -1) {
4743 624411d2 2023-07-08 jrick err = got_error_from_errno2("fstatat", abspath);
4744 624411d2 2023-07-08 jrick goto done;
4746 624411d2 2023-07-08 jrick f2 = fdopen(fd, "r");
4747 624411d2 2023-07-08 jrick if (f2 == NULL) {
4748 624411d2 2023-07-08 jrick err = got_error_from_errno2("fdopen", abspath);
4749 624411d2 2023-07-08 jrick goto done;
4752 624411d2 2023-07-08 jrick f2_exists = 1;
4755 624411d2 2023-07-08 jrick if (blob1) {
4756 624411d2 2023-07-08 jrick err = got_object_blob_dump_to_file(&size1, NULL, NULL,
4757 624411d2 2023-07-08 jrick a->f1, blob1);
4759 624411d2 2023-07-08 jrick goto done;
4762 624411d2 2023-07-08 jrick err = got_diff_blob_file(blob1, a->f1, size1, label1, f2 ? f2 : a->f2,
4763 624411d2 2023-07-08 jrick f2_exists, &sb, path, GOT_DIFF_ALGORITHM_PATIENCE, a->diff_context,
4764 624411d2 2023-07-08 jrick a->ignore_whitespace, a->force_text_diff, a->diffstat, a->outfile);
4766 624411d2 2023-07-08 jrick if (fd1 != -1 && close(fd1) == -1 && err == NULL)
4767 624411d2 2023-07-08 jrick err = got_error_from_errno("close");
4768 624411d2 2023-07-08 jrick if (fd2 != -1 && close(fd2) == -1 && err == NULL)
4769 624411d2 2023-07-08 jrick err = got_error_from_errno("close");
4770 624411d2 2023-07-08 jrick if (blob1)
4771 624411d2 2023-07-08 jrick got_object_blob_close(blob1);
4772 624411d2 2023-07-08 jrick if (fd != -1 && close(fd) == -1 && err == NULL)
4773 624411d2 2023-07-08 jrick err = got_error_from_errno("close");
4774 624411d2 2023-07-08 jrick if (f2 && fclose(f2) == EOF && err == NULL)
4775 624411d2 2023-07-08 jrick err = got_error_from_errno("fclose");
4776 624411d2 2023-07-08 jrick free(abspath);
4777 624411d2 2023-07-08 jrick return err;
4780 624411d2 2023-07-08 jrick static const struct got_error *
4781 624411d2 2023-07-08 jrick cmd_diff(int argc, char *argv[])
4783 624411d2 2023-07-08 jrick const struct got_error *error;
4784 624411d2 2023-07-08 jrick struct got_repository *repo = NULL;
4785 624411d2 2023-07-08 jrick struct got_worktree *worktree = NULL;
4786 624411d2 2023-07-08 jrick char *cwd = NULL, *repo_path = NULL;
4787 624411d2 2023-07-08 jrick const char *commit_args[2] = { NULL, NULL };
4788 624411d2 2023-07-08 jrick int ncommit_args = 0;
4789 624411d2 2023-07-08 jrick struct got_object_id *ids[2] = { NULL, NULL };
4790 624411d2 2023-07-08 jrick char *labels[2] = { NULL, NULL };
4791 624411d2 2023-07-08 jrick int type1 = GOT_OBJ_TYPE_ANY, type2 = GOT_OBJ_TYPE_ANY;
4792 624411d2 2023-07-08 jrick int diff_context = 3, diff_staged = 0, ignore_whitespace = 0, ch, i;
4793 624411d2 2023-07-08 jrick int force_text_diff = 0, force_path = 0, rflag = 0, show_diffstat = 0;
4794 624411d2 2023-07-08 jrick const char *errstr;
4795 624411d2 2023-07-08 jrick struct got_reflist_head refs;
4796 624411d2 2023-07-08 jrick struct got_pathlist_head diffstat_paths, paths;
4797 624411d2 2023-07-08 jrick FILE *f1 = NULL, *f2 = NULL, *outfile = NULL;
4798 624411d2 2023-07-08 jrick int fd1 = -1, fd2 = -1;
4799 624411d2 2023-07-08 jrick int *pack_fds = NULL;
4800 624411d2 2023-07-08 jrick struct got_diffstat_cb_arg dsa;
4802 624411d2 2023-07-08 jrick memset(&dsa, 0, sizeof(dsa));
4804 624411d2 2023-07-08 jrick TAILQ_INIT(&refs);
4805 624411d2 2023-07-08 jrick TAILQ_INIT(&paths);
4806 624411d2 2023-07-08 jrick TAILQ_INIT(&diffstat_paths);
4808 624411d2 2023-07-08 jrick #ifndef PROFILE
4809 624411d2 2023-07-08 jrick if (pledge("stdio rpath wpath cpath flock proc exec sendfd unveil",
4810 624411d2 2023-07-08 jrick NULL) == -1)
4811 624411d2 2023-07-08 jrick err(1, "pledge");
4814 624411d2 2023-07-08 jrick while ((ch = getopt(argc, argv, "aC:c:dPr:sw")) != -1) {
4815 624411d2 2023-07-08 jrick switch (ch) {
4816 624411d2 2023-07-08 jrick case 'a':
4817 624411d2 2023-07-08 jrick force_text_diff = 1;
4819 624411d2 2023-07-08 jrick case 'C':
4820 624411d2 2023-07-08 jrick diff_context = strtonum(optarg, 0, GOT_DIFF_MAX_CONTEXT,
4821 624411d2 2023-07-08 jrick &errstr);
4822 624411d2 2023-07-08 jrick if (errstr != NULL)
4823 624411d2 2023-07-08 jrick errx(1, "number of context lines is %s: %s",
4824 624411d2 2023-07-08 jrick errstr, optarg);
4826 624411d2 2023-07-08 jrick case 'c':
4827 624411d2 2023-07-08 jrick if (ncommit_args >= 2)
4828 624411d2 2023-07-08 jrick errx(1, "too many -c options used");
4829 624411d2 2023-07-08 jrick commit_args[ncommit_args++] = optarg;
4831 624411d2 2023-07-08 jrick case 'd':
4832 624411d2 2023-07-08 jrick show_diffstat = 1;
4834 624411d2 2023-07-08 jrick case 'P':
4835 624411d2 2023-07-08 jrick force_path = 1;
4837 624411d2 2023-07-08 jrick case 'r':
4838 624411d2 2023-07-08 jrick repo_path = realpath(optarg, NULL);
4839 624411d2 2023-07-08 jrick if (repo_path == NULL)
4840 624411d2 2023-07-08 jrick return got_error_from_errno2("realpath",
4842 624411d2 2023-07-08 jrick got_path_strip_trailing_slashes(repo_path);
4843 624411d2 2023-07-08 jrick rflag = 1;
4845 624411d2 2023-07-08 jrick case 's':
4846 624411d2 2023-07-08 jrick diff_staged = 1;
4848 624411d2 2023-07-08 jrick case 'w':
4849 624411d2 2023-07-08 jrick ignore_whitespace = 1;
4852 624411d2 2023-07-08 jrick usage_diff();
4853 624411d2 2023-07-08 jrick /* NOTREACHED */
4857 624411d2 2023-07-08 jrick argc -= optind;
4858 624411d2 2023-07-08 jrick argv += optind;
4860 624411d2 2023-07-08 jrick cwd = getcwd(NULL, 0);
4861 624411d2 2023-07-08 jrick if (cwd == NULL) {
4862 624411d2 2023-07-08 jrick error = got_error_from_errno("getcwd");
4863 624411d2 2023-07-08 jrick goto done;
4866 624411d2 2023-07-08 jrick error = got_repo_pack_fds_open(&pack_fds);
4867 624411d2 2023-07-08 jrick if (error != NULL)
4868 624411d2 2023-07-08 jrick goto done;
4870 624411d2 2023-07-08 jrick if (repo_path == NULL) {
4871 624411d2 2023-07-08 jrick error = got_worktree_open(&worktree, cwd);
4872 624411d2 2023-07-08 jrick if (error && error->code != GOT_ERR_NOT_WORKTREE)
4873 624411d2 2023-07-08 jrick goto done;
4875 624411d2 2023-07-08 jrick error = NULL;
4876 624411d2 2023-07-08 jrick if (worktree) {
4877 624411d2 2023-07-08 jrick repo_path =
4878 624411d2 2023-07-08 jrick strdup(got_worktree_get_repo_path(worktree));
4879 624411d2 2023-07-08 jrick if (repo_path == NULL) {
4880 624411d2 2023-07-08 jrick error = got_error_from_errno("strdup");
4881 624411d2 2023-07-08 jrick goto done;
4884 624411d2 2023-07-08 jrick repo_path = strdup(cwd);
4885 624411d2 2023-07-08 jrick if (repo_path == NULL) {
4886 624411d2 2023-07-08 jrick error = got_error_from_errno("strdup");
4887 624411d2 2023-07-08 jrick goto done;
4892 624411d2 2023-07-08 jrick error = got_repo_open(&repo, repo_path, NULL, pack_fds);
4893 624411d2 2023-07-08 jrick free(repo_path);
4894 624411d2 2023-07-08 jrick if (error != NULL)
4895 624411d2 2023-07-08 jrick goto done;
4897 624411d2 2023-07-08 jrick if (show_diffstat) {
4898 624411d2 2023-07-08 jrick dsa.paths = &diffstat_paths;
4899 624411d2 2023-07-08 jrick dsa.force_text = force_text_diff;
4900 624411d2 2023-07-08 jrick dsa.ignore_ws = ignore_whitespace;
4901 624411d2 2023-07-08 jrick dsa.diff_algo = GOT_DIFF_ALGORITHM_PATIENCE;
4904 624411d2 2023-07-08 jrick if (rflag || worktree == NULL || ncommit_args > 0) {
4905 624411d2 2023-07-08 jrick if (force_path) {
4906 624411d2 2023-07-08 jrick error = got_error_msg(GOT_ERR_NOT_IMPL,
4907 624411d2 2023-07-08 jrick "-P option can only be used when diffing "
4908 624411d2 2023-07-08 jrick "a work tree");
4909 624411d2 2023-07-08 jrick goto done;
4911 624411d2 2023-07-08 jrick if (diff_staged) {
4912 624411d2 2023-07-08 jrick error = got_error_msg(GOT_ERR_NOT_IMPL,
4913 624411d2 2023-07-08 jrick "-s option can only be used when diffing "
4914 624411d2 2023-07-08 jrick "a work tree");
4915 624411d2 2023-07-08 jrick goto done;
4919 624411d2 2023-07-08 jrick error = apply_unveil(got_repo_get_path(repo), 1,
4920 624411d2 2023-07-08 jrick worktree ? got_worktree_get_root_path(worktree) : NULL);
4921 624411d2 2023-07-08 jrick if (error)
4922 624411d2 2023-07-08 jrick goto done;
4924 624411d2 2023-07-08 jrick if ((!force_path && argc == 2) || ncommit_args > 0) {
4925 624411d2 2023-07-08 jrick int obj_type = (ncommit_args > 0 ?
4926 624411d2 2023-07-08 jrick GOT_OBJ_TYPE_COMMIT : GOT_OBJ_TYPE_ANY);
4927 624411d2 2023-07-08 jrick error = got_ref_list(&refs, repo, NULL, got_ref_cmp_by_name,
4929 624411d2 2023-07-08 jrick if (error)
4930 624411d2 2023-07-08 jrick goto done;
4931 624411d2 2023-07-08 jrick for (i = 0; i < (ncommit_args > 0 ? ncommit_args : argc); i++) {
4932 624411d2 2023-07-08 jrick const char *arg;
4933 624411d2 2023-07-08 jrick if (ncommit_args > 0)
4934 624411d2 2023-07-08 jrick arg = commit_args[i];
4936 624411d2 2023-07-08 jrick arg = argv[i];
4937 624411d2 2023-07-08 jrick error = got_repo_match_object_id(&ids[i], &labels[i],
4938 624411d2 2023-07-08 jrick arg, obj_type, &refs, repo);
4939 624411d2 2023-07-08 jrick if (error) {
4940 624411d2 2023-07-08 jrick if (error->code != GOT_ERR_NOT_REF &&
4941 624411d2 2023-07-08 jrick error->code != GOT_ERR_NO_OBJ)
4942 624411d2 2023-07-08 jrick goto done;
4943 624411d2 2023-07-08 jrick if (ncommit_args > 0)
4944 624411d2 2023-07-08 jrick goto done;
4945 624411d2 2023-07-08 jrick error = NULL;
4951 624411d2 2023-07-08 jrick f1 = got_opentemp();
4952 624411d2 2023-07-08 jrick if (f1 == NULL) {
4953 624411d2 2023-07-08 jrick error = got_error_from_errno("got_opentemp");
4954 624411d2 2023-07-08 jrick goto done;
4957 624411d2 2023-07-08 jrick f2 = got_opentemp();
4958 624411d2 2023-07-08 jrick if (f2 == NULL) {
4959 624411d2 2023-07-08 jrick error = got_error_from_errno("got_opentemp");
4960 624411d2 2023-07-08 jrick goto done;
4963 624411d2 2023-07-08 jrick outfile = got_opentemp();
4964 624411d2 2023-07-08 jrick if (outfile == NULL) {
4965 624411d2 2023-07-08 jrick error = got_error_from_errno("got_opentemp");
4966 624411d2 2023-07-08 jrick goto done;
4969 624411d2 2023-07-08 jrick if (ncommit_args == 0 && (ids[0] == NULL || ids[1] == NULL)) {
4970 624411d2 2023-07-08 jrick struct print_diff_arg arg;
4971 624411d2 2023-07-08 jrick char *id_str;
4973 624411d2 2023-07-08 jrick if (worktree == NULL) {
4974 624411d2 2023-07-08 jrick if (argc == 2 && ids[0] == NULL) {
4975 624411d2 2023-07-08 jrick error = got_error_path(argv[0], GOT_ERR_NO_OBJ);
4976 624411d2 2023-07-08 jrick goto done;
4977 624411d2 2023-07-08 jrick } else if (argc == 2 && ids[1] == NULL) {
4978 624411d2 2023-07-08 jrick error = got_error_path(argv[1], GOT_ERR_NO_OBJ);
4979 624411d2 2023-07-08 jrick goto done;
4980 624411d2 2023-07-08 jrick } else if (argc > 0) {
4981 624411d2 2023-07-08 jrick error = got_error_fmt(GOT_ERR_NOT_WORKTREE,
4982 624411d2 2023-07-08 jrick "%s", "specified paths cannot be resolved");
4983 624411d2 2023-07-08 jrick goto done;
4985 624411d2 2023-07-08 jrick error = got_error(GOT_ERR_NOT_WORKTREE);
4986 624411d2 2023-07-08 jrick goto done;
4990 624411d2 2023-07-08 jrick error = get_worktree_paths_from_argv(&paths, argc, argv,
4991 624411d2 2023-07-08 jrick worktree);
4992 624411d2 2023-07-08 jrick if (error)
4993 624411d2 2023-07-08 jrick goto done;
4995 624411d2 2023-07-08 jrick error = got_object_id_str(&id_str,
4996 624411d2 2023-07-08 jrick got_worktree_get_base_commit_id(worktree));
4997 624411d2 2023-07-08 jrick if (error)
4998 624411d2 2023-07-08 jrick goto done;
4999 624411d2 2023-07-08 jrick arg.repo = repo;
5000 624411d2 2023-07-08 jrick arg.worktree = worktree;
5001 624411d2 2023-07-08 jrick arg.diff_algo = GOT_DIFF_ALGORITHM_PATIENCE;
5002 624411d2 2023-07-08 jrick arg.diff_context = diff_context;
5003 624411d2 2023-07-08 jrick arg.id_str = id_str;
5004 624411d2 2023-07-08 jrick arg.header_shown = 0;
5005 624411d2 2023-07-08 jrick arg.diff_staged = diff_staged;
5006 624411d2 2023-07-08 jrick arg.ignore_whitespace = ignore_whitespace;
5007 624411d2 2023-07-08 jrick arg.force_text_diff = force_text_diff;
5008 624411d2 2023-07-08 jrick arg.diffstat = show_diffstat ? &dsa : NULL;
5009 624411d2 2023-07-08 jrick arg.f1 = f1;
5010 624411d2 2023-07-08 jrick arg.f2 = f2;
5011 624411d2 2023-07-08 jrick arg.outfile = outfile;
5013 624411d2 2023-07-08 jrick error = got_worktree_status(worktree, &paths, repo, 0,
5014 624411d2 2023-07-08 jrick print_diff, &arg, check_cancelled, NULL);
5015 624411d2 2023-07-08 jrick free(id_str);
5016 624411d2 2023-07-08 jrick if (error)
5017 624411d2 2023-07-08 jrick goto done;
5019 624411d2 2023-07-08 jrick if (show_diffstat && dsa.nfiles > 0) {
5020 624411d2 2023-07-08 jrick char *header;
5022 624411d2 2023-07-08 jrick if (asprintf(&header, "diffstat %s%s",
5023 624411d2 2023-07-08 jrick diff_staged ? "-s " : "",
5024 624411d2 2023-07-08 jrick got_worktree_get_root_path(worktree)) == -1) {
5025 624411d2 2023-07-08 jrick error = got_error_from_errno("asprintf");
5026 624411d2 2023-07-08 jrick goto done;
5029 624411d2 2023-07-08 jrick error = print_diffstat(&dsa, header);
5030 624411d2 2023-07-08 jrick free(header);
5031 624411d2 2023-07-08 jrick if (error)
5032 624411d2 2023-07-08 jrick goto done;
5035 624411d2 2023-07-08 jrick error = printfile(outfile);
5036 624411d2 2023-07-08 jrick goto done;
5039 624411d2 2023-07-08 jrick if (ncommit_args == 1) {
5040 624411d2 2023-07-08 jrick struct got_commit_object *commit;
5041 624411d2 2023-07-08 jrick error = got_object_open_as_commit(&commit, repo, ids[0]);
5042 624411d2 2023-07-08 jrick if (error)
5043 624411d2 2023-07-08 jrick goto done;
5045 624411d2 2023-07-08 jrick labels[1] = labels[0];
5046 624411d2 2023-07-08 jrick ids[1] = ids[0];
5047 624411d2 2023-07-08 jrick if (got_object_commit_get_nparents(commit) > 0) {
5048 624411d2 2023-07-08 jrick const struct got_object_id_queue *pids;
5049 624411d2 2023-07-08 jrick struct got_object_qid *pid;
5050 624411d2 2023-07-08 jrick pids = got_object_commit_get_parent_ids(commit);
5051 624411d2 2023-07-08 jrick pid = STAILQ_FIRST(pids);
5052 624411d2 2023-07-08 jrick ids[0] = got_object_id_dup(&pid->id);
5053 624411d2 2023-07-08 jrick if (ids[0] == NULL) {
5054 624411d2 2023-07-08 jrick error = got_error_from_errno(
5055 624411d2 2023-07-08 jrick "got_object_id_dup");
5056 624411d2 2023-07-08 jrick got_object_commit_close(commit);
5057 624411d2 2023-07-08 jrick goto done;
5059 624411d2 2023-07-08 jrick error = got_object_id_str(&labels[0], ids[0]);
5060 624411d2 2023-07-08 jrick if (error) {
5061 624411d2 2023-07-08 jrick got_object_commit_close(commit);
5062 624411d2 2023-07-08 jrick goto done;
5065 624411d2 2023-07-08 jrick ids[0] = NULL;
5066 624411d2 2023-07-08 jrick labels[0] = strdup("/dev/null");
5067 624411d2 2023-07-08 jrick if (labels[0] == NULL) {
5068 624411d2 2023-07-08 jrick error = got_error_from_errno("strdup");
5069 624411d2 2023-07-08 jrick got_object_commit_close(commit);
5070 624411d2 2023-07-08 jrick goto done;
5074 624411d2 2023-07-08 jrick got_object_commit_close(commit);
5077 624411d2 2023-07-08 jrick if (ncommit_args == 0 && argc > 2) {
5078 624411d2 2023-07-08 jrick error = got_error_msg(GOT_ERR_BAD_PATH,
5079 624411d2 2023-07-08 jrick "path arguments cannot be used when diffing two objects");
5080 624411d2 2023-07-08 jrick goto done;
5083 624411d2 2023-07-08 jrick if (ids[0]) {
5084 624411d2 2023-07-08 jrick error = got_object_get_type(&type1, repo, ids[0]);
5085 624411d2 2023-07-08 jrick if (error)
5086 624411d2 2023-07-08 jrick goto done;
5089 624411d2 2023-07-08 jrick error = got_object_get_type(&type2, repo, ids[1]);
5090 624411d2 2023-07-08 jrick if (error)
5091 624411d2 2023-07-08 jrick goto done;
5092 624411d2 2023-07-08 jrick if (type1 != GOT_OBJ_TYPE_ANY && type1 != type2) {
5093 624411d2 2023-07-08 jrick error = got_error(GOT_ERR_OBJ_TYPE);
5094 624411d2 2023-07-08 jrick goto done;
5096 624411d2 2023-07-08 jrick if (type1 == GOT_OBJ_TYPE_BLOB && argc > 2) {
5097 624411d2 2023-07-08 jrick error = got_error_msg(GOT_ERR_OBJ_TYPE,
5098 624411d2 2023-07-08 jrick "path arguments cannot be used when diffing blobs");
5099 624411d2 2023-07-08 jrick goto done;
5102 624411d2 2023-07-08 jrick for (i = 0; ncommit_args > 0 && i < argc; i++) {
5103 624411d2 2023-07-08 jrick char *in_repo_path;
5104 624411d2 2023-07-08 jrick struct got_pathlist_entry *new;
5105 624411d2 2023-07-08 jrick if (worktree) {
5106 624411d2 2023-07-08 jrick const char *prefix;
5108 624411d2 2023-07-08 jrick error = got_worktree_resolve_path(&p, worktree,
5109 624411d2 2023-07-08 jrick argv[i]);
5110 624411d2 2023-07-08 jrick if (error)
5111 624411d2 2023-07-08 jrick goto done;
5112 624411d2 2023-07-08 jrick prefix = got_worktree_get_path_prefix(worktree);
5113 624411d2 2023-07-08 jrick while (prefix[0] == '/')
5114 624411d2 2023-07-08 jrick prefix++;
5115 624411d2 2023-07-08 jrick if (asprintf(&in_repo_path, "%s%s%s", prefix,
5116 624411d2 2023-07-08 jrick (p[0] != '\0' && prefix[0] != '\0') ? "/" : "",
5117 624411d2 2023-07-08 jrick p) == -1) {
5118 624411d2 2023-07-08 jrick error = got_error_from_errno("asprintf");
5120 624411d2 2023-07-08 jrick goto done;
5124 624411d2 2023-07-08 jrick char *mapped_path, *s;
5125 624411d2 2023-07-08 jrick error = got_repo_map_path(&mapped_path, repo, argv[i]);
5126 624411d2 2023-07-08 jrick if (error)
5127 624411d2 2023-07-08 jrick goto done;
5128 624411d2 2023-07-08 jrick s = mapped_path;
5129 624411d2 2023-07-08 jrick while (s[0] == '/')
5131 624411d2 2023-07-08 jrick in_repo_path = strdup(s);
5132 624411d2 2023-07-08 jrick if (in_repo_path == NULL) {
5133 624411d2 2023-07-08 jrick error = got_error_from_errno("asprintf");
5134 624411d2 2023-07-08 jrick free(mapped_path);
5135 624411d2 2023-07-08 jrick goto done;
5137 624411d2 2023-07-08 jrick free(mapped_path);
5140 624411d2 2023-07-08 jrick error = got_pathlist_insert(&new, &paths, in_repo_path, NULL);
5141 624411d2 2023-07-08 jrick if (error || new == NULL /* duplicate */)
5142 624411d2 2023-07-08 jrick free(in_repo_path);
5143 624411d2 2023-07-08 jrick if (error)
5144 624411d2 2023-07-08 jrick goto done;
5147 624411d2 2023-07-08 jrick if (worktree) {
5148 624411d2 2023-07-08 jrick /* Release work tree lock. */
5149 624411d2 2023-07-08 jrick got_worktree_close(worktree);
5150 624411d2 2023-07-08 jrick worktree = NULL;
5153 624411d2 2023-07-08 jrick fd1 = got_opentempfd();
5154 624411d2 2023-07-08 jrick if (fd1 == -1) {
5155 624411d2 2023-07-08 jrick error = got_error_from_errno("got_opentempfd");
5156 624411d2 2023-07-08 jrick goto done;
5159 624411d2 2023-07-08 jrick fd2 = got_opentempfd();
5160 624411d2 2023-07-08 jrick if (fd2 == -1) {
5161 624411d2 2023-07-08 jrick error = got_error_from_errno("got_opentempfd");
5162 624411d2 2023-07-08 jrick goto done;
5165 624411d2 2023-07-08 jrick switch (type1 == GOT_OBJ_TYPE_ANY ? type2 : type1) {
5166 624411d2 2023-07-08 jrick case GOT_OBJ_TYPE_BLOB:
5167 624411d2 2023-07-08 jrick error = got_diff_objects_as_blobs(NULL, NULL, f1, f2,
5168 624411d2 2023-07-08 jrick fd1, fd2, ids[0], ids[1], NULL, NULL,
5169 624411d2 2023-07-08 jrick GOT_DIFF_ALGORITHM_PATIENCE, diff_context,
5170 624411d2 2023-07-08 jrick ignore_whitespace, force_text_diff,
5171 624411d2 2023-07-08 jrick show_diffstat ? &dsa : NULL, repo, outfile);
5173 624411d2 2023-07-08 jrick case GOT_OBJ_TYPE_TREE:
5174 624411d2 2023-07-08 jrick error = got_diff_objects_as_trees(NULL, NULL, f1, f2, fd1, fd2,
5175 624411d2 2023-07-08 jrick ids[0], ids[1], &paths, "", "",
5176 624411d2 2023-07-08 jrick GOT_DIFF_ALGORITHM_PATIENCE, diff_context,
5177 624411d2 2023-07-08 jrick ignore_whitespace, force_text_diff,
5178 624411d2 2023-07-08 jrick show_diffstat ? &dsa : NULL, repo, outfile);
5180 624411d2 2023-07-08 jrick case GOT_OBJ_TYPE_COMMIT:
5181 624411d2 2023-07-08 jrick fprintf(outfile, "diff %s %s\n", labels[0], labels[1]);
5182 624411d2 2023-07-08 jrick error = got_diff_objects_as_commits(NULL, NULL, f1, f2,
5183 624411d2 2023-07-08 jrick fd1, fd2, ids[0], ids[1], &paths,
5184 624411d2 2023-07-08 jrick GOT_DIFF_ALGORITHM_PATIENCE, diff_context,
5185 624411d2 2023-07-08 jrick ignore_whitespace, force_text_diff,
5186 624411d2 2023-07-08 jrick show_diffstat ? &dsa : NULL, repo, outfile);
5189 624411d2 2023-07-08 jrick error = got_error(GOT_ERR_OBJ_TYPE);
5191 624411d2 2023-07-08 jrick if (error)
5192 624411d2 2023-07-08 jrick goto done;
5194 624411d2 2023-07-08 jrick if (show_diffstat && dsa.nfiles > 0) {
5195 624411d2 2023-07-08 jrick char *header = NULL;
5197 624411d2 2023-07-08 jrick if (asprintf(&header, "diffstat %s %s",
5198 624411d2 2023-07-08 jrick labels[0], labels[1]) == -1) {
5199 624411d2 2023-07-08 jrick error = got_error_from_errno("asprintf");
5200 624411d2 2023-07-08 jrick goto done;
5203 624411d2 2023-07-08 jrick error = print_diffstat(&dsa, header);
5204 624411d2 2023-07-08 jrick free(header);
5205 624411d2 2023-07-08 jrick if (error)
5206 624411d2 2023-07-08 jrick goto done;
5209 624411d2 2023-07-08 jrick error = printfile(outfile);
5212 624411d2 2023-07-08 jrick free(labels[0]);
5213 624411d2 2023-07-08 jrick free(labels[1]);
5214 624411d2 2023-07-08 jrick free(ids[0]);
5215 624411d2 2023-07-08 jrick free(ids[1]);
5216 624411d2 2023-07-08 jrick if (worktree)
5217 624411d2 2023-07-08 jrick got_worktree_close(worktree);
5218 624411d2 2023-07-08 jrick if (repo) {
5219 624411d2 2023-07-08 jrick const struct got_error *close_err = got_repo_close(repo);
5220 624411d2 2023-07-08 jrick if (error == NULL)
5221 624411d2 2023-07-08 jrick error = close_err;
5223 624411d2 2023-07-08 jrick if (pack_fds) {
5224 624411d2 2023-07-08 jrick const struct got_error *pack_err =
5225 624411d2 2023-07-08 jrick got_repo_pack_fds_close(pack_fds);
5226 624411d2 2023-07-08 jrick if (error == NULL)
5227 624411d2 2023-07-08 jrick error = pack_err;
5229 624411d2 2023-07-08 jrick got_pathlist_free(&paths, GOT_PATHLIST_FREE_PATH);
5230 624411d2 2023-07-08 jrick got_pathlist_free(&diffstat_paths, GOT_PATHLIST_FREE_ALL);
5231 624411d2 2023-07-08 jrick got_ref_list_free(&refs);
5232 624411d2 2023-07-08 jrick if (outfile && fclose(outfile) == EOF && error == NULL)
5233 624411d2 2023-07-08 jrick error = got_error_from_errno("fclose");
5234 624411d2 2023-07-08 jrick if (f1 && fclose(f1) == EOF && error == NULL)
5235 624411d2 2023-07-08 jrick error = got_error_from_errno("fclose");
5236 624411d2 2023-07-08 jrick if (f2 && fclose(f2) == EOF && error == NULL)
5237 624411d2 2023-07-08 jrick error = got_error_from_errno("fclose");
5238 624411d2 2023-07-08 jrick if (fd1 != -1 && close(fd1) == -1 && error == NULL)
5239 624411d2 2023-07-08 jrick error = got_error_from_errno("close");
5240 624411d2 2023-07-08 jrick if (fd2 != -1 && close(fd2) == -1 && error == NULL)
5241 624411d2 2023-07-08 jrick error = got_error_from_errno("close");
5242 624411d2 2023-07-08 jrick return error;
5245 624411d2 2023-07-08 jrick __dead static void
5246 624411d2 2023-07-08 jrick usage_blame(void)
5248 624411d2 2023-07-08 jrick fprintf(stderr,
5249 624411d2 2023-07-08 jrick "usage: %s blame [-c commit] [-r repository-path] path\n",
5250 624411d2 2023-07-08 jrick getprogname());
5254 624411d2 2023-07-08 jrick struct blame_line {
5255 624411d2 2023-07-08 jrick int annotated;
5256 624411d2 2023-07-08 jrick char *id_str;
5257 624411d2 2023-07-08 jrick char *committer;
5258 624411d2 2023-07-08 jrick char datebuf[11]; /* YYYY-MM-DD + NUL */
5261 624411d2 2023-07-08 jrick struct blame_cb_args {
5262 624411d2 2023-07-08 jrick struct blame_line *lines;
5263 624411d2 2023-07-08 jrick int nlines;
5264 624411d2 2023-07-08 jrick int nlines_prec;
5265 624411d2 2023-07-08 jrick int lineno_cur;
5266 624411d2 2023-07-08 jrick off_t *line_offsets;
5268 624411d2 2023-07-08 jrick struct got_repository *repo;
5271 624411d2 2023-07-08 jrick static const struct got_error *
5272 624411d2 2023-07-08 jrick blame_cb(void *arg, int nlines, int lineno,
5273 624411d2 2023-07-08 jrick struct got_commit_object *commit, struct got_object_id *id)
5275 624411d2 2023-07-08 jrick const struct got_error *err = NULL;
5276 624411d2 2023-07-08 jrick struct blame_cb_args *a = arg;
5277 624411d2 2023-07-08 jrick struct blame_line *bline;
5278 624411d2 2023-07-08 jrick char *line = NULL;
5279 624411d2 2023-07-08 jrick size_t linesize = 0;
5280 624411d2 2023-07-08 jrick off_t offset;
5281 624411d2 2023-07-08 jrick struct tm tm;
5282 624411d2 2023-07-08 jrick time_t committer_time;
5284 624411d2 2023-07-08 jrick if (nlines != a->nlines ||
5285 624411d2 2023-07-08 jrick (lineno != -1 && lineno < 1) || lineno > a->nlines)
5286 624411d2 2023-07-08 jrick return got_error(GOT_ERR_RANGE);
5288 624411d2 2023-07-08 jrick if (sigint_received)
5289 624411d2 2023-07-08 jrick return got_error(GOT_ERR_ITER_COMPLETED);
5291 624411d2 2023-07-08 jrick if (lineno == -1)
5292 624411d2 2023-07-08 jrick return NULL; /* no change in this commit */
5294 624411d2 2023-07-08 jrick /* Annotate this line. */
5295 624411d2 2023-07-08 jrick bline = &a->lines[lineno - 1];
5296 624411d2 2023-07-08 jrick if (bline->annotated)
5297 624411d2 2023-07-08 jrick return NULL;
5298 624411d2 2023-07-08 jrick err = got_object_id_str(&bline->id_str, id);
5300 624411d2 2023-07-08 jrick return err;
5302 624411d2 2023-07-08 jrick bline->committer = strdup(got_object_commit_get_committer(commit));
5303 624411d2 2023-07-08 jrick if (bline->committer == NULL) {
5304 624411d2 2023-07-08 jrick err = got_error_from_errno("strdup");
5305 624411d2 2023-07-08 jrick goto done;
5308 624411d2 2023-07-08 jrick committer_time = got_object_commit_get_committer_time(commit);
5309 624411d2 2023-07-08 jrick if (gmtime_r(&committer_time, &tm) == NULL)
5310 624411d2 2023-07-08 jrick return got_error_from_errno("gmtime_r");
5311 624411d2 2023-07-08 jrick if (strftime(bline->datebuf, sizeof(bline->datebuf), "%G-%m-%d",
5312 624411d2 2023-07-08 jrick &tm) == 0) {
5313 624411d2 2023-07-08 jrick err = got_error(GOT_ERR_NO_SPACE);
5314 624411d2 2023-07-08 jrick goto done;
5316 624411d2 2023-07-08 jrick bline->annotated = 1;
5318 624411d2 2023-07-08 jrick /* Print lines annotated so far. */
5319 624411d2 2023-07-08 jrick bline = &a->lines[a->lineno_cur - 1];
5320 624411d2 2023-07-08 jrick if (!bline->annotated)
5321 624411d2 2023-07-08 jrick goto done;
5323 624411d2 2023-07-08 jrick offset = a->line_offsets[a->lineno_cur - 1];
5324 624411d2 2023-07-08 jrick if (fseeko(a->f, offset, SEEK_SET) == -1) {
5325 624411d2 2023-07-08 jrick err = got_error_from_errno("fseeko");
5326 624411d2 2023-07-08 jrick goto done;
5329 624411d2 2023-07-08 jrick while (a->lineno_cur <= a->nlines && bline->annotated) {
5330 624411d2 2023-07-08 jrick char *smallerthan, *at, *nl, *committer;
5331 624411d2 2023-07-08 jrick size_t len;
5333 624411d2 2023-07-08 jrick if (getline(&line, &linesize, a->f) == -1) {
5334 624411d2 2023-07-08 jrick if (ferror(a->f))
5335 624411d2 2023-07-08 jrick err = got_error_from_errno("getline");
5339 624411d2 2023-07-08 jrick committer = bline->committer;
5340 624411d2 2023-07-08 jrick smallerthan = strchr(committer, '<');
5341 624411d2 2023-07-08 jrick if (smallerthan && smallerthan[1] != '\0')
5342 624411d2 2023-07-08 jrick committer = smallerthan + 1;
5343 624411d2 2023-07-08 jrick at = strchr(committer, '@');
5345 624411d2 2023-07-08 jrick *at = '\0';
5346 624411d2 2023-07-08 jrick len = strlen(committer);
5347 624411d2 2023-07-08 jrick if (len >= 9)
5348 624411d2 2023-07-08 jrick committer[8] = '\0';
5350 624411d2 2023-07-08 jrick nl = strchr(line, '\n');
5352 624411d2 2023-07-08 jrick *nl = '\0';
5353 624411d2 2023-07-08 jrick printf("%.*d) %.8s %s %-8s %s\n", a->nlines_prec, a->lineno_cur,
5354 624411d2 2023-07-08 jrick bline->id_str, bline->datebuf, committer, line);
5356 624411d2 2023-07-08 jrick a->lineno_cur++;
5357 624411d2 2023-07-08 jrick bline = &a->lines[a->lineno_cur - 1];
5360 624411d2 2023-07-08 jrick free(line);
5361 624411d2 2023-07-08 jrick return err;
5364 624411d2 2023-07-08 jrick static const struct got_error *
5365 624411d2 2023-07-08 jrick cmd_blame(int argc, char *argv[])
5367 624411d2 2023-07-08 jrick const struct got_error *error;
5368 624411d2 2023-07-08 jrick struct got_repository *repo = NULL;
5369 624411d2 2023-07-08 jrick struct got_worktree *worktree = NULL;
5370 624411d2 2023-07-08 jrick char *path, *cwd = NULL, *repo_path = NULL, *in_repo_path = NULL;
5371 624411d2 2023-07-08 jrick char *link_target = NULL;
5372 624411d2 2023-07-08 jrick struct got_object_id *obj_id = NULL;
5373 624411d2 2023-07-08 jrick struct got_object_id *commit_id = NULL;
5374 624411d2 2023-07-08 jrick struct got_commit_object *commit = NULL;
5375 624411d2 2023-07-08 jrick struct got_blob_object *blob = NULL;
5376 624411d2 2023-07-08 jrick char *commit_id_str = NULL;
5377 624411d2 2023-07-08 jrick struct blame_cb_args bca;
5378 624411d2 2023-07-08 jrick int ch, obj_type, i, fd1 = -1, fd2 = -1, fd3 = -1;
5379 624411d2 2023-07-08 jrick off_t filesize;
5380 624411d2 2023-07-08 jrick int *pack_fds = NULL;
5381 624411d2 2023-07-08 jrick FILE *f1 = NULL, *f2 = NULL;
5383 624411d2 2023-07-08 jrick fd1 = got_opentempfd();
5384 624411d2 2023-07-08 jrick if (fd1 == -1)
5385 624411d2 2023-07-08 jrick return got_error_from_errno("got_opentempfd");
5387 624411d2 2023-07-08 jrick memset(&bca, 0, sizeof(bca));
5389 624411d2 2023-07-08 jrick #ifndef PROFILE
5390 624411d2 2023-07-08 jrick if (pledge("stdio rpath wpath cpath flock proc exec sendfd unveil",
5391 624411d2 2023-07-08 jrick NULL) == -1)
5392 624411d2 2023-07-08 jrick err(1, "pledge");
5395 624411d2 2023-07-08 jrick while ((ch = getopt(argc, argv, "c:r:")) != -1) {
5396 624411d2 2023-07-08 jrick switch (ch) {
5397 624411d2 2023-07-08 jrick case 'c':
5398 624411d2 2023-07-08 jrick commit_id_str = optarg;
5400 624411d2 2023-07-08 jrick case 'r':
5401 624411d2 2023-07-08 jrick repo_path = realpath(optarg, NULL);
5402 624411d2 2023-07-08 jrick if (repo_path == NULL)
5403 624411d2 2023-07-08 jrick return got_error_from_errno2("realpath",
5405 624411d2 2023-07-08 jrick got_path_strip_trailing_slashes(repo_path);
5408 624411d2 2023-07-08 jrick usage_blame();
5409 624411d2 2023-07-08 jrick /* NOTREACHED */
5413 624411d2 2023-07-08 jrick argc -= optind;
5414 624411d2 2023-07-08 jrick argv += optind;
5416 624411d2 2023-07-08 jrick if (argc == 1)
5417 624411d2 2023-07-08 jrick path = argv[0];
5419 624411d2 2023-07-08 jrick usage_blame();
5421 624411d2 2023-07-08 jrick cwd = getcwd(NULL, 0);
5422 624411d2 2023-07-08 jrick if (cwd == NULL) {
5423 624411d2 2023-07-08 jrick error = got_error_from_errno("getcwd");
5424 624411d2 2023-07-08 jrick goto done;
5427 624411d2 2023-07-08 jrick error = got_repo_pack_fds_open(&pack_fds);
5428 624411d2 2023-07-08 jrick if (error != NULL)
5429 624411d2 2023-07-08 jrick goto done;
5431 624411d2 2023-07-08 jrick if (repo_path == NULL) {
5432 624411d2 2023-07-08 jrick error = got_worktree_open(&worktree, cwd);
5433 624411d2 2023-07-08 jrick if (error && error->code != GOT_ERR_NOT_WORKTREE)
5434 624411d2 2023-07-08 jrick goto done;
5436 624411d2 2023-07-08 jrick error = NULL;
5437 624411d2 2023-07-08 jrick if (worktree) {
5438 624411d2 2023-07-08 jrick repo_path =
5439 624411d2 2023-07-08 jrick strdup(got_worktree_get_repo_path(worktree));
5440 624411d2 2023-07-08 jrick if (repo_path == NULL) {
5441 624411d2 2023-07-08 jrick error = got_error_from_errno("strdup");
5442 624411d2 2023-07-08 jrick if (error)
5443 624411d2 2023-07-08 jrick goto done;
5446 624411d2 2023-07-08 jrick repo_path = strdup(cwd);
5447 624411d2 2023-07-08 jrick if (repo_path == NULL) {
5448 624411d2 2023-07-08 jrick error = got_error_from_errno("strdup");
5449 624411d2 2023-07-08 jrick goto done;
5454 624411d2 2023-07-08 jrick error = got_repo_open(&repo, repo_path, NULL, pack_fds);
5455 624411d2 2023-07-08 jrick if (error != NULL)
5456 624411d2 2023-07-08 jrick goto done;
5458 624411d2 2023-07-08 jrick if (worktree) {
5459 624411d2 2023-07-08 jrick const char *prefix = got_worktree_get_path_prefix(worktree);
5462 624411d2 2023-07-08 jrick error = got_worktree_resolve_path(&p, worktree, path);
5463 624411d2 2023-07-08 jrick if (error)
5464 624411d2 2023-07-08 jrick goto done;
5465 624411d2 2023-07-08 jrick if (asprintf(&in_repo_path, "%s%s%s", prefix,
5466 624411d2 2023-07-08 jrick (p[0] != '\0' && !got_path_is_root_dir(prefix)) ? "/" : "",
5467 624411d2 2023-07-08 jrick p) == -1) {
5468 624411d2 2023-07-08 jrick error = got_error_from_errno("asprintf");
5470 624411d2 2023-07-08 jrick goto done;
5473 624411d2 2023-07-08 jrick error = apply_unveil(got_repo_get_path(repo), 1, NULL);
5475 624411d2 2023-07-08 jrick error = apply_unveil(got_repo_get_path(repo), 1, NULL);
5476 624411d2 2023-07-08 jrick if (error)
5477 624411d2 2023-07-08 jrick goto done;
5478 624411d2 2023-07-08 jrick error = got_repo_map_path(&in_repo_path, repo, path);
5480 624411d2 2023-07-08 jrick if (error)
5481 624411d2 2023-07-08 jrick goto done;
5483 624411d2 2023-07-08 jrick if (commit_id_str == NULL) {
5484 624411d2 2023-07-08 jrick struct got_reference *head_ref;
5485 624411d2 2023-07-08 jrick error = got_ref_open(&head_ref, repo, worktree ?
5486 624411d2 2023-07-08 jrick got_worktree_get_head_ref_name(worktree) : GOT_REF_HEAD, 0);
5487 624411d2 2023-07-08 jrick if (error != NULL)
5488 624411d2 2023-07-08 jrick goto done;
5489 624411d2 2023-07-08 jrick error = got_ref_resolve(&commit_id, repo, head_ref);
5490 624411d2 2023-07-08 jrick got_ref_close(head_ref);
5491 624411d2 2023-07-08 jrick if (error != NULL)
5492 624411d2 2023-07-08 jrick goto done;
5494 624411d2 2023-07-08 jrick struct got_reflist_head refs;
5495 624411d2 2023-07-08 jrick TAILQ_INIT(&refs);
5496 624411d2 2023-07-08 jrick error = got_ref_list(&refs, repo, NULL, got_ref_cmp_by_name,
5498 624411d2 2023-07-08 jrick if (error)
5499 624411d2 2023-07-08 jrick goto done;
5500 624411d2 2023-07-08 jrick error = got_repo_match_object_id(&commit_id, NULL,
5501 624411d2 2023-07-08 jrick commit_id_str, GOT_OBJ_TYPE_COMMIT, &refs, repo);
5502 624411d2 2023-07-08 jrick got_ref_list_free(&refs);
5503 624411d2 2023-07-08 jrick if (error)
5504 624411d2 2023-07-08 jrick goto done;
5507 624411d2 2023-07-08 jrick if (worktree) {
5508 624411d2 2023-07-08 jrick /* Release work tree lock. */
5509 624411d2 2023-07-08 jrick got_worktree_close(worktree);
5510 624411d2 2023-07-08 jrick worktree = NULL;
5513 624411d2 2023-07-08 jrick error = got_object_open_as_commit(&commit, repo, commit_id);
5514 624411d2 2023-07-08 jrick if (error)
5515 624411d2 2023-07-08 jrick goto done;
5517 624411d2 2023-07-08 jrick error = got_object_resolve_symlinks(&link_target, in_repo_path,
5518 624411d2 2023-07-08 jrick commit, repo);
5519 624411d2 2023-07-08 jrick if (error)
5520 624411d2 2023-07-08 jrick goto done;
5522 624411d2 2023-07-08 jrick error = got_object_id_by_path(&obj_id, repo, commit,
5523 624411d2 2023-07-08 jrick link_target ? link_target : in_repo_path);
5524 624411d2 2023-07-08 jrick if (error)
5525 624411d2 2023-07-08 jrick goto done;
5527 624411d2 2023-07-08 jrick error = got_object_get_type(&obj_type, repo, obj_id);
5528 624411d2 2023-07-08 jrick if (error)
5529 624411d2 2023-07-08 jrick goto done;
5531 624411d2 2023-07-08 jrick if (obj_type != GOT_OBJ_TYPE_BLOB) {
5532 624411d2 2023-07-08 jrick error = got_error_path(link_target ? link_target : in_repo_path,
5533 624411d2 2023-07-08 jrick GOT_ERR_OBJ_TYPE);
5534 624411d2 2023-07-08 jrick goto done;
5537 624411d2 2023-07-08 jrick error = got_object_open_as_blob(&blob, repo, obj_id, 8192, fd1);
5538 624411d2 2023-07-08 jrick if (error)
5539 624411d2 2023-07-08 jrick goto done;
5540 624411d2 2023-07-08 jrick bca.f = got_opentemp();
5541 624411d2 2023-07-08 jrick if (bca.f == NULL) {
5542 624411d2 2023-07-08 jrick error = got_error_from_errno("got_opentemp");
5543 624411d2 2023-07-08 jrick goto done;
5545 624411d2 2023-07-08 jrick error = got_object_blob_dump_to_file(&filesize, &bca.nlines,
5546 624411d2 2023-07-08 jrick &bca.line_offsets, bca.f, blob);
5547 624411d2 2023-07-08 jrick if (error || bca.nlines == 0)
5548 624411d2 2023-07-08 jrick goto done;
5550 624411d2 2023-07-08 jrick /* Don't include \n at EOF in the blame line count. */
5551 624411d2 2023-07-08 jrick if (bca.line_offsets[bca.nlines - 1] == filesize)
5552 624411d2 2023-07-08 jrick bca.nlines--;
5554 624411d2 2023-07-08 jrick bca.lines = calloc(bca.nlines, sizeof(*bca.lines));
5555 624411d2 2023-07-08 jrick if (bca.lines == NULL) {
5556 624411d2 2023-07-08 jrick error = got_error_from_errno("calloc");
5557 624411d2 2023-07-08 jrick goto done;
5559 624411d2 2023-07-08 jrick bca.lineno_cur = 1;
5560 624411d2 2023-07-08 jrick bca.nlines_prec = 0;
5561 624411d2 2023-07-08 jrick i = bca.nlines;
5562 624411d2 2023-07-08 jrick while (i > 0) {
5564 624411d2 2023-07-08 jrick bca.nlines_prec++;
5566 624411d2 2023-07-08 jrick bca.repo = repo;
5568 624411d2 2023-07-08 jrick fd2 = got_opentempfd();
5569 624411d2 2023-07-08 jrick if (fd2 == -1) {
5570 624411d2 2023-07-08 jrick error = got_error_from_errno("got_opentempfd");
5571 624411d2 2023-07-08 jrick goto done;
5573 624411d2 2023-07-08 jrick fd3 = got_opentempfd();
5574 624411d2 2023-07-08 jrick if (fd3 == -1) {
5575 624411d2 2023-07-08 jrick error = got_error_from_errno("got_opentempfd");
5576 624411d2 2023-07-08 jrick goto done;
5578 624411d2 2023-07-08 jrick f1 = got_opentemp();
5579 624411d2 2023-07-08 jrick if (f1 == NULL) {
5580 624411d2 2023-07-08 jrick error = got_error_from_errno("got_opentemp");
5581 624411d2 2023-07-08 jrick goto done;
5583 624411d2 2023-07-08 jrick f2 = got_opentemp();
5584 624411d2 2023-07-08 jrick if (f2 == NULL) {
5585 624411d2 2023-07-08 jrick error = got_error_from_errno("got_opentemp");
5586 624411d2 2023-07-08 jrick goto done;
5588 624411d2 2023-07-08 jrick error = got_blame(link_target ? link_target : in_repo_path, commit_id,
5589 624411d2 2023-07-08 jrick repo, GOT_DIFF_ALGORITHM_PATIENCE, blame_cb, &bca,
5590 624411d2 2023-07-08 jrick check_cancelled, NULL, fd2, fd3, f1, f2);
5592 624411d2 2023-07-08 jrick free(in_repo_path);
5593 624411d2 2023-07-08 jrick free(link_target);
5594 624411d2 2023-07-08 jrick free(repo_path);
5595 624411d2 2023-07-08 jrick free(cwd);
5596 624411d2 2023-07-08 jrick free(commit_id);
5597 624411d2 2023-07-08 jrick free(obj_id);
5598 624411d2 2023-07-08 jrick if (commit)
5599 624411d2 2023-07-08 jrick got_object_commit_close(commit);
5601 624411d2 2023-07-08 jrick if (fd1 != -1 && close(fd1) == -1 && error == NULL)
5602 624411d2 2023-07-08 jrick error = got_error_from_errno("close");
5603 624411d2 2023-07-08 jrick if (fd2 != -1 && close(fd2) == -1 && error == NULL)
5604 624411d2 2023-07-08 jrick error = got_error_from_errno("close");
5605 624411d2 2023-07-08 jrick if (fd3 != -1 && close(fd3) == -1 && error == NULL)
5606 624411d2 2023-07-08 jrick error = got_error_from_errno("close");
5607 624411d2 2023-07-08 jrick if (f1 && fclose(f1) == EOF && error == NULL)
5608 624411d2 2023-07-08 jrick error = got_error_from_errno("fclose");
5609 624411d2 2023-07-08 jrick if (f2 && fclose(f2) == EOF && error == NULL)
5610 624411d2 2023-07-08 jrick error = got_error_from_errno("fclose");
5612 624411d2 2023-07-08 jrick if (blob)
5613 624411d2 2023-07-08 jrick got_object_blob_close(blob);
5614 624411d2 2023-07-08 jrick if (worktree)
5615 624411d2 2023-07-08 jrick got_worktree_close(worktree);
5616 624411d2 2023-07-08 jrick if (repo) {
5617 624411d2 2023-07-08 jrick const struct got_error *close_err = got_repo_close(repo);
5618 624411d2 2023-07-08 jrick if (error == NULL)
5619 624411d2 2023-07-08 jrick error = close_err;
5621 624411d2 2023-07-08 jrick if (pack_fds) {
5622 624411d2 2023-07-08 jrick const struct got_error *pack_err =
5623 624411d2 2023-07-08 jrick got_repo_pack_fds_close(pack_fds);
5624 624411d2 2023-07-08 jrick if (error == NULL)
5625 624411d2 2023-07-08 jrick error = pack_err;
5627 624411d2 2023-07-08 jrick if (bca.lines) {
5628 624411d2 2023-07-08 jrick for (i = 0; i < bca.nlines; i++) {
5629 624411d2 2023-07-08 jrick struct blame_line *bline = &bca.lines[i];
5630 624411d2 2023-07-08 jrick free(bline->id_str);
5631 624411d2 2023-07-08 jrick free(bline->committer);
5633 624411d2 2023-07-08 jrick free(bca.lines);
5635 624411d2 2023-07-08 jrick free(bca.line_offsets);
5636 624411d2 2023-07-08 jrick if (bca.f && fclose(bca.f) == EOF && error == NULL)
5637 624411d2 2023-07-08 jrick error = got_error_from_errno("fclose");
5638 624411d2 2023-07-08 jrick return error;
5641 624411d2 2023-07-08 jrick __dead static void
5642 624411d2 2023-07-08 jrick usage_tree(void)
5644 624411d2 2023-07-08 jrick fprintf(stderr, "usage: %s tree [-iR] [-c commit] [-r repository-path] "
5645 624411d2 2023-07-08 jrick "[path]\n", getprogname());
5649 624411d2 2023-07-08 jrick static const struct got_error *
5650 624411d2 2023-07-08 jrick print_entry(struct got_tree_entry *te, const char *id, const char *path,
5651 624411d2 2023-07-08 jrick const char *root_path, struct got_repository *repo)
5653 624411d2 2023-07-08 jrick const struct got_error *err = NULL;
5654 624411d2 2023-07-08 jrick int is_root_path = (strcmp(path, root_path) == 0);
5655 624411d2 2023-07-08 jrick const char *modestr = "";
5656 624411d2 2023-07-08 jrick mode_t mode = got_tree_entry_get_mode(te);
5657 624411d2 2023-07-08 jrick char *link_target = NULL;
5659 624411d2 2023-07-08 jrick path += strlen(root_path);
5660 624411d2 2023-07-08 jrick while (path[0] == '/')
5663 624411d2 2023-07-08 jrick if (got_object_tree_entry_is_submodule(te))
5664 624411d2 2023-07-08 jrick modestr = "$";
5665 624411d2 2023-07-08 jrick else if (S_ISLNK(mode)) {
5668 624411d2 2023-07-08 jrick err = got_tree_entry_get_symlink_target(&link_target, te, repo);
5670 624411d2 2023-07-08 jrick return err;
5671 624411d2 2023-07-08 jrick for (i = 0; link_target[i] != '\0'; i++) {
5672 624411d2 2023-07-08 jrick if (!isprint((unsigned char)link_target[i]))
5673 624411d2 2023-07-08 jrick link_target[i] = '?';
5676 624411d2 2023-07-08 jrick modestr = "@";
5678 624411d2 2023-07-08 jrick else if (S_ISDIR(mode))
5679 624411d2 2023-07-08 jrick modestr = "/";
5680 624411d2 2023-07-08 jrick else if (mode & S_IXUSR)
5681 624411d2 2023-07-08 jrick modestr = "*";
5683 624411d2 2023-07-08 jrick printf("%s%s%s%s%s%s%s\n", id ? id : "", path,
5684 624411d2 2023-07-08 jrick is_root_path ? "" : "/", got_tree_entry_get_name(te), modestr,
5685 624411d2 2023-07-08 jrick link_target ? " -> ": "", link_target ? link_target : "");
5687 624411d2 2023-07-08 jrick free(link_target);
5688 624411d2 2023-07-08 jrick return NULL;
5691 624411d2 2023-07-08 jrick static const struct got_error *
5692 624411d2 2023-07-08 jrick print_tree(const char *path, struct got_commit_object *commit,
5693 624411d2 2023-07-08 jrick int show_ids, int recurse, const char *root_path,
5694 624411d2 2023-07-08 jrick struct got_repository *repo)
5696 624411d2 2023-07-08 jrick const struct got_error *err = NULL;
5697 624411d2 2023-07-08 jrick struct got_object_id *tree_id = NULL;
5698 624411d2 2023-07-08 jrick struct got_tree_object *tree = NULL;
5699 624411d2 2023-07-08 jrick int nentries, i;
5701 624411d2 2023-07-08 jrick err = got_object_id_by_path(&tree_id, repo, commit, path);
5703 624411d2 2023-07-08 jrick goto done;
5705 624411d2 2023-07-08 jrick err = got_object_open_as_tree(&tree, repo, tree_id);
5707 624411d2 2023-07-08 jrick goto done;
5708 624411d2 2023-07-08 jrick nentries = got_object_tree_get_nentries(tree);
5709 624411d2 2023-07-08 jrick for (i = 0; i < nentries; i++) {
5710 624411d2 2023-07-08 jrick struct got_tree_entry *te;
5711 624411d2 2023-07-08 jrick char *id = NULL;
5713 624411d2 2023-07-08 jrick if (sigint_received || sigpipe_received)
5716 624411d2 2023-07-08 jrick te = got_object_tree_get_entry(tree, i);
5717 624411d2 2023-07-08 jrick if (show_ids) {
5718 624411d2 2023-07-08 jrick char *id_str;
5719 624411d2 2023-07-08 jrick err = got_object_id_str(&id_str,
5720 624411d2 2023-07-08 jrick got_tree_entry_get_id(te));
5722 624411d2 2023-07-08 jrick goto done;
5723 624411d2 2023-07-08 jrick if (asprintf(&id, "%s ", id_str) == -1) {
5724 624411d2 2023-07-08 jrick err = got_error_from_errno("asprintf");
5725 624411d2 2023-07-08 jrick free(id_str);
5726 624411d2 2023-07-08 jrick goto done;
5728 624411d2 2023-07-08 jrick free(id_str);
5730 624411d2 2023-07-08 jrick err = print_entry(te, id, path, root_path, repo);
5731 624411d2 2023-07-08 jrick free(id);
5733 624411d2 2023-07-08 jrick goto done;
5735 624411d2 2023-07-08 jrick if (recurse && S_ISDIR(got_tree_entry_get_mode(te))) {
5736 624411d2 2023-07-08 jrick char *child_path;
5737 624411d2 2023-07-08 jrick if (asprintf(&child_path, "%s%s%s", path,
5738 624411d2 2023-07-08 jrick path[0] == '/' && path[1] == '\0' ? "" : "/",
5739 624411d2 2023-07-08 jrick got_tree_entry_get_name(te)) == -1) {
5740 624411d2 2023-07-08 jrick err = got_error_from_errno("asprintf");
5741 624411d2 2023-07-08 jrick goto done;
5743 624411d2 2023-07-08 jrick err = print_tree(child_path, commit, show_ids, 1,
5744 624411d2 2023-07-08 jrick root_path, repo);
5745 624411d2 2023-07-08 jrick free(child_path);
5747 624411d2 2023-07-08 jrick goto done;
5751 624411d2 2023-07-08 jrick if (tree)
5752 624411d2 2023-07-08 jrick got_object_tree_close(tree);
5753 624411d2 2023-07-08 jrick free(tree_id);
5754 624411d2 2023-07-08 jrick return err;
5757 624411d2 2023-07-08 jrick static const struct got_error *
5758 624411d2 2023-07-08 jrick cmd_tree(int argc, char *argv[])
5760 624411d2 2023-07-08 jrick const struct got_error *error;
5761 624411d2 2023-07-08 jrick struct got_repository *repo = NULL;
5762 624411d2 2023-07-08 jrick struct got_worktree *worktree = NULL;
5763 624411d2 2023-07-08 jrick const char *path, *refname = NULL;
5764 624411d2 2023-07-08 jrick char *cwd = NULL, *repo_path = NULL, *in_repo_path = NULL;
5765 624411d2 2023-07-08 jrick struct got_object_id *commit_id = NULL;
5766 624411d2 2023-07-08 jrick struct got_commit_object *commit = NULL;
5767 624411d2 2023-07-08 jrick char *commit_id_str = NULL;
5768 624411d2 2023-07-08 jrick int show_ids = 0, recurse = 0;
5770 624411d2 2023-07-08 jrick int *pack_fds = NULL;
5772 624411d2 2023-07-08 jrick #ifndef PROFILE
5773 624411d2 2023-07-08 jrick if (pledge("stdio rpath wpath cpath flock proc exec sendfd unveil",
5774 624411d2 2023-07-08 jrick NULL) == -1)
5775 624411d2 2023-07-08 jrick err(1, "pledge");
5778 624411d2 2023-07-08 jrick while ((ch = getopt(argc, argv, "c:iRr:")) != -1) {
5779 624411d2 2023-07-08 jrick switch (ch) {
5780 624411d2 2023-07-08 jrick case 'c':
5781 624411d2 2023-07-08 jrick commit_id_str = optarg;
5783 624411d2 2023-07-08 jrick case 'i':
5784 624411d2 2023-07-08 jrick show_ids = 1;
5786 624411d2 2023-07-08 jrick case 'R':
5787 624411d2 2023-07-08 jrick recurse = 1;
5789 624411d2 2023-07-08 jrick case 'r':
5790 624411d2 2023-07-08 jrick repo_path = realpath(optarg, NULL);
5791 624411d2 2023-07-08 jrick if (repo_path == NULL)
5792 624411d2 2023-07-08 jrick return got_error_from_errno2("realpath",
5794 624411d2 2023-07-08 jrick got_path_strip_trailing_slashes(repo_path);
5797 624411d2 2023-07-08 jrick usage_tree();
5798 624411d2 2023-07-08 jrick /* NOTREACHED */
5802 624411d2 2023-07-08 jrick argc -= optind;
5803 624411d2 2023-07-08 jrick argv += optind;
5805 624411d2 2023-07-08 jrick if (argc == 1)
5806 624411d2 2023-07-08 jrick path = argv[0];
5807 624411d2 2023-07-08 jrick else if (argc > 1)
5808 624411d2 2023-07-08 jrick usage_tree();
5810 624411d2 2023-07-08 jrick path = NULL;
5812 624411d2 2023-07-08 jrick cwd = getcwd(NULL, 0);
5813 624411d2 2023-07-08 jrick if (cwd == NULL) {
5814 624411d2 2023-07-08 jrick error = got_error_from_errno("getcwd");
5815 624411d2 2023-07-08 jrick goto done;
5818 624411d2 2023-07-08 jrick error = got_repo_pack_fds_open(&pack_fds);
5819 624411d2 2023-07-08 jrick if (error != NULL)
5820 624411d2 2023-07-08 jrick goto done;
5822 624411d2 2023-07-08 jrick if (repo_path == NULL) {
5823 624411d2 2023-07-08 jrick error = got_worktree_open(&worktree, cwd);
5824 624411d2 2023-07-08 jrick if (error && error->code != GOT_ERR_NOT_WORKTREE)
5825 624411d2 2023-07-08 jrick goto done;
5827 624411d2 2023-07-08 jrick error = NULL;
5828 624411d2 2023-07-08 jrick if (worktree) {
5829 624411d2 2023-07-08 jrick repo_path =
5830 624411d2 2023-07-08 jrick strdup(got_worktree_get_repo_path(worktree));
5831 624411d2 2023-07-08 jrick if (repo_path == NULL)
5832 624411d2 2023-07-08 jrick error = got_error_from_errno("strdup");
5833 624411d2 2023-07-08 jrick if (error)
5834 624411d2 2023-07-08 jrick goto done;
5836 624411d2 2023-07-08 jrick repo_path = strdup(cwd);
5837 624411d2 2023-07-08 jrick if (repo_path == NULL) {
5838 624411d2 2023-07-08 jrick error = got_error_from_errno("strdup");
5839 624411d2 2023-07-08 jrick goto done;
5844 624411d2 2023-07-08 jrick error = got_repo_open(&repo, repo_path, NULL, pack_fds);
5845 624411d2 2023-07-08 jrick if (error != NULL)
5846 624411d2 2023-07-08 jrick goto done;
5848 624411d2 2023-07-08 jrick if (worktree) {
5849 624411d2 2023-07-08 jrick const char *prefix = got_worktree_get_path_prefix(worktree);
5852 624411d2 2023-07-08 jrick if (path == NULL || got_path_is_root_dir(path))
5853 624411d2 2023-07-08 jrick path = "";
5854 624411d2 2023-07-08 jrick error = got_worktree_resolve_path(&p, worktree, path);
5855 624411d2 2023-07-08 jrick if (error)
5856 624411d2 2023-07-08 jrick goto done;
5857 624411d2 2023-07-08 jrick if (asprintf(&in_repo_path, "%s%s%s", prefix,
5858 624411d2 2023-07-08 jrick (p[0] != '\0' && !got_path_is_root_dir(prefix)) ? "/" : "",
5859 624411d2 2023-07-08 jrick p) == -1) {
5860 624411d2 2023-07-08 jrick error = got_error_from_errno("asprintf");
5862 624411d2 2023-07-08 jrick goto done;
5865 624411d2 2023-07-08 jrick error = apply_unveil(got_repo_get_path(repo), 1, NULL);
5866 624411d2 2023-07-08 jrick if (error)
5867 624411d2 2023-07-08 jrick goto done;
5869 624411d2 2023-07-08 jrick error = apply_unveil(got_repo_get_path(repo), 1, NULL);
5870 624411d2 2023-07-08 jrick if (error)
5871 624411d2 2023-07-08 jrick goto done;
5872 624411d2 2023-07-08 jrick if (path == NULL)
5873 624411d2 2023-07-08 jrick path = "/";
5874 624411d2 2023-07-08 jrick error = got_repo_map_path(&in_repo_path, repo, path);
5875 624411d2 2023-07-08 jrick if (error != NULL)
5876 624411d2 2023-07-08 jrick goto done;
5879 624411d2 2023-07-08 jrick if (commit_id_str == NULL) {
5880 624411d2 2023-07-08 jrick struct got_reference *head_ref;
5881 624411d2 2023-07-08 jrick if (worktree)
5882 624411d2 2023-07-08 jrick refname = got_worktree_get_head_ref_name(worktree);
5884 624411d2 2023-07-08 jrick refname = GOT_REF_HEAD;
5885 624411d2 2023-07-08 jrick error = got_ref_open(&head_ref, repo, refname, 0);
5886 624411d2 2023-07-08 jrick if (error != NULL)
5887 624411d2 2023-07-08 jrick goto done;
5888 624411d2 2023-07-08 jrick error = got_ref_resolve(&commit_id, repo, head_ref);
5889 624411d2 2023-07-08 jrick got_ref_close(head_ref);
5890 624411d2 2023-07-08 jrick if (error != NULL)
5891 624411d2 2023-07-08 jrick goto done;
5893 624411d2 2023-07-08 jrick struct got_reflist_head refs;
5894 624411d2 2023-07-08 jrick TAILQ_INIT(&refs);
5895 624411d2 2023-07-08 jrick error = got_ref_list(&refs, repo, NULL, got_ref_cmp_by_name,
5897 624411d2 2023-07-08 jrick if (error)
5898 624411d2 2023-07-08 jrick goto done;
5899 624411d2 2023-07-08 jrick error = got_repo_match_object_id(&commit_id, NULL,
5900 624411d2 2023-07-08 jrick commit_id_str, GOT_OBJ_TYPE_COMMIT, &refs, repo);
5901 624411d2 2023-07-08 jrick got_ref_list_free(&refs);
5902 624411d2 2023-07-08 jrick if (error)
5903 624411d2 2023-07-08 jrick goto done;
5906 624411d2 2023-07-08 jrick if (worktree) {
5907 624411d2 2023-07-08 jrick /* Release work tree lock. */
5908 624411d2 2023-07-08 jrick got_worktree_close(worktree);
5909 624411d2 2023-07-08 jrick worktree = NULL;
5912 624411d2 2023-07-08 jrick error = got_object_open_as_commit(&commit, repo, commit_id);
5913 624411d2 2023-07-08 jrick if (error)
5914 624411d2 2023-07-08 jrick goto done;
5916 624411d2 2023-07-08 jrick error = print_tree(in_repo_path, commit, show_ids, recurse,
5917 624411d2 2023-07-08 jrick in_repo_path, repo);
5919 624411d2 2023-07-08 jrick free(in_repo_path);
5920 624411d2 2023-07-08 jrick free(repo_path);
5921 624411d2 2023-07-08 jrick free(cwd);
5922 624411d2 2023-07-08 jrick free(commit_id);
5923 624411d2 2023-07-08 jrick if (commit)
5924 624411d2 2023-07-08 jrick got_object_commit_close(commit);
5925 624411d2 2023-07-08 jrick if (worktree)
5926 624411d2 2023-07-08 jrick got_worktree_close(worktree);
5927 624411d2 2023-07-08 jrick if (repo) {
5928 624411d2 2023-07-08 jrick const struct got_error *close_err = got_repo_close(repo);
5929 624411d2 2023-07-08 jrick if (error == NULL)
5930 624411d2 2023-07-08 jrick error = close_err;
5932 624411d2 2023-07-08 jrick if (pack_fds) {
5933 624411d2 2023-07-08 jrick const struct got_error *pack_err =
5934 624411d2 2023-07-08 jrick got_repo_pack_fds_close(pack_fds);
5935 624411d2 2023-07-08 jrick if (error == NULL)
5936 624411d2 2023-07-08 jrick error = pack_err;
5938 624411d2 2023-07-08 jrick return error;
5941 624411d2 2023-07-08 jrick __dead static void
5942 624411d2 2023-07-08 jrick usage_status(void)
5944 624411d2 2023-07-08 jrick fprintf(stderr, "usage: %s status [-I] [-S status-codes] "
5945 624411d2 2023-07-08 jrick "[-s status-codes] [path ...]\n", getprogname());
5949 624411d2 2023-07-08 jrick struct got_status_arg {
5950 624411d2 2023-07-08 jrick char *status_codes;
5951 624411d2 2023-07-08 jrick int suppress;
5954 624411d2 2023-07-08 jrick static const struct got_error *
5955 624411d2 2023-07-08 jrick print_status(void *arg, unsigned char status, unsigned char staged_status,
5956 624411d2 2023-07-08 jrick const char *path, struct got_object_id *blob_id,
5957 624411d2 2023-07-08 jrick struct got_object_id *staged_blob_id, struct got_object_id *commit_id,
5958 624411d2 2023-07-08 jrick int dirfd, const char *de_name)
5960 624411d2 2023-07-08 jrick struct got_status_arg *st = arg;
5962 624411d2 2023-07-08 jrick if (status == staged_status && (status == GOT_STATUS_DELETE))
5963 624411d2 2023-07-08 jrick status = GOT_STATUS_NO_CHANGE;
5964 624411d2 2023-07-08 jrick if (st != NULL && st->status_codes) {
5965 624411d2 2023-07-08 jrick size_t ncodes = strlen(st->status_codes);
5966 624411d2 2023-07-08 jrick int i, j = 0;
5968 624411d2 2023-07-08 jrick for (i = 0; i < ncodes ; i++) {
5969 624411d2 2023-07-08 jrick if (st->suppress) {
5970 624411d2 2023-07-08 jrick if (status == st->status_codes[i] ||
5971 624411d2 2023-07-08 jrick staged_status == st->status_codes[i]) {
5973 624411d2 2023-07-08 jrick continue;
5976 624411d2 2023-07-08 jrick if (status == st->status_codes[i] ||
5977 624411d2 2023-07-08 jrick staged_status == st->status_codes[i])
5982 624411d2 2023-07-08 jrick if (st->suppress && j == 0)
5983 624411d2 2023-07-08 jrick goto print;
5985 624411d2 2023-07-08 jrick if (i == ncodes)
5986 624411d2 2023-07-08 jrick return NULL;
5989 624411d2 2023-07-08 jrick printf("%c%c %s\n", status, staged_status, path);
5990 624411d2 2023-07-08 jrick return NULL;
5993 624411d2 2023-07-08 jrick static const struct got_error *
5994 624411d2 2023-07-08 jrick cmd_status(int argc, char *argv[])
5996 624411d2 2023-07-08 jrick const struct got_error *error = NULL;
5997 624411d2 2023-07-08 jrick struct got_repository *repo = NULL;
5998 624411d2 2023-07-08 jrick struct got_worktree *worktree = NULL;
5999 624411d2 2023-07-08 jrick struct got_status_arg st;
6000 624411d2 2023-07-08 jrick char *cwd = NULL;
6001 624411d2 2023-07-08 jrick struct got_pathlist_head paths;
6002 624411d2 2023-07-08 jrick int ch, i, no_ignores = 0;
6003 624411d2 2023-07-08 jrick int *pack_fds = NULL;
6005 624411d2 2023-07-08 jrick TAILQ_INIT(&paths);
6007 624411d2 2023-07-08 jrick memset(&st, 0, sizeof(st));
6008 624411d2 2023-07-08 jrick st.status_codes = NULL;
6009 624411d2 2023-07-08 jrick st.suppress = 0;
6011 624411d2 2023-07-08 jrick #ifndef PROFILE
6012 624411d2 2023-07-08 jrick if (pledge("stdio rpath wpath cpath flock proc exec sendfd unveil",
6013 624411d2 2023-07-08 jrick NULL) == -1)
6014 624411d2 2023-07-08 jrick err(1, "pledge");
6017 624411d2 2023-07-08 jrick while ((ch = getopt(argc, argv, "IS:s:")) != -1) {
6018 624411d2 2023-07-08 jrick switch (ch) {
6019 624411d2 2023-07-08 jrick case 'I':
6020 624411d2 2023-07-08 jrick no_ignores = 1;
6022 624411d2 2023-07-08 jrick case 'S':
6023 624411d2 2023-07-08 jrick if (st.status_codes != NULL && st.suppress == 0)
6024 624411d2 2023-07-08 jrick option_conflict('S', 's');
6025 624411d2 2023-07-08 jrick st.suppress = 1;
6026 624411d2 2023-07-08 jrick /* fallthrough */
6027 624411d2 2023-07-08 jrick case 's':
6028 624411d2 2023-07-08 jrick for (i = 0; optarg[i] != '\0'; i++) {
6029 624411d2 2023-07-08 jrick switch (optarg[i]) {
6030 624411d2 2023-07-08 jrick case GOT_STATUS_MODIFY:
6031 624411d2 2023-07-08 jrick case GOT_STATUS_ADD:
6032 624411d2 2023-07-08 jrick case GOT_STATUS_DELETE:
6033 624411d2 2023-07-08 jrick case GOT_STATUS_CONFLICT:
6034 624411d2 2023-07-08 jrick case GOT_STATUS_MISSING:
6035 624411d2 2023-07-08 jrick case GOT_STATUS_OBSTRUCTED:
6036 624411d2 2023-07-08 jrick case GOT_STATUS_UNVERSIONED:
6037 624411d2 2023-07-08 jrick case GOT_STATUS_MODE_CHANGE:
6038 624411d2 2023-07-08 jrick case GOT_STATUS_NONEXISTENT:
6041 624411d2 2023-07-08 jrick errx(1, "invalid status code '%c'",
6042 624411d2 2023-07-08 jrick optarg[i]);
6045 624411d2 2023-07-08 jrick if (ch == 's' && st.suppress)
6046 624411d2 2023-07-08 jrick option_conflict('s', 'S');
6047 624411d2 2023-07-08 jrick st.status_codes = optarg;
6050 624411d2 2023-07-08 jrick usage_status();
6051 624411d2 2023-07-08 jrick /* NOTREACHED */
6055 624411d2 2023-07-08 jrick argc -= optind;
6056 624411d2 2023-07-08 jrick argv += optind;
6058 624411d2 2023-07-08 jrick cwd = getcwd(NULL, 0);
6059 624411d2 2023-07-08 jrick if (cwd == NULL) {
6060 624411d2 2023-07-08 jrick error = got_error_from_errno("getcwd");
6061 624411d2 2023-07-08 jrick goto done;
6064 624411d2 2023-07-08 jrick error = got_repo_pack_fds_open(&pack_fds);
6065 624411d2 2023-07-08 jrick if (error != NULL)
6066 624411d2 2023-07-08 jrick goto done;
6068 624411d2 2023-07-08 jrick error = got_worktree_open(&worktree, cwd);
6069 624411d2 2023-07-08 jrick if (error) {
6070 624411d2 2023-07-08 jrick if (error->code == GOT_ERR_NOT_WORKTREE)
6071 624411d2 2023-07-08 jrick error = wrap_not_worktree_error(error, "status", cwd);
6072 624411d2 2023-07-08 jrick goto done;
6075 624411d2 2023-07-08 jrick error = got_repo_open(&repo, got_worktree_get_repo_path(worktree),
6076 624411d2 2023-07-08 jrick NULL, pack_fds);
6077 624411d2 2023-07-08 jrick if (error != NULL)
6078 624411d2 2023-07-08 jrick goto done;
6080 624411d2 2023-07-08 jrick error = apply_unveil(got_repo_get_path(repo), 1,
6081 624411d2 2023-07-08 jrick got_worktree_get_root_path(worktree));
6082 624411d2 2023-07-08 jrick if (error)
6083 624411d2 2023-07-08 jrick goto done;
6085 624411d2 2023-07-08 jrick error = get_worktree_paths_from_argv(&paths, argc, argv, worktree);
6086 624411d2 2023-07-08 jrick if (error)
6087 624411d2 2023-07-08 jrick goto done;
6089 624411d2 2023-07-08 jrick error = got_worktree_status(worktree, &paths, repo, no_ignores,
6090 624411d2 2023-07-08 jrick print_status, &st, check_cancelled, NULL);
6092 624411d2 2023-07-08 jrick if (pack_fds) {
6093 624411d2 2023-07-08 jrick const struct got_error *pack_err =
6094 624411d2 2023-07-08 jrick got_repo_pack_fds_close(pack_fds);
6095 624411d2 2023-07-08 jrick if (error == NULL)
6096 624411d2 2023-07-08 jrick error = pack_err;
6098 624411d2 2023-07-08 jrick if (repo) {
6099 624411d2 2023-07-08 jrick const struct got_error *close_err = got_repo_close(repo);
6100 624411d2 2023-07-08 jrick if (error == NULL)
6101 624411d2 2023-07-08 jrick error = close_err;
6104 624411d2 2023-07-08 jrick got_pathlist_free(&paths, GOT_PATHLIST_FREE_PATH);
6105 624411d2 2023-07-08 jrick free(cwd);
6106 624411d2 2023-07-08 jrick return error;
6109 624411d2 2023-07-08 jrick __dead static void
6110 624411d2 2023-07-08 jrick usage_ref(void)
6112 624411d2 2023-07-08 jrick fprintf(stderr, "usage: %s ref [-dlt] [-c object] [-r repository-path] "
6113 624411d2 2023-07-08 jrick "[-s reference] [name]\n", getprogname());
6117 624411d2 2023-07-08 jrick static const struct got_error *
6118 624411d2 2023-07-08 jrick list_refs(struct got_repository *repo, const char *refname, int sort_by_time)
6120 624411d2 2023-07-08 jrick static const struct got_error *err = NULL;
6121 624411d2 2023-07-08 jrick struct got_reflist_head refs;
6122 624411d2 2023-07-08 jrick struct got_reflist_entry *re;
6124 624411d2 2023-07-08 jrick TAILQ_INIT(&refs);
6125 624411d2 2023-07-08 jrick err = got_ref_list(&refs, repo, refname, sort_by_time ?
6126 624411d2 2023-07-08 jrick got_ref_cmp_by_commit_timestamp_descending : got_ref_cmp_by_name,
6129 624411d2 2023-07-08 jrick return err;
6131 624411d2 2023-07-08 jrick TAILQ_FOREACH(re, &refs, entry) {
6132 624411d2 2023-07-08 jrick char *refstr;
6133 624411d2 2023-07-08 jrick refstr = got_ref_to_str(re->ref);
6134 624411d2 2023-07-08 jrick if (refstr == NULL) {
6135 624411d2 2023-07-08 jrick err = got_error_from_errno("got_ref_to_str");
6138 624411d2 2023-07-08 jrick printf("%s: %s\n", got_ref_get_name(re->ref), refstr);
6139 624411d2 2023-07-08 jrick free(refstr);
6142 624411d2 2023-07-08 jrick got_ref_list_free(&refs);
6143 624411d2 2023-07-08 jrick return err;
6146 624411d2 2023-07-08 jrick static const struct got_error *
6147 624411d2 2023-07-08 jrick delete_ref_by_name(struct got_repository *repo, const char *refname)
6149 624411d2 2023-07-08 jrick const struct got_error *err;
6150 624411d2 2023-07-08 jrick struct got_reference *ref;
6152 624411d2 2023-07-08 jrick err = got_ref_open(&ref, repo, refname, 0);
6154 624411d2 2023-07-08 jrick return err;
6156 624411d2 2023-07-08 jrick err = delete_ref(repo, ref);
6157 624411d2 2023-07-08 jrick got_ref_close(ref);
6158 624411d2 2023-07-08 jrick return err;
6161 624411d2 2023-07-08 jrick static const struct got_error *
6162 624411d2 2023-07-08 jrick add_ref(struct got_repository *repo, const char *refname, const char *target)
6164 624411d2 2023-07-08 jrick const struct got_error *err = NULL;
6165 624411d2 2023-07-08 jrick struct got_object_id *id = NULL;
6166 624411d2 2023-07-08 jrick struct got_reference *ref = NULL;
6167 624411d2 2023-07-08 jrick struct got_reflist_head refs;
6170 624411d2 2023-07-08 jrick * Don't let the user create a reference name with a leading '-'.
6171 624411d2 2023-07-08 jrick * While technically a valid reference name, this case is usually
6172 624411d2 2023-07-08 jrick * an unintended typo.
6174 624411d2 2023-07-08 jrick if (refname[0] == '-')
6175 624411d2 2023-07-08 jrick return got_error_path(refname, GOT_ERR_REF_NAME_MINUS);
6177 624411d2 2023-07-08 jrick TAILQ_INIT(&refs);
6178 624411d2 2023-07-08 jrick err = got_ref_list(&refs, repo, NULL, got_ref_cmp_by_name, NULL);
6180 624411d2 2023-07-08 jrick goto done;
6181 624411d2 2023-07-08 jrick err = got_repo_match_object_id(&id, NULL, target, GOT_OBJ_TYPE_ANY,
6182 624411d2 2023-07-08 jrick &refs, repo);
6183 624411d2 2023-07-08 jrick got_ref_list_free(&refs);
6185 624411d2 2023-07-08 jrick goto done;
6187 624411d2 2023-07-08 jrick err = got_ref_alloc(&ref, refname, id);
6189 624411d2 2023-07-08 jrick goto done;
6191 624411d2 2023-07-08 jrick err = got_ref_write(ref, repo);
6194 624411d2 2023-07-08 jrick got_ref_close(ref);
6195 624411d2 2023-07-08 jrick free(id);
6196 624411d2 2023-07-08 jrick return err;
6199 624411d2 2023-07-08 jrick static const struct got_error *
6200 624411d2 2023-07-08 jrick add_symref(struct got_repository *repo, const char *refname, const char *target)
6202 624411d2 2023-07-08 jrick const struct got_error *err = NULL;
6203 624411d2 2023-07-08 jrick struct got_reference *ref = NULL;
6204 624411d2 2023-07-08 jrick struct got_reference *target_ref = NULL;
6207 624411d2 2023-07-08 jrick * Don't let the user create a reference name with a leading '-'.
6208 624411d2 2023-07-08 jrick * While technically a valid reference name, this case is usually
6209 624411d2 2023-07-08 jrick * an unintended typo.
6211 624411d2 2023-07-08 jrick if (refname[0] == '-')
6212 624411d2 2023-07-08 jrick return got_error_path(refname, GOT_ERR_REF_NAME_MINUS);
6214 624411d2 2023-07-08 jrick err = got_ref_open(&target_ref, repo, target, 0);
6216 624411d2 2023-07-08 jrick return err;
6218 624411d2 2023-07-08 jrick err = got_ref_alloc_symref(&ref, refname, target_ref);
6220 624411d2 2023-07-08 jrick goto done;
6222 624411d2 2023-07-08 jrick err = got_ref_write(ref, repo);
6224 624411d2 2023-07-08 jrick if (target_ref)
6225 624411d2 2023-07-08 jrick got_ref_close(target_ref);
6227 624411d2 2023-07-08 jrick got_ref_close(ref);
6228 624411d2 2023-07-08 jrick return err;
6231 624411d2 2023-07-08 jrick static const struct got_error *
6232 624411d2 2023-07-08 jrick cmd_ref(int argc, char *argv[])
6234 624411d2 2023-07-08 jrick const struct got_error *error = NULL;
6235 624411d2 2023-07-08 jrick struct got_repository *repo = NULL;
6236 624411d2 2023-07-08 jrick struct got_worktree *worktree = NULL;
6237 624411d2 2023-07-08 jrick char *cwd = NULL, *repo_path = NULL;
6238 624411d2 2023-07-08 jrick int ch, do_list = 0, do_delete = 0, sort_by_time = 0;
6239 624411d2 2023-07-08 jrick const char *obj_arg = NULL, *symref_target= NULL;
6240 624411d2 2023-07-08 jrick char *refname = NULL;
6241 624411d2 2023-07-08 jrick int *pack_fds = NULL;
6243 624411d2 2023-07-08 jrick #ifndef PROFILE
6244 624411d2 2023-07-08 jrick if (pledge("stdio rpath wpath cpath fattr flock proc exec "
6245 624411d2 2023-07-08 jrick "sendfd unveil", NULL) == -1)
6246 624411d2 2023-07-08 jrick err(1, "pledge");
6249 624411d2 2023-07-08 jrick while ((ch = getopt(argc, argv, "c:dlr:s:t")) != -1) {
6250 624411d2 2023-07-08 jrick switch (ch) {
6251 624411d2 2023-07-08 jrick case 'c':
6252 624411d2 2023-07-08 jrick obj_arg = optarg;
6254 624411d2 2023-07-08 jrick case 'd':
6255 624411d2 2023-07-08 jrick do_delete = 1;
6257 624411d2 2023-07-08 jrick case 'l':
6258 624411d2 2023-07-08 jrick do_list = 1;
6260 624411d2 2023-07-08 jrick case 'r':
6261 624411d2 2023-07-08 jrick repo_path = realpath(optarg, NULL);
6262 624411d2 2023-07-08 jrick if (repo_path == NULL)
6263 624411d2 2023-07-08 jrick return got_error_from_errno2("realpath",
6265 624411d2 2023-07-08 jrick got_path_strip_trailing_slashes(repo_path);
6267 624411d2 2023-07-08 jrick case 's':
6268 624411d2 2023-07-08 jrick symref_target = optarg;
6270 624411d2 2023-07-08 jrick case 't':
6271 624411d2 2023-07-08 jrick sort_by_time = 1;
6274 624411d2 2023-07-08 jrick usage_ref();
6275 624411d2 2023-07-08 jrick /* NOTREACHED */
6279 624411d2 2023-07-08 jrick if (obj_arg && do_list)
6280 624411d2 2023-07-08 jrick option_conflict('c', 'l');
6281 624411d2 2023-07-08 jrick if (obj_arg && do_delete)
6282 624411d2 2023-07-08 jrick option_conflict('c', 'd');
6283 624411d2 2023-07-08 jrick if (obj_arg && symref_target)
6284 624411d2 2023-07-08 jrick option_conflict('c', 's');
6285 624411d2 2023-07-08 jrick if (symref_target && do_delete)
6286 624411d2 2023-07-08 jrick option_conflict('s', 'd');
6287 624411d2 2023-07-08 jrick if (symref_target && do_list)
6288 624411d2 2023-07-08 jrick option_conflict('s', 'l');
6289 624411d2 2023-07-08 jrick if (do_delete && do_list)
6290 624411d2 2023-07-08 jrick option_conflict('d', 'l');
6291 624411d2 2023-07-08 jrick if (sort_by_time && !do_list)
6292 624411d2 2023-07-08 jrick errx(1, "-t option requires -l option");
6294 624411d2 2023-07-08 jrick argc -= optind;
6295 624411d2 2023-07-08 jrick argv += optind;
6297 624411d2 2023-07-08 jrick if (do_list) {
6298 624411d2 2023-07-08 jrick if (argc != 0 && argc != 1)
6299 624411d2 2023-07-08 jrick usage_ref();
6300 624411d2 2023-07-08 jrick if (argc == 1) {
6301 624411d2 2023-07-08 jrick refname = strdup(argv[0]);
6302 624411d2 2023-07-08 jrick if (refname == NULL) {
6303 624411d2 2023-07-08 jrick error = got_error_from_errno("strdup");
6304 624411d2 2023-07-08 jrick goto done;
6308 624411d2 2023-07-08 jrick if (argc != 1)
6309 624411d2 2023-07-08 jrick usage_ref();
6310 624411d2 2023-07-08 jrick refname = strdup(argv[0]);
6311 624411d2 2023-07-08 jrick if (refname == NULL) {
6312 624411d2 2023-07-08 jrick error = got_error_from_errno("strdup");
6313 624411d2 2023-07-08 jrick goto done;
6317 624411d2 2023-07-08 jrick if (refname)
6318 624411d2 2023-07-08 jrick got_path_strip_trailing_slashes(refname);
6320 624411d2 2023-07-08 jrick cwd = getcwd(NULL, 0);
6321 624411d2 2023-07-08 jrick if (cwd == NULL) {
6322 624411d2 2023-07-08 jrick error = got_error_from_errno("getcwd");
6323 624411d2 2023-07-08 jrick goto done;
6326 624411d2 2023-07-08 jrick error = got_repo_pack_fds_open(&pack_fds);
6327 624411d2 2023-07-08 jrick if (error != NULL)
6328 624411d2 2023-07-08 jrick goto done;
6330 624411d2 2023-07-08 jrick if (repo_path == NULL) {
6331 624411d2 2023-07-08 jrick error = got_worktree_open(&worktree, cwd);
6332 624411d2 2023-07-08 jrick if (error && error->code != GOT_ERR_NOT_WORKTREE)
6333 624411d2 2023-07-08 jrick goto done;
6335 624411d2 2023-07-08 jrick error = NULL;
6336 624411d2 2023-07-08 jrick if (worktree) {
6337 624411d2 2023-07-08 jrick repo_path =
6338 624411d2 2023-07-08 jrick strdup(got_worktree_get_repo_path(worktree));
6339 624411d2 2023-07-08 jrick if (repo_path == NULL)
6340 624411d2 2023-07-08 jrick error = got_error_from_errno("strdup");
6341 624411d2 2023-07-08 jrick if (error)
6342 624411d2 2023-07-08 jrick goto done;
6344 624411d2 2023-07-08 jrick repo_path = strdup(cwd);
6345 624411d2 2023-07-08 jrick if (repo_path == NULL) {
6346 624411d2 2023-07-08 jrick error = got_error_from_errno("strdup");
6347 624411d2 2023-07-08 jrick goto done;
6352 624411d2 2023-07-08 jrick error = got_repo_open(&repo, repo_path, NULL, pack_fds);
6353 624411d2 2023-07-08 jrick if (error != NULL)
6354 624411d2 2023-07-08 jrick goto done;
6356 624411d2 2023-07-08 jrick #ifndef PROFILE
6357 624411d2 2023-07-08 jrick if (do_list) {
6358 624411d2 2023-07-08 jrick /* Remove "cpath" promise. */
6359 624411d2 2023-07-08 jrick if (pledge("stdio rpath wpath flock proc exec sendfd unveil",
6360 624411d2 2023-07-08 jrick NULL) == -1)
6361 624411d2 2023-07-08 jrick err(1, "pledge");
6365 624411d2 2023-07-08 jrick error = apply_unveil(got_repo_get_path(repo), do_list,
6366 624411d2 2023-07-08 jrick worktree ? got_worktree_get_root_path(worktree) : NULL);
6367 624411d2 2023-07-08 jrick if (error)
6368 624411d2 2023-07-08 jrick goto done;
6370 624411d2 2023-07-08 jrick if (do_list)
6371 624411d2 2023-07-08 jrick error = list_refs(repo, refname, sort_by_time);
6372 624411d2 2023-07-08 jrick else if (do_delete)
6373 624411d2 2023-07-08 jrick error = delete_ref_by_name(repo, refname);
6374 624411d2 2023-07-08 jrick else if (symref_target)
6375 624411d2 2023-07-08 jrick error = add_symref(repo, refname, symref_target);
6377 624411d2 2023-07-08 jrick if (obj_arg == NULL)
6378 624411d2 2023-07-08 jrick usage_ref();
6379 624411d2 2023-07-08 jrick error = add_ref(repo, refname, obj_arg);
6382 624411d2 2023-07-08 jrick free(refname);
6383 624411d2 2023-07-08 jrick if (repo) {
6384 624411d2 2023-07-08 jrick const struct got_error *close_err = got_repo_close(repo);
6385 624411d2 2023-07-08 jrick if (error == NULL)
6386 624411d2 2023-07-08 jrick error = close_err;
6388 624411d2 2023-07-08 jrick if (worktree)
6389 624411d2 2023-07-08 jrick got_worktree_close(worktree);
6390 624411d2 2023-07-08 jrick if (pack_fds) {
6391 624411d2 2023-07-08 jrick const struct got_error *pack_err =
6392 624411d2 2023-07-08 jrick got_repo_pack_fds_close(pack_fds);
6393 624411d2 2023-07-08 jrick if (error == NULL)
6394 624411d2 2023-07-08 jrick error = pack_err;
6396 624411d2 2023-07-08 jrick free(cwd);
6397 624411d2 2023-07-08 jrick free(repo_path);
6398 624411d2 2023-07-08 jrick return error;
6401 624411d2 2023-07-08 jrick __dead static void
6402 624411d2 2023-07-08 jrick usage_branch(void)
6404 624411d2 2023-07-08 jrick fprintf(stderr, "usage: %s branch [-lnt] [-c commit] [-d name] "
6405 624411d2 2023-07-08 jrick "[-r repository-path] [name]\n", getprogname());
6409 624411d2 2023-07-08 jrick static const struct got_error *
6410 624411d2 2023-07-08 jrick list_branch(struct got_repository *repo, struct got_worktree *worktree,
6411 624411d2 2023-07-08 jrick struct got_reference *ref)
6413 624411d2 2023-07-08 jrick const struct got_error *err = NULL;
6414 624411d2 2023-07-08 jrick const char *refname, *marker = " ";
6415 624411d2 2023-07-08 jrick char *refstr;
6417 624411d2 2023-07-08 jrick refname = got_ref_get_name(ref);
6418 624411d2 2023-07-08 jrick if (worktree && strcmp(refname,
6419 624411d2 2023-07-08 jrick got_worktree_get_head_ref_name(worktree)) == 0) {
6420 624411d2 2023-07-08 jrick struct got_object_id *id = NULL;
6422 624411d2 2023-07-08 jrick err = got_ref_resolve(&id, repo, ref);
6424 624411d2 2023-07-08 jrick return err;
6425 624411d2 2023-07-08 jrick if (got_object_id_cmp(id,
6426 624411d2 2023-07-08 jrick got_worktree_get_base_commit_id(worktree)) == 0)
6427 624411d2 2023-07-08 jrick marker = "* ";
6429 624411d2 2023-07-08 jrick marker = "~ ";
6430 624411d2 2023-07-08 jrick free(id);
6433 624411d2 2023-07-08 jrick if (strncmp(refname, "refs/heads/", 11) == 0)
6434 624411d2 2023-07-08 jrick refname += 11;
6435 624411d2 2023-07-08 jrick if (strncmp(refname, "refs/got/worktree/", 18) == 0)
6436 624411d2 2023-07-08 jrick refname += 18;
6437 624411d2 2023-07-08 jrick if (strncmp(refname, "refs/remotes/", 13) == 0)
6438 624411d2 2023-07-08 jrick refname += 13;
6440 624411d2 2023-07-08 jrick refstr = got_ref_to_str(ref);
6441 624411d2 2023-07-08 jrick if (refstr == NULL)
6442 624411d2 2023-07-08 jrick return got_error_from_errno("got_ref_to_str");
6444 624411d2 2023-07-08 jrick printf("%s%s: %s\n", marker, refname, refstr);
6445 624411d2 2023-07-08 jrick free(refstr);
6446 624411d2 2023-07-08 jrick return NULL;
6449 624411d2 2023-07-08 jrick static const struct got_error *
6450 624411d2 2023-07-08 jrick show_current_branch(struct got_repository *repo, struct got_worktree *worktree)
6452 624411d2 2023-07-08 jrick const char *refname;
6454 624411d2 2023-07-08 jrick if (worktree == NULL)
6455 624411d2 2023-07-08 jrick return got_error(GOT_ERR_NOT_WORKTREE);
6457 624411d2 2023-07-08 jrick refname = got_worktree_get_head_ref_name(worktree);
6459 624411d2 2023-07-08 jrick if (strncmp(refname, "refs/heads/", 11) == 0)
6460 624411d2 2023-07-08 jrick refname += 11;
6461 624411d2 2023-07-08 jrick if (strncmp(refname, "refs/got/worktree/", 18) == 0)
6462 624411d2 2023-07-08 jrick refname += 18;
6464 624411d2 2023-07-08 jrick printf("%s\n", refname);
6466 624411d2 2023-07-08 jrick return NULL;
6469 624411d2 2023-07-08 jrick static const struct got_error *
6470 624411d2 2023-07-08 jrick list_branches(struct got_repository *repo, struct got_worktree *worktree,
6471 624411d2 2023-07-08 jrick int sort_by_time)
6473 624411d2 2023-07-08 jrick static const struct got_error *err = NULL;
6474 624411d2 2023-07-08 jrick struct got_reflist_head refs;
6475 624411d2 2023-07-08 jrick struct got_reflist_entry *re;
6476 624411d2 2023-07-08 jrick struct got_reference *temp_ref = NULL;
6477 624411d2 2023-07-08 jrick int rebase_in_progress, histedit_in_progress;
6479 624411d2 2023-07-08 jrick TAILQ_INIT(&refs);
6481 624411d2 2023-07-08 jrick if (worktree) {
6482 624411d2 2023-07-08 jrick err = got_worktree_rebase_in_progress(&rebase_in_progress,
6483 624411d2 2023-07-08 jrick worktree);
6485 624411d2 2023-07-08 jrick return err;
6487 624411d2 2023-07-08 jrick err = got_worktree_histedit_in_progress(&histedit_in_progress,
6488 624411d2 2023-07-08 jrick worktree);
6490 624411d2 2023-07-08 jrick return err;
6492 624411d2 2023-07-08 jrick if (rebase_in_progress || histedit_in_progress) {
6493 624411d2 2023-07-08 jrick err = got_ref_open(&temp_ref, repo,
6494 624411d2 2023-07-08 jrick got_worktree_get_head_ref_name(worktree), 0);
6496 624411d2 2023-07-08 jrick return err;
6497 624411d2 2023-07-08 jrick list_branch(repo, worktree, temp_ref);
6498 624411d2 2023-07-08 jrick got_ref_close(temp_ref);
6502 624411d2 2023-07-08 jrick err = got_ref_list(&refs, repo, "refs/heads", sort_by_time ?
6503 624411d2 2023-07-08 jrick got_ref_cmp_by_commit_timestamp_descending : got_ref_cmp_by_name,
6506 624411d2 2023-07-08 jrick return err;
6508 624411d2 2023-07-08 jrick TAILQ_FOREACH(re, &refs, entry)
6509 624411d2 2023-07-08 jrick list_branch(repo, worktree, re->ref);
6511 624411d2 2023-07-08 jrick got_ref_list_free(&refs);
6513 624411d2 2023-07-08 jrick err = got_ref_list(&refs, repo, "refs/remotes", sort_by_time ?
6514 624411d2 2023-07-08 jrick got_ref_cmp_by_commit_timestamp_descending : got_ref_cmp_by_name,
6517 624411d2 2023-07-08 jrick return err;
6519 624411d2 2023-07-08 jrick TAILQ_FOREACH(re, &refs, entry)
6520 624411d2 2023-07-08 jrick list_branch(repo, worktree, re->ref);
6522 624411d2 2023-07-08 jrick got_ref_list_free(&refs);
6524 624411d2 2023-07-08 jrick return NULL;
6527 624411d2 2023-07-08 jrick static const struct got_error *
6528 624411d2 2023-07-08 jrick delete_branch(struct got_repository *repo, struct got_worktree *worktree,
6529 624411d2 2023-07-08 jrick const char *branch_name)
6531 624411d2 2023-07-08 jrick const struct got_error *err = NULL;
6532 624411d2 2023-07-08 jrick struct got_reference *ref = NULL;
6533 624411d2 2023-07-08 jrick char *refname, *remote_refname = NULL;
6535 624411d2 2023-07-08 jrick if (strncmp(branch_name, "refs/", 5) == 0)
6536 624411d2 2023-07-08 jrick branch_name += 5;
6537 624411d2 2023-07-08 jrick if (strncmp(branch_name, "heads/", 6) == 0)
6538 624411d2 2023-07-08 jrick branch_name += 6;
6539 624411d2 2023-07-08 jrick else if (strncmp(branch_name, "remotes/", 8) == 0)
6540 624411d2 2023-07-08 jrick branch_name += 8;
6542 624411d2 2023-07-08 jrick if (asprintf(&refname, "refs/heads/%s", branch_name) == -1)
6543 624411d2 2023-07-08 jrick return got_error_from_errno("asprintf");
6545 624411d2 2023-07-08 jrick if (asprintf(&remote_refname, "refs/remotes/%s",
6546 624411d2 2023-07-08 jrick branch_name) == -1) {
6547 624411d2 2023-07-08 jrick err = got_error_from_errno("asprintf");
6548 624411d2 2023-07-08 jrick goto done;
6551 624411d2 2023-07-08 jrick err = got_ref_open(&ref, repo, refname, 0);
6552 624411d2 2023-07-08 jrick if (err) {
6553 624411d2 2023-07-08 jrick const struct got_error *err2;
6554 624411d2 2023-07-08 jrick if (err->code != GOT_ERR_NOT_REF)
6555 624411d2 2023-07-08 jrick goto done;
6557 624411d2 2023-07-08 jrick * Keep 'err' intact such that if neither branch exists
6558 624411d2 2023-07-08 jrick * we report "refs/heads" rather than "refs/remotes" in
6559 624411d2 2023-07-08 jrick * our error message.
6561 624411d2 2023-07-08 jrick err2 = got_ref_open(&ref, repo, remote_refname, 0);
6562 624411d2 2023-07-08 jrick if (err2)
6563 624411d2 2023-07-08 jrick goto done;
6564 624411d2 2023-07-08 jrick err = NULL;
6567 624411d2 2023-07-08 jrick if (worktree &&
6568 624411d2 2023-07-08 jrick strcmp(got_worktree_get_head_ref_name(worktree),
6569 624411d2 2023-07-08 jrick got_ref_get_name(ref)) == 0) {
6570 624411d2 2023-07-08 jrick err = got_error_msg(GOT_ERR_SAME_BRANCH,
6571 624411d2 2023-07-08 jrick "will not delete this work tree's current branch");
6572 624411d2 2023-07-08 jrick goto done;
6575 624411d2 2023-07-08 jrick err = delete_ref(repo, ref);
6578 624411d2 2023-07-08 jrick got_ref_close(ref);
6579 624411d2 2023-07-08 jrick free(refname);
6580 624411d2 2023-07-08 jrick free(remote_refname);
6581 624411d2 2023-07-08 jrick return err;
6584 624411d2 2023-07-08 jrick static const struct got_error *
6585 624411d2 2023-07-08 jrick add_branch(struct got_repository *repo, const char *branch_name,
6586 624411d2 2023-07-08 jrick struct got_object_id *base_commit_id)
6588 624411d2 2023-07-08 jrick const struct got_error *err = NULL;
6589 624411d2 2023-07-08 jrick struct got_reference *ref = NULL;
6590 624411d2 2023-07-08 jrick char *refname = NULL;
6593 624411d2 2023-07-08 jrick * Don't let the user create a branch name with a leading '-'.
6594 624411d2 2023-07-08 jrick * While technically a valid reference name, this case is usually
6595 624411d2 2023-07-08 jrick * an unintended typo.
6597 624411d2 2023-07-08 jrick if (branch_name[0] == '-')
6598 624411d2 2023-07-08 jrick return got_error_path(branch_name, GOT_ERR_REF_NAME_MINUS);
6600 624411d2 2023-07-08 jrick if (strncmp(branch_name, "refs/heads/", 11) == 0)
6601 624411d2 2023-07-08 jrick branch_name += 11;
6603 624411d2 2023-07-08 jrick if (asprintf(&refname, "refs/heads/%s", branch_name) == -1) {
6604 624411d2 2023-07-08 jrick err = got_error_from_errno("asprintf");
6605 624411d2 2023-07-08 jrick goto done;
6608 624411d2 2023-07-08 jrick err = got_ref_open(&ref, repo, refname, 0);
6609 624411d2 2023-07-08 jrick if (err == NULL) {
6610 624411d2 2023-07-08 jrick err = got_error(GOT_ERR_BRANCH_EXISTS);
6611 624411d2 2023-07-08 jrick goto done;
6612 624411d2 2023-07-08 jrick } else if (err->code != GOT_ERR_NOT_REF)
6613 624411d2 2023-07-08 jrick goto done;
6615 624411d2 2023-07-08 jrick err = got_ref_alloc(&ref, refname, base_commit_id);
6617 624411d2 2023-07-08 jrick goto done;
6619 624411d2 2023-07-08 jrick err = got_ref_write(ref, repo);
6622 624411d2 2023-07-08 jrick got_ref_close(ref);
6623 624411d2 2023-07-08 jrick free(refname);
6624 624411d2 2023-07-08 jrick return err;
6627 624411d2 2023-07-08 jrick static const struct got_error *
6628 624411d2 2023-07-08 jrick cmd_branch(int argc, char *argv[])
6630 624411d2 2023-07-08 jrick const struct got_error *error = NULL;
6631 624411d2 2023-07-08 jrick struct got_repository *repo = NULL;
6632 624411d2 2023-07-08 jrick struct got_worktree *worktree = NULL;
6633 624411d2 2023-07-08 jrick char *cwd = NULL, *repo_path = NULL;
6634 624411d2 2023-07-08 jrick int ch, do_list = 0, do_show = 0, do_update = 1, sort_by_time = 0;
6635 624411d2 2023-07-08 jrick const char *delref = NULL, *commit_id_arg = NULL;
6636 624411d2 2023-07-08 jrick struct got_reference *ref = NULL;
6637 624411d2 2023-07-08 jrick struct got_pathlist_head paths;
6638 624411d2 2023-07-08 jrick struct got_object_id *commit_id = NULL;
6639 624411d2 2023-07-08 jrick char *commit_id_str = NULL;
6640 624411d2 2023-07-08 jrick int *pack_fds = NULL;
6642 624411d2 2023-07-08 jrick TAILQ_INIT(&paths);
6644 624411d2 2023-07-08 jrick #ifndef PROFILE
6645 624411d2 2023-07-08 jrick if (pledge("stdio rpath wpath cpath fattr flock proc exec "
6646 624411d2 2023-07-08 jrick "sendfd unveil", NULL) == -1)
6647 624411d2 2023-07-08 jrick err(1, "pledge");
6650 624411d2 2023-07-08 jrick while ((ch = getopt(argc, argv, "c:d:lnr:t")) != -1) {
6651 624411d2 2023-07-08 jrick switch (ch) {
6652 624411d2 2023-07-08 jrick case 'c':
6653 624411d2 2023-07-08 jrick commit_id_arg = optarg;
6655 624411d2 2023-07-08 jrick case 'd':
6656 624411d2 2023-07-08 jrick delref = optarg;
6658 624411d2 2023-07-08 jrick case 'l':
6659 624411d2 2023-07-08 jrick do_list = 1;
6661 624411d2 2023-07-08 jrick case 'n':
6662 624411d2 2023-07-08 jrick do_update = 0;
6664 624411d2 2023-07-08 jrick case 'r':
6665 624411d2 2023-07-08 jrick repo_path = realpath(optarg, NULL);
6666 624411d2 2023-07-08 jrick if (repo_path == NULL)
6667 624411d2 2023-07-08 jrick return got_error_from_errno2("realpath",
6669 624411d2 2023-07-08 jrick got_path_strip_trailing_slashes(repo_path);
6671 624411d2 2023-07-08 jrick case 't':
6672 624411d2 2023-07-08 jrick sort_by_time = 1;
6675 624411d2 2023-07-08 jrick usage_branch();
6676 624411d2 2023-07-08 jrick /* NOTREACHED */
6680 624411d2 2023-07-08 jrick if (do_list && delref)
6681 624411d2 2023-07-08 jrick option_conflict('l', 'd');
6682 624411d2 2023-07-08 jrick if (sort_by_time && !do_list)
6683 624411d2 2023-07-08 jrick errx(1, "-t option requires -l option");
6685 624411d2 2023-07-08 jrick argc -= optind;
6686 624411d2 2023-07-08 jrick argv += optind;
6688 624411d2 2023-07-08 jrick if (!do_list && !delref && argc == 0)
6689 624411d2 2023-07-08 jrick do_show = 1;
6691 624411d2 2023-07-08 jrick if ((do_list || delref || do_show) && commit_id_arg != NULL)
6692 624411d2 2023-07-08 jrick errx(1, "-c option can only be used when creating a branch");
6694 624411d2 2023-07-08 jrick if (do_list || delref) {
6695 624411d2 2023-07-08 jrick if (argc > 0)
6696 624411d2 2023-07-08 jrick usage_branch();
6697 624411d2 2023-07-08 jrick } else if (!do_show && argc != 1)
6698 624411d2 2023-07-08 jrick usage_branch();
6700 624411d2 2023-07-08 jrick cwd = getcwd(NULL, 0);
6701 624411d2 2023-07-08 jrick if (cwd == NULL) {
6702 624411d2 2023-07-08 jrick error = got_error_from_errno("getcwd");
6703 624411d2 2023-07-08 jrick goto done;
6706 624411d2 2023-07-08 jrick error = got_repo_pack_fds_open(&pack_fds);
6707 624411d2 2023-07-08 jrick if (error != NULL)
6708 624411d2 2023-07-08 jrick goto done;
6710 624411d2 2023-07-08 jrick if (repo_path == NULL) {
6711 624411d2 2023-07-08 jrick error = got_worktree_open(&worktree, cwd);
6712 624411d2 2023-07-08 jrick if (error && error->code != GOT_ERR_NOT_WORKTREE)
6713 624411d2 2023-07-08 jrick goto done;
6715 624411d2 2023-07-08 jrick error = NULL;
6716 624411d2 2023-07-08 jrick if (worktree) {
6717 624411d2 2023-07-08 jrick repo_path =
6718 624411d2 2023-07-08 jrick strdup(got_worktree_get_repo_path(worktree));
6719 624411d2 2023-07-08 jrick if (repo_path == NULL)
6720 624411d2 2023-07-08 jrick error = got_error_from_errno("strdup");
6721 624411d2 2023-07-08 jrick if (error)
6722 624411d2 2023-07-08 jrick goto done;
6724 624411d2 2023-07-08 jrick repo_path = strdup(cwd);
6725 624411d2 2023-07-08 jrick if (repo_path == NULL) {
6726 624411d2 2023-07-08 jrick error = got_error_from_errno("strdup");
6727 624411d2 2023-07-08 jrick goto done;
6732 624411d2 2023-07-08 jrick error = got_repo_open(&repo, repo_path, NULL, pack_fds);
6733 624411d2 2023-07-08 jrick if (error != NULL)
6734 624411d2 2023-07-08 jrick goto done;
6736 624411d2 2023-07-08 jrick #ifndef PROFILE
6737 624411d2 2023-07-08 jrick if (do_list || do_show) {
6738 624411d2 2023-07-08 jrick /* Remove "cpath" promise. */
6739 624411d2 2023-07-08 jrick if (pledge("stdio rpath wpath flock proc exec sendfd unveil",
6740 624411d2 2023-07-08 jrick NULL) == -1)
6741 624411d2 2023-07-08 jrick err(1, "pledge");
6745 624411d2 2023-07-08 jrick error = apply_unveil(got_repo_get_path(repo), do_list,
6746 624411d2 2023-07-08 jrick worktree ? got_worktree_get_root_path(worktree) : NULL);
6747 624411d2 2023-07-08 jrick if (error)
6748 624411d2 2023-07-08 jrick goto done;
6750 624411d2 2023-07-08 jrick if (do_show)
6751 624411d2 2023-07-08 jrick error = show_current_branch(repo, worktree);
6752 624411d2 2023-07-08 jrick else if (do_list)
6753 624411d2 2023-07-08 jrick error = list_branches(repo, worktree, sort_by_time);
6754 624411d2 2023-07-08 jrick else if (delref)
6755 624411d2 2023-07-08 jrick error = delete_branch(repo, worktree, delref);
6757 624411d2 2023-07-08 jrick struct got_reflist_head refs;
6758 624411d2 2023-07-08 jrick TAILQ_INIT(&refs);
6759 624411d2 2023-07-08 jrick error = got_ref_list(&refs, repo, NULL, got_ref_cmp_by_name,
6761 624411d2 2023-07-08 jrick if (error)
6762 624411d2 2023-07-08 jrick goto done;
6763 624411d2 2023-07-08 jrick if (commit_id_arg == NULL)
6764 624411d2 2023-07-08 jrick commit_id_arg = worktree ?
6765 624411d2 2023-07-08 jrick got_worktree_get_head_ref_name(worktree) :
6766 624411d2 2023-07-08 jrick GOT_REF_HEAD;
6767 624411d2 2023-07-08 jrick error = got_repo_match_object_id(&commit_id, NULL,
6768 624411d2 2023-07-08 jrick commit_id_arg, GOT_OBJ_TYPE_COMMIT, &refs, repo);
6769 624411d2 2023-07-08 jrick got_ref_list_free(&refs);
6770 624411d2 2023-07-08 jrick if (error)
6771 624411d2 2023-07-08 jrick goto done;
6772 624411d2 2023-07-08 jrick error = add_branch(repo, argv[0], commit_id);
6773 624411d2 2023-07-08 jrick if (error)
6774 624411d2 2023-07-08 jrick goto done;
6775 624411d2 2023-07-08 jrick if (worktree && do_update) {
6776 624411d2 2023-07-08 jrick struct got_update_progress_arg upa;
6777 624411d2 2023-07-08 jrick char *branch_refname = NULL;
6779 624411d2 2023-07-08 jrick error = got_object_id_str(&commit_id_str, commit_id);
6780 624411d2 2023-07-08 jrick if (error)
6781 624411d2 2023-07-08 jrick goto done;
6782 624411d2 2023-07-08 jrick error = get_worktree_paths_from_argv(&paths, 0, NULL,
6783 624411d2 2023-07-08 jrick worktree);
6784 624411d2 2023-07-08 jrick if (error)
6785 624411d2 2023-07-08 jrick goto done;
6786 624411d2 2023-07-08 jrick if (asprintf(&branch_refname, "refs/heads/%s", argv[0])
6788 624411d2 2023-07-08 jrick error = got_error_from_errno("asprintf");
6789 624411d2 2023-07-08 jrick goto done;
6791 624411d2 2023-07-08 jrick error = got_ref_open(&ref, repo, branch_refname, 0);
6792 624411d2 2023-07-08 jrick free(branch_refname);
6793 624411d2 2023-07-08 jrick if (error)
6794 624411d2 2023-07-08 jrick goto done;
6795 624411d2 2023-07-08 jrick error = switch_head_ref(ref, commit_id, worktree,
6797 624411d2 2023-07-08 jrick if (error)
6798 624411d2 2023-07-08 jrick goto done;
6799 624411d2 2023-07-08 jrick error = got_worktree_set_base_commit_id(worktree, repo,
6800 624411d2 2023-07-08 jrick commit_id);
6801 624411d2 2023-07-08 jrick if (error)
6802 624411d2 2023-07-08 jrick goto done;
6803 624411d2 2023-07-08 jrick memset(&upa, 0, sizeof(upa));
6804 624411d2 2023-07-08 jrick error = got_worktree_checkout_files(worktree, &paths,
6805 624411d2 2023-07-08 jrick repo, update_progress, &upa, check_cancelled,
6807 624411d2 2023-07-08 jrick if (error)
6808 624411d2 2023-07-08 jrick goto done;
6809 624411d2 2023-07-08 jrick if (upa.did_something) {
6810 624411d2 2023-07-08 jrick printf("Updated to %s: %s\n",
6811 624411d2 2023-07-08 jrick got_worktree_get_head_ref_name(worktree),
6812 624411d2 2023-07-08 jrick commit_id_str);
6814 624411d2 2023-07-08 jrick print_update_progress_stats(&upa);
6819 624411d2 2023-07-08 jrick got_ref_close(ref);
6820 624411d2 2023-07-08 jrick if (repo) {
6821 624411d2 2023-07-08 jrick const struct got_error *close_err = got_repo_close(repo);
6822 624411d2 2023-07-08 jrick if (error == NULL)
6823 624411d2 2023-07-08 jrick error = close_err;
6825 624411d2 2023-07-08 jrick if (worktree)
6826 624411d2 2023-07-08 jrick got_worktree_close(worktree);
6827 624411d2 2023-07-08 jrick if (pack_fds) {
6828 624411d2 2023-07-08 jrick const struct got_error *pack_err =
6829 624411d2 2023-07-08 jrick got_repo_pack_fds_close(pack_fds);
6830 624411d2 2023-07-08 jrick if (error == NULL)
6831 624411d2 2023-07-08 jrick error = pack_err;
6833 624411d2 2023-07-08 jrick free(cwd);
6834 624411d2 2023-07-08 jrick free(repo_path);
6835 624411d2 2023-07-08 jrick free(commit_id);
6836 624411d2 2023-07-08 jrick free(commit_id_str);
6837 624411d2 2023-07-08 jrick got_pathlist_free(&paths, GOT_PATHLIST_FREE_PATH);
6838 624411d2 2023-07-08 jrick return error;
6842 624411d2 2023-07-08 jrick __dead static void
6843 624411d2 2023-07-08 jrick usage_tag(void)
6845 624411d2 2023-07-08 jrick fprintf(stderr, "usage: %s tag [-lVv] [-c commit] [-m message] "
6846 624411d2 2023-07-08 jrick "[-r repository-path] [-s signer-id] name\n", getprogname());
6851 624411d2 2023-07-08 jrick static const struct got_error *
6852 624411d2 2023-07-08 jrick sort_tags(struct got_reflist_head *sorted, struct got_reflist_head *tags)
6854 624411d2 2023-07-08 jrick const struct got_error *err = NULL;
6855 624411d2 2023-07-08 jrick struct got_reflist_entry *re, *se, *new;
6856 624411d2 2023-07-08 jrick struct got_object_id *re_id, *se_id;
6857 624411d2 2023-07-08 jrick struct got_tag_object *re_tag, *se_tag;
6858 624411d2 2023-07-08 jrick time_t re_time, se_time;
6860 624411d2 2023-07-08 jrick STAILQ_FOREACH(re, tags, entry) {
6861 624411d2 2023-07-08 jrick se = STAILQ_FIRST(sorted);
6862 624411d2 2023-07-08 jrick if (se == NULL) {
6863 624411d2 2023-07-08 jrick err = got_reflist_entry_dup(&new, re);
6865 624411d2 2023-07-08 jrick return err;
6866 624411d2 2023-07-08 jrick STAILQ_INSERT_HEAD(sorted, new, entry);
6867 624411d2 2023-07-08 jrick continue;
6869 624411d2 2023-07-08 jrick err = got_ref_resolve(&re_id, repo, re->ref);
6872 624411d2 2023-07-08 jrick err = got_object_open_as_tag(&re_tag, repo, re_id);
6873 624411d2 2023-07-08 jrick free(re_id);
6876 624411d2 2023-07-08 jrick re_time = got_object_tag_get_tagger_time(re_tag);
6877 624411d2 2023-07-08 jrick got_object_tag_close(re_tag);
6880 624411d2 2023-07-08 jrick while (se) {
6881 624411d2 2023-07-08 jrick err = got_ref_resolve(&se_id, repo, re->ref);
6884 624411d2 2023-07-08 jrick err = got_object_open_as_tag(&se_tag, repo, se_id);
6885 624411d2 2023-07-08 jrick free(se_id);
6888 624411d2 2023-07-08 jrick se_time = got_object_tag_get_tagger_time(se_tag);
6889 624411d2 2023-07-08 jrick got_object_tag_close(se_tag);
6891 624411d2 2023-07-08 jrick if (se_time > re_time) {
6892 624411d2 2023-07-08 jrick err = got_reflist_entry_dup(&new, re);
6894 624411d2 2023-07-08 jrick return err;
6895 624411d2 2023-07-08 jrick STAILQ_INSERT_AFTER(sorted, se, new, entry);
6898 624411d2 2023-07-08 jrick se = STAILQ_NEXT(se, entry);
6899 624411d2 2023-07-08 jrick continue;
6903 624411d2 2023-07-08 jrick return err;
6907 624411d2 2023-07-08 jrick static const struct got_error *
6908 624411d2 2023-07-08 jrick get_tag_refname(char **refname, const char *tag_name)
6910 624411d2 2023-07-08 jrick const struct got_error *err;
6912 624411d2 2023-07-08 jrick if (strncmp("refs/tags/", tag_name, 10) == 0) {
6913 624411d2 2023-07-08 jrick *refname = strdup(tag_name);
6914 624411d2 2023-07-08 jrick if (*refname == NULL)
6915 624411d2 2023-07-08 jrick return got_error_from_errno("strdup");
6916 624411d2 2023-07-08 jrick } else if (asprintf(refname, "refs/tags/%s", tag_name) == -1) {
6917 624411d2 2023-07-08 jrick err = got_error_from_errno("asprintf");
6918 624411d2 2023-07-08 jrick *refname = NULL;
6919 624411d2 2023-07-08 jrick return err;
6922 624411d2 2023-07-08 jrick return NULL;
6925 624411d2 2023-07-08 jrick static const struct got_error *
6926 624411d2 2023-07-08 jrick list_tags(struct got_repository *repo, const char *tag_name, int verify_tags,
6927 624411d2 2023-07-08 jrick const char *allowed_signers, const char *revoked_signers, int verbosity)
6929 624411d2 2023-07-08 jrick static const struct got_error *err = NULL;
6930 624411d2 2023-07-08 jrick struct got_reflist_head refs;
6931 624411d2 2023-07-08 jrick struct got_reflist_entry *re;
6932 624411d2 2023-07-08 jrick char *wanted_refname = NULL;
6933 624411d2 2023-07-08 jrick int bad_sigs = 0;
6935 624411d2 2023-07-08 jrick TAILQ_INIT(&refs);
6937 624411d2 2023-07-08 jrick err = got_ref_list(&refs, repo, "refs/tags", got_ref_cmp_tags, repo);
6939 624411d2 2023-07-08 jrick return err;
6941 624411d2 2023-07-08 jrick if (tag_name) {
6942 624411d2 2023-07-08 jrick struct got_reference *ref;
6943 624411d2 2023-07-08 jrick err = get_tag_refname(&wanted_refname, tag_name);
6945 624411d2 2023-07-08 jrick goto done;
6946 624411d2 2023-07-08 jrick /* Wanted tag reference should exist. */
6947 624411d2 2023-07-08 jrick err = got_ref_open(&ref, repo, wanted_refname, 0);
6949 624411d2 2023-07-08 jrick goto done;
6950 624411d2 2023-07-08 jrick got_ref_close(ref);
6953 624411d2 2023-07-08 jrick TAILQ_FOREACH(re, &refs, entry) {
6954 624411d2 2023-07-08 jrick const char *refname;
6955 624411d2 2023-07-08 jrick char *refstr, *tagmsg0, *tagmsg, *line, *id_str, *datestr;
6956 624411d2 2023-07-08 jrick char datebuf[26];
6957 624411d2 2023-07-08 jrick const char *tagger, *ssh_sig = NULL;
6958 624411d2 2023-07-08 jrick char *sig_msg = NULL;
6959 624411d2 2023-07-08 jrick time_t tagger_time;
6960 624411d2 2023-07-08 jrick struct got_object_id *id;
6961 624411d2 2023-07-08 jrick struct got_tag_object *tag;
6962 624411d2 2023-07-08 jrick struct got_commit_object *commit = NULL;
6964 624411d2 2023-07-08 jrick refname = got_ref_get_name(re->ref);
6965 624411d2 2023-07-08 jrick if (strncmp(refname, "refs/tags/", 10) != 0 ||
6966 624411d2 2023-07-08 jrick (wanted_refname && strcmp(refname, wanted_refname) != 0))
6967 624411d2 2023-07-08 jrick continue;
6968 624411d2 2023-07-08 jrick refname += 10;
6969 624411d2 2023-07-08 jrick refstr = got_ref_to_str(re->ref);
6970 624411d2 2023-07-08 jrick if (refstr == NULL) {
6971 624411d2 2023-07-08 jrick err = got_error_from_errno("got_ref_to_str");
6975 624411d2 2023-07-08 jrick err = got_ref_resolve(&id, repo, re->ref);
6978 624411d2 2023-07-08 jrick err = got_object_open_as_tag(&tag, repo, id);
6979 624411d2 2023-07-08 jrick if (err) {
6980 624411d2 2023-07-08 jrick if (err->code != GOT_ERR_OBJ_TYPE) {
6981 624411d2 2023-07-08 jrick free(id);
6984 624411d2 2023-07-08 jrick /* "lightweight" tag */
6985 624411d2 2023-07-08 jrick err = got_object_open_as_commit(&commit, repo, id);
6986 624411d2 2023-07-08 jrick if (err) {
6987 624411d2 2023-07-08 jrick free(id);
6990 624411d2 2023-07-08 jrick tagger = got_object_commit_get_committer(commit);
6991 624411d2 2023-07-08 jrick tagger_time =
6992 624411d2 2023-07-08 jrick got_object_commit_get_committer_time(commit);
6993 624411d2 2023-07-08 jrick err = got_object_id_str(&id_str, id);
6994 624411d2 2023-07-08 jrick free(id);
6998 624411d2 2023-07-08 jrick free(id);
6999 624411d2 2023-07-08 jrick tagger = got_object_tag_get_tagger(tag);
7000 624411d2 2023-07-08 jrick tagger_time = got_object_tag_get_tagger_time(tag);
7001 624411d2 2023-07-08 jrick err = got_object_id_str(&id_str,
7002 624411d2 2023-07-08 jrick got_object_tag_get_object_id(tag));
7007 624411d2 2023-07-08 jrick if (tag && verify_tags) {
7008 624411d2 2023-07-08 jrick ssh_sig = got_sigs_get_tagmsg_ssh_signature(
7009 624411d2 2023-07-08 jrick got_object_tag_get_message(tag));
7010 624411d2 2023-07-08 jrick if (ssh_sig && allowed_signers == NULL) {
7011 624411d2 2023-07-08 jrick err = got_error_msg(
7012 624411d2 2023-07-08 jrick GOT_ERR_VERIFY_TAG_SIGNATURE,
7013 624411d2 2023-07-08 jrick "SSH signature verification requires "
7014 624411d2 2023-07-08 jrick "setting allowed_signers in "
7015 624411d2 2023-07-08 jrick "got.conf(5)");
7020 624411d2 2023-07-08 jrick printf("%stag %s %s\n", GOT_COMMIT_SEP_STR, refname, refstr);
7021 624411d2 2023-07-08 jrick free(refstr);
7022 624411d2 2023-07-08 jrick printf("from: %s\n", tagger);
7023 624411d2 2023-07-08 jrick datestr = get_datestr(&tagger_time, datebuf);
7024 624411d2 2023-07-08 jrick if (datestr)
7025 624411d2 2023-07-08 jrick printf("date: %s UTC\n", datestr);
7026 624411d2 2023-07-08 jrick if (commit)
7027 624411d2 2023-07-08 jrick printf("object: %s %s\n", GOT_OBJ_LABEL_COMMIT, id_str);
7029 624411d2 2023-07-08 jrick switch (got_object_tag_get_object_type(tag)) {
7030 624411d2 2023-07-08 jrick case GOT_OBJ_TYPE_BLOB:
7031 624411d2 2023-07-08 jrick printf("object: %s %s\n", GOT_OBJ_LABEL_BLOB,
7034 624411d2 2023-07-08 jrick case GOT_OBJ_TYPE_TREE:
7035 624411d2 2023-07-08 jrick printf("object: %s %s\n", GOT_OBJ_LABEL_TREE,
7038 624411d2 2023-07-08 jrick case GOT_OBJ_TYPE_COMMIT:
7039 624411d2 2023-07-08 jrick printf("object: %s %s\n", GOT_OBJ_LABEL_COMMIT,
7042 624411d2 2023-07-08 jrick case GOT_OBJ_TYPE_TAG:
7043 624411d2 2023-07-08 jrick printf("object: %s %s\n", GOT_OBJ_LABEL_TAG,
7050 624411d2 2023-07-08 jrick free(id_str);
7052 624411d2 2023-07-08 jrick if (ssh_sig) {
7053 624411d2 2023-07-08 jrick err = got_sigs_verify_tag_ssh(&sig_msg, tag, ssh_sig,
7054 624411d2 2023-07-08 jrick allowed_signers, revoked_signers, verbosity);
7055 624411d2 2023-07-08 jrick if (err && err->code == GOT_ERR_BAD_TAG_SIGNATURE)
7056 624411d2 2023-07-08 jrick bad_sigs = 1;
7057 624411d2 2023-07-08 jrick else if (err)
7059 624411d2 2023-07-08 jrick printf("signature: %s", sig_msg);
7060 624411d2 2023-07-08 jrick free(sig_msg);
7061 624411d2 2023-07-08 jrick sig_msg = NULL;
7064 624411d2 2023-07-08 jrick if (commit) {
7065 624411d2 2023-07-08 jrick err = got_object_commit_get_logmsg(&tagmsg0, commit);
7068 624411d2 2023-07-08 jrick got_object_commit_close(commit);
7070 624411d2 2023-07-08 jrick tagmsg0 = strdup(got_object_tag_get_message(tag));
7071 624411d2 2023-07-08 jrick got_object_tag_close(tag);
7072 624411d2 2023-07-08 jrick if (tagmsg0 == NULL) {
7073 624411d2 2023-07-08 jrick err = got_error_from_errno("strdup");
7078 624411d2 2023-07-08 jrick tagmsg = tagmsg0;
7080 624411d2 2023-07-08 jrick line = strsep(&tagmsg, "\n");
7081 624411d2 2023-07-08 jrick if (line)
7082 624411d2 2023-07-08 jrick printf(" %s\n", line);
7083 624411d2 2023-07-08 jrick } while (line);
7084 624411d2 2023-07-08 jrick free(tagmsg0);
7087 624411d2 2023-07-08 jrick got_ref_list_free(&refs);
7088 624411d2 2023-07-08 jrick free(wanted_refname);
7090 624411d2 2023-07-08 jrick if (err == NULL && bad_sigs)
7091 624411d2 2023-07-08 jrick err = got_error(GOT_ERR_BAD_TAG_SIGNATURE);
7092 624411d2 2023-07-08 jrick return err;
7095 624411d2 2023-07-08 jrick static const struct got_error *
7096 624411d2 2023-07-08 jrick get_tag_message(char **tagmsg, char **tagmsg_path, const char *commit_id_str,
7097 624411d2 2023-07-08 jrick const char *tag_name, const char *repo_path)
7099 624411d2 2023-07-08 jrick const struct got_error *err = NULL;
7100 624411d2 2023-07-08 jrick char *template = NULL, *initial_content = NULL;
7101 624411d2 2023-07-08 jrick char *editor = NULL;
7102 624411d2 2023-07-08 jrick int initial_content_len;
7103 624411d2 2023-07-08 jrick int fd = -1;
7105 624411d2 2023-07-08 jrick if (asprintf(&template, GOT_TMPDIR_STR "/got-tagmsg") == -1) {
7106 624411d2 2023-07-08 jrick err = got_error_from_errno("asprintf");
7107 624411d2 2023-07-08 jrick goto done;
7110 624411d2 2023-07-08 jrick initial_content_len = asprintf(&initial_content,
7111 624411d2 2023-07-08 jrick "\n# tagging commit %s as %s\n",
7112 624411d2 2023-07-08 jrick commit_id_str, tag_name);
7113 624411d2 2023-07-08 jrick if (initial_content_len == -1) {
7114 624411d2 2023-07-08 jrick err = got_error_from_errno("asprintf");
7115 624411d2 2023-07-08 jrick goto done;
7118 624411d2 2023-07-08 jrick err = got_opentemp_named_fd(tagmsg_path, &fd, template, "");
7120 624411d2 2023-07-08 jrick goto done;
7122 624411d2 2023-07-08 jrick if (write(fd, initial_content, initial_content_len) == -1) {
7123 624411d2 2023-07-08 jrick err = got_error_from_errno2("write", *tagmsg_path);
7124 624411d2 2023-07-08 jrick goto done;
7126 624411d2 2023-07-08 jrick if (close(fd) == -1) {
7127 624411d2 2023-07-08 jrick err = got_error_from_errno2("close", *tagmsg_path);
7128 624411d2 2023-07-08 jrick goto done;
7132 624411d2 2023-07-08 jrick err = get_editor(&editor);
7134 624411d2 2023-07-08 jrick goto done;
7135 624411d2 2023-07-08 jrick err = edit_logmsg(tagmsg, editor, *tagmsg_path, initial_content,
7136 624411d2 2023-07-08 jrick initial_content_len, 1);
7138 624411d2 2023-07-08 jrick free(initial_content);
7139 624411d2 2023-07-08 jrick free(template);
7140 624411d2 2023-07-08 jrick free(editor);
7142 624411d2 2023-07-08 jrick if (fd != -1 && close(fd) == -1 && err == NULL)
7143 624411d2 2023-07-08 jrick err = got_error_from_errno2("close", *tagmsg_path);
7145 624411d2 2023-07-08 jrick if (err) {
7146 624411d2 2023-07-08 jrick free(*tagmsg);
7147 624411d2 2023-07-08 jrick *tagmsg = NULL;
7149 624411d2 2023-07-08 jrick return err;
7152 624411d2 2023-07-08 jrick static const struct got_error *
7153 624411d2 2023-07-08 jrick add_tag(struct got_repository *repo, const char *tagger,
7154 624411d2 2023-07-08 jrick const char *tag_name, const char *commit_arg, const char *tagmsg_arg,
7155 624411d2 2023-07-08 jrick const char *signer_id, int verbosity)
7157 624411d2 2023-07-08 jrick const struct got_error *err = NULL;
7158 624411d2 2023-07-08 jrick struct got_object_id *commit_id = NULL, *tag_id = NULL;
7159 624411d2 2023-07-08 jrick char *label = NULL, *commit_id_str = NULL;
7160 624411d2 2023-07-08 jrick struct got_reference *ref = NULL;
7161 624411d2 2023-07-08 jrick char *refname = NULL, *tagmsg = NULL;
7162 624411d2 2023-07-08 jrick char *tagmsg_path = NULL, *tag_id_str = NULL;
7163 624411d2 2023-07-08 jrick int preserve_tagmsg = 0;
7164 624411d2 2023-07-08 jrick struct got_reflist_head refs;
7166 624411d2 2023-07-08 jrick TAILQ_INIT(&refs);
7169 624411d2 2023-07-08 jrick * Don't let the user create a tag name with a leading '-'.
7170 624411d2 2023-07-08 jrick * While technically a valid reference name, this case is usually
7171 624411d2 2023-07-08 jrick * an unintended typo.
7173 624411d2 2023-07-08 jrick if (tag_name[0] == '-')
7174 624411d2 2023-07-08 jrick return got_error_path(tag_name, GOT_ERR_REF_NAME_MINUS);
7176 624411d2 2023-07-08 jrick err = got_ref_list(&refs, repo, NULL, got_ref_cmp_by_name, NULL);
7178 624411d2 2023-07-08 jrick goto done;
7180 624411d2 2023-07-08 jrick err = got_repo_match_object_id(&commit_id, &label, commit_arg,
7181 624411d2 2023-07-08 jrick GOT_OBJ_TYPE_COMMIT, &refs, repo);
7183 624411d2 2023-07-08 jrick goto done;
7185 624411d2 2023-07-08 jrick err = got_object_id_str(&commit_id_str, commit_id);
7187 624411d2 2023-07-08 jrick goto done;
7189 624411d2 2023-07-08 jrick err = get_tag_refname(&refname, tag_name);
7191 624411d2 2023-07-08 jrick goto done;
7192 624411d2 2023-07-08 jrick if (strncmp("refs/tags/", tag_name, 10) == 0)
7193 624411d2 2023-07-08 jrick tag_name += 10;
7195 624411d2 2023-07-08 jrick err = got_ref_open(&ref, repo, refname, 0);
7196 624411d2 2023-07-08 jrick if (err == NULL) {
7197 624411d2 2023-07-08 jrick err = got_error(GOT_ERR_TAG_EXISTS);
7198 624411d2 2023-07-08 jrick goto done;
7199 624411d2 2023-07-08 jrick } else if (err->code != GOT_ERR_NOT_REF)
7200 624411d2 2023-07-08 jrick goto done;
7202 624411d2 2023-07-08 jrick if (tagmsg_arg == NULL) {
7203 624411d2 2023-07-08 jrick err = get_tag_message(&tagmsg, &tagmsg_path, commit_id_str,
7204 624411d2 2023-07-08 jrick tag_name, got_repo_get_path(repo));
7205 624411d2 2023-07-08 jrick if (err) {
7206 624411d2 2023-07-08 jrick if (err->code != GOT_ERR_COMMIT_MSG_EMPTY &&
7207 624411d2 2023-07-08 jrick tagmsg_path != NULL)
7208 624411d2 2023-07-08 jrick preserve_tagmsg = 1;
7209 624411d2 2023-07-08 jrick goto done;
7211 624411d2 2023-07-08 jrick /* Editor is done; we can now apply unveil(2) */
7212 624411d2 2023-07-08 jrick err = got_sigs_apply_unveil();
7214 624411d2 2023-07-08 jrick goto done;
7215 624411d2 2023-07-08 jrick err = apply_unveil(got_repo_get_path(repo), 0, NULL);
7217 624411d2 2023-07-08 jrick goto done;
7220 624411d2 2023-07-08 jrick err = got_object_tag_create(&tag_id, tag_name, commit_id,
7221 624411d2 2023-07-08 jrick tagger, time(NULL), tagmsg ? tagmsg : tagmsg_arg, signer_id, repo,
7222 624411d2 2023-07-08 jrick verbosity);
7223 624411d2 2023-07-08 jrick if (err) {
7224 624411d2 2023-07-08 jrick if (tagmsg_path)
7225 624411d2 2023-07-08 jrick preserve_tagmsg = 1;
7226 624411d2 2023-07-08 jrick goto done;
7229 624411d2 2023-07-08 jrick err = got_ref_alloc(&ref, refname, tag_id);
7230 624411d2 2023-07-08 jrick if (err) {
7231 624411d2 2023-07-08 jrick if (tagmsg_path)
7232 624411d2 2023-07-08 jrick preserve_tagmsg = 1;
7233 624411d2 2023-07-08 jrick goto done;
7236 624411d2 2023-07-08 jrick err = got_ref_write(ref, repo);
7237 624411d2 2023-07-08 jrick if (err) {
7238 624411d2 2023-07-08 jrick if (tagmsg_path)
7239 624411d2 2023-07-08 jrick preserve_tagmsg = 1;
7240 624411d2 2023-07-08 jrick goto done;
7243 624411d2 2023-07-08 jrick err = got_object_id_str(&tag_id_str, tag_id);
7244 624411d2 2023-07-08 jrick if (err) {
7245 624411d2 2023-07-08 jrick if (tagmsg_path)
7246 624411d2 2023-07-08 jrick preserve_tagmsg = 1;
7247 624411d2 2023-07-08 jrick goto done;
7249 624411d2 2023-07-08 jrick printf("Created tag %s\n", tag_id_str);
7251 624411d2 2023-07-08 jrick if (preserve_tagmsg) {
7252 624411d2 2023-07-08 jrick fprintf(stderr, "%s: tag message preserved in %s\n",
7253 624411d2 2023-07-08 jrick getprogname(), tagmsg_path);
7254 624411d2 2023-07-08 jrick } else if (tagmsg_path && unlink(tagmsg_path) == -1 && err == NULL)
7255 624411d2 2023-07-08 jrick err = got_error_from_errno2("unlink", tagmsg_path);
7256 624411d2 2023-07-08 jrick free(tag_id_str);
7258 624411d2 2023-07-08 jrick got_ref_close(ref);
7259 624411d2 2023-07-08 jrick free(commit_id);
7260 624411d2 2023-07-08 jrick free(commit_id_str);
7261 624411d2 2023-07-08 jrick free(refname);
7262 624411d2 2023-07-08 jrick free(tagmsg);
7263 624411d2 2023-07-08 jrick free(tagmsg_path);
7264 624411d2 2023-07-08 jrick got_ref_list_free(&refs);
7265 624411d2 2023-07-08 jrick return err;
7268 624411d2 2023-07-08 jrick static const struct got_error *
7269 624411d2 2023-07-08 jrick cmd_tag(int argc, char *argv[])
7271 624411d2 2023-07-08 jrick const struct got_error *error = NULL;
7272 624411d2 2023-07-08 jrick struct got_repository *repo = NULL;
7273 624411d2 2023-07-08 jrick struct got_worktree *worktree = NULL;
7274 624411d2 2023-07-08 jrick char *cwd = NULL, *repo_path = NULL, *commit_id_str = NULL;
7275 624411d2 2023-07-08 jrick char *gitconfig_path = NULL, *tagger = NULL;
7276 624411d2 2023-07-08 jrick char *allowed_signers = NULL, *revoked_signers = NULL;
7277 624411d2 2023-07-08 jrick const char *signer_id = NULL;
7278 624411d2 2023-07-08 jrick const char *tag_name = NULL, *commit_id_arg = NULL, *tagmsg = NULL;
7279 624411d2 2023-07-08 jrick int ch, do_list = 0, verify_tags = 0, verbosity = 0;
7280 624411d2 2023-07-08 jrick int *pack_fds = NULL;
7282 624411d2 2023-07-08 jrick #ifndef PROFILE
7283 624411d2 2023-07-08 jrick if (pledge("stdio rpath wpath cpath fattr flock proc exec "
7284 624411d2 2023-07-08 jrick "sendfd unveil", NULL) == -1)
7285 624411d2 2023-07-08 jrick err(1, "pledge");
7288 624411d2 2023-07-08 jrick while ((ch = getopt(argc, argv, "c:lm:r:s:Vv")) != -1) {
7289 624411d2 2023-07-08 jrick switch (ch) {
7290 624411d2 2023-07-08 jrick case 'c':
7291 624411d2 2023-07-08 jrick commit_id_arg = optarg;
7293 624411d2 2023-07-08 jrick case 'l':
7294 624411d2 2023-07-08 jrick do_list = 1;
7296 624411d2 2023-07-08 jrick case 'm':
7297 624411d2 2023-07-08 jrick tagmsg = optarg;
7299 624411d2 2023-07-08 jrick case 'r':
7300 624411d2 2023-07-08 jrick repo_path = realpath(optarg, NULL);
7301 624411d2 2023-07-08 jrick if (repo_path == NULL) {
7302 624411d2 2023-07-08 jrick error = got_error_from_errno2("realpath",
7304 624411d2 2023-07-08 jrick goto done;
7306 624411d2 2023-07-08 jrick got_path_strip_trailing_slashes(repo_path);
7308 624411d2 2023-07-08 jrick case 's':
7309 624411d2 2023-07-08 jrick signer_id = optarg;
7311 624411d2 2023-07-08 jrick case 'V':
7312 624411d2 2023-07-08 jrick verify_tags = 1;
7314 624411d2 2023-07-08 jrick case 'v':
7315 624411d2 2023-07-08 jrick if (verbosity < 0)
7316 624411d2 2023-07-08 jrick verbosity = 0;
7317 624411d2 2023-07-08 jrick else if (verbosity < 3)
7318 624411d2 2023-07-08 jrick verbosity++;
7321 624411d2 2023-07-08 jrick usage_tag();
7322 624411d2 2023-07-08 jrick /* NOTREACHED */
7326 624411d2 2023-07-08 jrick argc -= optind;
7327 624411d2 2023-07-08 jrick argv += optind;
7329 624411d2 2023-07-08 jrick if (do_list || verify_tags) {
7330 624411d2 2023-07-08 jrick if (commit_id_arg != NULL)
7332 624411d2 2023-07-08 jrick "-c option can only be used when creating a tag");
7333 624411d2 2023-07-08 jrick if (tagmsg) {
7334 624411d2 2023-07-08 jrick if (do_list)
7335 624411d2 2023-07-08 jrick option_conflict('l', 'm');
7337 624411d2 2023-07-08 jrick option_conflict('V', 'm');
7339 624411d2 2023-07-08 jrick if (signer_id) {
7340 624411d2 2023-07-08 jrick if (do_list)
7341 624411d2 2023-07-08 jrick option_conflict('l', 's');
7343 624411d2 2023-07-08 jrick option_conflict('V', 's');
7345 624411d2 2023-07-08 jrick if (argc > 1)
7346 624411d2 2023-07-08 jrick usage_tag();
7347 624411d2 2023-07-08 jrick } else if (argc != 1)
7348 624411d2 2023-07-08 jrick usage_tag();
7350 624411d2 2023-07-08 jrick if (argc == 1)
7351 624411d2 2023-07-08 jrick tag_name = argv[0];
7353 624411d2 2023-07-08 jrick cwd = getcwd(NULL, 0);
7354 624411d2 2023-07-08 jrick if (cwd == NULL) {
7355 624411d2 2023-07-08 jrick error = got_error_from_errno("getcwd");
7356 624411d2 2023-07-08 jrick goto done;
7359 624411d2 2023-07-08 jrick error = got_repo_pack_fds_open(&pack_fds);
7360 624411d2 2023-07-08 jrick if (error != NULL)
7361 624411d2 2023-07-08 jrick goto done;
7363 624411d2 2023-07-08 jrick if (repo_path == NULL) {
7364 624411d2 2023-07-08 jrick error = got_worktree_open(&worktree, cwd);
7365 624411d2 2023-07-08 jrick if (error && error->code != GOT_ERR_NOT_WORKTREE)
7366 624411d2 2023-07-08 jrick goto done;
7368 624411d2 2023-07-08 jrick error = NULL;
7369 624411d2 2023-07-08 jrick if (worktree) {
7370 624411d2 2023-07-08 jrick repo_path =
7371 624411d2 2023-07-08 jrick strdup(got_worktree_get_repo_path(worktree));
7372 624411d2 2023-07-08 jrick if (repo_path == NULL)
7373 624411d2 2023-07-08 jrick error = got_error_from_errno("strdup");
7374 624411d2 2023-07-08 jrick if (error)
7375 624411d2 2023-07-08 jrick goto done;
7377 624411d2 2023-07-08 jrick repo_path = strdup(cwd);
7378 624411d2 2023-07-08 jrick if (repo_path == NULL) {
7379 624411d2 2023-07-08 jrick error = got_error_from_errno("strdup");
7380 624411d2 2023-07-08 jrick goto done;
7385 624411d2 2023-07-08 jrick if (do_list || verify_tags) {
7386 624411d2 2023-07-08 jrick error = got_repo_open(&repo, repo_path, NULL, pack_fds);
7387 624411d2 2023-07-08 jrick if (error != NULL)
7388 624411d2 2023-07-08 jrick goto done;
7389 624411d2 2023-07-08 jrick error = get_allowed_signers(&allowed_signers, repo, worktree);
7390 624411d2 2023-07-08 jrick if (error)
7391 624411d2 2023-07-08 jrick goto done;
7392 624411d2 2023-07-08 jrick error = get_revoked_signers(&revoked_signers, repo, worktree);
7393 624411d2 2023-07-08 jrick if (error)
7394 624411d2 2023-07-08 jrick goto done;
7395 624411d2 2023-07-08 jrick if (worktree) {
7396 624411d2 2023-07-08 jrick /* Release work tree lock. */
7397 624411d2 2023-07-08 jrick got_worktree_close(worktree);
7398 624411d2 2023-07-08 jrick worktree = NULL;
7402 624411d2 2023-07-08 jrick * Remove "cpath" promise unless needed for signature tmpfile
7403 624411d2 2023-07-08 jrick * creation.
7405 624411d2 2023-07-08 jrick if (verify_tags)
7406 624411d2 2023-07-08 jrick got_sigs_apply_unveil();
7408 624411d2 2023-07-08 jrick #ifndef PROFILE
7409 624411d2 2023-07-08 jrick if (pledge("stdio rpath wpath flock proc exec sendfd "
7410 624411d2 2023-07-08 jrick "unveil", NULL) == -1)
7411 624411d2 2023-07-08 jrick err(1, "pledge");
7414 624411d2 2023-07-08 jrick error = apply_unveil(got_repo_get_path(repo), 1, NULL);
7415 624411d2 2023-07-08 jrick if (error)
7416 624411d2 2023-07-08 jrick goto done;
7417 624411d2 2023-07-08 jrick error = list_tags(repo, tag_name, verify_tags, allowed_signers,
7418 624411d2 2023-07-08 jrick revoked_signers, verbosity);
7420 624411d2 2023-07-08 jrick error = get_gitconfig_path(&gitconfig_path);
7421 624411d2 2023-07-08 jrick if (error)
7422 624411d2 2023-07-08 jrick goto done;
7423 624411d2 2023-07-08 jrick error = got_repo_open(&repo, repo_path, gitconfig_path,
7424 624411d2 2023-07-08 jrick pack_fds);
7425 624411d2 2023-07-08 jrick if (error != NULL)
7426 624411d2 2023-07-08 jrick goto done;
7428 624411d2 2023-07-08 jrick error = get_author(&tagger, repo, worktree);
7429 624411d2 2023-07-08 jrick if (error)
7430 624411d2 2023-07-08 jrick goto done;
7431 624411d2 2023-07-08 jrick if (signer_id == NULL)
7432 624411d2 2023-07-08 jrick signer_id = get_signer_id(repo, worktree);
7434 624411d2 2023-07-08 jrick if (tagmsg) {
7435 624411d2 2023-07-08 jrick if (signer_id) {
7436 624411d2 2023-07-08 jrick error = got_sigs_apply_unveil();
7437 624411d2 2023-07-08 jrick if (error)
7438 624411d2 2023-07-08 jrick goto done;
7440 624411d2 2023-07-08 jrick error = apply_unveil(got_repo_get_path(repo), 0, NULL);
7441 624411d2 2023-07-08 jrick if (error)
7442 624411d2 2023-07-08 jrick goto done;
7445 624411d2 2023-07-08 jrick if (commit_id_arg == NULL) {
7446 624411d2 2023-07-08 jrick struct got_reference *head_ref;
7447 624411d2 2023-07-08 jrick struct got_object_id *commit_id;
7448 624411d2 2023-07-08 jrick error = got_ref_open(&head_ref, repo,
7449 624411d2 2023-07-08 jrick worktree ? got_worktree_get_head_ref_name(worktree)
7450 624411d2 2023-07-08 jrick : GOT_REF_HEAD, 0);
7451 624411d2 2023-07-08 jrick if (error)
7452 624411d2 2023-07-08 jrick goto done;
7453 624411d2 2023-07-08 jrick error = got_ref_resolve(&commit_id, repo, head_ref);
7454 624411d2 2023-07-08 jrick got_ref_close(head_ref);
7455 624411d2 2023-07-08 jrick if (error)
7456 624411d2 2023-07-08 jrick goto done;
7457 624411d2 2023-07-08 jrick error = got_object_id_str(&commit_id_str, commit_id);
7458 624411d2 2023-07-08 jrick free(commit_id);
7459 624411d2 2023-07-08 jrick if (error)
7460 624411d2 2023-07-08 jrick goto done;
7463 624411d2 2023-07-08 jrick if (worktree) {
7464 624411d2 2023-07-08 jrick /* Release work tree lock. */
7465 624411d2 2023-07-08 jrick got_worktree_close(worktree);
7466 624411d2 2023-07-08 jrick worktree = NULL;
7469 624411d2 2023-07-08 jrick error = add_tag(repo, tagger, tag_name,
7470 624411d2 2023-07-08 jrick commit_id_str ? commit_id_str : commit_id_arg, tagmsg,
7471 624411d2 2023-07-08 jrick signer_id, verbosity);
7474 624411d2 2023-07-08 jrick if (repo) {
7475 624411d2 2023-07-08 jrick const struct got_error *close_err = got_repo_close(repo);
7476 624411d2 2023-07-08 jrick if (error == NULL)
7477 624411d2 2023-07-08 jrick error = close_err;
7479 624411d2 2023-07-08 jrick if (worktree)
7480 624411d2 2023-07-08 jrick got_worktree_close(worktree);
7481 624411d2 2023-07-08 jrick if (pack_fds) {
7482 624411d2 2023-07-08 jrick const struct got_error *pack_err =
7483 624411d2 2023-07-08 jrick got_repo_pack_fds_close(pack_fds);
7484 624411d2 2023-07-08 jrick if (error == NULL)
7485 624411d2 2023-07-08 jrick error = pack_err;
7487 624411d2 2023-07-08 jrick free(cwd);
7488 624411d2 2023-07-08 jrick free(repo_path);
7489 624411d2 2023-07-08 jrick free(gitconfig_path);
7490 624411d2 2023-07-08 jrick free(commit_id_str);
7491 624411d2 2023-07-08 jrick free(tagger);
7492 624411d2 2023-07-08 jrick free(allowed_signers);
7493 624411d2 2023-07-08 jrick free(revoked_signers);
7494 624411d2 2023-07-08 jrick return error;
7497 624411d2 2023-07-08 jrick __dead static void
7498 624411d2 2023-07-08 jrick usage_add(void)
7500 624411d2 2023-07-08 jrick fprintf(stderr, "usage: %s add [-IR] path ...\n", getprogname());
7504 624411d2 2023-07-08 jrick static const struct got_error *
7505 624411d2 2023-07-08 jrick add_progress(void *arg, unsigned char status, const char *path)
7507 624411d2 2023-07-08 jrick while (path[0] == '/')
7509 624411d2 2023-07-08 jrick printf("%c %s\n", status, path);
7510 624411d2 2023-07-08 jrick return NULL;
7513 624411d2 2023-07-08 jrick static const struct got_error *
7514 624411d2 2023-07-08 jrick cmd_add(int argc, char *argv[])
7516 624411d2 2023-07-08 jrick const struct got_error *error = NULL;
7517 624411d2 2023-07-08 jrick struct got_repository *repo = NULL;
7518 624411d2 2023-07-08 jrick struct got_worktree *worktree = NULL;
7519 624411d2 2023-07-08 jrick char *cwd = NULL;
7520 624411d2 2023-07-08 jrick struct got_pathlist_head paths;
7521 624411d2 2023-07-08 jrick struct got_pathlist_entry *pe;
7522 624411d2 2023-07-08 jrick int ch, can_recurse = 0, no_ignores = 0;
7523 624411d2 2023-07-08 jrick int *pack_fds = NULL;
7525 624411d2 2023-07-08 jrick TAILQ_INIT(&paths);
7527 624411d2 2023-07-08 jrick #ifndef PROFILE
7528 624411d2 2023-07-08 jrick if (pledge("stdio rpath wpath cpath flock proc exec sendfd unveil",
7529 624411d2 2023-07-08 jrick NULL) == -1)
7530 624411d2 2023-07-08 jrick err(1, "pledge");
7533 624411d2 2023-07-08 jrick while ((ch = getopt(argc, argv, "IR")) != -1) {
7534 624411d2 2023-07-08 jrick switch (ch) {
7535 624411d2 2023-07-08 jrick case 'I':
7536 624411d2 2023-07-08 jrick no_ignores = 1;
7538 624411d2 2023-07-08 jrick case 'R':
7539 624411d2 2023-07-08 jrick can_recurse = 1;
7542 624411d2 2023-07-08 jrick usage_add();
7543 624411d2 2023-07-08 jrick /* NOTREACHED */
7547 624411d2 2023-07-08 jrick argc -= optind;
7548 624411d2 2023-07-08 jrick argv += optind;
7550 624411d2 2023-07-08 jrick if (argc < 1)
7551 624411d2 2023-07-08 jrick usage_add();
7553 624411d2 2023-07-08 jrick cwd = getcwd(NULL, 0);
7554 624411d2 2023-07-08 jrick if (cwd == NULL) {
7555 624411d2 2023-07-08 jrick error = got_error_from_errno("getcwd");
7556 624411d2 2023-07-08 jrick goto done;
7559 624411d2 2023-07-08 jrick error = got_repo_pack_fds_open(&pack_fds);
7560 624411d2 2023-07-08 jrick if (error != NULL)
7561 624411d2 2023-07-08 jrick goto done;
7563 624411d2 2023-07-08 jrick error = got_worktree_open(&worktree, cwd);
7564 624411d2 2023-07-08 jrick if (error) {
7565 624411d2 2023-07-08 jrick if (error->code == GOT_ERR_NOT_WORKTREE)
7566 624411d2 2023-07-08 jrick error = wrap_not_worktree_error(error, "add", cwd);
7567 624411d2 2023-07-08 jrick goto done;
7570 624411d2 2023-07-08 jrick error = got_repo_open(&repo, got_worktree_get_repo_path(worktree),
7571 624411d2 2023-07-08 jrick NULL, pack_fds);
7572 624411d2 2023-07-08 jrick if (error != NULL)
7573 624411d2 2023-07-08 jrick goto done;
7575 624411d2 2023-07-08 jrick error = apply_unveil(got_repo_get_path(repo), 1,
7576 624411d2 2023-07-08 jrick got_worktree_get_root_path(worktree));
7577 624411d2 2023-07-08 jrick if (error)
7578 624411d2 2023-07-08 jrick goto done;
7580 624411d2 2023-07-08 jrick error = get_worktree_paths_from_argv(&paths, argc, argv, worktree);
7581 624411d2 2023-07-08 jrick if (error)
7582 624411d2 2023-07-08 jrick goto done;
7584 624411d2 2023-07-08 jrick if (!can_recurse) {
7585 624411d2 2023-07-08 jrick char *ondisk_path;
7586 624411d2 2023-07-08 jrick struct stat sb;
7587 624411d2 2023-07-08 jrick TAILQ_FOREACH(pe, &paths, entry) {
7588 624411d2 2023-07-08 jrick if (asprintf(&ondisk_path, "%s/%s",
7589 624411d2 2023-07-08 jrick got_worktree_get_root_path(worktree),
7590 624411d2 2023-07-08 jrick pe->path) == -1) {
7591 624411d2 2023-07-08 jrick error = got_error_from_errno("asprintf");
7592 624411d2 2023-07-08 jrick goto done;
7594 624411d2 2023-07-08 jrick if (lstat(ondisk_path, &sb) == -1) {
7595 624411d2 2023-07-08 jrick if (errno == ENOENT) {
7596 624411d2 2023-07-08 jrick free(ondisk_path);
7597 624411d2 2023-07-08 jrick continue;
7599 624411d2 2023-07-08 jrick error = got_error_from_errno2("lstat",
7600 624411d2 2023-07-08 jrick ondisk_path);
7601 624411d2 2023-07-08 jrick free(ondisk_path);
7602 624411d2 2023-07-08 jrick goto done;
7604 624411d2 2023-07-08 jrick free(ondisk_path);
7605 624411d2 2023-07-08 jrick if (S_ISDIR(sb.st_mode)) {
7606 624411d2 2023-07-08 jrick error = got_error_msg(GOT_ERR_BAD_PATH,
7607 624411d2 2023-07-08 jrick "adding directories requires -R option");
7608 624411d2 2023-07-08 jrick goto done;
7613 624411d2 2023-07-08 jrick error = got_worktree_schedule_add(worktree, &paths, add_progress,
7614 624411d2 2023-07-08 jrick NULL, repo, no_ignores);
7616 624411d2 2023-07-08 jrick if (repo) {
7617 624411d2 2023-07-08 jrick const struct got_error *close_err = got_repo_close(repo);
7618 624411d2 2023-07-08 jrick if (error == NULL)
7619 624411d2 2023-07-08 jrick error = close_err;
7621 624411d2 2023-07-08 jrick if (worktree)
7622 624411d2 2023-07-08 jrick got_worktree_close(worktree);
7623 624411d2 2023-07-08 jrick if (pack_fds) {
7624 624411d2 2023-07-08 jrick const struct got_error *pack_err =
7625 624411d2 2023-07-08 jrick got_repo_pack_fds_close(pack_fds);
7626 624411d2 2023-07-08 jrick if (error == NULL)
7627 624411d2 2023-07-08 jrick error = pack_err;
7629 624411d2 2023-07-08 jrick got_pathlist_free(&paths, GOT_PATHLIST_FREE_PATH);
7630 624411d2 2023-07-08 jrick free(cwd);
7631 624411d2 2023-07-08 jrick return error;
7634 624411d2 2023-07-08 jrick __dead static void
7635 624411d2 2023-07-08 jrick usage_remove(void)
7637 624411d2 2023-07-08 jrick fprintf(stderr, "usage: %s remove [-fkR] [-s status-codes] path ...\n",
7638 624411d2 2023-07-08 jrick getprogname());
7642 624411d2 2023-07-08 jrick static const struct got_error *
7643 624411d2 2023-07-08 jrick print_remove_status(void *arg, unsigned char status,
7644 624411d2 2023-07-08 jrick unsigned char staged_status, const char *path)
7646 624411d2 2023-07-08 jrick while (path[0] == '/')
7648 624411d2 2023-07-08 jrick if (status == GOT_STATUS_NONEXISTENT)
7649 624411d2 2023-07-08 jrick return NULL;
7650 624411d2 2023-07-08 jrick if (status == staged_status && (status == GOT_STATUS_DELETE))
7651 624411d2 2023-07-08 jrick status = GOT_STATUS_NO_CHANGE;
7652 624411d2 2023-07-08 jrick printf("%c%c %s\n", status, staged_status, path);
7653 624411d2 2023-07-08 jrick return NULL;
7656 624411d2 2023-07-08 jrick static const struct got_error *
7657 624411d2 2023-07-08 jrick cmd_remove(int argc, char *argv[])
7659 624411d2 2023-07-08 jrick const struct got_error *error = NULL;
7660 624411d2 2023-07-08 jrick struct got_worktree *worktree = NULL;
7661 624411d2 2023-07-08 jrick struct got_repository *repo = NULL;
7662 624411d2 2023-07-08 jrick const char *status_codes = NULL;
7663 624411d2 2023-07-08 jrick char *cwd = NULL;
7664 624411d2 2023-07-08 jrick struct got_pathlist_head paths;
7665 624411d2 2023-07-08 jrick struct got_pathlist_entry *pe;
7666 624411d2 2023-07-08 jrick int ch, delete_local_mods = 0, can_recurse = 0, keep_on_disk = 0, i;
7667 624411d2 2023-07-08 jrick int ignore_missing_paths = 0;
7668 624411d2 2023-07-08 jrick int *pack_fds = NULL;
7670 624411d2 2023-07-08 jrick TAILQ_INIT(&paths);
7672 624411d2 2023-07-08 jrick #ifndef PROFILE
7673 624411d2 2023-07-08 jrick if (pledge("stdio rpath wpath cpath flock proc exec sendfd unveil",
7674 624411d2 2023-07-08 jrick NULL) == -1)
7675 624411d2 2023-07-08 jrick err(1, "pledge");
7678 624411d2 2023-07-08 jrick while ((ch = getopt(argc, argv, "fkRs:")) != -1) {
7679 624411d2 2023-07-08 jrick switch (ch) {
7680 624411d2 2023-07-08 jrick case 'f':
7681 624411d2 2023-07-08 jrick delete_local_mods = 1;
7682 624411d2 2023-07-08 jrick ignore_missing_paths = 1;
7684 624411d2 2023-07-08 jrick case 'k':
7685 624411d2 2023-07-08 jrick keep_on_disk = 1;
7687 624411d2 2023-07-08 jrick case 'R':
7688 624411d2 2023-07-08 jrick can_recurse = 1;
7690 624411d2 2023-07-08 jrick case 's':
7691 624411d2 2023-07-08 jrick for (i = 0; optarg[i] != '\0'; i++) {
7692 624411d2 2023-07-08 jrick switch (optarg[i]) {
7693 624411d2 2023-07-08 jrick case GOT_STATUS_MODIFY:
7694 624411d2 2023-07-08 jrick delete_local_mods = 1;
7696 624411d2 2023-07-08 jrick case GOT_STATUS_MISSING:
7697 624411d2 2023-07-08 jrick ignore_missing_paths = 1;
7700 624411d2 2023-07-08 jrick errx(1, "invalid status code '%c'",
7701 624411d2 2023-07-08 jrick optarg[i]);
7704 624411d2 2023-07-08 jrick status_codes = optarg;
7707 624411d2 2023-07-08 jrick usage_remove();
7708 624411d2 2023-07-08 jrick /* NOTREACHED */
7712 624411d2 2023-07-08 jrick argc -= optind;
7713 624411d2 2023-07-08 jrick argv += optind;
7715 624411d2 2023-07-08 jrick if (argc < 1)
7716 624411d2 2023-07-08 jrick usage_remove();
7718 624411d2 2023-07-08 jrick cwd = getcwd(NULL, 0);
7719 624411d2 2023-07-08 jrick if (cwd == NULL) {
7720 624411d2 2023-07-08 jrick error = got_error_from_errno("getcwd");
7721 624411d2 2023-07-08 jrick goto done;
7724 624411d2 2023-07-08 jrick error = got_repo_pack_fds_open(&pack_fds);
7725 624411d2 2023-07-08 jrick if (error != NULL)
7726 624411d2 2023-07-08 jrick goto done;
7728 624411d2 2023-07-08 jrick error = got_worktree_open(&worktree, cwd);
7729 624411d2 2023-07-08 jrick if (error) {
7730 624411d2 2023-07-08 jrick if (error->code == GOT_ERR_NOT_WORKTREE)
7731 624411d2 2023-07-08 jrick error = wrap_not_worktree_error(error, "remove", cwd);
7732 624411d2 2023-07-08 jrick goto done;
7735 624411d2 2023-07-08 jrick error = got_repo_open(&repo, got_worktree_get_repo_path(worktree),
7736 624411d2 2023-07-08 jrick NULL, pack_fds);
7737 624411d2 2023-07-08 jrick if (error)
7738 624411d2 2023-07-08 jrick goto done;
7740 624411d2 2023-07-08 jrick error = apply_unveil(got_repo_get_path(repo), 1,
7741 624411d2 2023-07-08 jrick got_worktree_get_root_path(worktree));
7742 624411d2 2023-07-08 jrick if (error)
7743 624411d2 2023-07-08 jrick goto done;
7745 624411d2 2023-07-08 jrick error = get_worktree_paths_from_argv(&paths, argc, argv, worktree);
7746 624411d2 2023-07-08 jrick if (error)
7747 624411d2 2023-07-08 jrick goto done;
7749 624411d2 2023-07-08 jrick if (!can_recurse) {
7750 624411d2 2023-07-08 jrick char *ondisk_path;
7751 624411d2 2023-07-08 jrick struct stat sb;
7752 624411d2 2023-07-08 jrick TAILQ_FOREACH(pe, &paths, entry) {
7753 624411d2 2023-07-08 jrick if (asprintf(&ondisk_path, "%s/%s",
7754 624411d2 2023-07-08 jrick got_worktree_get_root_path(worktree),
7755 624411d2 2023-07-08 jrick pe->path) == -1) {
7756 624411d2 2023-07-08 jrick error = got_error_from_errno("asprintf");
7757 624411d2 2023-07-08 jrick goto done;
7759 624411d2 2023-07-08 jrick if (lstat(ondisk_path, &sb) == -1) {
7760 624411d2 2023-07-08 jrick if (errno == ENOENT) {
7761 624411d2 2023-07-08 jrick free(ondisk_path);
7762 624411d2 2023-07-08 jrick continue;
7764 624411d2 2023-07-08 jrick error = got_error_from_errno2("lstat",
7765 624411d2 2023-07-08 jrick ondisk_path);
7766 624411d2 2023-07-08 jrick free(ondisk_path);
7767 624411d2 2023-07-08 jrick goto done;
7769 624411d2 2023-07-08 jrick free(ondisk_path);
7770 624411d2 2023-07-08 jrick if (S_ISDIR(sb.st_mode)) {
7771 624411d2 2023-07-08 jrick error = got_error_msg(GOT_ERR_BAD_PATH,
7772 624411d2 2023-07-08 jrick "removing directories requires -R option");
7773 624411d2 2023-07-08 jrick goto done;
7778 624411d2 2023-07-08 jrick error = got_worktree_schedule_delete(worktree, &paths,
7779 624411d2 2023-07-08 jrick delete_local_mods, status_codes, print_remove_status, NULL,
7780 624411d2 2023-07-08 jrick repo, keep_on_disk, ignore_missing_paths);
7782 624411d2 2023-07-08 jrick if (repo) {
7783 624411d2 2023-07-08 jrick const struct got_error *close_err = got_repo_close(repo);
7784 624411d2 2023-07-08 jrick if (error == NULL)
7785 624411d2 2023-07-08 jrick error = close_err;
7787 624411d2 2023-07-08 jrick if (worktree)
7788 624411d2 2023-07-08 jrick got_worktree_close(worktree);
7789 624411d2 2023-07-08 jrick if (pack_fds) {
7790 624411d2 2023-07-08 jrick const struct got_error *pack_err =
7791 624411d2 2023-07-08 jrick got_repo_pack_fds_close(pack_fds);
7792 624411d2 2023-07-08 jrick if (error == NULL)
7793 624411d2 2023-07-08 jrick error = pack_err;
7795 624411d2 2023-07-08 jrick got_pathlist_free(&paths, GOT_PATHLIST_FREE_PATH);
7796 624411d2 2023-07-08 jrick free(cwd);
7797 624411d2 2023-07-08 jrick return error;
7800 624411d2 2023-07-08 jrick __dead static void
7801 624411d2 2023-07-08 jrick usage_patch(void)
7803 624411d2 2023-07-08 jrick fprintf(stderr, "usage: %s patch [-nR] [-c commit] [-p strip-count] "
7804 624411d2 2023-07-08 jrick "[patchfile]\n", getprogname());
7808 624411d2 2023-07-08 jrick static const struct got_error *
7809 624411d2 2023-07-08 jrick patch_from_stdin(int *patchfd)
7811 624411d2 2023-07-08 jrick const struct got_error *err = NULL;
7812 624411d2 2023-07-08 jrick ssize_t r;
7813 624411d2 2023-07-08 jrick char buf[BUFSIZ];
7814 624411d2 2023-07-08 jrick sig_t sighup, sigint, sigquit;
7816 624411d2 2023-07-08 jrick *patchfd = got_opentempfd();
7817 624411d2 2023-07-08 jrick if (*patchfd == -1)
7818 624411d2 2023-07-08 jrick return got_error_from_errno("got_opentempfd");
7820 624411d2 2023-07-08 jrick sighup = signal(SIGHUP, SIG_DFL);
7821 624411d2 2023-07-08 jrick sigint = signal(SIGINT, SIG_DFL);
7822 624411d2 2023-07-08 jrick sigquit = signal(SIGQUIT, SIG_DFL);
7824 624411d2 2023-07-08 jrick for (;;) {
7825 624411d2 2023-07-08 jrick r = read(0, buf, sizeof(buf));
7826 624411d2 2023-07-08 jrick if (r == -1) {
7827 624411d2 2023-07-08 jrick err = got_error_from_errno("read");
7830 624411d2 2023-07-08 jrick if (r == 0)
7832 624411d2 2023-07-08 jrick if (write(*patchfd, buf, r) == -1) {
7833 624411d2 2023-07-08 jrick err = got_error_from_errno("write");
7838 624411d2 2023-07-08 jrick signal(SIGHUP, sighup);
7839 624411d2 2023-07-08 jrick signal(SIGINT, sigint);
7840 624411d2 2023-07-08 jrick signal(SIGQUIT, sigquit);
7842 624411d2 2023-07-08 jrick if (err == NULL && lseek(*patchfd, 0, SEEK_SET) == -1)
7843 624411d2 2023-07-08 jrick err = got_error_from_errno("lseek");
7845 624411d2 2023-07-08 jrick if (err != NULL) {
7846 624411d2 2023-07-08 jrick close(*patchfd);
7847 624411d2 2023-07-08 jrick *patchfd = -1;
7850 624411d2 2023-07-08 jrick return err;
7853 624411d2 2023-07-08 jrick struct got_patch_progress_arg {
7854 624411d2 2023-07-08 jrick int did_something;
7855 624411d2 2023-07-08 jrick int conflicts;
7856 624411d2 2023-07-08 jrick int rejects;
7859 624411d2 2023-07-08 jrick static const struct got_error *
7860 624411d2 2023-07-08 jrick patch_progress(void *arg, const char *old, const char *new,
7861 624411d2 2023-07-08 jrick unsigned char status, const struct got_error *error, int old_from,
7862 624411d2 2023-07-08 jrick int old_lines, int new_from, int new_lines, int offset,
7863 624411d2 2023-07-08 jrick int ws_mangled, const struct got_error *hunk_err)
7865 624411d2 2023-07-08 jrick const char *path = new == NULL ? old : new;
7866 624411d2 2023-07-08 jrick struct got_patch_progress_arg *a = arg;
7868 624411d2 2023-07-08 jrick while (*path == '/')
7871 624411d2 2023-07-08 jrick if (status != GOT_STATUS_NO_CHANGE &&
7872 624411d2 2023-07-08 jrick status != 0 /* per-hunk progress */) {
7873 624411d2 2023-07-08 jrick printf("%c %s\n", status, path);
7874 624411d2 2023-07-08 jrick a->did_something = 1;
7877 624411d2 2023-07-08 jrick if (hunk_err == NULL) {
7878 624411d2 2023-07-08 jrick if (status == GOT_STATUS_CANNOT_UPDATE)
7879 624411d2 2023-07-08 jrick a->rejects++;
7880 624411d2 2023-07-08 jrick else if (status == GOT_STATUS_CONFLICT)
7881 624411d2 2023-07-08 jrick a->conflicts++;
7884 624411d2 2023-07-08 jrick if (error != NULL)
7885 624411d2 2023-07-08 jrick fprintf(stderr, "%s: %s\n", getprogname(), error->msg);
7887 624411d2 2023-07-08 jrick if (offset != 0 || hunk_err != NULL || ws_mangled) {
7888 624411d2 2023-07-08 jrick printf("@@ -%d,%d +%d,%d @@ ", old_from,
7889 624411d2 2023-07-08 jrick old_lines, new_from, new_lines);
7890 624411d2 2023-07-08 jrick if (hunk_err != NULL)
7891 624411d2 2023-07-08 jrick printf("%s\n", hunk_err->msg);
7892 624411d2 2023-07-08 jrick else if (offset != 0)
7893 624411d2 2023-07-08 jrick printf("applied with offset %d\n", offset);
7895 624411d2 2023-07-08 jrick printf("hunk contains mangled whitespace\n");
7898 624411d2 2023-07-08 jrick return NULL;
7901 624411d2 2023-07-08 jrick static void
7902 624411d2 2023-07-08 jrick print_patch_progress_stats(struct got_patch_progress_arg *ppa)
7904 624411d2 2023-07-08 jrick if (!ppa->did_something)
7907 624411d2 2023-07-08 jrick if (ppa->conflicts > 0)
7908 624411d2 2023-07-08 jrick printf("Files with merge conflicts: %d\n", ppa->conflicts);
7910 624411d2 2023-07-08 jrick if (ppa->rejects > 0) {
7911 624411d2 2023-07-08 jrick printf("Files where patch failed to apply: %d\n",
7912 624411d2 2023-07-08 jrick ppa->rejects);
7916 624411d2 2023-07-08 jrick static const struct got_error *
7917 624411d2 2023-07-08 jrick cmd_patch(int argc, char *argv[])
7919 624411d2 2023-07-08 jrick const struct got_error *error = NULL, *close_error = NULL;
7920 624411d2 2023-07-08 jrick struct got_worktree *worktree = NULL;
7921 624411d2 2023-07-08 jrick struct got_repository *repo = NULL;
7922 624411d2 2023-07-08 jrick struct got_reflist_head refs;
7923 624411d2 2023-07-08 jrick struct got_object_id *commit_id = NULL;
7924 624411d2 2023-07-08 jrick const char *commit_id_str = NULL;
7925 624411d2 2023-07-08 jrick struct stat sb;
7926 624411d2 2023-07-08 jrick const char *errstr;
7927 624411d2 2023-07-08 jrick char *cwd = NULL;
7928 624411d2 2023-07-08 jrick int ch, nop = 0, strip = -1, reverse = 0;
7929 624411d2 2023-07-08 jrick int patchfd;
7930 624411d2 2023-07-08 jrick int *pack_fds = NULL;
7931 624411d2 2023-07-08 jrick struct got_patch_progress_arg ppa;
7933 624411d2 2023-07-08 jrick TAILQ_INIT(&refs);
7935 624411d2 2023-07-08 jrick #ifndef PROFILE
7936 624411d2 2023-07-08 jrick if (pledge("stdio rpath wpath cpath fattr proc exec sendfd flock "
7937 624411d2 2023-07-08 jrick "unveil", NULL) == -1)
7938 624411d2 2023-07-08 jrick err(1, "pledge");
7941 624411d2 2023-07-08 jrick while ((ch = getopt(argc, argv, "c:np:R")) != -1) {
7942 624411d2 2023-07-08 jrick switch (ch) {
7943 624411d2 2023-07-08 jrick case 'c':
7944 624411d2 2023-07-08 jrick commit_id_str = optarg;
7946 624411d2 2023-07-08 jrick case 'n':
7949 624411d2 2023-07-08 jrick case 'p':
7950 624411d2 2023-07-08 jrick strip = strtonum(optarg, 0, INT_MAX, &errstr);
7951 624411d2 2023-07-08 jrick if (errstr != NULL)
7952 624411d2 2023-07-08 jrick errx(1, "pathname strip count is %s: %s",
7953 624411d2 2023-07-08 jrick errstr, optarg);
7955 624411d2 2023-07-08 jrick case 'R':
7956 624411d2 2023-07-08 jrick reverse = 1;
7959 624411d2 2023-07-08 jrick usage_patch();
7960 624411d2 2023-07-08 jrick /* NOTREACHED */
7964 624411d2 2023-07-08 jrick argc -= optind;
7965 624411d2 2023-07-08 jrick argv += optind;
7967 624411d2 2023-07-08 jrick if (argc == 0) {
7968 624411d2 2023-07-08 jrick error = patch_from_stdin(&patchfd);
7969 624411d2 2023-07-08 jrick if (error)
7970 624411d2 2023-07-08 jrick return error;
7971 624411d2 2023-07-08 jrick } else if (argc == 1) {
7972 624411d2 2023-07-08 jrick patchfd = open(argv[0], O_RDONLY);
7973 624411d2 2023-07-08 jrick if (patchfd == -1) {
7974 624411d2 2023-07-08 jrick error = got_error_from_errno2("open", argv[0]);
7975 624411d2 2023-07-08 jrick return error;
7977 624411d2 2023-07-08 jrick if (fstat(patchfd, &sb) == -1) {
7978 624411d2 2023-07-08 jrick error = got_error_from_errno2("fstat", argv[0]);
7979 624411d2 2023-07-08 jrick goto done;
7981 624411d2 2023-07-08 jrick if (!S_ISREG(sb.st_mode)) {
7982 624411d2 2023-07-08 jrick error = got_error_path(argv[0], GOT_ERR_BAD_FILETYPE);
7983 624411d2 2023-07-08 jrick goto done;
7986 624411d2 2023-07-08 jrick usage_patch();
7988 624411d2 2023-07-08 jrick if ((cwd = getcwd(NULL, 0)) == NULL) {
7989 624411d2 2023-07-08 jrick error = got_error_from_errno("getcwd");
7990 624411d2 2023-07-08 jrick goto done;
7993 624411d2 2023-07-08 jrick error = got_repo_pack_fds_open(&pack_fds);
7994 624411d2 2023-07-08 jrick if (error != NULL)
7995 624411d2 2023-07-08 jrick goto done;
7997 624411d2 2023-07-08 jrick error = got_worktree_open(&worktree, cwd);
7998 624411d2 2023-07-08 jrick if (error != NULL)
7999 624411d2 2023-07-08 jrick goto done;
8001 624411d2 2023-07-08 jrick const char *repo_path = got_worktree_get_repo_path(worktree);
8002 624411d2 2023-07-08 jrick error = got_repo_open(&repo, repo_path, NULL, pack_fds);
8003 624411d2 2023-07-08 jrick if (error != NULL)
8004 624411d2 2023-07-08 jrick goto done;
8006 624411d2 2023-07-08 jrick error = apply_unveil(got_repo_get_path(repo), 0,
8007 624411d2 2023-07-08 jrick got_worktree_get_root_path(worktree));
8008 624411d2 2023-07-08 jrick if (error != NULL)
8009 624411d2 2023-07-08 jrick goto done;
8011 624411d2 2023-07-08 jrick error = got_ref_list(&refs, repo, NULL, got_ref_cmp_by_name, NULL);
8012 624411d2 2023-07-08 jrick if (error)
8013 624411d2 2023-07-08 jrick goto done;
8015 624411d2 2023-07-08 jrick if (commit_id_str != NULL) {
8016 624411d2 2023-07-08 jrick error = got_repo_match_object_id(&commit_id, NULL,
8017 624411d2 2023-07-08 jrick commit_id_str, GOT_OBJ_TYPE_COMMIT, &refs, repo);
8018 624411d2 2023-07-08 jrick if (error)
8019 624411d2 2023-07-08 jrick goto done;
8022 624411d2 2023-07-08 jrick memset(&ppa, 0, sizeof(ppa));
8023 624411d2 2023-07-08 jrick error = got_patch(patchfd, worktree, repo, nop, strip, reverse,
8024 624411d2 2023-07-08 jrick commit_id, patch_progress, &ppa, check_cancelled, NULL);
8025 624411d2 2023-07-08 jrick print_patch_progress_stats(&ppa);
8027 624411d2 2023-07-08 jrick got_ref_list_free(&refs);
8028 624411d2 2023-07-08 jrick free(commit_id);
8029 624411d2 2023-07-08 jrick if (repo) {
8030 624411d2 2023-07-08 jrick close_error = got_repo_close(repo);
8031 624411d2 2023-07-08 jrick if (error == NULL)
8032 624411d2 2023-07-08 jrick error = close_error;
8034 624411d2 2023-07-08 jrick if (worktree != NULL) {
8035 624411d2 2023-07-08 jrick close_error = got_worktree_close(worktree);
8036 624411d2 2023-07-08 jrick if (error == NULL)
8037 624411d2 2023-07-08 jrick error = close_error;
8039 624411d2 2023-07-08 jrick if (pack_fds) {
8040 624411d2 2023-07-08 jrick const struct got_error *pack_err =
8041 624411d2 2023-07-08 jrick got_repo_pack_fds_close(pack_fds);
8042 624411d2 2023-07-08 jrick if (error == NULL)
8043 624411d2 2023-07-08 jrick error = pack_err;
8045 624411d2 2023-07-08 jrick free(cwd);
8046 624411d2 2023-07-08 jrick return error;
8049 624411d2 2023-07-08 jrick __dead static void
8050 624411d2 2023-07-08 jrick usage_revert(void)
8052 624411d2 2023-07-08 jrick fprintf(stderr, "usage: %s revert [-pR] [-F response-script] path ...\n",
8053 624411d2 2023-07-08 jrick getprogname());
8057 624411d2 2023-07-08 jrick static const struct got_error *
8058 624411d2 2023-07-08 jrick revert_progress(void *arg, unsigned char status, const char *path)
8060 624411d2 2023-07-08 jrick if (status == GOT_STATUS_UNVERSIONED)
8061 624411d2 2023-07-08 jrick return NULL;
8063 624411d2 2023-07-08 jrick while (path[0] == '/')
8065 624411d2 2023-07-08 jrick printf("%c %s\n", status, path);
8066 624411d2 2023-07-08 jrick return NULL;
8069 624411d2 2023-07-08 jrick struct choose_patch_arg {
8070 624411d2 2023-07-08 jrick FILE *patch_script_file;
8071 624411d2 2023-07-08 jrick const char *action;
8074 624411d2 2023-07-08 jrick static const struct got_error *
8075 624411d2 2023-07-08 jrick show_change(unsigned char status, const char *path, FILE *patch_file, int n,
8076 624411d2 2023-07-08 jrick int nchanges, const char *action)
8078 624411d2 2023-07-08 jrick const struct got_error *err;
8079 624411d2 2023-07-08 jrick char *line = NULL;
8080 624411d2 2023-07-08 jrick size_t linesize = 0;
8081 624411d2 2023-07-08 jrick ssize_t linelen;
8083 624411d2 2023-07-08 jrick switch (status) {
8084 624411d2 2023-07-08 jrick case GOT_STATUS_ADD:
8085 624411d2 2023-07-08 jrick printf("A %s\n%s this addition? [y/n] ", path, action);
8087 624411d2 2023-07-08 jrick case GOT_STATUS_DELETE:
8088 624411d2 2023-07-08 jrick printf("D %s\n%s this deletion? [y/n] ", path, action);
8090 624411d2 2023-07-08 jrick case GOT_STATUS_MODIFY:
8091 624411d2 2023-07-08 jrick if (fseek(patch_file, 0L, SEEK_SET) == -1)
8092 624411d2 2023-07-08 jrick return got_error_from_errno("fseek");
8093 624411d2 2023-07-08 jrick printf(GOT_COMMIT_SEP_STR);
8094 624411d2 2023-07-08 jrick while ((linelen = getline(&line, &linesize, patch_file)) != -1)
8095 624411d2 2023-07-08 jrick printf("%s", line);
8096 624411d2 2023-07-08 jrick if (linelen == -1 && ferror(patch_file)) {
8097 624411d2 2023-07-08 jrick err = got_error_from_errno("getline");
8098 624411d2 2023-07-08 jrick free(line);
8099 624411d2 2023-07-08 jrick return err;
8101 624411d2 2023-07-08 jrick free(line);
8102 624411d2 2023-07-08 jrick printf(GOT_COMMIT_SEP_STR);
8103 624411d2 2023-07-08 jrick printf("M %s (change %d of %d)\n%s this change? [y/n/q] ",
8104 624411d2 2023-07-08 jrick path, n, nchanges, action);
8107 624411d2 2023-07-08 jrick return got_error_path(path, GOT_ERR_FILE_STATUS);
8110 624411d2 2023-07-08 jrick fflush(stdout);
8111 624411d2 2023-07-08 jrick return NULL;
8114 624411d2 2023-07-08 jrick static const struct got_error *
8115 624411d2 2023-07-08 jrick choose_patch(int *choice, void *arg, unsigned char status, const char *path,
8116 624411d2 2023-07-08 jrick FILE *patch_file, int n, int nchanges)
8118 624411d2 2023-07-08 jrick const struct got_error *err = NULL;
8119 624411d2 2023-07-08 jrick char *line = NULL;
8120 624411d2 2023-07-08 jrick size_t linesize = 0;
8121 624411d2 2023-07-08 jrick ssize_t linelen;
8122 624411d2 2023-07-08 jrick int resp = ' ';
8123 624411d2 2023-07-08 jrick struct choose_patch_arg *a = arg;
8125 624411d2 2023-07-08 jrick *choice = GOT_PATCH_CHOICE_NONE;
8127 624411d2 2023-07-08 jrick if (a->patch_script_file) {
8128 624411d2 2023-07-08 jrick char *nl;
8129 624411d2 2023-07-08 jrick err = show_change(status, path, patch_file, n, nchanges,
8130 624411d2 2023-07-08 jrick a->action);
8132 624411d2 2023-07-08 jrick return err;
8133 624411d2 2023-07-08 jrick linelen = getline(&line, &linesize, a->patch_script_file);
8134 624411d2 2023-07-08 jrick if (linelen == -1) {
8135 624411d2 2023-07-08 jrick if (ferror(a->patch_script_file))
8136 624411d2 2023-07-08 jrick return got_error_from_errno("getline");
8137 624411d2 2023-07-08 jrick return NULL;
8139 624411d2 2023-07-08 jrick nl = strchr(line, '\n');
8141 624411d2 2023-07-08 jrick *nl = '\0';
8142 624411d2 2023-07-08 jrick if (strcmp(line, "y") == 0) {
8143 624411d2 2023-07-08 jrick *choice = GOT_PATCH_CHOICE_YES;
8144 624411d2 2023-07-08 jrick printf("y\n");
8145 624411d2 2023-07-08 jrick } else if (strcmp(line, "n") == 0) {
8146 624411d2 2023-07-08 jrick *choice = GOT_PATCH_CHOICE_NO;
8147 624411d2 2023-07-08 jrick printf("n\n");
8148 624411d2 2023-07-08 jrick } else if (strcmp(line, "q") == 0 &&
8149 624411d2 2023-07-08 jrick status == GOT_STATUS_MODIFY) {
8150 624411d2 2023-07-08 jrick *choice = GOT_PATCH_CHOICE_QUIT;
8151 624411d2 2023-07-08 jrick printf("q\n");
8153 624411d2 2023-07-08 jrick printf("invalid response '%s'\n", line);
8154 624411d2 2023-07-08 jrick free(line);
8155 624411d2 2023-07-08 jrick return NULL;
8158 624411d2 2023-07-08 jrick while (resp != 'y' && resp != 'n' && resp != 'q') {
8159 624411d2 2023-07-08 jrick err = show_change(status, path, patch_file, n, nchanges,
8160 624411d2 2023-07-08 jrick a->action);
8162 624411d2 2023-07-08 jrick return err;
8163 624411d2 2023-07-08 jrick resp = getchar();
8164 624411d2 2023-07-08 jrick if (resp == '\n')
8165 624411d2 2023-07-08 jrick resp = getchar();
8166 624411d2 2023-07-08 jrick if (status == GOT_STATUS_MODIFY) {
8167 624411d2 2023-07-08 jrick if (resp != 'y' && resp != 'n' && resp != 'q') {
8168 624411d2 2023-07-08 jrick printf("invalid response '%c'\n", resp);
8169 624411d2 2023-07-08 jrick resp = ' ';
8171 624411d2 2023-07-08 jrick } else if (resp != 'y' && resp != 'n') {
8172 624411d2 2023-07-08 jrick printf("invalid response '%c'\n", resp);
8173 624411d2 2023-07-08 jrick resp = ' ';
8177 624411d2 2023-07-08 jrick if (resp == 'y')
8178 624411d2 2023-07-08 jrick *choice = GOT_PATCH_CHOICE_YES;
8179 624411d2 2023-07-08 jrick else if (resp == 'n')
8180 624411d2 2023-07-08 jrick *choice = GOT_PATCH_CHOICE_NO;
8181 624411d2 2023-07-08 jrick else if (resp == 'q' && status == GOT_STATUS_MODIFY)
8182 624411d2 2023-07-08 jrick *choice = GOT_PATCH_CHOICE_QUIT;
8184 624411d2 2023-07-08 jrick return NULL;
8187 624411d2 2023-07-08 jrick struct wt_commitable_path_arg {
8188 624411d2 2023-07-08 jrick struct got_pathlist_head *commit_paths;
8189 624411d2 2023-07-08 jrick int *has_changes;
8193 624411d2 2023-07-08 jrick * Shortcut work tree status callback to determine if the set of paths scanned
8194 624411d2 2023-07-08 jrick * has at least one versioned path that is being modified and, if not NULL, is
8195 624411d2 2023-07-08 jrick * in the arg->commit_paths list. Set arg and return GOT_ERR_FILE_MODIFIED as
8196 624411d2 2023-07-08 jrick * soon as a path is passed with a status that satisfies this criteria.
8198 624411d2 2023-07-08 jrick static const struct got_error *
8199 624411d2 2023-07-08 jrick worktree_has_commitable_path(void *arg, unsigned char status,
8200 624411d2 2023-07-08 jrick unsigned char staged_status, const char *path,
8201 624411d2 2023-07-08 jrick struct got_object_id *blob_id, struct got_object_id *staged_blob_id,
8202 624411d2 2023-07-08 jrick struct got_object_id *commit_id, int dirfd, const char *de_name)
8204 624411d2 2023-07-08 jrick struct wt_commitable_path_arg *a = arg;
8206 624411d2 2023-07-08 jrick if (status == staged_status && (status == GOT_STATUS_DELETE))
8207 624411d2 2023-07-08 jrick status = GOT_STATUS_NO_CHANGE;
8209 624411d2 2023-07-08 jrick if (!(status == GOT_STATUS_NO_CHANGE ||
8210 624411d2 2023-07-08 jrick status == GOT_STATUS_UNVERSIONED) ||
8211 624411d2 2023-07-08 jrick staged_status != GOT_STATUS_NO_CHANGE) {
8212 624411d2 2023-07-08 jrick if (a->commit_paths != NULL) {
8213 624411d2 2023-07-08 jrick struct got_pathlist_entry *pe;
8215 624411d2 2023-07-08 jrick TAILQ_FOREACH(pe, a->commit_paths, entry) {
8216 624411d2 2023-07-08 jrick if (strncmp(path, pe->path,
8217 624411d2 2023-07-08 jrick pe->path_len) == 0) {
8218 624411d2 2023-07-08 jrick *a->has_changes = 1;
8223 624411d2 2023-07-08 jrick *a->has_changes = 1;
8225 624411d2 2023-07-08 jrick if (*a->has_changes)
8226 624411d2 2023-07-08 jrick return got_error(GOT_ERR_FILE_MODIFIED);
8229 624411d2 2023-07-08 jrick return NULL;
8233 624411d2 2023-07-08 jrick * Check that the changeset of the commit identified by id is
8234 624411d2 2023-07-08 jrick * comprised of at least one modified path that is being committed.
8236 624411d2 2023-07-08 jrick static const struct got_error *
8237 624411d2 2023-07-08 jrick commit_path_changed_in_worktree(struct wt_commitable_path_arg *wcpa,
8238 624411d2 2023-07-08 jrick struct got_object_id *id, struct got_worktree *worktree,
8239 624411d2 2023-07-08 jrick struct got_repository *repo)
8241 624411d2 2023-07-08 jrick const struct got_error *err;
8242 624411d2 2023-07-08 jrick struct got_pathlist_head paths;
8243 624411d2 2023-07-08 jrick struct got_commit_object *commit = NULL, *pcommit = NULL;
8244 624411d2 2023-07-08 jrick struct got_tree_object *tree = NULL, *ptree = NULL;
8245 624411d2 2023-07-08 jrick struct got_object_qid *pid;
8247 624411d2 2023-07-08 jrick TAILQ_INIT(&paths);
8249 624411d2 2023-07-08 jrick err = got_object_open_as_commit(&commit, repo, id);
8251 624411d2 2023-07-08 jrick goto done;
8253 624411d2 2023-07-08 jrick err = got_object_open_as_tree(&tree, repo,
8254 624411d2 2023-07-08 jrick got_object_commit_get_tree_id(commit));
8256 624411d2 2023-07-08 jrick goto done;
8258 624411d2 2023-07-08 jrick pid = STAILQ_FIRST(got_object_commit_get_parent_ids(commit));
8259 624411d2 2023-07-08 jrick if (pid != NULL) {
8260 624411d2 2023-07-08 jrick err = got_object_open_as_commit(&pcommit, repo, &pid->id);
8262 624411d2 2023-07-08 jrick goto done;
8264 624411d2 2023-07-08 jrick err = got_object_open_as_tree(&ptree, repo,
8265 624411d2 2023-07-08 jrick got_object_commit_get_tree_id(pcommit));
8267 624411d2 2023-07-08 jrick goto done;
8270 624411d2 2023-07-08 jrick err = got_diff_tree(ptree, tree, NULL, NULL, -1, -1, "", "", repo,
8271 624411d2 2023-07-08 jrick got_diff_tree_collect_changed_paths, &paths, 0);
8273 624411d2 2023-07-08 jrick goto done;
8275 624411d2 2023-07-08 jrick err = got_worktree_status(worktree, &paths, repo, 0,
8276 624411d2 2023-07-08 jrick worktree_has_commitable_path, wcpa, check_cancelled, NULL);
8277 624411d2 2023-07-08 jrick if (err && err->code == GOT_ERR_FILE_MODIFIED) {
8279 624411d2 2023-07-08 jrick * At least one changed path in the referenced commit is
8280 624411d2 2023-07-08 jrick * modified in the work tree, that's all we need to know!
8282 624411d2 2023-07-08 jrick err = NULL;
8286 624411d2 2023-07-08 jrick got_pathlist_free(&paths, GOT_PATHLIST_FREE_ALL);
8287 624411d2 2023-07-08 jrick if (commit)
8288 624411d2 2023-07-08 jrick got_object_commit_close(commit);
8289 624411d2 2023-07-08 jrick if (pcommit)
8290 624411d2 2023-07-08 jrick got_object_commit_close(pcommit);
8291 624411d2 2023-07-08 jrick if (tree)
8292 624411d2 2023-07-08 jrick got_object_tree_close(tree);
8293 624411d2 2023-07-08 jrick if (ptree)
8294 624411d2 2023-07-08 jrick got_object_tree_close(ptree);
8295 624411d2 2023-07-08 jrick return err;
8299 624411d2 2023-07-08 jrick * Remove any "logmsg" reference comprised entirely of paths that have
8300 624411d2 2023-07-08 jrick * been reverted in this work tree. If any path in the logmsg ref changeset
8301 624411d2 2023-07-08 jrick * remains in a changed state in the worktree, do not remove the reference.
8303 624411d2 2023-07-08 jrick static const struct got_error *
8304 624411d2 2023-07-08 jrick rm_logmsg_ref(struct got_worktree *worktree, struct got_repository *repo)
8306 624411d2 2023-07-08 jrick const struct got_error *err;
8307 624411d2 2023-07-08 jrick struct got_reflist_head refs;
8308 624411d2 2023-07-08 jrick struct got_reflist_entry *re;
8309 624411d2 2023-07-08 jrick struct got_commit_object *commit = NULL;
8310 624411d2 2023-07-08 jrick struct got_object_id *commit_id = NULL;
8311 624411d2 2023-07-08 jrick struct wt_commitable_path_arg wcpa;
8312 624411d2 2023-07-08 jrick char *uuidstr = NULL;
8314 624411d2 2023-07-08 jrick TAILQ_INIT(&refs);
8316 624411d2 2023-07-08 jrick err = got_worktree_get_uuid(&uuidstr, worktree);
8318 624411d2 2023-07-08 jrick goto done;
8320 624411d2 2023-07-08 jrick err = got_ref_list(&refs, repo, "refs/got/worktree",
8321 624411d2 2023-07-08 jrick got_ref_cmp_by_name, repo);
8323 624411d2 2023-07-08 jrick goto done;
8325 624411d2 2023-07-08 jrick TAILQ_FOREACH(re, &refs, entry) {
8326 624411d2 2023-07-08 jrick const char *refname;
8327 624411d2 2023-07-08 jrick int has_changes = 0;
8329 624411d2 2023-07-08 jrick refname = got_ref_get_name(re->ref);
8331 624411d2 2023-07-08 jrick if (!strncmp(refname, GOT_WORKTREE_CHERRYPICK_REF_PREFIX,
8332 624411d2 2023-07-08 jrick GOT_WORKTREE_CHERRYPICK_REF_PREFIX_LEN))
8333 624411d2 2023-07-08 jrick refname += GOT_WORKTREE_CHERRYPICK_REF_PREFIX_LEN + 1;
8334 624411d2 2023-07-08 jrick else if (!strncmp(refname, GOT_WORKTREE_BACKOUT_REF_PREFIX,
8335 624411d2 2023-07-08 jrick GOT_WORKTREE_BACKOUT_REF_PREFIX_LEN))
8336 624411d2 2023-07-08 jrick refname += GOT_WORKTREE_BACKOUT_REF_PREFIX_LEN + 1;
8338 624411d2 2023-07-08 jrick continue;
8340 624411d2 2023-07-08 jrick if (strncmp(refname, uuidstr, GOT_WORKTREE_UUID_STRLEN) == 0)
8341 624411d2 2023-07-08 jrick refname += GOT_WORKTREE_UUID_STRLEN + 1; /* skip '-' */
8343 624411d2 2023-07-08 jrick continue;
8345 624411d2 2023-07-08 jrick err = got_repo_match_object_id(&commit_id, NULL, refname,
8346 624411d2 2023-07-08 jrick GOT_OBJ_TYPE_COMMIT, NULL, repo);
8348 624411d2 2023-07-08 jrick goto done;
8350 624411d2 2023-07-08 jrick err = got_object_open_as_commit(&commit, repo, commit_id);
8352 624411d2 2023-07-08 jrick goto done;
8354 624411d2 2023-07-08 jrick wcpa.commit_paths = NULL;
8355 624411d2 2023-07-08 jrick wcpa.has_changes = &has_changes;
8357 624411d2 2023-07-08 jrick err = commit_path_changed_in_worktree(&wcpa, commit_id,
8358 624411d2 2023-07-08 jrick worktree, repo);
8360 624411d2 2023-07-08 jrick goto done;
8362 624411d2 2023-07-08 jrick if (!has_changes) {
8363 624411d2 2023-07-08 jrick err = got_ref_delete(re->ref, repo);
8365 624411d2 2023-07-08 jrick goto done;
8368 624411d2 2023-07-08 jrick got_object_commit_close(commit);
8369 624411d2 2023-07-08 jrick commit = NULL;
8370 624411d2 2023-07-08 jrick free(commit_id);
8371 624411d2 2023-07-08 jrick commit_id = NULL;
8375 624411d2 2023-07-08 jrick free(uuidstr);
8376 624411d2 2023-07-08 jrick free(commit_id);
8377 624411d2 2023-07-08 jrick got_ref_list_free(&refs);
8378 624411d2 2023-07-08 jrick if (commit)
8379 624411d2 2023-07-08 jrick got_object_commit_close(commit);
8380 624411d2 2023-07-08 jrick return err;
8383 624411d2 2023-07-08 jrick static const struct got_error *
8384 624411d2 2023-07-08 jrick cmd_revert(int argc, char *argv[])
8386 624411d2 2023-07-08 jrick const struct got_error *error = NULL;
8387 624411d2 2023-07-08 jrick struct got_worktree *worktree = NULL;
8388 624411d2 2023-07-08 jrick struct got_repository *repo = NULL;
8389 624411d2 2023-07-08 jrick char *cwd = NULL, *path = NULL;
8390 624411d2 2023-07-08 jrick struct got_pathlist_head paths;
8391 624411d2 2023-07-08 jrick struct got_pathlist_entry *pe;
8392 624411d2 2023-07-08 jrick int ch, can_recurse = 0, pflag = 0;
8393 624411d2 2023-07-08 jrick FILE *patch_script_file = NULL;
8394 624411d2 2023-07-08 jrick const char *patch_script_path = NULL;
8395 624411d2 2023-07-08 jrick struct choose_patch_arg cpa;
8396 624411d2 2023-07-08 jrick int *pack_fds = NULL;
8398 624411d2 2023-07-08 jrick TAILQ_INIT(&paths);
8400 624411d2 2023-07-08 jrick #ifndef PROFILE
8401 624411d2 2023-07-08 jrick if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd "
8402 624411d2 2023-07-08 jrick "unveil", NULL) == -1)
8403 624411d2 2023-07-08 jrick err(1, "pledge");
8406 624411d2 2023-07-08 jrick while ((ch = getopt(argc, argv, "F:pR")) != -1) {
8407 624411d2 2023-07-08 jrick switch (ch) {
8408 624411d2 2023-07-08 jrick case 'F':
8409 624411d2 2023-07-08 jrick patch_script_path = optarg;
8411 624411d2 2023-07-08 jrick case 'p':
8412 624411d2 2023-07-08 jrick pflag = 1;
8414 624411d2 2023-07-08 jrick case 'R':
8415 624411d2 2023-07-08 jrick can_recurse = 1;
8418 624411d2 2023-07-08 jrick usage_revert();
8419 624411d2 2023-07-08 jrick /* NOTREACHED */
8423 624411d2 2023-07-08 jrick argc -= optind;
8424 624411d2 2023-07-08 jrick argv += optind;
8426 624411d2 2023-07-08 jrick if (argc < 1)
8427 624411d2 2023-07-08 jrick usage_revert();
8428 624411d2 2023-07-08 jrick if (patch_script_path && !pflag)
8429 624411d2 2023-07-08 jrick errx(1, "-F option can only be used together with -p option");
8431 624411d2 2023-07-08 jrick cwd = getcwd(NULL, 0);
8432 624411d2 2023-07-08 jrick if (cwd == NULL) {
8433 624411d2 2023-07-08 jrick error = got_error_from_errno("getcwd");
8434 624411d2 2023-07-08 jrick goto done;
8437 624411d2 2023-07-08 jrick error = got_repo_pack_fds_open(&pack_fds);
8438 624411d2 2023-07-08 jrick if (error != NULL)
8439 624411d2 2023-07-08 jrick goto done;
8441 624411d2 2023-07-08 jrick error = got_worktree_open(&worktree, cwd);
8442 624411d2 2023-07-08 jrick if (error) {
8443 624411d2 2023-07-08 jrick if (error->code == GOT_ERR_NOT_WORKTREE)
8444 624411d2 2023-07-08 jrick error = wrap_not_worktree_error(error, "revert", cwd);
8445 624411d2 2023-07-08 jrick goto done;
8448 624411d2 2023-07-08 jrick error = got_repo_open(&repo, got_worktree_get_repo_path(worktree),
8449 624411d2 2023-07-08 jrick NULL, pack_fds);
8450 624411d2 2023-07-08 jrick if (error != NULL)
8451 624411d2 2023-07-08 jrick goto done;
8453 624411d2 2023-07-08 jrick if (patch_script_path) {
8454 624411d2 2023-07-08 jrick patch_script_file = fopen(patch_script_path, "re");
8455 624411d2 2023-07-08 jrick if (patch_script_file == NULL) {
8456 624411d2 2023-07-08 jrick error = got_error_from_errno2("fopen",
8457 624411d2 2023-07-08 jrick patch_script_path);
8458 624411d2 2023-07-08 jrick goto done;
8463 624411d2 2023-07-08 jrick * XXX "c" perm needed on repo dir to delete merge references.
8465 624411d2 2023-07-08 jrick error = apply_unveil(got_repo_get_path(repo), 0,
8466 624411d2 2023-07-08 jrick got_worktree_get_root_path(worktree));
8467 624411d2 2023-07-08 jrick if (error)
8468 624411d2 2023-07-08 jrick goto done;
8470 624411d2 2023-07-08 jrick error = get_worktree_paths_from_argv(&paths, argc, argv, worktree);
8471 624411d2 2023-07-08 jrick if (error)
8472 624411d2 2023-07-08 jrick goto done;
8474 624411d2 2023-07-08 jrick if (!can_recurse) {
8475 624411d2 2023-07-08 jrick char *ondisk_path;
8476 624411d2 2023-07-08 jrick struct stat sb;
8477 624411d2 2023-07-08 jrick TAILQ_FOREACH(pe, &paths, entry) {
8478 624411d2 2023-07-08 jrick if (asprintf(&ondisk_path, "%s/%s",
8479 624411d2 2023-07-08 jrick got_worktree_get_root_path(worktree),
8480 624411d2 2023-07-08 jrick pe->path) == -1) {
8481 624411d2 2023-07-08 jrick error = got_error_from_errno("asprintf");
8482 624411d2 2023-07-08 jrick goto done;
8484 624411d2 2023-07-08 jrick if (lstat(ondisk_path, &sb) == -1) {
8485 624411d2 2023-07-08 jrick if (errno == ENOENT) {
8486 624411d2 2023-07-08 jrick free(ondisk_path);
8487 624411d2 2023-07-08 jrick continue;
8489 624411d2 2023-07-08 jrick error = got_error_from_errno2("lstat",
8490 624411d2 2023-07-08 jrick ondisk_path);
8491 624411d2 2023-07-08 jrick free(ondisk_path);
8492 624411d2 2023-07-08 jrick goto done;
8494 624411d2 2023-07-08 jrick free(ondisk_path);
8495 624411d2 2023-07-08 jrick if (S_ISDIR(sb.st_mode)) {
8496 624411d2 2023-07-08 jrick error = got_error_msg(GOT_ERR_BAD_PATH,
8497 624411d2 2023-07-08 jrick "reverting directories requires -R option");
8498 624411d2 2023-07-08 jrick goto done;
8503 624411d2 2023-07-08 jrick cpa.patch_script_file = patch_script_file;
8504 624411d2 2023-07-08 jrick cpa.action = "revert";
8505 624411d2 2023-07-08 jrick error = got_worktree_revert(worktree, &paths, revert_progress, NULL,
8506 624411d2 2023-07-08 jrick pflag ? choose_patch : NULL, &cpa, repo);
8508 624411d2 2023-07-08 jrick error = rm_logmsg_ref(worktree, repo);
8510 624411d2 2023-07-08 jrick if (patch_script_file && fclose(patch_script_file) == EOF &&
8511 624411d2 2023-07-08 jrick error == NULL)
8512 624411d2 2023-07-08 jrick error = got_error_from_errno2("fclose", patch_script_path);
8513 624411d2 2023-07-08 jrick if (repo) {
8514 624411d2 2023-07-08 jrick const struct got_error *close_err = got_repo_close(repo);
8515 624411d2 2023-07-08 jrick if (error == NULL)
8516 624411d2 2023-07-08 jrick error = close_err;
8518 624411d2 2023-07-08 jrick if (worktree)
8519 624411d2 2023-07-08 jrick got_worktree_close(worktree);
8520 624411d2 2023-07-08 jrick if (pack_fds) {
8521 624411d2 2023-07-08 jrick const struct got_error *pack_err =
8522 624411d2 2023-07-08 jrick got_repo_pack_fds_close(pack_fds);
8523 624411d2 2023-07-08 jrick if (error == NULL)
8524 624411d2 2023-07-08 jrick error = pack_err;
8526 624411d2 2023-07-08 jrick got_pathlist_free(&paths, GOT_PATHLIST_FREE_PATH);
8527 624411d2 2023-07-08 jrick free(path);
8528 624411d2 2023-07-08 jrick free(cwd);
8529 624411d2 2023-07-08 jrick return error;
8532 624411d2 2023-07-08 jrick __dead static void
8533 624411d2 2023-07-08 jrick usage_commit(void)
8535 624411d2 2023-07-08 jrick fprintf(stderr, "usage: %s commit [-CNnS] [-A author] [-F path] "
8536 624411d2 2023-07-08 jrick "[-m message] [path ...]\n", getprogname());
8540 624411d2 2023-07-08 jrick struct collect_commit_logmsg_arg {
8541 624411d2 2023-07-08 jrick const char *cmdline_log;
8542 624411d2 2023-07-08 jrick const char *prepared_log;
8543 624411d2 2023-07-08 jrick const char *merged_log;
8544 624411d2 2023-07-08 jrick int non_interactive;
8545 624411d2 2023-07-08 jrick const char *editor;
8546 624411d2 2023-07-08 jrick const char *worktree_path;
8547 624411d2 2023-07-08 jrick const char *repo_path;
8548 3d1b16d1 2023-07-08 jrick const char *dial_proto;
8549 624411d2 2023-07-08 jrick char *logmsg_path;
8552 624411d2 2023-07-08 jrick static const struct got_error *
8553 624411d2 2023-07-08 jrick read_prepared_logmsg(char **logmsg, const char *path)
8555 624411d2 2023-07-08 jrick const struct got_error *err = NULL;
8556 624411d2 2023-07-08 jrick FILE *f = NULL;
8557 624411d2 2023-07-08 jrick struct stat sb;
8558 624411d2 2023-07-08 jrick size_t r;
8560 624411d2 2023-07-08 jrick *logmsg = NULL;
8561 624411d2 2023-07-08 jrick memset(&sb, 0, sizeof(sb));
8563 624411d2 2023-07-08 jrick f = fopen(path, "re");
8564 624411d2 2023-07-08 jrick if (f == NULL)
8565 624411d2 2023-07-08 jrick return got_error_from_errno2("fopen", path);
8567 624411d2 2023-07-08 jrick if (fstat(fileno(f), &sb) == -1) {
8568 624411d2 2023-07-08 jrick err = got_error_from_errno2("fstat", path);
8569 624411d2 2023-07-08 jrick goto done;
8571 624411d2 2023-07-08 jrick if (sb.st_size == 0) {
8572 624411d2 2023-07-08 jrick err = got_error(GOT_ERR_COMMIT_MSG_EMPTY);
8573 624411d2 2023-07-08 jrick goto done;
8576 624411d2 2023-07-08 jrick *logmsg = malloc(sb.st_size + 1);
8577 624411d2 2023-07-08 jrick if (*logmsg == NULL) {
8578 624411d2 2023-07-08 jrick err = got_error_from_errno("malloc");
8579 624411d2 2023-07-08 jrick goto done;
8582 624411d2 2023-07-08 jrick r = fread(*logmsg, 1, sb.st_size, f);
8583 624411d2 2023-07-08 jrick if (r != sb.st_size) {
8584 624411d2 2023-07-08 jrick if (ferror(f))
8585 624411d2 2023-07-08 jrick err = got_error_from_errno2("fread", path);
8587 624411d2 2023-07-08 jrick err = got_error(GOT_ERR_IO);
8588 624411d2 2023-07-08 jrick goto done;
8590 624411d2 2023-07-08 jrick (*logmsg)[sb.st_size] = '\0';
8592 624411d2 2023-07-08 jrick if (fclose(f) == EOF && err == NULL)
8593 624411d2 2023-07-08 jrick err = got_error_from_errno2("fclose", path);
8594 624411d2 2023-07-08 jrick if (err) {
8595 624411d2 2023-07-08 jrick free(*logmsg);
8596 624411d2 2023-07-08 jrick *logmsg = NULL;
8598 624411d2 2023-07-08 jrick return err;
8601 624411d2 2023-07-08 jrick static const struct got_error *
8602 624411d2 2023-07-08 jrick collect_commit_logmsg(struct got_pathlist_head *commitable_paths,
8603 624411d2 2023-07-08 jrick const char *diff_path, char **logmsg, void *arg)
8605 624411d2 2023-07-08 jrick char *initial_content = NULL;
8606 624411d2 2023-07-08 jrick struct got_pathlist_entry *pe;
8607 624411d2 2023-07-08 jrick const struct got_error *err = NULL;
8608 624411d2 2023-07-08 jrick char *template = NULL;
8609 624411d2 2023-07-08 jrick char *prepared_msg = NULL, *merged_msg = NULL;
8610 624411d2 2023-07-08 jrick struct collect_commit_logmsg_arg *a = arg;
8611 624411d2 2023-07-08 jrick int initial_content_len;
8612 624411d2 2023-07-08 jrick int fd = -1;
8613 624411d2 2023-07-08 jrick size_t len;
8615 624411d2 2023-07-08 jrick /* if a message was specified on the command line, just use it */
8616 624411d2 2023-07-08 jrick if (a->cmdline_log != NULL && *a->cmdline_log != '\0') {
8617 624411d2 2023-07-08 jrick len = strlen(a->cmdline_log) + 1;
8618 624411d2 2023-07-08 jrick *logmsg = malloc(len + 1);
8619 624411d2 2023-07-08 jrick if (*logmsg == NULL)
8620 624411d2 2023-07-08 jrick return got_error_from_errno("malloc");
8621 624411d2 2023-07-08 jrick strlcpy(*logmsg, a->cmdline_log, len);
8622 624411d2 2023-07-08 jrick return NULL;
8623 624411d2 2023-07-08 jrick } else if (a->prepared_log != NULL && a->non_interactive)
8624 624411d2 2023-07-08 jrick return read_prepared_logmsg(logmsg, a->prepared_log);
8626 624411d2 2023-07-08 jrick if (asprintf(&template, "%s/logmsg", a->worktree_path) == -1)
8627 624411d2 2023-07-08 jrick return got_error_from_errno("asprintf");
8629 624411d2 2023-07-08 jrick err = got_opentemp_named_fd(&a->logmsg_path, &fd, template, "");
8631 624411d2 2023-07-08 jrick goto done;
8633 624411d2 2023-07-08 jrick if (a->prepared_log) {
8634 624411d2 2023-07-08 jrick err = read_prepared_logmsg(&prepared_msg, a->prepared_log);
8636 624411d2 2023-07-08 jrick goto done;
8637 624411d2 2023-07-08 jrick } else if (a->merged_log) {
8638 624411d2 2023-07-08 jrick err = read_prepared_logmsg(&merged_msg, a->merged_log);
8640 624411d2 2023-07-08 jrick goto done;
8643 624411d2 2023-07-08 jrick initial_content_len = asprintf(&initial_content,
8644 3d1b16d1 2023-07-08 jrick "%s%s\n# changes to be committed:\n",
8645 624411d2 2023-07-08 jrick prepared_msg ? prepared_msg : "",
8646 3d1b16d1 2023-07-08 jrick merged_msg ? merged_msg : "");
8647 624411d2 2023-07-08 jrick if (initial_content_len == -1) {
8648 624411d2 2023-07-08 jrick err = got_error_from_errno("asprintf");
8649 624411d2 2023-07-08 jrick goto done;
8652 624411d2 2023-07-08 jrick if (write(fd, initial_content, initial_content_len) == -1) {
8653 624411d2 2023-07-08 jrick err = got_error_from_errno2("write", a->logmsg_path);
8654 624411d2 2023-07-08 jrick goto done;
8657 624411d2 2023-07-08 jrick TAILQ_FOREACH(pe, commitable_paths, entry) {
8658 624411d2 2023-07-08 jrick struct got_commitable *ct = pe->data;
8659 624411d2 2023-07-08 jrick dprintf(fd, "# %c %s\n",
8660 624411d2 2023-07-08 jrick got_commitable_get_status(ct),
8661 624411d2 2023-07-08 jrick got_commitable_get_path(ct));
8664 624411d2 2023-07-08 jrick if (diff_path) {
8665 624411d2 2023-07-08 jrick dprintf(fd, "# detailed changes can be viewed in %s\n",
8666 624411d2 2023-07-08 jrick diff_path);
8669 624411d2 2023-07-08 jrick if (close(fd) == -1) {
8670 624411d2 2023-07-08 jrick err = got_error_from_errno2("close", a->logmsg_path);
8671 624411d2 2023-07-08 jrick goto done;
8675 624411d2 2023-07-08 jrick err = edit_logmsg(logmsg, a->editor, a->logmsg_path, initial_content,
8676 624411d2 2023-07-08 jrick initial_content_len, a->prepared_log ? 0 : 1);
8678 624411d2 2023-07-08 jrick free(initial_content);
8679 624411d2 2023-07-08 jrick free(template);
8680 624411d2 2023-07-08 jrick free(prepared_msg);
8681 624411d2 2023-07-08 jrick free(merged_msg);
8683 624411d2 2023-07-08 jrick if (fd != -1 && close(fd) == -1 && err == NULL)
8684 624411d2 2023-07-08 jrick err = got_error_from_errno2("close", a->logmsg_path);
8686 624411d2 2023-07-08 jrick /* Editor is done; we can now apply unveil(2) */
8687 624411d2 2023-07-08 jrick if (err == NULL)
8688 3d1b16d1 2023-07-08 jrick err = got_dial_apply_unveil(a->dial_proto);
8689 3d1b16d1 2023-07-08 jrick if (err == NULL)
8690 624411d2 2023-07-08 jrick err = apply_unveil(a->repo_path, 0, a->worktree_path);
8691 624411d2 2023-07-08 jrick if (err) {
8692 624411d2 2023-07-08 jrick free(*logmsg);
8693 624411d2 2023-07-08 jrick *logmsg = NULL;
8695 624411d2 2023-07-08 jrick return err;
8698 624411d2 2023-07-08 jrick static const struct got_error *
8699 624411d2 2023-07-08 jrick cat_logmsg(FILE *f, struct got_commit_object *commit, const char *idstr,
8700 624411d2 2023-07-08 jrick const char *type, int has_content)
8702 624411d2 2023-07-08 jrick const struct got_error *err = NULL;
8703 624411d2 2023-07-08 jrick char *logmsg = NULL;
8705 624411d2 2023-07-08 jrick err = got_object_commit_get_logmsg(&logmsg, commit);
8707 624411d2 2023-07-08 jrick return err;
8709 624411d2 2023-07-08 jrick if (fprintf(f, "%s# log message of %s commit %s:%s",
8710 624411d2 2023-07-08 jrick has_content ? "\n" : "", type, idstr, logmsg) < 0)
8711 624411d2 2023-07-08 jrick err = got_ferror(f, GOT_ERR_IO);
8713 624411d2 2023-07-08 jrick free(logmsg);
8714 624411d2 2023-07-08 jrick return err;
8718 624411d2 2023-07-08 jrick * Lookup "logmsg" references of backed-out and cherrypicked commits
8719 624411d2 2023-07-08 jrick * belonging to the current work tree. If found, and the worktree has
8720 624411d2 2023-07-08 jrick * at least one modified file that was changed in the referenced commit,
8721 624411d2 2023-07-08 jrick * add its log message to a new temporary file at *logmsg_path.
8722 624411d2 2023-07-08 jrick * Add all refs found to matched_refs to be scheduled for removal on
8723 624411d2 2023-07-08 jrick * successful commit.
8725 624411d2 2023-07-08 jrick static const struct got_error *
8726 624411d2 2023-07-08 jrick lookup_logmsg_ref(char **logmsg_path, struct got_pathlist_head *paths,
8727 624411d2 2023-07-08 jrick struct got_reflist_head *matched_refs, struct got_worktree *worktree,
8728 624411d2 2023-07-08 jrick struct got_repository *repo)
8730 624411d2 2023-07-08 jrick const struct got_error *err;
8731 624411d2 2023-07-08 jrick struct got_commit_object *commit = NULL;
8732 624411d2 2023-07-08 jrick struct got_object_id *id = NULL;
8733 624411d2 2023-07-08 jrick struct got_reflist_head refs;
8734 624411d2 2023-07-08 jrick struct got_reflist_entry *re, *re_match;
8735 624411d2 2023-07-08 jrick FILE *f = NULL;
8736 624411d2 2023-07-08 jrick char *uuidstr = NULL;
8737 624411d2 2023-07-08 jrick int added_logmsg = 0;
8739 624411d2 2023-07-08 jrick TAILQ_INIT(&refs);
8741 624411d2 2023-07-08 jrick *logmsg_path = NULL;
8743 624411d2 2023-07-08 jrick err = got_worktree_get_uuid(&uuidstr, worktree);
8745 624411d2 2023-07-08 jrick goto done;
8747 624411d2 2023-07-08 jrick err = got_ref_list(&refs, repo, "refs/got/worktree",
8748 624411d2 2023-07-08 jrick got_ref_cmp_by_name, repo);
8750 624411d2 2023-07-08 jrick goto done;
8752 624411d2 2023-07-08 jrick TAILQ_FOREACH(re, &refs, entry) {
8753 624411d2 2023-07-08 jrick const char *refname, *type;
8754 624411d2 2023-07-08 jrick struct wt_commitable_path_arg wcpa;
8755 624411d2 2023-07-08 jrick int add_logmsg = 0;
8757 624411d2 2023-07-08 jrick refname = got_ref_get_name(re->ref);
8759 624411d2 2023-07-08 jrick if (strncmp(refname, GOT_WORKTREE_CHERRYPICK_REF_PREFIX,
8760 624411d2 2023-07-08 jrick GOT_WORKTREE_CHERRYPICK_REF_PREFIX_LEN) == 0) {
8761 624411d2 2023-07-08 jrick refname += GOT_WORKTREE_CHERRYPICK_REF_PREFIX_LEN + 1;
8762 624411d2 2023-07-08 jrick type = "cherrypicked";
8763 624411d2 2023-07-08 jrick } else if (strncmp(refname, GOT_WORKTREE_BACKOUT_REF_PREFIX,
8764 624411d2 2023-07-08 jrick GOT_WORKTREE_BACKOUT_REF_PREFIX_LEN) == 0) {
8765 624411d2 2023-07-08 jrick refname += GOT_WORKTREE_BACKOUT_REF_PREFIX_LEN + 1;
8766 624411d2 2023-07-08 jrick type = "backed-out";
8768 624411d2 2023-07-08 jrick continue;
8770 624411d2 2023-07-08 jrick if (strncmp(refname, uuidstr, GOT_WORKTREE_UUID_STRLEN) == 0)
8771 624411d2 2023-07-08 jrick refname += GOT_WORKTREE_UUID_STRLEN + 1; /* skip '-' */
8773 624411d2 2023-07-08 jrick continue;
8775 624411d2 2023-07-08 jrick err = got_repo_match_object_id(&id, NULL, refname,
8776 624411d2 2023-07-08 jrick GOT_OBJ_TYPE_COMMIT, NULL, repo);
8778 624411d2 2023-07-08 jrick goto done;
8780 624411d2 2023-07-08 jrick err = got_object_open_as_commit(&commit, repo, id);
8782 624411d2 2023-07-08 jrick goto done;
8784 624411d2 2023-07-08 jrick wcpa.commit_paths = paths;
8785 624411d2 2023-07-08 jrick wcpa.has_changes = &add_logmsg;
8787 624411d2 2023-07-08 jrick err = commit_path_changed_in_worktree(&wcpa, id,
8788 624411d2 2023-07-08 jrick worktree, repo);
8790 624411d2 2023-07-08 jrick goto done;
8792 624411d2 2023-07-08 jrick if (add_logmsg) {
8793 624411d2 2023-07-08 jrick if (f == NULL) {
8794 624411d2 2023-07-08 jrick err = got_opentemp_named(logmsg_path, &f,
8795 624411d2 2023-07-08 jrick "got-commit-logmsg", "");
8797 624411d2 2023-07-08 jrick goto done;
8799 624411d2 2023-07-08 jrick err = cat_logmsg(f, commit, refname, type,
8800 624411d2 2023-07-08 jrick added_logmsg);
8802 624411d2 2023-07-08 jrick goto done;
8803 624411d2 2023-07-08 jrick if (!added_logmsg)
8804 624411d2 2023-07-08 jrick ++added_logmsg;
8806 624411d2 2023-07-08 jrick err = got_reflist_entry_dup(&re_match, re);
8808 624411d2 2023-07-08 jrick goto done;
8809 624411d2 2023-07-08 jrick TAILQ_INSERT_HEAD(matched_refs, re_match, entry);
8812 624411d2 2023-07-08 jrick got_object_commit_close(commit);
8813 624411d2 2023-07-08 jrick commit = NULL;
8814 624411d2 2023-07-08 jrick free(id);
8815 624411d2 2023-07-08 jrick id = NULL;
8819 624411d2 2023-07-08 jrick free(id);
8820 624411d2 2023-07-08 jrick free(uuidstr);
8821 624411d2 2023-07-08 jrick got_ref_list_free(&refs);
8822 624411d2 2023-07-08 jrick if (commit)
8823 624411d2 2023-07-08 jrick got_object_commit_close(commit);
8824 624411d2 2023-07-08 jrick if (f && fclose(f) == EOF && err == NULL)
8825 624411d2 2023-07-08 jrick err = got_error_from_errno("fclose");
8826 624411d2 2023-07-08 jrick if (!added_logmsg) {
8827 624411d2 2023-07-08 jrick if (*logmsg_path && unlink(*logmsg_path) != 0 && err == NULL)
8828 624411d2 2023-07-08 jrick err = got_error_from_errno2("unlink", *logmsg_path);
8829 624411d2 2023-07-08 jrick *logmsg_path = NULL;
8831 624411d2 2023-07-08 jrick return err;
8834 624411d2 2023-07-08 jrick static const struct got_error *
8835 624411d2 2023-07-08 jrick cmd_commit(int argc, char *argv[])
8837 624411d2 2023-07-08 jrick const struct got_error *error = NULL;
8838 624411d2 2023-07-08 jrick struct got_worktree *worktree = NULL;
8839 624411d2 2023-07-08 jrick struct got_repository *repo = NULL;
8840 624411d2 2023-07-08 jrick char *cwd = NULL, *id_str = NULL;
8841 624411d2 2023-07-08 jrick struct got_object_id *id = NULL;
8842 624411d2 2023-07-08 jrick const char *logmsg = NULL;
8843 624411d2 2023-07-08 jrick char *prepared_logmsg = NULL, *merged_logmsg = NULL;
8844 624411d2 2023-07-08 jrick struct collect_commit_logmsg_arg cl_arg;
8845 624411d2 2023-07-08 jrick const char *author = NULL;
8846 624411d2 2023-07-08 jrick char *gitconfig_path = NULL, *editor = NULL, *committer = NULL;
8847 624411d2 2023-07-08 jrick int ch, rebase_in_progress, histedit_in_progress, preserve_logmsg = 0;
8848 624411d2 2023-07-08 jrick int allow_bad_symlinks = 0, non_interactive = 0, merge_in_progress = 0;
8849 624411d2 2023-07-08 jrick int show_diff = 1, commit_conflicts = 0;
8850 624411d2 2023-07-08 jrick struct got_pathlist_head paths;
8851 624411d2 2023-07-08 jrick struct got_reflist_head refs;
8852 624411d2 2023-07-08 jrick struct got_reflist_entry *re;
8853 624411d2 2023-07-08 jrick int *pack_fds = NULL;
8854 3d1b16d1 2023-07-08 jrick const struct got_gotconfig *repo_conf = NULL, *worktree_conf = NULL;
8855 3d1b16d1 2023-07-08 jrick const struct got_remote_repo *remotes, *remote = NULL;
8856 3d1b16d1 2023-07-08 jrick int nremotes;
8857 3d1b16d1 2023-07-08 jrick char *proto = NULL, *host = NULL, *port = NULL;
8858 3d1b16d1 2023-07-08 jrick char *repo_name = NULL, *server_path = NULL;
8859 3d1b16d1 2023-07-08 jrick const char *remote_name;
8860 3d1b16d1 2023-07-08 jrick int verbosity = 0;
8863 624411d2 2023-07-08 jrick TAILQ_INIT(&refs);
8864 624411d2 2023-07-08 jrick TAILQ_INIT(&paths);
8865 624411d2 2023-07-08 jrick cl_arg.logmsg_path = NULL;
8867 624411d2 2023-07-08 jrick #ifndef PROFILE
8868 624411d2 2023-07-08 jrick if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd "
8869 624411d2 2023-07-08 jrick "unveil", NULL) == -1)
8870 624411d2 2023-07-08 jrick err(1, "pledge");
8873 624411d2 2023-07-08 jrick while ((ch = getopt(argc, argv, "A:CF:m:NnS")) != -1) {
8874 624411d2 2023-07-08 jrick switch (ch) {
8875 624411d2 2023-07-08 jrick case 'A':
8876 624411d2 2023-07-08 jrick author = optarg;
8877 624411d2 2023-07-08 jrick error = valid_author(author);
8878 624411d2 2023-07-08 jrick if (error)
8879 624411d2 2023-07-08 jrick return error;
8881 624411d2 2023-07-08 jrick case 'C':
8882 624411d2 2023-07-08 jrick commit_conflicts = 1;
8884 624411d2 2023-07-08 jrick case 'F':
8885 624411d2 2023-07-08 jrick if (logmsg != NULL)
8886 624411d2 2023-07-08 jrick option_conflict('F', 'm');
8887 624411d2 2023-07-08 jrick prepared_logmsg = realpath(optarg, NULL);
8888 624411d2 2023-07-08 jrick if (prepared_logmsg == NULL)
8889 624411d2 2023-07-08 jrick return got_error_from_errno2("realpath",
8892 624411d2 2023-07-08 jrick case 'm':
8893 624411d2 2023-07-08 jrick if (prepared_logmsg)
8894 624411d2 2023-07-08 jrick option_conflict('m', 'F');
8895 624411d2 2023-07-08 jrick logmsg = optarg;
8897 624411d2 2023-07-08 jrick case 'N':
8898 624411d2 2023-07-08 jrick non_interactive = 1;
8900 624411d2 2023-07-08 jrick case 'n':
8901 624411d2 2023-07-08 jrick show_diff = 0;
8903 624411d2 2023-07-08 jrick case 'S':
8904 624411d2 2023-07-08 jrick allow_bad_symlinks = 1;
8907 624411d2 2023-07-08 jrick usage_commit();
8908 624411d2 2023-07-08 jrick /* NOTREACHED */
8912 624411d2 2023-07-08 jrick argc -= optind;
8913 624411d2 2023-07-08 jrick argv += optind;
8915 624411d2 2023-07-08 jrick cwd = getcwd(NULL, 0);
8916 624411d2 2023-07-08 jrick if (cwd == NULL) {
8917 624411d2 2023-07-08 jrick error = got_error_from_errno("getcwd");
8918 624411d2 2023-07-08 jrick goto done;
8921 624411d2 2023-07-08 jrick error = got_repo_pack_fds_open(&pack_fds);
8922 624411d2 2023-07-08 jrick if (error != NULL)
8923 624411d2 2023-07-08 jrick goto done;
8925 624411d2 2023-07-08 jrick error = got_worktree_open(&worktree, cwd);
8926 624411d2 2023-07-08 jrick if (error) {
8927 624411d2 2023-07-08 jrick if (error->code == GOT_ERR_NOT_WORKTREE)
8928 624411d2 2023-07-08 jrick error = wrap_not_worktree_error(error, "commit", cwd);
8929 624411d2 2023-07-08 jrick goto done;
8932 624411d2 2023-07-08 jrick error = got_worktree_rebase_in_progress(&rebase_in_progress, worktree);
8933 624411d2 2023-07-08 jrick if (error)
8934 624411d2 2023-07-08 jrick goto done;
8935 624411d2 2023-07-08 jrick if (rebase_in_progress) {
8936 624411d2 2023-07-08 jrick error = got_error(GOT_ERR_REBASING);
8937 624411d2 2023-07-08 jrick goto done;
8940 624411d2 2023-07-08 jrick error = got_worktree_histedit_in_progress(&histedit_in_progress,
8941 624411d2 2023-07-08 jrick worktree);
8942 624411d2 2023-07-08 jrick if (error)
8943 624411d2 2023-07-08 jrick goto done;
8945 624411d2 2023-07-08 jrick error = get_gitconfig_path(&gitconfig_path);
8946 624411d2 2023-07-08 jrick if (error)
8947 624411d2 2023-07-08 jrick goto done;
8948 624411d2 2023-07-08 jrick error = got_repo_open(&repo, got_worktree_get_repo_path(worktree),
8949 624411d2 2023-07-08 jrick gitconfig_path, pack_fds);
8950 624411d2 2023-07-08 jrick if (error != NULL)
8951 624411d2 2023-07-08 jrick goto done;
8953 624411d2 2023-07-08 jrick error = got_worktree_merge_in_progress(&merge_in_progress, worktree, repo);
8954 624411d2 2023-07-08 jrick if (error)
8955 624411d2 2023-07-08 jrick goto done;
8956 624411d2 2023-07-08 jrick if (merge_in_progress) {
8957 624411d2 2023-07-08 jrick error = got_error(GOT_ERR_MERGE_BUSY);
8958 624411d2 2023-07-08 jrick goto done;
8961 624411d2 2023-07-08 jrick error = get_author(&committer, repo, worktree);
8962 624411d2 2023-07-08 jrick if (error)
8963 624411d2 2023-07-08 jrick goto done;
8965 624411d2 2023-07-08 jrick if (author == NULL)
8966 624411d2 2023-07-08 jrick author = committer;
8968 3d1b16d1 2023-07-08 jrick remote_name = GOT_SEND_DEFAULT_REMOTE_NAME;
8969 3d1b16d1 2023-07-08 jrick worktree_conf = got_worktree_get_gotconfig(worktree);
8970 3d1b16d1 2023-07-08 jrick if (worktree_conf) {
8971 3d1b16d1 2023-07-08 jrick got_gotconfig_get_remotes(&nremotes, &remotes,
8972 3d1b16d1 2023-07-08 jrick worktree_conf);
8973 3d1b16d1 2023-07-08 jrick for (i = 0; i < nremotes; i++) {
8974 3d1b16d1 2023-07-08 jrick if (strcmp(remotes[i].name, remote_name) == 0) {
8975 3d1b16d1 2023-07-08 jrick remote = &remotes[i];
8980 3d1b16d1 2023-07-08 jrick if (remote == NULL) {
8981 3d1b16d1 2023-07-08 jrick repo_conf = got_repo_get_gotconfig(repo);
8982 3d1b16d1 2023-07-08 jrick if (repo_conf) {
8983 3d1b16d1 2023-07-08 jrick got_gotconfig_get_remotes(&nremotes, &remotes,
8984 3d1b16d1 2023-07-08 jrick repo_conf);
8985 3d1b16d1 2023-07-08 jrick for (i = 0; i < nremotes; i++) {
8986 3d1b16d1 2023-07-08 jrick if (strcmp(remotes[i].name, remote_name) == 0) {
8987 3d1b16d1 2023-07-08 jrick remote = &remotes[i];
8993 3d1b16d1 2023-07-08 jrick if (remote == NULL) {
8994 3d1b16d1 2023-07-08 jrick got_repo_get_gitconfig_remotes(&nremotes, &remotes, repo);
8995 3d1b16d1 2023-07-08 jrick for (i = 0; i < nremotes; i++) {
8996 3d1b16d1 2023-07-08 jrick if (strcmp(remotes[i].name, remote_name) == 0) {
8997 3d1b16d1 2023-07-08 jrick remote = &remotes[i];
9002 3d1b16d1 2023-07-08 jrick if (remote == NULL) {
9003 3d1b16d1 2023-07-08 jrick error = got_error_path(remote_name, GOT_ERR_NO_REMOTE);
9004 3d1b16d1 2023-07-08 jrick goto done;
9007 3d1b16d1 2023-07-08 jrick error = got_dial_parse_uri(&proto, &host, &port, &server_path,
9008 3d1b16d1 2023-07-08 jrick &repo_name, remote->fetch_url);
9009 3d1b16d1 2023-07-08 jrick if (error)
9010 3d1b16d1 2023-07-08 jrick goto done;
9012 3d1b16d1 2023-07-08 jrick if (strcmp(proto, "git") == 0) {
9013 3d1b16d1 2023-07-08 jrick #ifndef PROFILE
9014 3d1b16d1 2023-07-08 jrick if (pledge("stdio rpath wpath cpath fattr flock proc exec "
9015 3d1b16d1 2023-07-08 jrick "sendfd dns inet unveil", NULL) == -1)
9016 3d1b16d1 2023-07-08 jrick err(1, "pledge");
9018 3d1b16d1 2023-07-08 jrick } else if (strcmp(proto, "git+ssh") == 0 ||
9019 3d1b16d1 2023-07-08 jrick strcmp(proto, "ssh") == 0) {
9020 3d1b16d1 2023-07-08 jrick #ifndef PROFILE
9021 3d1b16d1 2023-07-08 jrick if (pledge("stdio rpath wpath cpath fattr flock proc exec "
9022 3d1b16d1 2023-07-08 jrick "sendfd unveil", NULL) == -1)
9023 3d1b16d1 2023-07-08 jrick err(1, "pledge");
9025 3d1b16d1 2023-07-08 jrick } else if (strcmp(proto, "http") == 0 ||
9026 3d1b16d1 2023-07-08 jrick strcmp(proto, "git+http") == 0) {
9027 3d1b16d1 2023-07-08 jrick error = got_error_path(proto, GOT_ERR_NOT_IMPL);
9028 3d1b16d1 2023-07-08 jrick goto done;
9030 3d1b16d1 2023-07-08 jrick error = got_error_path(proto, GOT_ERR_BAD_PROTO);
9031 3d1b16d1 2023-07-08 jrick goto done;
9035 3d1b16d1 2023-07-08 jrick /*if (verbosity >= 0) {
9036 3d1b16d1 2023-07-08 jrick printf("Connecting to \"%s\" %s://%s%s%s%s%s\n",
9037 3d1b16d1 2023-07-08 jrick remote->name, proto, host,
9038 3d1b16d1 2023-07-08 jrick port ? ":" : "", port ? port : "",
9039 3d1b16d1 2023-07-08 jrick *server_path == '/' ? "" : "/", server_path);
9043 624411d2 2023-07-08 jrick * unveil(2) traverses exec(2); if an editor is used we have
9044 3d1b16d1 2023-07-08 jrick * to apply unveil after the log message has been written during
9045 3d1b16d1 2023-07-08 jrick * the callback.
9047 624411d2 2023-07-08 jrick if (logmsg == NULL || strlen(logmsg) == 0)
9048 624411d2 2023-07-08 jrick error = get_editor(&editor);
9050 3d1b16d1 2023-07-08 jrick error = got_dial_apply_unveil(proto);
9051 3d1b16d1 2023-07-08 jrick if (error)
9052 3d1b16d1 2023-07-08 jrick goto done;
9053 624411d2 2023-07-08 jrick error = apply_unveil(got_repo_get_path(repo), 0,
9054 624411d2 2023-07-08 jrick got_worktree_get_root_path(worktree));
9056 624411d2 2023-07-08 jrick if (error)
9057 624411d2 2023-07-08 jrick goto done;
9059 624411d2 2023-07-08 jrick if (prepared_logmsg == NULL) {
9060 624411d2 2023-07-08 jrick error = lookup_logmsg_ref(&merged_logmsg,
9061 624411d2 2023-07-08 jrick argc > 0 ? &paths : NULL, &refs, worktree, repo);
9062 624411d2 2023-07-08 jrick if (error)
9063 624411d2 2023-07-08 jrick goto done;
9066 3d1b16d1 2023-07-08 jrick error = get_worktree_paths_from_argv(&paths, argc, argv, worktree);
9067 3d1b16d1 2023-07-08 jrick if (error)
9068 3d1b16d1 2023-07-08 jrick goto done;
9070 624411d2 2023-07-08 jrick cl_arg.editor = editor;
9071 624411d2 2023-07-08 jrick cl_arg.cmdline_log = logmsg;
9072 624411d2 2023-07-08 jrick cl_arg.prepared_log = prepared_logmsg;
9073 624411d2 2023-07-08 jrick cl_arg.merged_log = merged_logmsg;
9074 624411d2 2023-07-08 jrick cl_arg.non_interactive = non_interactive;
9075 624411d2 2023-07-08 jrick cl_arg.worktree_path = got_worktree_get_root_path(worktree);
9076 3d1b16d1 2023-07-08 jrick cl_arg.repo_path = got_repo_get_path(repo);
9077 3d1b16d1 2023-07-08 jrick cl_arg.dial_proto = proto;
9078 3d1b16d1 2023-07-08 jrick error = got_worktree_cvg_commit(&id, worktree, &paths, author,
9079 3d1b16d1 2023-07-08 jrick committer, allow_bad_symlinks, show_diff, commit_conflicts,
9080 3d1b16d1 2023-07-08 jrick collect_commit_logmsg, &cl_arg, print_status, NULL, proto, host,
9081 3d1b16d1 2023-07-08 jrick port, server_path, verbosity, remote, check_cancelled, repo);
9082 624411d2 2023-07-08 jrick if (error) {
9083 624411d2 2023-07-08 jrick if (error->code != GOT_ERR_COMMIT_MSG_EMPTY &&
9084 624411d2 2023-07-08 jrick cl_arg.logmsg_path != NULL)
9085 624411d2 2023-07-08 jrick preserve_logmsg = 1;
9086 624411d2 2023-07-08 jrick goto done;
9089 624411d2 2023-07-08 jrick error = got_object_id_str(&id_str, id);
9090 624411d2 2023-07-08 jrick if (error)
9091 624411d2 2023-07-08 jrick goto done;
9092 624411d2 2023-07-08 jrick printf("Created commit %s\n", id_str);
9094 624411d2 2023-07-08 jrick TAILQ_FOREACH(re, &refs, entry) {
9095 624411d2 2023-07-08 jrick error = got_ref_delete(re->ref, repo);
9096 624411d2 2023-07-08 jrick if (error)
9097 624411d2 2023-07-08 jrick goto done;
9101 624411d2 2023-07-08 jrick if (preserve_logmsg) {
9102 624411d2 2023-07-08 jrick fprintf(stderr, "%s: log message preserved in %s\n",
9103 624411d2 2023-07-08 jrick getprogname(), cl_arg.logmsg_path);
9104 624411d2 2023-07-08 jrick } else if (cl_arg.logmsg_path && unlink(cl_arg.logmsg_path) == -1 &&
9105 624411d2 2023-07-08 jrick error == NULL)
9106 624411d2 2023-07-08 jrick error = got_error_from_errno2("unlink", cl_arg.logmsg_path);
9107 624411d2 2023-07-08 jrick free(cl_arg.logmsg_path);
9108 624411d2 2023-07-08 jrick if (merged_logmsg && unlink(merged_logmsg) == -1 && error == NULL)
9109 624411d2 2023-07-08 jrick error = got_error_from_errno2("unlink", merged_logmsg);
9110 624411d2 2023-07-08 jrick free(merged_logmsg);
9111 624411d2 2023-07-08 jrick if (repo) {
9112 624411d2 2023-07-08 jrick const struct got_error *close_err = got_repo_close(repo);
9113 624411d2 2023-07-08 jrick if (error == NULL)
9114 624411d2 2023-07-08 jrick error = close_err;
9116 624411d2 2023-07-08 jrick if (worktree)
9117 624411d2 2023-07-08 jrick got_worktree_close(worktree);
9118 624411d2 2023-07-08 jrick if (pack_fds) {
9119 624411d2 2023-07-08 jrick const struct got_error *pack_err =
9120 624411d2 2023-07-08 jrick got_repo_pack_fds_close(pack_fds);
9121 624411d2 2023-07-08 jrick if (error == NULL)
9122 624411d2 2023-07-08 jrick error = pack_err;
9124 624411d2 2023-07-08 jrick got_ref_list_free(&refs);
9125 624411d2 2023-07-08 jrick got_pathlist_free(&paths, GOT_PATHLIST_FREE_PATH);
9126 624411d2 2023-07-08 jrick free(cwd);
9127 624411d2 2023-07-08 jrick free(id_str);
9128 624411d2 2023-07-08 jrick free(gitconfig_path);
9129 624411d2 2023-07-08 jrick free(editor);
9130 624411d2 2023-07-08 jrick free(committer);
9131 624411d2 2023-07-08 jrick free(prepared_logmsg);
9132 624411d2 2023-07-08 jrick return error;
9135 624411d2 2023-07-08 jrick __dead static void
9136 624411d2 2023-07-08 jrick usage_send(void)
9138 624411d2 2023-07-08 jrick fprintf(stderr, "usage: %s send [-afqTv] [-b branch] [-d branch] "
9139 624411d2 2023-07-08 jrick "[-r repository-path] [-t tag] [remote-repository]\n",
9140 624411d2 2023-07-08 jrick getprogname());
9144 624411d2 2023-07-08 jrick static void
9145 624411d2 2023-07-08 jrick print_load_info(int print_colored, int print_found, int print_trees,
9146 624411d2 2023-07-08 jrick int ncolored, int nfound, int ntrees)
9148 624411d2 2023-07-08 jrick if (print_colored) {
9149 624411d2 2023-07-08 jrick printf("%d commit%s colored", ncolored,
9150 624411d2 2023-07-08 jrick ncolored == 1 ? "" : "s");
9152 624411d2 2023-07-08 jrick if (print_found) {
9153 624411d2 2023-07-08 jrick printf("%s%d object%s found",
9154 624411d2 2023-07-08 jrick ncolored > 0 ? "; " : "",
9155 624411d2 2023-07-08 jrick nfound, nfound == 1 ? "" : "s");
9157 624411d2 2023-07-08 jrick if (print_trees) {
9158 624411d2 2023-07-08 jrick printf("; %d tree%s scanned", ntrees,
9159 624411d2 2023-07-08 jrick ntrees == 1 ? "" : "s");
9163 624411d2 2023-07-08 jrick struct got_send_progress_arg {
9164 624411d2 2023-07-08 jrick char last_scaled_packsize[FMT_SCALED_STRSIZE];
9165 624411d2 2023-07-08 jrick int verbosity;
9166 624411d2 2023-07-08 jrick int last_ncolored;
9167 624411d2 2023-07-08 jrick int last_nfound;
9168 624411d2 2023-07-08 jrick int last_ntrees;
9169 624411d2 2023-07-08 jrick int loading_done;
9170 624411d2 2023-07-08 jrick int last_ncommits;
9171 624411d2 2023-07-08 jrick int last_nobj_total;
9172 624411d2 2023-07-08 jrick int last_p_deltify;
9173 624411d2 2023-07-08 jrick int last_p_written;
9174 624411d2 2023-07-08 jrick int last_p_sent;
9175 624411d2 2023-07-08 jrick int printed_something;
9176 624411d2 2023-07-08 jrick int sent_something;
9177 624411d2 2023-07-08 jrick struct got_pathlist_head *delete_branches;
9180 624411d2 2023-07-08 jrick static const struct got_error *
9181 624411d2 2023-07-08 jrick send_progress(void *arg, int ncolored, int nfound, int ntrees,
9182 624411d2 2023-07-08 jrick off_t packfile_size, int ncommits, int nobj_total, int nobj_deltify,
9183 624411d2 2023-07-08 jrick int nobj_written, off_t bytes_sent, const char *refname,
9184 624411d2 2023-07-08 jrick const char *errmsg, int success)
9186 624411d2 2023-07-08 jrick struct got_send_progress_arg *a = arg;
9187 624411d2 2023-07-08 jrick char scaled_packsize[FMT_SCALED_STRSIZE];
9188 624411d2 2023-07-08 jrick char scaled_sent[FMT_SCALED_STRSIZE];
9189 624411d2 2023-07-08 jrick int p_deltify = 0, p_written = 0, p_sent = 0;
9190 624411d2 2023-07-08 jrick int print_colored = 0, print_found = 0, print_trees = 0;
9191 624411d2 2023-07-08 jrick int print_searching = 0, print_total = 0;
9192 624411d2 2023-07-08 jrick int print_deltify = 0, print_written = 0, print_sent = 0;
9194 624411d2 2023-07-08 jrick if (a->verbosity < 0)
9195 624411d2 2023-07-08 jrick return NULL;
9197 624411d2 2023-07-08 jrick if (refname) {
9198 624411d2 2023-07-08 jrick const char *status = success ? "accepted" : "rejected";
9200 624411d2 2023-07-08 jrick if (success) {
9201 624411d2 2023-07-08 jrick struct got_pathlist_entry *pe;
9202 624411d2 2023-07-08 jrick TAILQ_FOREACH(pe, a->delete_branches, entry) {
9203 624411d2 2023-07-08 jrick const char *branchname = pe->path;
9204 624411d2 2023-07-08 jrick if (got_path_cmp(branchname, refname,
9205 624411d2 2023-07-08 jrick strlen(branchname), strlen(refname)) == 0) {
9206 624411d2 2023-07-08 jrick status = "deleted";
9207 624411d2 2023-07-08 jrick a->sent_something = 1;
9213 624411d2 2023-07-08 jrick if (a->printed_something)
9214 624411d2 2023-07-08 jrick putchar('\n');
9215 624411d2 2023-07-08 jrick printf("Server has %s %s", status, refname);
9216 624411d2 2023-07-08 jrick if (errmsg)
9217 624411d2 2023-07-08 jrick printf(": %s", errmsg);
9218 624411d2 2023-07-08 jrick a->printed_something = 1;
9219 624411d2 2023-07-08 jrick return NULL;
9222 624411d2 2023-07-08 jrick if (a->last_ncolored != ncolored) {
9223 624411d2 2023-07-08 jrick print_colored = 1;
9224 624411d2 2023-07-08 jrick a->last_ncolored = ncolored;
9227 624411d2 2023-07-08 jrick if (a->last_nfound != nfound) {
9228 624411d2 2023-07-08 jrick print_colored = 1;
9229 624411d2 2023-07-08 jrick print_found = 1;
9230 624411d2 2023-07-08 jrick a->last_nfound = nfound;
9233 624411d2 2023-07-08 jrick if (a->last_ntrees != ntrees) {
9234 624411d2 2023-07-08 jrick print_colored = 1;
9235 624411d2 2023-07-08 jrick print_found = 1;
9236 624411d2 2023-07-08 jrick print_trees = 1;
9237 624411d2 2023-07-08 jrick a->last_ntrees = ntrees;
9240 624411d2 2023-07-08 jrick if ((print_colored || print_found || print_trees) &&
9241 624411d2 2023-07-08 jrick !a->loading_done) {
9242 624411d2 2023-07-08 jrick printf("\r");
9243 624411d2 2023-07-08 jrick print_load_info(print_colored, print_found, print_trees,
9244 624411d2 2023-07-08 jrick ncolored, nfound, ntrees);
9245 624411d2 2023-07-08 jrick a->printed_something = 1;
9246 624411d2 2023-07-08 jrick fflush(stdout);
9247 624411d2 2023-07-08 jrick return NULL;
9248 624411d2 2023-07-08 jrick } else if (!a->loading_done) {
9249 624411d2 2023-07-08 jrick printf("\r");
9250 624411d2 2023-07-08 jrick print_load_info(1, 1, 1, ncolored, nfound, ntrees);
9251 624411d2 2023-07-08 jrick printf("\n");
9252 624411d2 2023-07-08 jrick a->loading_done = 1;
9255 624411d2 2023-07-08 jrick if (fmt_scaled(packfile_size, scaled_packsize) == -1)
9256 624411d2 2023-07-08 jrick return got_error_from_errno("fmt_scaled");
9257 624411d2 2023-07-08 jrick if (fmt_scaled(bytes_sent, scaled_sent) == -1)
9258 624411d2 2023-07-08 jrick return got_error_from_errno("fmt_scaled");
9260 624411d2 2023-07-08 jrick if (a->last_ncommits != ncommits) {
9261 624411d2 2023-07-08 jrick print_searching = 1;
9262 624411d2 2023-07-08 jrick a->last_ncommits = ncommits;
9265 624411d2 2023-07-08 jrick if (a->last_nobj_total != nobj_total) {
9266 624411d2 2023-07-08 jrick print_searching = 1;
9267 624411d2 2023-07-08 jrick print_total = 1;
9268 624411d2 2023-07-08 jrick a->last_nobj_total = nobj_total;
9271 624411d2 2023-07-08 jrick if (packfile_size > 0 && (a->last_scaled_packsize[0] == '\0' ||
9272 624411d2 2023-07-08 jrick strcmp(scaled_packsize, a->last_scaled_packsize)) != 0) {
9273 624411d2 2023-07-08 jrick if (strlcpy(a->last_scaled_packsize, scaled_packsize,
9274 624411d2 2023-07-08 jrick FMT_SCALED_STRSIZE) >= FMT_SCALED_STRSIZE)
9275 624411d2 2023-07-08 jrick return got_error(GOT_ERR_NO_SPACE);
9278 624411d2 2023-07-08 jrick if (nobj_deltify > 0 || nobj_written > 0) {
9279 624411d2 2023-07-08 jrick if (nobj_deltify > 0) {
9280 624411d2 2023-07-08 jrick p_deltify = (nobj_deltify * 100) / nobj_total;
9281 624411d2 2023-07-08 jrick if (p_deltify != a->last_p_deltify) {
9282 624411d2 2023-07-08 jrick a->last_p_deltify = p_deltify;
9283 624411d2 2023-07-08 jrick print_searching = 1;
9284 624411d2 2023-07-08 jrick print_total = 1;
9285 624411d2 2023-07-08 jrick print_deltify = 1;
9288 624411d2 2023-07-08 jrick if (nobj_written > 0) {
9289 624411d2 2023-07-08 jrick p_written = (nobj_written * 100) / nobj_total;
9290 624411d2 2023-07-08 jrick if (p_written != a->last_p_written) {
9291 624411d2 2023-07-08 jrick a->last_p_written = p_written;
9292 624411d2 2023-07-08 jrick print_searching = 1;
9293 624411d2 2023-07-08 jrick print_total = 1;
9294 624411d2 2023-07-08 jrick print_deltify = 1;
9295 624411d2 2023-07-08 jrick print_written = 1;
9300 624411d2 2023-07-08 jrick if (bytes_sent > 0) {
9301 624411d2 2023-07-08 jrick p_sent = (bytes_sent * 100) / packfile_size;
9302 624411d2 2023-07-08 jrick if (p_sent != a->last_p_sent) {
9303 624411d2 2023-07-08 jrick a->last_p_sent = p_sent;
9304 624411d2 2023-07-08 jrick print_searching = 1;
9305 624411d2 2023-07-08 jrick print_total = 1;
9306 624411d2 2023-07-08 jrick print_deltify = 1;
9307 624411d2 2023-07-08 jrick print_written = 1;
9308 624411d2 2023-07-08 jrick print_sent = 1;
9310 624411d2 2023-07-08 jrick a->sent_something = 1;
9313 624411d2 2023-07-08 jrick if (print_searching || print_total || print_deltify || print_written ||
9314 624411d2 2023-07-08 jrick print_sent)
9315 624411d2 2023-07-08 jrick printf("\r");
9316 624411d2 2023-07-08 jrick if (print_searching)
9317 624411d2 2023-07-08 jrick printf("packing %d reference%s", ncommits,
9318 624411d2 2023-07-08 jrick ncommits == 1 ? "" : "s");
9319 624411d2 2023-07-08 jrick if (print_total)
9320 624411d2 2023-07-08 jrick printf("; %d object%s", nobj_total,
9321 624411d2 2023-07-08 jrick nobj_total == 1 ? "" : "s");
9322 624411d2 2023-07-08 jrick if (print_deltify)
9323 624411d2 2023-07-08 jrick printf("; deltify: %d%%", p_deltify);
9324 624411d2 2023-07-08 jrick if (print_sent)
9325 624411d2 2023-07-08 jrick printf("; uploading pack: %*s %d%%", FMT_SCALED_STRSIZE - 2,
9326 624411d2 2023-07-08 jrick scaled_packsize, p_sent);
9327 624411d2 2023-07-08 jrick else if (print_written)
9328 624411d2 2023-07-08 jrick printf("; writing pack: %*s %d%%", FMT_SCALED_STRSIZE - 2,
9329 624411d2 2023-07-08 jrick scaled_packsize, p_written);
9330 624411d2 2023-07-08 jrick if (print_searching || print_total || print_deltify ||
9331 624411d2 2023-07-08 jrick print_written || print_sent) {
9332 624411d2 2023-07-08 jrick a->printed_something = 1;
9333 624411d2 2023-07-08 jrick fflush(stdout);
9335 624411d2 2023-07-08 jrick return NULL;
9338 624411d2 2023-07-08 jrick static const struct got_error *
9339 624411d2 2023-07-08 jrick cmd_send(int argc, char *argv[])
9341 624411d2 2023-07-08 jrick const struct got_error *error = NULL;
9342 624411d2 2023-07-08 jrick char *cwd = NULL, *repo_path = NULL;
9343 624411d2 2023-07-08 jrick const char *remote_name;
9344 624411d2 2023-07-08 jrick char *proto = NULL, *host = NULL, *port = NULL;
9345 624411d2 2023-07-08 jrick char *repo_name = NULL, *server_path = NULL;
9346 624411d2 2023-07-08 jrick const struct got_remote_repo *remotes, *remote = NULL;
9347 624411d2 2023-07-08 jrick int nremotes, nbranches = 0, ndelete_branches = 0;
9348 624411d2 2023-07-08 jrick struct got_repository *repo = NULL;
9349 624411d2 2023-07-08 jrick struct got_worktree *worktree = NULL;
9350 624411d2 2023-07-08 jrick const struct got_gotconfig *repo_conf = NULL, *worktree_conf = NULL;
9351 624411d2 2023-07-08 jrick struct got_pathlist_head branches;
9352 624411d2 2023-07-08 jrick struct got_pathlist_head tags;
9353 624411d2 2023-07-08 jrick struct got_reflist_head all_branches;
9354 624411d2 2023-07-08 jrick struct got_reflist_head all_tags;
9355 624411d2 2023-07-08 jrick struct got_pathlist_head delete_args;
9356 624411d2 2023-07-08 jrick struct got_pathlist_head delete_branches;
9357 624411d2 2023-07-08 jrick struct got_reflist_entry *re;
9358 624411d2 2023-07-08 jrick struct got_pathlist_entry *pe;
9359 624411d2 2023-07-08 jrick int i, ch, sendfd = -1, sendstatus;
9360 624411d2 2023-07-08 jrick pid_t sendpid = -1;
9361 624411d2 2023-07-08 jrick struct got_send_progress_arg spa;
9362 624411d2 2023-07-08 jrick int verbosity = 0, overwrite_refs = 0;
9363 624411d2 2023-07-08 jrick int send_all_branches = 0, send_all_tags = 0;
9364 624411d2 2023-07-08 jrick struct got_reference *ref = NULL;
9365 624411d2 2023-07-08 jrick int *pack_fds = NULL;
9367 624411d2 2023-07-08 jrick TAILQ_INIT(&branches);
9368 624411d2 2023-07-08 jrick TAILQ_INIT(&tags);
9369 624411d2 2023-07-08 jrick TAILQ_INIT(&all_branches);
9370 624411d2 2023-07-08 jrick TAILQ_INIT(&all_tags);
9371 624411d2 2023-07-08 jrick TAILQ_INIT(&delete_args);
9372 624411d2 2023-07-08 jrick TAILQ_INIT(&delete_branches);
9374 624411d2 2023-07-08 jrick while ((ch = getopt(argc, argv, "ab:d:fqr:Tt:v")) != -1) {
9375 624411d2 2023-07-08 jrick switch (ch) {
9376 624411d2 2023-07-08 jrick case 'a':
9377 624411d2 2023-07-08 jrick send_all_branches = 1;
9379 624411d2 2023-07-08 jrick case 'b':
9380 624411d2 2023-07-08 jrick error = got_pathlist_append(&branches, optarg, NULL);
9381 624411d2 2023-07-08 jrick if (error)
9382 624411d2 2023-07-08 jrick return error;
9383 624411d2 2023-07-08 jrick nbranches++;
9385 624411d2 2023-07-08 jrick case 'd':
9386 624411d2 2023-07-08 jrick error = got_pathlist_append(&delete_args, optarg, NULL);
9387 624411d2 2023-07-08 jrick if (error)
9388 624411d2 2023-07-08 jrick return error;
9390 624411d2 2023-07-08 jrick case 'f':
9391 624411d2 2023-07-08 jrick overwrite_refs = 1;
9393 624411d2 2023-07-08 jrick case 'q':
9394 624411d2 2023-07-08 jrick verbosity = -1;
9396 624411d2 2023-07-08 jrick case 'r':
9397 624411d2 2023-07-08 jrick repo_path = realpath(optarg, NULL);
9398 624411d2 2023-07-08 jrick if (repo_path == NULL)
9399 624411d2 2023-07-08 jrick return got_error_from_errno2("realpath",
9401 624411d2 2023-07-08 jrick got_path_strip_trailing_slashes(repo_path);
9403 624411d2 2023-07-08 jrick case 'T':
9404 624411d2 2023-07-08 jrick send_all_tags = 1;
9406 624411d2 2023-07-08 jrick case 't':
9407 624411d2 2023-07-08 jrick error = got_pathlist_append(&tags, optarg, NULL);
9408 624411d2 2023-07-08 jrick if (error)
9409 624411d2 2023-07-08 jrick return error;
9411 624411d2 2023-07-08 jrick case 'v':
9412 624411d2 2023-07-08 jrick if (verbosity < 0)
9413 624411d2 2023-07-08 jrick verbosity = 0;
9414 624411d2 2023-07-08 jrick else if (verbosity < 3)
9415 624411d2 2023-07-08 jrick verbosity++;
9418 624411d2 2023-07-08 jrick usage_send();
9419 624411d2 2023-07-08 jrick /* NOTREACHED */
9422 624411d2 2023-07-08 jrick argc -= optind;
9423 624411d2 2023-07-08 jrick argv += optind;
9425 624411d2 2023-07-08 jrick if (send_all_branches && !TAILQ_EMPTY(&branches))
9426 624411d2 2023-07-08 jrick option_conflict('a', 'b');
9427 624411d2 2023-07-08 jrick if (send_all_tags && !TAILQ_EMPTY(&tags))
9428 624411d2 2023-07-08 jrick option_conflict('T', 't');
9431 624411d2 2023-07-08 jrick if (argc == 0)
9432 624411d2 2023-07-08 jrick remote_name = GOT_SEND_DEFAULT_REMOTE_NAME;
9433 624411d2 2023-07-08 jrick else if (argc == 1)
9434 624411d2 2023-07-08 jrick remote_name = argv[0];
9436 624411d2 2023-07-08 jrick usage_send();
9438 624411d2 2023-07-08 jrick cwd = getcwd(NULL, 0);
9439 624411d2 2023-07-08 jrick if (cwd == NULL) {
9440 624411d2 2023-07-08 jrick error = got_error_from_errno("getcwd");
9441 624411d2 2023-07-08 jrick goto done;
9444 624411d2 2023-07-08 jrick error = got_repo_pack_fds_open(&pack_fds);
9445 624411d2 2023-07-08 jrick if (error != NULL)
9446 624411d2 2023-07-08 jrick goto done;
9448 624411d2 2023-07-08 jrick if (repo_path == NULL) {
9449 624411d2 2023-07-08 jrick error = got_worktree_open(&worktree, cwd);
9450 624411d2 2023-07-08 jrick if (error && error->code != GOT_ERR_NOT_WORKTREE)
9451 624411d2 2023-07-08 jrick goto done;
9453 624411d2 2023-07-08 jrick error = NULL;
9454 624411d2 2023-07-08 jrick if (worktree) {
9455 624411d2 2023-07-08 jrick repo_path =
9456 624411d2 2023-07-08 jrick strdup(got_worktree_get_repo_path(worktree));
9457 624411d2 2023-07-08 jrick if (repo_path == NULL)
9458 624411d2 2023-07-08 jrick error = got_error_from_errno("strdup");
9459 624411d2 2023-07-08 jrick if (error)
9460 624411d2 2023-07-08 jrick goto done;
9462 624411d2 2023-07-08 jrick repo_path = strdup(cwd);
9463 624411d2 2023-07-08 jrick if (repo_path == NULL) {
9464 624411d2 2023-07-08 jrick error = got_error_from_errno("strdup");
9465 624411d2 2023-07-08 jrick goto done;
9470 624411d2 2023-07-08 jrick error = got_repo_open(&repo, repo_path, NULL, pack_fds);
9471 624411d2 2023-07-08 jrick if (error)
9472 624411d2 2023-07-08 jrick goto done;
9474 624411d2 2023-07-08 jrick if (worktree) {
9475 624411d2 2023-07-08 jrick worktree_conf = got_worktree_get_gotconfig(worktree);
9476 624411d2 2023-07-08 jrick if (worktree_conf) {
9477 624411d2 2023-07-08 jrick got_gotconfig_get_remotes(&nremotes, &remotes,
9478 624411d2 2023-07-08 jrick worktree_conf);
9479 624411d2 2023-07-08 jrick for (i = 0; i < nremotes; i++) {
9480 624411d2 2023-07-08 jrick if (strcmp(remotes[i].name, remote_name) == 0) {
9481 624411d2 2023-07-08 jrick remote = &remotes[i];
9487 624411d2 2023-07-08 jrick if (remote == NULL) {
9488 624411d2 2023-07-08 jrick repo_conf = got_repo_get_gotconfig(repo);
9489 624411d2 2023-07-08 jrick if (repo_conf) {
9490 624411d2 2023-07-08 jrick got_gotconfig_get_remotes(&nremotes, &remotes,
9491 624411d2 2023-07-08 jrick repo_conf);
9492 624411d2 2023-07-08 jrick for (i = 0; i < nremotes; i++) {
9493 624411d2 2023-07-08 jrick if (strcmp(remotes[i].name, remote_name) == 0) {
9494 624411d2 2023-07-08 jrick remote = &remotes[i];
9500 624411d2 2023-07-08 jrick if (remote == NULL) {
9501 624411d2 2023-07-08 jrick got_repo_get_gitconfig_remotes(&nremotes, &remotes, repo);
9502 624411d2 2023-07-08 jrick for (i = 0; i < nremotes; i++) {
9503 624411d2 2023-07-08 jrick if (strcmp(remotes[i].name, remote_name) == 0) {
9504 624411d2 2023-07-08 jrick remote = &remotes[i];
9509 624411d2 2023-07-08 jrick if (remote == NULL) {
9510 624411d2 2023-07-08 jrick error = got_error_path(remote_name, GOT_ERR_NO_REMOTE);
9511 624411d2 2023-07-08 jrick goto done;
9514 624411d2 2023-07-08 jrick error = got_dial_parse_uri(&proto, &host, &port, &server_path,
9515 624411d2 2023-07-08 jrick &repo_name, remote->send_url);
9516 624411d2 2023-07-08 jrick if (error)
9517 624411d2 2023-07-08 jrick goto done;
9519 624411d2 2023-07-08 jrick if (strcmp(proto, "git") == 0) {
9520 624411d2 2023-07-08 jrick #ifndef PROFILE
9521 624411d2 2023-07-08 jrick if (pledge("stdio rpath wpath cpath fattr flock proc exec "
9522 624411d2 2023-07-08 jrick "sendfd dns inet unveil", NULL) == -1)
9523 624411d2 2023-07-08 jrick err(1, "pledge");
9525 624411d2 2023-07-08 jrick } else if (strcmp(proto, "git+ssh") == 0 ||
9526 624411d2 2023-07-08 jrick strcmp(proto, "ssh") == 0) {
9527 624411d2 2023-07-08 jrick #ifndef PROFILE
9528 624411d2 2023-07-08 jrick if (pledge("stdio rpath wpath cpath fattr flock proc exec "
9529 624411d2 2023-07-08 jrick "sendfd unveil", NULL) == -1)
9530 624411d2 2023-07-08 jrick err(1, "pledge");
9532 624411d2 2023-07-08 jrick } else if (strcmp(proto, "http") == 0 ||
9533 624411d2 2023-07-08 jrick strcmp(proto, "git+http") == 0) {
9534 624411d2 2023-07-08 jrick error = got_error_path(proto, GOT_ERR_NOT_IMPL);
9535 624411d2 2023-07-08 jrick goto done;
9537 624411d2 2023-07-08 jrick error = got_error_path(proto, GOT_ERR_BAD_PROTO);
9538 624411d2 2023-07-08 jrick goto done;
9541 624411d2 2023-07-08 jrick error = got_dial_apply_unveil(proto);
9542 624411d2 2023-07-08 jrick if (error)
9543 624411d2 2023-07-08 jrick goto done;
9545 624411d2 2023-07-08 jrick error = apply_unveil(got_repo_get_path(repo), 0, NULL);
9546 624411d2 2023-07-08 jrick if (error)
9547 624411d2 2023-07-08 jrick goto done;
9549 624411d2 2023-07-08 jrick if (send_all_branches) {
9550 624411d2 2023-07-08 jrick error = got_ref_list(&all_branches, repo, "refs/heads",
9551 624411d2 2023-07-08 jrick got_ref_cmp_by_name, NULL);
9552 624411d2 2023-07-08 jrick if (error)
9553 624411d2 2023-07-08 jrick goto done;
9554 624411d2 2023-07-08 jrick TAILQ_FOREACH(re, &all_branches, entry) {
9555 624411d2 2023-07-08 jrick const char *branchname = got_ref_get_name(re->ref);
9556 624411d2 2023-07-08 jrick error = got_pathlist_append(&branches,
9557 624411d2 2023-07-08 jrick branchname, NULL);
9558 624411d2 2023-07-08 jrick if (error)
9559 624411d2 2023-07-08 jrick goto done;
9560 624411d2 2023-07-08 jrick nbranches++;
9562 624411d2 2023-07-08 jrick } else if (nbranches == 0) {
9563 624411d2 2023-07-08 jrick for (i = 0; i < remote->nsend_branches; i++) {
9564 624411d2 2023-07-08 jrick error = got_pathlist_append(&branches,
9565 624411d2 2023-07-08 jrick remote->send_branches[i], NULL);
9566 624411d2 2023-07-08 jrick if (error)
9567 624411d2 2023-07-08 jrick goto done;
9571 624411d2 2023-07-08 jrick if (send_all_tags) {
9572 624411d2 2023-07-08 jrick error = got_ref_list(&all_tags, repo, "refs/tags",
9573 624411d2 2023-07-08 jrick got_ref_cmp_by_name, NULL);
9574 624411d2 2023-07-08 jrick if (error)
9575 624411d2 2023-07-08 jrick goto done;
9576 624411d2 2023-07-08 jrick TAILQ_FOREACH(re, &all_tags, entry) {
9577 624411d2 2023-07-08 jrick const char *tagname = got_ref_get_name(re->ref);
9578 624411d2 2023-07-08 jrick error = got_pathlist_append(&tags,
9579 624411d2 2023-07-08 jrick tagname, NULL);
9580 624411d2 2023-07-08 jrick if (error)
9581 624411d2 2023-07-08 jrick goto done;
9586 624411d2 2023-07-08 jrick * To prevent accidents only branches in refs/heads/ can be deleted
9587 624411d2 2023-07-08 jrick * with 'got send -d'.
9588 624411d2 2023-07-08 jrick * Deleting anything else requires local repository access or Git.
9590 624411d2 2023-07-08 jrick TAILQ_FOREACH(pe, &delete_args, entry) {
9591 624411d2 2023-07-08 jrick const char *branchname = pe->path;
9593 624411d2 2023-07-08 jrick struct got_pathlist_entry *new;
9594 624411d2 2023-07-08 jrick if (strncmp(branchname, "refs/heads/", 11) == 0) {
9595 624411d2 2023-07-08 jrick s = strdup(branchname);
9596 624411d2 2023-07-08 jrick if (s == NULL) {
9597 624411d2 2023-07-08 jrick error = got_error_from_errno("strdup");
9598 624411d2 2023-07-08 jrick goto done;
9601 624411d2 2023-07-08 jrick if (asprintf(&s, "refs/heads/%s", branchname) == -1) {
9602 624411d2 2023-07-08 jrick error = got_error_from_errno("asprintf");
9603 624411d2 2023-07-08 jrick goto done;
9606 624411d2 2023-07-08 jrick error = got_pathlist_insert(&new, &delete_branches, s, NULL);
9607 624411d2 2023-07-08 jrick if (error || new == NULL /* duplicate */)
9609 624411d2 2023-07-08 jrick if (error)
9610 624411d2 2023-07-08 jrick goto done;
9611 624411d2 2023-07-08 jrick ndelete_branches++;
9614 624411d2 2023-07-08 jrick if (nbranches == 0 && ndelete_branches == 0) {
9615 624411d2 2023-07-08 jrick struct got_reference *head_ref;
9616 624411d2 2023-07-08 jrick if (worktree)
9617 624411d2 2023-07-08 jrick error = got_ref_open(&head_ref, repo,
9618 624411d2 2023-07-08 jrick got_worktree_get_head_ref_name(worktree), 0);
9620 624411d2 2023-07-08 jrick error = got_ref_open(&head_ref, repo, GOT_REF_HEAD, 0);
9621 624411d2 2023-07-08 jrick if (error)
9622 624411d2 2023-07-08 jrick goto done;
9623 624411d2 2023-07-08 jrick if (got_ref_is_symbolic(head_ref)) {
9624 624411d2 2023-07-08 jrick error = got_ref_resolve_symbolic(&ref, repo, head_ref);
9625 624411d2 2023-07-08 jrick got_ref_close(head_ref);
9626 624411d2 2023-07-08 jrick if (error)
9627 624411d2 2023-07-08 jrick goto done;
9629 624411d2 2023-07-08 jrick ref = head_ref;
9630 624411d2 2023-07-08 jrick error = got_pathlist_append(&branches, got_ref_get_name(ref),
9632 624411d2 2023-07-08 jrick if (error)
9633 624411d2 2023-07-08 jrick goto done;
9634 624411d2 2023-07-08 jrick nbranches++;
9637 624411d2 2023-07-08 jrick if (verbosity >= 0) {
9638 624411d2 2023-07-08 jrick printf("Connecting to \"%s\" %s://%s%s%s%s%s\n",
9639 624411d2 2023-07-08 jrick remote->name, proto, host,
9640 624411d2 2023-07-08 jrick port ? ":" : "", port ? port : "",
9641 624411d2 2023-07-08 jrick *server_path == '/' ? "" : "/", server_path);
9644 624411d2 2023-07-08 jrick error = got_send_connect(&sendpid, &sendfd, proto, host, port,
9645 624411d2 2023-07-08 jrick server_path, verbosity);
9646 624411d2 2023-07-08 jrick if (error)
9647 624411d2 2023-07-08 jrick goto done;
9649 624411d2 2023-07-08 jrick memset(&spa, 0, sizeof(spa));
9650 624411d2 2023-07-08 jrick spa.last_scaled_packsize[0] = '\0';
9651 624411d2 2023-07-08 jrick spa.last_p_deltify = -1;
9652 624411d2 2023-07-08 jrick spa.last_p_written = -1;
9653 624411d2 2023-07-08 jrick spa.verbosity = verbosity;
9654 624411d2 2023-07-08 jrick spa.delete_branches = &delete_branches;
9655 624411d2 2023-07-08 jrick error = got_send_pack(remote_name, &branches, &tags, &delete_branches,
9656 624411d2 2023-07-08 jrick verbosity, overwrite_refs, sendfd, repo, send_progress, &spa,
9657 624411d2 2023-07-08 jrick check_cancelled, NULL);
9658 624411d2 2023-07-08 jrick if (spa.printed_something)
9659 624411d2 2023-07-08 jrick putchar('\n');
9660 624411d2 2023-07-08 jrick if (error)
9661 624411d2 2023-07-08 jrick goto done;
9662 624411d2 2023-07-08 jrick if (!spa.sent_something && verbosity >= 0)
9663 624411d2 2023-07-08 jrick printf("Already up-to-date\n");
9665 624411d2 2023-07-08 jrick if (sendpid > 0) {
9666 624411d2 2023-07-08 jrick if (kill(sendpid, SIGTERM) == -1)
9667 624411d2 2023-07-08 jrick error = got_error_from_errno("kill");
9668 624411d2 2023-07-08 jrick if (waitpid(sendpid, &sendstatus, 0) == -1 && error == NULL)
9669 624411d2 2023-07-08 jrick error = got_error_from_errno("waitpid");
9671 624411d2 2023-07-08 jrick if (sendfd != -1 && close(sendfd) == -1 && error == NULL)
9672 624411d2 2023-07-08 jrick error = got_error_from_errno("close");
9673 624411d2 2023-07-08 jrick if (repo) {
9674 624411d2 2023-07-08 jrick const struct got_error *close_err = got_repo_close(repo);
9675 624411d2 2023-07-08 jrick if (error == NULL)
9676 624411d2 2023-07-08 jrick error = close_err;
9678 624411d2 2023-07-08 jrick if (worktree)
9679 624411d2 2023-07-08 jrick got_worktree_close(worktree);
9680 624411d2 2023-07-08 jrick if (pack_fds) {
9681 624411d2 2023-07-08 jrick const struct got_error *pack_err =
9682 624411d2 2023-07-08 jrick got_repo_pack_fds_close(pack_fds);
9683 624411d2 2023-07-08 jrick if (error == NULL)
9684 624411d2 2023-07-08 jrick error = pack_err;
9687 624411d2 2023-07-08 jrick got_ref_close(ref);
9688 624411d2 2023-07-08 jrick got_pathlist_free(&branches, GOT_PATHLIST_FREE_NONE);
9689 624411d2 2023-07-08 jrick got_pathlist_free(&tags, GOT_PATHLIST_FREE_NONE);
9690 624411d2 2023-07-08 jrick got_ref_list_free(&all_branches);
9691 624411d2 2023-07-08 jrick got_ref_list_free(&all_tags);
9692 624411d2 2023-07-08 jrick got_pathlist_free(&delete_args, GOT_PATHLIST_FREE_NONE);
9693 624411d2 2023-07-08 jrick got_pathlist_free(&delete_branches, GOT_PATHLIST_FREE_PATH);
9694 624411d2 2023-07-08 jrick free(cwd);
9695 624411d2 2023-07-08 jrick free(repo_path);
9696 624411d2 2023-07-08 jrick free(proto);
9697 624411d2 2023-07-08 jrick free(host);
9698 624411d2 2023-07-08 jrick free(port);
9699 624411d2 2023-07-08 jrick free(server_path);
9700 624411d2 2023-07-08 jrick free(repo_name);
9701 624411d2 2023-07-08 jrick return error;
9705 624411d2 2023-07-08 jrick * Print and if delete is set delete all ref_prefix references.
9706 624411d2 2023-07-08 jrick * If wanted_ref is not NULL, only print or delete this reference.
9708 624411d2 2023-07-08 jrick static const struct got_error *
9709 624411d2 2023-07-08 jrick process_logmsg_refs(const char *ref_prefix, size_t prefix_len,
9710 624411d2 2023-07-08 jrick const char *wanted_ref, int delete, struct got_worktree *worktree,
9711 624411d2 2023-07-08 jrick struct got_repository *repo)
9713 624411d2 2023-07-08 jrick const struct got_error *err;
9714 624411d2 2023-07-08 jrick struct got_pathlist_head paths;
9715 624411d2 2023-07-08 jrick struct got_reflist_head refs;
9716 624411d2 2023-07-08 jrick struct got_reflist_entry *re;
9717 624411d2 2023-07-08 jrick struct got_reflist_object_id_map *refs_idmap = NULL;
9718 624411d2 2023-07-08 jrick struct got_commit_object *commit = NULL;
9719 624411d2 2023-07-08 jrick struct got_object_id *id = NULL;
9720 624411d2 2023-07-08 jrick const char *header_prefix;
9721 624411d2 2023-07-08 jrick char *uuidstr = NULL;
9722 624411d2 2023-07-08 jrick int found = 0;
9724 624411d2 2023-07-08 jrick TAILQ_INIT(&refs);
9725 624411d2 2023-07-08 jrick TAILQ_INIT(&paths);
9727 624411d2 2023-07-08 jrick err = got_ref_list(&refs, repo, NULL, got_ref_cmp_by_name, repo);
9729 624411d2 2023-07-08 jrick goto done;
9731 624411d2 2023-07-08 jrick err = got_reflist_object_id_map_create(&refs_idmap, &refs, repo);
9733 624411d2 2023-07-08 jrick goto done;
9735 624411d2 2023-07-08 jrick if (worktree != NULL) {
9736 624411d2 2023-07-08 jrick err = got_worktree_get_uuid(&uuidstr, worktree);
9738 624411d2 2023-07-08 jrick goto done;
9741 624411d2 2023-07-08 jrick if (wanted_ref) {
9742 624411d2 2023-07-08 jrick if (strncmp(wanted_ref, "refs/heads/", 11) == 0)
9743 624411d2 2023-07-08 jrick wanted_ref += 11;
9746 624411d2 2023-07-08 jrick if (strcmp(ref_prefix, GOT_WORKTREE_BACKOUT_REF_PREFIX) == 0)
9747 624411d2 2023-07-08 jrick header_prefix = "backout";
9749 624411d2 2023-07-08 jrick header_prefix = "cherrypick";
9751 624411d2 2023-07-08 jrick TAILQ_FOREACH(re, &refs, entry) {
9752 624411d2 2023-07-08 jrick const char *refname, *wt;
9754 624411d2 2023-07-08 jrick refname = got_ref_get_name(re->ref);
9756 624411d2 2023-07-08 jrick err = check_cancelled(NULL);
9758 624411d2 2023-07-08 jrick goto done;
9760 624411d2 2023-07-08 jrick if (strncmp(refname, ref_prefix, prefix_len) == 0)
9761 624411d2 2023-07-08 jrick refname += prefix_len + 1; /* skip '-' delimiter */
9763 624411d2 2023-07-08 jrick continue;
9765 624411d2 2023-07-08 jrick wt = refname;
9767 624411d2 2023-07-08 jrick if (worktree == NULL || strncmp(refname, uuidstr,
9768 624411d2 2023-07-08 jrick GOT_WORKTREE_UUID_STRLEN) == 0)
9769 624411d2 2023-07-08 jrick refname += GOT_WORKTREE_UUID_STRLEN + 1; /* skip '-' */
9771 624411d2 2023-07-08 jrick continue;
9773 624411d2 2023-07-08 jrick err = got_repo_match_object_id(&id, NULL, refname,
9774 624411d2 2023-07-08 jrick GOT_OBJ_TYPE_COMMIT, NULL, repo);
9776 624411d2 2023-07-08 jrick goto done;
9778 624411d2 2023-07-08 jrick err = got_object_open_as_commit(&commit, repo, id);
9780 624411d2 2023-07-08 jrick goto done;
9782 624411d2 2023-07-08 jrick if (wanted_ref)
9783 624411d2 2023-07-08 jrick found = strncmp(wanted_ref, refname,
9784 624411d2 2023-07-08 jrick strlen(wanted_ref)) == 0;
9785 624411d2 2023-07-08 jrick if (wanted_ref && !found) {
9786 624411d2 2023-07-08 jrick struct got_reflist_head *ci_refs;
9788 624411d2 2023-07-08 jrick ci_refs = got_reflist_object_id_map_lookup(refs_idmap,
9791 624411d2 2023-07-08 jrick if (ci_refs) {
9792 624411d2 2023-07-08 jrick char *refs_str = NULL;
9793 624411d2 2023-07-08 jrick char const *r = NULL;
9795 624411d2 2023-07-08 jrick err = build_refs_str(&refs_str, ci_refs, id,
9796 624411d2 2023-07-08 jrick repo, 1);
9798 624411d2 2023-07-08 jrick goto done;
9800 624411d2 2023-07-08 jrick r = refs_str;
9801 624411d2 2023-07-08 jrick while (r) {
9802 624411d2 2023-07-08 jrick if (strncmp(r, wanted_ref,
9803 624411d2 2023-07-08 jrick strlen(wanted_ref)) == 0) {
9804 624411d2 2023-07-08 jrick found = 1;
9807 624411d2 2023-07-08 jrick r = strchr(r, ' ');
9811 624411d2 2023-07-08 jrick free(refs_str);
9815 624411d2 2023-07-08 jrick if (wanted_ref == NULL || found) {
9816 624411d2 2023-07-08 jrick if (delete) {
9817 624411d2 2023-07-08 jrick err = got_ref_delete(re->ref, repo);
9819 624411d2 2023-07-08 jrick goto done;
9820 624411d2 2023-07-08 jrick printf("Deleted: ");
9821 624411d2 2023-07-08 jrick err = print_commit_oneline(commit, id, repo,
9822 624411d2 2023-07-08 jrick refs_idmap);
9825 624411d2 2023-07-08 jrick * Print paths modified by commit to help
9826 624411d2 2023-07-08 jrick * associate commits with worktree changes.
9828 624411d2 2023-07-08 jrick err = get_changed_paths(&paths, commit,
9829 624411d2 2023-07-08 jrick repo, NULL);
9831 624411d2 2023-07-08 jrick goto done;
9833 624411d2 2023-07-08 jrick err = print_commit(commit, id, repo, NULL,
9834 624411d2 2023-07-08 jrick &paths, NULL, 0, 0, refs_idmap, NULL,
9835 624411d2 2023-07-08 jrick header_prefix);
9836 624411d2 2023-07-08 jrick got_pathlist_free(&paths,
9837 624411d2 2023-07-08 jrick GOT_PATHLIST_FREE_ALL);
9839 624411d2 2023-07-08 jrick if (worktree == NULL)
9840 624411d2 2023-07-08 jrick printf("work tree: %.*s\n\n",
9841 624411d2 2023-07-08 jrick GOT_WORKTREE_UUID_STRLEN, wt);
9843 624411d2 2023-07-08 jrick if (err || found)
9844 624411d2 2023-07-08 jrick goto done;
9847 624411d2 2023-07-08 jrick got_object_commit_close(commit);
9848 624411d2 2023-07-08 jrick commit = NULL;
9849 624411d2 2023-07-08 jrick free(id);
9850 624411d2 2023-07-08 jrick id = NULL;
9853 624411d2 2023-07-08 jrick if (wanted_ref != NULL && !found)
9854 624411d2 2023-07-08 jrick err = got_error_fmt(GOT_ERR_NOT_REF, "%s", wanted_ref);
9857 624411d2 2023-07-08 jrick free(id);
9858 624411d2 2023-07-08 jrick free(uuidstr);
9859 624411d2 2023-07-08 jrick got_ref_list_free(&refs);
9860 624411d2 2023-07-08 jrick got_pathlist_free(&paths, GOT_PATHLIST_FREE_ALL);
9861 624411d2 2023-07-08 jrick if (refs_idmap)
9862 624411d2 2023-07-08 jrick got_reflist_object_id_map_free(refs_idmap);
9863 624411d2 2023-07-08 jrick if (commit)
9864 624411d2 2023-07-08 jrick got_object_commit_close(commit);
9865 624411d2 2023-07-08 jrick return err;
9869 624411d2 2023-07-08 jrick * Create new temp "logmsg" ref of the backed-out or cherrypicked commit
9870 624411d2 2023-07-08 jrick * identified by id for log messages to prepopulate the editor on commit.
9872 624411d2 2023-07-08 jrick static const struct got_error *
9873 624411d2 2023-07-08 jrick logmsg_ref(struct got_object_id *id, const char *prefix,
9874 624411d2 2023-07-08 jrick struct got_worktree *worktree, struct got_repository *repo)
9876 624411d2 2023-07-08 jrick const struct got_error *err = NULL;
9877 624411d2 2023-07-08 jrick char *idstr, *ref = NULL, *refname = NULL;
9878 624411d2 2023-07-08 jrick int histedit_in_progress;
9879 624411d2 2023-07-08 jrick int rebase_in_progress, merge_in_progress;
9882 624411d2 2023-07-08 jrick * Silenty refuse to create merge reference if any histedit, merge,
9883 624411d2 2023-07-08 jrick * or rebase operation is in progress.
9885 624411d2 2023-07-08 jrick err = got_worktree_histedit_in_progress(&histedit_in_progress,
9886 624411d2 2023-07-08 jrick worktree);
9888 624411d2 2023-07-08 jrick return err;
9889 624411d2 2023-07-08 jrick if (histedit_in_progress)
9890 624411d2 2023-07-08 jrick return NULL;
9892 624411d2 2023-07-08 jrick err = got_worktree_rebase_in_progress(&rebase_in_progress, worktree);
9894 624411d2 2023-07-08 jrick return err;
9895 624411d2 2023-07-08 jrick if (rebase_in_progress)
9896 624411d2 2023-07-08 jrick return NULL;
9898 624411d2 2023-07-08 jrick err = got_worktree_merge_in_progress(&merge_in_progress, worktree,
9901 624411d2 2023-07-08 jrick return err;
9902 624411d2 2023-07-08 jrick if (merge_in_progress)
9903 624411d2 2023-07-08 jrick return NULL;
9905 624411d2 2023-07-08 jrick err = got_object_id_str(&idstr, id);
9907 624411d2 2023-07-08 jrick return err;
9909 624411d2 2023-07-08 jrick err = got_worktree_get_logmsg_ref_name(&refname, worktree, prefix);
9911 624411d2 2023-07-08 jrick goto done;
9913 624411d2 2023-07-08 jrick if (asprintf(&ref, "%s-%s", refname, idstr) == -1) {
9914 624411d2 2023-07-08 jrick err = got_error_from_errno("asprintf");
9915 624411d2 2023-07-08 jrick goto done;
9918 624411d2 2023-07-08 jrick err = create_ref(ref, got_worktree_get_base_commit_id(worktree),
9919 624411d2 2023-07-08 jrick -1, repo);
9921 624411d2 2023-07-08 jrick free(ref);
9922 624411d2 2023-07-08 jrick free(idstr);
9923 624411d2 2023-07-08 jrick free(refname);
9924 624411d2 2023-07-08 jrick return err;
9927 624411d2 2023-07-08 jrick __dead static void
9928 624411d2 2023-07-08 jrick usage_cherrypick(void)
9930 624411d2 2023-07-08 jrick fprintf(stderr, "usage: %s cherrypick [-lX] [commit-id]\n",
9931 624411d2 2023-07-08 jrick getprogname());
9935 624411d2 2023-07-08 jrick static const struct got_error *
9936 624411d2 2023-07-08 jrick cmd_cherrypick(int argc, char *argv[])
9938 624411d2 2023-07-08 jrick const struct got_error *error = NULL;
9939 624411d2 2023-07-08 jrick struct got_worktree *worktree = NULL;
9940 624411d2 2023-07-08 jrick struct got_repository *repo = NULL;
9941 624411d2 2023-07-08 jrick char *cwd = NULL, *commit_id_str = NULL;
9942 624411d2 2023-07-08 jrick struct got_object_id *commit_id = NULL;
9943 624411d2 2023-07-08 jrick struct got_commit_object *commit = NULL;
9944 624411d2 2023-07-08 jrick struct got_object_qid *pid;
9945 624411d2 2023-07-08 jrick int ch, list_refs = 0, remove_refs = 0;
9946 624411d2 2023-07-08 jrick struct got_update_progress_arg upa;
9947 624411d2 2023-07-08 jrick int *pack_fds = NULL;
9949 624411d2 2023-07-08 jrick #ifndef PROFILE
9950 624411d2 2023-07-08 jrick if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd "
9951 624411d2 2023-07-08 jrick "unveil", NULL) == -1)
9952 624411d2 2023-07-08 jrick err(1, "pledge");
9955 624411d2 2023-07-08 jrick while ((ch = getopt(argc, argv, "lX")) != -1) {
9956 624411d2 2023-07-08 jrick switch (ch) {
9957 624411d2 2023-07-08 jrick case 'l':
9958 624411d2 2023-07-08 jrick list_refs = 1;
9960 624411d2 2023-07-08 jrick case 'X':
9961 624411d2 2023-07-08 jrick remove_refs = 1;
9964 624411d2 2023-07-08 jrick usage_cherrypick();
9965 624411d2 2023-07-08 jrick /* NOTREACHED */
9969 624411d2 2023-07-08 jrick argc -= optind;
9970 624411d2 2023-07-08 jrick argv += optind;
9972 624411d2 2023-07-08 jrick if (list_refs || remove_refs) {
9973 624411d2 2023-07-08 jrick if (argc != 0 && argc != 1)
9974 624411d2 2023-07-08 jrick usage_cherrypick();
9975 624411d2 2023-07-08 jrick } else if (argc != 1)
9976 624411d2 2023-07-08 jrick usage_cherrypick();
9977 624411d2 2023-07-08 jrick if (list_refs && remove_refs)
9978 624411d2 2023-07-08 jrick option_conflict('l', 'X');
9980 624411d2 2023-07-08 jrick cwd = getcwd(NULL, 0);
9981 624411d2 2023-07-08 jrick if (cwd == NULL) {
9982 624411d2 2023-07-08 jrick error = got_error_from_errno("getcwd");
9983 624411d2 2023-07-08 jrick goto done;
9986 624411d2 2023-07-08 jrick error = got_repo_pack_fds_open(&pack_fds);
9987 624411d2 2023-07-08 jrick if (error != NULL)
9988 624411d2 2023-07-08 jrick goto done;
9990 624411d2 2023-07-08 jrick error = got_worktree_open(&worktree, cwd);
9991 624411d2 2023-07-08 jrick if (error) {
9992 624411d2 2023-07-08 jrick if (list_refs || remove_refs) {
9993 624411d2 2023-07-08 jrick if (error->code != GOT_ERR_NOT_WORKTREE)
9994 624411d2 2023-07-08 jrick goto done;
9996 624411d2 2023-07-08 jrick if (error->code == GOT_ERR_NOT_WORKTREE)
9997 624411d2 2023-07-08 jrick error = wrap_not_worktree_error(error,
9998 624411d2 2023-07-08 jrick "cherrypick", cwd);
9999 624411d2 2023-07-08 jrick goto done;
10003 624411d2 2023-07-08 jrick error = got_repo_open(&repo,
10004 624411d2 2023-07-08 jrick worktree ? got_worktree_get_repo_path(worktree) : cwd,
10005 624411d2 2023-07-08 jrick NULL, pack_fds);
10006 624411d2 2023-07-08 jrick if (error != NULL)
10007 624411d2 2023-07-08 jrick goto done;
10009 624411d2 2023-07-08 jrick error = apply_unveil(got_repo_get_path(repo), 0,
10010 624411d2 2023-07-08 jrick worktree ? got_worktree_get_root_path(worktree) : NULL);
10011 624411d2 2023-07-08 jrick if (error)
10012 624411d2 2023-07-08 jrick goto done;
10014 624411d2 2023-07-08 jrick if (list_refs || remove_refs) {
10015 624411d2 2023-07-08 jrick error = process_logmsg_refs(GOT_WORKTREE_CHERRYPICK_REF_PREFIX,
10016 624411d2 2023-07-08 jrick GOT_WORKTREE_CHERRYPICK_REF_PREFIX_LEN,
10017 624411d2 2023-07-08 jrick argc == 1 ? argv[0] : NULL, remove_refs, worktree, repo);
10018 624411d2 2023-07-08 jrick goto done;
10021 624411d2 2023-07-08 jrick error = got_repo_match_object_id(&commit_id, NULL, argv[0],
10022 624411d2 2023-07-08 jrick GOT_OBJ_TYPE_COMMIT, NULL, repo);
10023 624411d2 2023-07-08 jrick if (error)
10024 624411d2 2023-07-08 jrick goto done;
10025 624411d2 2023-07-08 jrick error = got_object_id_str(&commit_id_str, commit_id);
10026 624411d2 2023-07-08 jrick if (error)
10027 624411d2 2023-07-08 jrick goto done;
10029 624411d2 2023-07-08 jrick error = got_object_open_as_commit(&commit, repo, commit_id);
10030 624411d2 2023-07-08 jrick if (error)
10031 624411d2 2023-07-08 jrick goto done;
10032 624411d2 2023-07-08 jrick pid = STAILQ_FIRST(got_object_commit_get_parent_ids(commit));
10033 624411d2 2023-07-08 jrick memset(&upa, 0, sizeof(upa));
10034 624411d2 2023-07-08 jrick error = got_worktree_merge_files(worktree, pid ? &pid->id : NULL,
10035 624411d2 2023-07-08 jrick commit_id, repo, update_progress, &upa, check_cancelled,
10037 624411d2 2023-07-08 jrick if (error != NULL)
10038 624411d2 2023-07-08 jrick goto done;
10040 624411d2 2023-07-08 jrick if (upa.did_something) {
10041 624411d2 2023-07-08 jrick error = logmsg_ref(commit_id,
10042 624411d2 2023-07-08 jrick GOT_WORKTREE_CHERRYPICK_REF_PREFIX, worktree, repo);
10043 624411d2 2023-07-08 jrick if (error)
10044 624411d2 2023-07-08 jrick goto done;
10045 624411d2 2023-07-08 jrick printf("Merged commit %s\n", commit_id_str);
10047 624411d2 2023-07-08 jrick print_merge_progress_stats(&upa);
10049 624411d2 2023-07-08 jrick free(cwd);
10050 624411d2 2023-07-08 jrick if (commit)
10051 624411d2 2023-07-08 jrick got_object_commit_close(commit);
10052 624411d2 2023-07-08 jrick free(commit_id_str);
10053 624411d2 2023-07-08 jrick if (worktree)
10054 624411d2 2023-07-08 jrick got_worktree_close(worktree);
10055 624411d2 2023-07-08 jrick if (repo) {
10056 624411d2 2023-07-08 jrick const struct got_error *close_err = got_repo_close(repo);
10057 624411d2 2023-07-08 jrick if (error == NULL)
10058 624411d2 2023-07-08 jrick error = close_err;
10060 624411d2 2023-07-08 jrick if (pack_fds) {
10061 624411d2 2023-07-08 jrick const struct got_error *pack_err =
10062 624411d2 2023-07-08 jrick got_repo_pack_fds_close(pack_fds);
10063 624411d2 2023-07-08 jrick if (error == NULL)
10064 624411d2 2023-07-08 jrick error = pack_err;
10067 624411d2 2023-07-08 jrick return error;
10070 624411d2 2023-07-08 jrick __dead static void
10071 624411d2 2023-07-08 jrick usage_backout(void)
10073 624411d2 2023-07-08 jrick fprintf(stderr, "usage: %s backout [-lX] [commit-id]\n", getprogname());
10074 624411d2 2023-07-08 jrick exit(1);
10077 624411d2 2023-07-08 jrick static const struct got_error *
10078 624411d2 2023-07-08 jrick cmd_backout(int argc, char *argv[])
10080 624411d2 2023-07-08 jrick const struct got_error *error = NULL;
10081 624411d2 2023-07-08 jrick struct got_worktree *worktree = NULL;
10082 624411d2 2023-07-08 jrick struct got_repository *repo = NULL;
10083 624411d2 2023-07-08 jrick char *cwd = NULL, *commit_id_str = NULL;
10084 624411d2 2023-07-08 jrick struct got_object_id *commit_id = NULL;
10085 624411d2 2023-07-08 jrick struct got_commit_object *commit = NULL;
10086 624411d2 2023-07-08 jrick struct got_object_qid *pid;
10087 624411d2 2023-07-08 jrick int ch, list_refs = 0, remove_refs = 0;
10088 624411d2 2023-07-08 jrick struct got_update_progress_arg upa;
10089 624411d2 2023-07-08 jrick int *pack_fds = NULL;
10091 624411d2 2023-07-08 jrick #ifndef PROFILE
10092 624411d2 2023-07-08 jrick if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd "
10093 624411d2 2023-07-08 jrick "unveil", NULL) == -1)
10094 624411d2 2023-07-08 jrick err(1, "pledge");
10097 624411d2 2023-07-08 jrick while ((ch = getopt(argc, argv, "lX")) != -1) {
10098 624411d2 2023-07-08 jrick switch (ch) {
10099 624411d2 2023-07-08 jrick case 'l':
10100 624411d2 2023-07-08 jrick list_refs = 1;
10102 624411d2 2023-07-08 jrick case 'X':
10103 624411d2 2023-07-08 jrick remove_refs = 1;
10105 624411d2 2023-07-08 jrick default:
10106 624411d2 2023-07-08 jrick usage_backout();
10107 624411d2 2023-07-08 jrick /* NOTREACHED */
10111 624411d2 2023-07-08 jrick argc -= optind;
10112 624411d2 2023-07-08 jrick argv += optind;
10114 624411d2 2023-07-08 jrick if (list_refs || remove_refs) {
10115 624411d2 2023-07-08 jrick if (argc != 0 && argc != 1)
10116 624411d2 2023-07-08 jrick usage_backout();
10117 624411d2 2023-07-08 jrick } else if (argc != 1)
10118 624411d2 2023-07-08 jrick usage_backout();
10119 624411d2 2023-07-08 jrick if (list_refs && remove_refs)
10120 624411d2 2023-07-08 jrick option_conflict('l', 'X');
10122 624411d2 2023-07-08 jrick cwd = getcwd(NULL, 0);
10123 624411d2 2023-07-08 jrick if (cwd == NULL) {
10124 624411d2 2023-07-08 jrick error = got_error_from_errno("getcwd");
10125 624411d2 2023-07-08 jrick goto done;
10128 624411d2 2023-07-08 jrick error = got_repo_pack_fds_open(&pack_fds);
10129 624411d2 2023-07-08 jrick if (error != NULL)
10130 624411d2 2023-07-08 jrick goto done;
10132 624411d2 2023-07-08 jrick error = got_worktree_open(&worktree, cwd);
10133 624411d2 2023-07-08 jrick if (error) {
10134 624411d2 2023-07-08 jrick if (list_refs || remove_refs) {
10135 624411d2 2023-07-08 jrick if (error->code != GOT_ERR_NOT_WORKTREE)
10136 624411d2 2023-07-08 jrick goto done;
10137 624411d2 2023-07-08 jrick } else {
10138 624411d2 2023-07-08 jrick if (error->code == GOT_ERR_NOT_WORKTREE)
10139 624411d2 2023-07-08 jrick error = wrap_not_worktree_error(error,
10140 624411d2 2023-07-08 jrick "backout", cwd);
10141 624411d2 2023-07-08 jrick goto done;
10145 624411d2 2023-07-08 jrick error = got_repo_open(&repo,
10146 624411d2 2023-07-08 jrick worktree ? got_worktree_get_repo_path(worktree) : cwd,
10147 624411d2 2023-07-08 jrick NULL, pack_fds);
10148 624411d2 2023-07-08 jrick if (error != NULL)
10149 624411d2 2023-07-08 jrick goto done;
10151 624411d2 2023-07-08 jrick error = apply_unveil(got_repo_get_path(repo), 0,
10152 624411d2 2023-07-08 jrick worktree ? got_worktree_get_root_path(worktree) : NULL);
10153 624411d2 2023-07-08 jrick if (error)
10154 624411d2 2023-07-08 jrick goto done;
10156 624411d2 2023-07-08 jrick if (list_refs || remove_refs) {
10157 624411d2 2023-07-08 jrick error = process_logmsg_refs(GOT_WORKTREE_BACKOUT_REF_PREFIX,
10158 624411d2 2023-07-08 jrick GOT_WORKTREE_BACKOUT_REF_PREFIX_LEN,
10159 624411d2 2023-07-08 jrick argc == 1 ? argv[0] : NULL, remove_refs, worktree, repo);
10160 624411d2 2023-07-08 jrick goto done;
10163 624411d2 2023-07-08 jrick error = got_repo_match_object_id(&commit_id, NULL, argv[0],
10164 624411d2 2023-07-08 jrick GOT_OBJ_TYPE_COMMIT, NULL, repo);
10165 624411d2 2023-07-08 jrick if (error)
10166 624411d2 2023-07-08 jrick goto done;
10167 624411d2 2023-07-08 jrick error = got_object_id_str(&commit_id_str, commit_id);
10168 624411d2 2023-07-08 jrick if (error)
10169 624411d2 2023-07-08 jrick goto done;
10171 624411d2 2023-07-08 jrick error = got_object_open_as_commit(&commit, repo, commit_id);
10172 624411d2 2023-07-08 jrick if (error)
10173 624411d2 2023-07-08 jrick goto done;
10174 624411d2 2023-07-08 jrick pid = STAILQ_FIRST(got_object_commit_get_parent_ids(commit));
10175 624411d2 2023-07-08 jrick if (pid == NULL) {
10176 624411d2 2023-07-08 jrick error = got_error(GOT_ERR_ROOT_COMMIT);
10177 624411d2 2023-07-08 jrick goto done;
10180 624411d2 2023-07-08 jrick memset(&upa, 0, sizeof(upa));
10181 624411d2 2023-07-08 jrick error = got_worktree_merge_files(worktree, commit_id, &pid->id,
10182 624411d2 2023-07-08 jrick repo, update_progress, &upa, check_cancelled, NULL);
10183 624411d2 2023-07-08 jrick if (error != NULL)
10184 624411d2 2023-07-08 jrick goto done;
10186 624411d2 2023-07-08 jrick if (upa.did_something) {
10187 624411d2 2023-07-08 jrick error = logmsg_ref(commit_id, GOT_WORKTREE_BACKOUT_REF_PREFIX,
10188 624411d2 2023-07-08 jrick worktree, repo);
10189 624411d2 2023-07-08 jrick if (error)
10190 624411d2 2023-07-08 jrick goto done;
10191 624411d2 2023-07-08 jrick printf("Backed out commit %s\n", commit_id_str);
10193 624411d2 2023-07-08 jrick print_merge_progress_stats(&upa);
10195 624411d2 2023-07-08 jrick free(cwd);
10196 624411d2 2023-07-08 jrick if (commit)
10197 624411d2 2023-07-08 jrick got_object_commit_close(commit);
10198 624411d2 2023-07-08 jrick free(commit_id_str);
10199 624411d2 2023-07-08 jrick if (worktree)
10200 624411d2 2023-07-08 jrick got_worktree_close(worktree);
10201 624411d2 2023-07-08 jrick if (repo) {
10202 624411d2 2023-07-08 jrick const struct got_error *close_err = got_repo_close(repo);
10203 624411d2 2023-07-08 jrick if (error == NULL)
10204 624411d2 2023-07-08 jrick error = close_err;
10206 624411d2 2023-07-08 jrick if (pack_fds) {
10207 624411d2 2023-07-08 jrick const struct got_error *pack_err =
10208 624411d2 2023-07-08 jrick got_repo_pack_fds_close(pack_fds);
10209 624411d2 2023-07-08 jrick if (error == NULL)
10210 624411d2 2023-07-08 jrick error = pack_err;
10212 624411d2 2023-07-08 jrick return error;
10215 624411d2 2023-07-08 jrick __dead static void
10216 624411d2 2023-07-08 jrick usage_rebase(void)
10218 624411d2 2023-07-08 jrick fprintf(stderr, "usage: %s rebase [-aCclX] [branch]\n", getprogname());
10219 624411d2 2023-07-08 jrick exit(1);
10222 624411d2 2023-07-08 jrick static void
10223 624411d2 2023-07-08 jrick trim_logmsg(char *logmsg, int limit)
10225 624411d2 2023-07-08 jrick char *nl;
10226 624411d2 2023-07-08 jrick size_t len;
10228 624411d2 2023-07-08 jrick len = strlen(logmsg);
10229 624411d2 2023-07-08 jrick if (len > limit)
10230 624411d2 2023-07-08 jrick len = limit;
10231 624411d2 2023-07-08 jrick logmsg[len] = '\0';
10232 624411d2 2023-07-08 jrick nl = strchr(logmsg, '\n');
10234 624411d2 2023-07-08 jrick *nl = '\0';
10237 624411d2 2023-07-08 jrick static const struct got_error *
10238 624411d2 2023-07-08 jrick get_short_logmsg(char **logmsg, int limit, struct got_commit_object *commit)
10240 624411d2 2023-07-08 jrick const struct got_error *err;
10241 624411d2 2023-07-08 jrick char *logmsg0 = NULL;
10242 624411d2 2023-07-08 jrick const char *s;
10244 624411d2 2023-07-08 jrick err = got_object_commit_get_logmsg(&logmsg0, commit);
10245 624411d2 2023-07-08 jrick if (err)
10246 624411d2 2023-07-08 jrick return err;
10248 624411d2 2023-07-08 jrick s = logmsg0;
10249 624411d2 2023-07-08 jrick while (isspace((unsigned char)s[0]))
10252 624411d2 2023-07-08 jrick *logmsg = strdup(s);
10253 624411d2 2023-07-08 jrick if (*logmsg == NULL) {
10254 624411d2 2023-07-08 jrick err = got_error_from_errno("strdup");
10255 624411d2 2023-07-08 jrick goto done;
10258 624411d2 2023-07-08 jrick trim_logmsg(*logmsg, limit);
10260 624411d2 2023-07-08 jrick free(logmsg0);
10261 624411d2 2023-07-08 jrick return err;
10264 624411d2 2023-07-08 jrick static const struct got_error *
10265 624411d2 2023-07-08 jrick show_rebase_merge_conflict(struct got_object_id *id,
10266 624411d2 2023-07-08 jrick struct got_repository *repo)
10268 624411d2 2023-07-08 jrick const struct got_error *err;
10269 624411d2 2023-07-08 jrick struct got_commit_object *commit = NULL;
10270 624411d2 2023-07-08 jrick char *id_str = NULL, *logmsg = NULL;
10272 624411d2 2023-07-08 jrick err = got_object_open_as_commit(&commit, repo, id);
10273 624411d2 2023-07-08 jrick if (err)
10274 624411d2 2023-07-08 jrick return err;
10276 624411d2 2023-07-08 jrick err = got_object_id_str(&id_str, id);
10277 624411d2 2023-07-08 jrick if (err)
10278 624411d2 2023-07-08 jrick goto done;
10280 624411d2 2023-07-08 jrick id_str[12] = '\0';
10282 624411d2 2023-07-08 jrick err = get_short_logmsg(&logmsg, 42, commit);
10283 624411d2 2023-07-08 jrick if (err)
10284 624411d2 2023-07-08 jrick goto done;
10286 624411d2 2023-07-08 jrick printf("%s -> merge conflict: %s\n", id_str, logmsg);
10288 624411d2 2023-07-08 jrick free(id_str);
10289 624411d2 2023-07-08 jrick got_object_commit_close(commit);
10290 624411d2 2023-07-08 jrick free(logmsg);
10291 624411d2 2023-07-08 jrick return err;
10294 624411d2 2023-07-08 jrick static const struct got_error *
10295 624411d2 2023-07-08 jrick show_rebase_progress(struct got_commit_object *commit,
10296 624411d2 2023-07-08 jrick struct got_object_id *old_id, struct got_object_id *new_id)
10298 624411d2 2023-07-08 jrick const struct got_error *err;
10299 624411d2 2023-07-08 jrick char *old_id_str = NULL, *new_id_str = NULL, *logmsg = NULL;
10301 624411d2 2023-07-08 jrick err = got_object_id_str(&old_id_str, old_id);
10302 624411d2 2023-07-08 jrick if (err)
10303 624411d2 2023-07-08 jrick goto done;
10305 624411d2 2023-07-08 jrick if (new_id) {
10306 624411d2 2023-07-08 jrick err = got_object_id_str(&new_id_str, new_id);
10307 624411d2 2023-07-08 jrick if (err)
10308 624411d2 2023-07-08 jrick goto done;
10311 624411d2 2023-07-08 jrick old_id_str[12] = '\0';
10312 624411d2 2023-07-08 jrick if (new_id_str)
10313 624411d2 2023-07-08 jrick new_id_str[12] = '\0';
10315 624411d2 2023-07-08 jrick err = get_short_logmsg(&logmsg, 42, commit);
10316 624411d2 2023-07-08 jrick if (err)
10317 624411d2 2023-07-08 jrick goto done;
10319 624411d2 2023-07-08 jrick printf("%s -> %s: %s\n", old_id_str,
10320 624411d2 2023-07-08 jrick new_id_str ? new_id_str : "no-op change", logmsg);
10322 624411d2 2023-07-08 jrick free(old_id_str);
10323 624411d2 2023-07-08 jrick free(new_id_str);
10324 624411d2 2023-07-08 jrick free(logmsg);
10325 624411d2 2023-07-08 jrick return err;
10328 624411d2 2023-07-08 jrick static const struct got_error *
10329 624411d2 2023-07-08 jrick rebase_complete(struct got_worktree *worktree, struct got_fileindex *fileindex,
10330 624411d2 2023-07-08 jrick struct got_reference *branch, struct got_reference *tmp_branch,
10331 624411d2 2023-07-08 jrick struct got_repository *repo, int create_backup)
10333 624411d2 2023-07-08 jrick printf("Switching work tree to %s\n", got_ref_get_name(branch));
10334 624411d2 2023-07-08 jrick return got_worktree_rebase_complete(worktree, fileindex,
10335 624411d2 2023-07-08 jrick tmp_branch, branch, repo, create_backup);
10338 624411d2 2023-07-08 jrick static const struct got_error *
10339 624411d2 2023-07-08 jrick rebase_commit(struct got_pathlist_head *merged_paths,
10340 624411d2 2023-07-08 jrick struct got_worktree *worktree, struct got_fileindex *fileindex,
10341 624411d2 2023-07-08 jrick struct got_reference *tmp_branch, const char *committer,
10342 624411d2 2023-07-08 jrick struct got_object_id *commit_id, int allow_conflict,
10343 624411d2 2023-07-08 jrick struct got_repository *repo)
10345 624411d2 2023-07-08 jrick const struct got_error *error;
10346 624411d2 2023-07-08 jrick struct got_commit_object *commit;
10347 624411d2 2023-07-08 jrick struct got_object_id *new_commit_id;
10349 624411d2 2023-07-08 jrick error = got_object_open_as_commit(&commit, repo, commit_id);
10350 624411d2 2023-07-08 jrick if (error)
10351 624411d2 2023-07-08 jrick return error;
10353 624411d2 2023-07-08 jrick error = got_worktree_rebase_commit(&new_commit_id, merged_paths,
10354 624411d2 2023-07-08 jrick worktree, fileindex, tmp_branch, committer, commit, commit_id,
10355 624411d2 2023-07-08 jrick allow_conflict, repo);
10356 624411d2 2023-07-08 jrick if (error) {
10357 624411d2 2023-07-08 jrick if (error->code != GOT_ERR_COMMIT_NO_CHANGES)
10358 624411d2 2023-07-08 jrick goto done;
10359 624411d2 2023-07-08 jrick error = show_rebase_progress(commit, commit_id, NULL);
10360 624411d2 2023-07-08 jrick } else {
10361 624411d2 2023-07-08 jrick error = show_rebase_progress(commit, commit_id, new_commit_id);
10362 624411d2 2023-07-08 jrick free(new_commit_id);
10365 624411d2 2023-07-08 jrick got_object_commit_close(commit);
10366 624411d2 2023-07-08 jrick return error;
10369 624411d2 2023-07-08 jrick struct check_path_prefix_arg {
10370 624411d2 2023-07-08 jrick const char *path_prefix;
10371 624411d2 2023-07-08 jrick size_t len;
10372 624411d2 2023-07-08 jrick int errcode;
10375 624411d2 2023-07-08 jrick static const struct got_error *
10376 624411d2 2023-07-08 jrick check_path_prefix_in_diff(void *arg, struct got_blob_object *blob1,
10377 624411d2 2023-07-08 jrick struct got_blob_object *blob2, FILE *f1, FILE *f2,
10378 624411d2 2023-07-08 jrick struct got_object_id *id1, struct got_object_id *id2,
10379 624411d2 2023-07-08 jrick const char *path1, const char *path2,
10380 624411d2 2023-07-08 jrick mode_t mode1, mode_t mode2, struct got_repository *repo)
10382 624411d2 2023-07-08 jrick struct check_path_prefix_arg *a = arg;
10384 624411d2 2023-07-08 jrick if ((path1 && !got_path_is_child(path1, a->path_prefix, a->len)) ||
10385 624411d2 2023-07-08 jrick (path2 && !got_path_is_child(path2, a->path_prefix, a->len)))
10386 624411d2 2023-07-08 jrick return got_error(a->errcode);
10388 624411d2 2023-07-08 jrick return NULL;
10391 624411d2 2023-07-08 jrick static const struct got_error *
10392 624411d2 2023-07-08 jrick check_path_prefix(struct got_object_id *parent_id,
10393 624411d2 2023-07-08 jrick struct got_object_id *commit_id, const char *path_prefix,
10394 624411d2 2023-07-08 jrick int errcode, struct got_repository *repo)
10396 624411d2 2023-07-08 jrick const struct got_error *err;
10397 624411d2 2023-07-08 jrick struct got_tree_object *tree1 = NULL, *tree2 = NULL;
10398 624411d2 2023-07-08 jrick struct got_commit_object *commit = NULL, *parent_commit = NULL;
10399 624411d2 2023-07-08 jrick struct check_path_prefix_arg cpp_arg;
10401 624411d2 2023-07-08 jrick if (got_path_is_root_dir(path_prefix))
10402 624411d2 2023-07-08 jrick return NULL;
10404 624411d2 2023-07-08 jrick err = got_object_open_as_commit(&commit, repo, commit_id);
10405 624411d2 2023-07-08 jrick if (err)
10406 624411d2 2023-07-08 jrick goto done;
10408 624411d2 2023-07-08 jrick err = got_object_open_as_commit(&parent_commit, repo, parent_id);
10409 624411d2 2023-07-08 jrick if (err)
10410 624411d2 2023-07-08 jrick goto done;
10412 624411d2 2023-07-08 jrick err = got_object_open_as_tree(&tree1, repo,
10413 624411d2 2023-07-08 jrick got_object_commit_get_tree_id(parent_commit));
10414 624411d2 2023-07-08 jrick if (err)
10415 624411d2 2023-07-08 jrick goto done;
10417 624411d2 2023-07-08 jrick err = got_object_open_as_tree(&tree2, repo,
10418 624411d2 2023-07-08 jrick got_object_commit_get_tree_id(commit));
10419 624411d2 2023-07-08 jrick if (err)
10420 624411d2 2023-07-08 jrick goto done;
10422 624411d2 2023-07-08 jrick cpp_arg.path_prefix = path_prefix;
10423 624411d2 2023-07-08 jrick while (cpp_arg.path_prefix[0] == '/')
10424 624411d2 2023-07-08 jrick cpp_arg.path_prefix++;
10425 624411d2 2023-07-08 jrick cpp_arg.len = strlen(cpp_arg.path_prefix);
10426 624411d2 2023-07-08 jrick cpp_arg.errcode = errcode;
10427 624411d2 2023-07-08 jrick err = got_diff_tree(tree1, tree2, NULL, NULL, -1, -1, "", "", repo,
10428 624411d2 2023-07-08 jrick check_path_prefix_in_diff, &cpp_arg, 0);
10430 624411d2 2023-07-08 jrick if (tree1)
10431 624411d2 2023-07-08 jrick got_object_tree_close(tree1);
10432 624411d2 2023-07-08 jrick if (tree2)
10433 624411d2 2023-07-08 jrick got_object_tree_close(tree2);
10434 624411d2 2023-07-08 jrick if (commit)
10435 624411d2 2023-07-08 jrick got_object_commit_close(commit);
10436 624411d2 2023-07-08 jrick if (parent_commit)
10437 624411d2 2023-07-08 jrick got_object_commit_close(parent_commit);
10438 624411d2 2023-07-08 jrick return err;
10441 624411d2 2023-07-08 jrick static const struct got_error *
10442 624411d2 2023-07-08 jrick collect_commits(struct got_object_id_queue *commits,
10443 624411d2 2023-07-08 jrick struct got_object_id *initial_commit_id,
10444 624411d2 2023-07-08 jrick struct got_object_id *iter_start_id, struct got_object_id *iter_stop_id,
10445 624411d2 2023-07-08 jrick const char *path_prefix, int path_prefix_errcode,
10446 624411d2 2023-07-08 jrick struct got_repository *repo)
10448 624411d2 2023-07-08 jrick const struct got_error *err = NULL;
10449 624411d2 2023-07-08 jrick struct got_commit_graph *graph = NULL;
10450 624411d2 2023-07-08 jrick struct got_object_id parent_id, commit_id;
10451 624411d2 2023-07-08 jrick struct got_object_qid *qid;
10453 624411d2 2023-07-08 jrick err = got_commit_graph_open(&graph, "/", 1);
10454 624411d2 2023-07-08 jrick if (err)
10455 624411d2 2023-07-08 jrick return err;
10457 624411d2 2023-07-08 jrick err = got_commit_graph_iter_start(graph, iter_start_id, repo,
10458 624411d2 2023-07-08 jrick check_cancelled, NULL);
10459 624411d2 2023-07-08 jrick if (err)
10460 624411d2 2023-07-08 jrick goto done;
10462 624411d2 2023-07-08 jrick memcpy(&commit_id, initial_commit_id, sizeof(commit_id));
10463 624411d2 2023-07-08 jrick while (got_object_id_cmp(&commit_id, iter_stop_id) != 0) {
10464 624411d2 2023-07-08 jrick err = got_commit_graph_iter_next(&parent_id, graph, repo,
10465 624411d2 2023-07-08 jrick check_cancelled, NULL);
10466 624411d2 2023-07-08 jrick if (err) {
10467 624411d2 2023-07-08 jrick if (err->code == GOT_ERR_ITER_COMPLETED) {
10468 624411d2 2023-07-08 jrick err = got_error_msg(GOT_ERR_ANCESTRY,
10469 624411d2 2023-07-08 jrick "ran out of commits to rebase before "
10470 624411d2 2023-07-08 jrick "youngest common ancestor commit has "
10471 624411d2 2023-07-08 jrick "been reached?!?");
10473 624411d2 2023-07-08 jrick goto done;
10474 624411d2 2023-07-08 jrick } else {
10475 624411d2 2023-07-08 jrick err = check_path_prefix(&parent_id, &commit_id,
10476 624411d2 2023-07-08 jrick path_prefix, path_prefix_errcode, repo);
10477 624411d2 2023-07-08 jrick if (err)
10478 624411d2 2023-07-08 jrick goto done;
10480 624411d2 2023-07-08 jrick err = got_object_qid_alloc(&qid, &commit_id);
10481 624411d2 2023-07-08 jrick if (err)
10482 624411d2 2023-07-08 jrick goto done;
10483 624411d2 2023-07-08 jrick STAILQ_INSERT_HEAD(commits, qid, entry);
10485 624411d2 2023-07-08 jrick memcpy(&commit_id, &parent_id, sizeof(commit_id));
10489 624411d2 2023-07-08 jrick got_commit_graph_close(graph);
10490 624411d2 2023-07-08 jrick return err;
10493 624411d2 2023-07-08 jrick static const struct got_error *
10494 624411d2 2023-07-08 jrick get_commit_brief_str(char **brief_str, struct got_commit_object *commit)
10496 624411d2 2023-07-08 jrick const struct got_error *err = NULL;
10497 624411d2 2023-07-08 jrick time_t committer_time;
10498 624411d2 2023-07-08 jrick struct tm tm;
10499 624411d2 2023-07-08 jrick char datebuf[11]; /* YYYY-MM-DD + NUL */
10500 624411d2 2023-07-08 jrick char *author0 = NULL, *author, *smallerthan;
10501 624411d2 2023-07-08 jrick char *logmsg0 = NULL, *logmsg, *newline;
10503 624411d2 2023-07-08 jrick committer_time = got_object_commit_get_committer_time(commit);
10504 624411d2 2023-07-08 jrick if (gmtime_r(&committer_time, &tm) == NULL)
10505 624411d2 2023-07-08 jrick return got_error_from_errno("gmtime_r");
10506 624411d2 2023-07-08 jrick if (strftime(datebuf, sizeof(datebuf), "%G-%m-%d", &tm) == 0)
10507 624411d2 2023-07-08 jrick return got_error(GOT_ERR_NO_SPACE);
10509 624411d2 2023-07-08 jrick author0 = strdup(got_object_commit_get_author(commit));
10510 624411d2 2023-07-08 jrick if (author0 == NULL)
10511 624411d2 2023-07-08 jrick return got_error_from_errno("strdup");
10512 624411d2 2023-07-08 jrick author = author0;
10513 624411d2 2023-07-08 jrick smallerthan = strchr(author, '<');
10514 624411d2 2023-07-08 jrick if (smallerthan && smallerthan[1] != '\0')
10515 624411d2 2023-07-08 jrick author = smallerthan + 1;
10516 624411d2 2023-07-08 jrick author[strcspn(author, "@>")] = '\0';
10518 624411d2 2023-07-08 jrick err = got_object_commit_get_logmsg(&logmsg0, commit);
10519 624411d2 2023-07-08 jrick if (err)
10520 624411d2 2023-07-08 jrick goto done;
10521 624411d2 2023-07-08 jrick logmsg = logmsg0;
10522 624411d2 2023-07-08 jrick while (*logmsg == '\n')
10523 624411d2 2023-07-08 jrick logmsg++;
10524 624411d2 2023-07-08 jrick newline = strchr(logmsg, '\n');
10525 624411d2 2023-07-08 jrick if (newline)
10526 624411d2 2023-07-08 jrick *newline = '\0';
10528 624411d2 2023-07-08 jrick if (asprintf(brief_str, "%s %s %s",
10529 624411d2 2023-07-08 jrick datebuf, author, logmsg) == -1)
10530 624411d2 2023-07-08 jrick err = got_error_from_errno("asprintf");
10532 624411d2 2023-07-08 jrick free(author0);
10533 624411d2 2023-07-08 jrick free(logmsg0);
10534 624411d2 2023-07-08 jrick return err;
10537 624411d2 2023-07-08 jrick static const struct got_error *
10538 624411d2 2023-07-08 jrick delete_backup_ref(struct got_reference *ref, struct got_object_id *id,
10539 624411d2 2023-07-08 jrick struct got_repository *repo)
10541 624411d2 2023-07-08 jrick const struct got_error *err;
10542 624411d2 2023-07-08 jrick char *id_str;
10544 624411d2 2023-07-08 jrick err = got_object_id_str(&id_str, id);
10545 624411d2 2023-07-08 jrick if (err)
10546 624411d2 2023-07-08 jrick return err;
10548 624411d2 2023-07-08 jrick err = got_ref_delete(ref, repo);
10549 624411d2 2023-07-08 jrick if (err)
10550 624411d2 2023-07-08 jrick goto done;
10552 624411d2 2023-07-08 jrick printf("Deleted %s: %s\n", got_ref_get_name(ref), id_str);
10554 624411d2 2023-07-08 jrick free(id_str);
10555 624411d2 2023-07-08 jrick return err;
10558 624411d2 2023-07-08 jrick static const struct got_error *
10559 624411d2 2023-07-08 jrick print_backup_ref(const char *branch_name, const char *new_id_str,
10560 624411d2 2023-07-08 jrick struct got_object_id *old_commit_id, struct got_commit_object *old_commit,
10561 624411d2 2023-07-08 jrick struct got_reflist_object_id_map *refs_idmap,
10562 624411d2 2023-07-08 jrick struct got_repository *repo)
10564 624411d2 2023-07-08 jrick const struct got_error *err = NULL;
10565 624411d2 2023-07-08 jrick struct got_reflist_head *refs;
10566 624411d2 2023-07-08 jrick char *refs_str = NULL;
10567 624411d2 2023-07-08 jrick struct got_object_id *new_commit_id = NULL;
10568 624411d2 2023-07-08 jrick struct got_commit_object *new_commit = NULL;
10569 624411d2 2023-07-08 jrick char *new_commit_brief_str = NULL;
10570 624411d2 2023-07-08 jrick struct got_object_id *yca_id = NULL;
10571 624411d2 2023-07-08 jrick struct got_commit_object *yca_commit = NULL;
10572 624411d2 2023-07-08 jrick char *yca_id_str = NULL, *yca_brief_str = NULL;
10573 624411d2 2023-07-08 jrick char *custom_refs_str;
10575 624411d2 2023-07-08 jrick if (asprintf(&custom_refs_str, "formerly %s", branch_name) == -1)
10576 624411d2 2023-07-08 jrick return got_error_from_errno("asprintf");
10578 624411d2 2023-07-08 jrick err = print_commit(old_commit, old_commit_id, repo, NULL, NULL, NULL,
10579 624411d2 2023-07-08 jrick 0, 0, refs_idmap, custom_refs_str, NULL);
10580 624411d2 2023-07-08 jrick if (err)
10581 624411d2 2023-07-08 jrick goto done;
10583 624411d2 2023-07-08 jrick err = got_object_resolve_id_str(&new_commit_id, repo, new_id_str);
10584 624411d2 2023-07-08 jrick if (err)
10585 624411d2 2023-07-08 jrick goto done;
10587 624411d2 2023-07-08 jrick refs = got_reflist_object_id_map_lookup(refs_idmap, new_commit_id);
10588 624411d2 2023-07-08 jrick if (refs) {
10589 624411d2 2023-07-08 jrick err = build_refs_str(&refs_str, refs, new_commit_id, repo, 0);
10590 624411d2 2023-07-08 jrick if (err)
10591 624411d2 2023-07-08 jrick goto done;
10594 624411d2 2023-07-08 jrick err = got_object_open_as_commit(&new_commit, repo, new_commit_id);
10595 624411d2 2023-07-08 jrick if (err)
10596 624411d2 2023-07-08 jrick goto done;
10598 624411d2 2023-07-08 jrick err = get_commit_brief_str(&new_commit_brief_str, new_commit);
10599 624411d2 2023-07-08 jrick if (err)
10600 624411d2 2023-07-08 jrick goto done;
10602 624411d2 2023-07-08 jrick err = got_commit_graph_find_youngest_common_ancestor(&yca_id,
10603 624411d2 2023-07-08 jrick old_commit_id, new_commit_id, 1, repo, check_cancelled, NULL);
10604 624411d2 2023-07-08 jrick if (err)
10605 624411d2 2023-07-08 jrick goto done;
10607 624411d2 2023-07-08 jrick printf("has become commit %s%s%s%s\n %s\n", new_id_str,
10608 624411d2 2023-07-08 jrick refs_str ? " (" : "", refs_str ? refs_str : "",
10609 624411d2 2023-07-08 jrick refs_str ? ")" : "", new_commit_brief_str);
10610 624411d2 2023-07-08 jrick if (yca_id && got_object_id_cmp(yca_id, new_commit_id) != 0 &&
10611 624411d2 2023-07-08 jrick got_object_id_cmp(yca_id, old_commit_id) != 0) {
10612 624411d2 2023-07-08 jrick free(refs_str);
10613 624411d2 2023-07-08 jrick refs_str = NULL;
10615 624411d2 2023-07-08 jrick err = got_object_open_as_commit(&yca_commit, repo, yca_id);
10616 624411d2 2023-07-08 jrick if (err)
10617 624411d2 2023-07-08 jrick goto done;
10619 624411d2 2023-07-08 jrick err = get_commit_brief_str(&yca_brief_str, yca_commit);
10620 624411d2 2023-07-08 jrick if (err)
10621 624411d2 2023-07-08 jrick goto done;
10623 624411d2 2023-07-08 jrick err = got_object_id_str(&yca_id_str, yca_id);
10624 624411d2 2023-07-08 jrick if (err)
10625 624411d2 2023-07-08 jrick goto done;
10627 624411d2 2023-07-08 jrick refs = got_reflist_object_id_map_lookup(refs_idmap, yca_id);
10628 624411d2 2023-07-08 jrick if (refs) {
10629 624411d2 2023-07-08 jrick err = build_refs_str(&refs_str, refs, yca_id, repo, 0);
10630 624411d2 2023-07-08 jrick if (err)
10631 624411d2 2023-07-08 jrick goto done;
10633 624411d2 2023-07-08 jrick printf("history forked at %s%s%s%s\n %s\n",
10634 624411d2 2023-07-08 jrick yca_id_str,
10635 624411d2 2023-07-08 jrick refs_str ? " (" : "", refs_str ? refs_str : "",
10636 624411d2 2023-07-08 jrick refs_str ? ")" : "", yca_brief_str);
10639 624411d2 2023-07-08 jrick free(custom_refs_str);
10640 624411d2 2023-07-08 jrick free(new_commit_id);
10641 624411d2 2023-07-08 jrick free(refs_str);
10642 624411d2 2023-07-08 jrick free(yca_id);
10643 624411d2 2023-07-08 jrick free(yca_id_str);
10644 624411d2 2023-07-08 jrick free(yca_brief_str);
10645 624411d2 2023-07-08 jrick if (new_commit)
10646 624411d2 2023-07-08 jrick got_object_commit_close(new_commit);
10647 624411d2 2023-07-08 jrick if (yca_commit)
10648 624411d2 2023-07-08 jrick got_object_commit_close(yca_commit);
10650 624411d2 2023-07-08 jrick return err;
10653 624411d2 2023-07-08 jrick static const struct got_error *
10654 624411d2 2023-07-08 jrick worktree_has_logmsg_ref(const char *caller, struct got_worktree *worktree,
10655 624411d2 2023-07-08 jrick struct got_repository *repo)
10657 624411d2 2023-07-08 jrick const struct got_error *err;
10658 624411d2 2023-07-08 jrick struct got_reflist_head refs;
10659 624411d2 2023-07-08 jrick struct got_reflist_entry *re;
10660 624411d2 2023-07-08 jrick char *uuidstr = NULL;
10661 624411d2 2023-07-08 jrick static char msg[160];
10663 624411d2 2023-07-08 jrick TAILQ_INIT(&refs);
10665 624411d2 2023-07-08 jrick err = got_worktree_get_uuid(&uuidstr, worktree);
10666 624411d2 2023-07-08 jrick if (err)
10667 624411d2 2023-07-08 jrick goto done;
10669 624411d2 2023-07-08 jrick err = got_ref_list(&refs, repo, "refs/got/worktree",
10670 624411d2 2023-07-08 jrick got_ref_cmp_by_name, repo);
10671 624411d2 2023-07-08 jrick if (err)
10672 624411d2 2023-07-08 jrick goto done;
10674 624411d2 2023-07-08 jrick TAILQ_FOREACH(re, &refs, entry) {
10675 624411d2 2023-07-08 jrick const char *cmd, *refname, *type;
10677 624411d2 2023-07-08 jrick refname = got_ref_get_name(re->ref);
10679 624411d2 2023-07-08 jrick if (strncmp(refname, GOT_WORKTREE_CHERRYPICK_REF_PREFIX,
10680 624411d2 2023-07-08 jrick GOT_WORKTREE_CHERRYPICK_REF_PREFIX_LEN) == 0) {
10681 624411d2 2023-07-08 jrick refname += GOT_WORKTREE_CHERRYPICK_REF_PREFIX_LEN + 1;
10682 624411d2 2023-07-08 jrick cmd = "cherrypick";
10683 624411d2 2023-07-08 jrick type = "cherrypicked";
10684 624411d2 2023-07-08 jrick } else if (strncmp(refname, GOT_WORKTREE_BACKOUT_REF_PREFIX,
10685 624411d2 2023-07-08 jrick GOT_WORKTREE_BACKOUT_REF_PREFIX_LEN) == 0) {
10686 624411d2 2023-07-08 jrick refname += GOT_WORKTREE_BACKOUT_REF_PREFIX_LEN + 1;
10687 624411d2 2023-07-08 jrick cmd = "backout";
10688 624411d2 2023-07-08 jrick type = "backed-out";
10690 624411d2 2023-07-08 jrick continue;
10692 624411d2 2023-07-08 jrick if (strncmp(refname, uuidstr, GOT_WORKTREE_UUID_STRLEN) != 0)
10693 624411d2 2023-07-08 jrick continue;
10695 624411d2 2023-07-08 jrick snprintf(msg, sizeof(msg),
10696 624411d2 2023-07-08 jrick "work tree has references created by %s commits which "
10697 624411d2 2023-07-08 jrick "must be removed with 'got %s -X' before running the %s "
10698 624411d2 2023-07-08 jrick "command", type, cmd, caller);
10699 624411d2 2023-07-08 jrick err = got_error_msg(GOT_ERR_WORKTREE_META, msg);
10700 624411d2 2023-07-08 jrick goto done;
10704 624411d2 2023-07-08 jrick free(uuidstr);
10705 624411d2 2023-07-08 jrick got_ref_list_free(&refs);
10706 624411d2 2023-07-08 jrick return err;
10709 624411d2 2023-07-08 jrick static const struct got_error *
10710 624411d2 2023-07-08 jrick process_backup_refs(const char *backup_ref_prefix,
10711 624411d2 2023-07-08 jrick const char *wanted_branch_name,
10712 624411d2 2023-07-08 jrick int delete, struct got_repository *repo)
10714 624411d2 2023-07-08 jrick const struct got_error *err;
10715 624411d2 2023-07-08 jrick struct got_reflist_head refs, backup_refs;
10716 624411d2 2023-07-08 jrick struct got_reflist_entry *re;
10717 624411d2 2023-07-08 jrick const size_t backup_ref_prefix_len = strlen(backup_ref_prefix);
10718 624411d2 2023-07-08 jrick struct got_object_id *old_commit_id = NULL;
10719 624411d2 2023-07-08 jrick char *branch_name = NULL;
10720 624411d2 2023-07-08 jrick struct got_commit_object *old_commit = NULL;
10721 624411d2 2023-07-08 jrick struct got_reflist_object_id_map *refs_idmap = NULL;
10722 624411d2 2023-07-08 jrick int wanted_branch_found = 0;
10724 624411d2 2023-07-08 jrick TAILQ_INIT(&refs);
10725 624411d2 2023-07-08 jrick TAILQ_INIT(&backup_refs);
10727 624411d2 2023-07-08 jrick err = got_ref_list(&refs, repo, NULL, got_ref_cmp_by_name, NULL);
10728 624411d2 2023-07-08 jrick if (err)
10729 624411d2 2023-07-08 jrick return err;
10731 624411d2 2023-07-08 jrick err = got_reflist_object_id_map_create(&refs_idmap, &refs, repo);
10732 624411d2 2023-07-08 jrick if (err)
10733 624411d2 2023-07-08 jrick goto done;
10735 624411d2 2023-07-08 jrick if (wanted_branch_name) {
10736 624411d2 2023-07-08 jrick if (strncmp(wanted_branch_name, "refs/heads/", 11) == 0)
10737 624411d2 2023-07-08 jrick wanted_branch_name += 11;
10740 624411d2 2023-07-08 jrick err = got_ref_list(&backup_refs, repo, backup_ref_prefix,
10741 624411d2 2023-07-08 jrick got_ref_cmp_by_commit_timestamp_descending, repo);
10742 624411d2 2023-07-08 jrick if (err)
10743 624411d2 2023-07-08 jrick goto done;
10745 624411d2 2023-07-08 jrick TAILQ_FOREACH(re, &backup_refs, entry) {
10746 624411d2 2023-07-08 jrick const char *refname = got_ref_get_name(re->ref);
10747 624411d2 2023-07-08 jrick char *slash;
10749 624411d2 2023-07-08 jrick err = check_cancelled(NULL);
10750 624411d2 2023-07-08 jrick if (err)
10753 624411d2 2023-07-08 jrick err = got_ref_resolve(&old_commit_id, repo, re->ref);
10754 624411d2 2023-07-08 jrick if (err)
10757 624411d2 2023-07-08 jrick err = got_object_open_as_commit(&old_commit, repo,
10758 624411d2 2023-07-08 jrick old_commit_id);
10759 624411d2 2023-07-08 jrick if (err)
10762 624411d2 2023-07-08 jrick if (strncmp(backup_ref_prefix, refname,
10763 624411d2 2023-07-08 jrick backup_ref_prefix_len) == 0)
10764 624411d2 2023-07-08 jrick refname += backup_ref_prefix_len;
10766 624411d2 2023-07-08 jrick while (refname[0] == '/')
10767 624411d2 2023-07-08 jrick refname++;
10769 624411d2 2023-07-08 jrick branch_name = strdup(refname);
10770 624411d2 2023-07-08 jrick if (branch_name == NULL) {
10771 624411d2 2023-07-08 jrick err = got_error_from_errno("strdup");
10774 624411d2 2023-07-08 jrick slash = strrchr(branch_name, '/');
10775 624411d2 2023-07-08 jrick if (slash) {
10776 624411d2 2023-07-08 jrick *slash = '\0';
10777 624411d2 2023-07-08 jrick refname += strlen(branch_name) + 1;
10780 624411d2 2023-07-08 jrick if (wanted_branch_name == NULL ||
10781 624411d2 2023-07-08 jrick strcmp(wanted_branch_name, branch_name) == 0) {
10782 624411d2 2023-07-08 jrick wanted_branch_found = 1;
10783 624411d2 2023-07-08 jrick if (delete) {
10784 624411d2 2023-07-08 jrick err = delete_backup_ref(re->ref,
10785 624411d2 2023-07-08 jrick old_commit_id, repo);
10786 624411d2 2023-07-08 jrick } else {
10787 624411d2 2023-07-08 jrick err = print_backup_ref(branch_name, refname,
10788 624411d2 2023-07-08 jrick old_commit_id, old_commit, refs_idmap,
10791 624411d2 2023-07-08 jrick if (err)
10795 624411d2 2023-07-08 jrick free(old_commit_id);
10796 624411d2 2023-07-08 jrick old_commit_id = NULL;
10797 624411d2 2023-07-08 jrick free(branch_name);
10798 624411d2 2023-07-08 jrick branch_name = NULL;
10799 624411d2 2023-07-08 jrick got_object_commit_close(old_commit);
10800 624411d2 2023-07-08 jrick old_commit = NULL;
10803 624411d2 2023-07-08 jrick if (wanted_branch_name && !wanted_branch_found) {
10804 624411d2 2023-07-08 jrick err = got_error_fmt(GOT_ERR_NOT_REF,
10805 624411d2 2023-07-08 jrick "%s/%s/", backup_ref_prefix, wanted_branch_name);
10808 624411d2 2023-07-08 jrick if (refs_idmap)
10809 624411d2 2023-07-08 jrick got_reflist_object_id_map_free(refs_idmap);
10810 624411d2 2023-07-08 jrick got_ref_list_free(&refs);
10811 624411d2 2023-07-08 jrick got_ref_list_free(&backup_refs);
10812 624411d2 2023-07-08 jrick free(old_commit_id);
10813 624411d2 2023-07-08 jrick free(branch_name);
10814 624411d2 2023-07-08 jrick if (old_commit)
10815 624411d2 2023-07-08 jrick got_object_commit_close(old_commit);
10816 624411d2 2023-07-08 jrick return err;
10819 624411d2 2023-07-08 jrick static const struct got_error *
10820 624411d2 2023-07-08 jrick abort_progress(void *arg, unsigned char status, const char *path)
10823 624411d2 2023-07-08 jrick * Unversioned files should not clutter progress output when
10824 624411d2 2023-07-08 jrick * an operation is aborted.
10826 624411d2 2023-07-08 jrick if (status == GOT_STATUS_UNVERSIONED)
10827 624411d2 2023-07-08 jrick return NULL;
10829 624411d2 2023-07-08 jrick return update_progress(arg, status, path);
10832 624411d2 2023-07-08 jrick static const struct got_error *
10833 624411d2 2023-07-08 jrick cmd_rebase(int argc, char *argv[])
10835 624411d2 2023-07-08 jrick const struct got_error *error = NULL;
10836 624411d2 2023-07-08 jrick struct got_worktree *worktree = NULL;
10837 624411d2 2023-07-08 jrick struct got_repository *repo = NULL;
10838 624411d2 2023-07-08 jrick struct got_fileindex *fileindex = NULL;
10839 624411d2 2023-07-08 jrick char *cwd = NULL, *committer = NULL, *gitconfig_path = NULL;
10840 624411d2 2023-07-08 jrick struct got_reference *branch = NULL;
10841 624411d2 2023-07-08 jrick struct got_reference *new_base_branch = NULL, *tmp_branch = NULL;
10842 624411d2 2023-07-08 jrick struct got_object_id *commit_id = NULL, *parent_id = NULL;
10843 624411d2 2023-07-08 jrick struct got_object_id *resume_commit_id = NULL;
10844 624411d2 2023-07-08 jrick struct got_object_id *branch_head_commit_id = NULL, *yca_id = NULL;
10845 624411d2 2023-07-08 jrick struct got_object_id *head_commit_id = NULL;
10846 624411d2 2023-07-08 jrick struct got_reference *head_ref = NULL;
10847 624411d2 2023-07-08 jrick struct got_commit_object *commit = NULL;
10848 624411d2 2023-07-08 jrick int ch, rebase_in_progress = 0, abort_rebase = 0, continue_rebase = 0;
10849 624411d2 2023-07-08 jrick int histedit_in_progress = 0, merge_in_progress = 0;
10850 624411d2 2023-07-08 jrick int create_backup = 1, list_backups = 0, delete_backups = 0;
10851 624411d2 2023-07-08 jrick int allow_conflict = 0;
10852 624411d2 2023-07-08 jrick struct got_object_id_queue commits;
10853 624411d2 2023-07-08 jrick struct got_pathlist_head merged_paths;
10854 624411d2 2023-07-08 jrick const struct got_object_id_queue *parent_ids;
10855 624411d2 2023-07-08 jrick struct got_object_qid *qid, *pid;
10856 624411d2 2023-07-08 jrick struct got_update_progress_arg upa;
10857 624411d2 2023-07-08 jrick int *pack_fds = NULL;
10859 624411d2 2023-07-08 jrick STAILQ_INIT(&commits);
10860 624411d2 2023-07-08 jrick TAILQ_INIT(&merged_paths);
10861 624411d2 2023-07-08 jrick memset(&upa, 0, sizeof(upa));
10863 624411d2 2023-07-08 jrick #ifndef PROFILE
10864 624411d2 2023-07-08 jrick if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd "
10865 624411d2 2023-07-08 jrick "unveil", NULL) == -1)
10866 624411d2 2023-07-08 jrick err(1, "pledge");
10869 624411d2 2023-07-08 jrick while ((ch = getopt(argc, argv, "aCclX")) != -1) {
10870 624411d2 2023-07-08 jrick switch (ch) {
10871 624411d2 2023-07-08 jrick case 'a':
10872 624411d2 2023-07-08 jrick abort_rebase = 1;
10874 624411d2 2023-07-08 jrick case 'C':
10875 624411d2 2023-07-08 jrick allow_conflict = 1;
10877 624411d2 2023-07-08 jrick case 'c':
10878 624411d2 2023-07-08 jrick continue_rebase = 1;
10880 624411d2 2023-07-08 jrick case 'l':
10881 624411d2 2023-07-08 jrick list_backups = 1;
10883 624411d2 2023-07-08 jrick case 'X':
10884 624411d2 2023-07-08 jrick delete_backups = 1;
10886 624411d2 2023-07-08 jrick default:
10887 624411d2 2023-07-08 jrick usage_rebase();
10888 624411d2 2023-07-08 jrick /* NOTREACHED */
10892 624411d2 2023-07-08 jrick argc -= optind;
10893 624411d2 2023-07-08 jrick argv += optind;
10895 624411d2 2023-07-08 jrick if (list_backups) {
10896 624411d2 2023-07-08 jrick if (abort_rebase)
10897 624411d2 2023-07-08 jrick option_conflict('l', 'a');
10898 624411d2 2023-07-08 jrick if (allow_conflict)
10899 624411d2 2023-07-08 jrick option_conflict('l', 'C');
10900 624411d2 2023-07-08 jrick if (continue_rebase)
10901 624411d2 2023-07-08 jrick option_conflict('l', 'c');
10902 624411d2 2023-07-08 jrick if (delete_backups)
10903 624411d2 2023-07-08 jrick option_conflict('l', 'X');
10904 624411d2 2023-07-08 jrick if (argc != 0 && argc != 1)
10905 624411d2 2023-07-08 jrick usage_rebase();
10906 624411d2 2023-07-08 jrick } else if (delete_backups) {
10907 624411d2 2023-07-08 jrick if (abort_rebase)
10908 624411d2 2023-07-08 jrick option_conflict('X', 'a');
10909 624411d2 2023-07-08 jrick if (allow_conflict)
10910 624411d2 2023-07-08 jrick option_conflict('X', 'C');
10911 624411d2 2023-07-08 jrick if (continue_rebase)
10912 624411d2 2023-07-08 jrick option_conflict('X', 'c');
10913 624411d2 2023-07-08 jrick if (list_backups)
10914 624411d2 2023-07-08 jrick option_conflict('l', 'X');
10915 624411d2 2023-07-08 jrick if (argc != 0 && argc != 1)
10916 624411d2 2023-07-08 jrick usage_rebase();
10917 624411d2 2023-07-08 jrick } else if (allow_conflict) {
10918 624411d2 2023-07-08 jrick if (abort_rebase)
10919 624411d2 2023-07-08 jrick option_conflict('C', 'a');
10920 624411d2 2023-07-08 jrick if (!continue_rebase)
10921 624411d2 2023-07-08 jrick errx(1, "-C option requires -c");
10922 624411d2 2023-07-08 jrick } else {
10923 624411d2 2023-07-08 jrick if (abort_rebase && continue_rebase)
10924 624411d2 2023-07-08 jrick usage_rebase();
10925 624411d2 2023-07-08 jrick else if (abort_rebase || continue_rebase) {
10926 624411d2 2023-07-08 jrick if (argc != 0)
10927 624411d2 2023-07-08 jrick usage_rebase();
10928 624411d2 2023-07-08 jrick } else if (argc != 1)
10929 624411d2 2023-07-08 jrick usage_rebase();
10932 624411d2 2023-07-08 jrick cwd = getcwd(NULL, 0);
10933 624411d2 2023-07-08 jrick if (cwd == NULL) {
10934 624411d2 2023-07-08 jrick error = got_error_from_errno("getcwd");
10935 624411d2 2023-07-08 jrick goto done;
10938 624411d2 2023-07-08 jrick error = got_repo_pack_fds_open(&pack_fds);
10939 624411d2 2023-07-08 jrick if (error != NULL)
10940 624411d2 2023-07-08 jrick goto done;
10942 624411d2 2023-07-08 jrick error = got_worktree_open(&worktree, cwd);
10943 624411d2 2023-07-08 jrick if (error) {
10944 624411d2 2023-07-08 jrick if (list_backups || delete_backups) {
10945 624411d2 2023-07-08 jrick if (error->code != GOT_ERR_NOT_WORKTREE)
10946 624411d2 2023-07-08 jrick goto done;
10947 624411d2 2023-07-08 jrick } else {
10948 624411d2 2023-07-08 jrick if (error->code == GOT_ERR_NOT_WORKTREE)
10949 624411d2 2023-07-08 jrick error = wrap_not_worktree_error(error,
10950 624411d2 2023-07-08 jrick "rebase", cwd);
10951 624411d2 2023-07-08 jrick goto done;
10955 624411d2 2023-07-08 jrick error = get_gitconfig_path(&gitconfig_path);
10956 624411d2 2023-07-08 jrick if (error)
10957 624411d2 2023-07-08 jrick goto done;
10958 624411d2 2023-07-08 jrick error = got_repo_open(&repo,
10959 624411d2 2023-07-08 jrick worktree ? got_worktree_get_repo_path(worktree) : cwd,
10960 624411d2 2023-07-08 jrick gitconfig_path, pack_fds);
10961 624411d2 2023-07-08 jrick if (error != NULL)
10962 624411d2 2023-07-08 jrick goto done;
10964 624411d2 2023-07-08 jrick if (worktree != NULL && !list_backups && !delete_backups) {
10965 624411d2 2023-07-08 jrick error = worktree_has_logmsg_ref("rebase", worktree, repo);
10966 624411d2 2023-07-08 jrick if (error)
10967 624411d2 2023-07-08 jrick goto done;
10970 624411d2 2023-07-08 jrick error = get_author(&committer, repo, worktree);
10971 624411d2 2023-07-08 jrick if (error && error->code != GOT_ERR_COMMIT_NO_AUTHOR)
10972 624411d2 2023-07-08 jrick goto done;
10974 624411d2 2023-07-08 jrick error = apply_unveil(got_repo_get_path(repo), 0,
10975 624411d2 2023-07-08 jrick worktree ? got_worktree_get_root_path(worktree) : NULL);
10976 624411d2 2023-07-08 jrick if (error)
10977 624411d2 2023-07-08 jrick goto done;
10979 624411d2 2023-07-08 jrick if (list_backups || delete_backups) {
10980 624411d2 2023-07-08 jrick error = process_backup_refs(
10981 624411d2 2023-07-08 jrick GOT_WORKTREE_REBASE_BACKUP_REF_PREFIX,
10982 624411d2 2023-07-08 jrick argc == 1 ? argv[0] : NULL, delete_backups, repo);
10983 624411d2 2023-07-08 jrick goto done; /* nothing else to do */
10986 624411d2 2023-07-08 jrick error = got_worktree_histedit_in_progress(&histedit_in_progress,
10987 624411d2 2023-07-08 jrick worktree);
10988 624411d2 2023-07-08 jrick if (error)
10989 624411d2 2023-07-08 jrick goto done;
10990 624411d2 2023-07-08 jrick if (histedit_in_progress) {
10991 624411d2 2023-07-08 jrick error = got_error(GOT_ERR_HISTEDIT_BUSY);
10992 624411d2 2023-07-08 jrick goto done;
10995 624411d2 2023-07-08 jrick error = got_worktree_merge_in_progress(&merge_in_progress,
10996 624411d2 2023-07-08 jrick worktree, repo);
10997 624411d2 2023-07-08 jrick if (error)
10998 624411d2 2023-07-08 jrick goto done;
10999 624411d2 2023-07-08 jrick if (merge_in_progress) {
11000 624411d2 2023-07-08 jrick error = got_error(GOT_ERR_MERGE_BUSY);
11001 624411d2 2023-07-08 jrick goto done;
11004 624411d2 2023-07-08 jrick error = got_worktree_rebase_in_progress(&rebase_in_progress, worktree);
11005 624411d2 2023-07-08 jrick if (error)
11006 624411d2 2023-07-08 jrick goto done;
11008 624411d2 2023-07-08 jrick if (abort_rebase) {
11009 624411d2 2023-07-08 jrick if (!rebase_in_progress) {
11010 624411d2 2023-07-08 jrick error = got_error(GOT_ERR_NOT_REBASING);
11011 624411d2 2023-07-08 jrick goto done;
11013 624411d2 2023-07-08 jrick error = got_worktree_rebase_continue(&resume_commit_id,
11014 624411d2 2023-07-08 jrick &new_base_branch, &tmp_branch, &branch, &fileindex,
11015 624411d2 2023-07-08 jrick worktree, repo);
11016 624411d2 2023-07-08 jrick if (error)
11017 624411d2 2023-07-08 jrick goto done;
11018 624411d2 2023-07-08 jrick printf("Switching work tree to %s\n",
11019 624411d2 2023-07-08 jrick got_ref_get_symref_target(new_base_branch));
11020 624411d2 2023-07-08 jrick error = got_worktree_rebase_abort(worktree, fileindex, repo,
11021 624411d2 2023-07-08 jrick new_base_branch, abort_progress, &upa);
11022 624411d2 2023-07-08 jrick if (error)
11023 624411d2 2023-07-08 jrick goto done;
11024 624411d2 2023-07-08 jrick printf("Rebase of %s aborted\n", got_ref_get_name(branch));
11025 624411d2 2023-07-08 jrick print_merge_progress_stats(&upa);
11026 624411d2 2023-07-08 jrick goto done; /* nothing else to do */
11029 624411d2 2023-07-08 jrick if (continue_rebase) {
11030 624411d2 2023-07-08 jrick if (!rebase_in_progress) {
11031 624411d2 2023-07-08 jrick error = got_error(GOT_ERR_NOT_REBASING);
11032 624411d2 2023-07-08 jrick goto done;
11034 624411d2 2023-07-08 jrick error = got_worktree_rebase_continue(&resume_commit_id,
11035 624411d2 2023-07-08 jrick &new_base_branch, &tmp_branch, &branch, &fileindex,
11036 624411d2 2023-07-08 jrick worktree, repo);
11037 624411d2 2023-07-08 jrick if (error)
11038 624411d2 2023-07-08 jrick goto done;
11040 624411d2 2023-07-08 jrick error = rebase_commit(NULL, worktree, fileindex, tmp_branch,
11041 624411d2 2023-07-08 jrick committer, resume_commit_id, allow_conflict, repo);
11042 624411d2 2023-07-08 jrick if (error)
11043 624411d2 2023-07-08 jrick goto done;
11045 624411d2 2023-07-08 jrick yca_id = got_object_id_dup(resume_commit_id);
11046 624411d2 2023-07-08 jrick if (yca_id == NULL) {
11047 624411d2 2023-07-08 jrick error = got_error_from_errno("got_object_id_dup");
11048 624411d2 2023-07-08 jrick goto done;
11050 624411d2 2023-07-08 jrick } else {
11051 624411d2 2023-07-08 jrick error = got_ref_open(&branch, repo, argv[0], 0);
11052 624411d2 2023-07-08 jrick if (error != NULL)
11053 624411d2 2023-07-08 jrick goto done;
11054 624411d2 2023-07-08 jrick if (strncmp(got_ref_get_name(branch), "refs/heads/", 11) != 0) {
11055 624411d2 2023-07-08 jrick error = got_error_msg(GOT_ERR_COMMIT_BRANCH,
11056 624411d2 2023-07-08 jrick "will not rebase a branch which lives outside "
11057 624411d2 2023-07-08 jrick "the \"refs/heads/\" reference namespace");
11058 624411d2 2023-07-08 jrick goto done;
11062 624411d2 2023-07-08 jrick error = got_ref_resolve(&branch_head_commit_id, repo, branch);
11063 624411d2 2023-07-08 jrick if (error)
11064 624411d2 2023-07-08 jrick goto done;
11066 624411d2 2023-07-08 jrick if (!continue_rebase) {
11067 624411d2 2023-07-08 jrick struct got_object_id *base_commit_id;
11069 624411d2 2023-07-08 jrick error = got_ref_open(&head_ref, repo,
11070 624411d2 2023-07-08 jrick got_worktree_get_head_ref_name(worktree), 0);
11071 624411d2 2023-07-08 jrick if (error)
11072 624411d2 2023-07-08 jrick goto done;
11073 624411d2 2023-07-08 jrick error = got_ref_resolve(&head_commit_id, repo, head_ref);
11074 624411d2 2023-07-08 jrick if (error)
11075 624411d2 2023-07-08 jrick goto done;
11076 624411d2 2023-07-08 jrick base_commit_id = got_worktree_get_base_commit_id(worktree);
11077 624411d2 2023-07-08 jrick if (got_object_id_cmp(base_commit_id, head_commit_id) != 0) {
11078 624411d2 2023-07-08 jrick error = got_error(GOT_ERR_REBASE_OUT_OF_DATE);
11079 624411d2 2023-07-08 jrick goto done;
11082 624411d2 2023-07-08 jrick error = got_commit_graph_find_youngest_common_ancestor(&yca_id,
11083 624411d2 2023-07-08 jrick base_commit_id, branch_head_commit_id, 1, repo,
11084 624411d2 2023-07-08 jrick check_cancelled, NULL);
11085 624411d2 2023-07-08 jrick if (error) {
11086 624411d2 2023-07-08 jrick if (error->code == GOT_ERR_ANCESTRY) {
11087 624411d2 2023-07-08 jrick error = got_error_msg(GOT_ERR_ANCESTRY,
11088 624411d2 2023-07-08 jrick "specified branch shares no common "
11089 624411d2 2023-07-08 jrick "ancestry with work tree's branch");
11091 624411d2 2023-07-08 jrick goto done;
11094 624411d2 2023-07-08 jrick if (got_object_id_cmp(base_commit_id, yca_id) == 0) {
11095 624411d2 2023-07-08 jrick struct got_pathlist_head paths;
11096 624411d2 2023-07-08 jrick printf("%s is already based on %s\n",
11097 624411d2 2023-07-08 jrick got_ref_get_name(branch),
11098 624411d2 2023-07-08 jrick got_worktree_get_head_ref_name(worktree));
11099 624411d2 2023-07-08 jrick error = switch_head_ref(branch, branch_head_commit_id,
11100 624411d2 2023-07-08 jrick worktree, repo);
11101 624411d2 2023-07-08 jrick if (error)
11102 624411d2 2023-07-08 jrick goto done;
11103 624411d2 2023-07-08 jrick error = got_worktree_set_base_commit_id(worktree, repo,
11104 624411d2 2023-07-08 jrick branch_head_commit_id);
11105 624411d2 2023-07-08 jrick if (error)
11106 624411d2 2023-07-08 jrick goto done;
11107 624411d2 2023-07-08 jrick TAILQ_INIT(&paths);
11108 624411d2 2023-07-08 jrick error = got_pathlist_append(&paths, "", NULL);
11109 624411d2 2023-07-08 jrick if (error)
11110 624411d2 2023-07-08 jrick goto done;
11111 624411d2 2023-07-08 jrick error = got_worktree_checkout_files(worktree,
11112 624411d2 2023-07-08 jrick &paths, repo, update_progress, &upa,
11113 624411d2 2023-07-08 jrick check_cancelled, NULL);
11114 624411d2 2023-07-08 jrick got_pathlist_free(&paths, GOT_PATHLIST_FREE_NONE);
11115 624411d2 2023-07-08 jrick if (error)
11116 624411d2 2023-07-08 jrick goto done;
11117 624411d2 2023-07-08 jrick if (upa.did_something) {
11118 624411d2 2023-07-08 jrick char *id_str;
11119 624411d2 2023-07-08 jrick error = got_object_id_str(&id_str,
11120 624411d2 2023-07-08 jrick branch_head_commit_id);
11121 624411d2 2023-07-08 jrick if (error)
11122 624411d2 2023-07-08 jrick goto done;
11123 624411d2 2023-07-08 jrick printf("Updated to %s: %s\n",
11124 624411d2 2023-07-08 jrick got_worktree_get_head_ref_name(worktree),
11125 624411d2 2023-07-08 jrick id_str);
11126 624411d2 2023-07-08 jrick free(id_str);
11128 624411d2 2023-07-08 jrick printf("Already up-to-date\n");
11129 624411d2 2023-07-08 jrick print_update_progress_stats(&upa);
11130 624411d2 2023-07-08 jrick goto done;
11134 624411d2 2023-07-08 jrick commit_id = branch_head_commit_id;
11135 624411d2 2023-07-08 jrick error = got_object_open_as_commit(&commit, repo, commit_id);
11136 624411d2 2023-07-08 jrick if (error)
11137 624411d2 2023-07-08 jrick goto done;
11139 624411d2 2023-07-08 jrick parent_ids = got_object_commit_get_parent_ids(commit);
11140 624411d2 2023-07-08 jrick pid = STAILQ_FIRST(parent_ids);
11141 624411d2 2023-07-08 jrick if (pid) {
11142 624411d2 2023-07-08 jrick error = collect_commits(&commits, commit_id, &pid->id,
11143 624411d2 2023-07-08 jrick yca_id, got_worktree_get_path_prefix(worktree),
11144 624411d2 2023-07-08 jrick GOT_ERR_REBASE_PATH, repo);
11145 624411d2 2023-07-08 jrick if (error)
11146 624411d2 2023-07-08 jrick goto done;
11149 624411d2 2023-07-08 jrick got_object_commit_close(commit);
11150 624411d2 2023-07-08 jrick commit = NULL;
11152 624411d2 2023-07-08 jrick if (!continue_rebase) {
11153 624411d2 2023-07-08 jrick error = got_worktree_rebase_prepare(&new_base_branch,
11154 624411d2 2023-07-08 jrick &tmp_branch, &fileindex, worktree, branch, repo);
11155 624411d2 2023-07-08 jrick if (error)
11156 624411d2 2023-07-08 jrick goto done;
11159 624411d2 2023-07-08 jrick if (STAILQ_EMPTY(&commits)) {
11160 624411d2 2023-07-08 jrick if (continue_rebase) {
11161 624411d2 2023-07-08 jrick error = rebase_complete(worktree, fileindex,
11162 624411d2 2023-07-08 jrick branch, tmp_branch, repo, create_backup);
11163 624411d2 2023-07-08 jrick goto done;
11164 624411d2 2023-07-08 jrick } else {
11165 624411d2 2023-07-08 jrick /* Fast-forward the reference of the branch. */
11166 624411d2 2023-07-08 jrick struct got_object_id *new_head_commit_id;
11167 624411d2 2023-07-08 jrick char *id_str;
11168 624411d2 2023-07-08 jrick error = got_ref_resolve(&new_head_commit_id, repo,
11169 624411d2 2023-07-08 jrick new_base_branch);
11170 624411d2 2023-07-08 jrick if (error)
11171 624411d2 2023-07-08 jrick goto done;
11172 624411d2 2023-07-08 jrick error = got_object_id_str(&id_str, new_head_commit_id);
11173 624411d2 2023-07-08 jrick if (error)
11174 624411d2 2023-07-08 jrick goto done;
11175 624411d2 2023-07-08 jrick printf("Forwarding %s to commit %s\n",
11176 624411d2 2023-07-08 jrick got_ref_get_name(branch), id_str);
11177 624411d2 2023-07-08 jrick free(id_str);
11178 624411d2 2023-07-08 jrick error = got_ref_change_ref(branch,
11179 624411d2 2023-07-08 jrick new_head_commit_id);
11180 624411d2 2023-07-08 jrick if (error)
11181 624411d2 2023-07-08 jrick goto done;
11182 624411d2 2023-07-08 jrick /* No backup needed since objects did not change. */
11183 624411d2 2023-07-08 jrick create_backup = 0;
11187 624411d2 2023-07-08 jrick pid = NULL;
11188 624411d2 2023-07-08 jrick STAILQ_FOREACH(qid, &commits, entry) {
11190 624411d2 2023-07-08 jrick commit_id = &qid->id;
11191 624411d2 2023-07-08 jrick parent_id = pid ? &pid->id : yca_id;
11192 624411d2 2023-07-08 jrick pid = qid;
11194 624411d2 2023-07-08 jrick memset(&upa, 0, sizeof(upa));
11195 624411d2 2023-07-08 jrick error = got_worktree_rebase_merge_files(&merged_paths,
11196 624411d2 2023-07-08 jrick worktree, fileindex, parent_id, commit_id, repo,
11197 624411d2 2023-07-08 jrick update_progress, &upa, check_cancelled, NULL);
11198 624411d2 2023-07-08 jrick if (error)
11199 624411d2 2023-07-08 jrick goto done;
11201 624411d2 2023-07-08 jrick print_merge_progress_stats(&upa);
11202 624411d2 2023-07-08 jrick if (upa.conflicts > 0 || upa.missing > 0 ||
11203 624411d2 2023-07-08 jrick upa.not_deleted > 0 || upa.unversioned > 0) {
11204 624411d2 2023-07-08 jrick if (upa.conflicts > 0) {
11205 624411d2 2023-07-08 jrick error = show_rebase_merge_conflict(&qid->id,
11207 624411d2 2023-07-08 jrick if (error)
11208 624411d2 2023-07-08 jrick goto done;
11210 624411d2 2023-07-08 jrick got_pathlist_free(&merged_paths, GOT_PATHLIST_FREE_PATH);
11214 624411d2 2023-07-08 jrick error = rebase_commit(&merged_paths, worktree, fileindex,
11215 624411d2 2023-07-08 jrick tmp_branch, committer, commit_id, 0, repo);
11216 624411d2 2023-07-08 jrick got_pathlist_free(&merged_paths, GOT_PATHLIST_FREE_PATH);
11217 624411d2 2023-07-08 jrick if (error)
11218 624411d2 2023-07-08 jrick goto done;
11221 624411d2 2023-07-08 jrick if (upa.conflicts > 0 || upa.missing > 0 ||
11222 624411d2 2023-07-08 jrick upa.not_deleted > 0 || upa.unversioned > 0) {
11223 624411d2 2023-07-08 jrick error = got_worktree_rebase_postpone(worktree, fileindex);
11224 624411d2 2023-07-08 jrick if (error)
11225 624411d2 2023-07-08 jrick goto done;
11226 624411d2 2023-07-08 jrick if (upa.conflicts > 0 && upa.missing == 0 &&
11227 624411d2 2023-07-08 jrick upa.not_deleted == 0 && upa.unversioned == 0) {
11228 624411d2 2023-07-08 jrick error = got_error_msg(GOT_ERR_CONFLICTS,
11229 624411d2 2023-07-08 jrick "conflicts must be resolved before rebasing "
11230 624411d2 2023-07-08 jrick "can continue");
11231 624411d2 2023-07-08 jrick } else if (upa.conflicts > 0) {
11232 624411d2 2023-07-08 jrick error = got_error_msg(GOT_ERR_CONFLICTS,
11233 624411d2 2023-07-08 jrick "conflicts must be resolved before rebasing "
11234 624411d2 2023-07-08 jrick "can continue; changes destined for some "
11235 624411d2 2023-07-08 jrick "files were not yet merged and should be "
11236 624411d2 2023-07-08 jrick "merged manually if required before the "
11237 624411d2 2023-07-08 jrick "rebase operation is continued");
11238 624411d2 2023-07-08 jrick } else {
11239 624411d2 2023-07-08 jrick error = got_error_msg(GOT_ERR_CONFLICTS,
11240 624411d2 2023-07-08 jrick "changes destined for some files were not "
11241 624411d2 2023-07-08 jrick "yet merged and should be merged manually "
11242 624411d2 2023-07-08 jrick "if required before the rebase operation "
11243 624411d2 2023-07-08 jrick "is continued");
11246 624411d2 2023-07-08 jrick error = rebase_complete(worktree, fileindex, branch,
11247 624411d2 2023-07-08 jrick tmp_branch, repo, create_backup);
11249 624411d2 2023-07-08 jrick free(cwd);
11250 624411d2 2023-07-08 jrick free(committer);
11251 624411d2 2023-07-08 jrick free(gitconfig_path);
11252 624411d2 2023-07-08 jrick got_object_id_queue_free(&commits);
11253 624411d2 2023-07-08 jrick free(branch_head_commit_id);
11254 624411d2 2023-07-08 jrick free(resume_commit_id);
11255 624411d2 2023-07-08 jrick free(head_commit_id);
11256 624411d2 2023-07-08 jrick free(yca_id);
11257 624411d2 2023-07-08 jrick if (commit)
11258 624411d2 2023-07-08 jrick got_object_commit_close(commit);
11259 624411d2 2023-07-08 jrick if (branch)
11260 624411d2 2023-07-08 jrick got_ref_close(branch);
11261 624411d2 2023-07-08 jrick if (new_base_branch)
11262 624411d2 2023-07-08 jrick got_ref_close(new_base_branch);
11263 624411d2 2023-07-08 jrick if (tmp_branch)
11264 624411d2 2023-07-08 jrick got_ref_close(tmp_branch);
11265 624411d2 2023-07-08 jrick if (head_ref)
11266 624411d2 2023-07-08 jrick got_ref_close(head_ref);
11267 624411d2 2023-07-08 jrick if (worktree)
11268 624411d2 2023-07-08 jrick got_worktree_close(worktree);
11269 624411d2 2023-07-08 jrick if (repo) {
11270 624411d2 2023-07-08 jrick const struct got_error *close_err = got_repo_close(repo);
11271 624411d2 2023-07-08 jrick if (error == NULL)
11272 624411d2 2023-07-08 jrick error = close_err;
11274 624411d2 2023-07-08 jrick if (pack_fds) {
11275 624411d2 2023-07-08 jrick const struct got_error *pack_err =
11276 624411d2 2023-07-08 jrick got_repo_pack_fds_close(pack_fds);
11277 624411d2 2023-07-08 jrick if (error == NULL)
11278 624411d2 2023-07-08 jrick error = pack_err;
11280 624411d2 2023-07-08 jrick return error;
11283 624411d2 2023-07-08 jrick __dead static void
11284 624411d2 2023-07-08 jrick usage_histedit(void)
11286 624411d2 2023-07-08 jrick fprintf(stderr, "usage: %s histedit [-aCcdeflmX] [-F histedit-script] "
11287 624411d2 2023-07-08 jrick "[branch]\n", getprogname());
11288 624411d2 2023-07-08 jrick exit(1);
11291 624411d2 2023-07-08 jrick #define GOT_HISTEDIT_PICK 'p'
11292 624411d2 2023-07-08 jrick #define GOT_HISTEDIT_EDIT 'e'
11293 624411d2 2023-07-08 jrick #define GOT_HISTEDIT_FOLD 'f'
11294 624411d2 2023-07-08 jrick #define GOT_HISTEDIT_DROP 'd'
11295 624411d2 2023-07-08 jrick #define GOT_HISTEDIT_MESG 'm'
11297 624411d2 2023-07-08 jrick static const struct got_histedit_cmd {
11298 624411d2 2023-07-08 jrick unsigned char code;
11299 624411d2 2023-07-08 jrick const char *name;
11300 624411d2 2023-07-08 jrick const char *desc;
11301 624411d2 2023-07-08 jrick } got_histedit_cmds[] = {
11302 624411d2 2023-07-08 jrick { GOT_HISTEDIT_PICK, "pick", "use commit" },
11303 624411d2 2023-07-08 jrick { GOT_HISTEDIT_EDIT, "edit", "use commit but stop for amending" },
11304 624411d2 2023-07-08 jrick { GOT_HISTEDIT_FOLD, "fold", "combine with next commit that will "
11305 624411d2 2023-07-08 jrick "be used" },
11306 624411d2 2023-07-08 jrick { GOT_HISTEDIT_DROP, "drop", "remove commit from history" },
11307 624411d2 2023-07-08 jrick { GOT_HISTEDIT_MESG, "mesg",
11308 624411d2 2023-07-08 jrick "single-line log message for commit above (open editor if empty)" },
11311 624411d2 2023-07-08 jrick struct got_histedit_list_entry {
11312 624411d2 2023-07-08 jrick TAILQ_ENTRY(got_histedit_list_entry) entry;
11313 624411d2 2023-07-08 jrick struct got_object_id *commit_id;
11314 624411d2 2023-07-08 jrick const struct got_histedit_cmd *cmd;
11315 624411d2 2023-07-08 jrick char *logmsg;
11317 624411d2 2023-07-08 jrick TAILQ_HEAD(got_histedit_list, got_histedit_list_entry);
11319 624411d2 2023-07-08 jrick static const struct got_error *
11320 624411d2 2023-07-08 jrick histedit_write_commit(struct got_object_id *commit_id, const char *cmdname,
11321 624411d2 2023-07-08 jrick FILE *f, struct got_repository *repo)
11323 624411d2 2023-07-08 jrick const struct got_error *err = NULL;
11324 624411d2 2023-07-08 jrick char *logmsg = NULL, *id_str = NULL;
11325 624411d2 2023-07-08 jrick struct got_commit_object *commit = NULL;
11328 624411d2 2023-07-08 jrick err = got_object_open_as_commit(&commit, repo, commit_id);
11329 624411d2 2023-07-08 jrick if (err)
11330 624411d2 2023-07-08 jrick goto done;
11332 624411d2 2023-07-08 jrick err = get_short_logmsg(&logmsg, 34, commit);
11333 624411d2 2023-07-08 jrick if (err)
11334 624411d2 2023-07-08 jrick goto done;
11336 624411d2 2023-07-08 jrick err = got_object_id_str(&id_str, commit_id);
11337 624411d2 2023-07-08 jrick if (err)
11338 624411d2 2023-07-08 jrick goto done;
11340 624411d2 2023-07-08 jrick n = fprintf(f, "%s %s %s\n", cmdname, id_str, logmsg);
11341 624411d2 2023-07-08 jrick if (n < 0)
11342 624411d2 2023-07-08 jrick err = got_ferror(f, GOT_ERR_IO);
11344 624411d2 2023-07-08 jrick if (commit)
11345 624411d2 2023-07-08 jrick got_object_commit_close(commit);
11346 624411d2 2023-07-08 jrick free(id_str);
11347 624411d2 2023-07-08 jrick free(logmsg);
11348 624411d2 2023-07-08 jrick return err;
11351 624411d2 2023-07-08 jrick static const struct got_error *
11352 624411d2 2023-07-08 jrick histedit_write_commit_list(struct got_object_id_queue *commits,
11353 624411d2 2023-07-08 jrick FILE *f, int edit_logmsg_only, int fold_only, int drop_only,
11354 624411d2 2023-07-08 jrick int edit_only, struct got_repository *repo)
11356 624411d2 2023-07-08 jrick const struct got_error *err = NULL;
11357 624411d2 2023-07-08 jrick struct got_object_qid *qid;
11358 624411d2 2023-07-08 jrick const char *histedit_cmd = NULL;
11360 624411d2 2023-07-08 jrick if (STAILQ_EMPTY(commits))
11361 624411d2 2023-07-08 jrick return got_error(GOT_ERR_EMPTY_HISTEDIT);
11363 624411d2 2023-07-08 jrick STAILQ_FOREACH(qid, commits, entry) {
11364 624411d2 2023-07-08 jrick histedit_cmd = got_histedit_cmds[0].name;
11365 624411d2 2023-07-08 jrick if (drop_only)
11366 624411d2 2023-07-08 jrick histedit_cmd = "drop";
11367 624411d2 2023-07-08 jrick else if (edit_only)
11368 624411d2 2023-07-08 jrick histedit_cmd = "edit";
11369 624411d2 2023-07-08 jrick else if (fold_only && STAILQ_NEXT(qid, entry) != NULL)
11370 624411d2 2023-07-08 jrick histedit_cmd = "fold";
11371 624411d2 2023-07-08 jrick err = histedit_write_commit(&qid->id, histedit_cmd, f, repo);
11372 624411d2 2023-07-08 jrick if (err)
11374 624411d2 2023-07-08 jrick if (edit_logmsg_only) {
11375 624411d2 2023-07-08 jrick int n = fprintf(f, "%c\n", GOT_HISTEDIT_MESG);
11376 624411d2 2023-07-08 jrick if (n < 0) {
11377 624411d2 2023-07-08 jrick err = got_ferror(f, GOT_ERR_IO);
11383 624411d2 2023-07-08 jrick return err;
11386 624411d2 2023-07-08 jrick static const struct got_error *
11387 624411d2 2023-07-08 jrick write_cmd_list(FILE *f, const char *branch_name,
11388 624411d2 2023-07-08 jrick struct got_object_id_queue *commits)
11390 624411d2 2023-07-08 jrick const struct got_error *err = NULL;
11391 624411d2 2023-07-08 jrick size_t i;
11393 624411d2 2023-07-08 jrick char *id_str;
11394 624411d2 2023-07-08 jrick struct got_object_qid *qid;
11396 624411d2 2023-07-08 jrick qid = STAILQ_FIRST(commits);
11397 624411d2 2023-07-08 jrick err = got_object_id_str(&id_str, &qid->id);
11398 624411d2 2023-07-08 jrick if (err)
11399 624411d2 2023-07-08 jrick return err;
11401 624411d2 2023-07-08 jrick n = fprintf(f,
11402 624411d2 2023-07-08 jrick "# Editing the history of branch '%s' starting at\n"
11403 624411d2 2023-07-08 jrick "# commit %s\n"
11404 624411d2 2023-07-08 jrick "# Commits will be processed in order from top to "
11405 624411d2 2023-07-08 jrick "bottom of this file.\n", branch_name, id_str);
11406 624411d2 2023-07-08 jrick if (n < 0) {
11407 624411d2 2023-07-08 jrick err = got_ferror(f, GOT_ERR_IO);
11408 624411d2 2023-07-08 jrick goto done;
11411 624411d2 2023-07-08 jrick n = fprintf(f, "# Available histedit commands:\n");
11412 624411d2 2023-07-08 jrick if (n < 0) {
11413 624411d2 2023-07-08 jrick err = got_ferror(f, GOT_ERR_IO);
11414 624411d2 2023-07-08 jrick goto done;
11417 624411d2 2023-07-08 jrick for (i = 0; i < nitems(got_histedit_cmds); i++) {
11418 624411d2 2023-07-08 jrick const struct got_histedit_cmd *cmd = &got_histedit_cmds[i];
11419 624411d2 2023-07-08 jrick n = fprintf(f, "# %s (%c): %s\n", cmd->name, cmd->code,
11420 624411d2 2023-07-08 jrick cmd->desc);
11421 624411d2 2023-07-08 jrick if (n < 0) {
11422 624411d2 2023-07-08 jrick err = got_ferror(f, GOT_ERR_IO);
11427 624411d2 2023-07-08 jrick free(id_str);
11428 624411d2 2023-07-08 jrick return err;
11431 624411d2 2023-07-08 jrick static const struct got_error *
11432 624411d2 2023-07-08 jrick histedit_syntax_error(int lineno)
11434 624411d2 2023-07-08 jrick static char msg[42];
11435 624411d2 2023-07-08 jrick int ret;
11437 624411d2 2023-07-08 jrick ret = snprintf(msg, sizeof(msg), "histedit syntax error on line %d",
11438 624411d2 2023-07-08 jrick lineno);
11439 624411d2 2023-07-08 jrick if (ret < 0 || (size_t)ret >= sizeof(msg))
11440 624411d2 2023-07-08 jrick return got_error(GOT_ERR_HISTEDIT_SYNTAX);
11442 624411d2 2023-07-08 jrick return got_error_msg(GOT_ERR_HISTEDIT_SYNTAX, msg);
11445 624411d2 2023-07-08 jrick static const struct got_error *
11446 624411d2 2023-07-08 jrick append_folded_commit_msg(char **new_msg, struct got_histedit_list_entry *hle,
11447 624411d2 2023-07-08 jrick char *logmsg, struct got_repository *repo)
11449 624411d2 2023-07-08 jrick const struct got_error *err;
11450 624411d2 2023-07-08 jrick struct got_commit_object *folded_commit = NULL;
11451 624411d2 2023-07-08 jrick char *id_str, *folded_logmsg = NULL;
11453 624411d2 2023-07-08 jrick err = got_object_id_str(&id_str, hle->commit_id);
11454 624411d2 2023-07-08 jrick if (err)
11455 624411d2 2023-07-08 jrick return err;
11457 624411d2 2023-07-08 jrick err = got_object_open_as_commit(&folded_commit, repo, hle->commit_id);
11458 624411d2 2023-07-08 jrick if (err)
11459 624411d2 2023-07-08 jrick goto done;
11461 624411d2 2023-07-08 jrick err = got_object_commit_get_logmsg(&folded_logmsg, folded_commit);
11462 624411d2 2023-07-08 jrick if (err)
11463 624411d2 2023-07-08 jrick goto done;
11464 624411d2 2023-07-08 jrick if (asprintf(new_msg, "%s%s# log message of folded commit %s: %s",
11465 624411d2 2023-07-08 jrick logmsg ? logmsg : "", logmsg ? "\n" : "", id_str,
11466 624411d2 2023-07-08 jrick folded_logmsg) == -1) {
11467 624411d2 2023-07-08 jrick err = got_error_from_errno("asprintf");
11470 624411d2 2023-07-08 jrick if (folded_commit)
11471 624411d2 2023-07-08 jrick got_object_commit_close(folded_commit);
11472 624411d2 2023-07-08 jrick free(id_str);
11473 624411d2 2023-07-08 jrick free(folded_logmsg);
11474 624411d2 2023-07-08 jrick return err;
11477 624411d2 2023-07-08 jrick static struct got_histedit_list_entry *
11478 624411d2 2023-07-08 jrick get_folded_commits(struct got_histedit_list_entry *hle)
11480 624411d2 2023-07-08 jrick struct got_histedit_list_entry *prev, *folded = NULL;
11482 624411d2 2023-07-08 jrick prev = TAILQ_PREV(hle, got_histedit_list, entry);
11483 624411d2 2023-07-08 jrick while (prev && (prev->cmd->code == GOT_HISTEDIT_FOLD ||
11484 624411d2 2023-07-08 jrick prev->cmd->code == GOT_HISTEDIT_DROP)) {
11485 624411d2 2023-07-08 jrick if (prev->cmd->code == GOT_HISTEDIT_FOLD)
11486 624411d2 2023-07-08 jrick folded = prev;
11487 624411d2 2023-07-08 jrick prev = TAILQ_PREV(prev, got_histedit_list, entry);
11490 624411d2 2023-07-08 jrick return folded;
11493 624411d2 2023-07-08 jrick static const struct got_error *
11494 624411d2 2023-07-08 jrick histedit_edit_logmsg(struct got_histedit_list_entry *hle,
11495 624411d2 2023-07-08 jrick struct got_repository *repo)
11497 624411d2 2023-07-08 jrick char *logmsg_path = NULL, *id_str = NULL, *orig_logmsg = NULL;
11498 624411d2 2023-07-08 jrick char *logmsg = NULL, *new_msg = NULL, *editor = NULL;
11499 624411d2 2023-07-08 jrick const struct got_error *err = NULL;
11500 624411d2 2023-07-08 jrick struct got_commit_object *commit = NULL;
11501 624411d2 2023-07-08 jrick int logmsg_len;
11502 624411d2 2023-07-08 jrick int fd = -1;
11503 624411d2 2023-07-08 jrick struct got_histedit_list_entry *folded = NULL;
11505 624411d2 2023-07-08 jrick err = got_object_open_as_commit(&commit, repo, hle->commit_id);
11506 624411d2 2023-07-08 jrick if (err)
11507 624411d2 2023-07-08 jrick return err;
11509 624411d2 2023-07-08 jrick folded = get_folded_commits(hle);
11510 624411d2 2023-07-08 jrick if (folded) {
11511 624411d2 2023-07-08 jrick while (folded != hle) {
11512 624411d2 2023-07-08 jrick if (folded->cmd->code == GOT_HISTEDIT_DROP) {
11513 624411d2 2023-07-08 jrick folded = TAILQ_NEXT(folded, entry);
11514 624411d2 2023-07-08 jrick continue;
11516 624411d2 2023-07-08 jrick err = append_folded_commit_msg(&new_msg, folded,
11517 624411d2 2023-07-08 jrick logmsg, repo);
11518 624411d2 2023-07-08 jrick if (err)
11519 624411d2 2023-07-08 jrick goto done;
11520 624411d2 2023-07-08 jrick free(logmsg);
11521 624411d2 2023-07-08 jrick logmsg = new_msg;
11522 624411d2 2023-07-08 jrick folded = TAILQ_NEXT(folded, entry);
11526 624411d2 2023-07-08 jrick err = got_object_id_str(&id_str, hle->commit_id);
11527 624411d2 2023-07-08 jrick if (err)
11528 624411d2 2023-07-08 jrick goto done;
11529 624411d2 2023-07-08 jrick err = got_object_commit_get_logmsg(&orig_logmsg, commit);
11530 624411d2 2023-07-08 jrick if (err)
11531 624411d2 2023-07-08 jrick goto done;
11532 624411d2 2023-07-08 jrick logmsg_len = asprintf(&new_msg,
11533 624411d2 2023-07-08 jrick "%s\n# original log message of commit %s: %s",
11534 624411d2 2023-07-08 jrick logmsg ? logmsg : "", id_str, orig_logmsg);
11535 624411d2 2023-07-08 jrick if (logmsg_len == -1) {
11536 624411d2 2023-07-08 jrick err = got_error_from_errno("asprintf");
11537 624411d2 2023-07-08 jrick goto done;
11539 624411d2 2023-07-08 jrick free(logmsg);
11540 624411d2 2023-07-08 jrick logmsg = new_msg;
11542 624411d2 2023-07-08 jrick err = got_object_id_str(&id_str, hle->commit_id);
11543 624411d2 2023-07-08 jrick if (err)
11544 624411d2 2023-07-08 jrick goto done;
11546 624411d2 2023-07-08 jrick err = got_opentemp_named_fd(&logmsg_path, &fd,
11547 624411d2 2023-07-08 jrick GOT_TMPDIR_STR "/got-logmsg", "");
11548 624411d2 2023-07-08 jrick if (err)
11549 624411d2 2023-07-08 jrick goto done;
11551 624411d2 2023-07-08 jrick if (write(fd, logmsg, logmsg_len) == -1) {
11552 624411d2 2023-07-08 jrick err = got_error_from_errno2("write", logmsg_path);
11553 624411d2 2023-07-08 jrick goto done;
11555 624411d2 2023-07-08 jrick if (close(fd) == -1) {
11556 624411d2 2023-07-08 jrick err = got_error_from_errno2("close", logmsg_path);
11557 624411d2 2023-07-08 jrick goto done;
11559 624411d2 2023-07-08 jrick fd = -1;
11561 624411d2 2023-07-08 jrick err = get_editor(&editor);
11562 624411d2 2023-07-08 jrick if (err)
11563 624411d2 2023-07-08 jrick goto done;
11565 624411d2 2023-07-08 jrick err = edit_logmsg(&hle->logmsg, editor, logmsg_path, logmsg,
11566 624411d2 2023-07-08 jrick logmsg_len, 0);
11567 624411d2 2023-07-08 jrick if (err) {
11568 624411d2 2023-07-08 jrick if (err->code != GOT_ERR_COMMIT_MSG_EMPTY)
11569 624411d2 2023-07-08 jrick goto done;
11570 624411d2 2023-07-08 jrick err = NULL;
11571 624411d2 2023-07-08 jrick hle->logmsg = strdup(new_msg);
11572 624411d2 2023-07-08 jrick if (hle->logmsg == NULL)
11573 624411d2 2023-07-08 jrick err = got_error_from_errno("strdup");
11576 624411d2 2023-07-08 jrick if (fd != -1 && close(fd) == -1 && err == NULL)
11577 624411d2 2023-07-08 jrick err = got_error_from_errno2("close", logmsg_path);
11578 624411d2 2023-07-08 jrick if (logmsg_path && unlink(logmsg_path) != 0 && err == NULL)
11579 624411d2 2023-07-08 jrick err = got_error_from_errno2("unlink", logmsg_path);
11580 624411d2 2023-07-08 jrick free(logmsg_path);
11581 624411d2 2023-07-08 jrick free(logmsg);
11582 624411d2 2023-07-08 jrick free(orig_logmsg);
11583 624411d2 2023-07-08 jrick free(editor);
11584 624411d2 2023-07-08 jrick if (commit)
11585 624411d2 2023-07-08 jrick got_object_commit_close(commit);
11586 624411d2 2023-07-08 jrick return err;
11589 624411d2 2023-07-08 jrick static const struct got_error *
11590 624411d2 2023-07-08 jrick histedit_parse_list(struct got_histedit_list *histedit_cmds,
11591 624411d2 2023-07-08 jrick FILE *f, struct got_repository *repo)
11593 624411d2 2023-07-08 jrick const struct got_error *err = NULL;
11594 624411d2 2023-07-08 jrick char *line = NULL, *p, *end;
11595 624411d2 2023-07-08 jrick size_t i, linesize = 0;
11596 624411d2 2023-07-08 jrick ssize_t linelen;
11597 624411d2 2023-07-08 jrick int lineno = 0, lastcmd = -1;
11598 624411d2 2023-07-08 jrick const struct got_histedit_cmd *cmd;
11599 624411d2 2023-07-08 jrick struct got_object_id *commit_id = NULL;
11600 624411d2 2023-07-08 jrick struct got_histedit_list_entry *hle = NULL;
11602 624411d2 2023-07-08 jrick for (;;) {
11603 624411d2 2023-07-08 jrick linelen = getline(&line, &linesize, f);
11604 624411d2 2023-07-08 jrick if (linelen == -1) {
11605 624411d2 2023-07-08 jrick const struct got_error *getline_err;
11606 624411d2 2023-07-08 jrick if (feof(f))
11608 624411d2 2023-07-08 jrick getline_err = got_error_from_errno("getline");
11609 624411d2 2023-07-08 jrick err = got_ferror(f, getline_err->code);
11612 624411d2 2023-07-08 jrick lineno++;
11613 624411d2 2023-07-08 jrick p = line;
11614 624411d2 2023-07-08 jrick while (isspace((unsigned char)p[0]))
11616 624411d2 2023-07-08 jrick if (p[0] == '#' || p[0] == '\0')
11617 624411d2 2023-07-08 jrick continue;
11618 624411d2 2023-07-08 jrick cmd = NULL;
11619 624411d2 2023-07-08 jrick for (i = 0; i < nitems(got_histedit_cmds); i++) {
11620 624411d2 2023-07-08 jrick cmd = &got_histedit_cmds[i];
11621 624411d2 2023-07-08 jrick if (strncmp(cmd->name, p, strlen(cmd->name)) == 0 &&
11622 624411d2 2023-07-08 jrick isspace((unsigned char)p[strlen(cmd->name)])) {
11623 624411d2 2023-07-08 jrick p += strlen(cmd->name);
11626 624411d2 2023-07-08 jrick if (p[0] == cmd->code && isspace((unsigned char)p[1])) {
11631 624411d2 2023-07-08 jrick if (i == nitems(got_histedit_cmds)) {
11632 624411d2 2023-07-08 jrick err = histedit_syntax_error(lineno);
11635 624411d2 2023-07-08 jrick while (isspace((unsigned char)p[0]))
11637 624411d2 2023-07-08 jrick if (cmd->code == GOT_HISTEDIT_MESG) {
11638 624411d2 2023-07-08 jrick if (lastcmd != GOT_HISTEDIT_PICK &&
11639 624411d2 2023-07-08 jrick lastcmd != GOT_HISTEDIT_EDIT) {
11640 624411d2 2023-07-08 jrick err = got_error(GOT_ERR_HISTEDIT_CMD);
11643 624411d2 2023-07-08 jrick if (p[0] == '\0') {
11644 624411d2 2023-07-08 jrick err = histedit_edit_logmsg(hle, repo);
11645 624411d2 2023-07-08 jrick if (err)
11647 624411d2 2023-07-08 jrick } else {
11648 624411d2 2023-07-08 jrick hle->logmsg = strdup(p);
11649 624411d2 2023-07-08 jrick if (hle->logmsg == NULL) {
11650 624411d2 2023-07-08 jrick err = got_error_from_errno("strdup");
11654 624411d2 2023-07-08 jrick lastcmd = cmd->code;
11655 624411d2 2023-07-08 jrick continue;
11656 624411d2 2023-07-08 jrick } else {
11657 624411d2 2023-07-08 jrick end = p;
11658 624411d2 2023-07-08 jrick while (end[0] && !isspace((unsigned char)end[0]))
11660 624411d2 2023-07-08 jrick *end = '\0';
11662 624411d2 2023-07-08 jrick err = got_object_resolve_id_str(&commit_id, repo, p);
11663 624411d2 2023-07-08 jrick if (err) {
11664 624411d2 2023-07-08 jrick /* override error code */
11665 624411d2 2023-07-08 jrick err = histedit_syntax_error(lineno);
11669 624411d2 2023-07-08 jrick hle = malloc(sizeof(*hle));
11670 624411d2 2023-07-08 jrick if (hle == NULL) {
11671 624411d2 2023-07-08 jrick err = got_error_from_errno("malloc");
11674 624411d2 2023-07-08 jrick hle->cmd = cmd;
11675 624411d2 2023-07-08 jrick hle->commit_id = commit_id;
11676 624411d2 2023-07-08 jrick hle->logmsg = NULL;
11677 624411d2 2023-07-08 jrick commit_id = NULL;
11678 624411d2 2023-07-08 jrick TAILQ_INSERT_TAIL(histedit_cmds, hle, entry);
11679 624411d2 2023-07-08 jrick lastcmd = cmd->code;
11682 624411d2 2023-07-08 jrick free(line);
11683 624411d2 2023-07-08 jrick free(commit_id);
11684 624411d2 2023-07-08 jrick return err;
11687 624411d2 2023-07-08 jrick static const struct got_error *
11688 624411d2 2023-07-08 jrick histedit_check_script(struct got_histedit_list *histedit_cmds,
11689 624411d2 2023-07-08 jrick struct got_object_id_queue *commits, struct got_repository *repo)
11691 624411d2 2023-07-08 jrick const struct got_error *err = NULL;
11692 624411d2 2023-07-08 jrick struct got_object_qid *qid;
11693 624411d2 2023-07-08 jrick struct got_histedit_list_entry *hle;
11694 624411d2 2023-07-08 jrick static char msg[92];
11695 624411d2 2023-07-08 jrick char *id_str;
11697 624411d2 2023-07-08 jrick if (TAILQ_EMPTY(histedit_cmds))
11698 624411d2 2023-07-08 jrick return got_error_msg(GOT_ERR_EMPTY_HISTEDIT,
11699 624411d2 2023-07-08 jrick "histedit script contains no commands");
11700 624411d2 2023-07-08 jrick if (STAILQ_EMPTY(commits))
11701 624411d2 2023-07-08 jrick return got_error(GOT_ERR_EMPTY_HISTEDIT);
11703 624411d2 2023-07-08 jrick TAILQ_FOREACH(hle, histedit_cmds, entry) {
11704 624411d2 2023-07-08 jrick struct got_histedit_list_entry *hle2;
11705 624411d2 2023-07-08 jrick TAILQ_FOREACH(hle2, histedit_cmds, entry) {
11706 624411d2 2023-07-08 jrick if (hle == hle2)
11707 624411d2 2023-07-08 jrick continue;
11708 624411d2 2023-07-08 jrick if (got_object_id_cmp(hle->commit_id,
11709 624411d2 2023-07-08 jrick hle2->commit_id) != 0)
11710 624411d2 2023-07-08 jrick continue;
11711 624411d2 2023-07-08 jrick err = got_object_id_str(&id_str, hle->commit_id);
11712 624411d2 2023-07-08 jrick if (err)
11713 624411d2 2023-07-08 jrick return err;
11714 624411d2 2023-07-08 jrick snprintf(msg, sizeof(msg), "commit %s is listed "
11715 624411d2 2023-07-08 jrick "more than once in histedit script", id_str);
11716 624411d2 2023-07-08 jrick free(id_str);
11717 624411d2 2023-07-08 jrick return got_error_msg(GOT_ERR_HISTEDIT_CMD, msg);
11721 624411d2 2023-07-08 jrick STAILQ_FOREACH(qid, commits, entry) {
11722 624411d2 2023-07-08 jrick TAILQ_FOREACH(hle, histedit_cmds, entry) {
11723 624411d2 2023-07-08 jrick if (got_object_id_cmp(&qid->id, hle->commit_id) == 0)
11726 624411d2 2023-07-08 jrick if (hle == NULL) {
11727 624411d2 2023-07-08 jrick err = got_object_id_str(&id_str, &qid->id);
11728 624411d2 2023-07-08 jrick if (err)
11729 624411d2 2023-07-08 jrick return err;
11730 624411d2 2023-07-08 jrick snprintf(msg, sizeof(msg),
11731 624411d2 2023-07-08 jrick "commit %s missing from histedit script", id_str);
11732 624411d2 2023-07-08 jrick free(id_str);
11733 624411d2 2023-07-08 jrick return got_error_msg(GOT_ERR_HISTEDIT_CMD, msg);
11737 624411d2 2023-07-08 jrick hle = TAILQ_LAST(histedit_cmds, got_histedit_list);
11738 624411d2 2023-07-08 jrick if (hle && hle->cmd->code == GOT_HISTEDIT_FOLD)
11739 624411d2 2023-07-08 jrick return got_error_msg(GOT_ERR_HISTEDIT_CMD,
11740 624411d2 2023-07-08 jrick "last commit in histedit script cannot be folded");
11742 624411d2 2023-07-08 jrick return NULL;
11745 624411d2 2023-07-08 jrick static const struct got_error *
11746 624411d2 2023-07-08 jrick histedit_run_editor(struct got_histedit_list *histedit_cmds,
11747 624411d2 2023-07-08 jrick const char *path, struct got_object_id_queue *commits,
11748 624411d2 2023-07-08 jrick struct got_repository *repo)
11750 624411d2 2023-07-08 jrick const struct got_error *err = NULL;
11751 624411d2 2023-07-08 jrick char *editor;
11752 624411d2 2023-07-08 jrick FILE *f = NULL;
11754 624411d2 2023-07-08 jrick err = get_editor(&editor);
11755 624411d2 2023-07-08 jrick if (err)
11756 624411d2 2023-07-08 jrick return err;
11758 624411d2 2023-07-08 jrick if (spawn_editor(editor, path) == -1) {
11759 624411d2 2023-07-08 jrick err = got_error_from_errno("failed spawning editor");
11760 624411d2 2023-07-08 jrick goto done;
11763 624411d2 2023-07-08 jrick f = fopen(path, "re");
11764 624411d2 2023-07-08 jrick if (f == NULL) {
11765 624411d2 2023-07-08 jrick err = got_error_from_errno("fopen");
11766 624411d2 2023-07-08 jrick goto done;
11768 624411d2 2023-07-08 jrick err = histedit_parse_list(histedit_cmds, f, repo);
11769 624411d2 2023-07-08 jrick if (err)
11770 624411d2 2023-07-08 jrick goto done;
11772 624411d2 2023-07-08 jrick err = histedit_check_script(histedit_cmds, commits, repo);
11774 624411d2 2023-07-08 jrick if (f && fclose(f) == EOF && err == NULL)
11775 624411d2 2023-07-08 jrick err = got_error_from_errno("fclose");
11776 624411d2 2023-07-08 jrick free(editor);
11777 624411d2 2023-07-08 jrick return err;
11780 624411d2 2023-07-08 jrick static const struct got_error *
11781 624411d2 2023-07-08 jrick histedit_edit_list_retry(struct got_histedit_list *, const struct got_error *,
11782 624411d2 2023-07-08 jrick struct got_object_id_queue *, const char *, const char *,
11783 624411d2 2023-07-08 jrick struct got_repository *);
11785 624411d2 2023-07-08 jrick static const struct got_error *
11786 624411d2 2023-07-08 jrick histedit_edit_script(struct got_histedit_list *histedit_cmds,
11787 624411d2 2023-07-08 jrick struct got_object_id_queue *commits, const char *branch_name,
11788 624411d2 2023-07-08 jrick int edit_logmsg_only, int fold_only, int drop_only, int edit_only,
11789 624411d2 2023-07-08 jrick struct got_repository *repo)
11791 624411d2 2023-07-08 jrick const struct got_error *err;
11792 624411d2 2023-07-08 jrick FILE *f = NULL;
11793 624411d2 2023-07-08 jrick char *path = NULL;
11795 624411d2 2023-07-08 jrick err = got_opentemp_named(&path, &f, "got-histedit", "");
11796 624411d2 2023-07-08 jrick if (err)
11797 624411d2 2023-07-08 jrick return err;
11799 624411d2 2023-07-08 jrick err = write_cmd_list(f, branch_name, commits);
11800 624411d2 2023-07-08 jrick if (err)
11801 624411d2 2023-07-08 jrick goto done;
11803 624411d2 2023-07-08 jrick err = histedit_write_commit_list(commits, f, edit_logmsg_only,
11804 624411d2 2023-07-08 jrick fold_only, drop_only, edit_only, repo);
11805 624411d2 2023-07-08 jrick if (err)
11806 624411d2 2023-07-08 jrick goto done;
11808 624411d2 2023-07-08 jrick if (drop_only || edit_logmsg_only || fold_only || edit_only) {
11809 624411d2 2023-07-08 jrick rewind(f);
11810 624411d2 2023-07-08 jrick err = histedit_parse_list(histedit_cmds, f, repo);
11811 624411d2 2023-07-08 jrick } else {
11812 624411d2 2023-07-08 jrick if (fclose(f) == EOF) {
11813 624411d2 2023-07-08 jrick err = got_error_from_errno("fclose");
11814 624411d2 2023-07-08 jrick goto done;
11816 624411d2 2023-07-08 jrick f = NULL;
11817 624411d2 2023-07-08 jrick err = histedit_run_editor(histedit_cmds, path, commits, repo);
11818 624411d2 2023-07-08 jrick if (err) {
11819 624411d2 2023-07-08 jrick if (err->code != GOT_ERR_HISTEDIT_SYNTAX &&
11820 624411d2 2023-07-08 jrick err->code != GOT_ERR_HISTEDIT_CMD)
11821 624411d2 2023-07-08 jrick goto done;
11822 624411d2 2023-07-08 jrick err = histedit_edit_list_retry(histedit_cmds, err,
11823 624411d2 2023-07-08 jrick commits, path, branch_name, repo);
11827 624411d2 2023-07-08 jrick if (f && fclose(f) == EOF && err == NULL)
11828 624411d2 2023-07-08 jrick err = got_error_from_errno("fclose");
11829 624411d2 2023-07-08 jrick if (path && unlink(path) != 0 && err == NULL)
11830 624411d2 2023-07-08 jrick err = got_error_from_errno2("unlink", path);
11831 624411d2 2023-07-08 jrick free(path);
11832 624411d2 2023-07-08 jrick return err;
11835 624411d2 2023-07-08 jrick static const struct got_error *
11836 624411d2 2023-07-08 jrick histedit_save_list(struct got_histedit_list *histedit_cmds,
11837 624411d2 2023-07-08 jrick struct got_worktree *worktree, struct got_repository *repo)
11839 624411d2 2023-07-08 jrick const struct got_error *err = NULL;
11840 624411d2 2023-07-08 jrick char *path = NULL;
11841 624411d2 2023-07-08 jrick FILE *f = NULL;
11842 624411d2 2023-07-08 jrick struct got_histedit_list_entry *hle;
11843 624411d2 2023-07-08 jrick struct got_commit_object *commit = NULL;
11845 624411d2 2023-07-08 jrick err = got_worktree_get_histedit_script_path(&path, worktree);
11846 624411d2 2023-07-08 jrick if (err)
11847 624411d2 2023-07-08 jrick return err;
11849 624411d2 2023-07-08 jrick f = fopen(path, "we");
11850 624411d2 2023-07-08 jrick if (f == NULL) {
11851 624411d2 2023-07-08 jrick err = got_error_from_errno2("fopen", path);
11852 624411d2 2023-07-08 jrick goto done;
11854 624411d2 2023-07-08 jrick TAILQ_FOREACH(hle, histedit_cmds, entry) {
11855 624411d2 2023-07-08 jrick err = histedit_write_commit(hle->commit_id, hle->cmd->name, f,
11857 624411d2 2023-07-08 jrick if (err)
11860 624411d2 2023-07-08 jrick if (hle->logmsg) {
11861 624411d2 2023-07-08 jrick int n = fprintf(f, "%c %s\n",
11862 624411d2 2023-07-08 jrick GOT_HISTEDIT_MESG, hle->logmsg);
11863 624411d2 2023-07-08 jrick if (n < 0) {
11864 624411d2 2023-07-08 jrick err = got_ferror(f, GOT_ERR_IO);
11870 624411d2 2023-07-08 jrick if (f && fclose(f) == EOF && err == NULL)
11871 624411d2 2023-07-08 jrick err = got_error_from_errno("fclose");
11872 624411d2 2023-07-08 jrick free(path);
11873 624411d2 2023-07-08 jrick if (commit)
11874 624411d2 2023-07-08 jrick got_object_commit_close(commit);
11875 624411d2 2023-07-08 jrick return err;
11878 624411d2 2023-07-08 jrick static void
11879 624411d2 2023-07-08 jrick histedit_free_list(struct got_histedit_list *histedit_cmds)
11881 624411d2 2023-07-08 jrick struct got_histedit_list_entry *hle;
11883 624411d2 2023-07-08 jrick while ((hle = TAILQ_FIRST(histedit_cmds))) {
11884 624411d2 2023-07-08 jrick TAILQ_REMOVE(histedit_cmds, hle, entry);
11885 624411d2 2023-07-08 jrick free(hle);
11889 624411d2 2023-07-08 jrick static const struct got_error *
11890 624411d2 2023-07-08 jrick histedit_load_list(struct got_histedit_list *histedit_cmds,
11891 624411d2 2023-07-08 jrick const char *path, struct got_repository *repo)
11893 624411d2 2023-07-08 jrick const struct got_error *err = NULL;
11894 624411d2 2023-07-08 jrick FILE *f = NULL;
11896 624411d2 2023-07-08 jrick f = fopen(path, "re");
11897 624411d2 2023-07-08 jrick if (f == NULL) {
11898 624411d2 2023-07-08 jrick err = got_error_from_errno2("fopen", path);
11899 624411d2 2023-07-08 jrick goto done;
11902 624411d2 2023-07-08 jrick err = histedit_parse_list(histedit_cmds, f, repo);
11904 624411d2 2023-07-08 jrick if (f && fclose(f) == EOF && err == NULL)
11905 624411d2 2023-07-08 jrick err = got_error_from_errno("fclose");
11906 624411d2 2023-07-08 jrick return err;
11909 624411d2 2023-07-08 jrick static const struct got_error *
11910 624411d2 2023-07-08 jrick histedit_edit_list_retry(struct got_histedit_list *histedit_cmds,
11911 624411d2 2023-07-08 jrick const struct got_error *edit_err, struct got_object_id_queue *commits,
11912 624411d2 2023-07-08 jrick const char *path, const char *branch_name, struct got_repository *repo)
11914 624411d2 2023-07-08 jrick const struct got_error *err = NULL, *prev_err = edit_err;
11915 624411d2 2023-07-08 jrick int resp = ' ';
11917 624411d2 2023-07-08 jrick while (resp != 'c' && resp != 'r' && resp != 'a') {
11918 624411d2 2023-07-08 jrick printf("%s: %s\n(c)ontinue editing, (r)estart editing, "
11919 624411d2 2023-07-08 jrick "or (a)bort: ", getprogname(), prev_err->msg);
11920 624411d2 2023-07-08 jrick resp = getchar();
11921 624411d2 2023-07-08 jrick if (resp == '\n')
11922 624411d2 2023-07-08 jrick resp = getchar();
11923 624411d2 2023-07-08 jrick if (resp == 'c') {
11924 624411d2 2023-07-08 jrick histedit_free_list(histedit_cmds);
11925 624411d2 2023-07-08 jrick err = histedit_run_editor(histedit_cmds, path, commits,
11927 624411d2 2023-07-08 jrick if (err) {
11928 624411d2 2023-07-08 jrick if (err->code != GOT_ERR_HISTEDIT_SYNTAX &&
11929 624411d2 2023-07-08 jrick err->code != GOT_ERR_HISTEDIT_CMD)
11931 624411d2 2023-07-08 jrick prev_err = err;
11932 624411d2 2023-07-08 jrick resp = ' ';
11933 624411d2 2023-07-08 jrick continue;
11936 624411d2 2023-07-08 jrick } else if (resp == 'r') {
11937 624411d2 2023-07-08 jrick histedit_free_list(histedit_cmds);
11938 624411d2 2023-07-08 jrick err = histedit_edit_script(histedit_cmds,
11939 624411d2 2023-07-08 jrick commits, branch_name, 0, 0, 0, 0, repo);
11940 624411d2 2023-07-08 jrick if (err) {
11941 624411d2 2023-07-08 jrick if (err->code != GOT_ERR_HISTEDIT_SYNTAX &&
11942 624411d2 2023-07-08 jrick err->code != GOT_ERR_HISTEDIT_CMD)
11944 624411d2 2023-07-08 jrick prev_err = err;
11945 624411d2 2023-07-08 jrick resp = ' ';
11946 624411d2 2023-07-08 jrick continue;
11949 624411d2 2023-07-08 jrick } else if (resp == 'a') {
11950 624411d2 2023-07-08 jrick err = got_error(GOT_ERR_HISTEDIT_CANCEL);
11953 624411d2 2023-07-08 jrick printf("invalid response '%c'\n", resp);
11956 624411d2 2023-07-08 jrick return err;
11959 624411d2 2023-07-08 jrick static const struct got_error *
11960 624411d2 2023-07-08 jrick histedit_complete(struct got_worktree *worktree,
11961 624411d2 2023-07-08 jrick struct got_fileindex *fileindex, struct got_reference *tmp_branch,
11962 624411d2 2023-07-08 jrick struct got_reference *branch, struct got_repository *repo)
11964 624411d2 2023-07-08 jrick printf("Switching work tree to %s\n",
11965 624411d2 2023-07-08 jrick got_ref_get_symref_target(branch));
11966 624411d2 2023-07-08 jrick return got_worktree_histedit_complete(worktree, fileindex, tmp_branch,
11967 624411d2 2023-07-08 jrick branch, repo);
11970 624411d2 2023-07-08 jrick static const struct got_error *
11971 624411d2 2023-07-08 jrick show_histedit_progress(struct got_commit_object *commit,
11972 624411d2 2023-07-08 jrick struct got_histedit_list_entry *hle, struct got_object_id *new_id)
11974 624411d2 2023-07-08 jrick const struct got_error *err;
11975 624411d2 2023-07-08 jrick char *old_id_str = NULL, *new_id_str = NULL, *logmsg = NULL;
11977 624411d2 2023-07-08 jrick err = got_object_id_str(&old_id_str, hle->commit_id);
11978 624411d2 2023-07-08 jrick if (err)
11979 624411d2 2023-07-08 jrick goto done;
11981 624411d2 2023-07-08 jrick if (new_id) {
11982 624411d2 2023-07-08 jrick err = got_object_id_str(&new_id_str, new_id);
11983 624411d2 2023-07-08 jrick if (err)
11984 624411d2 2023-07-08 jrick goto done;
11987 624411d2 2023-07-08 jrick old_id_str[12] = '\0';
11988 624411d2 2023-07-08 jrick if (new_id_str)
11989 624411d2 2023-07-08 jrick new_id_str[12] = '\0';
11991 624411d2 2023-07-08 jrick if (hle->logmsg) {
11992 624411d2 2023-07-08 jrick logmsg = strdup(hle->logmsg);
11993 624411d2 2023-07-08 jrick if (logmsg == NULL) {
11994 624411d2 2023-07-08 jrick err = got_error_from_errno("strdup");
11995 624411d2 2023-07-08 jrick goto done;
11997 624411d2 2023-07-08 jrick trim_logmsg(logmsg, 42);
11998 624411d2 2023-07-08 jrick } else {
11999 624411d2 2023-07-08 jrick err = get_short_logmsg(&logmsg, 42, commit);
12000 624411d2 2023-07-08 jrick if (err)
12001 624411d2 2023-07-08 jrick goto done;
12004 624411d2 2023-07-08 jrick switch (hle->cmd->code) {
12005 624411d2 2023-07-08 jrick case GOT_HISTEDIT_PICK:
12006 624411d2 2023-07-08 jrick case GOT_HISTEDIT_EDIT:
12007 624411d2 2023-07-08 jrick printf("%s -> %s: %s\n", old_id_str,
12008 624411d2 2023-07-08 jrick new_id_str ? new_id_str : "no-op change", logmsg);
12010 624411d2 2023-07-08 jrick case GOT_HISTEDIT_DROP:
12011 624411d2 2023-07-08 jrick case GOT_HISTEDIT_FOLD:
12012 624411d2 2023-07-08 jrick printf("%s -> %s commit: %s\n", old_id_str, hle->cmd->name,
12013 624411d2 2023-07-08 jrick logmsg);
12015 624411d2 2023-07-08 jrick default:
12019 624411d2 2023-07-08 jrick free(old_id_str);
12020 624411d2 2023-07-08 jrick free(new_id_str);
12021 624411d2 2023-07-08 jrick return err;
12024 624411d2 2023-07-08 jrick static const struct got_error *
12025 624411d2 2023-07-08 jrick histedit_commit(struct got_pathlist_head *merged_paths,
12026 624411d2 2023-07-08 jrick struct got_worktree *worktree, struct got_fileindex *fileindex,
12027 624411d2 2023-07-08 jrick struct got_reference *tmp_branch, struct got_histedit_list_entry *hle,
12028 624411d2 2023-07-08 jrick const char *committer, int allow_conflict, struct got_repository *repo)
12030 624411d2 2023-07-08 jrick const struct got_error *err;
12031 624411d2 2023-07-08 jrick struct got_commit_object *commit;
12032 624411d2 2023-07-08 jrick struct got_object_id *new_commit_id;
12034 624411d2 2023-07-08 jrick if ((hle->cmd->code == GOT_HISTEDIT_EDIT || get_folded_commits(hle))
12035 624411d2 2023-07-08 jrick && hle->logmsg == NULL) {
12036 624411d2 2023-07-08 jrick err = histedit_edit_logmsg(hle, repo);
12037 624411d2 2023-07-08 jrick if (err)
12038 624411d2 2023-07-08 jrick return err;
12041 624411d2 2023-07-08 jrick err = got_object_open_as_commit(&commit, repo, hle->commit_id);
12042 624411d2 2023-07-08 jrick if (err)
12043 624411d2 2023-07-08 jrick return err;
12045 624411d2 2023-07-08 jrick err = got_worktree_histedit_commit(&new_commit_id, merged_paths,
12046 624411d2 2023-07-08 jrick worktree, fileindex, tmp_branch, committer, commit, hle->commit_id,
12047 624411d2 2023-07-08 jrick hle->logmsg, allow_conflict, repo);
12048 624411d2 2023-07-08 jrick if (err) {
12049 624411d2 2023-07-08 jrick if (err->code != GOT_ERR_COMMIT_NO_CHANGES)
12050 624411d2 2023-07-08 jrick goto done;
12051 624411d2 2023-07-08 jrick err = show_histedit_progress(commit, hle, NULL);
12052 624411d2 2023-07-08 jrick } else {
12053 624411d2 2023-07-08 jrick err = show_histedit_progress(commit, hle, new_commit_id);
12054 624411d2 2023-07-08 jrick free(new_commit_id);
12057 624411d2 2023-07-08 jrick got_object_commit_close(commit);
12058 624411d2 2023-07-08 jrick return err;
12061 624411d2 2023-07-08 jrick static const struct got_error *
12062 624411d2 2023-07-08 jrick histedit_skip_commit(struct got_histedit_list_entry *hle,
12063 624411d2 2023-07-08 jrick struct got_worktree *worktree, struct got_repository *repo)
12065 624411d2 2023-07-08 jrick const struct got_error *error;
12066 624411d2 2023-07-08 jrick struct got_commit_object *commit;
12068 624411d2 2023-07-08 jrick error = got_worktree_histedit_skip_commit(worktree, hle->commit_id,
12070 624411d2 2023-07-08 jrick if (error)
12071 624411d2 2023-07-08 jrick return error;
12073 624411d2 2023-07-08 jrick error = got_object_open_as_commit(&commit, repo, hle->commit_id);
12074 624411d2 2023-07-08 jrick if (error)
12075 624411d2 2023-07-08 jrick return error;
12077 624411d2 2023-07-08 jrick error = show_histedit_progress(commit, hle, NULL);
12078 624411d2 2023-07-08 jrick got_object_commit_close(commit);
12079 624411d2 2023-07-08 jrick return error;
12082 624411d2 2023-07-08 jrick static const struct got_error *
12083 624411d2 2023-07-08 jrick check_local_changes(void *arg, unsigned char status,
12084 624411d2 2023-07-08 jrick unsigned char staged_status, const char *path,
12085 624411d2 2023-07-08 jrick struct got_object_id *blob_id, struct got_object_id *staged_blob_id,
12086 624411d2 2023-07-08 jrick struct got_object_id *commit_id, int dirfd, const char *de_name)
12088 624411d2 2023-07-08 jrick int *have_local_changes = arg;
12090 624411d2 2023-07-08 jrick switch (status) {
12091 624411d2 2023-07-08 jrick case GOT_STATUS_ADD:
12092 624411d2 2023-07-08 jrick case GOT_STATUS_DELETE:
12093 624411d2 2023-07-08 jrick case GOT_STATUS_MODIFY:
12094 624411d2 2023-07-08 jrick case GOT_STATUS_CONFLICT:
12095 624411d2 2023-07-08 jrick *have_local_changes = 1;
12096 624411d2 2023-07-08 jrick return got_error(GOT_ERR_CANCELLED);
12097 624411d2 2023-07-08 jrick default:
12101 624411d2 2023-07-08 jrick switch (staged_status) {
12102 624411d2 2023-07-08 jrick case GOT_STATUS_ADD:
12103 624411d2 2023-07-08 jrick case GOT_STATUS_DELETE:
12104 624411d2 2023-07-08 jrick case GOT_STATUS_MODIFY:
12105 624411d2 2023-07-08 jrick *have_local_changes = 1;
12106 624411d2 2023-07-08 jrick return got_error(GOT_ERR_CANCELLED);
12107 624411d2 2023-07-08 jrick default:
12111 624411d2 2023-07-08 jrick return NULL;
12114 624411d2 2023-07-08 jrick static const struct got_error *
12115 624411d2 2023-07-08 jrick cmd_histedit(int argc, char *argv[])
12117 624411d2 2023-07-08 jrick const struct got_error *error = NULL;
12118 624411d2 2023-07-08 jrick struct got_worktree *worktree = NULL;
12119 624411d2 2023-07-08 jrick struct got_fileindex *fileindex = NULL;
12120 624411d2 2023-07-08 jrick struct got_repository *repo = NULL;
12121 624411d2 2023-07-08 jrick char *cwd = NULL, *committer = NULL, *gitconfig_path = NULL;
12122 624411d2 2023-07-08 jrick struct got_reference *branch = NULL;
12123 624411d2 2023-07-08 jrick struct got_reference *tmp_branch = NULL;
12124 624411d2 2023-07-08 jrick struct got_object_id *resume_commit_id = NULL;
12125 624411d2 2023-07-08 jrick struct got_object_id *base_commit_id = NULL;
12126 624411d2 2023-07-08 jrick struct got_object_id *head_commit_id = NULL;
12127 624411d2 2023-07-08 jrick struct got_commit_object *commit = NULL;
12128 624411d2 2023-07-08 jrick int ch, rebase_in_progress = 0, merge_in_progress = 0;
12129 624411d2 2023-07-08 jrick struct got_update_progress_arg upa;
12130 624411d2 2023-07-08 jrick int edit_in_progress = 0, abort_edit = 0, continue_edit = 0;
12131 624411d2 2023-07-08 jrick int drop_only = 0, edit_logmsg_only = 0, fold_only = 0, edit_only = 0;
12132 624411d2 2023-07-08 jrick int allow_conflict = 0, list_backups = 0, delete_backups = 0;
12133 624411d2 2023-07-08 jrick const char *edit_script_path = NULL;
12134 624411d2 2023-07-08 jrick struct got_object_id_queue commits;
12135 624411d2 2023-07-08 jrick struct got_pathlist_head merged_paths;
12136 624411d2 2023-07-08 jrick const struct got_object_id_queue *parent_ids;
12137 624411d2 2023-07-08 jrick struct got_object_qid *pid;
12138 624411d2 2023-07-08 jrick struct got_histedit_list histedit_cmds;
12139 624411d2 2023-07-08 jrick struct got_histedit_list_entry *hle;
12140 624411d2 2023-07-08 jrick int *pack_fds = NULL;
12142 624411d2 2023-07-08 jrick STAILQ_INIT(&commits);
12143 624411d2 2023-07-08 jrick TAILQ_INIT(&histedit_cmds);
12144 624411d2 2023-07-08 jrick TAILQ_INIT(&merged_paths);
12145 624411d2 2023-07-08 jrick memset(&upa, 0, sizeof(upa));
12147 624411d2 2023-07-08 jrick #ifndef PROFILE
12148 624411d2 2023-07-08 jrick if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd "
12149 624411d2 2023-07-08 jrick "unveil", NULL) == -1)
12150 624411d2 2023-07-08 jrick err(1, "pledge");
12153 624411d2 2023-07-08 jrick while ((ch = getopt(argc, argv, "aCcdeF:flmX")) != -1) {
12154 624411d2 2023-07-08 jrick switch (ch) {
12155 624411d2 2023-07-08 jrick case 'a':
12156 624411d2 2023-07-08 jrick abort_edit = 1;
12158 624411d2 2023-07-08 jrick case 'C':
12159 624411d2 2023-07-08 jrick allow_conflict = 1;
12161 624411d2 2023-07-08 jrick case 'c':
12162 624411d2 2023-07-08 jrick continue_edit = 1;
12164 624411d2 2023-07-08 jrick case 'd':
12165 624411d2 2023-07-08 jrick drop_only = 1;
12167 624411d2 2023-07-08 jrick case 'e':
12168 624411d2 2023-07-08 jrick edit_only = 1;
12170 624411d2 2023-07-08 jrick case 'F':
12171 624411d2 2023-07-08 jrick edit_script_path = optarg;
12173 624411d2 2023-07-08 jrick case 'f':
12174 624411d2 2023-07-08 jrick fold_only = 1;
12176 624411d2 2023-07-08 jrick case 'l':
12177 624411d2 2023-07-08 jrick list_backups = 1;
12179 624411d2 2023-07-08 jrick case 'm':
12180 624411d2 2023-07-08 jrick edit_logmsg_only = 1;
12182 624411d2 2023-07-08 jrick case 'X':
12183 624411d2 2023-07-08 jrick delete_backups = 1;
12185 624411d2 2023-07-08 jrick default:
12186 624411d2 2023-07-08 jrick usage_histedit();
12187 624411d2 2023-07-08 jrick /* NOTREACHED */
12191 624411d2 2023-07-08 jrick argc -= optind;
12192 624411d2 2023-07-08 jrick argv += optind;
12194 624411d2 2023-07-08 jrick if (abort_edit && allow_conflict)
12195 624411d2 2023-07-08 jrick option_conflict('a', 'C');
12196 624411d2 2023-07-08 jrick if (abort_edit && continue_edit)
12197 624411d2 2023-07-08 jrick option_conflict('a', 'c');
12198 624411d2 2023-07-08 jrick if (edit_script_path && allow_conflict)
12199 624411d2 2023-07-08 jrick option_conflict('F', 'C');
12200 624411d2 2023-07-08 jrick if (edit_script_path && edit_logmsg_only)
12201 624411d2 2023-07-08 jrick option_conflict('F', 'm');
12202 624411d2 2023-07-08 jrick if (abort_edit && edit_logmsg_only)
12203 624411d2 2023-07-08 jrick option_conflict('a', 'm');
12204 624411d2 2023-07-08 jrick if (edit_logmsg_only && allow_conflict)
12205 624411d2 2023-07-08 jrick option_conflict('m', 'C');
12206 624411d2 2023-07-08 jrick if (continue_edit && edit_logmsg_only)
12207 624411d2 2023-07-08 jrick option_conflict('c', 'm');
12208 624411d2 2023-07-08 jrick if (abort_edit && fold_only)
12209 624411d2 2023-07-08 jrick option_conflict('a', 'f');
12210 624411d2 2023-07-08 jrick if (fold_only && allow_conflict)
12211 624411d2 2023-07-08 jrick option_conflict('f', 'C');
12212 624411d2 2023-07-08 jrick if (continue_edit && fold_only)
12213 624411d2 2023-07-08 jrick option_conflict('c', 'f');
12214 624411d2 2023-07-08 jrick if (fold_only && edit_logmsg_only)
12215 624411d2 2023-07-08 jrick option_conflict('f', 'm');
12216 624411d2 2023-07-08 jrick if (edit_script_path && fold_only)
12217 624411d2 2023-07-08 jrick option_conflict('F', 'f');
12218 624411d2 2023-07-08 jrick if (abort_edit && edit_only)
12219 624411d2 2023-07-08 jrick option_conflict('a', 'e');
12220 624411d2 2023-07-08 jrick if (continue_edit && edit_only)
12221 624411d2 2023-07-08 jrick option_conflict('c', 'e');
12222 624411d2 2023-07-08 jrick if (edit_only && edit_logmsg_only)
12223 624411d2 2023-07-08 jrick option_conflict('e', 'm');
12224 624411d2 2023-07-08 jrick if (edit_script_path && edit_only)
12225 624411d2 2023-07-08 jrick option_conflict('F', 'e');
12226 624411d2 2023-07-08 jrick if (fold_only && edit_only)
12227 624411d2 2023-07-08 jrick option_conflict('f', 'e');
12228 624411d2 2023-07-08 jrick if (drop_only && abort_edit)
12229 624411d2 2023-07-08 jrick option_conflict('d', 'a');
12230 624411d2 2023-07-08 jrick if (drop_only && allow_conflict)
12231 624411d2 2023-07-08 jrick option_conflict('d', 'C');
12232 624411d2 2023-07-08 jrick if (drop_only && continue_edit)
12233 624411d2 2023-07-08 jrick option_conflict('d', 'c');
12234 624411d2 2023-07-08 jrick if (drop_only && edit_logmsg_only)
12235 624411d2 2023-07-08 jrick option_conflict('d', 'm');
12236 624411d2 2023-07-08 jrick if (drop_only && edit_only)
12237 624411d2 2023-07-08 jrick option_conflict('d', 'e');
12238 624411d2 2023-07-08 jrick if (drop_only && edit_script_path)
12239 624411d2 2023-07-08 jrick option_conflict('d', 'F');
12240 624411d2 2023-07-08 jrick if (drop_only && fold_only)
12241 624411d2 2023-07-08 jrick option_conflict('d', 'f');
12242 624411d2 2023-07-08 jrick if (list_backups) {
12243 624411d2 2023-07-08 jrick if (abort_edit)
12244 624411d2 2023-07-08 jrick option_conflict('l', 'a');
12245 624411d2 2023-07-08 jrick if (allow_conflict)
12246 624411d2 2023-07-08 jrick option_conflict('l', 'C');
12247 624411d2 2023-07-08 jrick if (continue_edit)
12248 624411d2 2023-07-08 jrick option_conflict('l', 'c');
12249 624411d2 2023-07-08 jrick if (edit_script_path)
12250 624411d2 2023-07-08 jrick option_conflict('l', 'F');
12251 624411d2 2023-07-08 jrick if (edit_logmsg_only)
12252 624411d2 2023-07-08 jrick option_conflict('l', 'm');
12253 624411d2 2023-07-08 jrick if (drop_only)
12254 624411d2 2023-07-08 jrick option_conflict('l', 'd');
12255 624411d2 2023-07-08 jrick if (fold_only)
12256 624411d2 2023-07-08 jrick option_conflict('l', 'f');
12257 624411d2 2023-07-08 jrick if (edit_only)
12258 624411d2 2023-07-08 jrick option_conflict('l', 'e');
12259 624411d2 2023-07-08 jrick if (delete_backups)
12260 624411d2 2023-07-08 jrick option_conflict('l', 'X');
12261 624411d2 2023-07-08 jrick if (argc != 0 && argc != 1)
12262 624411d2 2023-07-08 jrick usage_histedit();
12263 624411d2 2023-07-08 jrick } else if (delete_backups) {
12264 624411d2 2023-07-08 jrick if (abort_edit)
12265 624411d2 2023-07-08 jrick option_conflict('X', 'a');
12266 624411d2 2023-07-08 jrick if (allow_conflict)
12267 624411d2 2023-07-08 jrick option_conflict('X', 'C');
12268 624411d2 2023-07-08 jrick if (continue_edit)
12269 624411d2 2023-07-08 jrick option_conflict('X', 'c');
12270 624411d2 2023-07-08 jrick if (drop_only)
12271 624411d2 2023-07-08 jrick option_conflict('X', 'd');
12272 624411d2 2023-07-08 jrick if (edit_script_path)
12273 624411d2 2023-07-08 jrick option_conflict('X', 'F');
12274 624411d2 2023-07-08 jrick if (edit_logmsg_only)
12275 624411d2 2023-07-08 jrick option_conflict('X', 'm');
12276 624411d2 2023-07-08 jrick if (fold_only)
12277 624411d2 2023-07-08 jrick option_conflict('X', 'f');
12278 624411d2 2023-07-08 jrick if (edit_only)
12279 624411d2 2023-07-08 jrick option_conflict('X', 'e');
12280 624411d2 2023-07-08 jrick if (list_backups)
12281 624411d2 2023-07-08 jrick option_conflict('X', 'l');
12282 624411d2 2023-07-08 jrick if (argc != 0 && argc != 1)
12283 624411d2 2023-07-08 jrick usage_histedit();
12284 624411d2 2023-07-08 jrick } else if (allow_conflict && !continue_edit)
12285 624411d2 2023-07-08 jrick errx(1, "-C option requires -c");
12286 624411d2 2023-07-08 jrick else if (argc != 0)
12287 624411d2 2023-07-08 jrick usage_histedit();
12290 624411d2 2023-07-08 jrick * This command cannot apply unveil(2) in all cases because the
12291 624411d2 2023-07-08 jrick * user may choose to run an editor to edit the histedit script
12292 624411d2 2023-07-08 jrick * and to edit individual commit log messages.
12293 624411d2 2023-07-08 jrick * unveil(2) traverses exec(2); if an editor is used we have to
12294 624411d2 2023-07-08 jrick * apply unveil after edit script and log messages have been written.
12295 624411d2 2023-07-08 jrick * XXX TODO: Make use of unveil(2) where possible.
12298 624411d2 2023-07-08 jrick cwd = getcwd(NULL, 0);
12299 624411d2 2023-07-08 jrick if (cwd == NULL) {
12300 624411d2 2023-07-08 jrick error = got_error_from_errno("getcwd");
12301 624411d2 2023-07-08 jrick goto done;
12304 624411d2 2023-07-08 jrick error = got_repo_pack_fds_open(&pack_fds);
12305 624411d2 2023-07-08 jrick if (error != NULL)
12306 624411d2 2023-07-08 jrick goto done;
12308 624411d2 2023-07-08 jrick error = got_worktree_open(&worktree, cwd);
12309 624411d2 2023-07-08 jrick if (error) {
12310 624411d2 2023-07-08 jrick if (list_backups || delete_backups) {
12311 624411d2 2023-07-08 jrick if (error->code != GOT_ERR_NOT_WORKTREE)
12312 624411d2 2023-07-08 jrick goto done;
12313 624411d2 2023-07-08 jrick } else {
12314 624411d2 2023-07-08 jrick if (error->code == GOT_ERR_NOT_WORKTREE)
12315 624411d2 2023-07-08 jrick error = wrap_not_worktree_error(error,
12316 624411d2 2023-07-08 jrick "histedit", cwd);
12317 624411d2 2023-07-08 jrick goto done;
12321 624411d2 2023-07-08 jrick if (list_backups || delete_backups) {
12322 624411d2 2023-07-08 jrick error = got_repo_open(&repo,
12323 624411d2 2023-07-08 jrick worktree ? got_worktree_get_repo_path(worktree) : cwd,
12324 624411d2 2023-07-08 jrick NULL, pack_fds);
12325 624411d2 2023-07-08 jrick if (error != NULL)
12326 624411d2 2023-07-08 jrick goto done;
12327 624411d2 2023-07-08 jrick error = apply_unveil(got_repo_get_path(repo), 0,
12328 624411d2 2023-07-08 jrick worktree ? got_worktree_get_root_path(worktree) : NULL);
12329 624411d2 2023-07-08 jrick if (error)
12330 624411d2 2023-07-08 jrick goto done;
12331 624411d2 2023-07-08 jrick error = process_backup_refs(
12332 624411d2 2023-07-08 jrick GOT_WORKTREE_HISTEDIT_BACKUP_REF_PREFIX,
12333 624411d2 2023-07-08 jrick argc == 1 ? argv[0] : NULL, delete_backups, repo);
12334 624411d2 2023-07-08 jrick goto done; /* nothing else to do */
12337 624411d2 2023-07-08 jrick error = get_gitconfig_path(&gitconfig_path);
12338 624411d2 2023-07-08 jrick if (error)
12339 624411d2 2023-07-08 jrick goto done;
12340 624411d2 2023-07-08 jrick error = got_repo_open(&repo, got_worktree_get_repo_path(worktree),
12341 624411d2 2023-07-08 jrick gitconfig_path, pack_fds);
12342 624411d2 2023-07-08 jrick if (error != NULL)
12343 624411d2 2023-07-08 jrick goto done;
12345 624411d2 2023-07-08 jrick if (worktree != NULL && !list_backups && !delete_backups) {
12346 624411d2 2023-07-08 jrick error = worktree_has_logmsg_ref("histedit", worktree, repo);
12347 624411d2 2023-07-08 jrick if (error)
12348 624411d2 2023-07-08 jrick goto done;
12351 624411d2 2023-07-08 jrick error = got_worktree_rebase_in_progress(&rebase_in_progress, worktree);
12352 624411d2 2023-07-08 jrick if (error)
12353 624411d2 2023-07-08 jrick goto done;
12354 624411d2 2023-07-08 jrick if (rebase_in_progress) {
12355 624411d2 2023-07-08 jrick error = got_error(GOT_ERR_REBASING);
12356 624411d2 2023-07-08 jrick goto done;
12359 624411d2 2023-07-08 jrick error = got_worktree_merge_in_progress(&merge_in_progress, worktree,
12361 624411d2 2023-07-08 jrick if (error)
12362 624411d2 2023-07-08 jrick goto done;
12363 624411d2 2023-07-08 jrick if (merge_in_progress) {
12364 624411d2 2023-07-08 jrick error = got_error(GOT_ERR_MERGE_BUSY);
12365 624411d2 2023-07-08 jrick goto done;
12368 624411d2 2023-07-08 jrick error = got_worktree_histedit_in_progress(&edit_in_progress, worktree);
12369 624411d2 2023-07-08 jrick if (error)
12370 624411d2 2023-07-08 jrick goto done;
12372 624411d2 2023-07-08 jrick if (edit_in_progress && edit_logmsg_only) {
12373 624411d2 2023-07-08 jrick error = got_error_msg(GOT_ERR_HISTEDIT_BUSY,
12374 624411d2 2023-07-08 jrick "histedit operation is in progress in this "
12375 624411d2 2023-07-08 jrick "work tree and must be continued or aborted "
12376 624411d2 2023-07-08 jrick "before the -m option can be used");
12377 624411d2 2023-07-08 jrick goto done;
12379 624411d2 2023-07-08 jrick if (edit_in_progress && drop_only) {
12380 624411d2 2023-07-08 jrick error = got_error_msg(GOT_ERR_HISTEDIT_BUSY,
12381 624411d2 2023-07-08 jrick "histedit operation is in progress in this "
12382 624411d2 2023-07-08 jrick "work tree and must be continued or aborted "
12383 624411d2 2023-07-08 jrick "before the -d option can be used");
12384 624411d2 2023-07-08 jrick goto done;
12386 624411d2 2023-07-08 jrick if (edit_in_progress && fold_only) {
12387 624411d2 2023-07-08 jrick error = got_error_msg(GOT_ERR_HISTEDIT_BUSY,
12388 624411d2 2023-07-08 jrick "histedit operation is in progress in this "
12389 624411d2 2023-07-08 jrick "work tree and must be continued or aborted "
12390 624411d2 2023-07-08 jrick "before the -f option can be used");
12391 624411d2 2023-07-08 jrick goto done;
12393 624411d2 2023-07-08 jrick if (edit_in_progress && edit_only) {
12394 624411d2 2023-07-08 jrick error = got_error_msg(GOT_ERR_HISTEDIT_BUSY,
12395 624411d2 2023-07-08 jrick "histedit operation is in progress in this "
12396 624411d2 2023-07-08 jrick "work tree and must be continued or aborted "
12397 624411d2 2023-07-08 jrick "before the -e option can be used");
12398 624411d2 2023-07-08 jrick goto done;
12401 624411d2 2023-07-08 jrick if (edit_in_progress && abort_edit) {
12402 624411d2 2023-07-08 jrick error = got_worktree_histedit_continue(&resume_commit_id,
12403 624411d2 2023-07-08 jrick &tmp_branch, &branch, &base_commit_id, &fileindex,
12404 624411d2 2023-07-08 jrick worktree, repo);
12405 624411d2 2023-07-08 jrick if (error)
12406 624411d2 2023-07-08 jrick goto done;
12407 624411d2 2023-07-08 jrick printf("Switching work tree to %s\n",
12408 624411d2 2023-07-08 jrick got_ref_get_symref_target(branch));
12409 624411d2 2023-07-08 jrick error = got_worktree_histedit_abort(worktree, fileindex, repo,
12410 624411d2 2023-07-08 jrick branch, base_commit_id, abort_progress, &upa);
12411 624411d2 2023-07-08 jrick if (error)
12412 624411d2 2023-07-08 jrick goto done;
12413 624411d2 2023-07-08 jrick printf("Histedit of %s aborted\n",
12414 624411d2 2023-07-08 jrick got_ref_get_symref_target(branch));
12415 624411d2 2023-07-08 jrick print_merge_progress_stats(&upa);
12416 624411d2 2023-07-08 jrick goto done; /* nothing else to do */
12417 624411d2 2023-07-08 jrick } else if (abort_edit) {
12418 624411d2 2023-07-08 jrick error = got_error(GOT_ERR_NOT_HISTEDIT);
12419 624411d2 2023-07-08 jrick goto done;
12422 624411d2 2023-07-08 jrick error = get_author(&committer, repo, worktree);
12423 624411d2 2023-07-08 jrick if (error)
12424 624411d2 2023-07-08 jrick goto done;
12426 624411d2 2023-07-08 jrick if (continue_edit) {
12427 624411d2 2023-07-08 jrick char *path;
12429 624411d2 2023-07-08 jrick if (!edit_in_progress) {
12430 624411d2 2023-07-08 jrick error = got_error(GOT_ERR_NOT_HISTEDIT);
12431 624411d2 2023-07-08 jrick goto done;
12434 624411d2 2023-07-08 jrick error = got_worktree_get_histedit_script_path(&path, worktree);
12435 624411d2 2023-07-08 jrick if (error)
12436 624411d2 2023-07-08 jrick goto done;
12438 624411d2 2023-07-08 jrick error = histedit_load_list(&histedit_cmds, path, repo);
12439 624411d2 2023-07-08 jrick free(path);
12440 624411d2 2023-07-08 jrick if (error)
12441 624411d2 2023-07-08 jrick goto done;
12443 624411d2 2023-07-08 jrick error = got_worktree_histedit_continue(&resume_commit_id,
12444 624411d2 2023-07-08 jrick &tmp_branch, &branch, &base_commit_id, &fileindex,
12445 624411d2 2023-07-08 jrick worktree, repo);
12446 624411d2 2023-07-08 jrick if (error)
12447 624411d2 2023-07-08 jrick goto done;
12449 624411d2 2023-07-08 jrick error = got_ref_resolve(&head_commit_id, repo, branch);
12450 624411d2 2023-07-08 jrick if (error)
12451 624411d2 2023-07-08 jrick goto done;
12453 624411d2 2023-07-08 jrick error = got_object_open_as_commit(&commit, repo,
12454 624411d2 2023-07-08 jrick head_commit_id);
12455 624411d2 2023-07-08 jrick if (error)
12456 624411d2 2023-07-08 jrick goto done;
12457 624411d2 2023-07-08 jrick parent_ids = got_object_commit_get_parent_ids(commit);
12458 624411d2 2023-07-08 jrick pid = STAILQ_FIRST(parent_ids);
12459 624411d2 2023-07-08 jrick if (pid == NULL) {
12460 624411d2 2023-07-08 jrick error = got_error(GOT_ERR_EMPTY_HISTEDIT);
12461 624411d2 2023-07-08 jrick goto done;
12463 624411d2 2023-07-08 jrick error = collect_commits(&commits, head_commit_id, &pid->id,
12464 624411d2 2023-07-08 jrick base_commit_id, got_worktree_get_path_prefix(worktree),
12465 624411d2 2023-07-08 jrick GOT_ERR_HISTEDIT_PATH, repo);
12466 624411d2 2023-07-08 jrick got_object_commit_close(commit);
12467 624411d2 2023-07-08 jrick commit = NULL;
12468 624411d2 2023-07-08 jrick if (error)
12469 624411d2 2023-07-08 jrick goto done;
12470 624411d2 2023-07-08 jrick } else {
12471 624411d2 2023-07-08 jrick if (edit_in_progress) {
12472 624411d2 2023-07-08 jrick error = got_error(GOT_ERR_HISTEDIT_BUSY);
12473 624411d2 2023-07-08 jrick goto done;
12476 624411d2 2023-07-08 jrick error = got_ref_open(&branch, repo,
12477 624411d2 2023-07-08 jrick got_worktree_get_head_ref_name(worktree), 0);
12478 624411d2 2023-07-08 jrick if (error != NULL)
12479 624411d2 2023-07-08 jrick goto done;
12481 624411d2 2023-07-08 jrick if (strncmp(got_ref_get_name(branch), "refs/heads/", 11) != 0) {
12482 624411d2 2023-07-08 jrick error = got_error_msg(GOT_ERR_COMMIT_BRANCH,
12483 624411d2 2023-07-08 jrick "will not edit commit history of a branch outside "
12484 624411d2 2023-07-08 jrick "the \"refs/heads/\" reference namespace");
12485 624411d2 2023-07-08 jrick goto done;
12488 624411d2 2023-07-08 jrick error = got_ref_resolve(&head_commit_id, repo, branch);
12489 624411d2 2023-07-08 jrick got_ref_close(branch);
12490 624411d2 2023-07-08 jrick branch = NULL;
12491 624411d2 2023-07-08 jrick if (error)
12492 624411d2 2023-07-08 jrick goto done;
12494 624411d2 2023-07-08 jrick error = got_object_open_as_commit(&commit, repo,
12495 624411d2 2023-07-08 jrick head_commit_id);
12496 624411d2 2023-07-08 jrick if (error)
12497 624411d2 2023-07-08 jrick goto done;
12498 624411d2 2023-07-08 jrick parent_ids = got_object_commit_get_parent_ids(commit);
12499 624411d2 2023-07-08 jrick pid = STAILQ_FIRST(parent_ids);
12500 624411d2 2023-07-08 jrick if (pid == NULL) {
12501 624411d2 2023-07-08 jrick error = got_error(GOT_ERR_EMPTY_HISTEDIT);
12502 624411d2 2023-07-08 jrick goto done;
12504 624411d2 2023-07-08 jrick error = collect_commits(&commits, head_commit_id, &pid->id,
12505 624411d2 2023-07-08 jrick got_worktree_get_base_commit_id(worktree),
12506 624411d2 2023-07-08 jrick got_worktree_get_path_prefix(worktree),
12507 624411d2 2023-07-08 jrick GOT_ERR_HISTEDIT_PATH, repo);
12508 624411d2 2023-07-08 jrick got_object_commit_close(commit);
12509 624411d2 2023-07-08 jrick commit = NULL;
12510 624411d2 2023-07-08 jrick if (error)
12511 624411d2 2023-07-08 jrick goto done;
12513 624411d2 2023-07-08 jrick if (STAILQ_EMPTY(&commits)) {
12514 624411d2 2023-07-08 jrick error = got_error(GOT_ERR_EMPTY_HISTEDIT);
12515 624411d2 2023-07-08 jrick goto done;
12518 624411d2 2023-07-08 jrick error = got_worktree_histedit_prepare(&tmp_branch, &branch,
12519 624411d2 2023-07-08 jrick &base_commit_id, &fileindex, worktree, repo);
12520 624411d2 2023-07-08 jrick if (error)
12521 624411d2 2023-07-08 jrick goto done;
12523 624411d2 2023-07-08 jrick if (edit_script_path) {
12524 624411d2 2023-07-08 jrick error = histedit_load_list(&histedit_cmds,
12525 624411d2 2023-07-08 jrick edit_script_path, repo);
12526 624411d2 2023-07-08 jrick if (error) {
12527 624411d2 2023-07-08 jrick got_worktree_histedit_abort(worktree, fileindex,
12528 624411d2 2023-07-08 jrick repo, branch, base_commit_id,
12529 624411d2 2023-07-08 jrick abort_progress, &upa);
12530 624411d2 2023-07-08 jrick print_merge_progress_stats(&upa);
12531 624411d2 2023-07-08 jrick goto done;
12533 624411d2 2023-07-08 jrick } else {
12534 624411d2 2023-07-08 jrick const char *branch_name;
12535 624411d2 2023-07-08 jrick branch_name = got_ref_get_symref_target(branch);
12536 624411d2 2023-07-08 jrick if (strncmp(branch_name, "refs/heads/", 11) == 0)
12537 624411d2 2023-07-08 jrick branch_name += 11;
12538 624411d2 2023-07-08 jrick error = histedit_edit_script(&histedit_cmds, &commits,
12539 624411d2 2023-07-08 jrick branch_name, edit_logmsg_only, fold_only,
12540 624411d2 2023-07-08 jrick drop_only, edit_only, repo);
12541 624411d2 2023-07-08 jrick if (error) {
12542 624411d2 2023-07-08 jrick got_worktree_histedit_abort(worktree, fileindex,
12543 624411d2 2023-07-08 jrick repo, branch, base_commit_id,
12544 624411d2 2023-07-08 jrick abort_progress, &upa);
12545 624411d2 2023-07-08 jrick print_merge_progress_stats(&upa);
12546 624411d2 2023-07-08 jrick goto done;
12551 624411d2 2023-07-08 jrick error = histedit_save_list(&histedit_cmds, worktree,
12553 624411d2 2023-07-08 jrick if (error) {
12554 624411d2 2023-07-08 jrick got_worktree_histedit_abort(worktree, fileindex,
12555 624411d2 2023-07-08 jrick repo, branch, base_commit_id,
12556 624411d2 2023-07-08 jrick abort_progress, &upa);
12557 624411d2 2023-07-08 jrick print_merge_progress_stats(&upa);
12558 624411d2 2023-07-08 jrick goto done;
12563 624411d2 2023-07-08 jrick error = histedit_check_script(&histedit_cmds, &commits, repo);
12564 624411d2 2023-07-08 jrick if (error)
12565 624411d2 2023-07-08 jrick goto done;
12567 624411d2 2023-07-08 jrick TAILQ_FOREACH(hle, &histedit_cmds, entry) {
12568 624411d2 2023-07-08 jrick if (resume_commit_id) {
12569 624411d2 2023-07-08 jrick if (got_object_id_cmp(hle->commit_id,
12570 624411d2 2023-07-08 jrick resume_commit_id) != 0)
12571 624411d2 2023-07-08 jrick continue;
12573 624411d2 2023-07-08 jrick resume_commit_id = NULL;
12574 624411d2 2023-07-08 jrick if (hle->cmd->code == GOT_HISTEDIT_DROP ||
12575 624411d2 2023-07-08 jrick hle->cmd->code == GOT_HISTEDIT_FOLD) {
12576 624411d2 2023-07-08 jrick error = histedit_skip_commit(hle, worktree,
12578 624411d2 2023-07-08 jrick if (error)
12579 624411d2 2023-07-08 jrick goto done;
12580 624411d2 2023-07-08 jrick } else {
12581 624411d2 2023-07-08 jrick struct got_pathlist_head paths;
12582 624411d2 2023-07-08 jrick int have_changes = 0;
12584 624411d2 2023-07-08 jrick TAILQ_INIT(&paths);
12585 624411d2 2023-07-08 jrick error = got_pathlist_append(&paths, "", NULL);
12586 624411d2 2023-07-08 jrick if (error)
12587 624411d2 2023-07-08 jrick goto done;
12588 624411d2 2023-07-08 jrick error = got_worktree_status(worktree, &paths,
12589 624411d2 2023-07-08 jrick repo, 0, check_local_changes, &have_changes,
12590 624411d2 2023-07-08 jrick check_cancelled, NULL);
12591 624411d2 2023-07-08 jrick got_pathlist_free(&paths,
12592 624411d2 2023-07-08 jrick GOT_PATHLIST_FREE_NONE);
12593 624411d2 2023-07-08 jrick if (error) {
12594 624411d2 2023-07-08 jrick if (error->code != GOT_ERR_CANCELLED)
12595 624411d2 2023-07-08 jrick goto done;
12596 624411d2 2023-07-08 jrick if (sigint_received || sigpipe_received)
12597 624411d2 2023-07-08 jrick goto done;
12599 624411d2 2023-07-08 jrick if (have_changes) {
12600 624411d2 2023-07-08 jrick error = histedit_commit(NULL, worktree,
12601 624411d2 2023-07-08 jrick fileindex, tmp_branch, hle,
12602 624411d2 2023-07-08 jrick committer, allow_conflict, repo);
12603 624411d2 2023-07-08 jrick if (error)
12604 624411d2 2023-07-08 jrick goto done;
12605 624411d2 2023-07-08 jrick } else {
12606 624411d2 2023-07-08 jrick error = got_object_open_as_commit(
12607 624411d2 2023-07-08 jrick &commit, repo, hle->commit_id);
12608 624411d2 2023-07-08 jrick if (error)
12609 624411d2 2023-07-08 jrick goto done;
12610 624411d2 2023-07-08 jrick error = show_histedit_progress(commit,
12611 624411d2 2023-07-08 jrick hle, NULL);
12612 624411d2 2023-07-08 jrick got_object_commit_close(commit);
12613 624411d2 2023-07-08 jrick commit = NULL;
12614 624411d2 2023-07-08 jrick if (error)
12615 624411d2 2023-07-08 jrick goto done;
12618 624411d2 2023-07-08 jrick continue;
12621 624411d2 2023-07-08 jrick if (hle->cmd->code == GOT_HISTEDIT_DROP) {
12622 624411d2 2023-07-08 jrick error = histedit_skip_commit(hle, worktree, repo);
12623 624411d2 2023-07-08 jrick if (error)
12624 624411d2 2023-07-08 jrick goto done;
12625 624411d2 2023-07-08 jrick continue;
12628 624411d2 2023-07-08 jrick error = got_object_open_as_commit(&commit, repo,
12629 624411d2 2023-07-08 jrick hle->commit_id);
12630 624411d2 2023-07-08 jrick if (error)
12631 624411d2 2023-07-08 jrick goto done;
12632 624411d2 2023-07-08 jrick parent_ids = got_object_commit_get_parent_ids(commit);
12633 624411d2 2023-07-08 jrick pid = STAILQ_FIRST(parent_ids);
12635 624411d2 2023-07-08 jrick error = got_worktree_histedit_merge_files(&merged_paths,
12636 624411d2 2023-07-08 jrick worktree, fileindex, &pid->id, hle->commit_id, repo,
12637 624411d2 2023-07-08 jrick update_progress, &upa, check_cancelled, NULL);
12638 624411d2 2023-07-08 jrick if (error)
12639 624411d2 2023-07-08 jrick goto done;
12640 624411d2 2023-07-08 jrick got_object_commit_close(commit);
12641 624411d2 2023-07-08 jrick commit = NULL;
12643 624411d2 2023-07-08 jrick print_merge_progress_stats(&upa);
12644 624411d2 2023-07-08 jrick if (upa.conflicts > 0 || upa.missing > 0 ||
12645 624411d2 2023-07-08 jrick upa.not_deleted > 0 || upa.unversioned > 0) {
12646 624411d2 2023-07-08 jrick if (upa.conflicts > 0) {
12647 624411d2 2023-07-08 jrick error = show_rebase_merge_conflict(
12648 624411d2 2023-07-08 jrick hle->commit_id, repo);
12649 624411d2 2023-07-08 jrick if (error)
12650 624411d2 2023-07-08 jrick goto done;
12652 624411d2 2023-07-08 jrick got_pathlist_free(&merged_paths, GOT_PATHLIST_FREE_PATH);
12656 624411d2 2023-07-08 jrick if (hle->cmd->code == GOT_HISTEDIT_EDIT) {
12657 624411d2 2023-07-08 jrick char *id_str;
12658 624411d2 2023-07-08 jrick error = got_object_id_str(&id_str, hle->commit_id);
12659 624411d2 2023-07-08 jrick if (error)
12660 624411d2 2023-07-08 jrick goto done;
12661 624411d2 2023-07-08 jrick printf("Stopping histedit for amending commit %s\n",
12662 624411d2 2023-07-08 jrick id_str);
12663 624411d2 2023-07-08 jrick free(id_str);
12664 624411d2 2023-07-08 jrick got_pathlist_free(&merged_paths, GOT_PATHLIST_FREE_PATH);
12665 624411d2 2023-07-08 jrick error = got_worktree_histedit_postpone(worktree,
12666 624411d2 2023-07-08 jrick fileindex);
12667 624411d2 2023-07-08 jrick goto done;
12670 624411d2 2023-07-08 jrick if (hle->cmd->code == GOT_HISTEDIT_FOLD) {
12671 624411d2 2023-07-08 jrick error = histedit_skip_commit(hle, worktree, repo);
12672 624411d2 2023-07-08 jrick if (error)
12673 624411d2 2023-07-08 jrick goto done;
12674 624411d2 2023-07-08 jrick continue;
12677 624411d2 2023-07-08 jrick error = histedit_commit(&merged_paths, worktree, fileindex,
12678 624411d2 2023-07-08 jrick tmp_branch, hle, committer, allow_conflict, repo);
12679 624411d2 2023-07-08 jrick got_pathlist_free(&merged_paths, GOT_PATHLIST_FREE_PATH);
12680 624411d2 2023-07-08 jrick if (error)
12681 624411d2 2023-07-08 jrick goto done;
12684 624411d2 2023-07-08 jrick if (upa.conflicts > 0 || upa.missing > 0 ||
12685 624411d2 2023-07-08 jrick upa.not_deleted > 0 || upa.unversioned > 0) {
12686 624411d2 2023-07-08 jrick error = got_worktree_histedit_postpone(worktree, fileindex);
12687 624411d2 2023-07-08 jrick if (error)
12688 624411d2 2023-07-08 jrick goto done;
12689 624411d2 2023-07-08 jrick if (upa.conflicts > 0 && upa.missing == 0 &&
12690 624411d2 2023-07-08 jrick upa.not_deleted == 0 && upa.unversioned == 0) {
12691 624411d2 2023-07-08 jrick error = got_error_msg(GOT_ERR_CONFLICTS,
12692 624411d2 2023-07-08 jrick "conflicts must be resolved before histedit "
12693 624411d2 2023-07-08 jrick "can continue");
12694 624411d2 2023-07-08 jrick } else if (upa.conflicts > 0) {
12695 624411d2 2023-07-08 jrick error = got_error_msg(GOT_ERR_CONFLICTS,
12696 624411d2 2023-07-08 jrick "conflicts must be resolved before histedit "
12697 624411d2 2023-07-08 jrick "can continue; changes destined for some "
12698 624411d2 2023-07-08 jrick "files were not yet merged and should be "
12699 624411d2 2023-07-08 jrick "merged manually if required before the "
12700 624411d2 2023-07-08 jrick "histedit operation is continued");
12701 624411d2 2023-07-08 jrick } else {
12702 624411d2 2023-07-08 jrick error = got_error_msg(GOT_ERR_CONFLICTS,
12703 624411d2 2023-07-08 jrick "changes destined for some files were not "
12704 624411d2 2023-07-08 jrick "yet merged and should be merged manually "
12705 624411d2 2023-07-08 jrick "if required before the histedit operation "
12706 624411d2 2023-07-08 jrick "is continued");
12709 624411d2 2023-07-08 jrick error = histedit_complete(worktree, fileindex, tmp_branch,
12710 624411d2 2023-07-08 jrick branch, repo);
12712 624411d2 2023-07-08 jrick free(cwd);
12713 624411d2 2023-07-08 jrick free(committer);
12714 624411d2 2023-07-08 jrick free(gitconfig_path);
12715 624411d2 2023-07-08 jrick got_object_id_queue_free(&commits);
12716 624411d2 2023-07-08 jrick histedit_free_list(&histedit_cmds);
12717 624411d2 2023-07-08 jrick free(head_commit_id);
12718 624411d2 2023-07-08 jrick free(base_commit_id);
12719 624411d2 2023-07-08 jrick free(resume_commit_id);
12720 624411d2 2023-07-08 jrick if (commit)
12721 624411d2 2023-07-08 jrick got_object_commit_close(commit);
12722 624411d2 2023-07-08 jrick if (branch)
12723 624411d2 2023-07-08 jrick got_ref_close(branch);
12724 624411d2 2023-07-08 jrick if (tmp_branch)
12725 624411d2 2023-07-08 jrick got_ref_close(tmp_branch);
12726 624411d2 2023-07-08 jrick if (worktree)
12727 624411d2 2023-07-08 jrick got_worktree_close(worktree);
12728 624411d2 2023-07-08 jrick if (repo) {
12729 624411d2 2023-07-08 jrick const struct got_error *close_err = got_repo_close(repo);
12730 624411d2 2023-07-08 jrick if (error == NULL)
12731 624411d2 2023-07-08 jrick error = close_err;
12733 624411d2 2023-07-08 jrick if (pack_fds) {
12734 624411d2 2023-07-08 jrick const struct got_error *pack_err =
12735 624411d2 2023-07-08 jrick got_repo_pack_fds_close(pack_fds);
12736 624411d2 2023-07-08 jrick if (error == NULL)
12737 624411d2 2023-07-08 jrick error = pack_err;
12739 624411d2 2023-07-08 jrick return error;
12742 624411d2 2023-07-08 jrick __dead static void
12743 624411d2 2023-07-08 jrick usage_integrate(void)
12745 624411d2 2023-07-08 jrick fprintf(stderr, "usage: %s integrate branch\n", getprogname());
12746 624411d2 2023-07-08 jrick exit(1);
12749 624411d2 2023-07-08 jrick static const struct got_error *
12750 624411d2 2023-07-08 jrick cmd_integrate(int argc, char *argv[])
12752 624411d2 2023-07-08 jrick const struct got_error *error = NULL;
12753 624411d2 2023-07-08 jrick struct got_repository *repo = NULL;
12754 624411d2 2023-07-08 jrick struct got_worktree *worktree = NULL;
12755 624411d2 2023-07-08 jrick char *cwd = NULL, *refname = NULL, *base_refname = NULL;
12756 624411d2 2023-07-08 jrick const char *branch_arg = NULL;
12757 624411d2 2023-07-08 jrick struct got_reference *branch_ref = NULL, *base_branch_ref = NULL;
12758 624411d2 2023-07-08 jrick struct got_fileindex *fileindex = NULL;
12759 624411d2 2023-07-08 jrick struct got_object_id *commit_id = NULL, *base_commit_id = NULL;
12761 624411d2 2023-07-08 jrick struct got_update_progress_arg upa;
12762 624411d2 2023-07-08 jrick int *pack_fds = NULL;
12764 624411d2 2023-07-08 jrick #ifndef PROFILE
12765 624411d2 2023-07-08 jrick if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd "
12766 624411d2 2023-07-08 jrick "unveil", NULL) == -1)
12767 624411d2 2023-07-08 jrick err(1, "pledge");
12770 624411d2 2023-07-08 jrick while ((ch = getopt(argc, argv, "")) != -1) {
12771 624411d2 2023-07-08 jrick switch (ch) {
12772 624411d2 2023-07-08 jrick default:
12773 624411d2 2023-07-08 jrick usage_integrate();
12774 624411d2 2023-07-08 jrick /* NOTREACHED */
12778 624411d2 2023-07-08 jrick argc -= optind;
12779 624411d2 2023-07-08 jrick argv += optind;
12781 624411d2 2023-07-08 jrick if (argc != 1)
12782 624411d2 2023-07-08 jrick usage_integrate();
12783 624411d2 2023-07-08 jrick branch_arg = argv[0];
12785 624411d2 2023-07-08 jrick cwd = getcwd(NULL, 0);
12786 624411d2 2023-07-08 jrick if (cwd == NULL) {
12787 624411d2 2023-07-08 jrick error = got_error_from_errno("getcwd");
12788 624411d2 2023-07-08 jrick goto done;
12791 624411d2 2023-07-08 jrick error = got_repo_pack_fds_open(&pack_fds);
12792 624411d2 2023-07-08 jrick if (error != NULL)
12793 624411d2 2023-07-08 jrick goto done;
12795 624411d2 2023-07-08 jrick error = got_worktree_open(&worktree, cwd);
12796 624411d2 2023-07-08 jrick if (error) {
12797 624411d2 2023-07-08 jrick if (error->code == GOT_ERR_NOT_WORKTREE)
12798 624411d2 2023-07-08 jrick error = wrap_not_worktree_error(error, "integrate",
12800 624411d2 2023-07-08 jrick goto done;
12803 624411d2 2023-07-08 jrick error = check_rebase_or_histedit_in_progress(worktree);
12804 624411d2 2023-07-08 jrick if (error)
12805 624411d2 2023-07-08 jrick goto done;
12807 624411d2 2023-07-08 jrick error = got_repo_open(&repo, got_worktree_get_repo_path(worktree),
12808 624411d2 2023-07-08 jrick NULL, pack_fds);
12809 624411d2 2023-07-08 jrick if (error != NULL)
12810 624411d2 2023-07-08 jrick goto done;
12812 624411d2 2023-07-08 jrick error = apply_unveil(got_repo_get_path(repo), 0,
12813 624411d2 2023-07-08 jrick got_worktree_get_root_path(worktree));
12814 624411d2 2023-07-08 jrick if (error)
12815 624411d2 2023-07-08 jrick goto done;
12817 624411d2 2023-07-08 jrick error = check_merge_in_progress(worktree, repo);
12818 624411d2 2023-07-08 jrick if (error)
12819 624411d2 2023-07-08 jrick goto done;
12821 624411d2 2023-07-08 jrick if (asprintf(&refname, "refs/heads/%s", branch_arg) == -1) {
12822 624411d2 2023-07-08 jrick error = got_error_from_errno("asprintf");
12823 624411d2 2023-07-08 jrick goto done;
12826 624411d2 2023-07-08 jrick error = got_worktree_integrate_prepare(&fileindex, &branch_ref,
12827 624411d2 2023-07-08 jrick &base_branch_ref, worktree, refname, repo);
12828 624411d2 2023-07-08 jrick if (error)
12829 624411d2 2023-07-08 jrick goto done;
12831 624411d2 2023-07-08 jrick refname = strdup(got_ref_get_name(branch_ref));
12832 624411d2 2023-07-08 jrick if (refname == NULL) {
12833 624411d2 2023-07-08 jrick error = got_error_from_errno("strdup");
12834 624411d2 2023-07-08 jrick got_worktree_integrate_abort(worktree, fileindex, repo,
12835 624411d2 2023-07-08 jrick branch_ref, base_branch_ref);
12836 624411d2 2023-07-08 jrick goto done;
12838 624411d2 2023-07-08 jrick base_refname = strdup(got_ref_get_name(base_branch_ref));
12839 624411d2 2023-07-08 jrick if (base_refname == NULL) {
12840 624411d2 2023-07-08 jrick error = got_error_from_errno("strdup");
12841 624411d2 2023-07-08 jrick got_worktree_integrate_abort(worktree, fileindex, repo,
12842 624411d2 2023-07-08 jrick branch_ref, base_branch_ref);
12843 624411d2 2023-07-08 jrick goto done;
12845 624411d2 2023-07-08 jrick if (strncmp(base_refname, "refs/heads/", 11) != 0) {
12846 624411d2 2023-07-08 jrick error = got_error(GOT_ERR_INTEGRATE_BRANCH);
12847 624411d2 2023-07-08 jrick got_worktree_integrate_abort(worktree, fileindex, repo,
12848 624411d2 2023-07-08 jrick branch_ref, base_branch_ref);
12849 624411d2 2023-07-08 jrick goto done;
12852 624411d2 2023-07-08 jrick error = got_ref_resolve(&commit_id, repo, branch_ref);
12853 624411d2 2023-07-08 jrick if (error)
12854 624411d2 2023-07-08 jrick goto done;
12856 624411d2 2023-07-08 jrick error = got_ref_resolve(&base_commit_id, repo, base_branch_ref);
12857 624411d2 2023-07-08 jrick if (error)
12858 624411d2 2023-07-08 jrick goto done;
12860 624411d2 2023-07-08 jrick if (got_object_id_cmp(commit_id, base_commit_id) == 0) {
12861 624411d2 2023-07-08 jrick error = got_error_msg(GOT_ERR_SAME_BRANCH,
12862 624411d2 2023-07-08 jrick "specified branch has already been integrated");
12863 624411d2 2023-07-08 jrick got_worktree_integrate_abort(worktree, fileindex, repo,
12864 624411d2 2023-07-08 jrick branch_ref, base_branch_ref);
12865 624411d2 2023-07-08 jrick goto done;
12868 624411d2 2023-07-08 jrick error = check_linear_ancestry(commit_id, base_commit_id, 1, repo);
12869 624411d2 2023-07-08 jrick if (error) {
12870 624411d2 2023-07-08 jrick if (error->code == GOT_ERR_ANCESTRY)
12871 624411d2 2023-07-08 jrick error = got_error(GOT_ERR_REBASE_REQUIRED);
12872 624411d2 2023-07-08 jrick got_worktree_integrate_abort(worktree, fileindex, repo,
12873 624411d2 2023-07-08 jrick branch_ref, base_branch_ref);
12874 624411d2 2023-07-08 jrick goto done;
12877 624411d2 2023-07-08 jrick memset(&upa, 0, sizeof(upa));
12878 624411d2 2023-07-08 jrick error = got_worktree_integrate_continue(worktree, fileindex, repo,
12879 624411d2 2023-07-08 jrick branch_ref, base_branch_ref, update_progress, &upa,
12880 624411d2 2023-07-08 jrick check_cancelled, NULL);
12881 624411d2 2023-07-08 jrick if (error)
12882 624411d2 2023-07-08 jrick goto done;
12884 624411d2 2023-07-08 jrick printf("Integrated %s into %s\n", refname, base_refname);
12885 624411d2 2023-07-08 jrick print_update_progress_stats(&upa);
12887 624411d2 2023-07-08 jrick if (repo) {
12888 624411d2 2023-07-08 jrick const struct got_error *close_err = got_repo_close(repo);
12889 624411d2 2023-07-08 jrick if (error == NULL)
12890 624411d2 2023-07-08 jrick error = close_err;
12892 624411d2 2023-07-08 jrick if (worktree)
12893 624411d2 2023-07-08 jrick got_worktree_close(worktree);
12894 624411d2 2023-07-08 jrick if (pack_fds) {
12895 624411d2 2023-07-08 jrick const struct got_error *pack_err =
12896 624411d2 2023-07-08 jrick got_repo_pack_fds_close(pack_fds);
12897 624411d2 2023-07-08 jrick if (error == NULL)
12898 624411d2 2023-07-08 jrick error = pack_err;
12900 624411d2 2023-07-08 jrick free(cwd);
12901 624411d2 2023-07-08 jrick free(base_commit_id);
12902 624411d2 2023-07-08 jrick free(commit_id);
12903 624411d2 2023-07-08 jrick free(refname);
12904 624411d2 2023-07-08 jrick free(base_refname);
12905 624411d2 2023-07-08 jrick return error;
12908 624411d2 2023-07-08 jrick __dead static void
12909 624411d2 2023-07-08 jrick usage_merge(void)
12911 624411d2 2023-07-08 jrick fprintf(stderr, "usage: %s merge [-aCcn] [branch]\n", getprogname());
12912 624411d2 2023-07-08 jrick exit(1);
12915 624411d2 2023-07-08 jrick static const struct got_error *
12916 624411d2 2023-07-08 jrick cmd_merge(int argc, char *argv[])
12918 624411d2 2023-07-08 jrick const struct got_error *error = NULL;
12919 624411d2 2023-07-08 jrick struct got_worktree *worktree = NULL;
12920 624411d2 2023-07-08 jrick struct got_repository *repo = NULL;
12921 624411d2 2023-07-08 jrick struct got_fileindex *fileindex = NULL;
12922 624411d2 2023-07-08 jrick char *cwd = NULL, *id_str = NULL, *author = NULL;
12923 624411d2 2023-07-08 jrick char *gitconfig_path = NULL;
12924 624411d2 2023-07-08 jrick struct got_reference *branch = NULL, *wt_branch = NULL;
12925 624411d2 2023-07-08 jrick struct got_object_id *branch_tip = NULL, *yca_id = NULL;
12926 624411d2 2023-07-08 jrick struct got_object_id *wt_branch_tip = NULL;
12927 624411d2 2023-07-08 jrick int ch, merge_in_progress = 0, abort_merge = 0, continue_merge = 0;
12928 624411d2 2023-07-08 jrick int allow_conflict = 0, prefer_fast_forward = 1, interrupt_merge = 0;
12929 624411d2 2023-07-08 jrick struct got_update_progress_arg upa;
12930 624411d2 2023-07-08 jrick struct got_object_id *merge_commit_id = NULL;
12931 624411d2 2023-07-08 jrick char *branch_name = NULL;
12932 624411d2 2023-07-08 jrick int *pack_fds = NULL;
12934 624411d2 2023-07-08 jrick memset(&upa, 0, sizeof(upa));
12936 624411d2 2023-07-08 jrick #ifndef PROFILE
12937 624411d2 2023-07-08 jrick if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd "
12938 624411d2 2023-07-08 jrick "unveil", NULL) == -1)
12939 624411d2 2023-07-08 jrick err(1, "pledge");
12942 624411d2 2023-07-08 jrick while ((ch = getopt(argc, argv, "aCcMn")) != -1) {
12943 624411d2 2023-07-08 jrick switch (ch) {
12944 624411d2 2023-07-08 jrick case 'a':
12945 624411d2 2023-07-08 jrick abort_merge = 1;
12947 624411d2 2023-07-08 jrick case 'C':
12948 624411d2 2023-07-08 jrick allow_conflict = 1;
12950 624411d2 2023-07-08 jrick case 'c':
12951 624411d2 2023-07-08 jrick continue_merge = 1;
12953 624411d2 2023-07-08 jrick case 'M':
12954 624411d2 2023-07-08 jrick prefer_fast_forward = 0;
12956 624411d2 2023-07-08 jrick case 'n':
12957 624411d2 2023-07-08 jrick interrupt_merge = 1;
12959 624411d2 2023-07-08 jrick default:
12960 624411d2 2023-07-08 jrick usage_merge();
12961 624411d2 2023-07-08 jrick /* NOTREACHED */
12965 624411d2 2023-07-08 jrick argc -= optind;
12966 624411d2 2023-07-08 jrick argv += optind;
12968 624411d2 2023-07-08 jrick if (abort_merge) {
12969 624411d2 2023-07-08 jrick if (continue_merge)
12970 624411d2 2023-07-08 jrick option_conflict('a', 'c');
12971 624411d2 2023-07-08 jrick if (!prefer_fast_forward)
12972 624411d2 2023-07-08 jrick option_conflict('a', 'M');
12973 624411d2 2023-07-08 jrick if (interrupt_merge)
12974 624411d2 2023-07-08 jrick option_conflict('a', 'n');
12975 624411d2 2023-07-08 jrick } else if (continue_merge) {
12976 624411d2 2023-07-08 jrick if (!prefer_fast_forward)
12977 624411d2 2023-07-08 jrick option_conflict('c', 'M');
12978 624411d2 2023-07-08 jrick if (interrupt_merge)
12979 624411d2 2023-07-08 jrick option_conflict('c', 'n');
12981 624411d2 2023-07-08 jrick if (allow_conflict) {
12982 624411d2 2023-07-08 jrick if (!continue_merge)
12983 624411d2 2023-07-08 jrick errx(1, "-C option requires -c");
12985 624411d2 2023-07-08 jrick if (abort_merge || continue_merge) {
12986 624411d2 2023-07-08 jrick if (argc != 0)
12987 624411d2 2023-07-08 jrick usage_merge();
12988 624411d2 2023-07-08 jrick } else if (argc != 1)
12989 624411d2 2023-07-08 jrick usage_merge();
12991 624411d2 2023-07-08 jrick cwd = getcwd(NULL, 0);
12992 624411d2 2023-07-08 jrick if (cwd == NULL) {
12993 624411d2 2023-07-08 jrick error = got_error_from_errno("getcwd");
12994 624411d2 2023-07-08 jrick goto done;
12997 624411d2 2023-07-08 jrick error = got_repo_pack_fds_open(&pack_fds);
12998 624411d2 2023-07-08 jrick if (error != NULL)
12999 624411d2 2023-07-08 jrick goto done;
13001 624411d2 2023-07-08 jrick error = got_worktree_open(&worktree, cwd);
13002 624411d2 2023-07-08 jrick if (error) {
13003 624411d2 2023-07-08 jrick if (error->code == GOT_ERR_NOT_WORKTREE)
13004 624411d2 2023-07-08 jrick error = wrap_not_worktree_error(error,
13005 624411d2 2023-07-08 jrick "merge", cwd);
13006 624411d2 2023-07-08 jrick goto done;
13009 624411d2 2023-07-08 jrick error = get_gitconfig_path(&gitconfig_path);
13010 624411d2 2023-07-08 jrick if (error)
13011 624411d2 2023-07-08 jrick goto done;
13012 624411d2 2023-07-08 jrick error = got_repo_open(&repo,
13013 624411d2 2023-07-08 jrick worktree ? got_worktree_get_repo_path(worktree) : cwd,
13014 624411d2 2023-07-08 jrick gitconfig_path, pack_fds);
13015 624411d2 2023-07-08 jrick if (error != NULL)
13016 624411d2 2023-07-08 jrick goto done;
13018 624411d2 2023-07-08 jrick if (worktree != NULL) {
13019 624411d2 2023-07-08 jrick error = worktree_has_logmsg_ref("merge", worktree, repo);
13020 624411d2 2023-07-08 jrick if (error)
13021 624411d2 2023-07-08 jrick goto done;
13024 624411d2 2023-07-08 jrick error = apply_unveil(got_repo_get_path(repo), 0,
13025 624411d2 2023-07-08 jrick worktree ? got_worktree_get_root_path(worktree) : NULL);
13026 624411d2 2023-07-08 jrick if (error)
13027 624411d2 2023-07-08 jrick goto done;
13029 624411d2 2023-07-08 jrick error = check_rebase_or_histedit_in_progress(worktree);
13030 624411d2 2023-07-08 jrick if (error)
13031 624411d2 2023-07-08 jrick goto done;
13033 624411d2 2023-07-08 jrick error = got_worktree_merge_in_progress(&merge_in_progress, worktree,
13035 624411d2 2023-07-08 jrick if (error)
13036 624411d2 2023-07-08 jrick goto done;
13038 624411d2 2023-07-08 jrick if (merge_in_progress && !(abort_merge || continue_merge)) {
13039 624411d2 2023-07-08 jrick error = got_error(GOT_ERR_MERGE_BUSY);
13040 624411d2 2023-07-08 jrick goto done;
13043 624411d2 2023-07-08 jrick if (!merge_in_progress && (abort_merge || continue_merge)) {
13044 624411d2 2023-07-08 jrick error = got_error(GOT_ERR_NOT_MERGING);
13045 624411d2 2023-07-08 jrick goto done;
13048 624411d2 2023-07-08 jrick if (abort_merge) {
13049 624411d2 2023-07-08 jrick error = got_worktree_merge_continue(&branch_name,
13050 624411d2 2023-07-08 jrick &branch_tip, &fileindex, worktree, repo);
13051 624411d2 2023-07-08 jrick if (error)
13052 624411d2 2023-07-08 jrick goto done;
13053 624411d2 2023-07-08 jrick error = got_worktree_merge_abort(worktree, fileindex, repo,
13054 624411d2 2023-07-08 jrick abort_progress, &upa);
13055 624411d2 2023-07-08 jrick if (error)
13056 624411d2 2023-07-08 jrick goto done;
13057 624411d2 2023-07-08 jrick printf("Merge of %s aborted\n", branch_name);
13058 624411d2 2023-07-08 jrick goto done; /* nothing else to do */
13061 624411d2 2023-07-08 jrick if (strncmp(got_worktree_get_head_ref_name(worktree),
13062 624411d2 2023-07-08 jrick "refs/heads/", 11) != 0) {
13063 624411d2 2023-07-08 jrick error = got_error_fmt(GOT_ERR_COMMIT_BRANCH,
13064 624411d2 2023-07-08 jrick "work tree's current branch %s is outside the "
13065 624411d2 2023-07-08 jrick "\"refs/heads/\" reference namespace; "
13066 624411d2 2023-07-08 jrick "update -b required",
13067 624411d2 2023-07-08 jrick got_worktree_get_head_ref_name(worktree));
13068 624411d2 2023-07-08 jrick goto done;
13071 624411d2 2023-07-08 jrick error = get_author(&author, repo, worktree);
13072 624411d2 2023-07-08 jrick if (error)
13073 624411d2 2023-07-08 jrick goto done;
13075 624411d2 2023-07-08 jrick error = got_ref_open(&wt_branch, repo,
13076 624411d2 2023-07-08 jrick got_worktree_get_head_ref_name(worktree), 0);
13077 624411d2 2023-07-08 jrick if (error)
13078 624411d2 2023-07-08 jrick goto done;
13079 624411d2 2023-07-08 jrick error = got_ref_resolve(&wt_branch_tip, repo, wt_branch);
13080 624411d2 2023-07-08 jrick if (error)
13081 624411d2 2023-07-08 jrick goto done;
13083 624411d2 2023-07-08 jrick if (continue_merge) {
13084 624411d2 2023-07-08 jrick struct got_object_id *base_commit_id;
13085 624411d2 2023-07-08 jrick base_commit_id = got_worktree_get_base_commit_id(worktree);
13086 624411d2 2023-07-08 jrick if (got_object_id_cmp(wt_branch_tip, base_commit_id) != 0) {
13087 624411d2 2023-07-08 jrick error = got_error(GOT_ERR_MERGE_COMMIT_OUT_OF_DATE);
13088 624411d2 2023-07-08 jrick goto done;
13090 624411d2 2023-07-08 jrick error = got_worktree_merge_continue(&branch_name,
13091 624411d2 2023-07-08 jrick &branch_tip, &fileindex, worktree, repo);
13092 624411d2 2023-07-08 jrick if (error)
13093 624411d2 2023-07-08 jrick goto done;
13094 624411d2 2023-07-08 jrick } else {
13095 624411d2 2023-07-08 jrick error = got_ref_open(&branch, repo, argv[0], 0);
13096 624411d2 2023-07-08 jrick if (error != NULL)
13097 624411d2 2023-07-08 jrick goto done;
13098 624411d2 2023-07-08 jrick branch_name = strdup(got_ref_get_name(branch));
13099 624411d2 2023-07-08 jrick if (branch_name == NULL) {
13100 624411d2 2023-07-08 jrick error = got_error_from_errno("strdup");
13101 624411d2 2023-07-08 jrick goto done;
13103 624411d2 2023-07-08 jrick error = got_ref_resolve(&branch_tip, repo, branch);
13104 624411d2 2023-07-08 jrick if (error)
13105 624411d2 2023-07-08 jrick goto done;
13108 624411d2 2023-07-08 jrick error = got_commit_graph_find_youngest_common_ancestor(&yca_id,
13109 624411d2 2023-07-08 jrick wt_branch_tip, branch_tip, 0, repo,
13110 624411d2 2023-07-08 jrick check_cancelled, NULL);
13111 624411d2 2023-07-08 jrick if (error && error->code != GOT_ERR_ANCESTRY)
13112 624411d2 2023-07-08 jrick goto done;
13114 624411d2 2023-07-08 jrick if (!continue_merge) {
13115 624411d2 2023-07-08 jrick error = check_path_prefix(wt_branch_tip, branch_tip,
13116 624411d2 2023-07-08 jrick got_worktree_get_path_prefix(worktree),
13117 624411d2 2023-07-08 jrick GOT_ERR_MERGE_PATH, repo);
13118 624411d2 2023-07-08 jrick if (error)
13119 624411d2 2023-07-08 jrick goto done;
13120 624411d2 2023-07-08 jrick error = got_worktree_merge_prepare(&fileindex, worktree, repo);
13121 624411d2 2023-07-08 jrick if (error)
13122 624411d2 2023-07-08 jrick goto done;
13123 624411d2 2023-07-08 jrick if (prefer_fast_forward && yca_id &&
13124 624411d2 2023-07-08 jrick got_object_id_cmp(wt_branch_tip, yca_id) == 0) {
13125 624411d2 2023-07-08 jrick struct got_pathlist_head paths;
13126 624411d2 2023-07-08 jrick if (interrupt_merge) {
13127 624411d2 2023-07-08 jrick error = got_error_fmt(GOT_ERR_BAD_OPTION,
13128 624411d2 2023-07-08 jrick "there are no changes to merge since %s "
13129 624411d2 2023-07-08 jrick "is already based on %s; merge cannot be "
13130 624411d2 2023-07-08 jrick "interrupted for amending; -n",
13131 624411d2 2023-07-08 jrick branch_name, got_ref_get_name(wt_branch));
13132 624411d2 2023-07-08 jrick goto done;
13134 624411d2 2023-07-08 jrick printf("Forwarding %s to %s\n",
13135 624411d2 2023-07-08 jrick got_ref_get_name(wt_branch), branch_name);
13136 624411d2 2023-07-08 jrick error = got_ref_change_ref(wt_branch, branch_tip);
13137 624411d2 2023-07-08 jrick if (error)
13138 624411d2 2023-07-08 jrick goto done;
13139 624411d2 2023-07-08 jrick error = got_ref_write(wt_branch, repo);
13140 624411d2 2023-07-08 jrick if (error)
13141 624411d2 2023-07-08 jrick goto done;
13142 624411d2 2023-07-08 jrick error = got_worktree_set_base_commit_id(worktree, repo,
13143 624411d2 2023-07-08 jrick branch_tip);
13144 624411d2 2023-07-08 jrick if (error)
13145 624411d2 2023-07-08 jrick goto done;
13146 624411d2 2023-07-08 jrick TAILQ_INIT(&paths);
13147 624411d2 2023-07-08 jrick error = got_pathlist_append(&paths, "", NULL);
13148 624411d2 2023-07-08 jrick if (error)
13149 624411d2 2023-07-08 jrick goto done;
13150 624411d2 2023-07-08 jrick error = got_worktree_checkout_files(worktree,
13151 624411d2 2023-07-08 jrick &paths, repo, update_progress, &upa,
13152 624411d2 2023-07-08 jrick check_cancelled, NULL);
13153 624411d2 2023-07-08 jrick got_pathlist_free(&paths, GOT_PATHLIST_FREE_NONE);
13154 624411d2 2023-07-08 jrick if (error)
13155 624411d2 2023-07-08 jrick goto done;
13156 624411d2 2023-07-08 jrick if (upa.did_something) {
13157 624411d2 2023-07-08 jrick char *id_str;
13158 624411d2 2023-07-08 jrick error = got_object_id_str(&id_str, branch_tip);
13159 624411d2 2023-07-08 jrick if (error)
13160 624411d2 2023-07-08 jrick goto done;
13161 624411d2 2023-07-08 jrick printf("Updated to commit %s\n", id_str);
13162 624411d2 2023-07-08 jrick free(id_str);
13164 624411d2 2023-07-08 jrick printf("Already up-to-date\n");
13165 624411d2 2023-07-08 jrick print_update_progress_stats(&upa);
13166 624411d2 2023-07-08 jrick goto done;
13168 624411d2 2023-07-08 jrick error = got_worktree_merge_write_refs(worktree, branch, repo);
13169 624411d2 2023-07-08 jrick if (error)
13170 624411d2 2023-07-08 jrick goto done;
13172 624411d2 2023-07-08 jrick error = got_worktree_merge_branch(worktree, fileindex,
13173 624411d2 2023-07-08 jrick yca_id, branch_tip, repo, update_progress, &upa,
13174 624411d2 2023-07-08 jrick check_cancelled, NULL);
13175 624411d2 2023-07-08 jrick if (error)
13176 624411d2 2023-07-08 jrick goto done;
13177 624411d2 2023-07-08 jrick print_merge_progress_stats(&upa);
13178 624411d2 2023-07-08 jrick if (!upa.did_something) {
13179 624411d2 2023-07-08 jrick error = got_worktree_merge_abort(worktree, fileindex,
13180 624411d2 2023-07-08 jrick repo, abort_progress, &upa);
13181 624411d2 2023-07-08 jrick if (error)
13182 624411d2 2023-07-08 jrick goto done;
13183 624411d2 2023-07-08 jrick printf("Already up-to-date\n");
13184 624411d2 2023-07-08 jrick goto done;
13188 624411d2 2023-07-08 jrick if (interrupt_merge) {
13189 624411d2 2023-07-08 jrick error = got_worktree_merge_postpone(worktree, fileindex);
13190 624411d2 2023-07-08 jrick if (error)
13191 624411d2 2023-07-08 jrick goto done;
13192 624411d2 2023-07-08 jrick printf("Merge of %s interrupted on request\n", branch_name);
13193 624411d2 2023-07-08 jrick } else if (upa.conflicts > 0 || upa.missing > 0 ||
13194 624411d2 2023-07-08 jrick upa.not_deleted > 0 || upa.unversioned > 0) {
13195 624411d2 2023-07-08 jrick error = got_worktree_merge_postpone(worktree, fileindex);
13196 624411d2 2023-07-08 jrick if (error)
13197 624411d2 2023-07-08 jrick goto done;
13198 624411d2 2023-07-08 jrick if (upa.conflicts > 0 && upa.missing == 0 &&
13199 624411d2 2023-07-08 jrick upa.not_deleted == 0 && upa.unversioned == 0) {
13200 624411d2 2023-07-08 jrick error = got_error_msg(GOT_ERR_CONFLICTS,
13201 624411d2 2023-07-08 jrick "conflicts must be resolved before merging "
13202 624411d2 2023-07-08 jrick "can continue");
13203 624411d2 2023-07-08 jrick } else if (upa.conflicts > 0) {
13204 624411d2 2023-07-08 jrick error = got_error_msg(GOT_ERR_CONFLICTS,
13205 624411d2 2023-07-08 jrick "conflicts must be resolved before merging "
13206 624411d2 2023-07-08 jrick "can continue; changes destined for some "
13207 624411d2 2023-07-08 jrick "files were not yet merged and "
13208 624411d2 2023-07-08 jrick "should be merged manually if required before the "
13209 624411d2 2023-07-08 jrick "merge operation is continued");
13210 624411d2 2023-07-08 jrick } else {
13211 624411d2 2023-07-08 jrick error = got_error_msg(GOT_ERR_CONFLICTS,
13212 624411d2 2023-07-08 jrick "changes destined for some "
13213 624411d2 2023-07-08 jrick "files were not yet merged and should be "
13214 624411d2 2023-07-08 jrick "merged manually if required before the "
13215 624411d2 2023-07-08 jrick "merge operation is continued");
13217 624411d2 2023-07-08 jrick goto done;
13218 624411d2 2023-07-08 jrick } else {
13219 624411d2 2023-07-08 jrick error = got_worktree_merge_commit(&merge_commit_id, worktree,
13220 624411d2 2023-07-08 jrick fileindex, author, NULL, 1, branch_tip, branch_name,
13221 624411d2 2023-07-08 jrick allow_conflict, repo, continue_merge ? print_status : NULL,
13223 624411d2 2023-07-08 jrick if (error)
13224 624411d2 2023-07-08 jrick goto done;
13225 624411d2 2023-07-08 jrick error = got_worktree_merge_complete(worktree, fileindex, repo);
13226 624411d2 2023-07-08 jrick if (error)
13227 624411d2 2023-07-08 jrick goto done;
13228 624411d2 2023-07-08 jrick error = got_object_id_str(&id_str, merge_commit_id);
13229 624411d2 2023-07-08 jrick if (error)
13230 624411d2 2023-07-08 jrick goto done;
13231 624411d2 2023-07-08 jrick printf("Merged %s into %s: %s\n", branch_name,
13232 624411d2 2023-07-08 jrick got_worktree_get_head_ref_name(worktree),
13233 624411d2 2023-07-08 jrick id_str);
13237 624411d2 2023-07-08 jrick free(gitconfig_path);
13238 624411d2 2023-07-08 jrick free(id_str);
13239 624411d2 2023-07-08 jrick free(merge_commit_id);
13240 624411d2 2023-07-08 jrick free(author);
13241 624411d2 2023-07-08 jrick free(branch_tip);
13242 624411d2 2023-07-08 jrick free(branch_name);
13243 624411d2 2023-07-08 jrick free(yca_id);
13244 624411d2 2023-07-08 jrick if (branch)
13245 624411d2 2023-07-08 jrick got_ref_close(branch);
13246 624411d2 2023-07-08 jrick if (wt_branch)
13247 624411d2 2023-07-08 jrick got_ref_close(wt_branch);
13248 624411d2 2023-07-08 jrick if (worktree)
13249 624411d2 2023-07-08 jrick got_worktree_close(worktree);
13250 624411d2 2023-07-08 jrick if (repo) {
13251 624411d2 2023-07-08 jrick const struct got_error *close_err = got_repo_close(repo);
13252 624411d2 2023-07-08 jrick if (error == NULL)
13253 624411d2 2023-07-08 jrick error = close_err;
13255 624411d2 2023-07-08 jrick if (pack_fds) {
13256 624411d2 2023-07-08 jrick const struct got_error *pack_err =
13257 624411d2 2023-07-08 jrick got_repo_pack_fds_close(pack_fds);
13258 624411d2 2023-07-08 jrick if (error == NULL)
13259 624411d2 2023-07-08 jrick error = pack_err;
13261 624411d2 2023-07-08 jrick return error;
13264 624411d2 2023-07-08 jrick __dead static void
13265 624411d2 2023-07-08 jrick usage_stage(void)
13267 624411d2 2023-07-08 jrick fprintf(stderr, "usage: %s stage [-lpS] [-F response-script] "
13268 624411d2 2023-07-08 jrick "[path ...]\n", getprogname());
13269 624411d2 2023-07-08 jrick exit(1);
13272 624411d2 2023-07-08 jrick static const struct got_error *
13273 624411d2 2023-07-08 jrick print_stage(void *arg, unsigned char status, unsigned char staged_status,
13274 624411d2 2023-07-08 jrick const char *path, struct got_object_id *blob_id,
13275 624411d2 2023-07-08 jrick struct got_object_id *staged_blob_id, struct got_object_id *commit_id,
13276 624411d2 2023-07-08 jrick int dirfd, const char *de_name)
13278 624411d2 2023-07-08 jrick const struct got_error *err = NULL;
13279 624411d2 2023-07-08 jrick char *id_str = NULL;
13281 624411d2 2023-07-08 jrick if (staged_status != GOT_STATUS_ADD &&
13282 624411d2 2023-07-08 jrick staged_status != GOT_STATUS_MODIFY &&
13283 624411d2 2023-07-08 jrick staged_status != GOT_STATUS_DELETE)
13284 624411d2 2023-07-08 jrick return NULL;
13286 624411d2 2023-07-08 jrick if (staged_status == GOT_STATUS_ADD ||
13287 624411d2 2023-07-08 jrick staged_status == GOT_STATUS_MODIFY)
13288 624411d2 2023-07-08 jrick err = got_object_id_str(&id_str, staged_blob_id);
13290 624411d2 2023-07-08 jrick err = got_object_id_str(&id_str, blob_id);
13291 624411d2 2023-07-08 jrick if (err)
13292 624411d2 2023-07-08 jrick return err;
13294 624411d2 2023-07-08 jrick printf("%s %c %s\n", id_str, staged_status, path);
13295 624411d2 2023-07-08 jrick free(id_str);
13296 624411d2 2023-07-08 jrick return NULL;
13299 624411d2 2023-07-08 jrick static const struct got_error *
13300 624411d2 2023-07-08 jrick cmd_stage(int argc, char *argv[])
13302 624411d2 2023-07-08 jrick const struct got_error *error = NULL;
13303 624411d2 2023-07-08 jrick struct got_repository *repo = NULL;
13304 624411d2 2023-07-08 jrick struct got_worktree *worktree = NULL;
13305 624411d2 2023-07-08 jrick char *cwd = NULL;
13306 624411d2 2023-07-08 jrick struct got_pathlist_head paths;
13307 624411d2 2023-07-08 jrick int ch, list_stage = 0, pflag = 0, allow_bad_symlinks = 0;
13308 624411d2 2023-07-08 jrick FILE *patch_script_file = NULL;
13309 624411d2 2023-07-08 jrick const char *patch_script_path = NULL;
13310 624411d2 2023-07-08 jrick struct choose_patch_arg cpa;
13311 624411d2 2023-07-08 jrick int *pack_fds = NULL;
13313 624411d2 2023-07-08 jrick TAILQ_INIT(&paths);
13315 624411d2 2023-07-08 jrick #ifndef PROFILE
13316 624411d2 2023-07-08 jrick if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd "
13317 624411d2 2023-07-08 jrick "unveil", NULL) == -1)
13318 624411d2 2023-07-08 jrick err(1, "pledge");
13321 624411d2 2023-07-08 jrick while ((ch = getopt(argc, argv, "F:lpS")) != -1) {
13322 624411d2 2023-07-08 jrick switch (ch) {
13323 624411d2 2023-07-08 jrick case 'F':
13324 624411d2 2023-07-08 jrick patch_script_path = optarg;
13326 624411d2 2023-07-08 jrick case 'l':
13327 624411d2 2023-07-08 jrick list_stage = 1;
13329 624411d2 2023-07-08 jrick case 'p':
13330 624411d2 2023-07-08 jrick pflag = 1;
13332 624411d2 2023-07-08 jrick case 'S':
13333 624411d2 2023-07-08 jrick allow_bad_symlinks = 1;
13335 624411d2 2023-07-08 jrick default:
13336 624411d2 2023-07-08 jrick usage_stage();
13337 624411d2 2023-07-08 jrick /* NOTREACHED */
13341 624411d2 2023-07-08 jrick argc -= optind;
13342 624411d2 2023-07-08 jrick argv += optind;
13344 624411d2 2023-07-08 jrick if (list_stage && (pflag || patch_script_path))
13345 624411d2 2023-07-08 jrick errx(1, "-l option cannot be used with other options");
13346 624411d2 2023-07-08 jrick if (patch_script_path && !pflag)
13347 624411d2 2023-07-08 jrick errx(1, "-F option can only be used together with -p option");
13349 624411d2 2023-07-08 jrick cwd = getcwd(NULL, 0);
13350 624411d2 2023-07-08 jrick if (cwd == NULL) {
13351 624411d2 2023-07-08 jrick error = got_error_from_errno("getcwd");
13352 624411d2 2023-07-08 jrick goto done;
13355 624411d2 2023-07-08 jrick error = got_repo_pack_fds_open(&pack_fds);
13356 624411d2 2023-07-08 jrick if (error != NULL)
13357 624411d2 2023-07-08 jrick goto done;
13359 624411d2 2023-07-08 jrick error = got_worktree_open(&worktree, cwd);
13360 624411d2 2023-07-08 jrick if (error) {
13361 624411d2 2023-07-08 jrick if (error->code == GOT_ERR_NOT_WORKTREE)
13362 624411d2 2023-07-08 jrick error = wrap_not_worktree_error(error, "stage", cwd);
13363 624411d2 2023-07-08 jrick goto done;
13366 624411d2 2023-07-08 jrick error = got_repo_open(&repo, got_worktree_get_repo_path(worktree),
13367 624411d2 2023-07-08 jrick NULL, pack_fds);
13368 624411d2 2023-07-08 jrick if (error != NULL)
13369 624411d2 2023-07-08 jrick goto done;
13371 624411d2 2023-07-08 jrick if (patch_script_path) {
13372 624411d2 2023-07-08 jrick patch_script_file = fopen(patch_script_path, "re");
13373 624411d2 2023-07-08 jrick if (patch_script_file == NULL) {
13374 624411d2 2023-07-08 jrick error = got_error_from_errno2("fopen",
13375 624411d2 2023-07-08 jrick patch_script_path);
13376 624411d2 2023-07-08 jrick goto done;
13379 624411d2 2023-07-08 jrick error = apply_unveil(got_repo_get_path(repo), 0,
13380 624411d2 2023-07-08 jrick got_worktree_get_root_path(worktree));
13381 624411d2 2023-07-08 jrick if (error)
13382 624411d2 2023-07-08 jrick goto done;
13384 624411d2 2023-07-08 jrick error = check_merge_in_progress(worktree, repo);
13385 624411d2 2023-07-08 jrick if (error)
13386 624411d2 2023-07-08 jrick goto done;
13388 624411d2 2023-07-08 jrick error = get_worktree_paths_from_argv(&paths, argc, argv, worktree);
13389 624411d2 2023-07-08 jrick if (error)
13390 624411d2 2023-07-08 jrick goto done;
13392 624411d2 2023-07-08 jrick if (list_stage)
13393 624411d2 2023-07-08 jrick error = got_worktree_status(worktree, &paths, repo, 0,
13394 624411d2 2023-07-08 jrick print_stage, NULL, check_cancelled, NULL);
13396 624411d2 2023-07-08 jrick cpa.patch_script_file = patch_script_file;
13397 624411d2 2023-07-08 jrick cpa.action = "stage";
13398 624411d2 2023-07-08 jrick error = got_worktree_stage(worktree, &paths,
13399 624411d2 2023-07-08 jrick pflag ? NULL : print_status, NULL,
13400 624411d2 2023-07-08 jrick pflag ? choose_patch : NULL, &cpa,
13401 624411d2 2023-07-08 jrick allow_bad_symlinks, repo);
13404 624411d2 2023-07-08 jrick if (patch_script_file && fclose(patch_script_file) == EOF &&
13405 624411d2 2023-07-08 jrick error == NULL)
13406 624411d2 2023-07-08 jrick error = got_error_from_errno2("fclose", patch_script_path);
13407 624411d2 2023-07-08 jrick if (repo) {
13408 624411d2 2023-07-08 jrick const struct got_error *close_err = got_repo_close(repo);
13409 624411d2 2023-07-08 jrick if (error == NULL)
13410 624411d2 2023-07-08 jrick error = close_err;
13412 624411d2 2023-07-08 jrick if (worktree)
13413 624411d2 2023-07-08 jrick got_worktree_close(worktree);
13414 624411d2 2023-07-08 jrick if (pack_fds) {
13415 624411d2 2023-07-08 jrick const struct got_error *pack_err =
13416 624411d2 2023-07-08 jrick got_repo_pack_fds_close(pack_fds);
13417 624411d2 2023-07-08 jrick if (error == NULL)
13418 624411d2 2023-07-08 jrick error = pack_err;
13420 624411d2 2023-07-08 jrick got_pathlist_free(&paths, GOT_PATHLIST_FREE_PATH);
13421 624411d2 2023-07-08 jrick free(cwd);
13422 624411d2 2023-07-08 jrick return error;
13425 624411d2 2023-07-08 jrick __dead static void
13426 624411d2 2023-07-08 jrick usage_unstage(void)
13428 624411d2 2023-07-08 jrick fprintf(stderr, "usage: %s unstage [-p] [-F response-script] "
13429 624411d2 2023-07-08 jrick "[path ...]\n", getprogname());
13430 624411d2 2023-07-08 jrick exit(1);
13434 624411d2 2023-07-08 jrick static const struct got_error *
13435 624411d2 2023-07-08 jrick cmd_unstage(int argc, char *argv[])
13437 624411d2 2023-07-08 jrick const struct got_error *error = NULL;
13438 624411d2 2023-07-08 jrick struct got_repository *repo = NULL;
13439 624411d2 2023-07-08 jrick struct got_worktree *worktree = NULL;
13440 624411d2 2023-07-08 jrick char *cwd = NULL;
13441 624411d2 2023-07-08 jrick struct got_pathlist_head paths;
13442 624411d2 2023-07-08 jrick int ch, pflag = 0;
13443 624411d2 2023-07-08 jrick struct got_update_progress_arg upa;
13444 624411d2 2023-07-08 jrick FILE *patch_script_file = NULL;
13445 624411d2 2023-07-08 jrick const char *patch_script_path = NULL;
13446 624411d2 2023-07-08 jrick struct choose_patch_arg cpa;
13447 624411d2 2023-07-08 jrick int *pack_fds = NULL;
13449 624411d2 2023-07-08 jrick TAILQ_INIT(&paths);
13451 624411d2 2023-07-08 jrick #ifndef PROFILE
13452 624411d2 2023-07-08 jrick if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd "
13453 624411d2 2023-07-08 jrick "unveil", NULL) == -1)
13454 624411d2 2023-07-08 jrick err(1, "pledge");
13457 624411d2 2023-07-08 jrick while ((ch = getopt(argc, argv, "F:p")) != -1) {
13458 624411d2 2023-07-08 jrick switch (ch) {
13459 624411d2 2023-07-08 jrick case 'F':
13460 624411d2 2023-07-08 jrick patch_script_path = optarg;
13462 624411d2 2023-07-08 jrick case 'p':
13463 624411d2 2023-07-08 jrick pflag = 1;
13465 624411d2 2023-07-08 jrick default:
13466 624411d2 2023-07-08 jrick usage_unstage();
13467 624411d2 2023-07-08 jrick /* NOTREACHED */
13471 624411d2 2023-07-08 jrick argc -= optind;
13472 624411d2 2023-07-08 jrick argv += optind;
13474 624411d2 2023-07-08 jrick if (patch_script_path && !pflag)
13475 624411d2 2023-07-08 jrick errx(1, "-F option can only be used together with -p option");
13477 624411d2 2023-07-08 jrick cwd = getcwd(NULL, 0);
13478 624411d2 2023-07-08 jrick if (cwd == NULL) {
13479 624411d2 2023-07-08 jrick error = got_error_from_errno("getcwd");
13480 624411d2 2023-07-08 jrick goto done;
13483 624411d2 2023-07-08 jrick error = got_repo_pack_fds_open(&pack_fds);
13484 624411d2 2023-07-08 jrick if (error != NULL)
13485 624411d2 2023-07-08 jrick goto done;
13487 624411d2 2023-07-08 jrick error = got_worktree_open(&worktree, cwd);
13488 624411d2 2023-07-08 jrick if (error) {
13489 624411d2 2023-07-08 jrick if (error->code == GOT_ERR_NOT_WORKTREE)
13490 624411d2 2023-07-08 jrick error = wrap_not_worktree_error(error, "unstage", cwd);
13491 624411d2 2023-07-08 jrick goto done;
13494 624411d2 2023-07-08 jrick error = got_repo_open(&repo, got_worktree_get_repo_path(worktree),
13495 624411d2 2023-07-08 jrick NULL, pack_fds);
13496 624411d2 2023-07-08 jrick if (error != NULL)
13497 624411d2 2023-07-08 jrick goto done;
13499 624411d2 2023-07-08 jrick if (patch_script_path) {
13500 624411d2 2023-07-08 jrick patch_script_file = fopen(patch_script_path, "re");
13501 624411d2 2023-07-08 jrick if (patch_script_file == NULL) {
13502 624411d2 2023-07-08 jrick error = got_error_from_errno2("fopen",
13503 624411d2 2023-07-08 jrick patch_script_path);
13504 624411d2 2023-07-08 jrick goto done;
13508 624411d2 2023-07-08 jrick error = apply_unveil(got_repo_get_path(repo), 0,
13509 624411d2 2023-07-08 jrick got_worktree_get_root_path(worktree));
13510 624411d2 2023-07-08 jrick if (error)
13511 624411d2 2023-07-08 jrick goto done;
13513 624411d2 2023-07-08 jrick error = get_worktree_paths_from_argv(&paths, argc, argv, worktree);
13514 624411d2 2023-07-08 jrick if (error)
13515 624411d2 2023-07-08 jrick goto done;
13517 624411d2 2023-07-08 jrick cpa.patch_script_file = patch_script_file;
13518 624411d2 2023-07-08 jrick cpa.action = "unstage";
13519 624411d2 2023-07-08 jrick memset(&upa, 0, sizeof(upa));
13520 624411d2 2023-07-08 jrick error = got_worktree_unstage(worktree, &paths, update_progress,
13521 624411d2 2023-07-08 jrick &upa, pflag ? choose_patch : NULL, &cpa, repo);
13522 624411d2 2023-07-08 jrick if (!error)
13523 624411d2 2023-07-08 jrick print_merge_progress_stats(&upa);
13525 624411d2 2023-07-08 jrick if (patch_script_file && fclose(patch_script_file) == EOF &&
13526 624411d2 2023-07-08 jrick error == NULL)
13527 624411d2 2023-07-08 jrick error = got_error_from_errno2("fclose", patch_script_path);
13528 624411d2 2023-07-08 jrick if (repo) {
13529 624411d2 2023-07-08 jrick const struct got_error *close_err = got_repo_close(repo);
13530 624411d2 2023-07-08 jrick if (error == NULL)
13531 624411d2 2023-07-08 jrick error = close_err;
13533 624411d2 2023-07-08 jrick if (worktree)
13534 624411d2 2023-07-08 jrick got_worktree_close(worktree);
13535 624411d2 2023-07-08 jrick if (pack_fds) {
13536 624411d2 2023-07-08 jrick const struct got_error *pack_err =
13537 624411d2 2023-07-08 jrick got_repo_pack_fds_close(pack_fds);
13538 624411d2 2023-07-08 jrick if (error == NULL)
13539 624411d2 2023-07-08 jrick error = pack_err;
13541 624411d2 2023-07-08 jrick got_pathlist_free(&paths, GOT_PATHLIST_FREE_PATH);
13542 624411d2 2023-07-08 jrick free(cwd);
13543 624411d2 2023-07-08 jrick return error;
13546 624411d2 2023-07-08 jrick __dead static void
13547 624411d2 2023-07-08 jrick usage_cat(void)
13549 624411d2 2023-07-08 jrick fprintf(stderr, "usage: %s cat [-P] [-c commit] [-r repository-path] "
13550 624411d2 2023-07-08 jrick "arg ...\n", getprogname());
13551 624411d2 2023-07-08 jrick exit(1);
13554 624411d2 2023-07-08 jrick static const struct got_error *
13555 624411d2 2023-07-08 jrick cat_blob(struct got_object_id *id, struct got_repository *repo, FILE *outfile)
13557 624411d2 2023-07-08 jrick const struct got_error *err;
13558 624411d2 2023-07-08 jrick struct got_blob_object *blob;
13559 624411d2 2023-07-08 jrick int fd = -1;
13561 624411d2 2023-07-08 jrick fd = got_opentempfd();
13562 624411d2 2023-07-08 jrick if (fd == -1)
13563 624411d2 2023-07-08 jrick return got_error_from_errno("got_opentempfd");
13565 624411d2 2023-07-08 jrick err = got_object_open_as_blob(&blob, repo, id, 8192, fd);
13566 624411d2 2023-07-08 jrick if (err)
13567 624411d2 2023-07-08 jrick goto done;
13569 624411d2 2023-07-08 jrick err = got_object_blob_dump_to_file(NULL, NULL, NULL, outfile, blob);
13571 624411d2 2023-07-08 jrick if (fd != -1 && close(fd) == -1 && err == NULL)
13572 624411d2 2023-07-08 jrick err = got_error_from_errno("close");
13573 624411d2 2023-07-08 jrick if (blob)
13574 624411d2 2023-07-08 jrick got_object_blob_close(blob);
13575 624411d2 2023-07-08 jrick return err;
13578 624411d2 2023-07-08 jrick static const struct got_error *
13579 624411d2 2023-07-08 jrick cat_tree(struct got_object_id *id, struct got_repository *repo, FILE *outfile)
13581 624411d2 2023-07-08 jrick const struct got_error *err;
13582 624411d2 2023-07-08 jrick struct got_tree_object *tree;
13583 624411d2 2023-07-08 jrick int nentries, i;
13585 624411d2 2023-07-08 jrick err = got_object_open_as_tree(&tree, repo, id);
13586 624411d2 2023-07-08 jrick if (err)
13587 624411d2 2023-07-08 jrick return err;
13589 624411d2 2023-07-08 jrick nentries = got_object_tree_get_nentries(tree);
13590 624411d2 2023-07-08 jrick for (i = 0; i < nentries; i++) {
13591 624411d2 2023-07-08 jrick struct got_tree_entry *te;
13592 624411d2 2023-07-08 jrick char *id_str;
13593 624411d2 2023-07-08 jrick if (sigint_received || sigpipe_received)
13595 624411d2 2023-07-08 jrick te = got_object_tree_get_entry(tree, i);
13596 624411d2 2023-07-08 jrick err = got_object_id_str(&id_str, got_tree_entry_get_id(te));
13597 624411d2 2023-07-08 jrick if (err)
13599 624411d2 2023-07-08 jrick fprintf(outfile, "%s %.7o %s\n", id_str,
13600 624411d2 2023-07-08 jrick got_tree_entry_get_mode(te),
13601 624411d2 2023-07-08 jrick got_tree_entry_get_name(te));
13602 624411d2 2023-07-08 jrick free(id_str);
13605 624411d2 2023-07-08 jrick got_object_tree_close(tree);
13606 624411d2 2023-07-08 jrick return err;
13609 624411d2 2023-07-08 jrick static const struct got_error *
13610 624411d2 2023-07-08 jrick cat_commit(struct got_object_id *id, struct got_repository *repo, FILE *outfile)
13612 624411d2 2023-07-08 jrick const struct got_error *err;
13613 624411d2 2023-07-08 jrick struct got_commit_object *commit;
13614 624411d2 2023-07-08 jrick const struct got_object_id_queue *parent_ids;
13615 624411d2 2023-07-08 jrick struct got_object_qid *pid;
13616 624411d2 2023-07-08 jrick char *id_str = NULL;
13617 624411d2 2023-07-08 jrick const char *logmsg = NULL;
13618 624411d2 2023-07-08 jrick char gmtoff[6];
13620 624411d2 2023-07-08 jrick err = got_object_open_as_commit(&commit, repo, id);
13621 624411d2 2023-07-08 jrick if (err)
13622 624411d2 2023-07-08 jrick return err;
13624 624411d2 2023-07-08 jrick err = got_object_id_str(&id_str, got_object_commit_get_tree_id(commit));
13625 624411d2 2023-07-08 jrick if (err)
13626 624411d2 2023-07-08 jrick goto done;
13628 624411d2 2023-07-08 jrick fprintf(outfile, "%s%s\n", GOT_COMMIT_LABEL_TREE, id_str);
13629 624411d2 2023-07-08 jrick parent_ids = got_object_commit_get_parent_ids(commit);
13630 624411d2 2023-07-08 jrick fprintf(outfile, "numparents %d\n",
13631 624411d2 2023-07-08 jrick got_object_commit_get_nparents(commit));
13632 624411d2 2023-07-08 jrick STAILQ_FOREACH(pid, parent_ids, entry) {
13633 624411d2 2023-07-08 jrick char *pid_str;
13634 624411d2 2023-07-08 jrick err = got_object_id_str(&pid_str, &pid->id);
13635 624411d2 2023-07-08 jrick if (err)
13636 624411d2 2023-07-08 jrick goto done;
13637 624411d2 2023-07-08 jrick fprintf(outfile, "%s%s\n", GOT_COMMIT_LABEL_PARENT, pid_str);
13638 624411d2 2023-07-08 jrick free(pid_str);
13640 624411d2 2023-07-08 jrick got_date_format_gmtoff(gmtoff, sizeof(gmtoff),
13641 624411d2 2023-07-08 jrick got_object_commit_get_author_gmtoff(commit));
13642 624411d2 2023-07-08 jrick fprintf(outfile, "%s%s %lld %s\n", GOT_COMMIT_LABEL_AUTHOR,
13643 624411d2 2023-07-08 jrick got_object_commit_get_author(commit),
13644 624411d2 2023-07-08 jrick (long long)got_object_commit_get_author_time(commit),
13645 624411d2 2023-07-08 jrick gmtoff);
13647 624411d2 2023-07-08 jrick got_date_format_gmtoff(gmtoff, sizeof(gmtoff),
13648 624411d2 2023-07-08 jrick got_object_commit_get_committer_gmtoff(commit));
13649 624411d2 2023-07-08 jrick fprintf(outfile, "%s%s %lld %s\n", GOT_COMMIT_LABEL_COMMITTER,
13650 624411d2 2023-07-08 jrick got_object_commit_get_committer(commit),
13651 624411d2 2023-07-08 jrick (long long)got_object_commit_get_committer_time(commit),
13652 624411d2 2023-07-08 jrick gmtoff);
13654 624411d2 2023-07-08 jrick logmsg = got_object_commit_get_logmsg_raw(commit);
13655 624411d2 2023-07-08 jrick fprintf(outfile, "messagelen %zd\n", strlen(logmsg));
13656 624411d2 2023-07-08 jrick fprintf(outfile, "%s", logmsg);
13658 624411d2 2023-07-08 jrick free(id_str);
13659 624411d2 2023-07-08 jrick got_object_commit_close(commit);
13660 624411d2 2023-07-08 jrick return err;
13663 624411d2 2023-07-08 jrick static const struct got_error *
13664 624411d2 2023-07-08 jrick cat_tag(struct got_object_id *id, struct got_repository *repo, FILE *outfile)
13666 624411d2 2023-07-08 jrick const struct got_error *err;
13667 624411d2 2023-07-08 jrick struct got_tag_object *tag;
13668 624411d2 2023-07-08 jrick char *id_str = NULL;
13669 624411d2 2023-07-08 jrick const char *tagmsg = NULL;
13670 624411d2 2023-07-08 jrick char gmtoff[6];
13672 624411d2 2023-07-08 jrick err = got_object_open_as_tag(&tag, repo, id);
13673 624411d2 2023-07-08 jrick if (err)
13674 624411d2 2023-07-08 jrick return err;
13676 624411d2 2023-07-08 jrick err = got_object_id_str(&id_str, got_object_tag_get_object_id(tag));
13677 624411d2 2023-07-08 jrick if (err)
13678 624411d2 2023-07-08 jrick goto done;
13680 624411d2 2023-07-08 jrick fprintf(outfile, "%s%s\n", GOT_TAG_LABEL_OBJECT, id_str);
13682 624411d2 2023-07-08 jrick switch (got_object_tag_get_object_type(tag)) {
13683 624411d2 2023-07-08 jrick case GOT_OBJ_TYPE_BLOB:
13684 624411d2 2023-07-08 jrick fprintf(outfile, "%s%s\n", GOT_TAG_LABEL_TYPE,
13685 624411d2 2023-07-08 jrick GOT_OBJ_LABEL_BLOB);
13687 624411d2 2023-07-08 jrick case GOT_OBJ_TYPE_TREE:
13688 624411d2 2023-07-08 jrick fprintf(outfile, "%s%s\n", GOT_TAG_LABEL_TYPE,
13689 624411d2 2023-07-08 jrick GOT_OBJ_LABEL_TREE);
13691 624411d2 2023-07-08 jrick case GOT_OBJ_TYPE_COMMIT:
13692 624411d2 2023-07-08 jrick fprintf(outfile, "%s%s\n", GOT_TAG_LABEL_TYPE,
13693 624411d2 2023-07-08 jrick GOT_OBJ_LABEL_COMMIT);
13695 624411d2 2023-07-08 jrick case GOT_OBJ_TYPE_TAG:
13696 624411d2 2023-07-08 jrick fprintf(outfile, "%s%s\n", GOT_TAG_LABEL_TYPE,
13697 624411d2 2023-07-08 jrick GOT_OBJ_LABEL_TAG);
13699 624411d2 2023-07-08 jrick default:
13703 624411d2 2023-07-08 jrick fprintf(outfile, "%s%s\n", GOT_TAG_LABEL_TAG,
13704 624411d2 2023-07-08 jrick got_object_tag_get_name(tag));
13706 624411d2 2023-07-08 jrick got_date_format_gmtoff(gmtoff, sizeof(gmtoff),
13707 624411d2 2023-07-08 jrick got_object_tag_get_tagger_gmtoff(tag));
13708 624411d2 2023-07-08 jrick fprintf(outfile, "%s%s %lld %s\n", GOT_TAG_LABEL_TAGGER,
13709 624411d2 2023-07-08 jrick got_object_tag_get_tagger(tag),
13710 624411d2 2023-07-08 jrick (long long)got_object_tag_get_tagger_time(tag),
13711 624411d2 2023-07-08 jrick gmtoff);
13713 624411d2 2023-07-08 jrick tagmsg = got_object_tag_get_message(tag);
13714 624411d2 2023-07-08 jrick fprintf(outfile, "messagelen %zd\n", strlen(tagmsg));
13715 624411d2 2023-07-08 jrick fprintf(outfile, "%s", tagmsg);
13717 624411d2 2023-07-08 jrick free(id_str);
13718 624411d2 2023-07-08 jrick got_object_tag_close(tag);
13719 624411d2 2023-07-08 jrick return err;
13722 624411d2 2023-07-08 jrick static const struct got_error *
13723 624411d2 2023-07-08 jrick cmd_cat(int argc, char *argv[])
13725 624411d2 2023-07-08 jrick const struct got_error *error;
13726 624411d2 2023-07-08 jrick struct got_repository *repo = NULL;
13727 624411d2 2023-07-08 jrick struct got_worktree *worktree = NULL;
13728 624411d2 2023-07-08 jrick char *cwd = NULL, *repo_path = NULL, *label = NULL;
13729 624411d2 2023-07-08 jrick const char *commit_id_str = NULL;
13730 624411d2 2023-07-08 jrick struct got_object_id *id = NULL, *commit_id = NULL;
13731 624411d2 2023-07-08 jrick struct got_commit_object *commit = NULL;
13732 624411d2 2023-07-08 jrick int ch, obj_type, i, force_path = 0;
13733 624411d2 2023-07-08 jrick struct got_reflist_head refs;
13734 624411d2 2023-07-08 jrick int *pack_fds = NULL;
13736 624411d2 2023-07-08 jrick TAILQ_INIT(&refs);
13738 624411d2 2023-07-08 jrick #ifndef PROFILE
13739 624411d2 2023-07-08 jrick if (pledge("stdio rpath wpath cpath flock proc exec sendfd unveil",
13740 624411d2 2023-07-08 jrick NULL) == -1)
13741 624411d2 2023-07-08 jrick err(1, "pledge");
13744 624411d2 2023-07-08 jrick while ((ch = getopt(argc, argv, "c:Pr:")) != -1) {
13745 624411d2 2023-07-08 jrick switch (ch) {
13746 624411d2 2023-07-08 jrick case 'c':
13747 624411d2 2023-07-08 jrick commit_id_str = optarg;
13749 624411d2 2023-07-08 jrick case 'P':
13750 624411d2 2023-07-08 jrick force_path = 1;
13752 624411d2 2023-07-08 jrick case 'r':
13753 624411d2 2023-07-08 jrick repo_path = realpath(optarg, NULL);
13754 624411d2 2023-07-08 jrick if (repo_path == NULL)
13755 624411d2 2023-07-08 jrick return got_error_from_errno2("realpath",
13756 624411d2 2023-07-08 jrick optarg);
13757 624411d2 2023-07-08 jrick got_path_strip_trailing_slashes(repo_path);
13759 624411d2 2023-07-08 jrick default:
13760 624411d2 2023-07-08 jrick usage_cat();
13761 624411d2 2023-07-08 jrick /* NOTREACHED */
13765 624411d2 2023-07-08 jrick argc -= optind;
13766 624411d2 2023-07-08 jrick argv += optind;
13768 624411d2 2023-07-08 jrick cwd = getcwd(NULL, 0);
13769 624411d2 2023-07-08 jrick if (cwd == NULL) {
13770 624411d2 2023-07-08 jrick error = got_error_from_errno("getcwd");
13771 624411d2 2023-07-08 jrick goto done;
13774 624411d2 2023-07-08 jrick error = got_repo_pack_fds_open(&pack_fds);
13775 624411d2 2023-07-08 jrick if (error != NULL)
13776 624411d2 2023-07-08 jrick goto done;
13778 624411d2 2023-07-08 jrick if (repo_path == NULL) {
13779 624411d2 2023-07-08 jrick error = got_worktree_open(&worktree, cwd);
13780 624411d2 2023-07-08 jrick if (error && error->code != GOT_ERR_NOT_WORKTREE)
13781 624411d2 2023-07-08 jrick goto done;
13782 624411d2 2023-07-08 jrick if (worktree) {
13783 624411d2 2023-07-08 jrick repo_path = strdup(
13784 624411d2 2023-07-08 jrick got_worktree_get_repo_path(worktree));
13785 624411d2 2023-07-08 jrick if (repo_path == NULL) {
13786 624411d2 2023-07-08 jrick error = got_error_from_errno("strdup");
13787 624411d2 2023-07-08 jrick goto done;
13790 624411d2 2023-07-08 jrick /* Release work tree lock. */
13791 624411d2 2023-07-08 jrick got_worktree_close(worktree);
13792 624411d2 2023-07-08 jrick worktree = NULL;
13796 624411d2 2023-07-08 jrick if (repo_path == NULL) {
13797 624411d2 2023-07-08 jrick repo_path = strdup(cwd);
13798 624411d2 2023-07-08 jrick if (repo_path == NULL)
13799 624411d2 2023-07-08 jrick return got_error_from_errno("strdup");
13802 624411d2 2023-07-08 jrick error = got_repo_open(&repo, repo_path, NULL, pack_fds);
13803 624411d2 2023-07-08 jrick free(repo_path);
13804 624411d2 2023-07-08 jrick if (error != NULL)
13805 624411d2 2023-07-08 jrick goto done;
13807 624411d2 2023-07-08 jrick error = apply_unveil(got_repo_get_path(repo), 1, NULL);
13808 624411d2 2023-07-08 jrick if (error)
13809 624411d2 2023-07-08 jrick goto done;
13811 624411d2 2023-07-08 jrick error = got_ref_list(&refs, repo, NULL, got_ref_cmp_by_name, NULL);
13812 624411d2 2023-07-08 jrick if (error)
13813 624411d2 2023-07-08 jrick goto done;
13815 624411d2 2023-07-08 jrick if (commit_id_str == NULL)
13816 624411d2 2023-07-08 jrick commit_id_str = GOT_REF_HEAD;
13817 624411d2 2023-07-08 jrick error = got_repo_match_object_id(&commit_id, NULL,
13818 624411d2 2023-07-08 jrick commit_id_str, GOT_OBJ_TYPE_COMMIT, &refs, repo);
13819 624411d2 2023-07-08 jrick if (error)
13820 624411d2 2023-07-08 jrick goto done;
13822 624411d2 2023-07-08 jrick error = got_object_open_as_commit(&commit, repo, commit_id);
13823 624411d2 2023-07-08 jrick if (error)
13824 624411d2 2023-07-08 jrick goto done;
13826 624411d2 2023-07-08 jrick for (i = 0; i < argc; i++) {
13827 624411d2 2023-07-08 jrick if (force_path) {
13828 624411d2 2023-07-08 jrick error = got_object_id_by_path(&id, repo, commit,
13829 624411d2 2023-07-08 jrick argv[i]);
13830 624411d2 2023-07-08 jrick if (error)
13832 624411d2 2023-07-08 jrick } else {
13833 624411d2 2023-07-08 jrick error = got_repo_match_object_id(&id, &label, argv[i],
13834 624411d2 2023-07-08 jrick GOT_OBJ_TYPE_ANY, NULL /* do not resolve tags */,
13836 624411d2 2023-07-08 jrick if (error) {
13837 624411d2 2023-07-08 jrick if (error->code != GOT_ERR_BAD_OBJ_ID_STR &&
13838 624411d2 2023-07-08 jrick error->code != GOT_ERR_NOT_REF)
13840 624411d2 2023-07-08 jrick error = got_object_id_by_path(&id, repo,
13841 624411d2 2023-07-08 jrick commit, argv[i]);
13842 624411d2 2023-07-08 jrick if (error)
13847 624411d2 2023-07-08 jrick error = got_object_get_type(&obj_type, repo, id);
13848 624411d2 2023-07-08 jrick if (error)
13851 624411d2 2023-07-08 jrick switch (obj_type) {
13852 624411d2 2023-07-08 jrick case GOT_OBJ_TYPE_BLOB:
13853 624411d2 2023-07-08 jrick error = cat_blob(id, repo, stdout);
13855 624411d2 2023-07-08 jrick case GOT_OBJ_TYPE_TREE:
13856 624411d2 2023-07-08 jrick error = cat_tree(id, repo, stdout);
13858 624411d2 2023-07-08 jrick case GOT_OBJ_TYPE_COMMIT:
13859 624411d2 2023-07-08 jrick error = cat_commit(id, repo, stdout);
13861 624411d2 2023-07-08 jrick case GOT_OBJ_TYPE_TAG:
13862 624411d2 2023-07-08 jrick error = cat_tag(id, repo, stdout);
13864 624411d2 2023-07-08 jrick default:
13865 624411d2 2023-07-08 jrick error = got_error(GOT_ERR_OBJ_TYPE);
13868 624411d2 2023-07-08 jrick if (error)
13870 624411d2 2023-07-08 jrick free(label);
13871 624411d2 2023-07-08 jrick label = NULL;
13872 624411d2 2023-07-08 jrick free(id);
13873 624411d2 2023-07-08 jrick id = NULL;
13876 624411d2 2023-07-08 jrick free(label);
13877 624411d2 2023-07-08 jrick free(id);
13878 624411d2 2023-07-08 jrick free(commit_id);
13879 624411d2 2023-07-08 jrick if (commit)
13880 624411d2 2023-07-08 jrick got_object_commit_close(commit);
13881 624411d2 2023-07-08 jrick if (worktree)
13882 624411d2 2023-07-08 jrick got_worktree_close(worktree);
13883 624411d2 2023-07-08 jrick if (repo) {
13884 624411d2 2023-07-08 jrick const struct got_error *close_err = got_repo_close(repo);
13885 624411d2 2023-07-08 jrick if (error == NULL)
13886 624411d2 2023-07-08 jrick error = close_err;
13888 624411d2 2023-07-08 jrick if (pack_fds) {
13889 624411d2 2023-07-08 jrick const struct got_error *pack_err =
13890 624411d2 2023-07-08 jrick got_repo_pack_fds_close(pack_fds);
13891 624411d2 2023-07-08 jrick if (error == NULL)
13892 624411d2 2023-07-08 jrick error = pack_err;
13895 624411d2 2023-07-08 jrick got_ref_list_free(&refs);
13896 624411d2 2023-07-08 jrick return error;
13899 624411d2 2023-07-08 jrick __dead static void
13900 624411d2 2023-07-08 jrick usage_info(void)
13902 624411d2 2023-07-08 jrick fprintf(stderr, "usage: %s info [path ...]\n",
13903 624411d2 2023-07-08 jrick getprogname());
13904 624411d2 2023-07-08 jrick exit(1);
13907 624411d2 2023-07-08 jrick static const struct got_error *
13908 624411d2 2023-07-08 jrick print_path_info(void *arg, const char *path, mode_t mode, time_t mtime,
13909 624411d2 2023-07-08 jrick struct got_object_id *blob_id, struct got_object_id *staged_blob_id,
13910 624411d2 2023-07-08 jrick struct got_object_id *commit_id)
13912 624411d2 2023-07-08 jrick const struct got_error *err = NULL;
13913 624411d2 2023-07-08 jrick char *id_str = NULL;
13914 624411d2 2023-07-08 jrick char datebuf[128];
13915 624411d2 2023-07-08 jrick struct tm mytm, *tm;
13916 624411d2 2023-07-08 jrick struct got_pathlist_head *paths = arg;
13917 624411d2 2023-07-08 jrick struct got_pathlist_entry *pe;
13920 624411d2 2023-07-08 jrick * Clear error indication from any of the path arguments which
13921 624411d2 2023-07-08 jrick * would cause this file index entry to be displayed.
13923 624411d2 2023-07-08 jrick TAILQ_FOREACH(pe, paths, entry) {
13924 624411d2 2023-07-08 jrick if (got_path_cmp(path, pe->path, strlen(path),
13925 624411d2 2023-07-08 jrick pe->path_len) == 0 ||
13926 624411d2 2023-07-08 jrick got_path_is_child(path, pe->path, pe->path_len))
13927 624411d2 2023-07-08 jrick pe->data = NULL; /* no error */
13930 624411d2 2023-07-08 jrick printf(GOT_COMMIT_SEP_STR);
13931 624411d2 2023-07-08 jrick if (S_ISLNK(mode))
13932 624411d2 2023-07-08 jrick printf("symlink: %s\n", path);
13933 624411d2 2023-07-08 jrick else if (S_ISREG(mode)) {
13934 624411d2 2023-07-08 jrick printf("file: %s\n", path);
13935 624411d2 2023-07-08 jrick printf("mode: %o\n", mode & (S_IRWXU | S_IRWXG | S_IRWXO));
13936 624411d2 2023-07-08 jrick } else if (S_ISDIR(mode))
13937 624411d2 2023-07-08 jrick printf("directory: %s\n", path);
13939 624411d2 2023-07-08 jrick printf("something: %s\n", path);
13941 624411d2 2023-07-08 jrick tm = localtime_r(&mtime, &mytm);
13942 624411d2 2023-07-08 jrick if (tm == NULL)
13943 624411d2 2023-07-08 jrick return NULL;
13944 624411d2 2023-07-08 jrick if (strftime(datebuf, sizeof(datebuf), "%c %Z", tm) == 0)
13945 624411d2 2023-07-08 jrick return got_error(GOT_ERR_NO_SPACE);
13946 624411d2 2023-07-08 jrick printf("timestamp: %s\n", datebuf);
13948 624411d2 2023-07-08 jrick if (blob_id) {
13949 624411d2 2023-07-08 jrick err = got_object_id_str(&id_str, blob_id);
13950 624411d2 2023-07-08 jrick if (err)
13951 624411d2 2023-07-08 jrick return err;
13952 624411d2 2023-07-08 jrick printf("based on blob: %s\n", id_str);
13953 624411d2 2023-07-08 jrick free(id_str);
13956 624411d2 2023-07-08 jrick if (staged_blob_id) {
13957 624411d2 2023-07-08 jrick err = got_object_id_str(&id_str, staged_blob_id);
13958 624411d2 2023-07-08 jrick if (err)
13959 624411d2 2023-07-08 jrick return err;
13960 624411d2 2023-07-08 jrick printf("based on staged blob: %s\n", id_str);
13961 624411d2 2023-07-08 jrick free(id_str);
13964 624411d2 2023-07-08 jrick if (commit_id) {
13965 624411d2 2023-07-08 jrick err = got_object_id_str(&id_str, commit_id);
13966 624411d2 2023-07-08 jrick if (err)
13967 624411d2 2023-07-08 jrick return err;
13968 624411d2 2023-07-08 jrick printf("based on commit: %s\n", id_str);
13969 624411d2 2023-07-08 jrick free(id_str);
13972 624411d2 2023-07-08 jrick return NULL;
13975 624411d2 2023-07-08 jrick static const struct got_error *
13976 624411d2 2023-07-08 jrick cmd_info(int argc, char *argv[])
13978 624411d2 2023-07-08 jrick const struct got_error *error = NULL;
13979 624411d2 2023-07-08 jrick struct got_worktree *worktree = NULL;
13980 624411d2 2023-07-08 jrick char *cwd = NULL, *id_str = NULL;
13981 624411d2 2023-07-08 jrick struct got_pathlist_head paths;
13982 624411d2 2023-07-08 jrick char *uuidstr = NULL;
13983 624411d2 2023-07-08 jrick int ch, show_files = 0;
13985 624411d2 2023-07-08 jrick TAILQ_INIT(&paths);
13987 624411d2 2023-07-08 jrick #ifndef PROFILE
13988 624411d2 2023-07-08 jrick if (pledge("stdio rpath wpath cpath flock proc exec sendfd unveil",
13989 624411d2 2023-07-08 jrick NULL) == -1)
13990 624411d2 2023-07-08 jrick err(1, "pledge");
13993 624411d2 2023-07-08 jrick while ((ch = getopt(argc, argv, "")) != -1) {
13994 624411d2 2023-07-08 jrick switch (ch) {
13995 624411d2 2023-07-08 jrick default:
13996 624411d2 2023-07-08 jrick usage_info();
13997 624411d2 2023-07-08 jrick /* NOTREACHED */
14001 624411d2 2023-07-08 jrick argc -= optind;
14002 624411d2 2023-07-08 jrick argv += optind;
14004 624411d2 2023-07-08 jrick cwd = getcwd(NULL, 0);
14005 624411d2 2023-07-08 jrick if (cwd == NULL) {
14006 624411d2 2023-07-08 jrick error = got_error_from_errno("getcwd");
14007 624411d2 2023-07-08 jrick goto done;
14010 624411d2 2023-07-08 jrick error = got_worktree_open(&worktree, cwd);
14011 624411d2 2023-07-08 jrick if (error) {
14012 624411d2 2023-07-08 jrick if (error->code == GOT_ERR_NOT_WORKTREE)
14013 624411d2 2023-07-08 jrick error = wrap_not_worktree_error(error, "info", cwd);
14014 624411d2 2023-07-08 jrick goto done;
14017 624411d2 2023-07-08 jrick #ifndef PROFILE
14018 624411d2 2023-07-08 jrick /* Remove "wpath cpath proc exec sendfd" promises. */
14019 624411d2 2023-07-08 jrick if (pledge("stdio rpath flock unveil", NULL) == -1)
14020 624411d2 2023-07-08 jrick err(1, "pledge");
14022 624411d2 2023-07-08 jrick error = apply_unveil(NULL, 0, got_worktree_get_root_path(worktree));
14023 624411d2 2023-07-08 jrick if (error)
14024 624411d2 2023-07-08 jrick goto done;
14026 624411d2 2023-07-08 jrick if (argc >= 1) {
14027 624411d2 2023-07-08 jrick error = get_worktree_paths_from_argv(&paths, argc, argv,
14028 624411d2 2023-07-08 jrick worktree);
14029 624411d2 2023-07-08 jrick if (error)
14030 624411d2 2023-07-08 jrick goto done;
14031 624411d2 2023-07-08 jrick show_files = 1;
14034 624411d2 2023-07-08 jrick error = got_object_id_str(&id_str,
14035 624411d2 2023-07-08 jrick got_worktree_get_base_commit_id(worktree));
14036 624411d2 2023-07-08 jrick if (error)
14037 624411d2 2023-07-08 jrick goto done;
14039 624411d2 2023-07-08 jrick error = got_worktree_get_uuid(&uuidstr, worktree);
14040 624411d2 2023-07-08 jrick if (error)
14041 624411d2 2023-07-08 jrick goto done;
14043 624411d2 2023-07-08 jrick printf("work tree: %s\n", got_worktree_get_root_path(worktree));
14044 624411d2 2023-07-08 jrick printf("work tree base commit: %s\n", id_str);
14045 624411d2 2023-07-08 jrick printf("work tree path prefix: %s\n",
14046 624411d2 2023-07-08 jrick got_worktree_get_path_prefix(worktree));
14047 624411d2 2023-07-08 jrick printf("work tree branch reference: %s\n",
14048 624411d2 2023-07-08 jrick got_worktree_get_head_ref_name(worktree));
14049 624411d2 2023-07-08 jrick printf("work tree UUID: %s\n", uuidstr);
14050 624411d2 2023-07-08 jrick printf("repository: %s\n", got_worktree_get_repo_path(worktree));
14052 624411d2 2023-07-08 jrick if (show_files) {
14053 624411d2 2023-07-08 jrick struct got_pathlist_entry *pe;
14054 624411d2 2023-07-08 jrick TAILQ_FOREACH(pe, &paths, entry) {
14055 624411d2 2023-07-08 jrick if (pe->path_len == 0)
14056 624411d2 2023-07-08 jrick continue;
14058 624411d2 2023-07-08 jrick * Assume this path will fail. This will be corrected
14059 624411d2 2023-07-08 jrick * in print_path_info() in case the path does suceeed.
14061 624411d2 2023-07-08 jrick pe->data = (void *)got_error(GOT_ERR_BAD_PATH);
14063 624411d2 2023-07-08 jrick error = got_worktree_path_info(worktree, &paths,
14064 624411d2 2023-07-08 jrick print_path_info, &paths, check_cancelled, NULL);
14065 624411d2 2023-07-08 jrick if (error)
14066 624411d2 2023-07-08 jrick goto done;
14067 624411d2 2023-07-08 jrick TAILQ_FOREACH(pe, &paths, entry) {
14068 624411d2 2023-07-08 jrick if (pe->data != NULL) {
14069 624411d2 2023-07-08 jrick const struct got_error *perr;
14071 624411d2 2023-07-08 jrick perr = pe->data;
14072 624411d2 2023-07-08 jrick error = got_error_fmt(perr->code, "%s",
14073 624411d2 2023-07-08 jrick pe->path);
14079 624411d2 2023-07-08 jrick if (worktree)
14080 624411d2 2023-07-08 jrick got_worktree_close(worktree);
14081 624411d2 2023-07-08 jrick got_pathlist_free(&paths, GOT_PATHLIST_FREE_PATH);
14082 624411d2 2023-07-08 jrick free(cwd);
14083 624411d2 2023-07-08 jrick free(id_str);
14084 624411d2 2023-07-08 jrick free(uuidstr);
14085 624411d2 2023-07-08 jrick return error;