1.7 cherry-pick, revert, rebase

Book can be downloaded from here

You have already seen what merge conflicts (the ones that come about when we are merging branches) look like. There are 3 other operations that can produce conflicts:

Even though the basics are the same, each one of the sections of the CB has a different meaning 36 from what they were during a merge.

1.7.1 cherry-pick - Example 12

In git 2.27, this change was introduced:

Listing 1.115:example 12 - change from 3be7efcafceeae34
$ git show --pretty= 3be7efcafceeae34 
diff --git a/commit-graph.c b/commit-graph.c 
index f013a84e29..e4f1a5b2f1 100644 
--- a/commit-graph.c 
+++ b/commit-graph.c 
@@ -23,6 +23,7 @@ 
 #define GRAPH_CHUNKID_DATA 0x43444154 /* "CDAT" */ 
 #define GRAPH_CHUNKID_EXTRAEDGES 0x45444745 /* "EDGE" */ 
 #define GRAPH_CHUNKID_BASE 0x42415345 /* "BASE" */ 
+#define MAX_NUM_CHUNKS 5 
 
 #define GRAPH_DATA_WIDTH (the_hash_algo->rawsz + 16) 
 
@@ -1350,8 +1351,8 @@ static int write_commit_graph_file(struct write_commit_graph_context *ctx) 
        int fd; 
        struct hashfile *f; 
        struct lock_file lk = LOCK_INIT; 
-       uint32_t chunk_ids[6]; 
-       uint64_t chunk_offsets[6]; 
+       uint32_t chunk_ids[MAX_NUM_CHUNKS + 1]; 
+       uint64_t chunk_offsets[MAX_NUM_CHUNKS + 1]; 
        const unsigned hashsz = the_hash_algo->rawsz; 
        struct strbuf progress_title = STRBUF_INIT; 
        int num_chunks = 3;

We can see the way that chunk_ids and chunk_offsets’s sizes are changed to be defined by a macro.

As an experiment, we want to backport this change on top of v2.22.4:

Listing 1.116:example 12 - backporting 3be7efcafceeae34
$ git checkout v2.22.4 
HEAD is now at c9808fa014 Git 2.22.4 
$ git cherry-pick 3be7efcafceeae34 
Auto-merging commit-graph.c 
CONFLICT (content): Merge conflict in commit-graph.c 
error: could not apply 3be7efcafc... commit-graph: define and use MAX_NUM_CHUNKS 
hint: after resolving the conflicts, mark the corrected paths 
hint: with ’git add <paths>’ or ’git rm <paths>’ 
hint: and commit the result with ’git commit’ 
$ git status 
HEAD detached at v2.22.4 
You are currently cherry-picking commit 3be7efcafc. 
  (fix conflicts and run "git cherry-pick --continue") 
  (use "git cherry-pick --skip" to skip this patch) 
  (use "git cherry-pick --abort" to cancel the cherry-pick operation) 
 
Unmerged paths: 
  (use "git add <file>..." to mark resolution) 
        both modified:   commit-graph.c 
 
no changes added to commit (use "git add" and/or "git commit -a")

What does the conflict look like? There are two CBs in commit-graph.c. The first CB looks like this:

CB#1

Listing 1.117:example 12 - CB#1 in commit-graph.c
25<<<<<<< HEAD 
26||||||| parent of 3be7efcafc... commit-graph: define and use MAX_NUM_CHUNKS 
27#define GRAPH_CHUNKID_BASE 0x42415345 /* "BASE" */ 
28======= 
29#define GRAPH_CHUNKID_BASE 0x42415345 /* "BASE" */ 
30#define MAX_NUM_CHUNKS 5 
31>>>>>>> 3be7efcafc... commit-graph: define and use MAX_NUM_CHUNKS

It looks a lot like the conflicts we have seen so far, right? Just like in a merge, there are 3 sections in the CB and I will keep on using the same terms/achronyms we have used so far. The first one is UB, in other words, code as it is on HEAD, in our case, on tag v2.22.4, as that is where we are currently working. Unlike normal merges where we get to see the common ancestor’s code in MB and the other branch’s code in LB, during a cherry-pick operation the other two blocks display something different, as described on the conflict markers. MB shows us the content of the parent of the revision we are trying to cherry-pick37 . LB shows us code as it is on the revision 3be7efcafc, what we are trying to cherry-pick. Even though the MB and LB relate to different concepts from a merge, the way the analysis has to be carried out is the same.

dMU#1

The macro GRAPH_CHUNKID_BASE (present in line 27) was removed.

dML#1

The macro MAX_NUM_CHUNKS was added (line 30).

Resolution#1

I don’t think there’s much difference working from UB or LB.... it’s just a tiny bit simpler to delete things than copying from another place so I will start working from LB:

Listing 1.118:example 12 - LB#1 in commit-graph.c
28======= 
29#define GRAPH_CHUNKID_BASE 0x42415345 /* "BASE" */ 
30#define MAX_NUM_CHUNKS 5 
31>>>>>>> 3be7efcafc... commit-graph: define and use MAX_NUM_CHUNKS

Then, as dMU is requesting, we remove GRAPH_CHUNKID_BASE.

Listing 1.119:example 12 - LB#1 in commit-graph.c
28======= 
29#define MAX_NUM_CHUNKS 5 
30>>>>>>> 3be7efcafc... commit-graph: define and use MAX_NUM_CHUNKS

Remove the other sections of the conflict and the markers and we are done.

Listing 1.120:example 12 - Solution of CB#1 in commit-graph.c
24#define GRAPH_CHUNKID_EXTRAEDGES 0x45444745 /* "EDGE" */ 
25#define MAX_NUM_CHUNKS 5 
26 
27#define GRAPH_DATA_WIDTH (the_hash_algo->rawsz + 16)

And then we go into CB#2 in commit-graph.c: 38

CB#2

Listing 1.121:example 12 - CB#2 in commit-graph.c
1031<<<<<<< HEAD 
1032        uint32_t chunk_ids[5]; 
1033        uint64_t chunk_offsets[5]; 
1034||||||| parent of 3be7efcafc... commit-graph: define and use MAX_NUM_CHUNKS 
1035        uint32_t chunk_ids[6]; 
1036        uint64_t chunk_offsets[6]; 
1037======= 
1038        uint32_t chunk_ids[MAX_NUM_CHUNKS + 1]; 
1039        uint64_t chunk_offsets[MAX_NUM_CHUNKS + 1]; 
1040>>>>>>> 3be7efcafc... commit-graph: define and use MAX_NUM_CHUNKS

dMU#2

The size of chunk_ids and chunk_offsets was changed from 6 to 5.

dML#2

Got rid of the numeric value and replaced it for MAX_NUM_CHUNKS + 1, using the macro we defined on the previous CB.

Resolution#2

In this special case we can keep code from LB as is because the change of 6 for 5 has no incidence on the requirement: We still need to use the macro. So:

Listing 1.122:example 12 - Solution of CB#2 in commit-graph.c
1030        struct lock_file lk = LOCK_INIT; 
1031        uint32_t chunk_ids[MAX_NUM_CHUNKS + 1]; 
1032        uint64_t chunk_offsets[MAX_NUM_CHUNKS + 1]; 
1033        const unsigned hashsz = the_hash_algo->rawsz;

And we are done! ... Or so you think! Do you remember the intent of the revision we are trying to cherry-pick? It was related to changing the way we define the size of the arrays to use a macro. This is probably so that if we needed to change the size of the arrays from 6 to 20 in the future, we would only adjust the value of MAX_NUM_CHUNKS from 5 to 19 and it would hit both arrays at the same time. Nice! But we are not applying it on a revision where the size of the arrays is 6. We have arrays of size 5 and it has to remain the same.39 Which means that we need to set up the macro to 4, so that the arrays end up with the correct original value when using the macro. Then we need to go back to the previous CB and we adjust the macro value:

Listing 1.123:example 12 - Adjustment of Solution of CB#1 in commit-graph.c
24#define GRAPH_CHUNKID_EXTRAEDGES 0x45444745 /* "EDGE" */ 
25#define MAX_NUM_CHUNKS 4 
26 
27#define GRAPH_DATA_WIDTH (the_hash_algo->rawsz + 16)

And now we are done!40

Question: Would it be OK to leave the macro with 5 and change the arrays in CB#2 to use MAX_NUMS_CHUNKS instead? Like this:

Listing 1.124:example 12 - Alternative solution to CB#2 in commit-graph.c
1030        struct lock_file lk = LOCK_INIT; 
1031        uint32_t chunk_ids[MAX_NUM_CHUNKS]; 
1032        uint64_t chunk_offsets[MAX_NUM_CHUNKS]; 
1033        const unsigned hashsz = the_hash_algo->rawsz;

From the plain coding point if view, it might be correct 41. Code compiles and behaves the same, right? But you are breaking the intent of the revision you are cherry-picking. Just so that you can glance the consequences of this decision, what would happen if, later on, you needed to cherry-pick another revision that uses this same macro? Now that you have broken the values that you are using for it, you will have to do more adjustments on the code than the original intent of the other revisions you were cherry-picking then.... and you might not even get conflicts when you cherry-pick them. Will you be able to keep this change in mind so that you are able to catch those situations later on and correct the code? I know I would.... for the first 30 seconds after I modified the code, but I don’t think I would be able to keep it for much longer. And I’m sure it’s extremely unlikey anyone else will keep this in mind. All in all: You better stick to the original intent. You have been forewarned.

1.7.2 revert - Example 13

When you want to take back the changes introduced by a revision, the operation you have to apply is revert 42 . Let’s consider a little case from git.

From git repo, checkout tag v2.26.2. We will revert revision 22a69fda197f. Let me show you what the revision that I want to revert did originally to builtin/rebase.c:

Listing 1.125:example 13 - Original revision
$ git show --pretty="" 22a69fda197f -- builtin/rebase.c 
diff --git a/builtin/rebase.c b/builtin/rebase.c 
index 8081741f8a..faa4e0d406 100644 
--- a/builtin/rebase.c 
+++ b/builtin/rebase.c 
@@ -453,8 +453,9 @@ int cmd_rebase__interactive(int argc, const char **argv, const char *prefix) 
                OPT_NEGBIT(0, "ff", &opts.flags, N_("allow fast-forward"), 
                           REBASE_FORCE), 
                OPT_BOOL(0, "keep-empty", &opts.keep_empty, N_("keep empty commits")), 
-               OPT_BOOL(0, "allow-empty-message", &opts.allow_empty_message, 
-                        N_("allow commits with empty messages")), 
+               OPT_BOOL_F(0, "allow-empty-message", &opts.allow_empty_message, 
+                          N_("allow commits with empty messages"), 
+                          PARSE_OPT_HIDDEN), 
                OPT_BOOL(0, "rebase-merges", &opts.rebase_merges, N_("rebase merge commits")), 
                OPT_BOOL(0, "rebase-cousins", &opts.rebase_cousins, 
                         N_("keep original branch points of cousins")), 
@@ -1495,9 +1496,10 @@ int cmd_rebase(int argc, const char **argv, const char *prefix) 
                OPT_STRING_LIST(’x’, "exec", &exec, N_("exec"), 
                                N_("add exec lines after each commit of the " 
                                   "editable list")), 
-               OPT_BOOL(0, "allow-empty-message", 
-                        &options.allow_empty_message, 
-                        N_("allow rebasing commits with empty messages")), 
+               OPT_BOOL_F(0, "allow-empty-message", 
+                          &options.allow_empty_message, 
+                          N_("allow rebasing commits with empty messages"), 
+                          PARSE_OPT_HIDDEN), 
                {OPTION_STRING, ’r’, "rebase-merges", &rebase_merges, 
                        N_("mode"), 
                        N_("try to rebase merges instead of skipping them"),

The revision we want to revert changed the original calls to OPT_BOOL() for defining allow-empty-message to OPT_BOOL_F() and adjusted the parameters. That means that if we want to revert this revision, we need to end up with the original OPT_BOOL() call to define allow-empty-message in place after the revert is finished, right? Let’s try:

Listing 1.126:example 13 - Reverting
$ git revert --no-commit 22a69fda197f 
Auto-merging builtin/rebase.c 
CONFLICT (content): Merge conflict in builtin/rebase.c 
Auto-merging Documentation/git-rebase.txt 
error: could not revert 22a69fda19... git-rebase.txt: update description of --allow-empty-message 
hint: after resolving the conflicts, mark the corrected paths 
hint: with ’git add <paths>’ or ’git rm <paths>’ 
$ git status 
HEAD detached at v2.26.2 
You are currently reverting commit 22a69fda19. 
  (fix conflicts and run "git revert --continue") 
  (use "git revert --skip" to skip this patch) 
  (use "git revert --abort" to cancel the revert operation) 
 
Changes to be committed: 
  (use "git restore --staged <file>..." to unstage) 
        modified:   Documentation/git-rebase.txt 
 
Unmerged paths: 
  (use "git restore --staged <file>..." to unstage) 
  (use "git add <file>..." to mark resolution) 
        both modified:   builtin/rebase.c

There is a CB in builtin/rebase.c:

Listing 1.127:example 13 - CB in builtin/rebase.c
473<<<<<<< HEAD 
474                { OPTION_CALLBACK, ’k’, "keep-empty", &options, NULL, 
475                        N_("(DEPRECATED) keep empty commits"), 
476                        PARSE_OPT_NOARG | PARSE_OPT_HIDDEN, 
477                        parse_opt_keep_empty }, 
478                OPT_BOOL_F(0, "allow-empty-message", &opts.allow_empty_message, 
479                           N_("allow commits with empty messages"), 
480                           PARSE_OPT_HIDDEN), 
481||||||| 22a69fda19... git-rebase.txt: update description of --allow-empty-message 
482                OPT_BOOL(0, "keep-empty", &opts.keep_empty, N_("keep empty commits")), 
483                OPT_BOOL_F(0, "allow-empty-message", &opts.allow_empty_message, 
484                           N_("allow commits with empty messages"), 
485                           PARSE_OPT_HIDDEN), 
486======= 
487                OPT_BOOL(0, "keep-empty", &opts.keep_empty, N_("keep empty commits")), 
488                OPT_BOOL(0, "allow-empty-message", &opts.allow_empty_message, 
489                         N_("allow commits with empty messages")), 
490>>>>>>> parent of 22a69fda19... git-rebase.txt: update description of --allow-empty-message

This is not too different from what we saw in cherry-pick, right? UB is the way the code is on v2.26.2, as that is the revision we started working from. The interesting part is in the other two blocks. You can see from the markers that MB is the way code looked on the revision we are trying to revert (in other words, the code the way it looked after the revision was applied) and LB is the way code looks on its parent revision (in other words, the way the code looked before) 43. This means that we, just like in the merges and cherry-picks we have already solved, need to go through dMU and dML without any changes in methodology so it’s business as usual.

dMU

The way keep-empty is defined is changed from a call to OPT_BOOL() in line 482 to a hand-made definition in lines 474-477.

dML

The way allow-empty-message is defined is changed from a call to OPT_BOOL_F() in lines 483-485 to OPT_BOOL() in lines 488-489, which also removed PARSE_OPT_HIDDEN as a parameter to the new call.

Resolution

I will stay working on UB, just because the way keep-empty was changed from the MB is bigger than the change that was done for allow-empty-message in dML. Then I will change the macro call from OPT_BOOL_F() to OPT_BOOL() (lines 478-480):

Listing 1.128:example 13 - Step 1 UB in builtin/rebase.c
473<<<<<<< HEAD 
474                { OPTION_CALLBACK, ’k’, "keep-empty", &options, NULL, 
475                        N_("(DEPRECATED) keep empty commits"), 
476                        PARSE_OPT_NOARG | PARSE_OPT_HIDDEN, 
477                        parse_opt_keep_empty }, 
478                OPT_BOOL_F(0, "allow-empty-message", &opts.allow_empty_message, 
479                           N_("allow commits with empty messages"), 
480                           PARSE_OPT_HIDDEN), 
481||||||| 22a69fda19... git-rebase.txt: update description of --allow-empty-message

Remove PARSE_OPT_HIDDEN as a parameter (present on line 480):

Listing 1.129:example 13 - Step 2 UB in builtin/rebase.c
473<<<<<<< HEAD 
474                { OPTION_CALLBACK, ’k’, "keep-empty", &options, NULL, 
475                        N_("(DEPRECATED) keep empty commits"), 
476                        PARSE_OPT_NOARG | PARSE_OPT_HIDDEN, 
477                        parse_opt_keep_empty }, 
478                OPT_BOOL(0, "allow-empty-message", &opts.allow_empty_message, 
479                           N_("allow commits with empty messages")), 
480||||||| 22a69fda19... git-rebase.txt: update description of --allow-empty-message

Reposition the second line for the argument on the second line of the macro call to align with the position of the call (line 479):

Listing 1.130:example 13 - Step 3 UB in builtin/rebase.c
473<<<<<<< HEAD 
474                { OPTION_CALLBACK, ’k’, "keep-empty", &options, NULL, 
475                        N_("(DEPRECATED) keep empty commits"), 
476                        PARSE_OPT_NOARG | PARSE_OPT_HIDDEN, 
477                        parse_opt_keep_empty }, 
478                OPT_BOOL(0, "allow-empty-message", &opts.allow_empty_message, 
479                         N_("allow commits with empty messages")), 
480||||||| 22a69fda19... git-rebase.txt: update description of --allow-empty-message

And now we are done with the reversion:

Listing 1.131:example 13 - Solution of CB in builtin/rebase.c
470        struct option options[] = { 
471                OPT_NEGBIT(0, "ff", &opts.flags, N_("allow fast-forward"), 
472                           REBASE_FORCE), 
473                { OPTION_CALLBACK, ’k’, "keep-empty", &options, NULL, 
474                        N_("(DEPRECATED) keep empty commits"), 
475                        PARSE_OPT_NOARG | PARSE_OPT_HIDDEN, 
476                        parse_opt_keep_empty }, 
477                OPT_BOOL(0, "allow-empty-message", &opts.allow_empty_message, 
478                         N_("allow commits with empty messages"), 
479                OPT_BOOL(0, "rebase-merges", &opts.rebase_merges, N_("rebase merge commits")),

And we can see how we ended up with a call to OPT_BOOL() to define allow-empty-message, just what we wanted to get with the reversion.

Just so that you can see that the same rules apply when analyzing a reversion, try solving the conflict working from LB and bring over the changes introduced in dMU. You should end up with the same code.

1.7.3 rebase - Example 14

Let’s play a little bit. From git repo, checkout revision ce9baf234f. Let’s take a look at a section of builtin/push.c on this revision:

Listing 1.132:example 14 - Section of builtin/push.c in ce9baf234f
548                OPT_BIT(’f’, "force", &flags, N_("force updates"), TRANSPORT_PUSH_FORCE), 
549                { OPTION_CALLBACK, 
550                  0, CAS_OPT_NAME, &cas, N_("<refname>:<expect>"), 
551                  N_("require old value of ref to be at this value"), 
552                  PARSE_OPT_OPTARG | PARSE_OPT_LITERAL_ARGHELP, parseopt_push_cas_option }, 
553                OPT_CALLBACK(0, "recurse-submodules", &recurse_submodules, "(check|on-demand|no)", 
554                             N_("control recursive pushing of submodules"), option_parse_recurse_submodules), 
555                OPT_BOOL_F( 0 , "thin", &thin, N_("use thin pack"), PARSE_OPT_NOCOMPLETE),

Take a close look at the way <refname>:<expect> and recurse-submodules are defined. <refname>:<expect> is defined using a struct by hand in lines 549-552 and recurse-submodules is defined with a call to OPT_CALLBACK() in lines 553-554.

Let’s ask git to rebase on top of 665271620044 . You should see a CB related to the section of builtin/push.c that I showed you before:

Listing 1.133:example 14 - CB in builtin/push.c
550                OPT_BIT(’f’, "force", &flags, N_("force updates"), TRANSPORT_PUSH_FORCE), 
551<<<<<<< HEAD 
552                OPT_CALLBACK_F(0, CAS_OPT_NAME, &cas, N_("<refname>:<expect>"), 
553                               N_("require old value of ref to be at this value"), 
554                               PARSE_OPT_OPTARG | PARSE_OPT_LITERAL_ARGHELP, parseopt_push_cas_option), 
555                { OPTION_CALLBACK, 0, "recurse-submodules", &recurse_submodules, "(check|on-demand|no)", 
556                        N_("control recursive pushing of submodules"), 
557                        PARSE_OPT_OPTARG, option_parse_recurse_submodules }, 
558||||||| parent of ce9baf234f... push: unset PARSE_OPT_OPTARG for --recurse-submodules 
559                { OPTION_CALLBACK, 
560                  0, CAS_OPT_NAME, &cas, N_("<refname>:<expect>"), 
561                  N_("require old value of ref to be at this value"), 
562                  PARSE_OPT_OPTARG | PARSE_OPT_LITERAL_ARGHELP, parseopt_push_cas_option }, 
563                { OPTION_CALLBACK, 0, "recurse-submodules", &recurse_submodules, "(check|on-demand|no)", 
564                        N_("control recursive pushing of submodules"), 
565                        PARSE_OPT_OPTARG, option_parse_recurse_submodules }, 
566======= 
567                { OPTION_CALLBACK, 
568                  0, CAS_OPT_NAME, &cas, N_("<refname>:<expect>"), 
569                  N_("require old value of ref to be at this value"), 
570                  PARSE_OPT_OPTARG | PARSE_OPT_LITERAL_ARGHELP, parseopt_push_cas_option }, 
571                OPT_CALLBACK(0, "recurse-submodules", &recurse_submodules, "(check|on-demand|no)", 
572                             N_("control recursive pushing of submodules"), option_parse_recurse_submodules), 
573>>>>>>> ce9baf234f... push: unset PARSE_OPT_OPTARG for --recurse-submodules 
574                OPT_BOOL_F( 0 , "thin", &thin, N_("use thin pack"), PARSE_OPT_NOCOMPLETE),

You remember the revision you were on when you ran rebase? It was on ce9baf234f, right? Look at UB. Does it look the way it was in ce9baf234f? No? Ok. How about LB? Oh, it’s there! And then, what is on UB? You remember that I said that UB always contains code as it is in HEAD? Well, that is correct, even in this case. The trick that you have to realize is that when you run a rebase git first checks out the base branch for the rebase and then starts to apply the revisions that you ask to rebase on top of the base branch.

So, in our current example, in UB you will see the code as it is in 6652716200 and in LB you will see the code from ce9baf234f. In MB you will see the parent of the revision that is being rebased at the time, so in this case it will hold the parent of ce9baf234f. You can see the details about the revision used in MB and LB in the conflict markers, just in case.

Now that we have cleared that up, we continue with the analysis as we have done so far, no changes:

dMU

The way that <refname>:<expect> is being defined is from by-hand in lines 559-562 to a call to OPT_CALLBACK_F() in lines 552-554.

dML

The way recurse-submodules is being defined is changed from by hand in lines 563-565 to a call to OPT_CALLBACK() in lines 571-572.

Resolution

I don’t see much difference between working from UB and LB. Let’s start working from UB:

Listing 1.134:example 14 - Step 1 UB in builtin/push.c
550<<<<<<< HEAD 
551                OPT_CALLBACK_F(0, CAS_OPT_NAME, &cas, N_("<refname>:<expect>"), 
552                               N_("require old value of ref to be at this value"), 
553                               PARSE_OPT_OPTARG | PARSE_OPT_LITERAL_ARGHELP, parseopt_push_cas_option), 
554                { OPTION_CALLBACK, 0, "recurse-submodules", &recurse_submodules, "(check|on-demand|no)", 
555                        N_("control recursive pushing of submodules"), 
556                        PARSE_OPT_OPTARG, option_parse_recurse_submodules }, 
557||||||| parent of ce9baf234f... push: unset PARSE_OPT_OPTARG for --recurse-submodules

Then we modify the way that recurse-submodules is defined as in dML:

Listing 1.135:example 14 - Step 2 UB in builtin/push.c
550<<<<<<< HEAD 
551                OPT_CALLBACK_F(0, CAS_OPT_NAME, &cas, N_("<refname>:<expect>"), 
552                               N_("require old value of ref to be at this value"), 
553                               PARSE_OPT_OPTARG | PARSE_OPT_LITERAL_ARGHELP, parseopt_push_cas_option), 
554                OPT_CALLBACK(0, "recurse-submodules", &recurse_submodules, "(check|on-demand|no)", 
555                             N_("control recursive pushing of submodules"), option_parse_recurse_submodules), 
556||||||| parent of ce9baf234f... push: unset PARSE_OPT_OPTARG for --recurse-submodules

And we are done:

Listing 1.136:example 14 - Solution of CB in builtin/push.c
550                OPT_BIT(’f’, "force", &flags, N_("force updates"), TRANSPORT_PUSH_FORCE), 
551                OPT_CALLBACK_F(0, CAS_OPT_NAME, &cas, N_("<refname>:<expect>"), 
552                               N_("require old value of ref to be at this value"), 
553                               PARSE_OPT_OPTARG | PARSE_OPT_LITERAL_ARGHELP, parseopt_push_cas_option), 
554                OPT_CALLBACK(0, "recurse-submodules", &recurse_submodules, "(check|on-demand|no)", 
555                             N_("control recursive pushing of submodules"), option_parse_recurse_submodules), 
556                OPT_BOOL_F( 0 , "thin", &thin, N_("use thin pack"), PARSE_OPT_NOCOMPLETE),

We add the file to index, nothing else is pending and so we can continue with the rebase 45 .

1.7.4 Tips

Regarless of the operation being done (merge, cherry-pick, revert, rebase), always use the same technique to solve conflicts: dMU/dML, Resolution.

Copyright 2020 Edmundo Carmona Antoranz