0

I created a tag on my DEV-branch. I merged this tag into my master-branch. Realising that the tag makes more sense in the master branch, I deleted the tag.

The DEV-branch is still merged with the master branch, but, to my surprise, the master-branch doesn't contain any changes from DEV.

This screenshot here was taken after I recreated and pushed the tag again, still with no changes in the master branch. Also I tried and failed to revert the merge...

Screenshot of git history

For Git, the merge was successful, so I can't remerge DEV into master. How can I solve this?

rotsch
  • 1,909
  • 16
  • 36
  • You did a `Revert "Merge tag '20150302-3.2.2015.10'"`, you'll have to revert the revert for the tag to be applied. Also: never revert merges, as they don't allow you to revert commits correctly. Sauce: http://stackoverflow.com/questions/7418644/git-revert-of-merge-commit-causes-issues-when-merge-is-actually-done – AlbertEngelB Mar 02 '15 at 17:14
  • I can't revert this revert: Your branch is up-to-date with 'origin/master'. nothing to commit, working directory clean – rotsch Mar 02 '15 at 17:21
  • The confusion comes from mixup of branches and tags. You should have simply deleted the tag, and re-tagged: ``git tag -d tagname`` ``git checkout master`` ``git tag -a tagname -m "annotation"``. If tag already pushed: ``git push origin :tagname`` ``git push origin --tags``. It can get messy if other people have already fetch the tag, they would need to delete their local copy of the tag as well otherwise git won't detect that the tag has been moved. Final advice: don't move tags, just retag and increment the version. – Sébastien Dawans Mar 02 '15 at 17:33

1 Answers1

4

[NB: this isn't quite an answer, but it won't fit as a comment.]

Your question starts with a basic misconception: tags don't attach to branches at all; they only point to a commit.

A tag is just a permanent1 name for one specific commit (one commit's SHA-1). Keep in mind that git identifies everything by SHA-1 internally, and reference names—branches and tags, mostly, although there are other forms—are partly2 used to let us puny humans deal with the SHA-1s.

Git commands—git merge in this case—that take branch and tag names generally turn the name into an SHA-1 and do most things using the SHA-1. In the specific case of git merge, the only part that retains the original name you passed in is the final commit message ("Merge tag '20150302-3.2.2015.10'", in this case). Everything else uses the underlying SHA-1. This means that if you later move the tag from one SHA-1 to another, that won't affect the merge at all, it will just confuse the next puny human to come along.

The confusion comes about in part because a tag is supposed to be permanent. In git, you have two kinds of commonly-used names, branches and tags, both of which are just names for SHA-1s; but they have different properties. A branch name has the property of moving, so that it refers to the latest commit. In fact, this is so useful that git will automatically move it for you (under the right, but very common, conditions anyway). That is, if you're "on branch master" or whatever, as git status puts it, and you make a new commit, then branch master is adjusted so that it points to the new commit you just made. This is how branches grow.

Tags, by contrast, are meant not to change, and git won't change them on its own. You can of course force a change, or delete a tag entirely (and then re-tag or not as you like). However, if anyone else—another git clone of our repo, or even yourself tomorrow or next week or whatever—has recorded the tag as pointing to commit 1234567 earlier, and now comes across the tag as pointing to commit 6789abc, that could be quite confusing. Branches are expected to move, so if a branch used to point to 1234567 and now points to 6789abc, that seems normal enough; but tags aren't, so that's a surprise.

In short, moving a tag is kind of rude: a bit of a shock to the reader. Sometimes it's appropriate anyway, but it is often better to avoid it.

None of this has anything to do with your current problem, which, to recap, is this:

the master-branch doesn't contain any changes from DEV.

Commenter Dropped.on.Caprica pointed out the reason, which is that you subsequently reverted your merge. Your commentary answer indicates that you attempted to revert the revert by repeating the git merge command. That won't work as git merge uses the commit graph to decide what work needs to be done, and according to the graph, no work needs to be done after all. See the linked answer for details.

To restore the merge, you can simply revert the revert; or, if you want to repeat the merge (and maybe do it differently), you can use the same git graph nodes (or different but nearby ones). For instance, you could attach a new branch name to the first-parent of the third commit in your graph. I can't see the commit message, nor the SHA-1, of this commit, but I can give you a relative name (which only works until the current commit changes):

git checkout -b newbranch HEAD~3

and then from there, merge the tip commit of the current DEV branch:

git merge DEV

If you like the resulting tree, but want it as a "fast-forward-able" commit on branch master, there are several ways to obtain that as well. See How to create copy of a snapshot (commit) in a branch onto another branch in git?, for instance.


1Well, meant to be permanent. See subsequent paragraphs.

2They're also used for a cheap sort of security, in that some exporters only give access to SHA-1s via reference names. This is routinely violated by other export mechanisms, though: for instance, many web servers will cough up a git object if you provide them the right SHA-1.

Perhaps most important of all, though, references are what make commits—all git objects, really—reachable. Objects that are not reachable—that can be found only by SHA-1, not by starting with a name-to-ID mapping and then following other IDs from there—are eligible for "garbage collection" and eventually are removed from the repository.

Community
  • 1
  • 1
torek
  • 448,244
  • 59
  • 642
  • 775
  • Thank you very much for your clarifications, torek. I took the hammer and hard deleted all the commits including the merge from DEV to master. I redid the merge DEV -> master. Still, no changes are taken over from DEV... Why? – rotsch Mar 03 '15 at 10:06
  • I'd have to know or see more (of the commit graph, or at least, the ID of the merge-base(s) of the branches in question and diffs from the base—with luck, there is only one—to the branch-tips) to say what's going on at this point. – torek Mar 03 '15 at 10:23
  • This is before the merge: http://i.imgur.com/LXO0PK8.png My understanding is, that, merging DEV into master should merge all the changes into master? – rotsch Mar 03 '15 at 10:30
  • Hm, OK, the merge-base there is the commit labeled `DEVold`. At that point if you're on `master` and merge `dev`, git should diff `DEVold`-vs-`master` (what you have in `master` now) and `DEVold`-vs-`DEV` (what changed in `DEV`) and combine those two diffs and make a new commit on `master`. So you can `git diff DEVold DEV` to see what changes the merge might try to bring in, and `git diff DEVold master` to see what changes you already have (that the bring-in step will therefore ignore). – torek Mar 03 '15 at 10:35
  • or... diff between DEV and master? :) because that shows me exactly the files I did change. The merge completes successfully but it doesn't change any file. When I diff DEV and master after the merge, it still shows me exactly the same files as before the merge... however the graph is correct: http://i.imgur.com/6EfPO8c.png – rotsch Mar 03 '15 at 11:15
  • No, comparing `DEV` directly to `master` (in either direction) implies a *copy* rather than a *merge*. The point of a merge is to pick up changes "they" (the merge-ee) made that you didn't, without wiping out changes you made, and without duplicating changes. To achieve this, git looks back in history for where the two branches were last joined—which is also where they diverged, by definition—and then diffs that merge-base against the two tips. The resulting diffs are "changes you made" and "changes they made". Git then combines these to get the tree, and commits to update the graph. – torek Mar 03 '15 at 11:37
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/72152/discussion-between-rotsch-and-torek). – rotsch Mar 03 '15 at 14:50