0

enter image description here I want to create experimental branch from develop and rebase feature branch that has 2 commits to it but something I make mistake and the result is like in this question : How to remove first commit of a specific branch?
Now I can fix by the solution of Mr.Gaƫl J. and want to redo again.
Is below command will achieve what I want? Thank you in advance.

===== Create experimental branch =====
git checkout develop
git pull origin develop
git checkout -b experimental
**Add Note.txt and put some text
git add -A
git commit -m "Experimental branch commit for experimental development"
git push origin experimental

===== Rebase feature branch to experimental branch =====
git checkout feature
git rebase --onto experimental develop feature
git push -f origin feature
Yumi
  • 23
  • 1
  • 6

1 Answers1

1

TL;DR: yes, your command sequence is correct.

You can shorten it slightly using git rebase experimental.

Long

Use git checkout or git switch to select the commit at the tip of develop:

git switch develop

You now have that commit as the current commit, with that branch name as the current branch name; I like to draw this as:

...--G--H   <-- develop (HEAD)
         \
          I--J   <-- feature

where the uppercase letters stand in for commit hash IDs.

Now you can create a new branch name experimental, and make it the current branch:

git switch -c experimental    # or git checkout -b experimental

producing:

...--G--H   <-- develop, experimental (HEAD)
         \
          I--J   <-- feature

A new commit you make now advances the name experimental:

          K   <-- experimental (HEAD)
         /
...--G--H   <-- develop
         \
          I--J   <-- feature

It's now necessary to copy commits I and J to new, slightly-different commits that use commit K as the parent of the copy of I, and use the copy of I as the parent of J. The git rebase command does this kind of copying.

If you give git rebase a branch argument, it runs an initial git switch (or git checkout) on that argument. I find this unwise (there's a bug recently discovered on the Git mailing list, in this area) and prefer to do my own separate git switch, but you can run:

git rebase --onto experimental develop feature

to eliminate the separate git checkout feature step. I wouldn't, as I said; I would run git switch feature first.

The set of commits that git rebase will copy starts with a list of commits as generated by git log or git rev-list:

git rebase [--onto <target>] <upstream>

uses the current branch as the source of these commits, and upstream..HEAD as the initial list of commits that might potentially be copied.1

Since your upstream argument is either develop or experimental, the list will be generated by:

git log develop..HEAD

or:

git log experimental..HEAD

If you try both commands at this point in the process, you will see that they produce the same output. The reason is that the left side of the two-dot operator, A..B, tells Git what commits not to use. The right side tells Git what commits to use, minus any overridden by the left side. Each of these operations works by finding the last commit, as named by the hash ID or branch name or HEAD name, and working backwards.

The last commit on feature is J, and the next-to-last is I, and the one behind that is H, and so on. The exclusion list either starts at K, then works back to H, and continues backwards from there, or it starts at H and works backwards from there. Commit K isn't in the inclusion list, so if it is in the exclusion list, this is "free": nothing happens one way or another.

This means you can use either experimental or develop as the upstream argument to git rebase. Both have the same effect.

If you use the --onto argument to git rebase, the commit hash ID or name you supply after the literal word --onto sets the target for the rebase operation. If you omit it, the upstream sets the target.2 The target that you want in this case is experimental.

Since experimental works as an upstream argument, the command:

git rebase experimental

suffices, and you don't need a separate --onto.

The git rebase process will now run, copying each commit one at a time, in the correct order, using Git's internal detached HEAD mode:

            I'  <-- HEAD
           /
          K   <-- experimental
         /
...--G--H   <-- develop
         \
          I--J   <-- feature

after copying I to I', and then:

            I'-J'  <-- HEAD
           /
          K   <-- experimental
         /
...--G--H   <-- develop
         \
          I--J   <-- feature

after copying J to J'. Merge conflicts can occur during the copying of each commit, but if they don't, Git will handle this all on its own. Finally, once both commits are copied, Git will yank the branch name feature over to point to the last-copied commit, and re-attach the special name HEAD:

            I'-J'  <-- feature (HEAD)
           /
          K   <-- experimental
         /
...--G--H   <-- develop
         \
          I--J   ???

and the rebase is complete.


1Specific commits may sometimes be subtracted away from this list, during or after generating the list. In your case, none will be subtracted away, so we get to ignore this, and just use the list that you'll see if you run git log.

2There's another trick involving --fork-point if you omit both names, but let's not get into that as it gets complicated.

torek
  • 448,244
  • 59
  • 642
  • 775