diff --git a/Documentation/git-add.txt b/Documentation/git-add.txt
index 1afd0c6..8620ae2 100644
--- a/Documentation/git-add.txt
+++ b/Documentation/git-add.txt
@@ -8,8 +8,8 @@ git-add - Add file contents to the index
SYNOPSIS
--------
[verse]
-'git-add' [-n] [-v] [-f] [--interactive | -i] [--patch | -p] [-u] [--refresh]
- [--ignore-errors] [--] <filepattern>...
+'git-add' [-n] [-v] [-f] [--interactive | -i] [--patch | -p] [--edit | -e]
+ [-u] [--refresh] [--ignore-errors] [--] <filepattern>...
DESCRIPTION
-----------
@@ -70,6 +70,15 @@ OPTIONS
bypassed and the 'patch' subcommand is invoked using each of
the specified filepatterns before exiting.
+-e, \--edit::
+ Open the diff vs. the index in an editor and let the user
+ edit it. After the editor was closed, adjust the hunk headers
+ and apply the patch to the index.
++
+*NOTE*: Obviously, if you change anything else than the first character
+on lines beginning with a space or a minus, the patch will no longer
+apply.
+
-u::
Update only files that git already knows about, staging modified
content for commit and marking deleted files for removal. This
diff --git a/builtin-add.c b/builtin-add.c
index 1da22ee..fe31453 100644
--- a/builtin-add.c
+++ b/builtin-add.c
@@ -19,7 +19,7 @@ static const char * const builtin_add_usage[] = {
"git-add [options] [--] <filepattern>...",
NULL
};
-static int patch_interactive = 0, add_interactive = 0;
+static int patch_interactive = 0, add_interactive = 0, edit_interactive = 0;
static int take_worktree_changes;
static void prune_directory(struct dir_struct *dir, const char **pathspec, int prefix)@@ -186,6 +186,56 @@ int interactive_add(int argc, const char **argv, const char *prefix)
return status;
}
+int edit_patch(int argc, const char **argv, const char *prefix)
+{
+ char *file = xstrdup(git_path("ADD_EDIT.patch"));
+ const char *apply_argv[] = { "apply", "--recount", "--cached",
+ file, NULL };
+ struct child_process child;
+ int result = 0, ac;
+ struct stat st;
+
+ memset(&child, 0, sizeof(child));
+ child.argv = xcalloc(sizeof(const char *), (argc + 5));
+ ac = 0;
+ child.git_cmd = 1;
+ child.argv[ac++] = "diff-files";
+ child.argv[ac++] = "--no-color";
+ child.argv[ac++] = "-p";
+ child.argv[ac++] = "--";
+ if (argc) {
+ const char **pathspec = validate_pathspec(argc, argv, prefix);
+ if (!pathspec)
+ return -1;
+ memcpy(&(child.argv[ac]), pathspec, sizeof(*argv) * argc);
+ ac += argc;
+ }
+ child.argv[ac] = NULL;
+ child.out = open(file, O_CREAT | O_WRONLY, 0644);
+ result = child.out < 0 && error("Could not write to '%s'", file);
+
+ if (!result)
+ result = run_command(&child);
+ free(child.argv);
+
+ launch_editor(file, NULL, NULL);
+
+ if (!result)
+ result = stat(file, &st) && error("Could not stat '%s'", file);
+ if (!result && !st.st_size)
+ result = error("Empty patch. Aborted.");
+
+ memset(&child, 0, sizeof(child));
+ child.git_cmd = 1;
+ child.argv = apply_argv;
+ if (!result)
+ result = run_command(&child) &&
+ error("Could not apply '%s'", file);
+ if (!result)
+ unlink(file);
+ return result;
+}
+
static struct lock_file lock_file;
static const char ignore_error[] =@@ -200,6 +250,7 @@ static struct option builtin_add_options[] = {
OPT_GROUP(""),
OPT_BOOLEAN('i', "interactive", &add_interactive, "interactive picking"),
OPT_BOOLEAN('p', "patch", &patch_interactive, "interactive patching"),
+ OPT_BOOLEAN('e', "edit", &edit_interactive, "super-interactive patching"),
OPT_BOOLEAN('f', NULL, &ignored_too, "allow adding otherwise ignored files"),
OPT_BOOLEAN('u', NULL, &take_worktree_changes, "update tracked files"),
OPT_BOOLEAN( 0 , "refresh", &refresh_only, "don't add, only refresh the index"),@@ -226,6 +277,8 @@ int cmd_add(int argc, const char **argv, const char *prefix)
argc = parse_options(argc, argv, builtin_add_options,
builtin_add_usage, 0);
+ if (edit_interactive)
+ return(edit_patch(argc, argv, prefix));
if (patch_interactive)
add_interactive = 1;
if (add_interactive)
diff --git a/t/t3702-add-edit.sh b/t/t3702-add-edit.sh
new file mode 100755
index 0000000..decf727
--- /dev/null
+++ b/t/t3702-add-edit.sh
@@ -0,0 +1,126 @@
+#!/bin/sh
+#
+# Copyright (c) 2007 Johannes E. Schindelin
+#
+
+test_description='add -e basic tests'
+. ./test-lib.sh
+
+
+cat > file << EOF
+LO, praise of the prowess of people-kings
+of spear-armed Danes, in days long sped,
+we have heard, and what honor the athelings won!
+Oft Scyld the Scefing from squadroned foes,
+from many a tribe, the mead-bench tore,
+awing the earls. Since erst he lay
+friendless, a foundling, fate repaid him:
+for he waxed under welkin, in wealth he throve,
+till before him the folk, both far and near,
+who house by the whale-path, heard his mandate,
+gave him gifts: a good king he!
+EOF
+
+test_expect_success 'setup' '
+
+ git add file &&
+ test_tick &&
+ git commit -m initial file
+
+'
+
+cat > patch << EOF
+diff --git a/file b/file
+index b9834b5..ef6e94c 100644
+--- a/file
++++ b/file
+@@ -3,1 +3,333 @@ of spear-armed Danes, in days long sped,
+ we have heard, and what honor the athelings won!
++
+ Oft Scyld the Scefing from squadroned foes,
+@@ -2,7 +1,5 @@ awing the earls. Since erst he lay
+ friendless, a foundling, fate repaid him:
++
+ for he waxed under welkin, in wealth he throve,
+EOF
+
+cat > expected << EOF
+diff --git a/file b/file
+index b9834b5..ef6e94c 100644
+--- a/file
++++ b/file
+@@ -1,10 +1,12 @@
+ LO, praise of the prowess of people-kings
+ of spear-armed Danes, in days long sped,
+ we have heard, and what honor the athelings won!
++
+ Oft Scyld the Scefing from squadroned foes,
+ from many a tribe, the mead-bench tore,
+ awing the earls. Since erst he lay
+ friendless, a foundling, fate repaid him:
++
+ for he waxed under welkin, in wealth he throve,
+ till before him the folk, both far and near,
+ who house by the whale-path, heard his mandate,
+EOF
+
+echo "#!$SHELL_PATH" >fake-editor.sh
+cat >> fake-editor.sh <<\EOF
+mv -f "$1" orig-patch &&
+mv -f patch "$1"
+EOF
+
+test_set_editor "$(pwd)/fake-editor.sh"
+chmod a+x fake-editor.sh
+
+test_expect_success 'add -e' '
+
+ cp fake-editor.sh file &&
+ git add -e &&
+ test_cmp fake-editor.sh file &&
+ git diff --cached > out &&
+ test_cmp out expected
+
+'
+
+cat > patch << EOF
+diff --git a/file b/file
+--- a/file
++++ b/file
+@@ -1,1 +1,1 @@
+ gave him gifts: a good king he!
++
+EOF
+
+test_expect_success 'add -e adds to the end of the file' '
+
+ test_tick &&
+ git commit -m update &&
+ git checkout &&
+ git add -e &&
+ git diff --cached > out &&
+ test "" = "$(git show :file | tail -n 1)"
+
+'
+
+cat > patch << EOF
+diff --git a/file b/file
+--- a/file
++++ b/file
+@@ -1,1 +1,1 @@
++
+ LO, praise of the prowess of people-kings
+EOF
+
+test_expect_success 'add -e adds to the beginning of the file' '
+
+ test_tick &&
+ git commit -m update &&
+ git checkout &&
+ git add -e &&
+ git diff --cached > out &&
+ test "" = "$(git show :file | head -n 1)"
+
+'
+
+test_done
--
1.5.6.rc1.181.gb439d