Xavier_Ex
Xavier_Ex

Reputation: 8810

programmatically use git rebase -i

I wrote a node module that uses git to make a bunch of commits from time to time. Considering the commits are better if grouped into one single commit, I'd like to use "git rebase -i" to squash them into one.

However squashing is only possible in interactive mode, which means I need to manually edit the lines in the editor that pops up when "git rebase -i" is called. I would like to know if it is possible to do this process programatically? So for example when the user calls "save" function my module would make a bunch of commits, and then automatically squash them together.

UPDATE

To be more precise of what I'm doing, when the "save" function is called, it is passed a bunch of commits to be "publish". My module will then cherry pick those commits and put them into the "publish" branch. This is a single "publish" action, but it generates a bunch of commits on the "publish" branch. What I wanna do is to squash the commits on the publish, so when I do "git log" all I see is "publish version 1", "publish version 2" etc, instead of 5 or 10 commits per publish action.

Upvotes: 5

Views: 1178

Answers (1)

cmbuckley
cmbuckley

Reputation: 42458

After seeing your update to your question, one of the two options below may work, depending on your usage:


The first (and simpler) case is where your unpublished work is always a single sequence of commits, and the published work is on the same branch, but a bit further behind:

  • You have an unpublished branch and a published branch. The latter is contained within the former (i.e. some number of commits behind).
  • The save action means that a hash abcdef from unpublished should now be the HEAD of published.
  • It performs git checkout published && git merge --ff-only abcdef.
  • This causes published to fast-forward to that commit.

The second is where the commits that can be published are not necessarily a linear sequence. This becomes a little more complicated as if you reorder commits, you may have to resolve conflicts that arise. I would solve that in the following way:

  • Assume again that there are unpublished and published branches.
  • The save action comprises some hashes from unpublished.
  • It should create a new, temporary branch like publish-2013-04-15-001 from the current published branch (the name of the new branch is largely irrelevant, as long as it's unique/new).
  • Perform git cherry-pick <hash> for each hash that should be saved. (If there are multiple commits, this is where you could get conflicts and may need to resolve them somehow.)
  • Once done, check out published branch.
  • Perform git merge --squash -m 'Publish version <n>' publish-2013-04-15-001.
  • (Optional) delete the temporary branch.

Since the second option introduces more complication, there are other options that you might want to consider to make it easier to debug the published process:

  • Should I keep the temporary branches around for tracking/logging?
  • Could the individual commits be kept separate on the merged branch (leave out --squash)?
  • If so, you could identify the save by forcing a merge commit (--no-ff).

EDIT: Here's an example using --no-ff. Each version $N does the following:

git checkout -b publish-$N published
# cherry-pick commits
git checkout published && git merge --no-ff publish-$N -m "Publish version $N"

example tig graph

Upvotes: 2

Related Questions