4
\$\begingroup\$

I use the following script to autotag the current workspace while building even if there are changed (not committed) files:

#!/bin/bash

tagname="autobuild-test1"
commitname="autocommit for tag $tagname"

set -e
head="`git rev-parse HEAD`"
test -n "$head"
git commit -m "$commitname" -a
taghead="`git rev-parse HEAD`"
git tag "$tagname" "$taghead"
#or just `git tag "$tagname" HEAD` for the 2 lines above
git reset "$head"

The idea: I commit everything which is not committed to a 'temporary commit' and tag its hash. After doing this, I revert to the original state by resetting to the previous HEAD.

In other words: I try to do git commit -a without touching HEAD, staging, stashing and workspace.

Pros:

  • this also works if the workspace is dirty
  • the script is very flexible
  • the script doesn't touch any files, doesn't do any checkout or remove operations

Cons:

  • the staging state is completely cleared after running the script
  • probably more state modifications which I didn't find yet
  • it is a script. I would prefer a single command for this use case
  • no proper error handling. if the script fails, HEAD might be changed

This script was inspired by cvs2git which uses the same strategy in cases where it's not clear to which revision a tag belongs to.

Is there anything you would change to make this script more rubust and/or to remove some of the cons?

\$\endgroup\$

migrated from stackoverflow.com Nov 2 '14 at 19:31

This question came from our site for professional and enthusiast programmers.

  • \$\begingroup\$ if there are new files (not added) they don't get commited. and you can use reset --soft to restore the index. Apart from this, I don't understand why you need a script like this..:) \$\endgroup\$ – vratojr Sep 16 '14 at 13:16
  • \$\begingroup\$ I'd look at what git stash does for this sort of thing actually (without the cleaning steps if you don't want to actually change the working directory). \$\endgroup\$ – Etan Reisner Sep 16 '14 at 14:08
  • \$\begingroup\$ @EtanReisner git stash merges working directory and index, which is not reversable... \$\endgroup\$ – Daniel Alder Oct 7 '14 at 13:39
  • \$\begingroup\$ git commit -a stages all unstaged changes and commits them. How is that different from git stash? You can't reverse that merge either. How is your desired/current process different than what stash is doing (if you ignore the --hard aspect of the reset that stash does)? The point of my comment was that if you wanted to see how to improve your script you should look at the implementation of git-stash (it is a shell script). \$\endgroup\$ – Etan Reisner Oct 7 '14 at 13:48
  • \$\begingroup\$ Ok, this was not clear to me (that I should look at the implementation). Will do this soon. So far I got an almost-perfect solution using your input. See in few minutes \$\endgroup\$ – Daniel Alder Oct 7 '14 at 14:19
2
\$\begingroup\$

With the input of @EtanReisner, I found a possible way to the solution:

That's our current situation:

$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    new file:   c
    new file:   e

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:    c
    modified:   e

Untracked files:
  (use "git add <file>..." to include in what will be committed)

    d

I try now to stash all this:

$ git stash --all

Now we can get the hash of it:

$ git rev-parse refs/stash
9a208ed215032b4e47cb1493fc5f16a4a5ea78c1

Or tag it directly (this works)

$ git tag tagged-workspace-01 refs/stash

Now I unstage everything

$ git stash pop --index

This worked quite well:

$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    new file:   c
    new file:   e

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

    modified:   e

Untracked files:
  (use "git add <file>..." to include in what will be committed)

    d

As you can see, under some (very unusual) conditions it happens that the revert is not 100% perfect (the not-staged removal of the file c which is also in the index as a new file), but so far it's the best solution I've found.

\$\endgroup\$
  • \$\begingroup\$ Sure, you needed to have done "rm c" instead of "git rm c" to get in that state, and git has no way of tracking that. \$\endgroup\$ – Andrew C Oct 7 '14 at 14:59
  • \$\begingroup\$ @AndrewC No. git stash is able to detect changes which are not in the index, like the modification of e and the new file d. so it should also detect the removal of c \$\endgroup\$ – Daniel Alder Oct 8 '14 at 7:50

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.