emacscollective / borg

Assimilate Emacs packages as Git submodules
https://emacsmirror.net/manual/borg
GNU General Public License v3.0
255 stars 28 forks source link

Fix submodule tracking for non-default branch #112

Closed chasecaleb closed 3 years ago

chasecaleb commented 3 years ago

This is a rough starting point to make submodules correctly track a non-default branch. A couple caveats that I couldn't figure out:

  1. Notice the FIXME. I don't have any branches with multiple remotes specified, so I'm not able to test how this works with the logic that loops through git config -f .gitmodules --get-all submodule."$name".remote (lines 33-69). I took a wild guess with head -n 1 to grab the first remote if there are multiple, but that's probably not right.
  2. I basically muddled my way around via internet research and reading git man pages, so while this works I doubt it's the most elegant solution. Using git switch immediately before git reset --hard can be inefficient if the two refer to different commits. I couldn't figure out an alternative and gave up though.

If you want to point me towards solutions for those caveats (and a repo I can test point 1 on) I can hack on this some more, but I certainly won't complain if you want to take what I have and polish it yourself either.

For a reproduction, you can check out my emacs.d here: https://gitlab.com/chasecaleb/emacs.d . You'll see that I'm using maint branch for org and release for prettier. Here's the difference that my fix makes:

caleb@arch-as-code-desktop> cd emacs.d-original/lib/prettier && git rev-parse HEAD && git status && cd -
e38d21a885e234af9ea6b03f499c487175570571
On branch master
Your branch and 'origin/master' have diverged,
and have 29 and 213 different commits each, respectively.
  (use "git pull" to merge the remote branch into yours)

nothing to commit, working tree clean
/tmp
caleb@arch-as-code-desktop> cd emacs.d-fixed/lib/prettier && git rev-parse HEAD && git status && cd -   
e38d21a885e234af9ea6b03f499c487175570571
On branch release
Your branch is up to date with 'origin/release'.

nothing to commit, working tree clean
/tmp

P.S. I made a few safety/lint fixes in a separate commit as well. If you haven't seen it before, https://www.shellcheck.net/ is an excellent shell linter. Feel free to rebase and drop the commit if you want to leave those as they were originally.

chasecaleb commented 3 years ago

Oh, and for clarity: the reason this is an issue is because tracking the wrong branch makes it painful to figure out whether or not there are new upstream commits to pull. This is the case whether using git on the command line or magit-list-submodules (the latter being my typical workflow).

tarsius commented 3 years ago

I have applied the cleanup commit.

I do not want to apply the functional change. I have indeed opted to assume that the default branch is the correct branch and leave it to the user to manually change the setup when that is not the case. I do realize that I probably will eventually have to come up with something better but don't want to rush anything.

This seems to work for you and so you should use it. (I am afraid that mean that you have to manually adjust the borg drone itself during bootstrap.) Coming up with something that is better for everyone will require much more thought than something that works for one particular user and I just don't have the motivation to do that right now.

chasecaleb commented 3 years ago

Coming up with something that is better for everyone will require much more thought than something that works for one particular user and I just don't have the motivation to do that right now.

What, you mean you aren't excited to make complicated changes involving submodules? I'm kidding.

Totally understandable, you're welcome to ping me in the future if/when the day comes that you work on this if you want me to test or help out however. Thanks for taking the time to respond.

chasecaleb commented 3 years ago

Just for the sake of others who may come across this, here's a solution that works without forking borg to modify borg.sh:

  1. I put fix-submodules.sh in the root of my emacs.d (i.e. same directory as Makefile):
    
    #!/usr/bin/env bash
    # Fixes submodules that track non-default branches, since borg doesn't handle this.
    #
    # For example, at the time of writing I have:
    # - lib/prettier on release branch
    # - org on maint branch
    #
    # WARNING: This does a hard reset, so this is dangerous. However so does borg's borg.sh, so this
    # shouldn't be surprising.

set -Eeuo pipefail die() { echo -e "$0" ERROR: "$@" >&2; exit 1; }

shellcheck disable=2154

trap 's=$?; die "line $LINENO - $BASH_COMMAND"; exit $s' ERR

while IFS= read -r line; do revision=$(awk '{print $2}' <<< "$line") path=$(awk '{print $4}' <<< "$line") remote_branch=$(git submodule--helper remote-branch "$path") ( cd "$path" local_branch=$(git branch --show-current)

    # submodules and detached heads go hand in hand, but this is particularly the case for lib/borg
    # since it's checked out by my top-level Makefile instead of lib/borg/borg.sh.
    if [[ "$remote_branch" == "HEAD" ]]; then
        remote=$(git submodule--helper print-default-remote)
        remote_branch=$(git rev-parse --abbrev-ref "$remote/$remote_branch" | cut -d '/' -f 2-)
    fi

    if [[  "$remote_branch" != "$local_branch" ]]; then
        echo "--- [$path] ---"
        echo "Fixing incorrect branch (was ${local_branch:-detached})"
        git switch --force-create "$remote_branch" "$revision"
    fi
)

done < <(git submodule--helper list)

2. Modify your `Makefile` to run the above script while bootstrapping by adding this snippet:

bootstrap: @$(MAKE) -f lib/borg/borg.mk "$@" @./fix-submodules.sh



@tarsius No action from you needed on this, but if you revisit this in the future I would recommend looking at how I did it here instead of 8933d7c1334f8d6470d23c5fcfb24d5b91c328d6 from the PR. This should handle multiple remotes correctly, avoids unnecessary working copy churn, and I don't think it has any edge cases that could break for other people. It also has the added bonus of making `lib/borg` track master instead of leaving it with a detached head, so that's helpful for people to keep borg updated. Ping me sometime if you want me to make a new PR that integrates this approach into `borg.sh`.