Git: Interactively Stage Portions of a Single Changed File for Commit Using git add -p

Posted on September 8 2013 01:38 PM by jatten in CodeProject, Git   ||   Comments (0)

Terminal 9 - the Hong Kong International Container Port-500The thing which makes Git powerful as a version control system is its flexibility, and the many ways exposed by the Git API to get things done.

Of course, this is also what can make Git challenging to learn and use. There are so many options available that it can be difficult to know how to approach a specific problem.

On top of that, the Command Line Interface (CLI) for Git, and the underlying API employ a syntax which is . . . inconsistent at times, and definitely not intuitive for the uninitiated.

 

Image by Kai Yan, Joseph Wong, Some Rights Reserved

This article is targeted at those newer to Git, who may be trying to find their way through some of the more advanced features for the first time. I've created a more condensed Quick Reference to Git's Interactive Patch Staging for those who don't need that narrative or pictures, and just want to refresh themselves on the syntax and/or options associated with this feature of git.

Skip the damn narrative and pictures, take me to the quick version

If you are just getting started with Git, you might find Getting Started With Git and a Basic Git Command Line Reference helpful in conjunction wit this article. Both were aimed at Windows users stepping into Git and the Bash CLI for the first time, but the concepts and commands discussed are mostly universal.

Don't Put Several Significant but Unrelated Changes in the Same Commit

If we were all perfect we would always be on top of things, and (for example) do a bug fix in one commit, and add new code in a different commit. But as we all know, in real life it doesn't actually work out that way sometimes (most of the time, if you are me!). On occasion, we perform a number of changes in the same code file, and then, after laboring to get it right for hours, we realize we have introduced unrelated changes, to different parts of the file, which should really be in separate commits.

Our Contrived Example

Consider the following contrived, but illustrative situation (the examples here are in C#, but this exercise could apply to any platform). We open our latest project on branch master and review a file, ComplicatedExistingClass, which looks like this to start with:

Original Code File for ComplicatedExistingClass:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace GitAddPartialFile
{
    public class ComplicatedExistingClass
    {
        public int ComplexCalculation(int numberOne, int numberTwo)
        {
            int sum = 0;
            // Some complex code which also contains a bug . . .
            sum = numberOne + numberTwo + 1;
            return sum;
        }
    }
}

 

We get to work, adding a new method. We start by checking out a feature branch (because we always do that, right? Create a feature branch to work on?):

Check Out a New Feature Branch:
$ git checkout -b newfeature

 

We then add our new method, which requires the addition of a couple new using statements at the top of the code file (yes, I KNOW System.Data and System.Data.OleDb are not actually used here, just mixing it up a bit – work with me), and of course, our new method:

Our Code File with New Method:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Data;
using System.Data.OleDb;
namespace GitAddPartialFile
{
    public class ComplicatedExistingClass
    {
        public int ComplexCalculation(int numberOne, int numberTwo)
        {
            int sum = 0;
            // Many lines of complex code which also contains a bug . . .
            sum = numberOne + numberTwo + 1;
            return sum;
        }
        public IEnumerable<int> DoSomethingWithNumbers(int[] numbers)
        {
            var output = new List<int>();
            foreach (int i in numbers)
            {
                int result = this.ComplexCalculation(i, numbers.Count());
                output.Add(result);
            }
            return output;
        }
    }
}

 

While testing out our complicated new method, which also calls the original ComplexCalculation method, we notice there is a bug in the original method. The bug fix is quite complex, requiring us to modify several lines of code after we discern just what it is that is wrong:

Modified Code File, including Arduous Bug Fix:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Data;
using System.Data.OleDb;
namespace GitAddPartialFile
{
    public class ComplicatedExistingClass
    {
        public int ComplexCalculation(int numberOne, int numberTwo)
        {
            int sum = 0;
            // Many lines of complex code which no longer contain any bugs
            // but took hours to figure out . . .
            sum = numberOne + numberTwo;
            return sum;
        }
        public IEnumerable<int> DoSomethingWithNumbers(int[] numbers)
        {
            var output = new List<int>();
            foreach (int i in numbers)
            {
                int result = this.ComplexCalculation(i, numbers.Count());
                output.Add(result);
            }
            return output;
        }
    }
}

 

We're Ready to Commit, but . . .

Only now do we come up for air long enough to realize we should have done the bug fix separately from adding our new method. For one, we might not be done with our feature yet, but the bug fix is critical and should be able to be merged back into master immediately. Also, it simply makes sense that a bug fix in the existing code base should be a singular commit, separate from adding new code. What to do?

What we would like to do is create a commit for the bug fix first, separate from our newly added feature code. Here is how.

Use Interactive Staging with Partial Files for Separate, Individual Patch Commits

Git to the rescue. We can use the Git command git add –p to do this interactively, and stage our code in patches. With git add –p, we selectively add chunks of a file (or files) from our working tree to the staging area, enabling us to select discreet chunks of changed code and build separate commits with pieces of a file or files.  The command syntax is as follows:

Git Add –P Syntax:
$ git add -p [optionalFileName]

 

In the above, the file name is optional, but most likely you will want to specify the file, as otherwise the next step will walk you through all files within the working tree with changes since the last commit.

Once we type this command and hit enter, git jumps into an interactive mode, allowing us to decide which file chucks we wish to add to the next commit. In the case of our example project, we would type the command like this:

Staging Patches from our Existing File for Commit:
$ git add -p ComplicatedExistingClass.cs

 

Our terminal window looks like this before we hit enter:

git-add-p-before-enter

Once we hit the enter key, we see this rather busy window:

git-add-p-after-enter-one

See the stuff called out in the red box? this represents the first chunk of changed code git has identified in the file. The changes are shown in green, and surrounding (unmodified) code is shown in white for context. Also notice the text in blue at the bottom of the window, with a prompt waiting for us to tell git what to do. Following are the options available to us with respect to the code chunk in the box. Typing one of the options and hitting enter will do one of the following, depending upon the option selected:

Options for Interactive Patch Staging:

Interactive Patch Staging Options:
y Stage the current code chuck for the next commit
n Do not stage the current code chunk for the next commit
a Stage the current chunk, and all remaining chunks in the current file
d Do not stage current chuck, or any remaining chunks in the current file
g Select the next code chuck to review
/ Search for a code chuck matching the given regex
j Leave undecided, see next undecided chunk
k Leave undecided, see next code chunk
K Leave undecided, see previous undecided code chunk
s Split the current code chunk into smaller chunks
e Manually edit the current code chunk
? Print help

 

Staging Just the Bug Fix For Commit

In our example case here, the code chunk above is related to our new method (work with me here, it's contrived, remember?), so we we don't want to add this chunk to the next commit. Hit n, then Enter:

Do Not Stage Current Code Chunk and Move to the Next Code Chunk:

git-bash-interactive-next-chuck-bug-fix-needs-split

Whoa. Ok, NOW we see the bug fix code we were looking for, but we also see our newly added method. We want to isolate the bug fix code. In this case, we need to select the s option from the menu, splitting the above chunk into smaller pieces. This results in a code chunk including our bug fix, and only our bug fix:

Split Current Code Chunk and Isolate Bug Fix:

git-bash-interactive-split-to-bug-fix

Now we have what we want to include in our next commit. Obviously, we choose the y option so that this chunk is staged for commit. Git then moves to the next code chunk:

Choose Bug Fix for Next Commit:

git-bash-interactive-choose-bug-fix-for-commit

What we now see in the terminal window is the rest of the code for our new feature. We don't want this in our bug fix commit. Also, because our entire bug fix has just been staged for commit by selecting the y option, we can tell git not to stage the current code chunk, or any remaining code chunks. We do this by selecting the d option:

Exit and Return to Terminal Command Prompt

git-bash-interactive-exit-and-return-to-prompt

Now we are ready to commit our bug fix. If we run git status, we see something interesting:

Git Status After Staging Partial Code Patch for Bug Fix:

Git Bash-git-status-after-stage-bugfix

In the image above, the item under "changes to be committed" in green is our ComplicatedExistingClass.cs file. But also, we see a similar item under "Changes not staged for commit." This is because we have staged some of our changes within that file for commit, and left some un-staged.

 

Committing the Staged Patches from the File:

From here, we can commit the bug fix:

$ git commit -m "Fixed bug in Complicated Calculation Method"

 

Commit the Bug Fix:

git-bash-commit-bug-fix

If we run git status again, we see that there are no changes staged for commit, and a single item modified but un-staged – the rest of our changes representing the addition of our new method:

Git Status After Committing Bug Fix:

Git Bash-git-status-after-commit-bugfix

 

Stage and Commit the New Feature Code

Now that we have our bug fix committed, we can (in this case) go ahead and stage the rest of the changes for as usual, and then commit, since they represent our complete work adding the new method:

Stage New Feature Changes:
$ git add .
Then Commit:
$ git commit -m "Added DoSomethingWithNumbers method as part of newfeature"

 

Our terminal window:

Stage and Commit the New Feature Code:

git-bash-commit-featture

 

Review Commit History with git log

Now, if we use git log to review our commit history, we see our nicely broken out commits as if the bug fix, and the new feature code had happened sequentially instead of in parallel:

Git Log After Committing Bug Fix and Feature Code Separately:

git-log-after-commit-feature

 

Merge the Bug Fix into Master

Additionally, we could, if we so desired, merge the bug fix back into master while keeping our feature-related changes on the feature branch. We do this by switching to master, then merging the bug fix commit using its SHA-1 identifier (the first 6-8 characters will do here):

Checkout Master Branch:
$ git checkout master
Merge Bug Fix Commit (#94327f06 . . .)
$ git merge 94327f06

 

Our terminal window:

git-merge-bugfix-into-master

 

Wrapping Up

We have taken a very basic look at using Git Interactive Patch Staging to make order out of chaos, so to speak. This feature is handy because in real life, our actual workflow does not always parallel the idealized flow we want to record as our project's history. Git is a powerful tool, but requires use and practice to master and become comfortable with. Check out the additional resources below for more of my own stuff, and others.

Additional Resources

 

Posted on September 8 2013 01:38 PM by jatten     

Comments (0)

Git Quick Reference: Interactive Patch Staging with git add -p

Posted on September 8 2013 01:36 PM by jatten in Git, CodeProject   ||   Comments (0)

Port of Long Beach-500NOTE: This is a reference, mainly for myself and others, condensed from a much more verbose article which does a lot of hand-holding for Git newcomers, and attempts to explain what is going on in a little more detail. 

Also, if you are newer to Git you might want to review my introductory posts on Getting Started with Git and a Handy Git Command Line Reference. While these tutorials were originally targeted at Windows developers, the information is pretty universal. Also, you might benefit from the more through treatment of this topic in the full-fledged walk-thru.

 

Image by msun523 Some Rights Reserved

I'm new and/or I enjoy reading. Take me to a full-fledged walk-through!

The git add –p Command and Syntax

The git add –p command allows us to interactively stage chunks of code within a file or files for commit, while leaving the rest of the file of files un-staged. The command syntax is:

The git add –p Command Syntax:
$ git add -p [optionalFileName]

 

In the above, the file name is optional, but without a specific file name, git will interactively move through all files with un-staged changes. Best to include only the file or files of interest.

git add –p Command Options

Once the git add –p command is executed, git enters interactive mode, and interactively moves through chunks of code in the file or files, prompting you to indicate what to do as far as staging each chunk. Following is a table of the options available with this command:

Interactive Patch Staging Options:
y Stage the current code chuck for the next commit
n Do not stage the current code chunk for the next commit
a Stage the current chunk, and all remaining chunks in the current file
d Do not stage current chuck, or any remaining chunks in the current file
g Select the next code chuck to review
/ Search for a code chuck matching the given regex
j Leave undecided, see next undecided chunk
k Leave undecided, see next code chunk
K Leave undecided, see previous undecided code chunk
s Split the current code chunk into smaller chunks
e Manually edit the current code chunk
? Print help

 

Example Usage Scenario

On occasion, we perform a number of changes in the same code file, and then, after laboring to get it right for hours, we realize we have introduced unrelated changes, to different parts of the file, which should really be in separate commits.

Contrived Example

Consider the following contrived, but illustrative situation (the examples here are in C#, but this exercise could apply to any platform). We open our latest project on branch master and review a file, ComplicatedExistingClass, which looks like this to start with:

Original Code File for ComplicatedExistingClass:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace GitAddPartialFile
{
    public class ComplicatedExistingClass
    {
        public int ComplexCalculation(int numberOne, int numberTwo)
        {
            int sum = 0;
            // Some complex code which also contains a bug . . .
            sum = numberOne + numberTwo + 1;
            return sum;
        }
    }
}

 

We then add our new method, which requires the addition of a couple new using statements at the top of the code file (yes, I KNOW System.Data and System.Data.OleDb are not actually used here, just mixing it up a bit – work with me), and of course, our new method:

Our Code File with New Method:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Data;
using System.Data.OleDb;
namespace GitAddPartialFile
{
    public class ComplicatedExistingClass
    {
        public int ComplexCalculation(int numberOne, int numberTwo)
        {
            int sum = 0;
            // Many lines of complex code which also contains a bug . . .
            sum = numberOne + numberTwo + 1;
            return sum;
        }
        public IEnumerable<int> DoSomethingWithNumbers(int[] numbers)
        {
            var output = new List<int>();
            foreach (int i in numbers)
            {
                int result = this.ComplexCalculation(i, numbers.Count());
                output.Add(result);
            }
            return output;
        }
    }
}

 

While testing out our complicated new method, which also calls the original ComplexCalculation method, we notice there is a bug in the original method. The bug fix is quite complex and takes hours, requiring us to modify several lines of code after we discern just what it is that is wrong:

Modified Code File, including Arduous Bug Fix:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Data;
using System.Data.OleDb;
namespace GitAddPartialFile
{
    public class ComplicatedExistingClass
    {
        public int ComplexCalculation(int numberOne, int numberTwo)
        {
            int sum = 0;
            // Many lines of complex code which no longer contain any bugs
            // but took hours to figure out . . .
            sum = numberOne + numberTwo;
            return sum;
        }
        public IEnumerable<int> DoSomethingWithNumbers(int[] numbers)
        {
            var output = new List<int>();
            foreach (int i in numbers)
            {
                int result = this.ComplexCalculation(i, numbers.Count());
                output.Add(result);
            }
            return output;
        }
    }
}

 

Only now do we come up for air long enough to realize we should have done the bug fix separately from adding our new method. For one, we might not be done with our feature yet, but the bug fix is critical and should be able to be merged back into master immediately. Also, it simply makes sense that a bug fix in the existing code base should be a singular commit, separate from adding new code. What to do?

What we would like to do is create a commit for the bug fix first, separate from our newly added feature code. Here is how.

Use git add –p to Stage Our Bug Fix Separately From the New Feature Code

We can now use the git add –p to do this interactively, and stage our code in patches. With git add –p, we will selectively add chunks of a file (or files) from our working tree to the staging area, enabling us to select discreet chunks of changed code and build separate commits with pieces of a file or files.

Once we type this command and hit enter, git jumps into an interactive mode, allowing us to decide which file chucks we wish to add to the next commit. In the case of our example project, we would type the command like this:

Staging Patches from our Existing File for Commit:
$ git add -p ComplicatedExistingClass.cs

 

What it Looks Like in the Terminal

Our terminal window looks like this before we hit enter:

git-add-p-before-enter_thumb[3]

Once we hit the enter key, we see this rather busy window:

git-add-p-after-enter-one_thumb[10]

See the stuff called out in the red box? this represents the first chunk of changed code git has identified in the file. The changes are shown in green, and surrounding (unmodified) code is shown in white for context. Also notice the text in blue at the bottom of the window, with a prompt waiting for us to tell git what to do. The prompt is waiting for us to enter one of the options from our table above.

In our example case here, the code chunk above is related to our new method (work with me here, it's contrived, remember?), so we we don't want to add this chunk to the next commit. Hit n, then Enter:

Do Not Stage Current Code Chunk and Move to the Next Code Chunk:

git-bash-interactive-next-chuck-bug-fix-needs-split_thumb[3]

Whoa. Ok, NOW we see the bug fix code we were looking for, but we also see our newly added method. We want to isolate the bug fix code. In this case, we need to select the s option from the menu, splitting the above chunk into smaller pieces. This results in a code chunk including our bug fix, and only our bug fix:

Split Current Code Chunk and Isolate Bug Fix:

git-bash-interactive-split-to-bug-fix_thumb[3]

Now we have what we want to include in our next commit. Obviously, we choose the y option so that this chunk is staged for commit. Git then moves to the next code chunk:

Choose Bug Fix for Next Commit:

git-bash-interactive-choose-bug-fix-for-commit_thumb[2]

 

What we now see in the terminal window is the rest of the code for our new feature. We don't want this in our bug fix commit. Also, because our entire bug fix has just been staged for commit by selecting the y option, we can tell git not to stage the current code chunk, or any remaining code chunks. We do this by selecting the d option:

Exit and Return to Terminal Command Prompt

git-bash-interactive-exit-and-return-to-prompt_thumb[2]

Now we are ready to commit our bug fix. After we do that, we can then stage our newly added feature code in the normal fashion and commit.

More Detail?

In this article I walked through this as briefly as I could while including sufficient examples and illustrative screenshots to show what is going on. There is more detail in the full tutorial Git: Interactively Stage Portions of a Single Changed File for Commit Using git add –p.

If you found this useful, consider some of my other posts related to Git, and as always, the most excellent book (free online) by Scott Chacon:

Additional Resources

 

Posted on September 8 2013 01:36 PM by jatten     

Comments (0)

Git: Combine and Organize Messy Commits Using Interactive Rebase

Posted on April 3 2013 03:52 PM by jatten in Git, CodeProject   ||   Comments (2)

This post describes a rather specific use of Git’s rebase command. Rebase is a powerful and complex topic which I am not fully covering here. I will attempt a more thorough look at rebase in general in an upcoming post. If you are newer to Git, as I am, you might want to refer to a few of my previous posts covering some of the basics:

A handy feature of Git is the ability to use the interactive rebase command to combine, re-organize, and otherwise clean up a messy commit history once development of a feature or bug fix is complete. I am a firm believer in the practice of “commit early, commit often” approach. However, this can leave untold number of commits which, when merged back into mainline development, clutter up a repository.

Image by CityGypsy11 (Creative Commons)

Warped-Clock-ImageHow often do you end up creating a commit which consists of some modified whitespace after cleaning up a code file, or a commit arising from updating some comments or renaming variables?

Oftentimes, when we complete a feature or fix, we can clearly see how (hindsight being, more often than not, 20/20)we would have liked the code to come together. In fact, for myself, I often wish I could just combine all of the relevant commits into one, which I could then merge back into master. For more complex features, or those which may have undergone substantial evolution during development, it can sometimes become clear how the commit history should have occurred, and not necessarily in the order of manner in which it actually did.

For reasons of maintenance, or particularly if we plan to push our code out to a public repository, it would be nice if we could straighten things up a little, and present a commit history to the world which will:

  • Allow us to rollback changes in a manner which does not cripple our codebase.
  • Make sense to those who might need to maintain or perhaps branch from our repository.
  • Not leave us looking like disorganized idiots (“Did you really commit the deletion of a single empty line?”).

Interactive rebase gives us a way to write that history.

A Simple Example

I will start with an overly simple example. Assume a straightforward git repository consisting of a master branch. In order to add a new feature, you create a feature branch, names (appropriately, feature). On the new feature branch, you work up the basic functionality of the new feature, knowing you will be fine-tuning things shortly. However, you commit the work to this point.

While developing the primary feature code, you noticed a bug in another part of the codebase, perhaps impacting the development of your new feature. You quickly spot a solution, fix the bug, and commit.

Once that is done, you fine-tune the new feature code until it is right where you want it. After committing those changes, you decide to do some cleanup. You remove unnecessary whitespace, rename some methods for clarity, and other housekeeping tasks. After committing this last batch of changes, you are ready to merge your work into master.

Except . . . the new feature, in this case, is not overly complex, and you sure wish you could merge it into master as a single commit. Also, that bug fix should remain separate, as that should be applied to master separately from the new feature. That way, if for whatever reason the new feature needs to be rolled back, it can be done so independently of the bug fix. As of right now, the state of your repo is something like this:

Repo After Feature Development

repo-after-feature-complete

 

 

 

 

 

 

 

 

 

 

 

 

 

If we were to perform a standard merge at this point, our repo would look like this:

Repo State After Hypothetical Standard Merge:

repo-after-standard-merge

 

 

 

 

 

 

 

 

 

 

 

 

As I stated, this is a rather simplified example. But you can see where we might want to combine our feature development (commits C, D, and E) into a single commit before merging to our master branch, while leaving our bug fix (commit C) on its own.

Use Git’s Interactive Rebase Feature to Re-Write History

I created a (very contrived) sample project with a main application on master, and a feature branch. After writing some trivial code to illustrate the commit history we are using in our example, I ran Gitk, which now looks like this:

The Feature Branch Shown in Gitk:

gitk-after-feature-complete

Similarly, the git log command, run from within our feature branch, shows us this:

Git Log Contents for Feature Branch:

git-log-after-feature-complete

If we want to re-write the commit history here such that commits B, D, and E are combined into a single new commit, we can tell git to run an interactive rebase which will allow us to provide direction to git with respect to how we would like it to handle each of the commits involved in the rebase.

What we are actually going to do here, consistent with how rebase works, is rewrite one or more commits in the same branch onto the parent commit we specify in the command below. Because we will be using the interactive flag, we will be allowed to reorder the commits we have selected for the operation, as well as provide some other direction as to how we want git to handle the process.

The Command Syntax is like this:
$ git rebase -i HEAD~n

 

In the above, n represents the number of commits we would like to edit. However, it is important to note that this actually points to the parent of commit n as the rebase target. So, having examined the state of my feature branch, I can see that I would like clean up commits B thru E. I want to combine Commits B, D and E into s single commit, and leave commit C as a stand-alone (the bug fix).

Here is what I will type into the command shell:

$ git rebase -i HEAD~4

 

9/12/2013 UPDATE: Interactive rebase uses the editor set up in your .gitconfig file as the default. Here, I am using Sublime Text 2, my preferred text editor (Notepad++ is a close second). Setting up Sublime Text as the default editor in Git is a minor excercise, but not necessarily intuitive. Check the linked article for more information. 

After I type that in and hit enter, my editor widow opens, and looks like this:

The Editor Window After Entering the Interactive Rebase Command:

editor-rebase-options-on-open

In this case, the first four lines which start with “pick” represent the commits I have chosen to edit. Note the order in which they appear. When we are finished editing, git will process our revised commits from top to bottom. This is significant because we can re-order them if we so choose. Also note the comments below. We are given some options here which we can apply to the editing process. If we replace the pick keyword with one of these flags for any specific commit, that operation will be performed on that commit.

Of particular interest to us in this case is the squash or s flag. When we replace pick with squash, we tell git to combine that commit with the previous one (remember the processing order, top to bottom). Remember what we want to do in this rather contrived example – we want to combine commits B, D, and E into one. However, the current processing order doesn’t allow us to do this, because our bug fix is sandwiched between commits B and D.

So first we will need to change the processing order by moving some commits around.  In the editor, we can easily Cut/Paste the top two lines to look like this instead:

Changing the Commit Processing Order in the Editor:

editor-rearrange-commit-processing-order

Now, git will process our edited commits as ordered above, starting with C, then B, then D, then E. Next, we tell git to squash commits D and E by replacing the pick flag with s or squash, so that they both roll up into the previous commit (Commit B, in this case):

Change the Commit Processing Flags in the Editor:

editor-set-commit-processing-flags

Now, having made the changes above, SAVE THE EDITOR CONTENTS (I often forget this step!) and close the editor window. Your command line window will return while Git processes the commits, and then the editor reappears. Git now wants you to sort out the commit messages, so that the newly created commit history will make sense.

In our example case, the first thing that we see is this:

Making Sense of the Commit History and Messages in the Editor:

editor-before-edit-commit-messages

We can see that the three commit messages in question are from our original commits B, D, and E, related to our new feature. We can clear all of these (and the comments included with them) and type a new, more meaningful commit message. Note that any line prefixed with a hash symbol (“#”) will be ignored:

Modifying the  Commit Message for the Combined Feature Commit in the Editor:

editor-after-edit-commit-messages

Now, SAVE THE EDITOR CONTENT AGAIN and close the editor window. The command line window now looks like this:

Command Window After Successful Interactive Rebase:

bash-after-rebase

If we run git log now, we see the following:

Git Log After Successful Interactive Rebase:

bash-git-log-after-interactive-rebase

If we run Gitk, we see this:

gitk-after-rebase-complete

As we can see, in the above, we now have a single commit representing the implementation of our new feature, and the original bug fix (previously, commit C) where previously there were four distinct commits. We have re-written history, in preparation for a sensible merge into our master branch.

Notice that our bug fix commit (previously commit C) now has a different hash identifier than previously, and the combined commit is brand-new as well. This is important, because again, HISTORY HAS BEEN CHANGED. The implication here is that if the previous history has been pushed to a public repository (or otherwise cloned, perhaps locally) the history of the feature branch will no longer be the same. In other words, we might as well think of Commit C as a new commit F, and the combined commit as a new commit G.

IMPORTANT: This should not be performed on commits which have been pushed to a public repository, if other committers are working with your code!!! It is generally best to reserve this technique for code in your local working tree, before publishing.

Graphically, our repository now looks like THIS:

Repo After Interactive Rebase:

repo-after-rebase-complete

But, What About Merge Conflicts During the Interactive Rebase?

As often as not, you will run into merge conflicts during this process. I contrived the example above specifically to illustrate the ability to combine commits, and studiously made sure conflicts  would not occur here.

In cases where there are conflicts, Git will stop the rebase process, and demand that you fix any conflicts before resuming. Once you have resolved any conflicts, type git rebase –continue in the command window, and the process will resume. We’ll take a look at conflict resolution in another post.

Additional Resources

 

Posted on April 3 2013 03:52 PM by jatten     

Comments (2)

About the author

My name is John Atten, and my username on many of my online accounts is xivSolutions. I am Fascinated by all things technology and software development. I work mostly with C#, Java, SQL Server 2012, learning ASP.NET MVC, html 5/CSS/Javascript. I am always looking for new information, and value your feedback (especially where I got something wrong!). You can email me at:

jatten@typecastexception.com

Web Hosting by