pull: ff --rebase --autostash works in dirty repo
When `git pull --rebase --autostash` in a dirty repository resulted in a fast-forward, nothing was being autostashed and the pull failed. This was due to a shortcut to avoid running rebase when we can fast-forward, but autostash is ignored on that codepath. Now we will only take the shortcut if autostash is not in effect. Based on a few tests against the git.git repo, the shortcut does not seem to give us significant performance benefits, on Linux at least. Regardless, it is more important to be correct than to be fast. Signed-off-by: Tyler Brazier <tyler@tylerbrazier.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Tyler Brazier committed
Jun 1, 2017 at 04:18 UTC
f15e7cf5cc95cbfd0d05c260f75631781e290edc
2 files changed
+32
-11
builtin/pull.c
+14
-11
@@ -772,6 +772,7 @@ int cmd_pull(int argc, const char **argv, const char *prefix)
772
struct oid_array merge_heads = OID_ARRAY_INIT;
773
struct object_id orig_head, curr_head;
774
struct object_id rebase_fork_point;
775
+ int autostash;
776
777
if (!getenv("GIT_REFLOG_ACTION"))
778
set_reflog_message(argc, argv);
@@ -800,8 +801,8 @@ int cmd_pull(int argc, const char **argv, const char *prefix)
801
if (!opt_rebase && opt_autostash != -1)
802
die(_("--[no-]autostash option is only valid with --rebase."));
803
804
+ autostash = config_autostash;
805
if (opt_rebase) {
804
- int autostash = config_autostash;
806
if (opt_autostash != -1)
807
autostash = opt_autostash;
808
@@ -862,16 +863,18 @@ int cmd_pull(int argc, const char **argv, const char *prefix)
863
die(_("Cannot rebase onto multiple branches."));
864
865
if (opt_rebase) {
865
- struct commit_list *list = NULL;
866
- struct commit *merge_head, *head;
867
-
868
- head = lookup_commit_reference(orig_head.hash);
869
- commit_list_insert(head, &list);
870
- merge_head = lookup_commit_reference(merge_heads.oid[0].hash);
871
- if (is_descendant_of(merge_head, list)) {
872
- /* we can fast-forward this without invoking rebase */
873
- opt_ff = "--ff-only";
874
- return run_merge();
866
+ if (!autostash) {
867
+ struct commit_list *list = NULL;
868
+ struct commit *merge_head, *head;
869
+
870
+ head = lookup_commit_reference(orig_head.hash);
871
+ commit_list_insert(head, &list);
872
+ merge_head = lookup_commit_reference(merge_heads.oid[0].hash);
873
+ if (is_descendant_of(merge_head, list)) {
874
+ /* we can fast-forward this without invoking rebase */
875
+ opt_ff = "--ff-only";
876
+ return run_merge();
877
+ }
878
}
879
return run_rebase(&curr_head, merge_heads.oid, &rebase_fork_point);
880
} else {
t/t5520-pull.sh
+18
@@ -272,6 +272,24 @@ test_expect_success '--rebase fast forward' '
272
test_cmp reflog.expected reflog.fuzzy
273
'
274
275
+test_expect_success '--rebase --autostash fast forward' '
276
+ test_when_finished "
277
+ git reset --hard
278
+ git checkout to-rebase
279
+ git branch -D to-rebase-ff
280
+ git branch -D behind" &&
281
+ git branch behind &&
282
+ git checkout -b to-rebase-ff &&
283
+ echo another modification >>file &&
284
+ git add file &&
285
+ git commit -m mod &&
286
+
287
+ git checkout behind &&
288
+ echo dirty >file &&
289
+ git pull --rebase --autostash . to-rebase-ff &&
290
+ test "$(git rev-parse HEAD)" = "$(git rev-parse to-rebase-ff)"
291
+'
292
+
293
test_expect_success '--rebase with conflicts shows advice' '
294
test_when_finished "git rebase --abort; git checkout -f to-rebase" &&
295
git checkout -b seq &&