5

In darcs, what if I want to re-order to the top (or just throw away) a patch which other patches depend on (i.e., change the same file)?

In git, I'd simply do a git rebase -i <UNTOUCHED-REVISION> and reorder or throw away some changes; then git would in a dumb fashion try to apply the old changes to the new variant of the tree one by one, and ask me to resolve the arising conflicts.

In darcs, I see no way to force it to ignore the dependencies between patches. If I obliterate or suspend (or unrecord) a patch which other patches depend on, darcs refuses to do it. (Because it wants to behave in a clever manner.)

imz -- Ivan Zakharyaschev
  • 4,921
  • 6
  • 53
  • 104

1 Answers1

4

I had the following plan to do this:

  1. suspend the dependent patches (those which depend on the patch which I want to re-order or throw away).
  2. somehow unrecord the patch to re-order and save it somewhere else (perhaps in another "darcs branch", i.e., a copy of the repo) and revert the changes to the working directory so that the working directory is clean.
  3. after that, unsuspend the suspended patches up to the state where I want to insert the re-ordered patch. (Resolving all arising conflicts.)
  4. apply the saved patch (perhaps, by pulling from the saved "branch", i.e., the copy of the darcs repo which I have saved on step 2).
  5. unsuspend all remaining patches. (Resolving all arising conflicts.)

Here are some notes on how all this has proceeded.

1. suspend the dependent patches

If among the patches dependent on the patch you want to re-order there is a single "minimal" one (according to the graph of dependencies), then you simply give the command to suspend it (and after that there will be no "active" patches which would depend on the re-ordered patch):

darcs suspend -h <MINIMAL-DEPENDENT-HASH>

(and confirm the suspension of all other dependent patches).

Of course, if there are several minimal dependent patches, you have to suspend each (each's subgraph will be asked for suspension).

2. save and revert the unwanted changes

Preparation

First, I look at the changes I'm going to work with:

darcs diff -h 61fbb4aeac9e69cf30d232eda274c18194d7a8d9 --diff-command='emacs -f ediff-directories-with-ancestor-command %1 %2'

(The change was logically simple, but diff showed it in a complicated way, so, here, I launched Emacs's ediff via a special function I had written for this purpose.)

I saw that the change included some cleanup and the addition of a new feature. So, the plan is now to split it: unrecord the patch, and record two patches instead.

darcs unrec -h 61fbb4aeac9e69cf30d232eda274c18194d7a8d9

Now, I can view and (perhaps, work) with the changes with ediff, too.

darcs diff --diff-command='emacs -f ediff-directories-with-ancestor-command %1 %2'

First, I record the cleanup patch (selecting and editing only the relevant hunks). Then, the added action:

darcs rec -m 'examples/Process.hs: code cleanup (present as a sequence of actions and error handling)'
darcs rec -m 'examples/Process.hs: print the C program (from the AST) after the check (as gcc -E does)'

Saving as a patch (a variant)

One could use darcs obliterate -o or -O to save the obliterated change, and then restore it with darcs apply (according to that advice).

But I proceeded differently:

Saving as a branch (a variant)

Cloning didn't work for a repo with suspended patches:

~/TOOLS/prog/language-c $ darcs clone . ../language-c_printAST

darcs failed:  Can't clone a repository with a rebase in progress
~/TOOLS/prog/language-c $ 

So, let's make a copy (and check whether we would be allowed to pull from it):

~/TOOLS/prog/language-c $ cp -a ../language-c ../language-c_printAST
~/TOOLS/prog/language-c $ darcs pull ../language-c_printAST

darcs failed:  Incompatibility with repository /home/imz/TOOLS/prog/language-c_printAST:
Cannot transfer patches from a repository where a rebase is in progress
~/TOOLS/prog/language-c $ cd ../language-c_printAST/
~/TOOLS/prog/language-c_printAST $ darcs rebase obliterate
<...>
Really obliterate all undecided patches? y
Rebase finished!
~/TOOLS/prog/language-c_printAST $ cd ../language-c
~/TOOLS/prog/language-c $ darcs pull ../language-c_printAST
HINT: if you want to change the default remote repository to
      /home/imz/TOOLS/prog/language-c_printAST,
      quit now and issue the same command with the --set-default flag.
No remote patches to pull in!
~/TOOLS/prog/language-c $ 

Ok, good, so we will pull from that repo later.

Revert the changes

Throw away the unwanted (or re-ordered) patch:

darcs obliterate

3. Unsuspend the patches that should come before it

It's a good idea to make a backup copy of the repo at this point, because you might screw something up during the unsuspending and resolving conflicts.

Unsuspend the patches that should come before it. (Unfortunately, external merge tool is not supported in unsuspend.) It's better to unsuspend them one by one as you'll have to resolve the conflicts caused by each one and amend the patch:

darcs rebase unsuspend
# resolve conflicts
darcs amend
# repeat for the remaining patches you want to have

4. Apply the saved patch

darcs pull ../../language-c_printAST
# resolve conflicts
darcs amend

5. Unsuspend all remaining patches.

(Again, it's better to do this one by one.)

darcs rebase unsuspend
# resolve conflicts
darcs amend
# repeat for the remaining patches you want to have

(For some reason, on the first attempt, I lost a hunk in the last unsuspended patch. But I repeated everything in a copy of the backup copy, and there I reached the wished final state.)

Community
  • 1
  • 1
imz -- Ivan Zakharyaschev
  • 4,921
  • 6
  • 53
  • 104
  • This is pretty much right. There are some small things darcs could do better - supporting external merge, and allowing clones/pulls etc with a rebase in progress. Also, if you suspend the patch you want to edit itself, then darcs will automatically suspend everything that depends on it. Then you can unsuspend that patch and continue. Note that this will change the patch identity, but it doesn't really matter given you want to edit it anyway. More generally, darcs ought to develop higher-level idioms to make operations like this easier, but it's not clear what those should be. – Ganesh Sittampalam Dec 28 '15 at 22:04
  • @GaneshSittampalam Yes, in this answer I didn't mention that explicitly, but I probably already understood that when writing the answer and can agree/confirm that: that suspending a patch other patches depend on will suspend the dependent pacthes automatically. And you are right: this can be re-used to easily suspend everything which depends on the patch you want to edit and it itself and then unsuspend the patch you want to edit. However, this will change the identity of the unsuspended patch. – imz -- Ivan Zakharyaschev Dec 29 '15 at 08:22
  • @GaneshSittampalam As for a higher-level tool: perhaps, suspending to several different (named) stores could be useful. At least, for the re-ordering task, it would be an obvious solution: to suspend to two stores, and then unsuspend in different order. – imz -- Ivan Zakharyaschev Dec 29 '15 at 08:26