Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion Documentation/git-revert.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ git-revert - Revert some existing commits
SYNOPSIS
--------
[verse]
'git revert' [--[no-]edit] [-n] [-m <parent-number>] [-s] [-S[<keyid>]] <commit>...
'git revert' [--[no-]edit] [-n] [-m <parent-number>] [-s] [-S[<keyid>]] [--allow-shallow-boundary] <commit>...
'git revert' (--continue | --skip | --abort | --quit)

DESCRIPTION
Expand Down Expand Up @@ -122,6 +122,16 @@ include::rerere-options.adoc[]
configuration variable can be used to enable this option by
default.

--allow-shallow-boundary::
By default, 'git revert' refuses to revert a commit that is a
shallow boundary (i.e. a commit listed in `.git/shallow`),
because its true parent history is absent from the clone and
reverting it would remove all tracked files. This option
overrides that safeguard and allows the revert to proceed.
+
To restore full history before reverting, use
`git fetch --unshallow` instead.


SEQUENCER SUBCOMMANDS
---------------------
Expand Down
4 changes: 3 additions & 1 deletion builtin/revert.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
*/

static const char * const revert_usage[] = {
N_("git revert [--[no-]edit] [-n] [-m <parent-number>] [-s] [-S[<keyid>]] <commit>..."),
N_("git revert [--[no-]edit] [-n] [-m <parent-number>] [-s] [-S[<keyid>]] [--allow-shallow-boundary] <commit>..."),
N_("git revert (--continue | --skip | --abort | --quit)"),
NULL
};
Expand Down Expand Up @@ -128,6 +128,8 @@ static int run_sequencer(int argc, const char **argv, const char *prefix,
OPT_BOOL('e', "edit", &opts->edit, N_("edit the commit message")),
OPT_NOOP_NOARG('r', NULL),
OPT_BOOL('s', "signoff", &opts->signoff, N_("add a Signed-off-by trailer")),
OPT_BOOL(0, "allow-shallow-boundary", &opts->allow_shallow_boundary,
N_("allow reverting a shallow boundary commit")),
OPT_CALLBACK('m', "mainline", opts, N_("parent-number"),
N_("select mainline parent"), option_parse_m),
OPT_RERERE_AUTOUPDATE(&opts->allow_rerere_auto),
Expand Down
14 changes: 14 additions & 0 deletions sequencer.c
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
#include "rebase-interactive.h"
#include "reset.h"
#include "branch.h"
#include "shallow.h"

#define GIT_REFLOG_ACTION "GIT_REFLOG_ACTION"

Expand Down Expand Up @@ -2366,6 +2367,19 @@ static enum pick_result do_pick_commit(struct repository *r,
}
discard_index(r->index);

if (is_repository_shallow(r)) {
struct commit_graft *graft = lookup_commit_graft(r, &commit->object.oid);
if (graft && graft->nr_parent < 0 && !opts->allow_shallow_boundary) {
return error(_("%s: commit %s is a shallow boundary commit.\n"
"Reverting it will remove all tracked files because its\n"
"true parent history is not present in this clone.\n"
"Use --allow-shallow-boundary to override, or\n"
"'git fetch --unshallow' to restore full history first."),
command_to_string(command),
oid_to_hex(&commit->object.oid));
}
}

if (!commit->parents)
parent = NULL;
else if (commit->parents->next) {
Expand Down
1 change: 1 addition & 0 deletions sequencer.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ struct replay_opts {
int committer_date_is_author_date;
int ignore_date;
int commit_use_reference;
int allow_shallow_boundary;

struct strvec trailer_args;

Expand Down
25 changes: 25 additions & 0 deletions t/t3501-revert-cherry-pick.sh
Original file line number Diff line number Diff line change
Expand Up @@ -256,4 +256,29 @@ test_expect_success 'cherry-pick is unaware of --reference (for now)' '
test_grep "^usage: git cherry-pick" actual
'

# Tests for shallow boundary safeguard

test_expect_success 'setup shallow boundary tests' '
git init src &&
test_commit -C src A &&
test_commit -C src B &&
git clone --no-local --depth=1 src shallow-repo
'

test_expect_success 'revert of shallow boundary commit is refused by default' '
test_must_fail git -C shallow-repo revert --no-edit HEAD 2>err &&
test_grep "shallow boundary commit" err
'

test_expect_success 'revert of shallow boundary succeeds with --allow-shallow-boundary' '
git -C shallow-repo revert --no-edit --allow-shallow-boundary HEAD
'

test_expect_success 'revert in non-shallow repo is unaffected' '
git init non-shallow &&
test_commit -C non-shallow A &&
test_commit -C non-shallow B &&
git -C non-shallow revert --no-edit HEAD
'

test_done
Loading