emacs-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Splitting changes (was: support for bzr shelve/unshelve in vc-dir)


From: Stefan Monnier
Subject: Splitting changes (was: support for bzr shelve/unshelve in vc-dir)
Date: Thu, 03 Dec 2009 12:05:49 -0500
User-agent: Gnus/5.13 (Gnus v5.13) Emacs/23.1.50 (gnu/linux)

>> The implementation shelves all the changes on the current
>> branch. Although this is useful, an usual application of `shelve' is for
>> temporarily removing out of your way some changes (allowing to commit
>> only specific changes of the edited files, for example.) An ideal
>> implementation of `shelve' for vc would show the output of `bzr diff',
>> mark the hunks you want to shelve, and then run the command. Sadly, it
>> seems impossible to non-interactively indicate to bzr which hunks it
>> should shelve.

> That's exactly the reason for the current implementation.
> Patches to add other methods to create shelves (including an
> interactive) are surely welcome.

I've been interested in this issue for a while now: I've been using
a local patch to VC which adds a command
"vc-prepare-for-partial-commit", which allows to choose which part of
some local changes should be committed and which part should be kept
for later.

I've never installed it in the trunk for various reasons, but I've use
it extensively for many years.  In this time I noticed the following:
- selecting only by files is not a fine enough granularity.
- selecting only by hunks is sometimes sufficient, but even that is too
  coarse in my experience.  The typical problem is that I want to split
  a change into a cleanup part and an actual new feature, but in most
  cases all the cleanup changes touch the exact same code as the new
  feature, so many of the hunks mix both.

So the way my hack works is the following:
- it takes ("stashes") a copy of the current state.
- then it lets you make any changes you want (the intention is that
  you're going to revert the changes you want to keep for later).
  You can do this part at any granularity: files, hunks, or even
  by hand.
- when done, you commit, after which the saved files are re-instated.

This gives me great flexibility, and lets me use any tool I want to
select which parts to keep and which parts not.  So I really like it.
But it has some serious drawbacks:
- if the final commit fails because the tree is not uptodate (any more),
  the backend won't know that the update should apply to both the file
  and its "stashed" copy.  So you end up having to deal with updates
  missing from the stashed copy, or abort the partial commit
  (i.e. revert to the stashed copy), then update, then re-do the split
  by hand.
- when doing the split by hand, you can make any change you want.
  The intention is for those changes to "undo" part of the local
  changes, but nothing prevents you from adding new changes during this
  time (as you revisit the code to choose how to split your changes, you
  may bump into new opportunities for cleanup and it's sometimes
  difficult to refrain from doing them at that point).  And if you do
  add local changes, then these will be undone after commit when the
  saved files are re-instated.

So I'd like VC to support something like that, but in a way that is
a bit more robust.  The way I see it working ideally is something like
the following:
- the copy is taken by committing the local changes on a new temporary branch
  (IIUC, that's pretty much what "git stash" does).
- then revert to the original branch and reapply those same changes
  (without committing them).
- at this point the user can use any tool he likes to remove parts of
  those changes he doesn't want to commit yet.  She can also "update"
  her tree when needed.
- when she's ready, she can perform the "commit", after which VC will
  ask to merge the temporary branch (without committing the result),
  which will hopefully result in pretty much the same as the original
  code before this whle partial commit took place.

The advantage here, is that because we use branches rather than manually
copying files behind the VCS's back, the VCS has all the needed
meta-data to ensure that no change is accidentally lost or undone.

The disadvantage is that the final merge is likely to introduce spurious
conflicts since it will re-apply the parts of the changes that
were just committed.  But if "same change conflicts" are automatically
resolved by your merge tool, then all the changes that were selected at
the granularity of a hunk (or larger) should be merged
without conflict.  I.e. you should only see conflicts when you actually
take advantage of the extra flexibility.


        Stefan




reply via email to

[Prev in Thread] Current Thread [Next in Thread]