# Git Automation with GitPython

This guide demonstrates how to automate common Git operations (clone, add, commit, push, pull) using the `GitPython` library. This is useful for build scripts, automated backups, or managing multiple repositories programmatically.

**Modules Used:**
*   `git` (GitPython): To interact with Git repositories.
*   [[programming/python/modules/argparse-module|argparse]]: To handle command-line arguments.

## Installation

You need to install `GitPython`. You also need `git` installed on your system and available in your PATH.

```bash
pip install GitPython
```

## The Code

Save this as `git_tool.py`.

```python
import git
from git import Repo
import argparse
import os
import sys

def clone_repo(url, destination):
    if os.path.exists(destination):
        print(f"Error: Destination '{destination}' already exists.")
        return
    
    try:
        print(f"Cloning {url} to {destination}...")
        Repo.clone_from(url, destination)
        print("Clone successful.")
    except Exception as e:
        print(f"Clone failed: {e}")

def handle_repo(path, commit_msg=None, push=False, pull=False):
    try:
        repo = Repo(path)
        
        if repo.bare:
            print(f"Error: '{path}' is a bare repository.")
            return

        print(f"Repository: {path}")
        print(f"Active Branch: {repo.active_branch}")

        # 1. Pull
        if pull:
            print("Pulling changes from origin...")
            origin = repo.remotes.origin
            origin.pull()
            print("Pull complete.")

        # 2. Commit
        if commit_msg:
            # Check if there are changes (modified or untracked)
            if repo.is_dirty(untracked_files=True):
                print("Changes detected.")
                
                # Stage all files (git add .)
                print("Staging all files...")
                repo.git.add(A=True)
                
                # Commit
                print(f"Committing: {commit_msg}")
                repo.index.commit(commit_msg)
                print("Commit successful.")
                
                # 3. Push (only if committed)
                if push:
                    print("Pushing to origin...")
                    origin = repo.remotes.origin
                    origin.push()
                    print("Push successful.")
            else:
                print("No changes to commit.")
        elif push:
             # Push without commit if requested
             print("Pushing to origin...")
             origin = repo.remotes.origin
             origin.push()
             print("Push successful.")

    except git.exc.InvalidGitRepositoryError:
        print(f"Error: '{path}' is not a valid Git repository.")
    except Exception as e:
        print(f"Error: {e}")

if __name__ == "__main__":
    parser = argparse.ArgumentParser(description="Git Automation Tool")
    subparsers = parser.add_subparsers(dest="command", help="Command to run")

    # Clone Command
    clone_parser = subparsers.add_parser("clone", help="Clone a repository")
    clone_parser.add_argument("url", help="Repository URL")
    clone_parser.add_argument("dest", help="Destination folder")

    # Sync Command (Commit/Push/Pull)
    sync_parser = subparsers.add_parser("sync", help="Sync a repository (Commit, Push, Pull)")
    sync_parser.add_argument("path", help="Path to local repository")
    sync_parser.add_argument("-m", "--message", help="Commit message (required for commit)")
    sync_parser.add_argument("--push", action="store_true", help="Push changes to remote")
    sync_parser.add_argument("--pull", action="store_true", help="Pull changes from remote before committing")

    args = parser.parse_args()

    if args.command == "clone":
        clone_repo(args.url, args.dest)
    elif args.command == "sync":
        handle_repo(args.path, args.message, args.push, args.pull)
    else:
        parser.print_help()
```

## Usage

```bash
# Clone a repo
python git_tool.py clone https://github.com/gitpython-developers/GitPython.git ./my_repo

# Pull latest changes
python git_tool.py sync ./my_repo --pull

# Add all changes, commit, and push
python git_tool.py sync ./my_repo -m "Automated backup" --push
```

[[programming/python/python]]