user7898461
user7898461

Reputation:

git reset --soft - does it go back to git checkout point or to the last git merge point?

I think what I am looking for is the oldest shared ancestor of two branches, or something like that, this question seems to touch on it: Finding a branch point with Git?

But instead of the diagram in the OP, this is more what I am looking at:

-- I -- I -- I -- I -- I -- I -- I  (integration branch) 
          \         \          /
           \         \        /
             F -- F -- F -- F  (feature branch)

My question is - if we checkout a feature branch from integration and make some changes and some commits, and then we update/merge with integration a few times as we go. Aka, commit commit, merge with integration, commit commit, merge with integration, etc. If we then do a git reset --soft <integration>, is that going to reset it to the commit on integration when git checkout was used, or will it simply reset it to the point where the last git merge with integration occurred?

The goal is so that I can make my feature into one big commit. If the git reset --soft only goes back as far as the last git merge with integration, then my feature might have 100s of commits, which is no bueno, and I will need another technique.

Upvotes: 3

Views: 229

Answers (2)

torek
torek

Reputation: 490078

You can use git reset --soft, but there's something else you must do—or rather, not do—first.

The goal is so that I can make my feature into one big commit.

In that case, make sure you don't start with:

-- o -- A -- B -- C -- D -- E -- IM   <-- integration
          \         \          /
           \         \        /
            F1 -- F2 - FM - F4   <-- feature

Note that I have replaced the individual letters here so that I can talk about particular commits. The two most interesting commits, as far as Git itself is concerned, are F4, which is the tip commit of the branch named feature, and IM, which is the tip commit of the branch named integration.

The commit labeled FM is not a problem, even though it is a merge commit. The commit labeled IM is a problem. That's because this commit is reachable from the tip of integration. For (much) more on the concept of reachability in general, see Think Like (a) Git. Whenever commit IM itself is reachable by starting at the commit to which integration points, and working backwards (leftwards), so are all commits that commit IM itself reaches. Commit IM leads back to both commit E (not a problem) and F4 (problem!).

If you eliminate commit IM, so that you have:

-- o -- A -- B -- C -- D -- E   <-- integration
          \         \
           \         \
            F1 -- F2 - FM - F4   <-- feature

you can now git checkout feature and run git reset --soft integration, resulting in this:

-- o -- A -- B -- C -- D -- E   <-- feature (HEAD), integration
          \         \
           \         \
            F1 -- F2 - FM - F4   [abandoned, but remembered as feature@{1}]

Your index and work-tree are unchanged from when you had commit F4 checked out, though, so you can now run git commit to turn the current index into a new commit. The name feature will now point to the new commit:

                              F   <-- feature (HEAD)
                             /
-- o -- A -- B -- C -- D -- E   <-- integration
          \         \
           \         \
            F1 -- F2 - FM - F4   [feature@{1}]

The snapshot for new commit F will match that for commit F4:

git diff feature@{1} feature

will print nothing at all. But the parent of new commit F is existing commit E. (Commit F also has a new author and committer and corresponding "now" time stamps, which also distinguish it from F4.)

Upvotes: 1

VonC
VonC

Reputation: 1329712

Each time you are merging feature back to integration, you are moving integration HEAD (which now reference the new merge commit)

You need to mark integration before doing your feature branch and your merges in order to get back to it.

One possible marker would be origin/integration: that last time you fetch integration).

Another one is git merge-base --fork-point (based on reflog, so unreliable) or some diff between git rev-list --first-parent of both branches.

In any case, your git reset --soft would have to use that marker, not the local integration branch.

Upvotes: 0

Related Questions