1
0
Fork 0
mirror of https://github.com/git/git.git synced 2024-05-25 12:26:12 +02:00

checkout --ours/--theirs: allow checking out one side of a conflicting merge

This lets you to check out 'our' (or 'their') version of an
unmerged path out of the index while resolving conflicts.

Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Junio C Hamano 2008-08-30 07:48:18 -07:00
parent db9410990e
commit 38901a4837
3 changed files with 72 additions and 3 deletions

View File

@ -9,7 +9,7 @@ SYNOPSIS
--------
[verse]
'git checkout' [-q] [-f] [[--track | --no-track] -b <new_branch> [-l]] [-m] [<branch>]
'git checkout' [-f] [<tree-ish>] [--] <paths>...
'git checkout' [-f|--ours|--theirs] [<tree-ish>] [--] <paths>...
DESCRIPTION
-----------
@ -33,7 +33,9 @@ working tree.
The index may contain unmerged entries after a failed merge. By
default, if you try to check out such an entry from the index, the
checkout operation will fail and nothing will be checked out.
Using -f will ignore these unmerged entries.
Using -f will ignore these unmerged entries. The contents from a
specific side of the merge can be checked out of the index by
using --ours or --theirs.
OPTIONS
-------
@ -48,6 +50,11 @@ OPTIONS
When checking out paths from the index, do not fail upon unmerged
entries; instead, unmerged entries are ignored.
--ours::
--theirs::
When checking out paths from the index, check out stage #2
('ours') or #3 ('theirs') for unmerged paths.
-b::
Create a new branch named <new_branch> and start it at
<branch>. The new branch name must pass all checks defined

View File

@ -24,6 +24,7 @@ struct checkout_opts {
int quiet;
int merge;
int force;
int writeout_stage;
int writeout_error;
const char *new_branch;
@ -95,6 +96,32 @@ static int skip_same_name(struct cache_entry *ce, int pos)
return pos;
}
static int check_stage(int stage, struct cache_entry *ce, int pos)
{
while (pos < active_nr &&
!strcmp(active_cache[pos]->name, ce->name)) {
if (ce_stage(active_cache[pos]) == stage)
return 0;
pos++;
}
return error("path '%s' does not have %s version",
ce->name,
(stage == 2) ? "our" : "their");
}
static int checkout_stage(int stage, struct cache_entry *ce, int pos,
struct checkout *state)
{
while (pos < active_nr &&
!strcmp(active_cache[pos]->name, ce->name)) {
if (ce_stage(active_cache[pos]) == stage)
return checkout_entry(active_cache[pos], state, NULL);
pos++;
}
return error("path '%s' does not have %s version",
ce->name,
(stage == 2) ? "our" : "their");
}
static int checkout_paths(struct tree *source_tree, const char **pathspec,
struct checkout_opts *opts)
@ -106,7 +133,7 @@ static int checkout_paths(struct tree *source_tree, const char **pathspec,
int flag;
struct commit *head;
int errs = 0;
int stage = opts->writeout_stage;
int newfd;
struct lock_file *lock_file = xcalloc(1, sizeof(struct lock_file));
@ -136,6 +163,8 @@ static int checkout_paths(struct tree *source_tree, const char **pathspec,
continue;
if (opts->force) {
warning("path '%s' is unmerged", ce->name);
} else if (stage) {
errs |= check_stage(stage, ce, pos);
} else {
errs = 1;
error("path '%s' is unmerged", ce->name);
@ -157,6 +186,8 @@ static int checkout_paths(struct tree *source_tree, const char **pathspec,
errs |= checkout_entry(ce, &state, NULL);
continue;
}
if (stage)
errs |= checkout_stage(stage, ce, pos, &state);
pos = skip_same_name(ce, pos) - 1;
}
}
@ -458,6 +489,10 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
OPT_BOOLEAN('l', NULL, &opts.new_branch_log, "log for new branch"),
OPT_SET_INT('t', "track", &opts.track, "track",
BRANCH_TRACK_EXPLICIT),
OPT_SET_INT('2', "ours", &opts.writeout_stage, "stage",
2),
OPT_SET_INT('3', "theirs", &opts.writeout_stage, "stage",
3),
OPT_BOOLEAN('f', NULL, &opts.force, "force"),
OPT_BOOLEAN('m', NULL, &opts.merge, "merge"),
OPT_END(),
@ -573,6 +608,8 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
if (new.name && !new.commit) {
die("Cannot switch branch to a non-commit.");
}
if (opts.writeout_stage)
die("--ours/--theirs is incompatible with switching branches.");
return switch_branches(&opts, &new);
}

View File

@ -382,4 +382,29 @@ test_expect_success 'checkout with an unmerged path can be ignored' '
test_cmp sample file
'
test_expect_success 'checkout unmerged stage' '
rm -f .git/index &&
O=$(echo original | git hash-object -w --stdin) &&
A=$(echo ourside | git hash-object -w --stdin) &&
B=$(echo theirside | git hash-object -w --stdin) &&
(
echo "100644 $A 0 fild" &&
echo "100644 $O 1 file" &&
echo "100644 $A 2 file" &&
echo "100644 $B 3 file" &&
echo "100644 $A 0 filf"
) | git update-index --index-info &&
echo "none of the above" >sample &&
echo ourside >expect &&
cat sample >fild &&
cat sample >file &&
cat sample >filf &&
git checkout --ours . &&
test_cmp expect fild &&
test_cmp expect filf &&
test_cmp expect file &&
git checkout --theirs file &&
test ztheirside = "z$(cat file)"
'
test_done