]> git.proxmox.com Git - libgit2.git/commitdiff
Introduce status/diff TYPECHANGE flags
authorRussell Belfer <rb@github.com>
Fri, 28 Sep 2012 20:40:02 +0000 (13:40 -0700)
committerRussell Belfer <rb@github.com>
Tue, 9 Oct 2012 18:54:01 +0000 (11:54 -0700)
When I wrote the diff code, I based it on core git's diff output
which tends to split a type change into an add and a delete.  But
core git's status has the notion of a T (typechange) flag for a
file.  This introduces that into our status APIs and modifies the
diff code so it can be forced to not split type changes.

include/git2/diff.h
include/git2/status.h
src/diff.c
src/status.c

index 121c403070e72c880a022e65b97513effeb19238..24556db73860cc7b2619f2873fb0a4c9774530c6 100644 (file)
@@ -49,6 +49,7 @@ enum {
        GIT_DIFF_DISABLE_PATHSPEC_MATCH = (1 << 11),
        GIT_DIFF_DELTAS_ARE_ICASE = (1 << 12),
        GIT_DIFF_INCLUDE_UNTRACKED_CONTENT = (1 << 13),
+       GIT_DIFF_DONT_SPLIT_TYPECHANGE = (1 << 14),
 };
 
 /**
@@ -116,7 +117,8 @@ typedef enum {
        GIT_DELTA_RENAMED = 4,
        GIT_DELTA_COPIED = 5,
        GIT_DELTA_IGNORED = 6,
-       GIT_DELTA_UNTRACKED = 7
+       GIT_DELTA_UNTRACKED = 7,
+       GIT_DELTA_TYPECHANGE = 8,
 } git_delta_t;
 
 /**
index cc94d7680224edcd3edc8b1b54550a328ec8161f..725e3ef592c7c33d9f150dad0737a3513276f157 100644 (file)
  */
 GIT_BEGIN_DECL
 
-enum {
-       GIT_STATUS_CURRENT      = 0,
+typedef enum {
+       GIT_STATUS_CURRENT = 0,
 
-       GIT_STATUS_INDEX_NEW = (1 << 0),
-       GIT_STATUS_INDEX_MODIFIED = (1 << 1),
-       GIT_STATUS_INDEX_DELETED = (1 << 2),
+       GIT_STATUS_INDEX_NEW        = (1u << 0),
+       GIT_STATUS_INDEX_MODIFIED   = (1u << 1),
+       GIT_STATUS_INDEX_DELETED    = (1u << 2),
+       GIT_STATUS_INDEX_RENAMED    = (1u << 3),
+       GIT_STATUS_INDEX_TYPECHANGE = (1u << 4),
 
-       GIT_STATUS_WT_NEW = (1 << 3),
-       GIT_STATUS_WT_MODIFIED = (1 << 4),
-       GIT_STATUS_WT_DELETED = (1 << 5),
+       GIT_STATUS_WT_NEW           = (1u << 7),
+       GIT_STATUS_WT_MODIFIED      = (1u << 8),
+       GIT_STATUS_WT_DELETED       = (1u << 9),
+       GIT_STATUS_WT_TYPECHANGE    = (1u << 10),
 
-       GIT_STATUS_IGNORED = (1 << 6),
-};
+       GIT_STATUS_IGNORED          = (1u << 14),
+} git_status_t;
 
 /**
  * Gather file statuses and run a callback for each one.
index 8ab8af3a15d6f7130d13926f6f7908f193b19d10..f88bda4aad89b9543077a961d3b3ff9633d6a437 100644 (file)
@@ -508,6 +508,7 @@ static int maybe_modified(
        git_delta_t status = GIT_DELTA_MODIFIED;
        unsigned int omode = oitem->mode;
        unsigned int nmode = nitem->mode;
+       bool new_is_workdir = (new_iter->type == GIT_ITERATOR_WORKDIR);
 
        GIT_UNUSED(old_iter);
 
@@ -515,15 +516,14 @@ static int maybe_modified(
                return 0;
 
        /* on platforms with no symlinks, preserve mode of existing symlinks */
-       if (S_ISLNK(omode) && S_ISREG(nmode) &&
-               !(diff->diffcaps & GIT_DIFFCAPS_HAS_SYMLINKS) &&
-               new_iter->type == GIT_ITERATOR_WORKDIR)
+       if (S_ISLNK(omode) && S_ISREG(nmode) && new_is_workdir &&
+               !(diff->diffcaps & GIT_DIFFCAPS_HAS_SYMLINKS))
                nmode = omode;
 
        /* on platforms with no execmode, just preserve old mode */
        if (!(diff->diffcaps & GIT_DIFFCAPS_TRUST_MODE_BITS) &&
                (nmode & MODE_BITS_MASK) != (omode & MODE_BITS_MASK) &&
-               new_iter->type == GIT_ITERATOR_WORKDIR)
+               new_is_workdir)
                nmode = (nmode & ~MODE_BITS_MASK) | (omode & MODE_BITS_MASK);
 
        /* support "assume unchanged" (poorly, b/c we still stat everything) */
@@ -537,10 +537,14 @@ static int maybe_modified(
 
        /* if basic type of file changed, then split into delete and add */
        else if (GIT_MODE_TYPE(omode) != GIT_MODE_TYPE(nmode)) {
-               if (diff_delta__from_one(diff, GIT_DELTA_DELETED, oitem) < 0 ||
-                       diff_delta__from_one(diff, GIT_DELTA_ADDED, nitem) < 0)
-                       return -1;
-               return 0;
+               if ((diff->opts.flags & GIT_DIFF_DONT_SPLIT_TYPECHANGE) != 0)
+                       status = GIT_DELTA_TYPECHANGE;
+               else {
+                       if (diff_delta__from_one(diff, GIT_DELTA_DELETED, oitem) < 0 ||
+                               diff_delta__from_one(diff, GIT_DELTA_ADDED, nitem) < 0)
+                               return -1;
+                       return 0;
+               }
        }
 
        /* if oids and modes match, then file is unmodified */
@@ -551,9 +555,7 @@ static int maybe_modified(
        /* if we have an unknown OID and a workdir iterator, then check some
         * circumstances that can accelerate things or need special handling
         */
-       else if (git_oid_iszero(&nitem->oid) &&
-                        new_iter->type == GIT_ITERATOR_WORKDIR)
-       {
+       else if (git_oid_iszero(&nitem->oid) && new_is_workdir) {
                /* TODO: add check against index file st_mtime to avoid racy-git */
 
                /* if the stat data looks exactly alike, then assume the same */
@@ -600,7 +602,7 @@ static int maybe_modified(
        /* if we got here and decided that the files are modified, but we
         * haven't calculated the OID of the new item, then calculate it now
         */
-       if (status == GIT_DELTA_MODIFIED && git_oid_iszero(&nitem->oid)) {
+       if (status != GIT_DELTA_UNMODIFIED && git_oid_iszero(&nitem->oid)) {
                if (oid_for_workdir_item(diff->repo, nitem, &noid) < 0)
                        return -1;
                else if (omode == nmode && git_oid_equal(&oitem->oid, &noid))
index 3a0ed075ff92fa2331d0070b92b3e9ebd5b7ee41..e39006e938d0d6405e56404e8172381cabe7a8d4 100644 (file)
@@ -25,7 +25,6 @@ static unsigned int index_delta2status(git_delta_t index_status)
        switch (index_status) {
        case GIT_DELTA_ADDED:
        case GIT_DELTA_COPIED:
-       case GIT_DELTA_RENAMED:
                st = GIT_STATUS_INDEX_NEW;
                break;
        case GIT_DELTA_DELETED:
@@ -34,6 +33,12 @@ static unsigned int index_delta2status(git_delta_t index_status)
        case GIT_DELTA_MODIFIED:
                st = GIT_STATUS_INDEX_MODIFIED;
                break;
+       case GIT_DELTA_RENAMED:
+               st = GIT_STATUS_INDEX_RENAMED;
+               break;
+       case GIT_DELTA_TYPECHANGE:
+               st = GIT_STATUS_INDEX_TYPECHANGE;
+               break;
        default:
                break;
        }
@@ -47,8 +52,8 @@ static unsigned int workdir_delta2status(git_delta_t workdir_status)
 
        switch (workdir_status) {
        case GIT_DELTA_ADDED:
-       case GIT_DELTA_COPIED:
        case GIT_DELTA_RENAMED:
+       case GIT_DELTA_COPIED:
        case GIT_DELTA_UNTRACKED:
                st = GIT_STATUS_WT_NEW;
                break;
@@ -61,6 +66,9 @@ static unsigned int workdir_delta2status(git_delta_t workdir_status)
        case GIT_DELTA_IGNORED:
                st = GIT_STATUS_IGNORED;
                break;
+       case GIT_DELTA_TYPECHANGE:
+               st = GIT_STATUS_WT_TYPECHANGE;
+               break;
        default:
                break;
        }
@@ -92,6 +100,8 @@ int git_status_foreach_ext(
        memset(&diffopt, 0, sizeof(diffopt));
        memcpy(&diffopt.pathspec, &opts->pathspec, sizeof(diffopt.pathspec));
 
+       diffopt.flags = GIT_DIFF_DONT_SPLIT_TYPECHANGE;
+
        if ((opts->flags & GIT_STATUS_OPT_INCLUDE_UNTRACKED) != 0)
                diffopt.flags = diffopt.flags | GIT_DIFF_INCLUDE_UNTRACKED;
        if ((opts->flags & GIT_STATUS_OPT_INCLUDE_IGNORED) != 0)