Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Temporarily clearing untracked files before commit in Git

Whenever I commit, I worry that I may have missed out a dependency and I'm looking for the simplest way to test my git tree in isolation to ensure whatever is in the git index ("staged") will in fact compile/run on their own.

My code's dependencies exist in the filesystem from where I do the 'git add' and so simple compiling and running tests doesn't guarantee that whatever I checkin would compile/run if the tree (or staging area) was checkout out onto a clean filesystem.

I could have a continuous build that would check after submission but I prefer not to have any bad commits in the history that I later have to patch. I therefore want a way of creating an isolated environment that includes a checkout of the tree as well as the index/staging area.

One thing I've considered is using git stash twice, i.e.:

  1. Invoke 'git stash' to save the files in the index
  2. Somehow get a list of the files not tracked, 'git add' all these files, save a new stash
  3. Delete all the previously untracked files
  4. Restore the original stash
  5. I should now have a clean environment that has only the code already checked-in and the code in the staging area which I can compile & test.
  6. Once finished, I restore the stash of the untracked files and then untrack them to leave me in the same position that I was in originally.

(These untracked files may be useful but not necessarily things I want to check in to the repository - e.g. eclipse projects).

I have a feeling I'm overengineering a simple problem, though.

like image 336
Ash Avatar asked Nov 05 '10 14:11

Ash


People also ask

Can I commit with untracked files?

Untracked basically means that Git sees a file you didn't have in the previous snapshot (commit), and which hasn't yet been staged; Git won't start including it in your commit snapshots until you explicitly tell it to do so.

Does git reset remove untracked files?

git reset --hard is a classic command in this situation - but it will only discard changes in tracked files (i.e. files that already are under version control). To get rid of new / untracked files, you'll have to use git clean !


1 Answers

Install this script (or something like it -- mine is stolen too) as a pre-commit hook. It copies the index to a temporary working dir and runs a build there. It will catch files that you've missed.

I know there are at least one or two other SO questions that address this exact issue -- testing/validating the index instead of the working dir in a pre-commit hook -- but I can't seem to find them right now.

(For completeness, I've got this script in my repo as .git-hooks/pre-commit/test-the-index; there are a couple of other scripts there. See below for what I'm using as .git/hooks/pre-commit.)

#!/bin/sh
#
# Via: http://github.com/jwiegley/git-scripts/blob/master/pre-commit.sh
#

if [ ! $(git rev-parse --symbolic-full-name HEAD) = refs/heads/master ]; then
    exit 0
fi

# These are the locations I keep my temporary source and build trees in
TMPDIR=$HOME/code/myproject-pre-commit
MIRROR=$HOME/code/myproject-pre-commit-mirror

# Exit with status 1 if any command below fails
set -e

# Checkout a copy of the current index into MIRROR
git checkout-index --prefix=$MIRROR/ -af

# Remove files from MIRROR which are no longer present in the index
git diff-index --cached --name-only --diff-filter=D -z HEAD | \
    (cd $MIRROR && xargs -0 rm -f --)

# Copy only _changed files_ from MIRROR to TMPDIR, without copying timestamps.
# This includes copying over new files, and deleting removed ones.  This way,
# "make check" will only rebuild what is necessary to validate the commit.
rsync -rlpgoDOc --delete --exclude-from=.git-hooks/excludes $MIRROR/ $TMPDIR/

# Everything else happens in the temporary build tree
cd $TMPDIR

nosetests

exit 0

This is my actual .git/hooks/pre-commit:

#!/bin/bash

set -e
for hook in $(find .git-hooks/pre-commit -perm /u+x,g+x,o+x -type f -not -name '*~' 2>/dev/null)
do
  echo "@@ Running hook: $(basename $hook)"
  $hook "$@"
done
like image 150
bstpierre Avatar answered Sep 21 '22 03:09

bstpierre