2 * Copyright (C) 2009-2012 the libgit2 contributors
4 * This file is part of libgit2, distributed under the GNU GPL v2 with
5 * a Linking Exception. For full terms see the included COPYING file.
9 #include "repository.h"
13 #include "git2/diff.h"
14 #include "git2/stash.h"
15 #include "git2/status.h"
16 #include "git2/checkout.h"
17 #include "signature.h"
19 static int create_error(int error
, const char *msg
)
21 giterr_set(GITERR_STASH
, "Cannot stash changes - %s", msg
);
25 static int ensure_non_bare_repository(git_repository
*repo
)
27 if (!git_repository_is_bare(repo
))
30 return create_error(GIT_EBAREREPO
,
31 "Stash related operations require a working directory.");
34 static int retrieve_head(git_reference
**out
, git_repository
*repo
)
36 int error
= git_repository_head(out
, repo
);
38 if (error
== GIT_EORPHANEDHEAD
)
39 return create_error(error
, "You do not have the initial commit yet.");
44 static int append_abbreviated_oid(git_buf
*out
, const git_oid
*b_commit
)
48 formatted_oid
= git_oid_allocfmt(b_commit
);
49 GITERR_CHECK_ALLOC(formatted_oid
);
51 git_buf_put(out
, formatted_oid
, 7);
52 git__free(formatted_oid
);
54 return git_buf_oom(out
) ? -1 : 0;
57 static int append_commit_description(git_buf
*out
, git_commit
* commit
)
62 if (append_abbreviated_oid(out
, git_commit_id(commit
)) < 0)
65 message
= git_commit_message(commit
);
66 len
= strlen(message
);
68 /* TODO: Replace with proper commit short message
69 * when git_commit_message_short() is implemented.
71 while (pos
< len
&& message
[pos
] != '\n')
74 git_buf_putc(out
, ' ');
75 git_buf_put(out
, message
, pos
);
76 git_buf_putc(out
, '\n');
78 return git_buf_oom(out
) ? -1 : 0;
81 static int retrieve_base_commit_and_message(
82 git_commit
**b_commit
,
83 git_buf
*stash_message
,
86 git_reference
*head
= NULL
;
89 if ((error
= retrieve_head(&head
, repo
)) < 0)
94 if (strcmp("HEAD", git_reference_name(head
)) == 0)
95 git_buf_puts(stash_message
, "(no branch): ");
100 git_reference_name(head
) + strlen(GIT_REFS_HEADS_DIR
));
102 if (git_commit_lookup(b_commit
, repo
, git_reference_target(head
)) < 0)
105 if (append_commit_description(stash_message
, *b_commit
) < 0)
111 git_reference_free(head
);
115 static int build_tree_from_index(git_tree
**out
, git_index
*index
)
119 if (git_index_write_tree(&i_tree_oid
, index
) < 0)
122 return git_tree_lookup(out
, git_index_owner(index
), &i_tree_oid
);
125 static int commit_index(
126 git_commit
**i_commit
,
128 git_signature
*stasher
,
130 const git_commit
*parent
)
132 git_tree
*i_tree
= NULL
;
133 git_oid i_commit_oid
;
134 git_buf msg
= GIT_BUF_INIT
;
137 if (build_tree_from_index(&i_tree
, index
) < 0)
140 if (git_buf_printf(&msg
, "index on %s\n", message
) < 0)
143 if (git_commit_create(
145 git_index_owner(index
),
156 error
= git_commit_lookup(i_commit
, git_index_owner(index
), &i_commit_oid
);
159 git_tree_free(i_tree
);
167 bool include_changed
;
168 bool include_untracked
;
169 bool include_ignored
;
172 static int update_index_cb(
173 const git_diff_delta
*delta
,
178 struct cb_data
*data
= (struct cb_data
*)payload
;
180 GIT_UNUSED(progress
);
182 switch (delta
->status
) {
183 case GIT_DELTA_IGNORED
:
184 if (!data
->include_ignored
)
187 return git_index_add_from_workdir(data
->index
, delta
->new_file
.path
);
189 case GIT_DELTA_UNTRACKED
:
190 if (!data
->include_untracked
)
193 return git_index_add_from_workdir(data
->index
, delta
->new_file
.path
);
195 case GIT_DELTA_ADDED
:
197 case GIT_DELTA_MODIFIED
:
198 if (!data
->include_changed
)
201 return git_index_add_from_workdir(data
->index
, delta
->new_file
.path
);
203 case GIT_DELTA_DELETED
:
204 if (!data
->include_changed
)
207 if ((pos
= git_index_find(data
->index
, delta
->new_file
.path
)) < 0)
210 if (git_index_remove(data
->index
, delta
->new_file
.path
, 0) < 0)
217 "Cannot update index. Unimplemented status kind (%d)",
225 static int build_untracked_tree(
228 git_commit
*i_commit
,
231 git_tree
*i_tree
= NULL
;
232 git_diff_list
*diff
= NULL
;
233 git_diff_options opts
= GIT_DIFF_OPTIONS_INIT
;
234 struct cb_data data
= {0};
237 git_index_clear(index
);
241 if (flags
& GIT_STASH_INCLUDE_UNTRACKED
) {
242 opts
.flags
|= GIT_DIFF_INCLUDE_UNTRACKED
| GIT_DIFF_RECURSE_UNTRACKED_DIRS
;
243 data
.include_untracked
= true;
246 if (flags
& GIT_STASH_INCLUDE_IGNORED
) {
247 opts
.flags
|= GIT_DIFF_INCLUDE_IGNORED
;
248 data
.include_ignored
= true;
251 if (git_commit_tree(&i_tree
, i_commit
) < 0)
254 if (git_diff_tree_to_workdir(&diff
, git_index_owner(index
), i_tree
, &opts
) < 0)
257 if (git_diff_foreach(diff
, update_index_cb
, NULL
, NULL
, &data
) < 0)
260 if (build_tree_from_index(tree_out
, index
) < 0)
266 git_diff_list_free(diff
);
267 git_tree_free(i_tree
);
271 static int commit_untracked(
272 git_commit
**u_commit
,
274 git_signature
*stasher
,
276 git_commit
*i_commit
,
279 git_tree
*u_tree
= NULL
;
280 git_oid u_commit_oid
;
281 git_buf msg
= GIT_BUF_INIT
;
284 if (build_untracked_tree(&u_tree
, index
, i_commit
, flags
) < 0)
287 if (git_buf_printf(&msg
, "untracked files on %s\n", message
) < 0)
290 if (git_commit_create(
292 git_index_owner(index
),
303 error
= git_commit_lookup(u_commit
, git_index_owner(index
), &u_commit_oid
);
306 git_tree_free(u_tree
);
311 static int build_workdir_tree(
314 git_commit
*b_commit
)
316 git_repository
*repo
= git_index_owner(index
);
317 git_tree
*b_tree
= NULL
;
318 git_diff_list
*diff
= NULL
, *diff2
= NULL
;
319 git_diff_options opts
= GIT_DIFF_OPTIONS_INIT
;
320 struct cb_data data
= {0};
323 if (git_commit_tree(&b_tree
, b_commit
) < 0)
326 if (git_diff_tree_to_index(&diff
, repo
, b_tree
, NULL
, &opts
) < 0)
329 if (git_diff_index_to_workdir(&diff2
, repo
, NULL
, &opts
) < 0)
332 if (git_diff_merge(diff
, diff2
) < 0)
336 data
.include_changed
= true;
338 if (git_diff_foreach(diff
, update_index_cb
, NULL
, NULL
, &data
) < 0)
341 if (build_tree_from_index(tree_out
, index
) < 0)
347 git_diff_list_free(diff
);
348 git_diff_list_free(diff2
);
349 git_tree_free(b_tree
);
353 static int commit_worktree(
354 git_oid
*w_commit_oid
,
356 git_signature
*stasher
,
358 git_commit
*i_commit
,
359 git_commit
*b_commit
,
360 git_commit
*u_commit
)
362 git_tree
*w_tree
= NULL
, *i_tree
= NULL
;
365 const git_commit
*parents
[] = { NULL
, NULL
, NULL
};
367 parents
[0] = b_commit
;
368 parents
[1] = i_commit
;
369 parents
[2] = u_commit
;
371 if (git_commit_tree(&i_tree
, i_commit
) < 0)
374 if (git_index_read_tree(index
, i_tree
) < 0)
377 if (build_workdir_tree(&w_tree
, index
, b_commit
) < 0)
380 if (git_commit_create(
382 git_index_owner(index
),
389 u_commit
? 3 : 2, parents
) < 0)
395 git_tree_free(i_tree
);
396 git_tree_free(w_tree
);
400 static int prepare_worktree_commit_message(
402 const char *user_message
)
404 git_buf buf
= GIT_BUF_INIT
;
407 git_buf_set(&buf
, git_buf_cstr(msg
), git_buf_len(msg
));
411 git_buf_printf(msg
, "WIP on %s", git_buf_cstr(&buf
));
415 if ((colon
= strchr(git_buf_cstr(&buf
), ':')) == NULL
)
418 git_buf_puts(msg
, "On ");
419 git_buf_put(msg
, git_buf_cstr(&buf
), colon
- buf
.ptr
);
420 git_buf_printf(msg
, ": %s\n", user_message
);
423 error
= git_buf_oom(msg
) || git_buf_oom(&buf
) ? -1 : 0;
430 static int update_reflog(
431 git_oid
*w_commit_oid
,
432 git_repository
*repo
,
433 git_signature
*stasher
,
436 git_reference
*stash
= NULL
;
437 git_reflog
*reflog
= NULL
;
440 if ((error
= git_reference_create(&stash
, repo
, GIT_REFS_STASH_FILE
, w_commit_oid
, 1)) < 0)
443 if ((error
= git_reflog_read(&reflog
, stash
)) < 0)
446 if ((error
= git_reflog_append(reflog
, w_commit_oid
, stasher
, message
)) < 0)
449 if ((error
= git_reflog_write(reflog
)) < 0)
455 git_reference_free(stash
);
456 git_reflog_free(reflog
);
460 static int is_dirty_cb(const char *path
, unsigned int status
, void *payload
)
469 static int ensure_there_are_changes_to_stash(
470 git_repository
*repo
,
471 bool include_untracked_files
,
472 bool include_ignored_files
)
475 git_status_options opts
= GIT_STATUS_OPTIONS_INIT
;
477 opts
.show
= GIT_STATUS_SHOW_INDEX_AND_WORKDIR
;
478 if (include_untracked_files
)
479 opts
.flags
= GIT_STATUS_OPT_INCLUDE_UNTRACKED
|
480 GIT_STATUS_OPT_RECURSE_UNTRACKED_DIRS
;
482 if (include_ignored_files
)
483 opts
.flags
= GIT_STATUS_OPT_INCLUDE_IGNORED
;
485 error
= git_status_foreach_ext(repo
, &opts
, is_dirty_cb
, NULL
);
487 if (error
== GIT_EUSER
)
491 return create_error(GIT_ENOTFOUND
, "There is nothing to stash.");
496 static int reset_index_and_workdir(
497 git_repository
*repo
,
499 bool remove_untracked
)
501 git_checkout_opts opts
= GIT_CHECKOUT_OPTS_INIT
;
503 opts
.checkout_strategy
=
504 GIT_CHECKOUT_UPDATE_MODIFIED
| GIT_CHECKOUT_UPDATE_UNTRACKED
;
506 if (remove_untracked
)
507 opts
.checkout_strategy
|= GIT_CHECKOUT_REMOVE_UNTRACKED
;
509 return git_checkout_tree(repo
, (git_object
*)commit
, &opts
);
514 git_repository
*repo
,
515 git_signature
*stasher
,
519 git_index
*index
= NULL
;
520 git_commit
*b_commit
= NULL
, *i_commit
= NULL
, *u_commit
= NULL
;
521 git_buf msg
= GIT_BUF_INIT
;
524 assert(out
&& repo
&& stasher
);
526 if ((error
= ensure_non_bare_repository(repo
)) < 0)
529 if ((error
= retrieve_base_commit_and_message(&b_commit
, &msg
, repo
)) < 0)
532 if ((error
= ensure_there_are_changes_to_stash(
534 (flags
& GIT_STASH_INCLUDE_UNTRACKED
) == GIT_STASH_INCLUDE_UNTRACKED
,
535 (flags
& GIT_STASH_INCLUDE_IGNORED
) == GIT_STASH_INCLUDE_IGNORED
)) < 0)
540 if (git_repository_index(&index
, repo
) < 0)
543 if (commit_index(&i_commit
, index
, stasher
, git_buf_cstr(&msg
), b_commit
) < 0)
546 if ((flags
& GIT_STASH_INCLUDE_UNTRACKED
|| flags
& GIT_STASH_INCLUDE_IGNORED
)
547 && commit_untracked(&u_commit
, index
, stasher
, git_buf_cstr(&msg
), i_commit
, flags
) < 0)
550 if (prepare_worktree_commit_message(&msg
, message
) < 0)
553 if (commit_worktree(out
, index
, stasher
, git_buf_cstr(&msg
), i_commit
, b_commit
, u_commit
) < 0)
557 if (update_reflog(out
, repo
, stasher
, git_buf_cstr(&msg
)) < 0)
560 if (reset_index_and_workdir(
562 ((flags
& GIT_STASH_KEEP_INDEX
) == GIT_STASH_KEEP_INDEX
) ?
564 (flags
& GIT_STASH_INCLUDE_UNTRACKED
) == GIT_STASH_INCLUDE_UNTRACKED
) < 0)
571 git_commit_free(i_commit
);
572 git_commit_free(b_commit
);
573 git_commit_free(u_commit
);
574 git_index_free(index
);
578 int git_stash_foreach(
579 git_repository
*repo
,
580 git_stash_cb callback
,
583 git_reference
*stash
;
584 git_reflog
*reflog
= NULL
;
587 const git_reflog_entry
*entry
;
589 error
= git_reference_lookup(&stash
, repo
, GIT_REFS_STASH_FILE
);
590 if (error
== GIT_ENOTFOUND
)
596 if ((error
= git_reflog_read(&reflog
, stash
)) < 0)
599 max
= git_reflog_entrycount(reflog
);
600 for (i
= 0; i
< max
; i
++) {
601 entry
= git_reflog_entry_byindex(reflog
, i
);
604 git_reflog_entry_message(entry
),
605 git_reflog_entry_id_new(entry
),
615 git_reference_free(stash
);
616 git_reflog_free(reflog
);
621 git_repository
*repo
,
624 git_reference
*stash
;
625 git_reflog
*reflog
= NULL
;
629 if ((error
= git_reference_lookup(&stash
, repo
, GIT_REFS_STASH_FILE
)) < 0)
632 if ((error
= git_reflog_read(&reflog
, stash
)) < 0)
635 max
= git_reflog_entrycount(reflog
);
637 if (index
> max
- 1) {
638 error
= GIT_ENOTFOUND
;
639 giterr_set(GITERR_STASH
, "No stashed state at position %" PRIuZ
, index
);
643 if ((error
= git_reflog_drop(reflog
, index
, true)) < 0)
646 if ((error
= git_reflog_write(reflog
)) < 0)
650 error
= git_reference_delete(stash
);
655 git_reference_free(stash
);
656 git_reflog_free(reflog
);