1 /* Copyright (c) 2006-2014 Jonas Fonseca <jonas.fonseca@gmail.com>
3 * This program is free software; you can redistribute it and/or
4 * modify it under the terms of the GNU General Public License as
5 * published by the Free Software Foundation; either version 2 of
6 * the License, or (at your option) any later version.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
17 #include "tig/refdb.h"
20 #define REPO_INFO_GIT_DIR "--git-dir"
21 #define REPO_INFO_WORK_TREE "--is-inside-work-tree"
22 #define REPO_INFO_SHOW_CDUP "--show-cdup"
23 #define REPO_INFO_SHOW_PREFIX "--show-prefix"
24 #define REPO_INFO_SYMBOLIC_HEAD "--symbolic-full-name"
25 #define REPO_INFO_RESOLVED_HEAD "HEAD"
27 struct repo_info_state
{
32 read_repo_info(char *name
, size_t namelen
, char *value
, size_t valuelen
, void *data
)
34 struct repo_info_state
*state
= data
;
35 const char *arg
= *state
->argv
? *state
->argv
++ : "";
37 if (!strcmp(arg
, REPO_INFO_GIT_DIR
)) {
38 string_ncopy(repo
.git_dir
, name
, namelen
);
40 } else if (!strcmp(arg
, REPO_INFO_WORK_TREE
)) {
41 /* This can be 3 different values depending on the
42 * version of git being used. If git-rev-parse does not
43 * understand --is-inside-work-tree it will simply echo
44 * the option else either "true" or "false" is printed.
45 * Default to true for the unknown case. */
46 repo
.is_inside_work_tree
= strcmp(name
, "false") ? TRUE
: FALSE
;
48 } else if (!strcmp(arg
, REPO_INFO_SHOW_CDUP
)) {
49 string_ncopy(repo
.cdup
, name
, namelen
);
51 } else if (!strcmp(arg
, REPO_INFO_SHOW_PREFIX
)) {
52 /* Some versions of Git does not emit anything for --show-prefix
53 * when the user is in the repository root directory. Try to detect
54 * this special case by looking at the emitted value. If it looks
55 * like a commit ID and there's no cdup path assume that no value
57 if (!*repo
.cdup
&& namelen
== 40 && iscommit(name
))
58 return read_repo_info(name
, namelen
, value
, valuelen
, data
);
60 string_ncopy(repo
.prefix
, name
, namelen
);
62 } else if (!strcmp(arg
, REPO_INFO_RESOLVED_HEAD
)) {
63 string_ncopy(repo
.head_id
, name
, namelen
);
65 } else if (!strcmp(arg
, REPO_INFO_SYMBOLIC_HEAD
)) {
66 if (!prefixcmp(name
, "refs/heads/")) {
67 add_ref(repo
.head_id
, name
, repo
.remote
, repo
.head
);
68 name
+= STRING_SIZE("refs/heads/");
70 string_ncopy(repo
.head
, name
, strlen(name
) + 1);
78 reload_repo_info(const char **rev_parse_argv
)
80 struct repo_info_state state
= { rev_parse_argv
+ 2 };
82 return io_run_load(rev_parse_argv
, "=", read_repo_info
, &state
);
88 const char *rev_parse_argv
[] = {
89 "git", "rev-parse", REPO_INFO_GIT_DIR
, REPO_INFO_WORK_TREE
,
90 REPO_INFO_SHOW_CDUP
, REPO_INFO_SHOW_PREFIX
, \
91 REPO_INFO_RESOLVED_HEAD
, REPO_INFO_SYMBOLIC_HEAD
, "HEAD",
95 return reload_repo_info(rev_parse_argv
);
101 const char *rev_parse_argv
[] = {
102 "git", "rev-parse", REPO_INFO_RESOLVED_HEAD
,
103 REPO_INFO_SYMBOLIC_HEAD
, "HEAD", NULL
106 return reload_repo_info(rev_parse_argv
);
109 struct repo_info repo
;
118 const char *update_index_argv
[] = {
119 "git", "update-index", "-q", "--unmerged", "--refresh", NULL
122 return io_run_bg(update_index_argv
);
126 index_diff(struct index_diff
*diff
, bool untracked
, bool count_all
)
128 const char *untracked_arg
= !untracked
? "--untracked-files=no" :
129 count_all
? "--untracked-files=all" :
130 "--untracked-files=normal";
131 const char *status_argv
[] = {
132 "git", "status", "--porcelain", "-z", untracked_arg
, NULL
138 memset(diff
, 0, sizeof(*diff
));
140 if (!io_run(&io
, IO_RD
, repo
.cdup
, NULL
, status_argv
))
143 while (io_get(&io
, &buf
, 0, TRUE
) && (ok
= buf
.size
> 3)) {
144 if (buf
.data
[0] == '?')
146 /* Ignore staged but unmerged entries. */
147 else if (buf
.data
[0] != ' ' && buf
.data
[0] != 'U')
149 if (buf
.data
[1] != ' ')
151 if (!count_all
&& diff
->staged
&& diff
->unstaged
&&
152 (!untracked
|| diff
->untracked
))
163 /* vim: set ts=8 sw=8 noexpandtab: */