Merge branch 'master' of git://github.com/alshopov/git-po
[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 struct lock_file lock_file;
133
134 static int option_parse_stage(const struct option *opt,
135                               const char *arg, int unset)
136 {
137         if (!strcmp(arg, "all")) {
138                 to_tempfile = 1;
139                 checkout_stage = CHECKOUT_ALL;
140         } else {
141                 int ch = arg[0];
142                 if ('1' <= ch && ch <= '3')
143                         checkout_stage = arg[0] - '0';
144                 else
145                         die(_("stage should be between 1 and 3 or all"));
146         }
147         return 0;
148 }
149
150 int cmd_checkout_index(int argc, const char **argv, const char *prefix)
151 {
152         int i;
153         int newfd = -1;
154         int all = 0;
155         int read_from_stdin = 0;
156         int prefix_length;
157         int force = 0, quiet = 0, not_new = 0;
158         int index_opt = 0;
159         struct option builtin_checkout_index_options[] = {
160                 OPT_BOOL('a', "all", &all,
161                         N_("check out all files in the index")),
162                 OPT__FORCE(&force, N_("force overwrite of existing files")),
163                 OPT__QUIET(&quiet,
164                         N_("no warning for existing files and files not in index")),
165                 OPT_BOOL('n', "no-create", &not_new,
166                         N_("don't checkout new files")),
167                 OPT_BOOL('u', "index", &index_opt,
168                          N_("update stat information in the index file")),
169                 OPT_BOOL('z', NULL, &nul_term_line,
170                         N_("paths are separated with NUL character")),
171                 OPT_BOOL(0, "stdin", &read_from_stdin,
172                         N_("read list of paths from the standard input")),
173                 OPT_BOOL(0, "temp", &to_tempfile,
174                         N_("write the content to temporary files")),
175                 OPT_STRING(0, "prefix", &state.base_dir, N_("string"),
176                         N_("when creating files, prepend <string>")),
177                 { OPTION_CALLBACK, 0, "stage", NULL, "1-3|all",
178                         N_("copy out the files from named stage"),
179                         PARSE_OPT_NONEG, option_parse_stage },
180                 OPT_END()
181         };
182
183         if (argc == 2 && !strcmp(argv[1], "-h"))
184                 usage_with_options(builtin_checkout_index_usage,
185                                    builtin_checkout_index_options);
186         git_config(git_default_config, NULL);
187         prefix_length = prefix ? strlen(prefix) : 0;
188
189         if (read_cache() < 0) {
190                 die("invalid cache");
191         }
192
193         argc = parse_options(argc, argv, prefix, builtin_checkout_index_options,
194                         builtin_checkout_index_usage, 0);
195         state.force = force;
196         state.quiet = quiet;
197         state.not_new = not_new;
198
199         if (!state.base_dir)
200                 state.base_dir = "";
201         state.base_dir_len = strlen(state.base_dir);
202
203         /*
204          * when --prefix is specified we do not want to update cache.
205          */
206         if (index_opt && !state.base_dir_len && !to_tempfile) {
207                 state.refresh_cache = 1;
208                 state.istate = &the_index;
209                 newfd = hold_locked_index(&lock_file, LOCK_DIE_ON_ERROR);
210         }
211
212         /* Check out named files first */
213         for (i = 0; i < argc; i++) {
214                 const char *arg = argv[i];
215                 char *p;
216
217                 if (all)
218                         die("git checkout-index: don't mix '--all' and explicit filenames");
219                 if (read_from_stdin)
220                         die("git checkout-index: don't mix '--stdin' and explicit filenames");
221                 p = prefix_path(prefix, prefix_length, arg);
222                 checkout_file(p, prefix);
223                 free(p);
224         }
225
226         if (read_from_stdin) {
227                 struct strbuf buf = STRBUF_INIT;
228                 struct strbuf unquoted = STRBUF_INIT;
229                 strbuf_getline_fn getline_fn;
230
231                 if (all)
232                         die("git checkout-index: don't mix '--all' and '--stdin'");
233
234                 getline_fn = nul_term_line ? strbuf_getline_nul : strbuf_getline_lf;
235                 while (getline_fn(&buf, stdin) != EOF) {
236                         char *p;
237                         if (!nul_term_line && buf.buf[0] == '"') {
238                                 strbuf_reset(&unquoted);
239                                 if (unquote_c_style(&unquoted, buf.buf, NULL))
240                                         die("line is badly quoted");
241                                 strbuf_swap(&buf, &unquoted);
242                         }
243                         p = prefix_path(prefix, prefix_length, buf.buf);
244                         checkout_file(p, prefix);
245                         free(p);
246                 }
247                 strbuf_release(&unquoted);
248                 strbuf_release(&buf);
249         }
250
251         if (all)
252                 checkout_all(prefix, prefix_length);
253
254         if (0 <= newfd &&
255             write_locked_index(&the_index, &lock_file, COMMIT_LOCK))
256                 die("Unable to write new index file");
257         return 0;
258 }