The answers to the two questions are "not exactly" and "no", but also "normally there's no need", and in fact, the question itself does not make a lot of sense as asked. The first and largest problem lies in the phrase "if local is clean"—what, precisely, does this mean?
If "clean" refers to what git status
reports:
On branch master
Your branch is up-to-date with 'origin/master'.
nothing to commit, working tree clean
then "clean" refers to the work-tree, and sometimes perhaps to the index, as compared to each other and/or the HEAD
commit.
Unless you use git worktree add
to create auxiliary work-trees, there's only one work-tree (and one corresponding index) for any given Git repository. (If you do use git worktree add
, each added work-tree is on its own separate branch. That might in fact be the answer you are really looking for, here.)
Let's note here as well that a branch name like master
or feature
denotes one particular commit, which Git calls the tip commit of that branch. There are other meanings for the word "branch": see What exactly do we mean by "branch"? But when you have a branch checked out, what this implies is that you have one particular commit checked out as well. That commit's contents fill the index and the work-tree.
The command that switches branches—or to a "detached HEAD"—is git checkout
. It accomplishes the branch-switching (or HEAD-detaching) by writing, into the index and the work-tree, whatever is needed to achieve the switch from the commit you had checked-out before, to the commit you will have checked-out now. If the work-tree was clean before the git checkout
, this is always possible, and the work-tree will be clean after the git checkout
as well.
If the work-tree is not clean before the git checkout
, it's sometimes, but not always, still possible to switch branches: see Checkout another branch when there are uncommitted changes on the current branch. In that case, the work-tree will generally also be not-clean after the git checkout
has switched branches. The not-clean-ness will be because the checkout, when switching branches, did not have to update the index and work-tree entries for the files that did not match the commit that you had checked out just before you ran git checkout branchname
.
Checking if the work-tree is clean
With the above out of the way, note that git-sh-setup
, a script that is available to other Git scripts, includes a function named require_clean_work_tree
. You can examine this code, or simply use it, to determine whether a work-tree is clean.
You can combine this with phd's answer about using a post-checkout hook to do the check and, if appropriate, run git merge
or git fetch && git merge
. (I recommend avoiding git pull
entirely: break it down into its two separate steps like this. Your life will be happier afterward.)
Why I suspect you should not need this at all
(Our branches are frequently created and deleted as company policy is one branch per task which is PR'd and merged when reviewed)
As a general rule, if you're not going to work on a named branch (make new commits on it), you should not create it in the first place. Having not created it, you never need to worry about updating it either.
Suppose, for instance, that you have a repository with one remote named origin
, and on origin
, there are branches for various tasks. You want to inspect origin/task/feedkittens
occasionally, but work on the (single) task task/fillcatnip
.
In this case, to inspect things, go ahead and use the "detached HEAD" mode:
git checkout origin/task/feedkittens
To work on things, use git checkout
to create task/fillcatnip
from origin/task/fillcatnip
:
git checkout task/fillcatnip
This works because git checkout
will, if you ask it to check out a branch that doesn't exist, search for an origin/
branch that otherwise has the same name. If so, it will create the local branch such that the branch tip commit is the same as the remote-tracking name's commit. At the same time, it will set up the local branch to track (have as its upstream) the remote-tracking name.
By creating the local branch name, you can now create new commits. These will make the local branch
By avoiding creating task/feedkittens
, you can just run git fetch
and git checkout origin/task/feedkittens
to see the latest. You will be in "detached HEAD" mode, so it's usually a bad idea to create new commits now, but this means there's no need to drag around a local branch.
When the branch named task/feedkittens
is deleted on origin
, you can have your own remote-tracking name get deleted automatically during git fetch
by setting:
git config fetch.prune true
As soon as you git checkout
some other commit or name, you stop being detached-HEAD on the origin/task/feedkittens
commit that no longer has a name.
If you want to work on (as in "add commits to") multiple different branches simultaneously, consider using git worktree add
, as long as your Git is at least version 2.5. Each added work-tree has its own private index, but all the added work-trees share the single underlying repository. If your Git is too old, consider just making separate clones for each branch you want to work on at once.