I periodically get message from git that look like this:
Your branch is behind the tracked remote branch 'local-master/master'
by 3 commits, and can be fast-forwarded.
I would like to be able to write commands in a shell script that can do the following:
How can I tell if my current branch can be fast-forwarded from the remote branch it is tracking?
How can I tell how many commits "behind" my branch is?
How can I fast-forward by just one commit, so that for example, my local branch would go from "behind by 3 commits" to "behind by 2 commits"?
(For those who are interested, I am trying to put together a quality git/darcs mirror.)
The remote branch can be fast-forwarded to the local branch if the current commit is the ancestor of the remote branch head. In other words, if the "one-branch history" of the remote branch contains the current commit (because if it does, it is sure that the new commits were committed "onto" the current commit)
So a safe way to determine whether the remote branch can be fast-forwarded:
# Convert reference names to commit IDs
current_commit=$(git rev-parse HEAD)
remote_commit=$(git rev-parse remote_name/remote_branch_name)
# Call git log so that it prints only commit IDs
log=$(git log --topo-order --format='%H' $remote_commit | grep $current_commit)
# Check the existence of the current commit in the log
if [ ! -z "$log" ]
then echo 'Remote branch can be fast-forwarded!'
fi
Note that git log was called without the --all parameter (which would list all branches), so it is not possible that the current commit is on a "side branch" and is still printed on the output.
The number of commits ahead of the current commit equals the number of rows in $log before $current_commit.
If you want to fast-forward only one commit, you take the row previous to the current commit (with grep -B 1, for example), and reset the local branch to this commit.
UPDATE: you can use git log commit1..commit2
to determine the number of fast-forwarding commits:
if [ ! -z "$log" ]
then
# print the number of commits ahead of the current commit
ff_commits=$(git log --topo-order --format='%H' \
$current_commit..$remote_commit | wc -l)
echo "Number of fast-forwarding commits: $ff_commits"
# fast-forward only one commit
if [ $ff_commits -gt 1 ]
then
next_commit=$(git log --topo-order --format='%H' \
$current_commit..$remote_commit | tail -1)
git reset --hard $next_commit
fi
fi
Of course, you can do this with one git log call if you save the result of the first call into a file.