Merge branch 'cc/replace-with-the-same-type'
* cc/replace-with-the-same-type: Doc: 'replace' merge and non-merge commits t6050-replace: use some long option names replace: allow long option names Documentation/replace: add Creating Replacement Objects section t6050-replace: add test to clean up all the replace refs t6050-replace: test that objects are of the same type Documentation/replace: state that objects must be of the same type replace: forbid replacing an object with one of a different type
This commit is contained in:
commit
80f165a58a
@ -20,8 +20,14 @@ The name of the 'replace' reference is the SHA-1 of the object that is
|
||||
replaced. The content of the 'replace' reference is the SHA-1 of the
|
||||
replacement object.
|
||||
|
||||
The replaced object and the replacement object must be of the same type.
|
||||
This restriction can be bypassed using `-f`.
|
||||
|
||||
Unless `-f` is given, the 'replace' reference must not yet exist.
|
||||
|
||||
There is no other restriction on the replaced and replacement objects.
|
||||
Merge commits can be replaced by non-merge commits and vice versa.
|
||||
|
||||
Replacement references will be used by default by all Git commands
|
||||
except those doing reachability traversal (prune, pack transfer and
|
||||
fsck).
|
||||
@ -49,18 +55,34 @@ achieve the same effect as the `--no-replace-objects` option.
|
||||
OPTIONS
|
||||
-------
|
||||
-f::
|
||||
--force::
|
||||
If an existing replace ref for the same object exists, it will
|
||||
be overwritten (instead of failing).
|
||||
|
||||
-d::
|
||||
--delete::
|
||||
Delete existing replace refs for the given objects.
|
||||
|
||||
-l <pattern>::
|
||||
--list <pattern>::
|
||||
List replace refs for objects that match the given pattern (or
|
||||
all if no pattern is given).
|
||||
Typing "git replace" without arguments, also lists all replace
|
||||
refs.
|
||||
|
||||
CREATING REPLACEMENT OBJECTS
|
||||
----------------------------
|
||||
|
||||
linkgit:git-filter-branch[1], linkgit:git-hash-object[1] and
|
||||
linkgit:git-rebase[1], among other git commands, can be used to create
|
||||
replacement objects from existing objects.
|
||||
|
||||
If you want to replace many blobs, trees or commits that are part of a
|
||||
string of commits, you may just want to create a replacement string of
|
||||
commits and then only replace the commit at the tip of the target
|
||||
string of commits with the commit at the tip of the replacement string
|
||||
of commits.
|
||||
|
||||
BUGS
|
||||
----
|
||||
Comparing blobs or trees that have been replaced with those that
|
||||
@ -69,12 +91,13 @@ go back to a replaced commit will move the branch to the replacement
|
||||
commit instead of the replaced commit.
|
||||
|
||||
There may be other problems when using 'git rev-list' related to
|
||||
pending objects. And of course things may break if an object of one
|
||||
type is replaced by an object of another type (for example a blob
|
||||
replaced by a commit).
|
||||
pending objects.
|
||||
|
||||
SEE ALSO
|
||||
--------
|
||||
linkgit:git-hash-object[1]
|
||||
linkgit:git-filter-branch[1]
|
||||
linkgit:git-rebase[1]
|
||||
linkgit:git-tag[1]
|
||||
linkgit:git-branch[1]
|
||||
linkgit:git[1]
|
||||
|
@ -85,6 +85,7 @@ static int replace_object(const char *object_ref, const char *replace_ref,
|
||||
int force)
|
||||
{
|
||||
unsigned char object[20], prev[20], repl[20];
|
||||
enum object_type obj_type, repl_type;
|
||||
char ref[PATH_MAX];
|
||||
struct ref_lock *lock;
|
||||
|
||||
@ -100,6 +101,15 @@ static int replace_object(const char *object_ref, const char *replace_ref,
|
||||
if (check_refname_format(ref, 0))
|
||||
die("'%s' is not a valid ref name.", ref);
|
||||
|
||||
obj_type = sha1_object_info(object, NULL);
|
||||
repl_type = sha1_object_info(repl, NULL);
|
||||
if (!force && obj_type != repl_type)
|
||||
die("Objects must be of the same type.\n"
|
||||
"'%s' points to a replaced object of type '%s'\n"
|
||||
"while '%s' points to a replacement object of type '%s'.",
|
||||
object_ref, typename(obj_type),
|
||||
replace_ref, typename(repl_type));
|
||||
|
||||
if (read_ref(ref, prev))
|
||||
hashclr(prev);
|
||||
else if (!force)
|
||||
@ -118,9 +128,9 @@ int cmd_replace(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
int list = 0, delete = 0, force = 0;
|
||||
struct option options[] = {
|
||||
OPT_BOOL('l', NULL, &list, N_("list replace refs")),
|
||||
OPT_BOOL('d', NULL, &delete, N_("delete replace refs")),
|
||||
OPT_BOOL('f', NULL, &force, N_("replace the ref if it exists")),
|
||||
OPT_BOOL('l', "list", &list, N_("list replace refs")),
|
||||
OPT_BOOL('d', "delete", &delete, N_("delete replace refs")),
|
||||
OPT_BOOL('f', "force", &force, N_("replace the ref if it exists")),
|
||||
OPT_END()
|
||||
};
|
||||
|
||||
|
@ -122,9 +122,9 @@ test_expect_success '"git replace" listing and deleting' '
|
||||
test "$HASH2" = "$(git replace -l)" &&
|
||||
test "$HASH2" = "$(git replace)" &&
|
||||
aa=${HASH2%??????????????????????????????????????} &&
|
||||
test "$HASH2" = "$(git replace -l "$aa*")" &&
|
||||
test "$HASH2" = "$(git replace --list "$aa*")" &&
|
||||
test_must_fail git replace -d $R &&
|
||||
test_must_fail git replace -d &&
|
||||
test_must_fail git replace --delete &&
|
||||
test_must_fail git replace -l -d $HASH2 &&
|
||||
git replace -d $HASH2 &&
|
||||
git show $HASH2 | grep "A U Thor" &&
|
||||
@ -147,7 +147,7 @@ test_expect_success '"git replace" resolves sha1' '
|
||||
git show $HASH2 | grep "O Thor" &&
|
||||
test_must_fail git replace $HASH2 $R &&
|
||||
git replace -f $HASH2 $R &&
|
||||
test_must_fail git replace -f &&
|
||||
test_must_fail git replace --force &&
|
||||
test "$HASH2" = "$(git replace)"
|
||||
'
|
||||
|
||||
@ -263,4 +263,23 @@ test_expect_success 'not just commits' '
|
||||
test_cmp file.replaced file
|
||||
'
|
||||
|
||||
test_expect_success 'replaced and replacement objects must be of the same type' '
|
||||
test_must_fail git replace mytag $HASH1 &&
|
||||
test_must_fail git replace HEAD^{tree} HEAD~1 &&
|
||||
BLOB=$(git rev-parse :file) &&
|
||||
test_must_fail git replace HEAD^ $BLOB
|
||||
'
|
||||
|
||||
test_expect_success '-f option bypasses the type check' '
|
||||
git replace -f mytag $HASH1 &&
|
||||
git replace --force HEAD^{tree} HEAD~1 &&
|
||||
git replace -f HEAD^ $BLOB
|
||||
'
|
||||
|
||||
test_expect_success 'replace ref cleanup' '
|
||||
test -n "$(git replace)" &&
|
||||
git replace -d $(git replace) &&
|
||||
test -z "$(git replace)"
|
||||
'
|
||||
|
||||
test_done
|
||||
|
Loading…
Reference in New Issue
Block a user