In our current workflow, we have 2 main git branches:
master
- stable release branch
testing
- were everyone tests their code
Now every developer creates new branches for each feature they develop. When they are done, they merge it to testing
, and when our QA says it's good to go, they merge their branch into master
which gets deployed into production.
As time passes, our testing
branch get polluted with commits that never make it to production. Abandoned features, stuff that got rewritten instead of fixed and other things.
To keep master
and testing
in a somewhat consistent state, we'd like to "reset" testing
from time to time. Right now, we do so by entirely removing testing
and re-branching it from master
.
The big problem here is that we need to make sure that every single developer also remove his local testing
branch and checks out a fresh copy of it.
If one developer forgets to do that and pushes to testing again, all the dirty commits that we are trying to get rid of are back.
Is there any way to reset a branch on the server in a way that it distributes to all users?
An acceptable solution would also be putting the testing
branch in a state where nobody can push to it anymore without doing a reset locally. But I can't think of a way how to do it.
Creating a diff between master
and testing
and reverting commits is not an option as this prevents each of these commits to ever go into testing again.
Ideally, I'd have a script that performs this reset periodically and no interaction (other than git pull
) is needed on each users local environment.
The short answer is "no, you can't do that".
Remember that each clone is a complete stand-alone entity1 that is little different from the source repository it was cloned-from, except for its origin
and (depending on clone options) some of the initial branch states.2 Once someone has picked up a branch named testing
and called it origin/testing
:
origin/testing
that their git will update automatically, and even prune (delete) if directed, when they connect to remote origin
.So far so good, and this "automatic prune" action sounds great. If you can convince them to set remote.origin.prune
to true
:
$ git config remote.origin.prune true
then once you delete your branch named testing
, their origin/testing
will go away automatically on their next git fetch origin
.
The problem comes in when they create a branch named testing
. Their git won't delete this branch unless and until they ask it to. As far as their git is concerned, their private branches are their private branches. You can't convince their git to delete their private testing
any more than you can convince their git to delete their private experiment-22
. They created it; it's their repository; they keep control of it.
(Note that they also keep control of automatic pruning, since they can git config
the remote.origin.prune
setting away, or to false
, at any time as well. That setting is meant for their convenience, not yours—it goes with their remote.origin.fetch
settings, which they change so that their git fetch
changes what it does; its initial default setting is something they created when they ran git clone
.)
You can continue with this model, provided you get all your developers to do their own controlled deletion or cleaning of this branch label. But it's not the way to go. Instead, you should use another model: create a new, different branch label for your developers for the new (and different) line of development you're doing.
For instance, you might have dev-feature-X
as a temporary branch that your developers can all share for working on Feature X. When you're all done with it, you keep or delete it at leisure, and your developers pick up the deletion automatically (with the prune setting) or not at their leisure. Meanwhile you've created dev-feature-Y
as a temporary branch that your developers can all share for working on Feature Y, and so on.
1Ignoring special cases like "shallow" clones that don't apply here, at least.
2If you clone without --mirror
, the source's branches become your remote branches, and you have no local branches at all until you check one out (usually master
, usually as the last step of the clone
command). Also, clone can't see the source's hooks, so those are not cloned. Neither is any other special state in the .git
directory, such as items in .git/info
. None of these affect the principles of ordinary branch usage, though.