Reputation: 3141
Often I want to break up a large commit:
git commit -a -m "Monolith"
I know how to split a commit (git gui
is my friend) but sometimes I actually want to rework it by hand...
git branch temp # Keep a reference to all my hard work
git reset --hard HEAD~ # Rewind 'my-topic' branch
# hack hack
git commit -a -m "Refactor 1"
# hack hack
git commit -a -m "Refactor 2"
To complete it, I then want to apply another commit that brings the code back to exactly the state stored in branch temp
, usually including the original commit message.
Is there an easy way to do this?
I imagined that a merge-strategy on cherry-pick
might get the job done, but alas none of these did:
git cherry-pick --strategy=theirs temp # I am told about conflicts
git status # ... But here I find no changes to commit!
git cherry-pick --strategy=ours temp # Worth a try. Nope, empty commit.
git cherry-pick --strategy=recursive --strategy-option=ours temp # Partial result, bits are missing
I know of one way to achieve this:
git log -1 temp # note the SHA
git checkout temp
git reset --soft my-topic
git commit -C <SHA-from-above> # branch 'temp' now contains the desired commit
git checkout HEAD -B my-topic
git br -d temp
However this seems a very error-prone way to go about it. Any little mistake and the commits I want to keep might not be in any branch (git reflog
to the rescue...). I'd like to find something more logical and easier to remember/do.
Upvotes: 1
Views: 88
Reputation: 45679
j6t's answer has some reasonable options, but I prefer a simplified version of the procedure you yourself suggest. (I'm not sure what errors you're afraid of making, but I suspect they arise from the fact that you're taking unnecessary steps.)
git checkout temp
git reset --soft my_topic
git checkout my_topic
git commit -C temp
git branch -D temp
This may seem like a strange preference, since git checkout -- .
(one of their suggestions) looks like a one-liner; but note my comment on their answer. And their are other subtle gotchas that can creep in - like what if you forget you're not at the worktree root. You can work around all of those, of course...
So you can either be in the habit of doing git rm
first, or "know" when you need to (an opportunity to make mistakes). And you can use :/:
instead of .
as a matter of habit (and get used to explaining it to everyone you work with), or always double-check that you're in the root (another opportunity to make mistakes). And then you get
git rm -- :/:
git checkout temp -- :/:
git commit -C temp
git branch -D temp
which is only one simple command "less" than the solution I'm suggesting.
Upvotes: 1
Reputation: 60305
The direct route to a straight import of another commit's snapshot is the core command to do exactly that:
git read-tree -u temp
followed by
git commit -C temp
to commit that with temp
's commit message.
git read-tree
is what underlies almost every command that updates the index and work tree from existing repo contents. git reset
is some option-picking logic around git update-ref HEAD
and git read-tree
; git checkout
is also some option-picking logic around git update-ref HEAD
and git read-tree
; git merge
is some fairly heavy-duty cleanup work on the results of a git read-tree
... yeah. By the way, git commit
is some option-picking logic around git update-ref HEAD
git write-tree
and git commit-tree
(which latter adds a single tiny object to the object db).
Upvotes: 0
Reputation: 13387
To recreate the tree at temp
, there are (at least) two fairly simple ways: One is
git checkout temp -- .
and the other is
git diff temp | git apply --index
After that, you create the commit with the same commit message using
git commit -C temp
The two options each having their pros and cons. The checkout
route does not remove files that are not present in temp
anymore. The apply
route does not work with binary files.
Side note: With modern Git you would use git restore
instead of git checkout
, but I'm and old-timer and haven't learnt to use it.
Upvotes: 2
Reputation: 535306
Forget about your temp branch. Instead of reset hard, reset mixed.
The result is that the index is reset but the working tree is not. Now you can add and commit in any combinations you like, and then just add everything else and commit to finish up.
See my https://stackoverflow.com/a/59675191/341994 for more.
Upvotes: 0