4

I've started to use one script posted in this another thread:

#!/bin/bash

main() {
  REMOTES="$@";
  if [ -z "$REMOTES" ]; then
    REMOTES=$(git remote);
  fi
  REMOTES=$(echo "$REMOTES" | xargs -n1 echo)
  CLB=$(git branch -l|awk '/^\*/{print $2}');
  echo "$REMOTES" | while read REMOTE; do
    git remote update $REMOTE
    git remote show $REMOTE -n \
    | awk '/merges with remote/{print $5" "$1}' \
    | while read line; do
      RB=$(echo "$line"|cut -f1 -d" ");
      ARB="refs/remotes/$REMOTE/$RB";
      LB=$(echo "$line"|cut -f2 -d" ");
      ALB="refs/heads/$LB";
      NBEHIND=$(( $(git rev-list --count $ALB..$ARB 2>/dev/null) +0));
      NAHEAD=$(( $(git rev-list --count $ARB..$ALB 2>/dev/null) +0));
      if [ "$NBEHIND" -gt 0 ]; then
        if [ "$NAHEAD" -gt 0 ]; then
          echo " branch $LB is $NBEHIND commit(s) behind and $NAHEAD commit(s) ahead of $REMOTE/$RB. could not be fast-forwarded";
        elif [ "$LB" = "$CLB" ]; then
          echo " branch $LB was $NBEHIND commit(s) behind of $REMOTE/$RB. fast-forward merge";
          git merge -q $ARB;
        else
          echo " branch $LB was $NBEHIND commit(s) behind of $REMOTE/$RB. reseting local branch to remote";
          git branch -l -f $LB -t $ARB >/dev/null;
        fi
      fi
    done
  done
}

main $@

It works great so far but I was wondering how to tweak it to pull all branches, for some reason it won't pull certain local branches.

First example: I got 4 local branches behind with master being the current one, after running this script few branches (4) that were behind respect to the remote were pulled but I can still see the master branch behind the remote like the below picture:

enter image description here

Second example: before running the script I got this, 2 local branches behind and the current one (release) is fine:

enter image description here

I run the script and I got this:

enter image description here

So, how could i tweak the script to pull "all" local branches?

Community
  • 1
  • 1
BPL
  • 9,632
  • 9
  • 59
  • 117

2 Answers2

1

First check your upstream branch for master: it might not be origin, which is why pulling from origin might not have any effect for master.

git rev-parse --abbrev-ref --symbolic-full-name master@{u}

Second, to display in a script the number of commits ahead/behind, use the Git 1.9 syntax %(upstream:track) :

git for-each-ref --format="%(refname:short) %(upstream:track)" refs/heads

Note that the upstream branch (or remote tracking branch, that is the branch you are pulling from) might differs from the branch you are pushing to.
Check if you see a push url with:

git config --get-regexp branch.master
Community
  • 1
  • 1
VonC
  • 1,262,500
  • 529
  • 4,410
  • 5,250
  • First of all, thanks for your answer. Could you please specify how to integrate those 3 command in the script so I can test it out? I'm a total newbie with git so I'm kinda lost with those commands per-se – BPL Nov 11 '16 at 13:06
  • @BPL The command 1 and 3 are for you to check out how master is configured: what is its remote tracking branch (or "upstream" branch, ie from which remote branch it is pulling), and what is its push branch. The command 2 is to be used as is, with your script having to parse its output (as you are doing currently): so try command 2 in a repo and see how its output is, in order to parse it. – VonC Nov 11 '16 at 13:14
  • I haven't validated yet your answer cos I don't know how to tweak the script with them. In any case, let's say I got this [repo](http://www.screencast.com/t/KNWkHA6e), if i try your commands 1&3 individually I'll get [this](http://screencast.com/t/VOxK2HpsVhGk). If you were so kind to put the final script including your 3 command so I could test it out I'd could validate your answer, thanks for your time in any case. – BPL Nov 12 '16 at 12:21
  • @BPL What version of SourceTree are you using? Are you using the embedded Git or a Git installed on your computer? What is your version of Git used in this SourceTree? – VonC Nov 12 '16 at 12:44
  • Using System Git version 2.10.1 + SourceTree 1.5.2.0 combo. After trying SourceTree 1.6.x or latest SourceTree 1.9.x I must to say there is no real reason for me to upgrade further, didn't like some Attlasian decission with those later versions so I'm fine staying with this reasonable fast/(no many buggy) old version :) – BPL Nov 12 '16 at 12:50
  • @BPL OK, that explains why I did not reproduce right away the issue (I use the latest 1.9.6.1). I will try your script. – VonC Nov 12 '16 at 13:21
  • Hi, did you finally try this one? – BPL Nov 17 '16 at 13:14
  • @BPL Sorry, I didn't get the chance to try it out. – VonC Nov 17 '16 at 14:02
  • Ok, giving you the bounties cos don't want them to be wasted... But I can't validate this yet. – BPL Nov 18 '16 at 10:00
  • @BPL Still, just for testing, it would be interesting to check with the latest SourceTree has the same issue. – VonC Nov 18 '16 at 10:08
1

In addition to my previous answer, I would add that your script should only limit the merge or reset of a given branch to it upstream branch.
Hence my use of %(upstream:track)

Here is the script I just tested with:

  • git version 2.11.0.windows.1
  • SourceTree 1.9.10.0

That is:

#!/bin/bash

branches=$(git for-each-ref --format="%(refname) %(upstream) %(upstream:track)" refs/heads)

echo "${branches}"
branch_checkedout=$(cat .git/HEAD|cut -f2 -d" ")
echo branch checked out: "${branch_checkedout}"

while read -r branch_line; do
  ahead=0
  behind=0
  branch_local=$(echo ${branch_line}|cut -f1 -d" ")
  branch_remote=$(echo ${branch_line}|cut -f2 -d" ")
  echo ${branch_line} | grep "ahead" >/dev/null && ahead=1
  echo ${branch_line} | grep "behind" >/dev/null && behind=1
  NAHEAD=$(( $(git rev-list --count ${branch_remote}..${branch_local} 2>/dev/null) +0))
  NBEHIND=$(( $(git rev-list --count ${branch_local}..${branch_remote} 2>/dev/null) +0));

  if [ "$NBEHIND" -gt 0 ]; then
    if [ "$NAHEAD" -gt 0 ]; then
      echo " branch $LB is $NBEHIND commit(s) behind and $NAHEAD commit(s) ahead of $REMOTE/$RB. could not be fast-forwarded";
    elif [ "${branch_local}" = "${branch_checkedout}" ]; then
      echo " branch ${branch_local} was $NBEHIND commit(s) behind of ${branch_remote}. fast-forward merge";
      echo "git merge -q ${branch_remote}"
      git merge -q ${branch_remote};
    else
      echo " branch ${branch_local} was $NBEHIND commit(s) behind of ${branch_remote}. reseting local branch to remote";
      bl=${branch_local#*/}
      bl=${bl#*/}
      echo "git branch -l -f ${bl} -t ${branch_remote}"
      git branch -l -f ${bl} -t ${branch_remote} >/dev/null;
    fi
  fi
done <<< "${branches}"

Note the use of:

  • branches=$(git for-each-ref --format="%(refname) %(upstream) %(upstream:track)" refs/heads)
    to get both the full upstream branch name, and the ahead/behind status
  • branch_checkedout=$(cat .git/HEAD|cut -f2 -d" ") to get the name of the checked out branch
  • while read -r branch_line; do to loop only on the branches with upstreams, and not "all the remotes" (which might or might not include a given branch)
Community
  • 1
  • 1
VonC
  • 1,262,500
  • 529
  • 4,410
  • 5,250
  • Thank you very much, i've tested with `git version 2.10.1.windows.1` and `sourcetree 1.5.2` and it's worked so far very good. I hadn't had time to test it before. Btw, do you foresee any case where you need to be specially careful before using your script? – BPL Dec 20 '16 at 16:25
  • @BPL So far, I didn't get any special case. I'll check with repo involving submodule entries, to see if that is an issue. – VonC Dec 20 '16 at 19:26