Rebase a branch in a Git repository
Replays a branch on top of another one and pushes the rewritten branch back into the repository Clarive hosts. Like Merge a branch in a Git repository, the work happens in a throwaway clone on the Clarive server, and the clone is deleted whether the rebase worked or not.
Reach for it when you want a branch to carry the latest upstream work without a merge commit in the way. The cost is that the branch is rewritten: every commit gets a new id, and the push that saves the result is a forced one.
Fields¶
Repository¶
The repositories to work on. More than one entry is allowed, and each is cloned, rebased and pushed in turn. The picker offers variables as well as repository resources, and a variable that resolves to several ids separated by commas counts as several repositories.
Every entry costs a full clone on every run.
Blank stops the op with a missing-repository error.
Branch¶
The branch that gets rewritten, the source side. Its commits are the ones replayed, and it is this
branch that is pushed back at the end. Expands ${var} against the stash.
Leave it blank and the op stops with a missing-value error whose wording talks about a "from" value
rather than about Branch. It is this field it means.
Upstream Branch¶
The branch the commits are replayed on top of. Expands ${var}. It is read only, never written, so
this side of the pair comes out of the op unchanged.
Blank stops the op with a missing-upstream error.
Options¶
Extra options handed to the rebase, as one string. Expands ${var}. The string is split on
whitespace, so --rebase-merges --keep-empty arrives as two options. There is no shell and no
quoting, so an option whose value contains a space cannot be expressed here. The upstream branch is
always appended after whatever you type.
Leave it blank for a plain rebase, which is what most rules want.
Interactive options do not work. There is no terminal and no editor behind this op, so anything that
would open one fails or hangs. If you use options that can stall, put a value in Timeout on the
op's Options tab. It arms a clock before the op starts and aborts it when the time runs out. Trap
timeout is no help here: it only counts down once an error has already been trapped, so a rebase
that is still waiting never reaches it.
The forced push¶
This is the part that catches people. The rewritten branch is pushed with force, so the hosted repository takes the new history whatever it was holding before.
A push that would be rejected elsewhere goes through here. If somebody pushed to that branch, or another rule wrote to it, between the moment this op cloned and the moment it pushed, those commits are dropped from the branch without an error and without a log line. Nothing in the rule reports it.
Anyone with the branch checked out has to reset to the new history. Commit ids change even for commits the rebase did not have to modify. A tag or a topic that references an old id keeps pointing at a commit no branch reaches any more.
Run this op only on branches your rules own, and never on a branch people share, such as an integration or production branch.
Failure, ordering and rollback¶
Repositories are handled in picker order. A conflict during the replay stops the op on that repository with the error text and Git's output attached. The clone is discarded, so that repository keeps its original branch, while repositories earlier in the list keep the rebases they already received.
Conflicts cannot be resolved here, since there is nobody to resolve them. Any conflict is a failure.
The op returns nothing, so a Return Key on it holds an empty value. A branch already sitting on top of its upstream is rebased to the same result and pushed again, which is a success with no visible change.
Both directions are enabled on a new op, so a rebase left at its defaults runs again during a rollback pass and force-pushes a second time. It does not put the old history back. Untick Run Rollback, and take a tag on the branch beforehand if you want the old commits to stay reachable.
Combining with other ops¶
Tag the branch before the rebase and you have a way back, since the tag keeps the pre-rebase commits alive even though no branch points at them. Drop the tag afterwards with Delete a reference in a Git repository once you are satisfied.
Rebase then merge is the usual pair for a linear history: bring the topic branch up to date here,
then run Merge a branch in a Git repository with
No Fast-Forward? unchecked so the target moves forward without a merge commit.
Guard the op with IF var condition THEN so it only runs for the branches you intend, and wrap it in TRY with CATCH to turn a conflict into a message on the topic rather than a stopped job. For a repository set known only at run time, use FOREACH CI.
Examples¶
Bring a topic's feature branch up to date with the integration branch before it is reviewed.
Repository ${repository}
Branch feature/${topic_id}
Upstream Branch develop
Options
Rebase across a list of repositories held in a variable, keeping merge commits in the replayed range.
Repository ${project_repos}
Branch ${branch_name}
Upstream Branch ${production_branch}
Options --rebase-merges