When I work on a local branch, I prefer to commit in small increments with a few comments on what I did in the commits; however, as these commits do not build or pass any test requirements, I cannot submit them for review and verification one by one. I have to merge them in my branch, and still, cherry picking my fix would require me to cherry-pick twice the number of commits, which is not very handy.
What we can do is rebase and squash the commits into a single commit or at least a smaller number of commits.
To get started with this example, we need a new branch, namely rebaseExample3
, that tracks origin/stable-3.1
. Create the branch with the following command:
$ git checkout -b rebaseExample3 --track origin/stable-3.1 Branch rebaseExample3 set up to track remote branch stable-3.1 from origin. Switched to a new branch 'rebaseExample3'
To really showcase this feature of Git, we will start by being six commits ahead of the origin/stable-3.1
branch. This is to simulate the fact that we have just created six commits on top of the rebaseExample3
branch; to do this, perform the following steps:
origin/stable-3.1
and origin/stable-3.2
and list the commits in reverse order. If you don't list them in reverse order, you can scroll down to the bottom of the output and find the commit we will use, as shown in the following snippet:$ git log origin/stable-3.1..origin/stable-3.2 --oneline --reverse 8a51c44 Do not close ArchiveOutputStream on error 3467e86 Revert "Close unfinished archive entries on error" f045a68 Added the git-describe implementation 0be59ab Merge "Added the git-describe implementation" fdc80f7 Merge branch 'stable-3.1' 7995d87 Prepare 3.2.0-SNAPSHOT builds 5218f7b Propagate IOException where possible when getting refs.
rebaseExample3
branch to the 5218f7b
commit; this will simulate that we have six commits on top of the origin/stable-3.1
branch. This can be tested by running the status of Git as follows:$ git reset --hard 5218f7b HEAD is now at 5218f7b Propagate IOException where possible when getting refs. $ git status On branch rebaseExample3 Your branch is ahead of 'origin/stable-3.1' by 6 commits. (use "git push" to publish your local commits) nothing to commit, working directory clean
origin/stable-3.1
branch, and we want to squash these commits into two different commits instead of six commits. This can be done by simply running git rebase --interactive
. Notice that we are not specifying which branch we want to rebase to since we have already set up a tracking branch when we created the branch using --track
. To continue, let's execute the rebase command as follows:$ git rebase --interactive pick 8a51c44 Do not close ArchiveOutputStream on error pick f045a68 Added the git-describe implementation pick 7995d87 Prepare 3.2.0-SNAPSHOT builds pick 5218f7b Propagate IOException where possible when getting refs.
--preserve-merges
flag. As per the Help section of Git, this is not recommended.According to the Help section in Git --preserve-merges
instead of ignoring merges, tries to recreate them.
The --preserve-merges
flag uses the --interactive
machinery internally, but combining it with the --interactive
option explicitly is generally not a good idea unless you know what you are doing (see the BUGS in the following snippet).
pick 8a51c44 Do not close ArchiveOutputStream on error squash f045a68 Added the git-describe implementation pick 7995d87 Prepare 3.2.0-SNAPSHOT builds squash 5218f7b Propagate IOException where possible when getting refs.
8a51c44
and then squash f045a68
into the commit 8a51c44
. This will open the commit message editor that contains both the commit messages. You can edit the commit messages, but for now, let us just close the editor to finish with the rebase and the squashing of these two commits. The editor will open one more time to complete the squashing of 5218f7b
into 7995d87
. Use gitk
to verify the result.The following screenshot is as expected; now, we only have two commits on top of the origin/stable3-1
branch:
HEAD
commit, you will see that it has the information of two commits, as shown in the following command. This is because we decided not to change the commit message when we made the change:$ git log -1 commit 9c96a651ff881c7d7c5a3974fa7a19a9c264d0a0 Author: Matthias Sohn <[email protected]> Date: Thu Oct 3 17:40:22 2013 +0200 Prepare 3.2.0-SNAPSHOT builds Change-Id: Iac6cf7a5bb6146ee3fe38abe8020fc3fc4217584 Signed-off-by: Matthias Sohn <[email protected]> Propagate IOException where possible when getting refs. Currently, Repository.getAllRefs() and Repository.getTags() silently ignores an IOException and instead returns an empty map. Repository is a public API and as such cannot be changed until the next major revision change. Where possible, update the internal jgit APIs to use the RefDatabase directly, since it propagates the error. Change-Id: I4e4537d8bd0fa772f388262684c5c4ca1929dc4c
Now we have squashed two commits, but we could have used other keywords when editing the rebase's to-do list.
We will try the fixup functionality, which works like the squash functionality, by performing the following steps; the exception is that Git will select the commit message of the commits with the pick
keyword:
$ git reset --hard 5218f7b HEAD is now at 5218f7b Propagate IOException where possible when getting refs. $ git status On branch rebaseExample3 Your branch is ahead of 'origin/stable-3.1' by 6 commits. (use "git push" to publish your local commits) nothing to commit, working directory clean
origin/stable-3.1
branch. Now, we can try the fixup functionality. Start the interactive rebase and change the file according to the following output. Notice that you can use f
instead of fixup
.$ git rebase --interactive pick 8a51c44 Do not close ArchiveOutputStream on error f f045a68 Added the git-describe implementation pick 7995d87 Prepare 3.2.0-SNAPSHOT builds f 5218f7b Propagate IOException where possible when getting refs.
orgin/stable-3.1
branch.$ git rebase --interactive [detached HEAD 70b4eb7] Do not close ArchiveOutputStream on error Author: Jonathan Nieder <[email protected]> 6 files changed, 537 insertions(+), 2 deletions(-) create mode 100644 org.eclipse.jgit.test/tst/org/eclipse/jgit/api/DescribeComma ndTest.java create mode 100644 org.eclipse.jgit/src/org/eclipse/jgit/api/DescribeCommand.ja va [detached HEAD c5bc5cc] Prepare 3.2.0-SNAPSHOT builds Author: Matthias Sohn <[email protected]> 67 files changed, 422 insertions(+), 372 deletions(-) rewrite org.eclipse.jgit.http.server/META-INF/MANIFEST.MF (61%) rewrite org.eclipse.jgit.java7.test/META-INF/MANIFEST.MF (66%) rewrite org.eclipse.jgit.junit/META-INF/MANIFEST.MF (73%) rewrite org.eclipse.jgit.pgm.test/META-INF/MANIFEST.MF (61%) rewrite org.eclipse.jgit.pgm/META-INF/MANIFEST.MF (63%) rewrite org.eclipse.jgit.test/META-INF/MANIFEST.MF (77%) rewrite org.eclipse.jgit.ui/META-INF/MANIFEST.MF (67%) rewrite org.eclipse.jgit/META-INF/MANIFEST.MF (64%) Successfully rebased and updated refs/heads/rebaseExample3.
commit c5bc5cc9e0956575cc3c30c3be4aecab19980e4d Author: Matthias Sohn <[email protected]> Date: Thu Oct 3 17:40:22 2013 +0200 Prepare 3.2.0-SNAPSHOT builds Change-Id: Iac6cf7a5bb6146ee3fe38abe8020fc3fc4217584 Signed-off-by: Matthias Sohn [email protected]
9c96a65
, using the following command:$ git diff 9c96a65
As predicted, there is no output from git diff
, so we still have the same source code.
This check can also be performed on the previous example.