Reputation: 10556
Most of the time, when doing some work, one ends up with changes that should be saved into different commits.
I am looking for best practices for how to do that in a good way.
Of course, the basic answer is to use git add -p
.
The problem with that basic answer is that it doesn't enable to test a given state of the repository before committing. Very often, this would mean forgetting to add some imports, or forgetting a dependency between some staged code and some unstaged parts. As a result, a given commit would not pass a build.
Thus I am looking for a way to create several commits, with the ability to run tests for each commit.
The workflows I have tried so far are the following:
As long as there is more than 1 commit to do with current changes, repeat:
git add -N <new files> # To mark all new files as potentially stageable
git add -p # To add only first commit's changes
git commit
git stash save -k -u
git stash pop
git commit --amend --no-edit
git stash save -k -u
git stash pop
The main problem I see with this workflow is the fact that it doesn't make a lot of sense to commit something without having tested it, knowing that it is likely to be amended shortly after.
As long as there is more than 1 commit to do with current changes, repeat:
git add -N <new files> # To mark all new files as potentially stageable
git add -p # To add only first commit's changes
git stash save -k -u # To remove everything that was not added
git stash pop
git stash save -k -u
git commit
git stash pop
The main problem I find with that workflow, is the fact that git stash pop
often fails with a conflict. That results in having to redo git add -p
on all the conflict files, which can be very time consuming. This happens among other things when trying to add only part of a new file.
Are there other better practices for saving into several commits while testing each one ?
Upvotes: 4
Views: 167
Reputation: 46482
Forget stash
, use interactive rebase
. Commit everything as needed and clean up the mess later.
I'd suggest using git gui
to create the commits, but that's a minor point. After a while I get a list of commits like
Implement feature A
Refactor mess B
f A 1
f A 2
f B 3
Improve formatting
f A 4
f B 5
where "f A" means "fixup for A". Then I call
git rebase -i
or maybe
git rebase -i HEAD~8
get a list of commits and reorder them like
Improve formatting
Implement feature A
f A 1
f A 2
f A 4
Refactor mess B
f B 3
f B 5
I do this reordering in many small steps, just in case it fails. I use git diff ORIG_HEAD
in order to verify that the final version stayed the same.
As the last step I change "pick" to "f" (fixup) so that I end up with three commits only.
For running tests on the intermediate steps, you can also use rebase. Just replace "pick" with "e" (edit), so that git stops after each commit (use git rebase --continue
to continue to the next commit).
When doing such a commit cleanup, I usually run the tests last as they usually pass and, in case they don't, the fix is usually obvious.
When rebasing, be careful not to change commits pushed to a shared repository.
Upvotes: 1
Reputation: 94809
The best answer is CI (continuous integration) server. You push as many commits as you want, CI server pulls the branch, checkout commits one by one and run tests on every commit.
Upvotes: 0