29

There's a question on SO about splitting hunks using magit, and the two solutions given are to either stage the region (mark a region, hit stage), or to shrink/grow all hunks using + & -. That's not what I'm after.

In magit's status buffer, I want to split a hunk into two hunks, at the point, or at least at the lines around the point.

Turning this (excuse my bad diff formatting)

@@ blah blah blah
- foo
+ bar
+ baz
+

Into

@@ blah blah
- foo
+ bar

@ blah blah
+ baz

When the point is on bar.

Motivations:

  • baz being a debug statement, so I'd like to drop it from the commit of foo & bar without getting rid of it.

  • bar and baz being only partially related, meaning that their changes should not be in the same commit.

  • bar is large and baz is small, making it a lot easier to split the hunk rather than select bar

  • Similar to the last point, say a 20 line commit contains a single line the middle that should not be staged. It'd be easier to split & stage the top and bottom two hunks ignoring the middle one than use the region.

  • The above can arise sometimes when the diff presentation will separate the before and after of something that's been modified, and have something unhelpful in the middle. e.g.

@@ line
- old_foo
+ random stuff
+ new foo
  • There is nothing in magit that can do this. It even more than that: The design of magit make this probably inpossible to code without a vast redesign of magit-status. – Rémi Jan 6 '15 at 12:47
  • 4
    Thanks, makes sense. Unfortunately the best I could think of would be some automation around selecting forward or backward from point and then staging. Also worth noting (for folks who haven't used the feature before) that you can use the region to both stage and unstage. For example you can stage a big hunk, then switch to the staged section and unstage a line in the middle. But agreed with @MrBones that a split-hunk option would be easier than fiddling with selection. – glucas Jan 6 '15 at 15:22
  • Interesting, selecting 2 distincts non adjacents regions. +1 – Nsukami _ Jan 6 '15 at 15:35
  • 1
    Personally I'd stage the whole hunk, and then unstage the debug statement. (My pre-commit hook catches staged debug statements, so there's no danger of me committing one.) – phils Jan 6 '15 at 19:02
  • I don't know enough about Magit to help, but I just want to point out that Emacs's diff-mode has the command diff-split-hunk which does just that. IOW your request is for a way to use diff-split-hunk (or something equivalent) from the magit-status buffer. – Stefan Nov 28 '17 at 13:46
16

As mentioned in the comments above, Magit does not support splitting a hunk into multiple hunks beyond what is possible by using git diff -U<n>. That's because Magit relies on that Git command to create the diffs. That isn't going to change, Magit will always use the diffs it gets from Git as-is.

(Actually Magit does strip some headers which are not really relevant to humans, but does restore them when applying changes. But splitting a hunk further than what -U<n> supports is a whole different story, it would lead down a rabbit hole - there's a reason why Git doesn't allow "smaller hunks", it wouldn't be able to apply them).

While Magit does not support displaying smaller hunks as asked for here, it does support applying just parts of a hunk. When the region is active while staging, then only that part of the hunk is applied.

That doesn't help much when the part which should not be staged is right in the middle of the text which should be staged. As others have suggested, what you should do in this case is to stage the whole hunk, and then unstage the line which you don't want to commit in a second step.

That could of course be automated. The only way I can see in which this could be automated is to "stage the current hunk except for the region. But I do have some doubts about how often that would actually be useful and fear that it would not be easy to implement that robustly. And so I do not currently intend to implement this.

39

You can split hunks with Magit.

Instead of just leaving the cursor inside the hunk, select the lines you want to stage from the hunk and press s. Only the selected part of the hunk will be staged, whereas the rest of the hunk still sits in the unstaged area.

That way you splitted it into two. I think you can use the same mechanism for moving parts of hunks into the stash. When using k you will just purge part of hunk.

  • 3
    IMO, this should be the accepted answer, as it satisfies the request (and I've found this answer a few times when trying to remember how to do this). – chaseadamsio Dec 28 '16 at 23:52
  • 2
    Yeah this should be accepted as answer! – copyninja Apr 25 '17 at 4:12
2

If you want to discard parts of a hunk, select the lines within the hunk you want to discard and pressing x.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.