6

When I'm going to do a Git operation that could be problematic (e.g. a merge/rebase that will require a lot of conflict resolution) my typical workflow is:

# was on `feature-branch` which has lots of conflicts with `master`
git checkout -b temp
git checkout feature-branch
git rebase master

This way, if I screw something up in the rebase I've saved the original state in the temp branch. I'm wondering if there is a better way to do this than create a temporary branch.

  • 2
    Slightly easier: `git branch temp; git rebase master`. No need to checkout the new branch when creating it. – 0x5453 Jun 10 '21 at 21:19
  • Excellent...thanks! – Jamesmontalvo3 Jun 10 '21 at 21:22
  • 1
    To save a commit I usually create a tag instead of a branch, with `git tag temp`. No need to checkout back to `feature-branch`. – rodrigo Jun 10 '21 at 21:25
  • 1
    In theory, you can use the branch's reflog to recover, but I prefer a named branch myself. In fact my usual method is: `git branch foo.0; git rebase master` when I'm on `foo` and want it to now be version 1. If I've done that a few times before it becomes `git branch foo.3; git rebase master`, etc. :-) – torek Jun 11 '21 at 07:13
  • I think the best answer to my question would say "no need to checkout, just do `git branch foo` instead" and then touch on the other options outlined in other answers. All the answers and comments have been very helpful. I could write up an answer to my own question at this point that combines these answers, but it feels like cheating. Is that acceptable in SO etiquette (to answer your own question after reading others' answers)? If someone reading this combines the options I'd totally accept that answer, of course. – Jamesmontalvo3 Jun 11 '21 at 12:25

4 Answers4

3

It is a good way to keep track of a prior state, I do this too (a branch, or a tag).

But you don't necessarily need to do that, since when you use git reflog <branch> (typically HEAD) you will see the history of <branch>, so you can reset to a commit the branch previously pointed to even if you don't first make a temporary branch for it.

coredump
  • 37,664
  • 5
  • 43
  • 77
  • Thanks for the quick response! So `git reflog ` will show me all the prior head commits, and I can check them out even if they have no branches referencing them anymore. I'm assuming these commits may be garbage-collected at some point, right? – Jamesmontalvo3 Jun 10 '21 at 21:21
  • Yes, there is an expiry delay that can be configured (30 days / 90 days depending whether the commit is reachable), that is checked when "git gc" is run (some commands call it automatically, see e.g. https://stackoverflow.com/questions/52743153/git-reflog-expiration-time). Usually you have plenty of time to recover but in any case you can still add a tag/branch if you want to keep a reference for an indefinite time. – coredump Jun 10 '21 at 21:32
2

Thing to know: a branch is just a name pointing to a commit.

Another thing to know: A rebase just copies commits, but then it moves the original branch pointer.

So what you're doing is sensible, although there is no need to checkout the temp branch and switch back. If you make another branch pointer, you have an easy way to repoint the original branch pointer again (with a hard reset) in case you don't like the way things turned out.

So before rebase:

A -- B -- C <-- main
      \
       X -- Y -- Z <-- branch

Prep step:

A -- B -- C <-- main
      \
       X -- Y -- Z <-- branch, temp

After rebase:

        main
          |
A -- B -- C -- X' -- Y' -- Z' <-- branch
      \
       X -- Y -- Z <-- temp

So just reset branch hard back to temp if you dislike the outcome, and let the copies it pointed to go out of existence. Then delete temp.

If you do like the outcome, delete temp, and let the original commits it pointed to go out of existence.

matt
  • 515,959
  • 87
  • 875
  • 1,141
1

You need to perform git stash operations like so:

git stash create [<message>]

git stash branch <branchname> [<stash>]

Then keep this all aside and do whatever you want with the branch you are already working on.

Then if something not working with your current operation, you can use the previously saved branch by using:

git stash list

Or

git stash show

And finally, if you want to apply or remove that stash, simply use:

git stash ( pop | apply ) [--index] [-q|--quiet] [<stash>]

That's it

Link to the docs:

https://git-scm.com/docs/git-stash

  • I wondered if there was a way to do it with `git stash`, but wasn't sure since I thought that was intended for dirty working directory only. Re-reading the docs, I don't think it works as a solution to my question. If I'm on a clean `feature-branch` and want to rebase it onto `master`, doing `git stash create` and/or `git stash branch feature-branch` and/or `git stash feature-branch.1` nothing happens. Doing `git stash list` or `git stash show` afterwards shows nothing. – Jamesmontalvo3 Jun 11 '21 at 12:17
  • Here is an exact example that will solve your current problem: 1st: `git status` let us say that you have current changes 2nd: `git stash` now you stashed the changes 3rd: `git status` again, you will see no changes 4th: `git branch ` 6th: `git checkout ` 5th: `git stash pop` to remove the stash from the saved place and apply them to the current branch. 6th: `git stash apply` to apply the stash to the new branch. This what you should apply to the changes (conflicts) that you will create in the rebase process – Mostafa A. Hamid Jun 12 '21 at 14:37
  • And if you want to do that perior to rebase, then here is the workflow: 1st: `git branch ` 2nd: `git stash` 3rd: `git stash pop` 4th: `git stash apply` 5th: `git checkout master` 6th: `git rebase ` In case you want to roll back: 1st: `git rebase --abort` 2nd: `git checkout ` 3rd: `git apply --reverse` Then you are now back to the original changes. – Mostafa A. Hamid Jun 12 '21 at 14:54
1

I assume you push your feature-branch to your remote anyway, so you don't have to backup anything, since it is backed up on your remote. Just make sure you didn't break anything during rebase before force pushing the feature-branch.

So the workflow would be as follows.

Before rebase:

A -- B -- C <-- main, origin/main
      \
       X -- Y -- Z <-- branch, origin/branch

After rebase:

        main, origin/main
          |
A -- B -- C -- X' -- Y' -- Z' <-- branch
      \
       X -- Y -- Z <-- origin/branch

If everything worked well, you just run git push -f to update the remote feature branch.

        main, origin/main
          |
A -- B -- C -- X' -- Y' -- Z' <-- branch, origin/branch

And if it doesn't you hard reset to origin/branch and you are back at the beginning (git reset --hard origin/branch).

A -- B -- C <-- main, origin/main
      \
       X -- Y -- Z <-- branch, origin/branch

This is basically, the greatness of git and maintaining a remote repository, it's not just about collaboration with others, you can also collaborate with your past self :D

schilli
  • 1,700
  • 1
  • 9
  • 17