1 /*
2  * Copyright (C) the libgit2 contributors. All rights reserved.
3  *
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.
6  */
7 #ifndef INCLUDE_git_status_h__
8 #define INCLUDE_git_status_h__
9 
10 #include "common.h"
11 #include "types.h"
12 #include "strarray.h"
13 #include "diff.h"
14 
15 /**
16  * @file git2/status.h
17  * @brief Git file status routines
18  * @defgroup git_status Git file status routines
19  * @ingroup Git
20  * @{
21  */
22 GIT_BEGIN_DECL
23 
24 /**
25  * Status flags for a single file.
26  *
27  * A combination of these values will be returned to indicate the status of
28  * a file.  Status compares the working directory, the index, and the
29  * current HEAD of the repository.  The `GIT_STATUS_INDEX` set of flags
30  * represents the status of file in the index relative to the HEAD, and the
31  * `GIT_STATUS_WT` set of flags represent the status of the file in the
32  * working directory relative to the index.
33  */
34 typedef enum {
35 	GIT_STATUS_CURRENT = 0,
36 
37 	GIT_STATUS_INDEX_NEW        = (1u << 0),
38 	GIT_STATUS_INDEX_MODIFIED   = (1u << 1),
39 	GIT_STATUS_INDEX_DELETED    = (1u << 2),
40 	GIT_STATUS_INDEX_RENAMED    = (1u << 3),
41 	GIT_STATUS_INDEX_TYPECHANGE = (1u << 4),
42 
43 	GIT_STATUS_WT_NEW           = (1u << 7),
44 	GIT_STATUS_WT_MODIFIED      = (1u << 8),
45 	GIT_STATUS_WT_DELETED       = (1u << 9),
46 	GIT_STATUS_WT_TYPECHANGE    = (1u << 10),
47 	GIT_STATUS_WT_RENAMED       = (1u << 11),
48 	GIT_STATUS_WT_UNREADABLE    = (1u << 12),
49 
50 	GIT_STATUS_IGNORED          = (1u << 14),
51 	GIT_STATUS_CONFLICTED       = (1u << 15),
52 } git_status_t;
53 
54 /**
55  * Function pointer to receive status on individual files
56  *
57  * `path` is the relative path to the file from the root of the repository.
58  *
59  * `status_flags` is a combination of `git_status_t` values that apply.
60  *
61  * `payload` is the value you passed to the foreach function as payload.
62  */
63 typedef int GIT_CALLBACK(git_status_cb)(
64 	const char *path, unsigned int status_flags, void *payload);
65 
66 /**
67  * Select the files on which to report status.
68  *
69  * With `git_status_foreach_ext`, this will control which changes get
70  * callbacks.  With `git_status_list_new`, these will control which
71  * changes are included in the list.
72  *
73  * - GIT_STATUS_SHOW_INDEX_AND_WORKDIR is the default.  This roughly
74  *   matches `git status --porcelain` regarding which files are
75  *   included and in what order.
76  * - GIT_STATUS_SHOW_INDEX_ONLY only gives status based on HEAD to index
77  *   comparison, not looking at working directory changes.
78  * - GIT_STATUS_SHOW_WORKDIR_ONLY only gives status based on index to
79  *   working directory comparison, not comparing the index to the HEAD.
80  */
81 typedef enum {
82 	GIT_STATUS_SHOW_INDEX_AND_WORKDIR = 0,
83 	GIT_STATUS_SHOW_INDEX_ONLY = 1,
84 	GIT_STATUS_SHOW_WORKDIR_ONLY = 2,
85 } git_status_show_t;
86 
87 /**
88  * Flags to control status callbacks
89  *
90  * - GIT_STATUS_OPT_INCLUDE_UNTRACKED says that callbacks should be made
91  *   on untracked files.  These will only be made if the workdir files are
92  *   included in the status "show" option.
93  * - GIT_STATUS_OPT_INCLUDE_IGNORED says that ignored files get callbacks.
94  *   Again, these callbacks will only be made if the workdir files are
95  *   included in the status "show" option.
96  * - GIT_STATUS_OPT_INCLUDE_UNMODIFIED indicates that callback should be
97  *   made even on unmodified files.
98  * - GIT_STATUS_OPT_EXCLUDE_SUBMODULES indicates that submodules should be
99  *   skipped.  This only applies if there are no pending typechanges to
100  *   the submodule (either from or to another type).
101  * - GIT_STATUS_OPT_RECURSE_UNTRACKED_DIRS indicates that all files in
102  *   untracked directories should be included.  Normally if an entire
103  *   directory is new, then just the top-level directory is included (with
104  *   a trailing slash on the entry name).  This flag says to include all
105  *   of the individual files in the directory instead.
106  * - GIT_STATUS_OPT_DISABLE_PATHSPEC_MATCH indicates that the given path
107  *   should be treated as a literal path, and not as a pathspec pattern.
108  * - GIT_STATUS_OPT_RECURSE_IGNORED_DIRS indicates that the contents of
109  *   ignored directories should be included in the status.  This is like
110  *   doing `git ls-files -o -i --exclude-standard` with core git.
111  * - GIT_STATUS_OPT_RENAMES_HEAD_TO_INDEX indicates that rename detection
112  *   should be processed between the head and the index and enables
113  *   the GIT_STATUS_INDEX_RENAMED as a possible status flag.
114  * - GIT_STATUS_OPT_RENAMES_INDEX_TO_WORKDIR indicates that rename
115  *   detection should be run between the index and the working directory
116  *   and enabled GIT_STATUS_WT_RENAMED as a possible status flag.
117  * - GIT_STATUS_OPT_SORT_CASE_SENSITIVELY overrides the native case
118  *   sensitivity for the file system and forces the output to be in
119  *   case-sensitive order
120  * - GIT_STATUS_OPT_SORT_CASE_INSENSITIVELY overrides the native case
121  *   sensitivity for the file system and forces the output to be in
122  *   case-insensitive order
123  * - GIT_STATUS_OPT_RENAMES_FROM_REWRITES indicates that rename detection
124  *   should include rewritten files
125  * - GIT_STATUS_OPT_NO_REFRESH bypasses the default status behavior of
126  *   doing a "soft" index reload (i.e. reloading the index data if the
127  *   file on disk has been modified outside libgit2).
128  * - GIT_STATUS_OPT_UPDATE_INDEX tells libgit2 to refresh the stat cache
129  *   in the index for files that are unchanged but have out of date stat
130  *   information in the index.  It will result in less work being done on
131  *   subsequent calls to get status.  This is mutually exclusive with the
132  *   NO_REFRESH option.
133  *
134  * Calling `git_status_foreach()` is like calling the extended version
135  * with: GIT_STATUS_OPT_INCLUDE_IGNORED, GIT_STATUS_OPT_INCLUDE_UNTRACKED,
136  * and GIT_STATUS_OPT_RECURSE_UNTRACKED_DIRS.  Those options are bundled
137  * together as `GIT_STATUS_OPT_DEFAULTS` if you want them as a baseline.
138  */
139 typedef enum {
140 	GIT_STATUS_OPT_INCLUDE_UNTRACKED                = (1u << 0),
141 	GIT_STATUS_OPT_INCLUDE_IGNORED                  = (1u << 1),
142 	GIT_STATUS_OPT_INCLUDE_UNMODIFIED               = (1u << 2),
143 	GIT_STATUS_OPT_EXCLUDE_SUBMODULES               = (1u << 3),
144 	GIT_STATUS_OPT_RECURSE_UNTRACKED_DIRS           = (1u << 4),
145 	GIT_STATUS_OPT_DISABLE_PATHSPEC_MATCH           = (1u << 5),
146 	GIT_STATUS_OPT_RECURSE_IGNORED_DIRS             = (1u << 6),
147 	GIT_STATUS_OPT_RENAMES_HEAD_TO_INDEX            = (1u << 7),
148 	GIT_STATUS_OPT_RENAMES_INDEX_TO_WORKDIR         = (1u << 8),
149 	GIT_STATUS_OPT_SORT_CASE_SENSITIVELY            = (1u << 9),
150 	GIT_STATUS_OPT_SORT_CASE_INSENSITIVELY          = (1u << 10),
151 	GIT_STATUS_OPT_RENAMES_FROM_REWRITES            = (1u << 11),
152 	GIT_STATUS_OPT_NO_REFRESH                       = (1u << 12),
153 	GIT_STATUS_OPT_UPDATE_INDEX                     = (1u << 13),
154 	GIT_STATUS_OPT_INCLUDE_UNREADABLE               = (1u << 14),
155 	GIT_STATUS_OPT_INCLUDE_UNREADABLE_AS_UNTRACKED  = (1u << 15),
156 } git_status_opt_t;
157 
158 #define GIT_STATUS_OPT_DEFAULTS \
159 	(GIT_STATUS_OPT_INCLUDE_IGNORED | \
160 	GIT_STATUS_OPT_INCLUDE_UNTRACKED | \
161 	GIT_STATUS_OPT_RECURSE_UNTRACKED_DIRS)
162 
163 /**
164  * Options to control how `git_status_foreach_ext()` will issue callbacks.
165  *
166  * Initialize with `GIT_STATUS_OPTIONS_INIT`. Alternatively, you can
167  * use `git_status_options_init`.
168  *
169  */
170 typedef struct {
171 	unsigned int      version; /**< The version */
172 
173 	/**
174 	 * The `show` value is one of the `git_status_show_t` constants that
175 	 * control which files to scan and in what order.
176 	 */
177 	git_status_show_t show;
178 
179 	/**
180 	 * The `flags` value is an OR'ed combination of the `git_status_opt_t`
181 	 * values above.
182 	 */
183 	unsigned int      flags;
184 
185 	/**
186 	 * The `pathspec` is an array of path patterns to match (using
187 	 * fnmatch-style matching), or just an array of paths to match exactly if
188 	 * `GIT_STATUS_OPT_DISABLE_PATHSPEC_MATCH` is specified in the flags.
189 	 */
190 	git_strarray      pathspec;
191 
192 	/**
193 	 * The `baseline` is the tree to be used for comparison to the working directory
194 	 * and index; defaults to HEAD.
195 	 */
196 	git_tree          *baseline;
197 } git_status_options;
198 
199 #define GIT_STATUS_OPTIONS_VERSION 1
200 #define GIT_STATUS_OPTIONS_INIT {GIT_STATUS_OPTIONS_VERSION}
201 
202 /**
203  * Initialize git_status_options structure
204  *
205  * Initializes a `git_status_options` with default values. Equivalent to
206  * creating an instance with `GIT_STATUS_OPTIONS_INIT`.
207  *
208  * @param opts The `git_status_options` struct to initialize.
209  * @param version The struct version; pass `GIT_STATUS_OPTIONS_VERSION`.
210  * @return Zero on success; -1 on failure.
211  */
212 GIT_EXTERN(int) git_status_options_init(
213 	git_status_options *opts,
214 	unsigned int version);
215 
216 /**
217  * A status entry, providing the differences between the file as it exists
218  * in HEAD and the index, and providing the differences between the index
219  * and the working directory.
220  *
221  * The `status` value provides the status flags for this file.
222  *
223  * The `head_to_index` value provides detailed information about the
224  * differences between the file in HEAD and the file in the index.
225  *
226  * The `index_to_workdir` value provides detailed information about the
227  * differences between the file in the index and the file in the
228  * working directory.
229  */
230 typedef struct {
231 	git_status_t status;
232 	git_diff_delta *head_to_index;
233 	git_diff_delta *index_to_workdir;
234 } git_status_entry;
235 
236 
237 /**
238  * Gather file statuses and run a callback for each one.
239  *
240  * The callback is passed the path of the file, the status (a combination of
241  * the `git_status_t` values above) and the `payload` data pointer passed
242  * into this function.
243  *
244  * If the callback returns a non-zero value, this function will stop looping
245  * and return that value to caller.
246  *
247  * @param repo A repository object
248  * @param callback The function to call on each file
249  * @param payload Pointer to pass through to callback function
250  * @return 0 on success, non-zero callback return value, or error code
251  */
252 GIT_EXTERN(int) git_status_foreach(
253 	git_repository *repo,
254 	git_status_cb callback,
255 	void *payload);
256 
257 /**
258  * Gather file status information and run callbacks as requested.
259  *
260  * This is an extended version of the `git_status_foreach()` API that
261  * allows for more granular control over which paths will be processed and
262  * in what order.  See the `git_status_options` structure for details
263  * about the additional controls that this makes available.
264  *
265  * Note that if a `pathspec` is given in the `git_status_options` to filter
266  * the status, then the results from rename detection (if you enable it) may
267  * not be accurate.  To do rename detection properly, this must be called
268  * with no `pathspec` so that all files can be considered.
269  *
270  * @param repo Repository object
271  * @param opts Status options structure
272  * @param callback The function to call on each file
273  * @param payload Pointer to pass through to callback function
274  * @return 0 on success, non-zero callback return value, or error code
275  */
276 GIT_EXTERN(int) git_status_foreach_ext(
277 	git_repository *repo,
278 	const git_status_options *opts,
279 	git_status_cb callback,
280 	void *payload);
281 
282 /**
283  * Get file status for a single file.
284  *
285  * This tries to get status for the filename that you give.  If no files
286  * match that name (in either the HEAD, index, or working directory), this
287  * returns GIT_ENOTFOUND.
288  *
289  * If the name matches multiple files (for example, if the `path` names a
290  * directory or if running on a case- insensitive filesystem and yet the
291  * HEAD has two entries that both match the path), then this returns
292  * GIT_EAMBIGUOUS because it cannot give correct results.
293  *
294  * This does not do any sort of rename detection.  Renames require a set of
295  * targets and because of the path filtering, there is not enough
296  * information to check renames correctly.  To check file status with rename
297  * detection, there is no choice but to do a full `git_status_list_new` and
298  * scan through looking for the path that you are interested in.
299  *
300  * @param status_flags Output combination of git_status_t values for file
301  * @param repo A repository object
302  * @param path The exact path to retrieve status for relative to the
303  * repository working directory
304  * @return 0 on success, GIT_ENOTFOUND if the file is not found in the HEAD,
305  *      index, and work tree, GIT_EAMBIGUOUS if `path` matches multiple files
306  *      or if it refers to a folder, and -1 on other errors.
307  */
308 GIT_EXTERN(int) git_status_file(
309 	unsigned int *status_flags,
310 	git_repository *repo,
311 	const char *path);
312 
313 /**
314  * Gather file status information and populate the `git_status_list`.
315  *
316  * Note that if a `pathspec` is given in the `git_status_options` to filter
317  * the status, then the results from rename detection (if you enable it) may
318  * not be accurate.  To do rename detection properly, this must be called
319  * with no `pathspec` so that all files can be considered.
320  *
321  * @param out Pointer to store the status results in
322  * @param repo Repository object
323  * @param opts Status options structure
324  * @return 0 on success or error code
325  */
326 GIT_EXTERN(int) git_status_list_new(
327 	git_status_list **out,
328 	git_repository *repo,
329 	const git_status_options *opts);
330 
331 /**
332  * Gets the count of status entries in this list.
333  *
334  * If there are no changes in status (at least according the options given
335  * when the status list was created), this can return 0.
336  *
337  * @param statuslist Existing status list object
338  * @return the number of status entries
339  */
340 GIT_EXTERN(size_t) git_status_list_entrycount(
341 	git_status_list *statuslist);
342 
343 /**
344  * Get a pointer to one of the entries in the status list.
345  *
346  * The entry is not modifiable and should not be freed.
347  *
348  * @param statuslist Existing status list object
349  * @param idx Position of the entry
350  * @return Pointer to the entry; NULL if out of bounds
351  */
352 GIT_EXTERN(const git_status_entry *) git_status_byindex(
353 	git_status_list *statuslist,
354 	size_t idx);
355 
356 /**
357  * Free an existing status list
358  *
359  * @param statuslist Existing status list object
360  */
361 GIT_EXTERN(void) git_status_list_free(
362 	git_status_list *statuslist);
363 
364 /**
365  * Test if the ignore rules apply to a given file.
366  *
367  * This function checks the ignore rules to see if they would apply to the
368  * given file.  This indicates if the file would be ignored regardless of
369  * whether the file is already in the index or committed to the repository.
370  *
371  * One way to think of this is if you were to do "git add ." on the
372  * directory containing the file, would it be added or not?
373  *
374  * @param ignored Boolean returning 0 if the file is not ignored, 1 if it is
375  * @param repo A repository object
376  * @param path The file to check ignores for, rooted at the repo's workdir.
377  * @return 0 if ignore rules could be processed for the file (regardless
378  *         of whether it exists or not), or an error < 0 if they could not.
379  */
380 GIT_EXTERN(int) git_status_should_ignore(
381 	int *ignored,
382 	git_repository *repo,
383 	const char *path);
384 
385 /** @} */
386 GIT_END_DECL
387 #endif
388