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