0

My scenario, using git:

  • Wrote some code and committed
  • Added feature 1 and committed
  • Added feature 2 and committed
  • Added feature 3 and committed
  • Added feature 4 and committed

and so on...

Everything is of course in master.

I have now decided that I don't want to implement features 3 and 4 at this time (may want them in the future). So I would like to "go back" (there is lots of debate about the word "revert" so I will avoid using it) to just after feature 2's commit and continue there.

I feel like branching is somehow in the equation here but I am not clear on what to do. I would like to understand the logical scenario first and then understand the commands to get me there.

Howiecamp
  • 2,981
  • 6
  • 38
  • 59
  • possible duplicate of [Revert to a previous Git commit](http://stackoverflow.com/questions/4114095/revert-to-a-previous-git-commit) – OMGtechy Aug 20 '14 at 21:23
  • have you pushed those changes yet? – bitoiu Aug 20 '14 at 21:34
  • @OMGtechy Great link.From reading that post&thinking about what Im trying to do its not clear to me if (as stated in Jefromis answer https://stackoverflow.com/a/4114122/133247) if I want to go back to the old commit&make changes,in which case Id make a new branch*,or if I want to revert which,quoting him,means to:"create a commit with the reverse patch to cancel it out."I want to keep the feature 3&4 commits,I just don't want them in my main codebase.So I'm not sure which choice to make.*If I do create a new branch,I consider that my main (master?) branch,so can I somehow still call it master? – Howiecamp Aug 20 '14 at 22:03
  • @bitoiu I'm new and just getting an understanding of the terminology. By 'push' I assume you mean to send these changes to some remote repo used by others? The answer is no. Btw does push mean the same as 'publish'? https://stackoverflow.com/questions/4114095/revert-to-a-previous-git-commit#comment39646023_4114122 – Howiecamp Aug 20 '14 at 22:05
  • @OMGtechy Ignore the "*" part of my question. It has been answered. I wish the site let me edit the comments. – Howiecamp Aug 20 '14 at 22:12

2 Answers2

1

There are a couple of options depending on if you have pushed these changes to the remote server or not.

If you haven't pushed up to remote yet, I would create a feature branch pointed at feature 4, and reset master back to feature 2.

git checkout -b <feature-branch> master
git checkout master
git reset --hard HEAD^^

If you have pushed the changes to remote, I would go a different route as it's generally a bad idea to change up commits that are public.

git checkout master
git revert <feature 3 sha>
git revert <feature 4 sha>
git checkout -b <feature-branch> master
git cherry-pick <feature 3 sha>
git cherry-pick <feature 4 sha>
Keith
  • 686
  • 5
  • 7
  • In an effort to understand the 3 commands I see that the -b option is actually a shortcut which does a git branch behind the scenes. So if I am right per [this man page](https://www.kernel.org/pub/software/scm/git/docs/git-checkout.html) the `git checkout -b master` line is equal to `git branch -f master` & `git checkout `. (But the second command would seem to do nothing here b/c feature-branch is already in my working dir.) Am I right that these are equal? – Howiecamp Aug 20 '14 at 22:25
  • You are correct that `git checkout -b` will create a new branch and switch to that branch in one command. I'm a little confused by "the second command would seem to do nothing". `git branch -f master` will create the new feature branch for you, but will not switch to that branch, which is what the second command does for you. Or, you can use the shorthand `git checkout -b master` to do it all in one. – Keith Aug 20 '14 at 22:34
  • To answer your comment about the confusion, maybe I am not exactly clear on what `git branch -f master` is actually doing. I thought it was creating a new branch called "feature-branch" which starts at master. After that is done, so master and "feature-branch" point to the same place? I'm not understanding how `git checkout master` switches to the *new* branch, since we are saying to check out master, not 'feature-branch'. – Howiecamp Aug 20 '14 at 23:58
  • Ahh, I see. The reason I'm saying switch back to master right after is because after we create feature branch to point to the same place (to preserve commits), we want to be on master to move it back to a point before feature 3 and 4 were implemented. It would have been cleaner for me to say `git branch -f master` as step one so I didn't have the extra step of switching back to master – Keith Aug 21 '14 at 00:03
  • Gotcha - So to confirm, before I do anything, I am at the HEAD of master. Then I do the `git branch -f master` and when that is done, "feature-branch" and master both point at the same place (master is of course unchanged, and now there is a new branch, called feature-branch, pointing at the same place as master). Then I do `git reset --hard HEAD^^` which sets master's head to two commits back (to after feature 2's commit). Right? – Howiecamp Aug 21 '14 at 00:14
  • From my understanding of the question, you want master to point at feature 2's commit and continue work from there. Just to be safe since I can't see your actual repository, run `git reset --hard ` which will move master to that point. You can verify your new branch is created and master is moved properly by looking at gitk. – Keith Aug 21 '14 at 00:44
  • I like using the ID also - removes ambiguity about how many tops back. – Howiecamp Aug 24 '14 at 00:43
0

So what you have now is a chain of commits all on one branch:

--(1)--(2)--(3)--(4) master

There are many things you could do from here. Here's the approach I would take. Start by creating some branches to keep track of the work you already have:

git branch features/3_and_4
git branch features/1_and_2 commit_2

        ------------ features/1_and_2
        |
--(1)--(2)--(3)--(4) master
                     features/3_and_4

Checkout those branches and verify they actually contain the history you want before you proceed, we're about to do something potentially destructive.

git checkout master
git reset --hard commit_2

Now we should have:

--(1)--(2)           master
        |            features/1_and_2
        |
        --(3)--(4)   features/3_and_4

Now you're in a good position to move forward. If features 1 and 2 are done you can merge their branch into master and continue development there (though I suggest you start a new branch off of master for each feature and merge it when the feature is finished.

Eventually you might return to features 3 and 4 after making some other changes. You'll then be looking at something like:

--(1)--(2)--(5)--(6) master
        |
        --(3)--(4)   features/3_and_4

That is where you might want rebase to bring your old features up to date:

git checkout features/3_and_4
git rebase master

--(1)--(2)--(5)--(6)           master
                  |
                  --(3)--(4)   features/3_and_4

All of the above assumes you are in a good position to rewrite history, no one else has seen these changes so it's fine to reorder them. If that's not the case you could still start with the same branches but you'll want to avoid reset and possibly avoid rebase as well depending on your team's workflow.

Jonah
  • 17,918
  • 1
  • 43
  • 70