4

I am new to Git and need help understanding Git history graphs, i.e. the relationship between commits and merges as they are displayed on the graph in tools like SmartGit or GitGui. In the image below, what is the relationship between the commits in red, specifically "IA-481" and "Merge branch IA-481(Release2)...." I am mainly asking because "IA-481" was intended to go in a branch called "IA-481(Release2), not in Master.

So here is a little more detail:

  1. I originally checked in my files in a branch called "IA-481(Release)".
  2. I then switched to Master, called merge from the Master Branch to merge the files from "IA-481(Release)" with Master. I made a few more changes but realized it was too soon to commit to Master, so I didn't commit to Master.
  3. Instead, I created and switched to another new branch called "IA-481(Release2) and I committed the merged files to that second new branch (not to Master).
  4. Someone else switched to the IA-481(Release2) branch to check out my work, and made some check-ins.

Later we find out that the IA-481 commit I originally made to the "IA-481(Release2)" branch somehow wound up in the Master Branch. and I'm trying to figure out how it got there. Was it the commit called "Merge branch IA-481(Release2)" made by that other person that merged it with Master, or was it already in Master with my IA-481 check-in. At which commit did things go wrong?

John
  • 263
  • 2
  • 10

5 Answers5

1

IA-481 was a commit on a branch separate from master. Then that branch was merged into master at the merge commit that you highlighted.

Gary Fixler
  • 4,762
  • 1
  • 17
  • 37
  • IA-481 wasn't supposed to be merged. Did someone consciously do it or did it happen automatically somehow? All the merged files don't appear under the merge commit I highlighted. They appear under the IA-481 commit, which makes it appear that they were merged at the IA-481 commit. Is this true? – John May 03 '13 at 11:07
  • @John What does `git log -1 ` tell you about who committed the merge? (Alternatively, highlight that merge commit in `gitk` or whatever repository browser that is, and look at the commit message - it should tell you who merged the branch containing IA-481 into master.) Also, usually, the only files that appear to be modified by merge commits themselves are the ones that had conflicts that had to be resolved. – twalberg May 03 '13 at 16:01
  • The "Merge branch 'IA-481(Release2)" commit is clearly done by the other person, not me. But because the unwanted the files are under my check-in (IA-481), not his, I am being blamed for the error. Make sense? I am trying to confidently prove it wasn't me. – John May 03 '13 at 16:13
  • Well, the person who did the merge into `master` is the one that introduced the changes to `master`. Before that those changes only existed isolated on the IA-481 branch. Whether they should have even been there is a bit different question (did those files really need to be changed/added/deleted/whatever?). If you didn't do the merge commit, then you're not the one that "broke the build" or whatever the issue is... – twalberg May 03 '13 at 16:28
  • "Before that those changes only existed isolated on the IA-481 branch"--does that graph definitely confirm that? Since the IA-481 check-in appears in the graph for Master branch above with my name and unwanted files as part of the commit, the argument by the other party is that I was the one who checked them into Master. – John May 04 '13 at 03:14
  • Get the SHA-1 name of the IA-481 commit and in a shell do `git log -1 --format=fuller ` and you'll see who authored the commit, and at what time, and who committed it, and at what time. The committer date changes when the commit is rebased or cherry-picked, and perhaps as a result of other commit-moving commands, but the author/author time will stay the same. You can also do this in the merge commit to see who did that. If you want to see what changed in a commit, either do `git whatchanged -1 ` or `git show `. These will help you figure out what changed, and who did it. – Gary Fixler May 04 '13 at 03:58
  • We already know who authored each commit. I authored IA-481 and the other guy authored "Merge branch 'IA-481(Release2)". The graph shows the correct sequence. His commit came after mine (and contained all the files in my commit). Again, the question is, whose fault was it that the unwanted files made it to Master? – John May 05 '13 at 00:59
  • I think that once someone merges a branch to Master, all the commits in that other branch appear in the Master graph. How can I prove that my commit was not originally in Master, but in "IA-481(Release2)", and that the other guys commit named "Merge branch 'IA-481(Release2)" was the one that merged my files to Master? – John May 05 '13 at 01:00
  • Are you able to work with straight git in a command line? I don't know any of the guis. If so, you can look at the commits before the merge to see where the file comes in. The commit with the message `IA-1617` was on master, and your commit `IA-481` was merged into master with that commit to create `Merge branch 'IA-481 (Release 2)'` You can look at both sides coming into the merge here with `git show `, using the hash of each one. Are you even able to see the hashes in your UI? They're not shown here. You can also do `git whatchanged -1 `; the files with `A` were added there. – Gary Fixler May 05 '13 at 10:20
  • I am totally aware that my changes were merged into Master by the Merge branch 'IA-481 (Release 2)' commit. However, I'm trying to prove is that my IA-481 was not already committed to Master. For example in the first Image above, notice the 3rd commit from the top "IA-1416 Squid Proxy" appears to be on a separate branch from Master (similar to my IA-481 commit in question). However that commit was actually checked into master (remote origin or something like that) and then was officially merged into Master with the topmost commit called "Merge remote-tracking branch..." – John May 05 '13 at 22:35
  • We may have some communication issues here (not all that uncommon when helping with git online :). I want to make sure first of all that you know these numbers are your/your company's invention, not git's. They're commit comments. The SHA-1 hashes, which would be more helpful for us in this situation look like what you see in the second commit down from the top of your first image (7b6d7e1etc...). Normally we would see those in between the train tracks on the left and the commit messages on the right. These would help us much more easily and succinctly refer to particular commits. – Gary Fixler May 06 '13 at 02:16
  • Anyway, these SHA-1 hashes are how you can ask questions about particular commits. Git doesn't have a way to ask about the commit with commit comment "IA-481", so I can't directly give you a command to try in a shell, like `git show 7b6d7e1`, or `git whatchanged 7b6d7e1`, either of which would show you exactly what happened in that particular commit. You can follow any of these branches back in time, with every commit having a unique SHA-1 name (which, again, we can't see in your images), and you'd be able to keep going back on each branch until you saw where those file names first appeared. – Gary Fixler May 06 '13 at 02:20
  • Gary I understand that the commit comments don't mean anything. I do have the SHA-1 hashes for the commits in question and I am able to use a command line. However, Using git show or git whatchanged is similar to what the SmartGit Gui is already doing. I know what is in these commits, I am just not sure how to use that information to answer my own question as to who first introduced the unwanted changes to Master. To be exact, the "Merge branch 'IA-481(Release2)" has all the unwanted changes in my commit "IA-481" plus a few more changes, but my commit came first in time. – John May 06 '13 at 04:21
  • This is why the other guy is blaming me for the error. Would it be helpful if I posted the results of `git whatchanged` for my commit and his? Here is some additinal facts: IA-481 (my commit) has all the unwanted files. IA-1617 (commit after mine) does not have the unwanted files. "Merge branch 'IA-481(Release2)" has all unwanted files. – John May 06 '13 at 04:32
  • Please see updated question above with git whatchanged results – John May 06 '13 at 04:48
  • You say "I know what is **in** these commits," (emphasis mine), but `git show` and `git whatchanged` don't show what's in a commit; they show what *changed* from the previous commit. They show this in different ways. `git whatchanged` would be a better choice here, as the `A` on the line would mean the file had been created. If you find a commit that says that the filename in question was added there, then it didn't exist before that. If you're on the master branch and you do `git whatchanged -1 ` on a commit, and it shows an A for that filename, *that's* where it appeared. – Gary Fixler May 06 '13 at 08:24
  • There are several IA-1617 commits. I'm presuming we're talking about the one that appears in the images immediately above your IA-481. If so, and if the unwanted files are not in the IA-1617 commit, and they are in your IA-481 commit, then IA-481 is where they came from in the "Release2" merge commit. To see if they were *added* in your IA-481 commit, do `git whatchanged `. It should show you as the author, and you'll see the filename(s) with an `M` or `A` preceding them. If you see an `A`, then you added those files in IA-481. If you don't see this, they were added earlier. – Gary Fixler May 06 '13 at 08:37
  • @John Use `-m` with `git whatchanged`, otherwise it won't show the changes in merge commits. – tom May 06 '13 at 09:17
  • git changed `-m` shows that the other guy's merge included the unwanted files, but also shows that my commit included the unwanted files. I've updated the question above with the `-m` results. Really appreciate your help. – John May 06 '13 at 15:46
1

Commits introduce changes. When commits are made one after another on the same branch (the normal case), the changes are cumulative. When branches are created, the changes made in one branch do not appear in the other branches. A merge is required to combine the independent changes.

Consider the following simple history. The commits modify a single file. The content of the file after each commit is displayed in double quotes. Commit 0 is the first commit, commits 1 through 4 add the English name of their commit number, and commit 5 merges the changes introduced by commits 3 and 4.

*   commit 5: "one two three four"
|\  Merge: 3 4
| | 
| |   
| * commit 4 "one two four"
| | 
| |   
* | commit 3 "one two three"
|/   
|  
* commit 2: "one two"
| 
|  
* commit 1: "one"
| 
|  
* commit 0: ""

Commit 4 was made on a different branch. It corresponds to commit IA-481. Presumably this commit introduced some changes, and in commit "Merge branch IA-481(Release2)...." these changes have been integrated into the master branch. This is the normal workflow when working on multiple things: branch, commit the changes, then merge them into the master branch. Without the merge, the changes just sit in the separate branch and don't do anything.

tom
  • 18,043
  • 6
  • 39
  • 36
  • Thanks, what you say makes sense. The problem/issue is that the files in commit IA-481 weren't supposed to be merged into Master. How did they wind up there? Prior to the second commit called "Merge branch IA-481(Release2)...." were the files for IA-481 already in Master, or were they still in their own branch? At which commit did things go wrong? – John May 03 '13 at 10:44
  • The changes in commit IA-481 definitely look like they were merged into Master in commit "Merge branch IA-481(Release2)....". I don't think they could have ended up in Master before that, but you should verify this by checking out IA-1617 and having a look. Consider using `git revert` (or the GUI equivalent) to undo the merge. – tom May 03 '13 at 11:06
  • I actually did a checkout of IA-1617 (the one after IA-481) and the unwanted files were not part of that checkout. The problem is that all the unwanted files, nevertheless appear under the IA-481 commit (my commit) in the GUI (see second image above), so it appears that it was my mistake. The actual merge commit only contains 1 file that correctly belongs in the Master branch – John May 03 '13 at 11:27
  • Please go through the commits systematically. For each of consecutive commits IA-1617, IA-481, IA-1617, Merge with branch IA-481(Release2), and IA-1535, (a) check out the commit and see if the unwanted files appear and (b) tell us if you made that commit. – tom May 03 '13 at 11:37
  • I have gone through them in the order below and checked out within the Master branch. Here are the results regarding the unwanted files: IA-1617--unwanted files not present. IA-481-- unwanted files present. IA-1617 unwanted files not present. "Merge Branch IA-481(Release2)"--unwanted files present – John May 03 '13 at 14:51
  • I have updated the description of the question with a little more history to give more context. Please help. – John May 03 '13 at 15:17
  • The changes wound up in the Master branch because of the commit "Merge branch IA-481(Release2)", so the fault is with whoever made that commit. The only thing that doesn't add up is *"The actual merge commit only contains 1 file that correctly belongs in the Master branch"*, which you contradict later by saying *"Merge Branch IA-481(Release2)--unwanted files present"*. – tom May 04 '13 at 01:56
  • Tom. I appreciate your feedback and you bring up a good point. My sentence that you quoted above is a little inaccurate. SmartGit was showing me that 1 file was in that commit (maybe the tool only shows the file that had a merge conflict), but when I looked at the history on the Git site, I saw that commit included all the unwanted files. However, my commit IA-481 also includes all the unwanted files as well (but they weren't supposed to be in Master). Does the graph and information I gave you confirm that? Also please read the updated details in the question if you haven't read them yet. – John May 04 '13 at 03:09
  • Yes, the information you gave confirms that the changes made their way to Master because of the commit "Merge Branch IA-481(Release2)". If you have to argue this point you should quote the SHA-1 checksums for commit "Merge Branch IA-481(Release2)" and the commit below it (IA-1617), the parent on the Master branch's side. – tom May 04 '13 at 03:54
  • I think we're almost there and I'm ready to make my argument, but there is one last piece of the puzzle. While the Github history does not show that I checked the files in Master, it also does not show that the other party, Frank, committed the merge to Master either. Rather it shows that he also checked in his Merge to "IA-481(Release2)". In other words, the actual github history does not show that either he or I checked those files into Master. Please see the 3rd image I added to the updated question above. – John May 04 '13 at 19:53
  • GitHub doesn't show branches well. If you click the link to the Merge commit, 6b5f811, it should show the changes with the other party's name as the committer. The first screenshot shows this commit was on branch Master and yours (IA-481) wasn't. It is actually a bit more complicated than that (see [Finding what branch a commit came from](http://stackoverflow.com/q/2706797/952648)), but in your case I think it is obvious that the blue line with all the commits is the Master branch and the grey line with IA-481 is your IA-481(Release2) branch. – tom May 05 '13 at 01:22
  • Following the link you gave me, I did this: `git reflog show --all | grep b6d7e180b1b933cc408bcefeaa15db216bd9d9e` using the SHA ID of my commit and the results looked like this `7b6d7e1 refs/heads/master@{18}: reset: moving to 7b6d7e180b1b933cc408bcefeaa15db216bd9d9e 7b6d7e1 refs/heads/master@{33}: reset: moving to 7b6d7e180b1b933cc408bcefeaa15db216bd9d9e` I guess this means that the original check-in was Master? :( – John May 05 '13 at 02:57
  • No, that's a different commit. Try `git reflog show --all | grep '^\(6b5f811\|7b6d7e1\)' -C3`. Looking carefully at the graph, it is possible that the changes only entered Master in commit "Merge branch 'master' of ...". The script mentioned in the linked question, [git-what-branch](https://github.com/SethRobertson/git-what-branch), might help you work out exactly which commits were on Master. – tom May 05 '13 at 04:22
  • The command you gave me shows me a lot of data with the master as the branch. Regarding that script you recommended. Do I need to install Perl to run it? – John May 05 '13 at 16:53
  • 2
    Your answers have been very helpful. I tried to give some votes to your answer, but I am new to this site and I'm 2 reputation points away from being able to vote. – John May 05 '13 at 22:01
  • Yes, you need to install Perl to run the script, but I wouldn't bother. The important thing is to figure out what each person considers to be the Master branch. You don't consider IA-481 to be on Master. If the third party considers "Merge branch IA-481(Release2)" to be on Master, that's the place things went wrong. Otherwise it was probably "Merge branch 'master' of ...". If there is disagreement, that's where you can use the reflog to see where Master was on each host. – tom May 06 '13 at 10:21
  • I am not sure the `--all` option to `git reflog show` does what it seems. You may get more information if you use `git reflog show master` and `git reflog show 'IA-481(Release2)'`. Also, the option `--date=local` will display the dates and help narrow down the relevant ref changes. – tom May 07 '13 at 11:22
  • I would try to stick to the simple facts: the merge commit "Merge branch 'IA-481(Release2)'..." was made by the third party and the commit message (which is almost certainly the automatically generated one) shows the undesirable changes were brought in from your 'IA-481(Release2)' branch, and were not already on Master. – tom May 07 '13 at 11:23
0

The graphs are rather simple to interpret. Different commits are dots so if you just change something and make a commit you get another little dot connected to the previous commit.

If you branch you can get multiple dots connected to the previous commit.

If you merge multiple previous commits will connect to your new dot.

So IA-481 was a commit on a different branch than master (but it is sorted chronologically so that's why it is displayed between IA-1617 and IA-1617 which were commits on master) and it is merged into the master branch at your second highlight from the bottom.

Your last highlighted point is another merge but this time with a remote branch.

Anything still unclear?

Sarien
  • 5,956
  • 5
  • 32
  • 46
  • What is unclear is why IA-481 got to Master. I checked that into a branch, but I'm being blamed for it making into Master. So was it my fault, or the fault of the one who checked in "Merge branch IA-481(Release2)"? All the unwanted files for IA-481 appear under the IA-481 commit, not the "Merge branch IA-481(Release2)" commit. And since this is the graph for the Master branch, it appears that it was the fault of the one (me) who checked in the IA-481 commit that these files made it to Master. Was it really my fault? See additional graph(s). – John May 03 '13 at 10:32
  • Well, then yes it got there because of that merge commit which you highlighted and it was either (1) your fault for checking it into a branch that will end up in master (2) the fault of the person who merged (for merging a branch that should not have been merged into master) (3) an error in your process :) – Sarien May 03 '13 at 11:17
  • What I checked in was supposed to be checked in to a branch, not Master (not yet at least), and as far as I remember, I checked into a branch, not master. Does the graph confirm that? – John May 03 '13 at 11:20
  • As far as I know you need to explicitly call git merge to merge two branches. But I don't know of course if you maybe have some sort of tool that might have done it for you. There should however be some name associated with that merge commit. – Sarien May 03 '13 at 12:27
  • So here is a little more detail. I originally checked in my files in a branch called "IA-481(Release)". I then did call merge from the Master Branch to merge those files with Master because I was going to merge to Master, but realized it was too soon so I didn't commit to master the merged files. I am certain of this. Instead, I created and switched to another new branch called "IA-481(Release2) and I committed the merged files to that second branch. – John May 03 '13 at 14:59
  • 1
    _> I checked into a branch, not master. Does the graph confirm that?_ It neither confirms that nor the opposite. You need to know who was the committer of the first commit that brought the unwanted files into master. I don't know the graphic tool you use, but on the command line `git cat-file commit ` will show you the raw information. But note: the committer info is configurable by the user, if somebody wants to fake it, git doesn't care. Also branches can be renamed. So what was branch foo yesterday could be branch master now. These issues can be prevented/made traceable by signing. – Uwe Geuder May 03 '13 at 17:46
  • I committed the files in IA-481 which had all the files that should not go into Master, but I committed into a branch called "IA-481(Release2) not into Master. That's the whole question. How those files got into Master. – John May 04 '13 at 02:59
  • and the other question is how to prove that I didn't actually commit IA-481 into Master. The fact that IA-481 is on a gray line parallel to the blue Master branch is not enough to prove it was on a different branch? – John May 05 '13 at 22:06
  • It's not really enough. All these lines do is show which commits certain commits consider to be their parents. Commits are entire snapshots. It's not necessary for them to have parents, really. Each is complete in and of itself. It's improbable anyone would be mucking about at a lower level, moving things around, but it's possible. The trust and verification comes from multiple people working with a repo. I've done things in my own repos like manually create my own commits in a text editor (they're just text files), hash them into the object store, then point existing branches to them. – Gary Fixler May 07 '13 at 08:00
  • So, for example, you can swap branch names easily: `git tag oldmaster master; git checkout dev; git branch -f master dev; git checkout master; git branch -f dev oldmaster; git tag -d oldmaster` - that just swapped the master and dev branch names. All branches are are text files named for a branch with a SHA-1 in them. To *really* prove things, you'd have to compare your repo against at least one other, trusted repo. Again, that anyone would have done this is pretty unlikely. I'm just talking about absolute proof. You really can't say that two separate lines in the history graph is proof. – Gary Fixler May 07 '13 at 08:13
  • As a further example of why, I started working on a branch for a new project for my company. I realized I was randomly making two different kinds of commits - very project-specific ones full of NDA-covered project things, and much more generic, tools stuff. I was the only one on this so far - it hadn't been pushed elsewhere - so I just tagged the branch head, did an interactive rebase, and deleted all the tool-specific stuff, creating a new branch of just project commits. I then created a new tools branch at the original, pre-rebase branch, and did the inverse, leaving just tools commits. – Gary Fixler May 07 '13 at 08:18
  • That said, and with a further reminder that things are a bit liquid in git (which accounts for much of its power), you can checkout master and try this: `git log --diff-filter=A -- filename` to see when that filename was added to master. That will give you a log output of the commit where `filename` was added to the master branch, at least by the current, understood history of master. Of course, that will also show author. To see committer as well, which would show if someone else rebased or cherry-picked your commit to master, use `git log --diff-filter=A --format=fuller -- filename`. – Gary Fixler May 07 '13 at 09:04
0

The other answers seem long winded.

Merging from another branch brings in the changes from that branch. You seem to be think you have to merge, then commit the merge. This is incorrect - the merge itself is a commit that introduces the changes from the other branch.

Edit: @tom is correct. If there are merge conflicts, you have to actively commit the merge after marking the conflicts as resolved.

eddiemoya
  • 5,260
  • 1
  • 19
  • 31
  • This is news to me. I am under the impression that you have to commit the merge. So what is the point of the commit after the merge??? – John May 04 '13 at 02:03
  • @John If there are no conflicts the merge creates a commit. If there are conflicts you have to resolve them and then commit manually. – tom May 04 '13 at 05:03
  • I am not sure which tool you use, but with SmartGit, the merged files only get committed if you actively call commit regardless of whether or not there was a conflict. – John May 04 '13 at 19:29
  • @John I refer to `git merge`. – tom May 04 '13 at 23:03
  • @John - I dont use any special tool. I am explaining what git does natively, bu default. Its worth mentioning though that regardless of your tool, the merge commit *is* the merge. If you don't commit it, it never happened, conversely if theres a merge commit, thats when the merged changes where introduced. – eddiemoya May 06 '13 at 07:23
0

Did you try what @gary mentioned? I felt as there were many comments you might have missed it, but this should help based on your question and comments.

Link to git log: git log manpage

--diff-filter=[(A|C|D|M|R|T|U|X|B)…[*]] 
Select only files that are Added (A), Copied (C), Deleted (D), Modified (M), Renamed (R), have   their type (i.e. regular file,
symlink, submodule, …) changed (T), are Unmerged (U), are Unknown   (X), or have had their pairing Broken (B). Any combination 
of the filter characters (including none)   can be used. When * (All-or-none) is added to the combination, all paths are 
selected if   there is any file that matches other criteria in the comparison; if there is no file that matches   other 
criteria, nothing is selected. 

So this command will tell you the commit where newAddedFile.c file was added

git log --diff-filter=A -- newAddedFile.c

functionoid
  • 1,822
  • 1
  • 13
  • 14