Scenario goes like this:
Assume you (me really) have a bitbucket repository containing some source code. You also have the luxury of two machines to develop with. Further assume that at this given point in time, both development machines are synchronized with your online repository.
Earlier in the day just before your first cup of morning coffee, your crank out some code and performed an Hg Commit pushing these changes to your online repository. Gave a big pat on the back for this accomplishment and went on to do something else. Later in the day, you decide to use the other development machine, crank out some code again, and attempt another Hg Commit. This time, TortoiseHg declines your push request saying something along the lines of:
“push will create a new head: XXXXX did you forget to update and merge?”
Duh, yes, I did. Veterans of DVCS will have probably stopped right here to reverse the damage but since you are not yet such a veteran, you try to hack your way out.
Not thinking clearly, you quickly do an update from your online repository, completely oblivious to the fact that you had just attempted an unsuccessful commit. Mercurial pulls the changes from remote and when you attempt a merge, it complains again saying something along the lines of
“Cannot update to local repository with uncommitted changes”
Huh? But I did not commit anything dammit, you scream in frustration. Does not help, that you are doing this at about 12:30 am way beyond normal bedtime.
Fact of the matter is, yes you did indeed commit but it was against your local repository. The changes were just not pushed to your remote repository. So now you find yourself looking at a chicken or egg problem, which in this context is defined as follows:
Changesets pulled in from your remote repository cannot be merge with the local repository if the latter contains uncommitted changes (or changes that have not been pushed to the remote repository). Also, the local commits cannot be pushed to the remote repository if changes pulled from the remote have not been merged to the local repository, that contains uncommitted changed.
I do not know if this is the case with GitHub, but this is what I have experienced with Mercurial.
This is typically a good time to stop and go grab another cup of coffee, a smoke or walk, or whatever to clear those brain cells. currently committed to this problem. Assume you do just this.
You come back with a clearer head, read some more about DVCS, and then decide to tackle the problem with the following tasks:
- Eliminate the local commits.
- Complete the remote update.
- Re-apply the local commits.
So, what does this procedure really entail? Will it even work?
Using TortoiseHg 2.7 on Windows, this is the work breakdown of the above tasks.
- Create a backup copy of your current local repository. This is important!
- Launched TortoiseHg.
- Identify the revision to remove. This is the bad local commit. In the attached image, this is revision 6.
- Right click on this revision, selected Modify History -> Strip.
- On the Strip dialog presented, select option Discard local changes, no backup (-f/ -force).
This is basically telling TortoiseHg to instruct Mercurial to remove any trace of this revision, including stripping out your local change. Hence reason for step 1.
- After stripping this revision, your last pull should indicate it needs to be merged as shown below.
- Right click on this revision and select “update”, selecting option to Discard local changes, no backup (-C/ -clean), to merge your last pull. If all goes well, you should have a single branch as shown below:
- Copy all your changes from the backup created in step 1, to this repository, using whatever tool works best for you. Tools like Beyond Compare work well for such tasks.
- Ensure your solution builds, compiles and runs, then commit these changes to your local repository and push them to the remote.
- Ensure that you do not have hanging branches as shown below.
If this is the case,
- Go give your self a pat on the back, adding this to the list of things learned today.
There must be a way to prevent this in the future. Before commit local changes, does Tortoise Hg have a way to pull and update then merge before committing? Sounds like a crazy expectation.