1

I'm looking for some way to automatically save the current state of my code whenever I run some experiment.

But I do not want to pollute the commit history of my main branch with a million automatically-made commits. I was thinking of making a my_experiments branch, to which I just push the current state of the code whenever an experiment runs.

So I guess what I want is to commit my current code to an experiments branch, without committing it to my current branch. I still want to retain my uncommitted code on my current branch.

What is the nicest way to do this in git?

Edit

I've been asked to clarify what I want and why.

Sometimes I make a change to the code in order to test something. The changes are typically ugly hacks. Typically the process goes:

  • Make hacky change
  • Run Code and Save result
  • CTRL-Z
  • View saved result

I am saving the results of the run, and I would also like to save the state of the code alongside it.

Now I want these "hack" changes to be separate from my normal development cycle - I really just need a record of the state of the code when I made the hack. So rather than have a series of "make hack" "revert-hack" pairs in the commit history of my main branch, I'd like to have all the "hacky" changes committed only to a single "experiments" branch.

Peter
  • 12,274
  • 9
  • 71
  • 86

4 Answers4

3

I am giving an answer considering you have some changes already made to your current branch and you want to commit them in another branch keeping your current branch same as it was earlier.

git stash
git checkout -b <new_branch>
git stash pop
git add .
git commit -m '<Your Commit Message Here>'
Rishabh Dugar
  • 606
  • 5
  • 16
  • Nice, but when I follow up by returning to my original branch `git checkout -` I want the (un-added) changes to be there, but instead I've reverted to the last commit – Peter Sep 12 '17 at 11:55
  • I used a modified version your answer to come to my solution, thanks. – Peter Sep 12 '17 at 12:43
  • 1
    Glad It helped , I was about to post apply thing :P . (y) – Rishabh Dugar Sep 12 '17 at 12:47
  • The problem isn't quite solved though. See my other answer (based on this one) and the "caveats" mentioned in it. – Peter Dec 17 '19 at 18:43
1

There is nothing wrong with making a large number of commits on your branch, because you can always squash them down at a later point, assuming you have not yet pushed them. For example, assuming you made 10 small commits on your branch, but you wanted to really just push a single logical commit, you could use reset soft:

git reset --soft HEAD~10
git commit -m 'single commit with all my changes'
git push origin master

If you just want to take a snapshot of your branch in its current state, you could always create a new branch from the HEAD, e.g.

git branch backup_experiment_1

Although typically you don't need this because Git is very flexible even with just a single branch.

Tim Biegeleisen
  • 502,043
  • 27
  • 286
  • 360
  • Thanks, didn't know about that. Doesn't quite fit my requirements though, because (1) I want to have a single branch that records all experiments - not to just have the commits on the branch that I happen to be working on. (2) I don't want to have to worry about how many "little" commits I have to reset every time I do a "big" commit. – Peter Sep 12 '17 at 09:24
  • `git branch backup_experiment_1 ` seems to create a branch off of the last commit from the current branch, which is not what i need. I need to commit the current state of the code (including uncommitted changes) to an "experiments" branch, and return to my current branch, while retaining the uncommitted changes as uncommitted changes. – Peter Sep 12 '17 at 12:02
  • @Peter I don't think you really need this. I've been using Git for the better part of a decade and I've never even heard of such a workflow. – Tim Biegeleisen Sep 12 '17 at 12:06
  • So have I and I didn't think I needed it until I did. Context is I'm making a [Python package](https://github.com/QUVA-Lab/artemis) for running and saving experiments, and for reproducability I would like to associate each run of an "experiment" to a commit - But I don't want to pollute the history of my main working branch with the huge amount of commits that would be involved here. – Peter Dec 17 '19 at 18:47
1

I found the solution I need (edit: it's not quite right yet - see comments) is:

git stash
git checkout -B experiments  
git stash apply  
git diff --name-only --diff-filter=U | xargs git checkout --theirs
git commit -am 'autocommit'
git checkout -
git stash pop

What this does:

  • git stash Copy a temporary copy of the working code
  • git checkout -B experiments Checkout branch experiments, creating it if it doesn't exist.
  • git stash apply Paste the temporary copy into the "experiments" branch. This will create conflicts if you've already run this command.
  • git diff --name-only --diff-filter=U | xargs git checkout --theirs Resolves all conflicts in favour of the pasted stash (it calls git checkout --theirs X for X in (list of conflicted files)
  • git commit -am 'autocommit' Commit these changes to the experiment branch
  • git checkout - Return to your previous branch.
  • git stash pop Paste the temporary copy of the working code, and free the saved copy from memory.

Thanks to Rishabh Dugar for the inspiration to use stash, and another answer by Charles Bailey: https://stackoverflow.com/a/10874862/851699.

Note that your current directory needs to be the root of your git repo for this to work.

Peter
  • 12,274
  • 9
  • 71
  • 86
  • 1
    Several caveats apply here: (1) `git checkout -B experiments` will forcibly reset any existing `experiments` branch to point to the current commit, even if that means forgetting previous commits (though they will still be in its reflog). (2) `git stash` is a no-op if there is nothing to stash. The intermediate and final stash ops will then either fail (nothing in the stash) or, worse, use a *previous* stash. It's probably wise to check that there's something to save. (3) If you have some changes stored in the index and some only in the work tree, things may get messy. – torek Sep 12 '17 at 15:10
0

Just checkout to a temp branch, make as many commits as you like, and when you've a workable code squash all the commits into one.

git checkout -b my_experiments
# Do your "experiments"
git rebase -i branch # <branch> should be the parent branch i.e. develop/master

Rewriting git history

# For instance
>>> git rebase -i master
pick 8705209 first
edit 7979797 second # Use edit wherever you want to view and edit commit
squash 9793757 third # Use squash to squash commits into the previous one.
hspandher
  • 15,934
  • 2
  • 32
  • 45
  • Thanks, But I don't ever want to merge my experimental-commit tree into my main tree. I want the "experiment" branch to exist purely as a record of the state of the code when the experiment was run. – Peter Sep 12 '17 at 11:58
  • 2
    @Peter The commits you make to your current branch already _are_ a record of the state of the code. Really, you should edit your question and tell us why you need such a workflow. – Tim Biegeleisen Sep 12 '17 at 12:07
  • 1
    @Peter Branches are cheap in git. Just create a new branch every time, and do whatever you want. – hspandher Sep 12 '17 at 12:43