JGit: How to pick and squash a region of commits from one branch to another

If I have a branch of single-parent commits; how can I pick a contiguous region of commits from this branch, and add the squash of them to another branch? I do not want to change the original branch (and assume each commit has only one parent).

Here’s an example: I want to pick C, D, and E, squash them, and place them onto Z. Then pick F and G, squash them, and place them onto the head of Z. We start with the tree below:

A-----B------C------D------E------F------G------H
 \
  \
   Z

And obtain this result:

A-----B------C------D------E------F------G------H
 \
  \
   Z------Y------X

Where:

Y is the squashed commit of C, D, and E

X is the squashed commit of F and G.

I want to avoid the intermediate result below:

A-----B------C------D------E------F------G------H
 \
  \
   Z------C------D------E------F------G

Is there a direct way to do this in JGit? I have been looking at MergeCommand, CherryPickCommand, and RebaseCommand, but I am not sure how to do this while avoiding the intermediate result. I cannot find many JGit examples either. Any suggestions would be helpful.

  • git - how to exclude files from merging
  • How to squash merge multiple commits from branch to master in a single commit using SmartGIT?
  • How to merge back cherry-picked commits in git?
  • How to merge all files manually in Git?
  • Git merge two remote branches in one repository
  • .xcodeproj file is lost, cannot be opened after a branch merge
  • Get merged branch back in git
  • Is it better to use a separate commit message for a git merge?
  • One Solution collect form web for “JGit: How to pick and squash a region of commits from one branch to another”

    I found a solution using the CherryPickCommand and RebaseCommand. Using the example above, I switch to branch at Z.

    A-----B------C------D------E------F------G------H
     \
      \
       Z
    

    Then, I cherry pick the RevCommits C, D, and E using .include(RevCommit) for each commit. Then I use .call() to add the commits onto my new branch, resulting in the diagram below:

    A-----B------C------D------E------F------G------H
     \
      \
       Z------C------D------E
    

    Next, I squash C, D, and E into a single commit with RebaseCommand. First, I set the upstream commi with .setUpstream("HEAD~3") to move back 3 commits. Then I run the interactive handler using a callback function shown below:

    runInteractively(new InteractiveHandler() {
                        @Override
                        public String modifyCommitMessage(String commit)
                        {
                            return rebaseMessage;
                        }
                        @Override
                        public void prepareSteps(List<RebaseTodoLine> steps)
                        {
                            try
                            {
                                steps.get(0).setAction(RebaseTodoLine.Action.PICK);
                                for (int j = 1; j < steps.size(); j++)
                                {
                                    RebaseTodoLine step = steps.get(j); 
                                    step.setAction(RebaseTodoLine.Action.SQUASH);
                                }
                            }
                            catch (IllegalTodoFileModification e)
                            {
                                System.out.println("Cannot prepare step: " + e);
                                e.printStackTrace();
                            }
                        }
                    });
    

    This effectively gives instructions to the interactive command line prompt that you see in normal git rebase operations. Now, my repo looks as follows:

    A-----B------C------D------E------F------G------H
     \
      \
       Z------Y
    

    Where:

    Y is the squashed commit of C, D, and E

    And that’s it!

    To finish the example, I would do the same for commits F and G.

    If there is a direct method to add and squash the commits in one move, I would be very interested. For now, this works and avoids duplication of the entire branch.

    Git Baby is a git and github fan, let's start git clone.