kael
kael

Reputation: 6735

git checkout to temp work tree without altering index

I'm creating a git post-checkout hook to ensure my database state is consistent as I move between branches, but I'm running into a peculiar problem.

To make this work, I have to access migrations from both the "from" branch and from the "to" branch. The post-checkout hook runs after the index and work tree have been brought up to date with the "to" branch. What it does is this:

  1. Runs GIT_WORK_TREE=/tmp/from-branch git checkout $from_branch -- db to get the db files of the "from" branch into /tmp/from-branch/db.
  2. Runs GIT_WORK_TREE=/tmp/to-branch git checkout $to_branch -- db to get the db files of the "to" branch into /tmp/to-branch.
  3. Finds the common ancestor among the migrations.
  4. Runs the necessary downward migrations from /tmp/from-branch.
  5. Runs any new upward migrations from the current working tree in the repo.

This all works splendidly, except that after it runs, git is showing the following:

Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

        new file:   db/migrations/non-prod/20180718_102122-new-one-test-data.sql
        new file:   db/migrations/schema/20180718_102108-new-one.sql

Changes not staged for commit:
  (use "git add/rm <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

        deleted:    db/migrations/non-prod/20180718_102122-new-one-test-data.sql
        deleted:    db/migrations/schema/20180718_102108-new-one.sql

These two files are the files that were checked out from $from_branch into the tmp work tree. Git seems to be assuming that I'm checking them into my repo (despite my setting the GIT_WORK_TREE variable to another path) and automatically adding them to the index as "staged". I've combed the git-checkout manpage for options that would prevent this and haven't found any.

My current best solution is to run git reset after the checkout, but that feels like a hack. Just wondering if anyone else can think of some better solution.

Upvotes: 1

Views: 489

Answers (1)

torek
torek

Reputation: 488183

Your terminology is a little bit off, but this is essentially correct: git checkout copies files into the index first, before copying them out to the work-tree. This is how it is that the index indexes or caches the work-tree—hence the names the index and the cache. (Git also uses the index's cached information to minimize the amount of actual work done, so that if the files already exist in the work-tree in the correct form, Git does not have to touch them there.)

You are, as you note, using a different, temporarily overridden, work-tree. What you need, then, is a different, temporarily overridden, index. And in fact, Git supports just that:

TF=$(mktemp)
trap "rm -f $TF" 0 1 2 3 15   # clean up on exit

rm -f $TF # Git prefers a non-existent file to an empty one
GIT_INDEX_FILE=$TF GIT_WORK_TREE=/tmp/from-branch git checkout $from_branch -- db
rm -f $TF
GIT_INDEX_FILE=$TF GIT_WORK_TREE=/tmp/to-branch git checkout $to_branch -- db
... proceed as before

Note that rather than removing the temporary index each time, you could, if you choose to keep the /tmp/from-branch and /tmp/to-branch work-trees around as permanent work-trees, use two permanent indexes to index those two work-trees.

Upvotes: 4

Related Questions