Skip to main content
Removed `--quiet` flags from merge / rebase continues.
Source Link
#!/bin/env python3

# Imports
import subprocess
import json

# Updates a branch `orig_branch` with deps `branch_deps`
def update_branch(orig_branch, branch_deps):
    # Checkout a temp branch on master
    subprocess.check_call(["git", "checkout", "-b", "temp", "master", "--quiet"])

    # Merge all dependencies
    for branch in branch_deps:
        print(f"> Merge`{branch}`")
        if subprocess.call(["git", "merge", f"{branch}", "--no-ff", "-m", f"Merge branch `{branch}`", "--quiet"]) != 0:
            # If we fail to merge, try to `continue` the merge after the user fixes conflicts
            while True:
                input("Unable to merge, check possible conflicts...")
                
                print("Continuing merge")
                if subprocess.call(["git", "merge", "--continue", "--quiet"]continue"]) == 0:
                    break;

    # Then rebase the orignal branch
    print(f"> Rebase")
    subprocess.check_call(["git", "checkout", f"{orig_branch}", "--quiet"])
    if subprocess.call(["git", "rebase", "temp", "--quiet"]) != 0:
        # If we fail to rebase, try to `continue` the rebase after the user fixes conflicts
        while True:
            input("Unable to rebase, check possible conflicts...")
            
            print("Continuing rebase")
            if subprocess.call(["git", "rebase", "--continue", "--quiet"]continue"]) == 0:
                break;

    # Finally delete the temp branch
    subprocess.check_call(["git", "branch", "-d", "temp", "--quiet"])

if __name__ == "__main__":
    # If any changes exist, return Err
    changes = subprocess.check_output(["git", "status", "--porcelain"]);
    if len(changes) != 0:
        print("You must stash or commit changes before updating")
        exit(1)
    
    # Get the current branch name
    orig_branch = subprocess.check_output(["git", "rev-parse", "--abbrev-ref", "HEAD"])
    orig_branch = orig_branch.decode("utf-8").strip()
    if orig_branch == "master":
        print("Cannot update master, checkout another branch")
        exit(1)
    print(f"Updating branch `{orig_branch}`")

    # Then read it's dependencies
    branch_deps = json.load(open(".branch-deps.json"))[orig_branch]
    print(f"Found {len(branch_deps)} dependencies")

    # And update it
    update_branch(orig_branch, branch)
#!/bin/env python3

# Imports
import subprocess
import json

# Updates a branch `orig_branch` with deps `branch_deps`
def update_branch(orig_branch, branch_deps):
    # Checkout a temp branch on master
    subprocess.check_call(["git", "checkout", "-b", "temp", "master", "--quiet"])

    # Merge all dependencies
    for branch in branch_deps:
        print(f"> Merge`{branch}`")
        if subprocess.call(["git", "merge", f"{branch}", "--no-ff", "-m", f"Merge branch `{branch}`", "--quiet"]) != 0:
            # If we fail to merge, try to `continue` the merge after the user fixes conflicts
            while True:
                input("Unable to merge, check possible conflicts...")
                
                print("Continuing merge")
                if subprocess.call(["git", "merge", "--continue", "--quiet"]) == 0:
                    break;

    # Then rebase the orignal branch
    print(f"> Rebase")
    subprocess.check_call(["git", "checkout", f"{orig_branch}", "--quiet"])
    if subprocess.call(["git", "rebase", "temp", "--quiet"]) != 0:
        # If we fail to rebase, try to `continue` the rebase after the user fixes conflicts
        while True:
            input("Unable to rebase, check possible conflicts...")
            
            print("Continuing rebase")
            if subprocess.call(["git", "rebase", "--continue", "--quiet"]) == 0:
                break;

    # Finally delete the temp branch
    subprocess.check_call(["git", "branch", "-d", "temp", "--quiet"])

if __name__ == "__main__":
    # If any changes exist, return Err
    changes = subprocess.check_output(["git", "status", "--porcelain"]);
    if len(changes) != 0:
        print("You must stash or commit changes before updating")
        exit(1)
    
    # Get the current branch name
    orig_branch = subprocess.check_output(["git", "rev-parse", "--abbrev-ref", "HEAD"])
    orig_branch = orig_branch.decode("utf-8").strip()
    if orig_branch == "master":
        print("Cannot update master, checkout another branch")
        exit(1)
    print(f"Updating branch `{orig_branch}`")

    # Then read it's dependencies
    branch_deps = json.load(open(".branch-deps.json"))[orig_branch]
    print(f"Found {len(branch_deps)} dependencies")

    # And update it
    update_branch(orig_branch, branch)
#!/bin/env python3

# Imports
import subprocess
import json

# Updates a branch `orig_branch` with deps `branch_deps`
def update_branch(orig_branch, branch_deps):
    # Checkout a temp branch on master
    subprocess.check_call(["git", "checkout", "-b", "temp", "master", "--quiet"])

    # Merge all dependencies
    for branch in branch_deps:
        print(f"> Merge`{branch}`")
        if subprocess.call(["git", "merge", f"{branch}", "--no-ff", "-m", f"Merge branch `{branch}`", "--quiet"]) != 0:
            # If we fail to merge, try to `continue` the merge after the user fixes conflicts
            while True:
                input("Unable to merge, check possible conflicts...")
                
                print("Continuing merge")
                if subprocess.call(["git", "merge", "--continue"]) == 0:
                    break;

    # Then rebase the orignal branch
    print(f"> Rebase")
    subprocess.check_call(["git", "checkout", f"{orig_branch}", "--quiet"])
    if subprocess.call(["git", "rebase", "temp", "--quiet"]) != 0:
        # If we fail to rebase, try to `continue` the rebase after the user fixes conflicts
        while True:
            input("Unable to rebase, check possible conflicts...")
            
            print("Continuing rebase")
            if subprocess.call(["git", "rebase", "--continue"]) == 0:
                break;

    # Finally delete the temp branch
    subprocess.check_call(["git", "branch", "-d", "temp", "--quiet"])

if __name__ == "__main__":
    # If any changes exist, return Err
    changes = subprocess.check_output(["git", "status", "--porcelain"]);
    if len(changes) != 0:
        print("You must stash or commit changes before updating")
        exit(1)
    
    # Get the current branch name
    orig_branch = subprocess.check_output(["git", "rev-parse", "--abbrev-ref", "HEAD"])
    orig_branch = orig_branch.decode("utf-8").strip()
    if orig_branch == "master":
        print("Cannot update master, checkout another branch")
        exit(1)
    print(f"Updating branch `{orig_branch}`")

    # Then read it's dependencies
    branch_deps = json.load(open(".branch-deps.json"))[orig_branch]
    print(f"Found {len(branch_deps)} dependencies")

    # And update it
    update_branch(orig_branch, branch)
Source Link

Although amon's answer will likely be relevant for most of everyone else attempting this sort of "creative" usage of git, for those that want to use it like this, I ended up using the following scripts to perform all updates automatically:

Warning: This was made for a hobby project with only 1 collaborator, so the code quality is low. Don't use this for anything large or if you're planning on having multiple people work simultaneously, as it will break everything.

The plan is to have a .branch-deps.json file in master that has all of the dependencies of the project, as such:

{
  "a": [],
  "b": [],
  "c": ["b"]
}

Then we have two scripts, one to update a specific branch, and another to update all branches:

update_branch.py:

#!/bin/env python3

# Imports
import subprocess
import json

# Updates a branch `orig_branch` with deps `branch_deps`
def update_branch(orig_branch, branch_deps):
    # Checkout a temp branch on master
    subprocess.check_call(["git", "checkout", "-b", "temp", "master", "--quiet"])

    # Merge all dependencies
    for branch in branch_deps:
        print(f"> Merge`{branch}`")
        if subprocess.call(["git", "merge", f"{branch}", "--no-ff", "-m", f"Merge branch `{branch}`", "--quiet"]) != 0:
            # If we fail to merge, try to `continue` the merge after the user fixes conflicts
            while True:
                input("Unable to merge, check possible conflicts...")
                
                print("Continuing merge")
                if subprocess.call(["git", "merge", "--continue", "--quiet"]) == 0:
                    break;

    # Then rebase the orignal branch
    print(f"> Rebase")
    subprocess.check_call(["git", "checkout", f"{orig_branch}", "--quiet"])
    if subprocess.call(["git", "rebase", "temp", "--quiet"]) != 0:
        # If we fail to rebase, try to `continue` the rebase after the user fixes conflicts
        while True:
            input("Unable to rebase, check possible conflicts...")
            
            print("Continuing rebase")
            if subprocess.call(["git", "rebase", "--continue", "--quiet"]) == 0:
                break;

    # Finally delete the temp branch
    subprocess.check_call(["git", "branch", "-d", "temp", "--quiet"])

if __name__ == "__main__":
    # If any changes exist, return Err
    changes = subprocess.check_output(["git", "status", "--porcelain"]);
    if len(changes) != 0:
        print("You must stash or commit changes before updating")
        exit(1)
    
    # Get the current branch name
    orig_branch = subprocess.check_output(["git", "rev-parse", "--abbrev-ref", "HEAD"])
    orig_branch = orig_branch.decode("utf-8").strip()
    if orig_branch == "master":
        print("Cannot update master, checkout another branch")
        exit(1)
    print(f"Updating branch `{orig_branch}`")

    # Then read it's dependencies
    branch_deps = json.load(open(".branch-deps.json"))[orig_branch]
    print(f"Found {len(branch_deps)} dependencies")

    # And update it
    update_branch(orig_branch, branch)

This script will create a new branch temp on master, merge all dependencies, then rebase the original branch on temp and finally delete temp.

This would be used when you just want to work on a single branch, but it's dependencies have been updated in the meantime.

update_all_branches.py

#!/bin/env python3

# Imports
import subprocess
import json
import update_branch

# Checksout and updates `branch`, with all branch dependencies in `branch_deps` and the already updated
# branches in `updated_branches`
def checkout_update_branch(branch, branch_deps, updated_branches):
    # If we're already updated, return
    if branch in updated_branches:
        return
    
    # Update any dependencies first
    for dep_branch in branch_deps[branch]:
        checkout_update_branch(dep_branch, branch_deps, updated_branches)
    
    # Then checkout the branch and update
    print(f"`{branch}`:")
    subprocess.check_call(["git", "checkout", f"{branch}", "--quiet"])
    update_branch.update_branch(branch, branch_deps[branch])
    
    # And set ourselves as updated
    updated_branches.add(branch)

if __name__ == "__main__":
    # If we have any changes, return Err
    changes = subprocess.check_output(["git", "status", "--porcelain"]);
    if len(changes) != 0:
        print("You must stash or commit changes before updating")
        exit(1)
    
    # If we aren't in master, return Err
    cur_branch = subprocess.check_output(["git", "rev-parse", "--abbrev-ref", "HEAD"])
    cur_branch = cur_branch.decode("utf-8").strip()
    if cur_branch != "master":
        print("Updating all branches must be done from master")
        exit(1)

    # Else read all branches
    branch_deps = json.load(open(".branch-deps.json"))
    print(f"Found {len(branch_deps)} branches")

    # All updated branches
    updated_branches = set()

    # Then for each one, update it
    for branch in branch_deps:
        checkout_update_branch(branch, branch_deps, updated_branches)
    
    # Finally checkout master
    subprocess.check_call(["git", "checkout", "master", "--quiet"])

This script will update each branch in .branch-deps.json. It will also be sure to update dependencies first to ensure every branch ends up updated.

This would be used when master receives new updates, or a major branch with a ton of dependencies is updated.