// Copyright 2017-2025 WIT.COM Inc. All rights reserved. // Use of this source code is governed by the GPL 3.0 package main import ( "fmt" "path/filepath" "go.wit.com/lib/protobuf/gitpb" "go.wit.com/log" ) // reverts all repos back to the original master branches // automatically deletes local devel and user branches func doClean() error { // fix this to work, then delete all the other options for "forge clean' if err := doAllCheckoutMaster(); err != nil { // badExit(err) } all := me.forge.Repos.SortByFullPath() for all.Scan() { repo := all.Next() if repo.GetCurrentBranchName() != repo.GetMasterBranchName() { continue } if repo.IsDirty() { continue } // when publishing, clean out the details of that if it's still there if repo.GetTargetVersion() != "" { repo.SetTargetVersion("") configSave = true } // try to delete user if err := doRepoCleanUser(repo); err != nil { log.Info(repo.GetGoPath(), err) } // try to delete devel doRepoCleanDevel(repo) } found := gitpb.NewRepos() total := 0 // find all repos that aren't "clean" all = me.forge.Repos.SortByFullPath() for all.Scan() { repo := all.Next() total += 1 // find repos not on master branch if repo.GetCurrentBranchName() != repo.GetMasterBranchName() { found.AppendByFullPath(repo) continue } // find dirty repos if repo.IsDirty() { found.AppendByFullPath(repo) continue } // find repos that still have a local user branch if repo.IsLocalBranch(repo.GetUserBranchName()) { found.AppendByFullPath(repo) continue } // find repos that still have a local devel branch if repo.IsLocalBranch(repo.GetDevelBranchName()) { found.AppendByFullPath(repo) continue } } // display all the repos that aren't clean to the user log.Printf("\n") // padding for now if argv.Verbose { me.forge.PrintHumanTableDirty(found) } else { me.forge.PrintHumanTable(found) } log.Printf("\n") // padding for now if found.Len() == 0 { log.Printf("%d repos are not clean\n", found.Len()) } else { log.Info("All repos are clean", total, found.Len()) } return nil } /* func doesLocalBranchExist(repo *gitpb.Repo, branch string) bool { return repo.Exists(filepath.Join(".git/refs/heads", branch)) } */ func doRepoCleanDevel(repo *gitpb.Repo) error { if !repo.IsLocalBranch(repo.GetDevelBranchName()) { // there is no local branch named 'devel' return nil } if repo.GetCurrentBranchName() != repo.GetMasterBranchName() { return log.Errorf("%s not on master branch:", repo.GetFullPath()) } if repo.IsDirty() { return log.Errorf("%s is dirty:", repo.GetFullPath()) } if err := justDeleteTheDevelBranchAlready(repo); err != nil { log.Info("justDeleteTheDevel() err", repo.GetGoPath(), err) configSave = true return err } return nil } // removes all local user branches func doRepoCleanUser(repo *gitpb.Repo) error { if repo.IsDirty() { return nil } bruser := repo.GetUserBranchName() brdevel := repo.GetDevelBranchName() if repo.IsBranchRemote(bruser) { log.Info("forge is designed to always have local only user branches", bruser) return fmt.Errorf("forge is designed to always have local only user branches") } if !repo.IsLocalBranch(bruser) { // there is no local user branch return nil } // will you loose work if you delete your user branch? // if DevelBranchExists() // then if UserBranchCommits exist in DevelBranch // DeleteUserBranch is safe if repo.IsLocalBranch(brdevel) { b1 := repo.CountDiffObjects(bruser, "refs/heads/"+brdevel) // should be zero if b1 == 0 { // every user branch exists in devel. delete user branch cmd := []string{"git", "branch", "-D", bruser} // log.Info("USER IS IN DEVEL", repo.GetGoPath(), cmd) _, err := repo.RunVerboseOnError(cmd) return err } } brmaster := repo.GetMasterBranchName() // will you loose work if you delete your user branch? // if master branch exists() // then if all user commits exist in master // delete user branch is safe if repo.IsLocalBranch(brmaster) { b1 := repo.CountDiffObjects(bruser, "refs/heads/"+brmaster) // should be zero if b1 == 0 { cmd := []string{"git", "branch", "-D", bruser} // log.Info("USER IS IN DEVEL", repo.GetGoPath(), cmd) _, err := repo.RunVerboseOnError(cmd) return err } } return fmt.Errorf("%s branch has unique commits", bruser) } // if you call this, there is no going back. no checks anymore. nothing // it deletes the 'devel' branch. git branch -D "devel". END OF STORY func justDeleteTheDevelBranchAlready(repo *gitpb.Repo) error { branch := repo.GetDevelBranchName() remote := filepath.Join("origin", branch) if me.forge.Config.IsReadOnly(repo.GetGoPath()) { if repo.IsDevelRemote() { // just make sure the remote & local branches are the same return repo.DeleteLocalDevelBranch() } } // check against remote if it exists if repo.IsDevelRemote() { b1 := repo.CountDiffObjects(branch, remote) // should be zero if b1 == 0 { cmd := []string{"git", "branch", "-D", repo.GetDevelBranchName()} // log.Info("DEVEL IS IN REMOTE", repo.GetGoPath(), cmd) _, err := repo.RunVerboseOnError(cmd) return err } cmd := []string{"git", "push"} log.Info("DEVEL LOCAL NEEDS GIT PUSH TO REMOTE", repo.GetGoPath(), cmd) err := repo.RunVerbose(cmd) return err } // remote doesn't exist, check against master master := repo.GetMasterBranchName() b1 := repo.CountDiffObjects(branch, "refs/heads/"+master) // should be zero if b1 == 0 { cmd := []string{"git", "branch", "-D", repo.GetDevelBranchName()} // log.Info("DEVEL IS IN REMOTE", repo.GetGoPath(), cmd) _, err := repo.RunVerboseOnError(cmd) return err } cmd := []string{"git", "merge something somehow"} log.Info("DEVEL LOCAL NEEDS GIT MERGE TO MASTER", repo.GetGoPath(), cmd, b1) // _, err := repo.RunVerbose(cmd) return nil }