|
5 | 5 | * a Linking Exception. For full terms see the included COPYING file. |
6 | 6 | */ |
7 | 7 |
|
| 8 | +#include "common.h" |
| 9 | + |
| 10 | +#include "git2/branch.h" |
| 11 | +#include "git2/commit.h" |
8 | 12 | #include "git2/worktree.h" |
9 | 13 |
|
10 | | -#include "common.h" |
11 | 14 | #include "repository.h" |
12 | 15 | #include "worktree.h" |
13 | 16 |
|
@@ -90,6 +93,25 @@ static char *read_link(const char *base, const char *file) |
90 | 93 | return NULL; |
91 | 94 | } |
92 | 95 |
|
| 96 | +static int write_wtfile(const char *base, const char *file, const git_buf *buf) |
| 97 | +{ |
| 98 | + git_buf path = GIT_BUF_INIT; |
| 99 | + int err; |
| 100 | + |
| 101 | + assert(base && file && buf); |
| 102 | + |
| 103 | + if ((err = git_buf_joinpath(&path, base, file)) < 0) |
| 104 | + goto out; |
| 105 | + |
| 106 | + if ((err = git_futils_writebuffer(buf, path.ptr, O_CREAT|O_EXCL|O_WRONLY, 0644)) < 0) |
| 107 | + goto out; |
| 108 | + |
| 109 | +out: |
| 110 | + git_buf_free(&path); |
| 111 | + |
| 112 | + return err; |
| 113 | +} |
| 114 | + |
93 | 115 | int git_worktree_lookup(git_worktree **out, git_repository *repo, const char *name) |
94 | 116 | { |
95 | 117 | git_buf path = GIT_BUF_INIT; |
@@ -183,3 +205,81 @@ int git_worktree_validate(const git_worktree *wt) |
183 | 205 |
|
184 | 206 | return err; |
185 | 207 | } |
| 208 | + |
| 209 | +int git_worktree_add(git_worktree **out, git_repository *repo, const char *name, const char *worktree) |
| 210 | +{ |
| 211 | + git_buf path = GIT_BUF_INIT, buf = GIT_BUF_INIT; |
| 212 | + git_reference *ref = NULL, *head = NULL; |
| 213 | + git_commit *commit = NULL; |
| 214 | + git_repository *wt = NULL; |
| 215 | + git_checkout_options coopts = GIT_CHECKOUT_OPTIONS_INIT; |
| 216 | + int err; |
| 217 | + |
| 218 | + assert(out && repo && name && worktree); |
| 219 | + |
| 220 | + *out = NULL; |
| 221 | + |
| 222 | + /* Create worktree related files in commondir */ |
| 223 | + if ((err = git_buf_joinpath(&path, repo->commondir, "worktrees")) < 0) |
| 224 | + goto out; |
| 225 | + if (!git_path_exists(path.ptr)) |
| 226 | + if ((err = git_futils_mkdir(path.ptr, 0755, GIT_MKDIR_EXCL)) < 0) |
| 227 | + goto out; |
| 228 | + if ((err = git_buf_joinpath(&path, path.ptr, name)) < 0) |
| 229 | + goto out; |
| 230 | + if ((err = git_futils_mkdir(path.ptr, 0755, GIT_MKDIR_EXCL)) < 0) |
| 231 | + goto out; |
| 232 | + |
| 233 | + /* Create worktree work dir */ |
| 234 | + if ((err = git_futils_mkdir(worktree, 0755, GIT_MKDIR_EXCL)) < 0) |
| 235 | + goto out; |
| 236 | + |
| 237 | + /* Create worktree .git file */ |
| 238 | + if ((err = git_buf_printf(&buf, "gitdir: %s\n", path.ptr)) < 0) |
| 239 | + goto out; |
| 240 | + if ((err = write_wtfile(worktree, ".git", &buf)) < 0) |
| 241 | + goto out; |
| 242 | + |
| 243 | + /* Create commondir files */ |
| 244 | + if ((err = git_buf_sets(&buf, repo->commondir)) < 0 |
| 245 | + || (err = git_buf_putc(&buf, '\n')) < 0 |
| 246 | + || (err = write_wtfile(path.ptr, "commondir", &buf)) < 0) |
| 247 | + goto out; |
| 248 | + if ((err = git_buf_joinpath(&buf, worktree, ".git")) < 0 |
| 249 | + || (err = git_buf_putc(&buf, '\n')) < 0 |
| 250 | + || (err = write_wtfile(path.ptr, "gitdir", &buf)) < 0) |
| 251 | + goto out; |
| 252 | + |
| 253 | + /* Create new branch */ |
| 254 | + if ((err = git_repository_head(&head, repo)) < 0) |
| 255 | + goto out; |
| 256 | + if ((err = git_commit_lookup(&commit, repo, &head->target.oid)) < 0) |
| 257 | + goto out; |
| 258 | + if ((err = git_branch_create(&ref, repo, name, commit, false)) < 0) |
| 259 | + goto out; |
| 260 | + |
| 261 | + /* Set worktree's HEAD */ |
| 262 | + if ((err = git_repository_create_head(path.ptr, name)) < 0) |
| 263 | + goto out; |
| 264 | + if ((err = git_repository_open(&wt, worktree)) < 0) |
| 265 | + goto out; |
| 266 | + |
| 267 | + /* Checkout worktree's HEAD */ |
| 268 | + coopts.checkout_strategy = GIT_CHECKOUT_FORCE; |
| 269 | + if ((err = git_checkout_head(wt, &coopts)) < 0) |
| 270 | + goto out; |
| 271 | + |
| 272 | + /* Load result */ |
| 273 | + if ((err = git_worktree_lookup(out, repo, name)) < 0) |
| 274 | + goto out; |
| 275 | + |
| 276 | +out: |
| 277 | + git_buf_free(&path); |
| 278 | + git_buf_free(&buf); |
| 279 | + git_reference_free(ref); |
| 280 | + git_reference_free(head); |
| 281 | + git_commit_free(commit); |
| 282 | + git_repository_free(wt); |
| 283 | + |
| 284 | + return err; |
| 285 | +} |
0 commit comments