1

So during a hectic coding session, I forgot to do git commit as I did baby steps. Now I have fifty changes in my working directory. And these changes are related to five separate tasks. So I would like to put each change/hunk in to one of five commit messages.

I have the five commit messages noted down in my notepad.

Does magit make this easy? How do I go about doing this with magit? An ideal workflow would be, I am presented each hunk, and I choose which existing commit or new commit message it should be "filed" under.

  • 1
    Actually, it isn't very uncommon to intentionally get into the situation you are in. Typically, I'd do small commits as I work, but before merging them into master, I'd squash all of them, then reset to previous commit and recombine the changes in such a way that they make sense together. – wvxvw Nov 26 '17 at 10:28
4

Magit makes this very easy; although you will need to consider one commit at a time.

In the magit status buffer, with all changes unstaged, expand all of the unstaged changes with TAB, and then use n and p to navigate through those changed files/hunks.

Now, considering commit A, for every unstaged hunk that is relevant to A type s to stage that hunk. If you need to split a hunk it's generally easiest to mark a region of the hunk (set the mark with C-SPC) and then s will stage only that marked region.

(Alternatively, - and + tell git to produce smaller or bigger hunks respectively, but in most cases I find magit's region handling feature far more efficient.)

Work your way through the changes until you have staged everything required for commit A, and then commit it. You can first expand all of the staged changes with TAB to verify what you are about to commit1. Unstaging with u works the same as s, if you accidentally2 staged something not wanted in commit A.

Now simply repeat the process to build the other commits.


1 Equivalent to git diff --cached. I highly recommend making this review step a habit for every commit you make.

2 or indeed intentionally -- at times it's simpler to stage a large thing, and then unstage selected bits of it.

  • 1
    And if you find after the fact that you missed something, you can use the fixup commit features to easily amend previous commits. – phils Nov 24 '17 at 1:52
  • thanks @phils. this is a great answer. This question is about five tasks, and this answer makes me go through the changes five times. A better solution (if there was one) would make me go though the changes one times, "filing" them to one of five commit messages as I go along. – american-ninja-warrior Nov 26 '17 at 15:02
  • 1
    I know of no such facility. The question reminds me of github.com/magit/magit/issues/1729 though. – phils Nov 26 '17 at 21:01
  • 1
    @joshsverns you could commit each hunk immediately with commit message 1, 2, 3, 4, or 5 to "file" them appropriately, and then interactive rebase afterwards to combine them. – npostavs Nov 27 '17 at 0:25
  • magit issue 1729 mentions exactly the same issue I'm facing: " ... So you're talking about doing a single manual pass through all the changes, during which you 'tag' each hunk in turn as being for any one of a series of known/planned commits; rather than doing multiple passes through the changes (one per commit; during which you stage only the hunks relevant to that commit) ..." – american-ninja-warrior Nov 27 '17 at 12:32
0

This is what I'm experimenting with right now.

First instead of writing down the five commit messages on paper, create five empty commits.

Now Inside magit-status, pick an unstaged hunk, and stage it. Now do c (commit), and F (instant Fixup) and you're presented with a list of recent commits you can "add on to".

Pick one, C-c to apply. Rinse and repeat.

Sounds too good to be true. I'm going to try this tommorow

  • The instant fixup feature is indeed excellent, but it's also doing quite a lot of work behind the scenes. I believe it needs to stash all unstaged changes, create the fixup commit, then rebase to squash the fixup into the selected commit, and finally reapply the stash to restore the other changes. I was sufficiently dubious about this being a suitable answer to your question that I refrained from even suggesting it, other than my comment about fixing any mistakes later. – phils Nov 29 '17 at 6:29
  • In short, yes, it kinda allows you to do what you were asking for; but it's such a heavy-handed approach with the continual autostashing and rebasing -- things which can sometimes be annoying to recover from if anything goes awry -- that it seems like asking for trouble to make that a common workflow. Give it a whirl, though -- being familiar with magit's fixup features is highly recommended. – phils Nov 29 '17 at 6:42

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.