12 #include "cache-tree.h"
13 #include "unpack-trees.h"
14 #include "reflog-walk.h"
17 // uses the ls-files code
18 #include "builtin-ls-files.c"
21 // custom cache entry flags (just to make sure that no git functions get confused)
22 #define CE_IG_ADDED 0x2000000
23 #define CE_IG_DELETED 0x4000000
24 #define CE_IG_STAGED 0x8000000
29 // cached last access, to speed up searches (since we get a sorted list from git code)
30 struct DirStatus
*pLastAccessedChild
;
34 struct DirStatus
*next
;
35 struct DirStatus
*children
;
36 struct DirStatus
*parent
;
39 BOOL bExplicitlyIgnored
;
42 static struct DirStatus l_dirTree
;
47 struct cache_entry
*ce
;
48 struct EntryRef
*next
;
51 static struct EntryRef
*l_delQueue
= NULL
;
54 // enable caching of last commit's index (to reduce disk i/o caused by unpacking trees and whatnot)
55 static BOOL l_bEnableIndexCache
= TRUE
;
57 static BOOL l_bNoRecurse
;
58 static int l_nMinStatusRelevantForDirs
;
59 static BOOL l_bSkipNormalDirs
;
60 static int l_nEmptyDirStatus
;
61 static BOOL l_bNoRecurseDir
;
63 static BOOL l_bFullPath
;
64 static char l_sFullPathBuf
[2048];
65 static LPSTR l_lpszFileName
;
67 static BOOL l_bDirStatus
;
68 static int l_nLastStatus
;
69 static int l_nEnumeratedCached
= 0;
71 static BOOL l_bHasHistory
= FALSE
;
74 static inline char GetStatusChar(int nStatus
)
78 case WGFS_Normal
: return 'N';
79 case WGFS_Modified
: return 'M';
80 case WGFS_Staged
: return 'S';
81 case WGFS_Added
: return 'A';
82 case WGFS_Conflicted
: return 'C';
83 case WGFS_Deleted
: return 'D';
85 case WGFS_Unversioned
: return 'U';
86 case WGFS_Ignored
: return 'I';
87 case WGFS_Unknown
: return '?';
88 case WGFS_Empty
: return 'E';
95 static inline void queue_deleted(struct cache_entry
*ce
)
97 struct EntryRef
*p
= (struct EntryRef
*) malloc( sizeof(struct EntryRef
) );
101 p
->next
= l_delQueue
;
106 static BOOL
enum_ce_entry(struct cache_entry
*ce
, struct stat
*st
)
108 // is this of any use (ce->ce_flags & CE_VALID) ?
114 sFileName
= ce
->name
+ prefix_offset
;
118 strcpy(l_lpszFileName
, ce
->name
);
119 sFileName
= l_sFullPathBuf
;
122 const int nStage
= ce_stage(ce
);
124 int nStatus
= WGFS_Unknown
;
125 if (!st
|| (ce
->ce_flags
& CE_IG_DELETED
))
126 nStatus
= WGFS_Deleted
;
128 nStatus
= WGFS_Conflicted
;
129 else if (ce
->ce_flags
& CE_IG_ADDED
)
130 nStatus
= WGFS_Added
;
131 else if ( ce_modified(ce
, st
, 0) )
132 nStatus
= WGFS_Modified
;
133 else if (ce
->ce_flags
& CE_IG_STAGED
)
134 nStatus
= WGFS_Staged
;
135 else if (!l_bHasHistory
)
136 nStatus
= WGFS_Added
;
138 nStatus
= WGFS_Normal
;
139 l_nLastStatus
= nStatus
;
141 // output format: "F status sha1 filename"
144 fputc(GetStatusChar(nStatus
), stdout
);
146 fputsha1(ce
->sha1
, stdout
);
148 fputs(sFileName
, stdout
);
151 l_nEnumeratedCached
++;
156 // same as enum except it skips enumeration and just determines status (used for recursive folder status)
157 // returns TRUE if file was processed
158 static BOOL
process_ce_entry_status(struct cache_entry
*ce
, struct stat
*st
)
160 // is this of any use (ce->ce_flags & CE_VALID) ?
164 ef.sFileName = ce->name + offset;
168 strcpy(l_lpszFileName, ce->name);
169 ef.sFileName = l_sFullPathBuf;
172 const int nStage
= ce_stage(ce
);
174 UINT nStatus
= WGFS_Unknown
;
175 if (!st
|| (ce
->ce_flags
& CE_IG_DELETED
))
176 nStatus
= WGFS_Deleted
;
178 nStatus
= WGFS_Conflicted
;
179 else if (ce
->ce_flags
& CE_IG_ADDED
)
180 nStatus
= WGFS_Added
;
181 else if ( ce_modified(ce
, st
, 0) )
182 nStatus
= WGFS_Modified
;
183 else if (ce
->ce_flags
& CE_IG_STAGED
)
184 nStatus
= WGFS_Staged
;
185 else if (!l_bHasHistory
)
186 nStatus
= WGFS_Added
;
188 nStatus
= WGFS_Normal
;
189 l_nLastStatus
= nStatus
;
191 //ef.nStage = st ? ce_stage(ce) : 0;
193 //ef.sha1 = ce->sha1;
199 static void update_dirs_unversioned(struct dir_entry
*ce
, int nPathNameOffset
);
201 static void enum_unversioned(struct dir_entry
**files
, int nr
, BOOL bIgnored
)
206 struct dir_entry
*ent
= files
[i
];
208 if (ent
->name
[ent
->len
-1] != '/' && !cache_name_is_other(ent
->name
, ent
->len
))
211 int len
= prefix_len
;
214 die("igit status: internal error - directory entry not superset of prefix");
216 if (pathspec
&& !match_pathspec(pathspec
, ent
->name
, ent
->len
, len
, ps_matched
))
223 sFileName
= ent
->name
+ prefix_offset
;
227 strcpy(l_lpszFileName
, ent
->name
);
228 sFileName
= l_sFullPathBuf
;
233 // because we specified collect_all_ignored this may be a directory that was ignored
234 if (ent
->name
[ent
->len
-1] != '/')
238 l_nLastStatus
= WGFS_Ignored
;
239 update_dirs_unversioned(ent
, len
);
242 fputs("F I 0000000000000000000000000000000000000000 ", stdout
);
248 const int nOrgEmptyDirStatus
= l_nEmptyDirStatus
;
249 l_nLastStatus
= l_nEmptyDirStatus
= WGFS_Ignored
;
250 update_dirs_unversioned(ent
, len
);
251 l_nEmptyDirStatus
= nOrgEmptyDirStatus
;
259 if (ent
->name
[ent
->len
-1] != '/')
263 l_nLastStatus
= WGFS_Unversioned
;
264 update_dirs_unversioned(ent
, len
);
267 fputs("F U 0000000000000000000000000000000000000000 ", stdout
);
273 l_nLastStatus
= l_nEmptyDirStatus
;
274 update_dirs_unversioned(ent
, len
);
280 fputs(sFileName
, stdout
);
286 static inline BOOL
enum_dir(struct DirStatus
*dir
, LPCSTR lpszPathName
)
288 if (dir
->nStatus
== WGFS_Normal
&& l_bSkipNormalDirs
)
291 // output format: "D status pathname"
294 fputc(GetStatusChar(dir
->nStatus
), stdout
);
296 fputs(lpszPathName
, stdout
);
302 static BOOL
enum_dirs(struct DirStatus
*dir
, LPSTR sPathNameBuf
)
304 const int len
= strlen(dir
->lpszName
);
305 memcpy(sPathNameBuf
, dir
->lpszName
, len
);
309 if ( enum_dir(dir
, l_bFullPath
? l_sFullPathBuf
: l_sFullPathBuf
+prefix_offset
) )
312 if (!l_bNoRecurse
&& dir
->children
)
316 *sPathNameBuf
++ = '/';
323 if ( enum_dirs(dir
, sPathNameBuf
) )
334 static struct DirStatus
* GetSubDir(struct DirStatus
*dir
, LPCSTR lpszName
, int nNameLenInclTerminator
)
336 // check for cached access
337 if (dir
->pLastAccessedChild
338 && !strcmp(dir
->pLastAccessedChild
->lpszName
, lpszName
))
340 return dir
->pLastAccessedChild
;
344 struct DirStatus
*p
= dir
->children
;
345 struct DirStatus
*last
= NULL
;
348 if ( !strcmp(p
->lpszName
, lpszName
) )
349 return (dir
->pLastAccessedChild
= p
);
355 // dir not accessed before, create new entry
356 // TODO: do more efficient allocator (allocate larger pools, they can still be fire and forget and let our garbage collector clean up)
357 p
= dir
->pLastAccessedChild
= (struct DirStatus
*) malloc(sizeof(struct DirStatus
) + ((nNameLenInclTerminator
+3)&~3));
359 p
->pLastAccessedChild
= NULL
;
360 p
->lpszName
= (char*)p
+ sizeof(struct DirStatus
);
364 if (l_nEmptyDirStatus
!= WGFS_Ignored
)
366 p
->bExplicitlyIgnored
= dir
->bExplicitlyIgnored
;
367 p
->nStatus
= (p
->bExplicitlyIgnored
&& l_nEmptyDirStatus
< WGFS_Ignored
) ? WGFS_Ignored
: l_nEmptyDirStatus
;
371 p
->nStatus
= WGFS_Ignored
;
372 p
->bExplicitlyIgnored
= TRUE
;
382 memcpy((char*)p
->lpszName
, lpszName
, nNameLenInclTerminator
);
388 static inline BOOL
IsStatusRelevantForDirs(int nStatus
)
390 return nStatus
>= l_nMinStatusRelevantForDirs
&& nStatus
!= WGFS_Deleted
;
394 static void update_dirs_unversioned_rec(LPCSTR lpszFileName
, UINT nDirLen
, struct dir_entry
*ce
, struct DirStatus
*parentDir
)
396 const int nDirLen1
= nDirLen
+1;
398 memcpy(s
, lpszFileName
, nDirLen
);
401 struct DirStatus
*dir
= GetSubDir(parentDir
, s
, nDirLen1
);
402 //ASSERT(dir != NULL);
404 if (dir
->nStatus
>= WGFS_Conflicted
&& l_bNoRecurse
)
406 // no further processing needed
410 // process next subdir in lpszFileName
412 lpszFileName
+= nDirLen1
;
414 LPCSTR p
= strchr(lpszFileName
, '/');
417 // no more dirs in pathname (ie we are in the dir the file is located)
419 if (l_nEmptyDirStatus
== WGFS_Unknown
)
420 // only want dirs enumerated without recursive status
423 const int nFileStatus
= l_nLastStatus
;
425 if (nFileStatus
> dir
->nStatus
)
427 // update status on dir and all parents
430 if (nFileStatus
> dir
->nStatus
)
431 dir
->nStatus
= nFileStatus
;
433 while ( (dir
= dir
->parent
) );
436 else if (lpszFileName
!= p
) // quick check to make sure we're not left with a "/" filename
438 update_dirs_unversioned_rec(lpszFileName
, (UINT
)(p
-lpszFileName
), ce
, dir
);
442 static void update_dirs_unversioned(struct dir_entry
*ce
, int nPathNameOffset
)
444 // filename relative to enumerated path
445 LPCSTR lpszFileName
= ce
->name
+ nPathNameOffset
;
447 LPCSTR p
= strchr(lpszFileName
, '/');
448 if (p
<= lpszFileName
)
450 // file is not in sub-dir
452 if (l_nEmptyDirStatus
== WGFS_Unknown
)
453 // only want dirst enumerated without recursive status
456 const int nFileStatus
= l_nLastStatus
;
458 if (nFileStatus
> l_dirTree
.nStatus
)
459 l_dirTree
.nStatus
= nFileStatus
;
464 if (!l_bNoRecurseDir
)
466 update_dirs_unversioned_rec(lpszFileName
, (UINT
)(p
-lpszFileName
), ce
, &l_dirTree
);
471 static void update_dirs_rec(LPCSTR lpszFileName
, UINT nDirLen
, struct cache_entry
*ce
, BOOL bStatusCached
, struct DirStatus
*parentDir
)
473 const int nDirLen1
= nDirLen
+1;
475 memcpy(s
, lpszFileName
, nDirLen
);
478 struct DirStatus
*dir
= GetSubDir(parentDir
, s
, nDirLen1
);
479 //ASSERT(dir != NULL);
481 if (dir
->nStatus
>= WGFS_Conflicted
&& l_bNoRecurse
)
483 // no further processing needed
487 // process next subdir in lpszFileName
489 lpszFileName
+= nDirLen1
;
491 LPCSTR p
= strchr(lpszFileName
, '/');
494 // no more dirs in pathname (ie we are in the dir the file is located)
496 if (l_nEmptyDirStatus
== WGFS_Unknown
)
497 // only want dirst enumerated without recursive status
502 // file status not determined yet, do it now
504 int err
= lstat(ce
->name
, &st
);
505 if (!process_ce_entry_status(ce
, err
? NULL
: &st
) || !IsStatusRelevantForDirs(l_nLastStatus
))
508 const int nFileStatus
= l_nLastStatus
;
510 if (nFileStatus
> dir
->nStatus
)
512 // update status on dir and all parents
515 if (nFileStatus
> dir
->nStatus
)
516 dir
->nStatus
= nFileStatus
;
518 while ( (dir
= dir
->parent
) );
521 else if (lpszFileName
!= p
) // quick check to make sure we're not left with a "/" filename
523 update_dirs_rec(lpszFileName
, (UINT
)(p
-lpszFileName
), ce
, bStatusCached
, dir
);
527 static void update_dirs(struct cache_entry
*ce
, int nPathNameOffset
, BOOL bStatusCached
)
529 // filename relative to enumerated path
530 LPCSTR lpszFileName
= ce
->name
+ nPathNameOffset
;
532 LPCSTR p
= strchr(lpszFileName
, '/');
533 if (p
<= lpszFileName
)
535 // file is not in sub-dir
537 if (l_nEmptyDirStatus
== WGFS_Unknown
)
538 // only want dirs enumerated without recursive status
543 // file status not determined yet, do it now
545 int err
= lstat(ce
->name
, &st
);
546 if (!process_ce_entry_status(ce
, err
? NULL
: &st
) || !IsStatusRelevantForDirs(l_nLastStatus
))
549 const int nFileStatus
= l_nLastStatus
;
551 if (nFileStatus
> l_dirTree
.nStatus
)
552 l_dirTree
.nStatus
= nFileStatus
;
557 if (!l_bNoRecurseDir
)
559 update_dirs_rec(lpszFileName
, (UINT
)(p
-lpszFileName
), ce
, bStatusCached
, &l_dirTree
);
564 static inline BOOL
is_subpath(const char *sPath
, int nPathLen
, const char *sFile
)
566 return strchr(sFile
+ nPathLen
, '/') != NULL
;
569 static BOOL
is_dir(const char *sProjectPath
, const char *sSubPath
)
573 strcpy(s
, sProjectPath
);
582 // make sure it ends with a slash
586 // backslashify sub-path
595 int err
= lstat(s
, &st
);
597 return (!err
&& S_ISDIR(st
.st_mode
));
600 static inline BOOL
is_ce_name_eq(struct cache_entry
*ce1
, struct cache_entry
*ce2
)
602 const size_t len1
= ce1
->ce_flags
& CE_NAMEMASK
;
603 const size_t len2
= ce2
->ce_flags
& CE_NAMEMASK
;
605 return (len1
== len2
) ? !strcmp(ce1
->name
, ce2
->name
) : FALSE
;
609 struct oneway_unpack_data
{
610 struct rev_info
*revs
;
611 char symcache
[PATH_MAX
];
614 // modified version of function in diff-lib.c
615 static void do_oneway_diff(struct unpack_trees_options
*o
, struct cache_entry
*idx
, struct cache_entry
*tree
)
621 // file has no previous commit, newly added
622 idx
->ce_flags
|= CE_IG_ADDED
;
627 // file only in previous commit, deleted
628 tree
->ce_flags
|= CE_IG_DELETED
;
631 else if (!(idx
->ce_flags
& CE_INTENT_TO_ADD
)
632 && hashcmp(tree
->sha1
, idx
->sha1
) && !is_null_sha1(idx
->sha1
))
634 // file modified and in both indices, staged
635 idx
->ce_flags
|= CE_IG_STAGED
;
639 // function taken from diff-lib.c
640 static inline void skip_same_name(struct cache_entry
*ce
, struct unpack_trees_options
*o
)
642 int len
= ce_namelen(ce
);
643 const struct index_state
*index
= o
->src_index
;
645 while (o
->pos
< index
->cache_nr
) {
646 struct cache_entry
*next
= index
->cache
[o
->pos
];
647 if (len
!= ce_namelen(next
))
649 if (memcmp(ce
->name
, next
->name
, len
))
655 // function taken from diff-lib.c
656 static int oneway_diff(struct cache_entry
**src
, struct unpack_trees_options
*o
)
658 struct cache_entry
*idx
= src
[0];
659 struct cache_entry
*tree
= src
[1];
660 struct oneway_unpack_data
*cbdata
= o
->unpack_data
;
661 struct rev_info
*revs
= cbdata
->revs
;
663 if (idx
&& ce_stage(idx
))
664 skip_same_name(idx
, o
);
667 * Unpack-trees generates a DF/conflict entry if
668 * there was a directory in the index and a tree
669 * in the tree. From a diff standpoint, that's a
670 * delete of the tree and a create of the file.
672 if (tree
== o
->df_conflict_entry
)
675 if (ce_path_match(idx
? idx
: tree
, revs
->prune_data
))
676 do_oneway_diff(o
, idx
, tree
);
681 static int dummy_diff(struct cache_entry
**src
, struct unpack_trees_options
*o
)
687 * This turns all merge entries into "stage 3". That guarantees that
688 * when we read in the new tree (into "stage 1"), we won't lose sight
689 * of the fact that we had unmerged entries.
691 static void mark_merge_entries(void)
694 for (i
= 0; i
< active_nr
; i
++) {
695 struct cache_entry
*ce
= active_cache
[i
];
698 ce
->ce_flags
|= CE_STAGEMASK
;
702 static void preprocess_index(struct rev_info
*revs
)
704 // compare current index with index from last commit to detect staged and newly added files
706 struct unpack_trees_options opts
;
707 struct index_state old_index
= { 0 };
709 char filename
[MAX_PATH
];
710 unsigned char cursha1
[20+12];
712 if (l_bEnableIndexCache
)
715 // load cached index if valid
718 if ( get_sha1("HEAD", cursha1
) )
719 die("Could not resolve SHA1 of HEAD");
721 sprintf(filename
, "%s_cached.igit", get_index_file());
723 fd
= open(filename
, O_RDONLY
);
727 // check if cached file contains desired revision
729 // NOTE: the cache file header is 32 bytes, where the first 20 bytes is the SHA1 of the cached revision
730 // the remaining 12 bytes are for future use
732 unsigned char sha1
[20+12];
733 BOOL res
= (read(fd
, sha1
, 32) == 32);
736 if (res
&& !hashcmp(cursha1
, sha1
))
738 // cached index is valid, read it
739 read_index_from_ex(&old_index
, filename
, 32);
746 // based on run_diff_index()
749 // build old_index (and save to cached file)
753 const char *tree_name
;
755 struct oneway_unpack_data unpack_cb
;
757 if (!l_bEnableIndexCache
)
758 mark_merge_entries();
760 ent
= revs
->pending
.objects
[0].item
;
761 tree_name
= revs
->pending
.objects
[0].name
;
762 tree
= parse_tree_indirect(ent
->sha1
);
767 unpack_cb
.revs
= revs
;
768 unpack_cb
.symcache
[0] = '\0';
769 memset(&opts
, 0, sizeof(opts
));
772 if (!l_bEnableIndexCache
)
775 opts
.fn
= oneway_diff
;
776 opts
.src_index
= &the_index
;
777 opts
.dst_index
= NULL
;
782 opts
.fn
= dummy_diff
;
783 opts
.src_index
= NULL
;
784 opts
.dst_index
= &old_index
;
786 opts
.unpack_data
= &unpack_cb
;
788 init_tree_desc(&t
, tree
->buffer
, tree
->size
);
790 if ( unpack_trees(1, &t
, &opts
) )
794 if (l_bEnableIndexCache
)
796 fd
= open(filename
, O_WRONLY
| O_CREAT
, 0666);
798 memset(cursha1
+20, 0, 12);
799 write(fd
, cursha1
, 32);
801 if (fd
< 0 || write_index(&old_index
, fd
) || close(fd
))
802 die("Could not write cached index to %s", filename
);
805 // merge/diff old index with current index
810 mark_merge_entries();
812 memset(&opts
, 0, sizeof(opts
));
816 opts
.fn
= dummy_diff
;
817 opts
.unpack_data
= &unpack_cb
;
818 opts
.src_index
= NULL
;
819 opts
.dst_index
= &old_index
;
823 for (; i
<active_nr
&& j
<old_index
.cache_nr
;)
825 struct cache_entry
*ce
= active_cache
[i
];
826 struct cache_entry
*oldce
= old_index
.cache
[j
];
828 int len
= ce_namelen(ce
);
829 int oldlen
= ce_namelen(oldce
);
831 int cmp
= df_name_compare(
832 ce
->name
, len
, ce
->ce_mode
,
833 oldce
->name
, oldlen
, oldce
->ce_mode
);
837 // new entry is bigger than the old one (old file has been deleted)
838 do_oneway_diff(&opts
, NULL
, oldce
);
844 // new entry is smaller than the old one (newly added file)
845 do_oneway_diff(&opts
, ce
, NULL
);
851 do_oneway_diff(&opts
, ce
, oldce
);
853 // skip consecutive unmerged entries
857 for (k
=i
+1; k
<active_nr
; k
++)
859 if ( !is_ce_name_eq(ce
, active_cache
[k
]) )
870 // process remaining entries (should there be any)
871 for (; i
<active_nr
; i
++)
873 struct cache_entry
*ce
= active_cache
[i
];
876 do_oneway_diff(&opts
, ce
, NULL
);
878 // skip consecutive unmerged entries
882 for (k
=i
+1; k
<active_nr
; k
++)
884 if ( !is_ce_name_eq(ce
, active_cache
[k
]) )
890 for (; j
<old_index
.cache_nr
; j
++)
892 // old file has been deleted
893 do_oneway_diff(&opts
, NULL
, old_index
.cache
[j
]);
897 // add deleted files to index (easier for enumeration functions to process)
900 struct EntryRef
*p
= l_delQueue
;
904 // only add file for enumeration if they still exist
906 if ( lstat(p
->ce
->name
, &st
) )
908 struct cache_entry
*ce
= make_cache_entry(p
->ce
->ce_mode
, null_sha1
, p
->ce
->name
, 0, 0);
910 add_index_entry(&the_index
, ce
, ADD_CACHE_OK_TO_ADD
|ADD_CACHE_SKIP_DFCHECK
|ADD_CACHE_NEW_ONLY
);
911 ce
->ce_flags
&= ~CE_ADDED
;
912 ce
->ce_flags
|= CE_IG_DELETED
;
915 struct EntryRef
*q
= p
;
924 if (l_bEnableIndexCache
)
925 discard_index(&old_index
);
929 static struct object
*get_reference(struct rev_info
*revs
, const char *name
, const unsigned char *sha1
, unsigned int flags
)
931 struct object
*object
;
933 object
= parse_object(sha1
);
935 return NULL
;//die("bad object %s", name);
936 object
->flags
|= flags
;
940 static int add_pending_object_with_mode(struct rev_info
*revs
, struct object
*obj
, const char *name
, unsigned mode
)
942 if (revs
->no_walk
&& (obj
->flags
& UNINTERESTING
))
943 return 1;//die("object ranges do not make sense when not walking revisions");
944 if (revs
->reflog_info
&& obj
->type
== OBJ_COMMIT
945 && add_reflog_for_walk(revs
->reflog_info
, (struct commit
*)obj
, name
))
947 add_object_array_with_mode(obj
, name
, &revs
->pending
, mode
);
951 static int setup_revisions_lite(struct rev_info
*revs
, const char *def
)
953 if (revs
->def
== NULL
)
955 if (revs
->def
&& !revs
->pending
.nr
) {
956 unsigned char sha1
[20];
957 struct object
*object
;
959 if (get_sha1_with_mode(revs
->def
, sha1
, &mode
))
960 return 1;//die("bad default revision '%s'", revs->def);
961 object
= get_reference(revs
, revs
->def
, sha1
, 0);
964 if ( add_pending_object_with_mode(revs
, object
, revs
->def
, mode
) )
968 /* Did the user ask for any diff output? Run the diff! */
969 if (revs
->diffopt
.output_format
& ~DIFF_FORMAT_NO_OUTPUT
)
972 /* Pickaxe, diff-filter and rename following need diffs */
973 if (revs
->diffopt
.pickaxe
||
974 revs
->diffopt
.filter
||
975 DIFF_OPT_TST(&revs
->diffopt
, FOLLOW_RENAMES
))
978 if (revs
->topo_order
)
981 if (revs
->prune_data
) {
982 diff_tree_setup_paths(revs
->prune_data
, &revs
->pruning
);
983 /* Can't prune commits with rename following: the paths change.. */
984 if (!DIFF_OPT_TST(&revs
->diffopt
, FOLLOW_RENAMES
))
986 if (!revs
->full_diff
)
987 diff_tree_setup_paths(revs
->prune_data
, &revs
->diffopt
);
989 if (revs
->combine_merges
) {
990 revs
->ignore_merges
= 0;
991 if (revs
->dense_combined_merges
&& !revs
->diffopt
.output_format
)
992 revs
->diffopt
.output_format
= DIFF_FORMAT_PATCH
;
994 revs
->diffopt
.abbrev
= revs
->abbrev
;
995 if (diff_setup_done(&revs
->diffopt
) < 0)
996 return 4;//die("diff_setup_done failed");
998 compile_grep_patterns(&revs
->grep_filter
);
1000 /*if (revs->reverse && revs->reflog_info)
1001 die("cannot combine --reverse with --walk-reflogs");
1002 if (revs->rewrite_parents && revs->children.name)
1003 die("cannot combine --parents and --children");*/
1006 * Limitations on the graph functionality
1008 /*if (revs->reverse && revs->graph)
1009 die("cannot combine --reverse with --graph");
1011 if (revs->reflog_info && revs->graph)
1012 die("cannot combine --walk-reflogs with --graph");*/
1019 BOOL
ig_enum_files(const char *pszProjectPath
, const char *pszSubPath
, const char *prefix
, unsigned int nFlags
)
1021 // reset all local vars of builtin-ls-files.c to default
1031 line_terminator
= '\n';
1045 if (nFlags
& WGEFF_NoCacheIndex
)
1046 l_bEnableIndexCache
= FALSE
;
1048 const BOOL bSubDir
= pszSubPath
&& is_dir(pszProjectPath
, pszSubPath
);
1050 LPCSTR pszSubPathSpec
= pszSubPath
;
1051 if (bSubDir
&& !(nFlags
& WGEFF_SingleFile
))
1053 int len
= strlen(pszSubPath
);
1054 char *s
= (char*)malloc(len
+3);
1055 strcpy(s
, pszSubPath
);
1056 strcpy(s
+len
, "/*");
1061 //int exc_given = 0, require_work_tree = 0;
1062 struct dir_struct _dir
;
1064 memset(&_dir
, 0, sizeof(_dir
));
1066 memset(&l_dirTree
, 0, sizeof(l_dirTree
));
1067 l_dirTree
.nStatus
= WGFS_Normal
; // root dir is always at least WGFS_Normal even if empty
1068 if (pszSubPath
&& !(nFlags
& WGEFF_EmptyAsNormal
))
1069 l_dirTree
.nStatus
= WGFS_Empty
;
1071 // NOTE: to force names to be relative to project root dir (no mater what current dir is) set prefix_offset to 0
1073 prefix_offset
= strlen(prefix
);
1074 git_config(git_default_config
, NULL
);
1076 struct dir_struct
*dir
= &_dir
;
1078 const char *argv
[2];
1079 argv
[0] = pszSubPathSpec
;
1082 if (/*require_work_tree &&*/ !is_inside_work_tree())
1085 pathspec
= get_pathspec(prefix
, argv
);
1087 // TODO: in ls-files from v1.6.2 read_cache call was moved up here, not sure if that is needed or works correctly here
1090 // Verify that the pathspec matches the prefix
1092 prefix
= verify_pathspec(prefix
);
1094 // Treat unmatching pathspec elements as errors
1095 if (pathspec
&& error_unmatch
)
1098 for (num
= 0; pathspec
[num
]; num
++)
1100 ps_matched
= xcalloc(1, num
);
1103 // vars used for path recursion check
1104 int pathspec_len
= 0;
1105 if (pathspec
&& *pathspec
)
1107 // calc length of pathspec plus 1 for a / (unless it already ends with a slash)
1108 pathspec_len
= strlen(*pathspec
);
1109 if ((*pathspec
)[pathspec_len
-1] == '*')
1111 if ((*pathspec
)[pathspec_len
-1] != '/')
1114 const char *refpath
= (pathspec
&& *pathspec
) ? *pathspec
: "";
1120 l_bNoRecurseDir
= FALSE
;
1122 BOOL single_dir
= (nFlags
& WGEFF_SingleFile
) && (!pszSubPath
|| bSubDir
);
1123 // adjust other flags for best performance / correct results when WGEFF_SingleFile is set
1124 if (single_dir
&& (nFlags
& WGEFF_NoRecurse
))
1125 l_bNoRecurseDir
= TRUE
;
1126 if (nFlags
& WGEFF_SingleFile
)
1128 nFlags
|= WGEFF_NoRecurse
;
1130 nFlags
&= ~(WGEFF_DirStatusAll
|WGEFF_DirStatusDelta
);
1134 nFlags
= (nFlags
& ~WGEFF_DirStatusAll
) | WGEFF_DirStatusDelta
;
1136 if ( !(nFlags
& WGEFF_EmptyAsNormal
) )
1137 l_dirTree
.nStatus
= WGFS_Empty
;
1140 BOOL no_recurse
= nFlags
& WGEFF_NoRecurse
;
1141 l_bNoRecurse
= no_recurse
;
1142 l_bFullPath
= nFlags
& WGEFF_FullPath
;
1143 l_bDirStatus
= nFlags
& (WGEFF_DirStatusDelta
|WGEFF_DirStatusAll
);
1145 // when all dirs should be enumerated we need IsStatusRelevantForDirs to report files of any status as relevant
1146 // otherwise only above normal are considered, which is slightly more efficient
1147 l_nMinStatusRelevantForDirs
= (nFlags
& WGEFF_DirStatusAll
) ? WGFS_Empty
: (WGFS_Normal
+1);
1149 // initial status of dirs
1150 l_nEmptyDirStatus
= (nFlags
& WGEFF_EmptyAsNormal
) ? WGFS_Normal
: WGFS_Empty
;
1152 l_bSkipNormalDirs
= ((nFlags
& (WGEFF_DirStatusDelta
|WGEFF_DirStatusAll
)) == WGEFF_DirStatusDelta
);
1154 if (!(nFlags
& WGEFF_SingleFile
) && !l_bDirStatus
)
1156 // no recursive dir status requested, list all dirs as unknown
1157 l_bDirStatus
= TRUE
;
1158 l_nEmptyDirStatus
= l_nMinStatusRelevantForDirs
= WGFS_Unknown
;
1159 l_bSkipNormalDirs
= FALSE
;
1160 l_dirTree
.nStatus
= WGFS_Unknown
;
1163 *l_sFullPathBuf
= 0;
1164 l_lpszFileName
= NULL
;
1167 strcpy(l_sFullPathBuf
, pszProjectPath
);
1169 LPSTR q
= l_sFullPathBuf
;
1176 // make sure it ends with a slash
1182 // save pointer to where file paths, with project-relative names, can be concatenated
1186 // shouldn't have any effect but set them to reflect what we want listed
1192 struct rev_info rev
;
1193 init_revisions(&rev
, prefix
);
1194 rev
.ignore_merges
= 0;
1197 l_bHasHistory
= !setup_revisions_lite(&rev
, "HEAD");
1201 preprocess_index(&rev
);
1203 prune_cache(prefix
);
1205 //if (pathspec && *pathspec) OutputDebugString(*pathspec);OutputDebugString(" (1)\r\n");
1206 //if (prefix) OutputDebugString(prefix);OutputDebugString(" (2)\r\n");
1212 for (i
=0; i
<active_nr
; i
++)
1214 struct cache_entry
*ce
= active_cache
[i
];
1218 int dtype
= ce_to_dtype(ce
);
1220 if (excluded(dir
, ce
->name
, &dtype
) != !!(dir
->flags
& DIR_SHOW_IGNORED
))
1222 if (ce
->ce_flags
& CE_UPDATE
)
1225 // skip file if not inside specified sub-path
1226 // this test was originally done in enum_ce_entry but in order to avoid unecessery lstat calls it was moved
1227 if (prefix_len
>= ce_namelen(ce
))
1228 die("git ls-files: internal error - cache entry not superset of prefix");
1229 if (pathspec
&& !match_pathspec(pathspec
, ce
->name
, ce_namelen(ce
), prefix_len
, ps_matched
))
1232 if (single_dir
|| (no_recurse
&& is_subpath(refpath
, pathspec_len
, ce
->name
)))
1235 // this file would normally be skipped, but in order to determine correct dir status we need to process it
1236 update_dirs(ce
, pathspec_len
, FALSE
);
1241 err
= (ce
->ce_flags
& CE_IG_DELETED
) ? 1 : lstat(ce
->name
, &st
);
1243 if ( enum_ce_entry(ce
, err
? NULL
: &st
) )
1246 // normally (always?) conflicted/unmerged files will have 3 entries in a row (one in stage 1, one in 2 and one in 3)
1247 // skip redundant entries here
1252 for (j
=i
+1; j
<active_nr
; j
++)
1254 struct cache_entry
*nextce
= active_cache
[j
];
1256 if ( !is_ce_name_eq(ce
, nextce
) )
1263 if (l_bDirStatus
&& IsStatusRelevantForDirs(l_nLastStatus
))
1264 update_dirs(ce
, pathspec_len
, TRUE
);
1267 BOOL bIgnoreInitialized
= FALSE
;
1271 // check if root (pszSubPath) dir is ignored
1273 if (!bIgnoreInitialized
)
1276 setup_standard_excludes(dir
);
1277 bIgnoreInitialized
= TRUE
;
1280 char sDir
[MAX_PATH
];
1281 strcpy(sDir
, pszSubPath
);
1282 LPSTR p
= strrchr(sDir
, '/');
1286 // check for matching ignore for each subdir level
1287 p
= strchr(sDir
, '/');
1293 if ( excluded(dir
, sDir
, &dtype
) )
1295 l_dirTree
.nStatus
= WGFS_Ignored
;
1296 l_dirTree
.bExplicitlyIgnored
= TRUE
;
1302 p
= strchr(p
+1, '/');
1313 // enumerate unversioned files
1314 if ( !(nFlags
& WGEFF_SingleFile
) )
1316 const char *path
= ".", *base
= "";
1317 int baselen
= prefix_len
;
1320 path
= base
= prefix
;
1322 if (!bIgnoreInitialized
)
1325 setup_standard_excludes(dir
);
1326 bIgnoreInitialized
= TRUE
;
1328 dir
->flags
|= DIR_COLLECT_IGNORED
;
1329 dir
->flags
&= ~DIR_SHOW_IGNORED
;
1330 dir
->flags
&= ~DIR_SHOW_OTHER_DIRECTORIES
;
1331 dir
->flags
&= ~DIR_HIDE_EMPTY_DIRECTORIES
;
1332 dir
->flags
|= DIR_COLLECT_ALL_IGNORED
;
1333 dir
->flags
|= DIR_COLLECT_DIRECTORIES
;
1335 dir
->flags
|= DIR_NO_RECURSE_READDIR
;
1337 dir
->flags
&= ~DIR_NO_RECURSE_READDIR
;
1338 read_directory(dir
, path
, base
, baselen
, pathspec
);
1340 // if root dir is ignored, then all unversioned files under it are considered ignore
1341 enum_unversioned(dir
->entries
, dir
->nr
, l_dirTree
.bExplicitlyIgnored
);
1342 enum_unversioned(dir
->ignored
, dir
->ignored_nr
, TRUE
);
1344 else if (!single_dir
&& !l_nEnumeratedCached
)
1346 // get status of a single unversioned file
1348 if (!bIgnoreInitialized
)
1351 setup_standard_excludes(dir
);
1352 bIgnoreInitialized
= TRUE
;
1359 sFileName
= pszSubPath
+ prefix_offset
;
1363 strcpy(l_lpszFileName
, pszSubPath
);
1364 sFileName
= l_sFullPathBuf
;
1368 // if root dir is ignored, then all unversioned files under it are considered ignore
1369 if (!l_dirTree
.bExplicitlyIgnored
&& excluded(dir
, pszSubPath
, &dtype
))
1370 fputs("F I 0000000000000000000000000000000000000000 ", stdout
);
1372 fputs("F U 0000000000000000000000000000000000000000 ", stdout
);
1373 fputs(sFileName
, stdout
);
1381 LPCSTR lpszRootDir
="/";
1384 lpszRootDir
= l_sFullPathBuf
;
1387 strcpy(l_lpszFileName
, *pathspec
);
1388 l_lpszFileName
+= pathspec_len
;
1391 *l_lpszFileName
= 0;
1392 // remove trailng slash
1393 l_lpszFileName
[-1] = 0;
1395 else if (pathspec_len
)
1399 strcpy(l_sFullPathBuf
, *pathspec
);
1400 l_sFullPathBuf
[pathspec_len
-1] = '/';
1401 l_sFullPathBuf
[pathspec_len
] = 0;
1402 l_lpszFileName
= l_sFullPathBuf
;
1408 l_lpszFileName
= l_sFullPathBuf
;
1413 // enumerate single dir
1414 l_bSkipNormalDirs
= FALSE
;
1415 enum_dir(&l_dirTree
, lpszRootDir
);
1417 else if (!enum_dir(&l_dirTree
, lpszRootDir
) && l_dirTree
.children
)
1420 // re-add trailing slash
1421 l_lpszFileName
[-1] = '/';
1423 struct DirStatus
*p
= l_dirTree
.children
;
1427 if ( enum_dirs(p
, l_lpszFileName
) )
1430 while ( (p
= p
->next
) );