Merge branch 'tr/maint-mailinfo'
[git] / builtin / checkout-index.c
1 /*
2  * Check-out files from the "current cache directory"
3  *
4  * Copyright (C) 2005 Linus Torvalds
5  *
6  */
7 #include "builtin.h"
8 #include "cache.h"
9 #include "quote.h"
10 #include "cache-tree.h"
11 #include "parse-options.h"
12
13 #define CHECKOUT_ALL 4
14 static int line_termination = '\n';
15 static int checkout_stage; /* default to checkout stage0 */
16 static int to_tempfile;
17 static char topath[4][PATH_MAX + 1];
18
19 static struct checkout state;
20
21 static void write_tempfile_record(const char *name, int prefix_length)
22 {
23         int i;
24
25         if (CHECKOUT_ALL == checkout_stage) {
26                 for (i = 1; i < 4; i++) {
27                         if (i > 1)
28                                 putchar(' ');
29                         if (topath[i][0])
30                                 fputs(topath[i], stdout);
31                         else
32                                 putchar('.');
33                 }
34         } else
35                 fputs(topath[checkout_stage], stdout);
36
37         putchar('\t');
38         write_name_quoted(name + prefix_length, stdout, line_termination);
39
40         for (i = 0; i < 4; i++) {
41                 topath[i][0] = 0;
42         }
43 }
44
45 static int checkout_file(const char *name, int prefix_length)
46 {
47         int namelen = strlen(name);
48         int pos = cache_name_pos(name, namelen);
49         int has_same_name = 0;
50         int did_checkout = 0;
51         int errs = 0;
52
53         if (pos < 0)
54                 pos = -pos - 1;
55
56         while (pos < active_nr) {
57                 struct cache_entry *ce = active_cache[pos];
58                 if (ce_namelen(ce) != namelen ||
59                     memcmp(ce->name, name, namelen))
60                         break;
61                 has_same_name = 1;
62                 pos++;
63                 if (ce_stage(ce) != checkout_stage
64                     && (CHECKOUT_ALL != checkout_stage || !ce_stage(ce)))
65                         continue;
66                 did_checkout = 1;
67                 if (checkout_entry(ce, &state,
68                     to_tempfile ? topath[ce_stage(ce)] : NULL) < 0)
69                         errs++;
70         }
71
72         if (did_checkout) {
73                 if (to_tempfile)
74                         write_tempfile_record(name, prefix_length);
75                 return errs > 0 ? -1 : 0;
76         }
77
78         if (!state.quiet) {
79                 fprintf(stderr, "git checkout-index: %s ", name);
80                 if (!has_same_name)
81                         fprintf(stderr, "is not in the cache");
82                 else if (checkout_stage)
83                         fprintf(stderr, "does not exist at stage %d",
84                                 checkout_stage);
85                 else
86                         fprintf(stderr, "is unmerged");
87                 fputc('\n', stderr);
88         }
89         return -1;
90 }
91
92 static void checkout_all(const char *prefix, int prefix_length)
93 {
94         int i, errs = 0;
95         struct cache_entry *last_ce = NULL;
96
97         for (i = 0; i < active_nr ; i++) {
98                 struct cache_entry *ce = active_cache[i];
99                 if (ce_stage(ce) != checkout_stage
100                     && (CHECKOUT_ALL != checkout_stage || !ce_stage(ce)))
101                         continue;
102                 if (prefix && *prefix &&
103                     (ce_namelen(ce) <= prefix_length ||
104                      memcmp(prefix, ce->name, prefix_length)))
105                         continue;
106                 if (last_ce && to_tempfile) {
107                         if (ce_namelen(last_ce) != ce_namelen(ce)
108                             || memcmp(last_ce->name, ce->name, ce_namelen(ce)))
109                                 write_tempfile_record(last_ce->name, prefix_length);
110                 }
111                 if (checkout_entry(ce, &state,
112                     to_tempfile ? topath[ce_stage(ce)] : NULL) < 0)
113                         errs++;
114                 last_ce = ce;
115         }
116         if (last_ce && to_tempfile)
117                 write_tempfile_record(last_ce->name, prefix_length);
118         if (errs)
119                 /* we have already done our error reporting.
120                  * exit with the same code as die().
121                  */
122                 exit(128);
123 }
124
125 static const char * const builtin_checkout_index_usage[] = {
126         "git checkout-index [options] [--] [<file>...]",
127         NULL
128 };
129
130 static struct lock_file lock_file;
131
132 static int option_parse_u(const struct option *opt,
133                               const char *arg, int unset)
134 {
135         int *newfd = opt->value;
136
137         state.refresh_cache = 1;
138         if (*newfd < 0)
139                 *newfd = hold_locked_index(&lock_file, 1);
140         return 0;
141 }
142
143 static int option_parse_z(const struct option *opt,
144                           const char *arg, int unset)
145 {
146         if (unset)
147                 line_termination = '\n';
148         else
149                 line_termination = 0;
150         return 0;
151 }
152
153 static int option_parse_prefix(const struct option *opt,
154                                const char *arg, int unset)
155 {
156         state.base_dir = arg;
157         state.base_dir_len = strlen(arg);
158         return 0;
159 }
160
161 static int option_parse_stage(const struct option *opt,
162                               const char *arg, int unset)
163 {
164         if (!strcmp(arg, "all")) {
165                 to_tempfile = 1;
166                 checkout_stage = CHECKOUT_ALL;
167         } else {
168                 int ch = arg[0];
169                 if ('1' <= ch && ch <= '3')
170                         checkout_stage = arg[0] - '0';
171                 else
172                         die("stage should be between 1 and 3 or all");
173         }
174         return 0;
175 }
176
177 int cmd_checkout_index(int argc, const char **argv, const char *prefix)
178 {
179         int i;
180         int newfd = -1;
181         int all = 0;
182         int read_from_stdin = 0;
183         int prefix_length;
184         int force = 0, quiet = 0, not_new = 0;
185         struct option builtin_checkout_index_options[] = {
186                 OPT_BOOLEAN('a', "all", &all,
187                         "checks out all files in the index"),
188                 OPT__FORCE(&force, "forces overwrite of existing files"),
189                 OPT__QUIET(&quiet,
190                         "no warning for existing files and files not in index"),
191                 OPT_BOOLEAN('n', "no-create", &not_new,
192                         "don't checkout new files"),
193                 { OPTION_CALLBACK, 'u', "index", &newfd, NULL,
194                         "update stat information in the index file",
195                         PARSE_OPT_NOARG, option_parse_u },
196                 { OPTION_CALLBACK, 'z', NULL, NULL, NULL,
197                         "paths are separated with NUL character",
198                         PARSE_OPT_NOARG, option_parse_z },
199                 OPT_BOOLEAN(0, "stdin", &read_from_stdin,
200                         "read list of paths from the standard input"),
201                 OPT_BOOLEAN(0, "temp", &to_tempfile,
202                         "write the content to temporary files"),
203                 OPT_CALLBACK(0, "prefix", NULL, "string",
204                         "when creating files, prepend <string>",
205                         option_parse_prefix),
206                 OPT_CALLBACK(0, "stage", NULL, NULL,
207                         "copy out the files from named stage",
208                         option_parse_stage),
209                 OPT_END()
210         };
211
212         if (argc == 2 && !strcmp(argv[1], "-h"))
213                 usage_with_options(builtin_checkout_index_usage,
214                                    builtin_checkout_index_options);
215         git_config(git_default_config, NULL);
216         state.base_dir = "";
217         prefix_length = prefix ? strlen(prefix) : 0;
218
219         if (read_cache() < 0) {
220                 die("invalid cache");
221         }
222
223         argc = parse_options(argc, argv, prefix, builtin_checkout_index_options,
224                         builtin_checkout_index_usage, 0);
225         state.force = force;
226         state.quiet = quiet;
227         state.not_new = not_new;
228
229         if (state.base_dir_len || to_tempfile) {
230                 /* when --prefix is specified we do not
231                  * want to update cache.
232                  */
233                 if (state.refresh_cache) {
234                         rollback_lock_file(&lock_file);
235                         newfd = -1;
236                 }
237                 state.refresh_cache = 0;
238         }
239
240         /* Check out named files first */
241         for (i = 0; i < argc; i++) {
242                 const char *arg = argv[i];
243                 const char *p;
244
245                 if (all)
246                         die("git checkout-index: don't mix '--all' and explicit filenames");
247                 if (read_from_stdin)
248                         die("git checkout-index: don't mix '--stdin' and explicit filenames");
249                 p = prefix_path(prefix, prefix_length, arg);
250                 checkout_file(p, prefix_length);
251                 if (p < arg || p > arg + strlen(arg))
252                         free((char *)p);
253         }
254
255         if (read_from_stdin) {
256                 struct strbuf buf = STRBUF_INIT, nbuf = STRBUF_INIT;
257
258                 if (all)
259                         die("git checkout-index: don't mix '--all' and '--stdin'");
260
261                 while (strbuf_getline(&buf, stdin, line_termination) != EOF) {
262                         const char *p;
263                         if (line_termination && buf.buf[0] == '"') {
264                                 strbuf_reset(&nbuf);
265                                 if (unquote_c_style(&nbuf, buf.buf, NULL))
266                                         die("line is badly quoted");
267                                 strbuf_swap(&buf, &nbuf);
268                         }
269                         p = prefix_path(prefix, prefix_length, buf.buf);
270                         checkout_file(p, prefix_length);
271                         if (p < buf.buf || p > buf.buf + buf.len)
272                                 free((char *)p);
273                 }
274                 strbuf_release(&nbuf);
275                 strbuf_release(&buf);
276         }
277
278         if (all)
279                 checkout_all(prefix, prefix_length);
280
281         if (0 <= newfd &&
282             (write_cache(newfd, active_cache, active_nr) ||
283              commit_locked_index(&lock_file)))
284                 die("Unable to write new index file");
285         return 0;
286 }