53

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
5
  • 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
    Commented Jan 6, 2015 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
    Commented Jan 6, 2015 at 15:22
  • Interesting, selecting 2 distincts non adjacents regions. +1
    – Nsukami _
    Commented Jan 6, 2015 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
    Commented Jan 6, 2015 at 19:02
  • 1
    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
    Commented Nov 28, 2017 at 13:46

3 Answers 3

45

Update: What Magit does not support is to display the sort of tiny hunks that are used as examples in the question. This is how I understood that question: "how do I make Magit display such smaller hunks instead of the hunks it is actually displaying?" The correct answer to that is still "that's not possible" and below I give that answer using more words.

However, Magit does support "applying" only parts of a displayed hunk. To do that one has to use the region to mark the part that one wants to apply before invoking the apply command.

Here "apply" stands for a family of actions that include staging, unstaging, "actual apply" and a few others. See Applying as well as Staging and Unstaging.


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.

4
  • This does not answer the question. The answer from @Sven Rieke below provides a working solution.
    – Zach
    Commented Jul 15, 2020 at 17:06
  • 5
    Well let's say I answered the question that was actually asked: "In magit's status buffer, I want to split a hunk into two hunks", which really is not possible in the way described for the reasons given. But it is obvious that many users who find this page are looking for an answer to another, closely related question, which my post now also tries to answer.
    – tarsius
    Commented Jul 15, 2020 at 17:28
  • This does answer the question and gives a workaround: "stage the whole hunk, and then unstage the line which you don't want". I will agree even this is not optimal because then you have to search for what you just staged, unless there's a quick way to jump to that?
    – mcp
    Commented Jan 16, 2022 at 18:59
  • I created a proper question for that: Jump to last staged hunk.
    – mcp
    Commented Jan 16, 2022 at 19:10
78

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
  • 9
    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). Commented Dec 28, 2016 at 23:52
  • 3
    Yeah this should be accepted as answer!
    – copyninja
    Commented Apr 25, 2017 at 4:12
  • This was addressed by OP as not optimal. I think the best workaround was mentioned by @tarsius "...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.".
    – mcp
    Commented Jan 16, 2022 at 18:58
5

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

1
  • This removes the change from the code itself. OP wants to keep the code, just not commit it.
    – mcp
    Commented Jan 16, 2022 at 18:57

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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