async createBranchAndPush()

in app/lib/server/processors/ApiJobExecutor.ts [463:603]


  async createBranchAndPush(options: {
    repositoryUrl: string;
    branch: string;
    baseBranch: string;
    title: string;
    description: string;
    files: any[];
    credentials?: any;
  }): Promise<{ branch: string; commitHash: string }> {
    let tempDir: string | null = null;

    try {
      console.log(
        `🌿 Creating branch '${options.branch}' and pushing changes...`
      );

      // Create temporary directory
      tempDir = await fs.mkdtemp(path.join(os.tmpdir(), "hugex-git-"));
      console.log(`📁 Created temp directory: ${tempDir}`);

      // Get authenticated repository URL (if needed)
      const repoUrl = await this.getAuthenticatedRepoUrl(options.repositoryUrl);

      // 1. Shallow clone the repository
      console.log(`📌 Cloning repository: ${options.repositoryUrl}`);
      await execAsync(
        `git clone --depth=1 --branch ${options.baseBranch} "${repoUrl}" repo`,
        {
          cwd: tempDir,
          env: { ...process.env, GIT_TERMINAL_PROMPT: "0" },
        }
      );

      const repoPath = path.join(tempDir, "repo");

      // 2. Create and checkout new branch
      console.log(`🌱 Creating branch: ${options.branch}`);
      await execAsync(`git checkout -b "${options.branch}"`, {
        cwd: repoPath,
        env: { ...process.env, GIT_TERMINAL_PROMPT: "0" },
      });

      // 3. Apply file changes from diff
      console.log(`🗏 Applying ${options.files.length} file changes...`);
      await this.applyFileChanges(repoPath, options.files);

      // 4. Configure git user (required for commits)
      await execAsync('git config user.name "HugeX Bot"', {
        cwd: repoPath,
        env: { ...process.env, GIT_TERMINAL_PROMPT: "0" },
      });
      await execAsync(
        'git config user.email "hugex@users.noreply.github.com"',
        {
          cwd: repoPath,
          env: { ...process.env, GIT_TERMINAL_PROMPT: "0" },
        }
      );

      // 5. Stage all changes
      console.log(`📚 Staging changes...`);
      await execAsync("git add .", {
        cwd: repoPath,
        env: { ...process.env, GIT_TERMINAL_PROMPT: "0" },
      });

      // Check if there are any changes to commit
      const { stdout: statusOutput } = await execAsync(
        "git status --porcelain",
        {
          cwd: repoPath,
          env: { ...process.env, GIT_TERMINAL_PROMPT: "0" },
        }
      );

      console.log(`Git status output:`, statusOutput);

      if (!statusOutput.trim()) {
        // No changes detected - let's create a minimal change to ensure we have something to commit
        console.log("No changes detected, creating minimal change...");

        // Create a simple marker file to indicate this branch was created by HugeX
        const markerPath = path.join(repoPath, ".hugex-branch-marker");
        const markerContent = `Branch created by Hugex\nTimestamp: ${new Date().toISOString()}\nBranch: ${
          options.branch
        }\nRepository: ${options.repositoryUrl}\n`;
        await fs.writeFile(markerPath, markerContent, "utf8");

        // Stage the marker file
        await execAsync("git add .hugex-branch-marker", {
          cwd: repoPath,
          env: { ...process.env, GIT_TERMINAL_PROMPT: "0" },
        });

        console.log("Created marker file to ensure non-empty commit");
      }

      // 6. Commit changes
      const commitMessage = `${options.title}\n\n${options.description}`;
      console.log(`📝 Committing changes...`);
      await execAsync(`git commit -m "${commitMessage.replace(/"/g, '\\"')}"`, {
        cwd: repoPath,
        env: { ...process.env, GIT_TERMINAL_PROMPT: "0" },
      });

      // 7. Get commit hash
      const { stdout: commitHash } = await execAsync("git rev-parse HEAD", {
        cwd: repoPath,
        env: { ...process.env, GIT_TERMINAL_PROMPT: "0" },
      });

      // 8. Push branch to origin
      console.log(`🚀 Pushing branch to origin...`);
      await execAsync(`git push origin "${options.branch}"`, {
        cwd: repoPath,
        env: { ...process.env, GIT_TERMINAL_PROMPT: "0" },
      });

      const finalCommitHash = commitHash.trim();
      console.log(
        `✅ Successfully created branch '${options.branch}' with commit: ${finalCommitHash}`
      );

      return {
        branch: options.branch,
        commitHash: finalCommitHash,
      };
    } catch (error) {
      console.error("❌ Failed to create branch and push:", error);
      throw new Error(`Git operation failed: ${error.message}`);
    } finally {
      // Clean up temporary directory
      if (tempDir) {
        try {
          await fs.rm(tempDir, { recursive: true, force: true });
          console.log(`🧽 Cleaned up temp directory: ${tempDir}`);
        } catch (cleanupError) {
          console.warn(`⚠️ Failed to clean up temp directory: ${cleanupError}`);
        }
      }
    }