I've been asked to write a script to run in post-build events in Visual Studio that will respond to an output-updating build by committing all changes, including new (untracked) files, to a local "autocommit" branch. The idea is to help the lazy developer backup buildable code frequently so they can avoid losing their work.
If the user isn't on the autocommit branch, I stash their changes and untracked files, checkout the autocommit branch, apply the stash, and commit before returning to the previous branch and popping from the stash to return to the initial state.
If a file is untracked on the user's current branch, but has already been auto-committed to the autocommit branch, then git stash apply
fails to overwrite the file tracked on the autocommit branch with the untracked version in the stash.
From the git stash
documentation, it doesn't seem like there are any relevant arguments I could use on the apply
call to get around this. I can detect untracked files in the current branch before stashing by parsing the result of a git status --porcelain
for lines starting with ??
, but that won't tell me which of those are already being tracked on the autocommit branch.
I'm currently required to use Windows batch files, so I'd like to limit my solution to tools likely to be available in that environment on any dev machine.
Here's the relevant snippet from my current approach:
git stash save --include-untracked -keep-index
git checkout autocommit
git stash apply
git add -A
git commit -m "Autocommit of build %VERSION%"
git checkout %BRANCHNAME%
git stash pop
The auto-commit process is intended to serve strictly as a convenience, git-based, auto-save system that doesn't require the developer to touch git or take any additional manual steps every time they rebuild their project successfully.
It doesn't align with normal git philosophy, because it's not intended to be used for source control or code sharing. I simply want to use git to provide snapshots for the developer to revert to e.g. if they lose their project to file corruption. This will lead to a large volume of tiny commits with little individual value, and that's okay - in fact, it's ideal for my needs.
The script assumes that the uncommitted changes on the current branch can be sensibly applied and committed to the autocommit branch. Any reason that assumption is invalid would be caused by the developer's direct interaction with the repo. As part of any such interaction, the developer is responsible for updating the autocommit branch accordingly so that the script's assumptions are valid the next time it's run.
I see some potential problems with your approach:
git stash apply
on autocommit
might give conflicts which need manual resolution. This will take the "automatic" out of the whole procedure. autocommit
is not guaranteed to be identical to the current working copy since git stash apply
performs a merge. The following sequence should solve both those problems and sidestep your original problem.
git stash -u
git stash apply
git add -A
git commit -m "dummy"
git merge --no-ff autocommit -s ours
git checkout autocommit
git merge - --squash
git commit -m "Autocommit of build %VERSION%"
git checkout -
git reset --hard HEAD~2
git stash pop
Explanation:
autocommit
with our changes to facilitate moving the changes. The ours
strategy ensures that the result of the merge is identical to the state of the working copy we want to save. There will never be a merge conflict with this strategy. This merge cannot be done into autocommit
because there is no theirs
strategy. autocommit
branch. --squash
option is vital. No commit is made, instead all the changes are staged. The result should be a single commit on autocommit
representing the working copy.
Be aware that this script likely will commit lots of junk (build files). The autocommit
branch will also be very different for different developers. I recommend it remains local to avoid bloating the original repo. If you must push it try to give each developer their own branch name to avoid conflicts.