Skip to content

Commit c59cb03

Browse files
dschogitster
authored andcommitted
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>
1 parent ee7ec2f commit c59cb03

File tree

3 files changed

+175
-4
lines changed

3 files changed

+175
-4
lines changed

Documentation/git-add.txt

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ SYNOPSIS
99
--------
1010
[verse]
1111
'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]
1313
[--refresh] [--ignore-errors] [--] <filepattern>...
1414

1515
DESCRIPTION
@@ -76,6 +76,15 @@ OPTIONS
7676
bypassed and the 'patch' subcommand is invoked using each of
7777
the specified filepatterns before exiting.
7878

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+
7988
-u::
8089
--update::
8190
Update only files that git already knows about, staging modified

builtin-add.c

Lines changed: 56 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,14 @@
1010
#include "cache-tree.h"
1111
#include "run-command.h"
1212
#include "parse-options.h"
13+
#include "diff.h"
14+
#include "revision.h"
1315

1416
static const char * const builtin_add_usage[] = {
1517
"git add [options] [--] <filepattern>...",
1618
NULL
1719
};
18-
static int patch_interactive, add_interactive;
20+
static int patch_interactive, add_interactive, edit_interactive;
1921
static int take_worktree_changes;
2022

2123
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)
187189
return status;
188190
}
189191

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+
190237
static struct lock_file lock_file;
191238

192239
static const char ignore_error[] =
@@ -201,6 +248,7 @@ static struct option builtin_add_options[] = {
201248
OPT_GROUP(""),
202249
OPT_BOOLEAN('i', "interactive", &add_interactive, "interactive picking"),
203250
OPT_BOOLEAN('p', "patch", &patch_interactive, "interactive patching"),
251+
OPT_BOOLEAN('e', "edit", &edit_interactive, "edit current diff and apply"),
204252
OPT_BOOLEAN('f', "force", &ignored_too, "allow adding otherwise ignored files"),
205253
OPT_BOOLEAN('u', "update", &take_worktree_changes, "update tracked files"),
206254
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)
251299
int require_pathspec;
252300

253301
argc = parse_options(argc, argv, builtin_add_options,
254-
builtin_add_usage, 0);
302+
builtin_add_usage, PARSE_OPT_KEEP_ARGV0);
255303
if (patch_interactive)
256304
add_interactive = 1;
257305
if (add_interactive)
258-
exit(interactive_add(argc, argv, prefix));
306+
exit(interactive_add(argc - 1, argv + 1, prefix));
259307

260308
git_config(add_config, NULL);
261309

310+
if (edit_interactive)
311+
return(edit_patch(argc, argv, prefix));
312+
argc--;
313+
argv++;
314+
262315
if (addremove && take_worktree_changes)
263316
die("-A and -u are mutually incompatible");
264317
if ((addremove || take_worktree_changes) && !argc) {

t/t3702-add-edit.sh

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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

0 commit comments

Comments
 (0)