threads / discuss / 32038

Re: Revert option for git add --patch

Subject: Re: Revert option for git add --patch

## tl;dr

5 messages between Nov 8, 2012 and Nov 9, 2012.

replies: 4people: 4as markdown or json

Jonathon Mah· Nov 8, 2012, 08:57 UTC · lore
Nathan,
I find myself performing similar actions to you: using git add -p to stage hunks, sometimes editing the staged patch; and keeping mental notes of things I wanted to revert, sometimes changing them in the editor in another window, and sometimes reverting them after the add session with git checkout -p).
The interactive staging-and-editing tool could be improved, but I'm not sure that tool should be called 'git add -p'. git add doesn't touch the working tree — at least I hope not, because I wouldn't expect it.
But I eagerly support more discussion. If someone does want to add this feature to "git add -p" (or named differently), I'll add a request for another letter (perhaps '!')  to edit the hunk in the working tree.
	

Jonathon Mah me@JonathonMah.com

Nguyen Thai Ngoc Duy· Nov 8, 2012, 12:00 UTC · re: Jonathon Mah · lore
On Thu, Nov 8, 2012 at 3:57 PM, Jonathon Mah <jmah@me.com> wrote:
> Nathan,
>
> I find myself performing similar actions to you: using git add -p to stage hunks, sometimes editing the staged patch; and keeping mental notes of things I wanted to revert, sometimes changing them in the editor in another window, and sometimes reverting them after the add session with git checkout -p).

I agree. I'd be really nice to have an interactive command about hunk manipulation between HEAD (or some other ref), index and worktree in both directions (except writing to HEAD, of course). This reminds me of the "git put" discussion a while ago, which also moves code between different locations..

-- 
Duy
Jeff King· Nov 8, 2012, 15:15 UTC · re: Jonathon Mah · lore
On Thu, Nov 08, 2012 at 12:57:19AM -0800, Jonathon Mah wrote:
Show 5 quoted lines
> I find myself performing similar actions to you: using git add -p to
> stage hunks, sometimes editing the staged patch; and keeping mental
> notes of things I wanted to revert, sometimes changing them in the
> editor in another window, and sometimes reverting them after the add
> session with git checkout -p).
Yeah, I often use a similar workflow. A related one is:
  (1) Make lots of unrelated changes in the working tree.
      $ hack hack hack
  (2) Pick out hunks for the first commit.
      $ git add -p
  (3) Put the rest of the changes aside.
      $ git stash -k
  (4) Test (and possibly tweak) the result, then commit.
      $ make test
      $ git commit -m "topic 1"
  (5) Bring back the stashed changes.
      $ git stash pop
  (6) If there are still interesting changes, goto step 2.
  (7) Otherwise, discard with "git reset --hard" or "git checkout -p".

I.e., iterating on the changes to put them into several different commits (and achieving a clean, testable state before making each commit).

The downside of these workflows is that you have to say "no" to hunks multiple times (one per iteration) instead of just sorting them in a single pass. This works OK in practice, but it might be nice to have a tool that makes a single pass and lets you drop hunks into buckets (topic 1 vs topic 2 vs discard), and then apply the buckets in order, stopping to test, tweak, and commit after each one.

> The interactive staging-and-editing tool could be improved, but I'm
> not sure that tool should be called 'git add -p'. git add doesn't
> touch the working tree — at least I hope not, because I wouldn't
> expect it.

Right. I think the idea of one-pass tool is a good one, but it should not be called "git add -p".

-Peff
Bogolisk· Nov 9, 2012, 14:09 UTC · re: Jonathon Mah · lore
Jonathon Mah <jmah <at> me.com> writes:
> 
> Nathan,
> 
> I find myself performing similar actions to you: using git add -p to stage 
hunks, sometimes editing the
> staged patch; and keeping mental notes of things I wanted to revert, sometimes 
changing them in the editor
> in another window, and sometimes reverting them after the add session with git 
checkout -p).

Other front-ends like Egg and Magit has been providing the ability to move hunks back and forth, for a long time.

Jeff King· Nov 8, 2012, 20:04 UTC · lore
On Fri, Nov 09, 2012 at 08:42:33AM +1300, Nathan Broadbent wrote:
> It sounds like we want a tool that combines the functionality of 'git add
> --patch', 'git checkout --patch', and other features, so that we can
> perform various actions on 'hunks' without switching context. What do you
> think about naming this command 'git patch'?

I think it would be a slightly confusing name, given that it is not related to the usual Unix "patch" command (git's analog to that is "git apply").

I was thinking something like "git organize" because it is about organizing muddled changes. Duy mentioned my earlier "git put", which is based around the same ideas. This could be thought of as "git put --patch", I suppose.

> I'm not sure how dropping hunks into 'buckets' would work, but the main
> idea is to be able to stage, discard or edit hunks in a single pass.

Buckets are really just patches you are building up from hunks. So I think you are dealing with two buckets either way: a to-stage bucket and a to-discard bucket. Adding more buckets isn't hard; you just turn the to-stage bucket into an array of buckets.

The tricky part is figuring out how to keep the state persistent across multiple invocations. The simplest program flow for the 2-bucket case would be something like:

  for h in hunks
  do
          show hunk to user
          ask user what they want to do
          if they want to stage
             append to to-stage patch
          else if they want to discard
             append to to-discard patch
          else
             ignore the hunk
  done
  feed to-stage patch to "git apply --cached"
  feed to-discard patch to "git apply -R"

Modifying the loop to have more buckets is easy. But the end is probably something like:

  feed to-discard patch to "git apply -R"
  feed bucket[0] to "git apply --cached"
  save bucket[1..n] somewhere
  exit

Then the user gets control back, builds, tests, commits, whatever, and then runs "git organize --continue" to apply bucket[1], and so on. And since we don't know what the user did in between, we have to be ready for conflicts in applying the buckets. Hmm, this is sounding a lot like how "rebase --interactive" works.

One way to implement this would be to store each bucket as a commit against HEAD (i.e., stage it into a temporary index, then run "git write-tree" and "git commit-tree"), and then make a "rebase -i" instruction sheet like:

  pick $sha1_of_bucket_1_commit
  edit
  pick $sha1_of_bucket_2_commit
  edit

and so forth, except that we would not want our picks to actually commit (just pull the changes into the working tree and/or index).

That's just me thinking off the top of my head. Obviously what you are proposing is way simpler, and it is probably sane to start with the simple thing, and then build the more complex thing on top. But it might be worth keeping in mind the complex case when building out the infrastructure for the simple case.

-Peff

← back to recent threads