How to force Git to abort a checkout if working directory is not clean (i.e. disregarding the check for conflicts)?

StackOverflow https://stackoverflow.com/questions/22609566

  •  20-06-2023
  •  | 
  •  

Pregunta

When you do a git checkout some_branch, and your working directory is not clean, then Git will check if the checkout will result in any conflicts, and if so it will abort with:

$ git checkout some_branch
error: Your local changes to the following files would be overwritten by checkout:
        some_file
Please, commit your changes or stash them before you can switch branches.
Aborting

However, if the checkout will not result in any conflicts, then Git will switch to that new branch and carry over all uncommitted changes (and listing them, polite as Git is).

$ git checkout some_branch
M       some_file
M       some_other_file
Switched to branch 'some_branch'

So far so good ...

Now, not all Git users uses cmd line. If you use an IDE (like e.g. Eclipse) and do a checkout of some_branch with a dirty working directory which will not result in any conflicts, then you will not be nicely notified that the changes you were working on in previous_branch are still present in your working directory after changing to some_branch.

I.e. when you compile your code your uncommitted changes from previous_branch are still present in your working directory on some_branch.

Question #1:

Is it possible to force Git to abort a checkout if working directory is not clean (no matter if there are any conflicts or not)?

I would prefer a setting in global Git config.

Question #2:

If this is not possible to setup, is it then a valid request for a new config option in Git?

As I see it Git is very strong in context switching (i.e. working on multiple issues on multiple branches), and I could see a use for a setting which setup a strict check for if working directory is not clean (disregarding the check for conflicts).

This would mean that your changes created while on branch #1 will not be carried over when changing to branch #2, i.e. you will work strictly context based always.

Any views or opinions on this?

¿Fue útil?

Solución

I'm not aware of such an option, but here's a script to simulate this behavior. Maybe IDE(or OS) can be configured to run this script instead of git-checkout.

#!/bin/sh

MODIFIED=$(git status -s | grep ^\ M)

if [ "$MODIFIED" != "" ]; then
  echo "Current branch is dirty!"
  exit 1
else
  git checkout $1
fi

You can name this script git-cleancheckout, put to your $PATH and run like this

git cleancheckout mybranch

Otros consejos

There should be an option to "reset" the previous changes. It is depicted by --force on the command line. I use gitEx and this is available at the time of checkout <branch> as follows -

enter image description here

This would remove all your local changes automatically before checking out the branch. The option (stash) in the image can be used if you want to keep your changes in the store and get them back once you want to start working again on the old branch.

You should be able to use a post-checkout hook to do almost what you need. The limitation is that there is no pre-checkout hook, so you cannot abort. Instead, you can only discard local changes to get a clean state. If you want to, you can save the local changes with git stash save X and creating an archive of any untracked files before they are removed.

You indicate that you would prefer a setting in global git config; as previously suggested elsewhere on SO, with git 1.7.1 or later, you can use the following:

git config --global init.templatedir '~/.git-template'

to create all repositories (via git init or git clone) with templated hooks. The templated hooks are symbolic links that point into the repository itself, so they won't have any effect when you create other (unrelated) repositories:

mkdir -p ~/.git-template/hooks && \
  ln -sf ../../special-git-hooks/post-checkout ~/.git-template/hooks/.

The special-git-hooks/post-checkout script is the one that will implement the moral equivalent of git checkout --force:

#!/bin/sh
#
# git hook to clean branch checkout (git checkout --force plus more)
#

# arguments to post-checkout (see `man githooks`)
OLD_REV=$1
NEW_REV=$2
BRANCH=$3

if [ 0 = "$BRANCH" -o x"$OLD_REV" = x"$NEW_REV"]; then
    exit 0
fi

# Start from the repository root.
cd ./$(git rev-parse --show-cdup)

ARCHIVE=`mktemp -qu gitco-XXXXXXXXX`

git clean -nxd | sed 's/Would remove //' | cpio -oz --format ustar > $ARCHIVE.tgz
git add -f $ARCHIVE.tgz
git clean -fxd
git stash save $ARCHIVE

Note that this script doesn't handle files with newlines or other non-printing characters in their names. I'm working on a Perl version of this script that does.

In the commandline just checkout the previous branch if realize you forgot something. In EGit the changes are visible in the staging view, which unfortunately isn't always visible.

A new option in Git doesn't automatically find its way into Eclipse, but displaying a list of modified files after checkout seems like a reasable feature request for EGit.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top