Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,34 @@ brew install gittower/formula/git-flow-next
git flow feature finish my-feature
```

## Configuration

git-flow-next supports various configuration options through Git config. Here are some key options:

### Fetch Before Finish

Control whether to fetch from remote before finishing topic branches:

```bash
# Enable fetch for feature branches
git config gitflow.feature.finish.fetch true

# Enable fetch for release branches
git config gitflow.release.finish.fetch true

# Enable fetch for hotfix branches
git config gitflow.hotfix.finish.fetch true
```

You can also use command line options to override the configuration:
- `--fetch` - Fetch from remote before finishing branch
- `--no-fetch` - Don't fetch from remote before finishing branch

Example:
```bash
git flow feature finish my-feature --fetch
```

## Documentation

For detailed documentation, please visit our [documentation site](https://github.com/gittower/git-flow-next/wiki).
Expand Down
68 changes: 68 additions & 0 deletions cmd/finish.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ type BranchRetentionOptions struct {
KeepRemote *bool // Whether to keep the remote branch (nil means use config default)
KeepLocal *bool // Whether to keep the local branch (nil means use config default)
ForceDelete *bool // Whether to force delete the branch (nil means use config default)
ShouldFetch *bool // Whether to fetch from remote before finishing (nil means use config default)
}

// FinishCommand is the implementation of the finish command for topic branches
Expand Down Expand Up @@ -234,6 +235,58 @@ func finish(state *mergestate.MergeState, branchConfig config.BranchConfig, tagO
}
fmt.Printf("Switched to branch '%s'\n", state.ParentBranch)

// Determine if we should fetch before finishing
shouldFetch := false
if retentionOptions != nil && retentionOptions.ShouldFetch != nil {
// Command line option overrides config
shouldFetch = *retentionOptions.ShouldFetch
} else {
// Check config if no command line option specified
configKey := fmt.Sprintf("gitflow.%s.finish.fetch", state.BranchType)
fetchConfig, err := git.GetConfig(configKey)
if err == nil && fetchConfig == "true" {
shouldFetch = true
}
}

// Perform fetch if requested
if shouldFetch {
// Get remote name from config
cfg, err := config.LoadConfig()
if err != nil {
return &errors.GitError{Operation: "load configuration", Err: err}
}

remoteName := cfg.Remote
fmt.Printf("Fetching from %s...\n", remoteName)
if err := git.Fetch(remoteName); err != nil {
fmt.Fprintf(os.Stderr, "Warning: %v\n", err)
} else {
// After successful fetch, merge remote changes into the target branch
remoteBranch := fmt.Sprintf("%s/%s", remoteName, state.ParentBranch)

// Check if remote branch exists
if git.RemoteBranchExists(remoteName, state.ParentBranch) {
fmt.Printf("Merging remote changes from %s into %s...\n", remoteBranch, state.ParentBranch)
if err := git.Merge(remoteBranch); err != nil {
if strings.Contains(err.Error(), "conflict") {
// Save state before returning conflict error
state.CurrentStep = "merge_remote"
if err := mergestate.SaveMergeState(state); err != nil {
return &errors.GitError{Operation: "save merge state", Err: err}
}

msg := fmt.Sprintf("Merge conflicts detected while merging remote changes. Resolve conflicts and run 'git flow %s finish --continue %s'\n", state.BranchType, state.BranchName)
msg += fmt.Sprintf("To abort the merge, run 'git flow %s finish --abort %s'", state.BranchType, state.BranchName)
fmt.Println(msg)
return &errors.UnresolvedConflictsError{}
}
fmt.Fprintf(os.Stderr, "Warning: Failed to merge remote changes: %v\n", err)
}
}
}
}

// Perform merge based on strategy
fmt.Printf("Merging using strategy: %v\n", strings.ToLower(branchConfig.UpstreamStrategy))
var mergeErr error
Expand Down Expand Up @@ -291,6 +344,21 @@ func finish(state *mergestate.MergeState, branchConfig config.BranchConfig, tagO

func handleContinue(state *mergestate.MergeState, branchConfig config.BranchConfig, tagOptions *TagOptions, retentionOptions *BranchRetentionOptions) error {
switch state.CurrentStep {
case "merge_remote":
// Check if there are still conflicts from merging remote changes
if git.HasConflicts() {
return &errors.UnresolvedConflictsError{}
}

// Move to the main merge step
state.CurrentStep = "merge"
if err := mergestate.SaveMergeState(state); err != nil {
return &errors.GitError{Operation: "save merge state", Err: err}
}

// Continue with the regular merge
return finish(state, branchConfig, tagOptions, retentionOptions)

case "merge":
// Check if there are still conflicts
if git.HasConflicts() {
Expand Down
9 changes: 9 additions & 0 deletions cmd/topicbranch.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,10 @@ func registerBranchCommand(branchType string) {
abortOp, _ := cmd.Flags().GetBool("abort")
force, _ := cmd.Flags().GetBool("force")

// Get fetch-related flags
fetch, _ := cmd.Flags().GetBool("fetch")
noFetch, _ := cmd.Flags().GetBool("no-fetch")

// Get tag-related flags
tag, _ := cmd.Flags().GetBool("tag")
noTag, _ := cmd.Flags().GetBool("notag")
Expand Down Expand Up @@ -147,6 +151,7 @@ func registerBranchCommand(branchType string) {
KeepRemote: getBoolFlag(keepRemote, noKeepRemote),
KeepLocal: getBoolFlag(keepLocal, noKeepLocal),
ForceDelete: getBoolFlag(forceDelete, noForceDelete),
ShouldFetch: getBoolFlag(fetch, noFetch),
}

// Call the generic finish command with the branch type and name
Expand All @@ -159,6 +164,10 @@ func registerBranchCommand(branchType string) {
finishCmd.Flags().BoolP("abort", "a", false, "Abort the finish operation and return to the original state")
finishCmd.Flags().BoolP("force", "f", false, "Force finish a non-standard branch using this branch type's strategy")

// Add fetch-related flags
finishCmd.Flags().Bool("fetch", false, "Fetch from remote before finishing branch")
finishCmd.Flags().Bool("no-fetch", false, "Don't fetch from remote before finishing branch")

// Add tag-related flags
finishCmd.Flags().Bool("tag", false, "Create a tag for the finished branch")
finishCmd.Flags().Bool("notag", false, "Don't create a tag for the finished branch")
Expand Down
Binary file added git-flow-next
Binary file not shown.
Loading