mirror of
https://github.com/git/git.git
synced 2026-01-27 17:27:19 +09:00
Merge branch 'en/ps-history-some' into seen
* en/ps-history-some: history: fix detached HEAD handling SQUASH ME: Fixups
This commit is contained in:
commit
7cfdc50b1b
@ -63,7 +63,7 @@ OPTIONS
|
||||
`--ref-action=(branches|head|print)`::
|
||||
Control which references will be updated by the command, if any. With
|
||||
`branches`, all local branches that point to commits which are
|
||||
decendants of the original commit will be rewritten. With `head`, only
|
||||
descendants of the original commit will be rewritten. With `head`, only
|
||||
the current `HEAD` reference will be rewritten. With `print`, all
|
||||
updates as they would be performed with `branches` are printed in a
|
||||
format that can be consumed by linkgit:git-update-ref[1].
|
||||
|
||||
@ -178,17 +178,23 @@ static int handle_reference_updates(enum ref_action action,
|
||||
{
|
||||
const struct name_decoration *decoration;
|
||||
struct replay_revisions_options opts = { 0 };
|
||||
struct replay_result result = {
|
||||
.final_oid = rewritten->object.oid,
|
||||
};
|
||||
struct replay_result result = { 0 };
|
||||
struct ref_transaction *transaction = NULL;
|
||||
struct strvec args = STRVEC_INIT;
|
||||
struct strbuf err = STRBUF_INIT;
|
||||
struct commit *head = NULL;
|
||||
char *head_ref = NULL;
|
||||
bool detached_head = false;
|
||||
struct rev_info revs;
|
||||
char hex[GIT_MAX_HEXSZ + 1];
|
||||
int ret;
|
||||
|
||||
head_ref = refs_resolve_refdup(get_main_ref_store(repo), "HEAD",
|
||||
RESOLVE_REF_READING, NULL, NULL);
|
||||
if (!strcmp(head_ref, "HEAD"))
|
||||
detached_head = true;
|
||||
free(head_ref);
|
||||
|
||||
repo_init_revisions(repo, &revs, NULL);
|
||||
strvec_push(&args, "ignored");
|
||||
strvec_push(&args, "--reverse");
|
||||
@ -233,9 +239,10 @@ static int handle_reference_updates(enum ref_action action,
|
||||
goto out;
|
||||
}
|
||||
|
||||
strvec_push(&args, oid_to_hex(&head->object.oid));
|
||||
strvec_push(&args, "HEAD");
|
||||
} else {
|
||||
strvec_push(&args, "--branches");
|
||||
strvec_push(&args, "HEAD");
|
||||
}
|
||||
|
||||
setup_revisions_from_strvec(&args, &revs, NULL);
|
||||
@ -244,13 +251,14 @@ static int handle_reference_updates(enum ref_action action,
|
||||
|
||||
opts.onto = oid_to_hex_r(hex, &rewritten->object.oid);
|
||||
|
||||
ret = replay_revisions(repo, &revs, &opts, &result);
|
||||
ret = replay_revisions(&revs, &opts, &result);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
switch (action) {
|
||||
case REF_ACTION_DEFAULT:
|
||||
case REF_ACTION_BRANCHES:
|
||||
case REF_ACTION_HEAD:
|
||||
transaction = ref_store_transaction_begin(get_main_ref_store(repo), 0, &err);
|
||||
if (!transaction) {
|
||||
ret = error(_("failed to begin ref transaction: %s"), err.buf);
|
||||
@ -279,9 +287,11 @@ static int handle_reference_updates(enum ref_action action,
|
||||
decoration;
|
||||
decoration = decoration->next)
|
||||
{
|
||||
if (decoration->type != DECORATION_REF_LOCAL)
|
||||
if ((decoration->type != DECORATION_REF_HEAD ||
|
||||
(action != REF_ACTION_HEAD && !detached_head)) &&
|
||||
(decoration->type != DECORATION_REF_LOCAL ||
|
||||
action == REF_ACTION_HEAD))
|
||||
continue;
|
||||
|
||||
ret = ref_transaction_update(transaction,
|
||||
decoration->name,
|
||||
&rewritten->object.oid,
|
||||
@ -300,13 +310,6 @@ static int handle_reference_updates(enum ref_action action,
|
||||
}
|
||||
|
||||
break;
|
||||
case REF_ACTION_HEAD:
|
||||
ret = refs_update_ref(get_main_ref_store(repo), reflog_msg, "HEAD",
|
||||
&result.final_oid, &head->object.oid, 0,
|
||||
UPDATE_REFS_MSG_ON_ERR);
|
||||
if (ret)
|
||||
goto out;
|
||||
break;
|
||||
case REF_ACTION_PRINT:
|
||||
for (size_t i = 0; i < result.updates_nr; i++)
|
||||
printf("update %s %s %s\n",
|
||||
|
||||
@ -167,7 +167,7 @@ int cmd_replay(int argc,
|
||||
revs.simplify_history = 0;
|
||||
}
|
||||
|
||||
ret = replay_revisions(repo, &revs, &opts, &result);
|
||||
ret = replay_revisions(&revs, &opts, &result);
|
||||
if (ret)
|
||||
goto cleanup;
|
||||
|
||||
@ -220,11 +220,5 @@ cleanup:
|
||||
strbuf_release(&reflog_msg);
|
||||
release_revisions(&revs);
|
||||
|
||||
if (ret) {
|
||||
if (result.merge_conflict)
|
||||
return 1;
|
||||
return 128;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
28
replay.c
28
replay.c
@ -5,11 +5,11 @@
|
||||
#include "hex.h"
|
||||
#include "merge-ort.h"
|
||||
#include "object-name.h"
|
||||
#include "oidset.h"
|
||||
#include "parse-options.h"
|
||||
#include "refs.h"
|
||||
#include "replay.h"
|
||||
#include "revision.h"
|
||||
#include "strmap.h"
|
||||
#include "tree.h"
|
||||
|
||||
static const char *short_commit_name(struct repository *repo,
|
||||
@ -151,11 +151,20 @@ static void get_ref_information(struct repository *repo,
|
||||
static void set_up_replay_mode(struct repository *repo,
|
||||
struct rev_cmdline_info *cmd_info,
|
||||
const char *onto_name,
|
||||
bool *detached_head,
|
||||
char **advance_name,
|
||||
struct commit **onto,
|
||||
struct strset **update_refs)
|
||||
{
|
||||
struct ref_info rinfo;
|
||||
char *head_ref;
|
||||
|
||||
*detached_head = false;
|
||||
head_ref = refs_resolve_refdup(get_main_ref_store(repo), "HEAD",
|
||||
RESOLVE_REF_READING, NULL, NULL);
|
||||
if (!strcmp(head_ref, "HEAD"))
|
||||
*detached_head = true;
|
||||
free(head_ref);
|
||||
|
||||
get_ref_information(repo, cmd_info, &rinfo);
|
||||
if (!rinfo.positive_refexprs)
|
||||
@ -256,7 +265,7 @@ static void replay_result_queue_update(struct replay_result *result,
|
||||
result->updates_nr++;
|
||||
}
|
||||
|
||||
int replay_revisions(struct repository *repo, struct rev_info *revs,
|
||||
int replay_revisions(struct rev_info *revs,
|
||||
struct replay_revisions_options *opts,
|
||||
struct replay_result *out)
|
||||
{
|
||||
@ -265,16 +274,18 @@ int replay_revisions(struct repository *repo, struct rev_info *revs,
|
||||
struct commit *last_commit = NULL;
|
||||
struct commit *commit;
|
||||
struct commit *onto = NULL;
|
||||
struct repository *repo = revs->repo;
|
||||
struct merge_options merge_opt;
|
||||
struct merge_result result = {
|
||||
.clean = 1,
|
||||
};
|
||||
char *advance;
|
||||
bool detached_head;
|
||||
int ret;
|
||||
|
||||
advance = xstrdup_or_null(opts->advance);
|
||||
set_up_replay_mode(repo, &revs->cmdline, opts->onto, &advance,
|
||||
&onto, &update_refs);
|
||||
set_up_replay_mode(repo, &revs->cmdline, opts->onto,
|
||||
&detached_head, &advance, &onto, &update_refs);
|
||||
|
||||
/* FIXME: Should allow replaying commits with the first as a root commit */
|
||||
|
||||
@ -316,7 +327,9 @@ int replay_revisions(struct repository *repo, struct rev_info *revs,
|
||||
if (!decoration)
|
||||
continue;
|
||||
while (decoration) {
|
||||
if (decoration->type == DECORATION_REF_LOCAL &&
|
||||
if ((decoration->type == DECORATION_REF_LOCAL ||
|
||||
(decoration->type == DECORATION_REF_HEAD &&
|
||||
detached_head)) &&
|
||||
(opts->contained || strset_contains(update_refs,
|
||||
decoration->name))) {
|
||||
replay_result_queue_update(out, decoration->name,
|
||||
@ -328,8 +341,7 @@ int replay_revisions(struct repository *repo, struct rev_info *revs,
|
||||
}
|
||||
|
||||
if (!result.clean) {
|
||||
out->merge_conflict = true;
|
||||
ret = -1;
|
||||
ret = 1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
@ -339,8 +351,6 @@ int replay_revisions(struct repository *repo, struct rev_info *revs,
|
||||
&onto->object.oid,
|
||||
&last_commit->object.oid);
|
||||
|
||||
out->final_oid = last_commit->object.oid;
|
||||
|
||||
ret = 0;
|
||||
|
||||
out:
|
||||
|
||||
21
replay.h
21
replay.h
@ -43,25 +43,6 @@ struct replay_result {
|
||||
struct object_id new_oid;
|
||||
} *updates;
|
||||
size_t updates_nr, updates_alloc;
|
||||
|
||||
/* Set to true in case the replay failed with a merge conflict. */
|
||||
bool merge_conflict;
|
||||
|
||||
/*
|
||||
* The final object ID that was rewritten. Note that this field has
|
||||
* somewhat special semantics and may or may not be what you want:
|
||||
*
|
||||
* - If no commits were rewritten it will remain uninitialized.
|
||||
*
|
||||
* - If a thicket of branches is rewritten it is undefined in which
|
||||
* order those branches will be rewritten, and thus the final object
|
||||
* ID may point to a different commit than you'd expect.
|
||||
*
|
||||
* That being said, this field can still be useful when you know that
|
||||
* you only replay a single strand of commits. In that case, the final
|
||||
* commit will point to the tip of the rewritten strand of commits.
|
||||
*/
|
||||
struct object_id final_oid;
|
||||
};
|
||||
|
||||
void replay_result_release(struct replay_result *result);
|
||||
@ -73,7 +54,7 @@ void replay_result_release(struct replay_result *result);
|
||||
*
|
||||
* Returns 0 on success, a negative error code otherwise.
|
||||
*/
|
||||
int replay_revisions(struct repository *repo, struct rev_info *revs,
|
||||
int replay_revisions(struct rev_info *revs,
|
||||
struct replay_revisions_options *opts,
|
||||
struct replay_result *out);
|
||||
|
||||
|
||||
@ -77,6 +77,53 @@ test_expect_success 'can reword commit in the middle' '
|
||||
)
|
||||
'
|
||||
|
||||
test_expect_success 'can reword commit in the middle even on detached head' '
|
||||
test_when_finished "rm -rf repo" &&
|
||||
git init repo &&
|
||||
(
|
||||
cd repo &&
|
||||
test_commit first &&
|
||||
test_commit second &&
|
||||
test_commit third_on_main &&
|
||||
git checkout --detach HEAD^ &&
|
||||
test_commit third_on_head &&
|
||||
|
||||
reword_with_message HEAD~ <<-EOF &&
|
||||
second reworded
|
||||
EOF
|
||||
|
||||
expect_log HEAD --branches --graph <<-\EOF
|
||||
* third_on_head
|
||||
| * third_on_main
|
||||
|/
|
||||
* second reworded
|
||||
* first
|
||||
EOF
|
||||
)
|
||||
'
|
||||
|
||||
test_expect_success 'can reword the detached head' '
|
||||
test_when_finished "rm -rf repo" &&
|
||||
git init repo &&
|
||||
(
|
||||
cd repo &&
|
||||
test_commit first &&
|
||||
test_commit second &&
|
||||
git checkout --detach HEAD &&
|
||||
test_commit third &&
|
||||
|
||||
reword_with_message HEAD <<-EOF &&
|
||||
third reworded
|
||||
EOF
|
||||
|
||||
expect_log <<-\EOF
|
||||
third reworded
|
||||
second
|
||||
first
|
||||
EOF
|
||||
)
|
||||
'
|
||||
|
||||
test_expect_success 'can reword root commit' '
|
||||
test_when_finished "rm -rf repo" &&
|
||||
git init repo &&
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user