5

I'm attempting to automate a particular operation on a git-repository (typedoc, a command to generate TypeScript documentation); but I need that command to only "see" the actually-staged changes. Any unstaged changes need to be "hidden" from the command.

My current approach is attempting to automate git-stash, such that it stashes away any untracked-files and unstaged-changes, then runs the command, then pops that stash. The meat of the script is thus:

stash_working=_no

git update-index --refresh
if git diff-index HEAD -- .':!Documentation/'; then
   stash_working=_yes
fi

if [ "$stash_working" != "_no" ]; then
   git stash push --include-untracked --keep-index -m "AUTOMATED STASH" \
       -- .':!Documentation/'
fi

typedoc
typedoc_exit_status=$?

if [ "$stash_working" != "_no" ]; then
   git stash pop
fi

exit $typedoc_exit_status

Unfortunately, this isn't working as hoped: in particular, despite "not being included" in the stash, the stashed changes are ... interfering with themselves(?) when being popped. For instance, if the staged content (that I do want in the docs) contains this line,

 * This is some fake documentation for testing purposes.

... but there's an unstaged-change updating that to

 * THIS IS A CHANGE TO THAT DOCUMENTATION

... then I get the following conflict, and that git stash pop fails:

<<<<<<< Updated upstream
/**
 * This is some fake documentation for testing purposes.
 */
export const Foo = {}
||||||| constructed merge base
=======
/**
 * THIS IS A CHANGE TO THAT DOCUMENTATION
 */
export const Foo = {}
>>>>>>> Stashed changes

I've also tried git stash pop --index, but that has the same effect, in this case.

Is there a Git-centric way (i.e. not scripting the creation of a temporary working-directory, checking out, running docgen, copying docs back to original project, type-of-thing) for me to improve on this automation so that such merge-conflicts don't occur, and the working-directory is transparently kept in the state it was at during the

Géry Ogam
  • 6,336
  • 4
  • 38
  • 67
ELLIOTTCABLE
  • 17,185
  • 12
  • 62
  • 78
  • 1
    When using `--keep-index`, you must do a subsequent hard reset (or `git restore`) before the eventual `git stash apply --index`. When using `--include-untracked`, you must do a subsequent `clean` as well. It's tricky to get these right: you only want to hard-reset and clean away files that are in the stash. The fact that you made the stash yourself, with `git stash push` *and no limiting pathspecs*, helps out a lot here. – torek Sep 10 '21 at 05:39
  • Personally, I'm more or less convinced that `git stash` is the wrong approach. I don't have one I recommend here though. – torek Sep 10 '21 at 05:39
  • In the actual script, there are in fact limiting pathspecs. And they can get kinda complex. … crap. Added one as an example to the inlined version up above. /= – ELLIOTTCABLE Sep 10 '21 at 05:40
  • It's worth looking at the Python code over at pre-commit.com. I have not looked at it closely myself, but the author put in a lot of skull-sweat over getting this sort of thing to work right. – torek Sep 10 '21 at 05:43
  • if you want to work with the staged version of your files, it's worth knowing the existence of [`git checkout-index`](https://git-scm.com/docs/git-checkout-index). For example : `git checkout-index --all --prefix=/tmp/mycheckout/` (don't forget the trailing slash though ...) should give you a checkout of your staged files at `/tmp/mycheckout/` – LeGEC Sep 10 '21 at 07:05
  • I've written something very similar 2 days ago: https://stackoverflow.com/a/69110051/3052438 It's about doing that in a Git hook but there should be no difference. – Piotr Siupa Sep 10 '21 at 07:26
  • What changes did `typedoc` generate in your worktree / your index ? can you check : `git diff --name-status stash` (<- compare your worktree with the stash) and `git diff --name-status --cached stash` (<- compare your index with the stash) ? – LeGEC Sep 10 '21 at 12:04

0 Answers0