@matheusbsbs / matheus-bagliano / commits / c59cb03a8b
Fork 0

git-add: introduce --edit (to edit the diff vs. the index)

With "git add -e [<files>]", Git will fire up an editor with the current diff relative to the index (i.e. what you would get with "git diff [<files>]"). Now you can edit the patch as much as you like, including adding/removing lines, editing the text, whatever. Make sure, though, that the first character of the hunk lines is still a space, a plus or a minus. After you closed the editor, Git will adjust the line counts of the hunks if necessary, thanks to the --recount option of apply, and commit the patch. Except if you deleted everything, in which case nothing happens (for obvious reasons). Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Johannes Schindelin committed Apr 8, 2009 at 23:30 UTC c59cb03a8bfc4b09758b07b23b6fe70a909ff9f4
3 files changed +175 -4
Documentation/git-add.txt
+10 -1
@@ -9,7 +9,7 @@ SYNOPSIS
9 --------
10 [verse]
11 'git add' [-n] [-v] [--force | -f] [--interactive | -i] [--patch | -p]
12 - [--all | [--update | -u]] [--intent-to-add | -N]
12 + [--edit | -e] [--all | [--update | -u]] [--intent-to-add | -N]
13 [--refresh] [--ignore-errors] [--] <filepattern>...
14
15 DESCRIPTION
@@ -76,6 +76,15 @@ OPTIONS
76 bypassed and the 'patch' subcommand is invoked using each of
77 the specified filepatterns before exiting.
78
79 +-e, \--edit::
80 + Open the diff vs. the index in an editor and let the user
81 + edit it. After the editor was closed, adjust the hunk headers
82 + and apply the patch to the index.
83 ++
84 +*NOTE*: Obviously, if you change anything else than the first character
85 +on lines beginning with a space or a minus, the patch will no longer
86 +apply.
87 +
88 -u::
89 --update::
90 Update only files that git already knows about, staging modified
builtin-add.c
+56 -3
@@ -10,12 +10,14 @@
10 #include "cache-tree.h"
11 #include "run-command.h"
12 #include "parse-options.h"
13 +#include "diff.h"
14 +#include "revision.h"
15
16 static const char * const builtin_add_usage[] = {
17 "git add [options] [--] <filepattern>...",
18 NULL
19 };
18 -static int patch_interactive, add_interactive;
20 +static int patch_interactive, add_interactive, edit_interactive;
21 static int take_worktree_changes;
22
23 static void fill_pathspec_matches(const char **pathspec, char *seen, int specs)
@@ -187,6 +189,51 @@ int interactive_add(int argc, const char **argv, const char *prefix)
189 return status;
190 }
191
192 +int edit_patch(int argc, const char **argv, const char *prefix)
193 +{
194 + char *file = xstrdup(git_path("ADD_EDIT.patch"));
195 + const char *apply_argv[] = { "apply", "--recount", "--cached",
196 + file, NULL };
197 + struct child_process child;
198 + struct rev_info rev;
199 + int out;
200 + struct stat st;
201 +
202 + git_config(git_diff_basic_config, NULL); /* no "diff" UI options */
203 +
204 + if (read_cache() < 0)
205 + die ("Could not read the index");
206 +
207 + init_revisions(&rev, prefix);
208 + rev.diffopt.context = 7;
209 +
210 + argc = setup_revisions(argc, argv, &rev, NULL);
211 + rev.diffopt.output_format = DIFF_FORMAT_PATCH;
212 + out = open(file, O_CREAT | O_WRONLY, 0644);
213 + if (out < 0)
214 + die ("Could not open '%s' for writing.", file);
215 + rev.diffopt.file = fdopen(out, "w");
216 + rev.diffopt.close_file = 1;
217 + if (run_diff_files(&rev, 0))
218 + die ("Could not write patch");
219 +
220 + launch_editor(file, NULL, NULL);
221 +
222 + if (stat(file, &st))
223 + die("Could not stat '%s'", file);
224 + if (!st.st_size)
225 + die("Empty patch. Aborted.");
226 +
227 + memset(&child, 0, sizeof(child));
228 + child.git_cmd = 1;
229 + child.argv = apply_argv;
230 + if (run_command(&child))
231 + die ("Could not apply '%s'", file);
232 +
233 + unlink(file);
234 + return 0;
235 +}
236 +
237 static struct lock_file lock_file;
238
239 static const char ignore_error[] =
@@ -201,6 +248,7 @@ static struct option builtin_add_options[] = {
248 OPT_GROUP(""),
249 OPT_BOOLEAN('i', "interactive", &add_interactive, "interactive picking"),
250 OPT_BOOLEAN('p', "patch", &patch_interactive, "interactive patching"),
251 + OPT_BOOLEAN('e', "edit", &edit_interactive, "edit current diff and apply"),
252 OPT_BOOLEAN('f', "force", &ignored_too, "allow adding otherwise ignored files"),
253 OPT_BOOLEAN('u', "update", &take_worktree_changes, "update tracked files"),
254 OPT_BOOLEAN('N', "intent-to-add", &intent_to_add, "record only the fact that the path will be added later"),
@@ -251,14 +299,19 @@ int cmd_add(int argc, const char **argv, const char *prefix)
299 int require_pathspec;
300
301 argc = parse_options(argc, argv, builtin_add_options,
254 - builtin_add_usage, 0);
302 + builtin_add_usage, PARSE_OPT_KEEP_ARGV0);
303 if (patch_interactive)
304 add_interactive = 1;
305 if (add_interactive)
258 - exit(interactive_add(argc, argv, prefix));
306 + exit(interactive_add(argc - 1, argv + 1, prefix));
307
308 git_config(add_config, NULL);
309
310 + if (edit_interactive)
311 + return(edit_patch(argc, argv, prefix));
312 + argc--;
313 + argv++;
314 +
315 if (addremove && take_worktree_changes)
316 die("-A and -u are mutually incompatible");
317 if ((addremove || take_worktree_changes) && !argc) {
t/t3702-add-edit.sh new
+109
@@ -0,0 +1,109 @@
1 +#!/bin/sh
2 +#
3 +# Copyright (c) 2007 Johannes E. Schindelin
4 +#
5 +
6 +test_description='add -e basic tests'
7 +. ./test-lib.sh
8 +
9 +
10 +cat > file << EOF
11 +LO, praise of the prowess of people-kings
12 +of spear-armed Danes, in days long sped,
13 +we have heard, and what honor the athelings won!
14 +Oft Scyld the Scefing from squadroned foes,
15 +from many a tribe, the mead-bench tore,
16 +awing the earls. Since erst he lay
17 +friendless, a foundling, fate repaid him:
18 +for he waxed under welkin, in wealth he throve,
19 +till before him the folk, both far and near,
20 +who house by the whale-path, heard his mandate,
21 +gave him gifts: a good king he!
22 +EOF
23 +
24 +test_expect_success 'setup' '
25 +
26 + git add file &&
27 + test_tick &&
28 + git commit -m initial file
29 +
30 +'
31 +
32 +cat > expected-patch << EOF
33 +diff --git a/file b/file
34 +index b9834b5..0b8f197 100644
35 +--- a/file
36 ++++ b/file
37 +@@ -1,11 +1,3 @@
38 +-LO, praise of the prowess of people-kings
39 +-of spear-armed Danes, in days long sped,
40 +-we have heard, and what honor the athelings won!
41 +-Oft Scyld the Scefing from squadroned foes,
42 +-from many a tribe, the mead-bench tore,
43 +-awing the earls. Since erst he lay
44 +-friendless, a foundling, fate repaid him:
45 +-for he waxed under welkin, in wealth he throve,
46 +-till before him the folk, both far and near,
47 +-who house by the whale-path, heard his mandate,
48 +-gave him gifts: a good king he!
49 ++#!$SHELL_PATH
50 ++mv -f "\$1" orig-patch &&
51 ++mv -f patch "\$1"
52 +EOF
53 +
54 +cat > patch << EOF
55 +diff --git a/file b/file
56 +index b9834b5..ef6e94c 100644
57 +--- a/file
58 ++++ b/file
59 +@@ -3,1 +3,333 @@ of spear-armed Danes, in days long sped,
60 + we have heard, and what honor the athelings won!
61 ++
62 + Oft Scyld the Scefing from squadroned foes,
63 +@@ -2,7 +1,5 @@ awing the earls. Since erst he lay
64 + friendless, a foundling, fate repaid him:
65 ++
66 + for he waxed under welkin, in wealth he throve,
67 +EOF
68 +
69 +cat > expected << EOF
70 +diff --git a/file b/file
71 +index b9834b5..ef6e94c 100644
72 +--- a/file
73 ++++ b/file
74 +@@ -1,10 +1,12 @@
75 + LO, praise of the prowess of people-kings
76 + of spear-armed Danes, in days long sped,
77 + we have heard, and what honor the athelings won!
78 ++
79 + Oft Scyld the Scefing from squadroned foes,
80 + from many a tribe, the mead-bench tore,
81 + awing the earls. Since erst he lay
82 + friendless, a foundling, fate repaid him:
83 ++
84 + for he waxed under welkin, in wealth he throve,
85 + till before him the folk, both far and near,
86 + who house by the whale-path, heard his mandate,
87 +EOF
88 +
89 +echo "#!$SHELL_PATH" >fake-editor.sh
90 +cat >> fake-editor.sh <<\EOF
91 +mv -f "$1" orig-patch &&
92 +mv -f patch "$1"
93 +EOF
94 +
95 +test_set_editor "$(pwd)/fake-editor.sh"
96 +chmod a+x fake-editor.sh
97 +
98 +test_expect_success 'add -e' '
99 +
100 + cp fake-editor.sh file &&
101 + git add -e &&
102 + test_cmp fake-editor.sh file &&
103 + test_cmp orig-patch expected-patch &&
104 + git diff --cached > out &&
105 + test_cmp out expected
106 +
107 +'
108 +
109 +test_done