#include "dir.h"
#include "tree.h"
#include "commit.h"
-#include "diff.h"
-#include "diffcore.h"
-#include "revision.h"
#include "blob.h"
+#include "resolve-undo.h"
+
+static struct cache_entry *refresh_cache_entry(struct cache_entry *ce, int really);
/* Index extensions.
*
#define CACHE_EXT(s) ( (s[0]<<24)|(s[1]<<16)|(s[2]<<8)|(s[3]) )
#define CACHE_EXT_TREE 0x54524545 /* "TREE" */
+#define CACHE_EXT_RESOLVE_UNDO 0x52455543 /* "REUN" */
struct index_state the_index;
return 0;
}
-int is_empty_blob_sha1(const unsigned char *sha1)
+static int is_empty_blob_sha1(const unsigned char *sha1)
{
static const unsigned char empty_blob_sha1[20] = {
0xe6,0x9d,0xe2,0x9b,0xb2,0xd1,0xd6,0x43,0x4b,0x8b,
{
unsigned int changed;
int ignore_valid = options & CE_MATCH_IGNORE_VALID;
+ int ignore_skip_worktree = options & CE_MATCH_IGNORE_SKIP_WORKTREE;
int assume_racy_is_modified = options & CE_MATCH_RACY_IS_DIRTY;
/*
* If it's marked as always valid in the index, it's
* valid whatever the checked-out copy says.
+ *
+ * skip-worktree has the same effect with higher precedence
*/
+ if (!ignore_skip_worktree && ce_skip_worktree(ce))
+ return 0;
if (!ignore_valid && (ce->ce_flags & CE_VALID))
return 0;
{
struct cache_entry *ce = istate->cache[pos];
+ record_resolve_undo(istate, ce);
remove_name_hash(ce);
istate->cache_changed = 1;
istate->cache_nr--;
int size, namelen, was_same;
mode_t st_mode = st->st_mode;
struct cache_entry *ce, *alias;
- unsigned ce_option = CE_MATCH_IGNORE_VALID|CE_MATCH_RACY_IS_DIRTY;
+ unsigned ce_option = CE_MATCH_IGNORE_VALID|CE_MATCH_IGNORE_SKIP_WORKTREE|CE_MATCH_RACY_IS_DIRTY;
int verbose = flags & (ADD_CACHE_VERBOSE | ADD_CACHE_PRETEND);
int pretend = flags & ADD_CACHE_PRETEND;
int intent_only = flags & ADD_CACHE_INTENT;
if (alias && !ce_stage(alias) && !ie_match_stat(istate, alias, st, ce_option)) {
/* Nothing changed, really */
free(ce);
- ce_mark_uptodate(alias);
+ if (!S_ISGITLINK(alias->ce_mode))
+ ce_mark_uptodate(alias);
alias->ce_flags |= CE_ADDED;
return 0;
}
{
struct stat st;
if (lstat(path, &st))
- die("%s: unable to stat (%s)", path, strerror(errno));
+ die_errno("unable to stat '%s'", path);
return add_to_index(istate, path, &st, flags);
}
struct cache_entry *updated;
int changed, size;
int ignore_valid = options & CE_MATCH_IGNORE_VALID;
+ int ignore_skip_worktree = options & CE_MATCH_IGNORE_SKIP_WORKTREE;
if (ce_uptodate(ce))
return ce;
/*
- * CE_VALID means the user promised us that the change to
- * the work tree does not matter and told us not to worry.
+ * CE_VALID or CE_SKIP_WORKTREE means the user promised us
+ * that the change to the work tree does not matter and told
+ * us not to worry.
*/
+ if (!ignore_skip_worktree && ce_skip_worktree(ce)) {
+ ce_mark_uptodate(ce);
+ return ce;
+ }
if (!ignore_valid && (ce->ce_flags & CE_VALID)) {
ce_mark_uptodate(ce);
return ce;
* because CE_UPTODATE flag is in-core only;
* we are not going to write this change out.
*/
- ce_mark_uptodate(ce);
+ if (!S_ISGITLINK(ce->ce_mode))
+ ce_mark_uptodate(ce);
return ce;
}
}
return updated;
}
-int refresh_index(struct index_state *istate, unsigned int flags, const char **pathspec, char *seen)
+static void show_file(const char * fmt, const char * name, int in_porcelain,
+ int * first, char *header_msg)
+{
+ if (in_porcelain && *first && header_msg) {
+ printf("%s\n", header_msg);
+ *first=0;
+ }
+ printf(fmt, name);
+}
+
+int refresh_index(struct index_state *istate, unsigned int flags, const char **pathspec,
+ char *seen, char *header_msg)
{
int i;
int has_errors = 0;
int quiet = (flags & REFRESH_QUIET) != 0;
int not_new = (flags & REFRESH_IGNORE_MISSING) != 0;
int ignore_submodules = (flags & REFRESH_IGNORE_SUBMODULES) != 0;
+ int first = 1;
+ int in_porcelain = (flags & REFRESH_IN_PORCELAIN);
unsigned int options = really ? CE_MATCH_IGNORE_VALID : 0;
- const char *needs_update_message;
+ const char *needs_update_fmt;
+ const char *needs_merge_fmt;
- needs_update_message = ((flags & REFRESH_SAY_CHANGED)
- ? "locally modified" : "needs update");
+ needs_update_fmt = (in_porcelain ? "M\t%s\n" : "%s: needs update\n");
+ needs_merge_fmt = (in_porcelain ? "U\t%s\n" : "%s: needs merge\n");
for (i = 0; i < istate->cache_nr; i++) {
struct cache_entry *ce, *new;
int cache_errno = 0;
i--;
if (allow_unmerged)
continue;
- printf("%s: needs merge\n", ce->name);
+ show_file(needs_merge_fmt, ce->name, in_porcelain, &first, header_msg);
has_errors = 1;
continue;
}
}
if (quiet)
continue;
- printf("%s: %s\n", ce->name, needs_update_message);
+ show_file(needs_update_fmt, ce->name, in_porcelain, &first, header_msg);
has_errors = 1;
continue;
}
return has_errors;
}
-struct cache_entry *refresh_cache_entry(struct cache_entry *ce, int really)
+static struct cache_entry *refresh_cache_entry(struct cache_entry *ce, int really)
{
return refresh_cache_ent(&the_index, ce, really, NULL);
}
case CACHE_EXT_TREE:
istate->cache_tree = cache_tree_read(data, sz);
break;
+ case CACHE_EXT_RESOLVE_UNDO:
+ istate->resolve_undo = resolve_undo_read(data, sz);
+ break;
default:
if (*ext < 'A' || 'Z' < *ext)
return error("index uses %.4s extension, which we do not understand",
if (fd < 0) {
if (errno == ENOENT)
return 0;
- die("index file open failed (%s)", strerror(errno));
+ die_errno("index file open failed");
}
if (fstat(fd, &st))
- die("cannot stat the open index (%s)", strerror(errno));
+ die_errno("cannot stat the open index");
errno = EINVAL;
mmap_size = xsize_t(st.st_size);
mmap = xmmap(NULL, mmap_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
close(fd);
if (mmap == MAP_FAILED)
- die("unable to map index file");
+ die_errno("unable to map index file");
hdr = mmap;
if (verify_hdr(hdr, mmap_size) < 0)
* extension name (4-byte) and section length
* in 4-byte network byte order.
*/
- unsigned long extsize;
+ uint32_t extsize;
memcpy(&extsize, (char *)mmap + src_offset + 4, 4);
extsize = ntohl(extsize);
if (read_index_extension(istate,
int discard_index(struct index_state *istate)
{
+ resolve_undo_clear_index(istate);
istate->cache_nr = 0;
istate->cache_changed = 0;
istate->timestamp.sec = 0;
if (err)
return -1;
}
+ if (istate->resolve_undo) {
+ struct strbuf sb = STRBUF_INIT;
+
+ resolve_undo_write(&sb, istate->resolve_undo);
+ err = write_index_ext_header(&c, newfd, CACHE_EXT_RESOLVE_UNDO,
+ sb.len) < 0
+ || ce_write(&c, newfd, sb.buf, sb.len) < 0;
+ strbuf_release(&sb);
+ if (err)
+ return -1;
+ }
if (ce_flush(&c, newfd) || fstat(newfd, &st))
return -1;
len = strlen(ce->name);
size = cache_entry_size(len);
new_ce = xcalloc(1, size);
- hashcpy(new_ce->sha1, ce->sha1);
memcpy(new_ce->name, ce->name, len);
- new_ce->ce_flags = create_ce_flags(len, 0);
+ new_ce->ce_flags = create_ce_flags(len, 0) | CE_CONFLICTED;
new_ce->ce_mode = ce->ce_mode;
if (add_index_entry(istate, new_ce, 0))
return error("%s: cannot drop to stage #0",
return unmerged;
}
-struct update_callback_data
-{
- int flags;
- int add_errors;
-};
-
-static void update_callback(struct diff_queue_struct *q,
- struct diff_options *opt, void *cbdata)
-{
- int i;
- struct update_callback_data *data = cbdata;
-
- for (i = 0; i < q->nr; i++) {
- struct diff_filepair *p = q->queue[i];
- const char *path = p->one->path;
- switch (p->status) {
- default:
- die("unexpected diff status %c", p->status);
- case DIFF_STATUS_UNMERGED:
- /*
- * ADD_CACHE_IGNORE_REMOVAL is unset if "git
- * add -u" is calling us, In such a case, a
- * missing work tree file needs to be removed
- * if there is an unmerged entry at stage #2,
- * but such a diff record is followed by
- * another with DIFF_STATUS_DELETED (and if
- * there is no stage #2, we won't see DELETED
- * nor MODIFIED). We can simply continue
- * either way.
- */
- if (!(data->flags & ADD_CACHE_IGNORE_REMOVAL))
- continue;
- /*
- * Otherwise, it is "git add path" is asking
- * to explicitly add it; we fall through. A
- * missing work tree file is an error and is
- * caught by add_file_to_index() in such a
- * case.
- */
- case DIFF_STATUS_MODIFIED:
- case DIFF_STATUS_TYPE_CHANGED:
- if (add_file_to_index(&the_index, path, data->flags)) {
- if (!(data->flags & ADD_CACHE_IGNORE_ERRORS))
- die("updating files failed");
- data->add_errors++;
- }
- break;
- case DIFF_STATUS_DELETED:
- if (data->flags & ADD_CACHE_IGNORE_REMOVAL)
- break;
- if (!(data->flags & ADD_CACHE_PRETEND))
- remove_file_from_index(&the_index, path);
- if (data->flags & (ADD_CACHE_PRETEND|ADD_CACHE_VERBOSE))
- printf("remove '%s'\n", path);
- break;
- }
- }
-}
-
-int add_files_to_cache(const char *prefix, const char **pathspec, int flags)
-{
- struct update_callback_data data;
- struct rev_info rev;
- init_revisions(&rev, prefix);
- setup_revisions(0, NULL, &rev, NULL);
- rev.prune_data = pathspec;
- rev.diffopt.output_format = DIFF_FORMAT_CALLBACK;
- rev.diffopt.format_callback = update_callback;
- data.flags = flags;
- data.add_errors = 0;
- rev.diffopt.format_callback_data = &data;
- run_diff_files(&rev, DIFF_RACY_IS_MODIFIED);
- return !!data.add_errors;
-}
-
/*
* Returns 1 if the path is an "other" path with respect to
* the index; that is, the path is not mentioned in the index at all,