I've never gotten the hang of git, and I only work on programming off and on, so I forget the status of my projects. At the moment I'm not making sense of what git is telling me about old branches.
git branch -a
says:
dashboard
* master
php7
remotes/origin/HEAD -> origin/master
remotes/origin/master
remotes/origin/php7
So it says I have two branches besides master: dashboard
and php7
. I remember php7
clearly - it was a big chunk of work with many commits. I don't remember dashboard
, but the name tells me what file it was related to.
git branch --merged
says:
dashboard
* master
php7
So apparently both are merged. But php7
is known on remote while dashboard
is not. I don't remember what git commands I did to get to this point.
When I look at the log in PHPStorm (or with git log --graph
) those two don't look like what I would expect a branch to look like - there is no diverted line with commits on it. Here is the most recent section of the log:
Mysteries (at least to me):
php7
branch are all on the same orange line as master
. If I merged and then deleted the branch (logical), why is it still listed as a branch at all?php7
branch? I would think recent pushes would cause remote to look just like local, with only one "origin" label on the latest commit. Surely remote doesn't consider php7
to be not-yet-merged - that would be horrible, as that code is critical.dashboard
is not known by remote at all (https://github.com/OsakaWebbie/kizunadb) - how could that be?On the other hand, earlier in the log there is a very obvious branch that had two commits and then was merged, which is not in the list of branches:
I would be happy to delete it (I don't keep old branches for nostalgia), but git branch -d texlabels
says: error: branch 'texlabels' not found.
The most branchy-looking thing in the log isn't a branch? My head hurts.
I'm sure you git gurus will immediately know what this all means and how to clean it up - I look forward to clarity.
Thanks to Kata for a thorough answer (very likely to be accepted). But I have a few followup questions that would be hard to read in a tiny comment (I wish comments could be longer and have more formatting), so bear with me a little longer. I guess they can be answered either by a comment or by Kata adding to his answer - whatever works.
Because it is not sure that in the past
php7
was merged into master.
If it's not sure that php7
was merged, why is it listed in --merged
? (The thought of git being "unsure" about anything worries me...) I have no idea how to move a branch head later, so that scenario is unlikely. However, there was a time when I did something locally that caused Github to refuse pushes (I think I might have amended files to an already-pushed commit) - someone else helped me look it over, and I ended up doing push -f
(I'm the only developer). Perhaps that caused a pointer to get out of place...
Anyway, I know the php7
code is part of my current codebase, because it is happily running on PHP7 now. And I recognize several of the commits as having been done on that branch. In fact, it's possible that all the commits from the time I created php7
until I merged it (46 commits) were done on that branch (i.e. no flipping back to master to fix bugs in the meantime). Would that explain why there is no extra line in the DAG beside the master line?
If so, then perhaps texlabels
is the only branch I ever interrupted to fix a bug on master, since it's the only extra line in the DAG. Also, no other branch has an entry for "Merge branch 'so-and-so'" - is it because without any master commits, merge doesn't need to change any content (just move pointers)?
Because
dashboard
was created locally and has never pushed to remote.
Oh, I didn't realize that a basic push doesn't include branch information. Apparently Github knows about php7
because I no doubt did pushes while it was checked out. (Is that right?)
I've also now learned about tags, and I created a tag at the point I deployed my project on a new server with PHP7 and other differences. I would be happy to not have the php7
or dashboard
branches anymore, as long as my current codebase stays my current codebase. But if you're saying that there is some uncertainty about their merge status, is it safe to delete them? (Deleting things sounds scary, but if it's merely a pointer...)
After Kata mentioned that without --all
I might not be seeing everything, I did a diff between with/without that flag. I discovered that at the very beginning of my php7
work, the first four commits were repeated, first on a "branchy-looking" branch (only seen in --all
), and then on the main line with everything else. Here is the relevant snippet from git log --graph --decorate --all --oneline
:
* 3b1c25a Removal of .html files (won't work with the new server config) and $client in db connect file
* dccc3f3 minor edits
* 20a1aab remove .idea files from repo
* 629d891 Second day of cleanup for PHP7: various things, hacking away at errors one at a time (note: I
* a669fa0 First day of cleanup for PHP7: * mysql_ to mysqli_ (major functions, anyway) * convert my
| * 51738d1 (refs/original/refs/heads/php7) minor edits
| * f1aa0f9 remove .idea files from repo
| * 38aef9b (refs/original/refs/remotes/origin/php7) Second day of cleanup for PHP7: various things, ha
| * cfcaa51 First day of cleanup for PHP7: * mysql_ to mysqli_ (major functions, anyway) * convert
|/
* 294ef21 Feature: batch category delete
I'm guessing that the weirdness was somehow caused by me accidentally using the command line on my VM to do two of the four ("remove .idea..." & "minor edits") instead of OsakaWebbie like the rest of them. (The user doesn't show in --oneline
, but you can see that on Github.) But no matter how it happened, I'm assuming the first set (cfcaa51 thru 51738d1) will go away when I delete the branch, but since they are repeated (and I know my current codebase reflects the changes in those commits), it should be okay, right?
You're better to think branches as heads (or pointers). What git log
shows you is a DAG of the commits and a list of heads pointing to particular commits. What you can see at the current moment is something like: the php7
head is pointing to this commit. You cannot know in the past how the php7
head was moving since git
allows us to move heads in a free manner.
Regarding git branch --merged [<commit>]
, look into its document, the command simply shows all the heads that can be reached from the <commit>
. In your case, the <commit>
is HEAD
which means master
. So the result is obvious: dashboard
, master
, and php7
are reachable from HEAD
. Notice that by default git branch
does not show remote heads, add -a
option for that.
Now I think your questions could be answered.
Commits I remember doing on the php7 branch are all on the same orange line as master. If I merged and then deleted the branch (logical), why is it still listed as a branch at all?
Because it is not sure that in the past php7
was merged into master
. Even if it was, it could be always that at some point later the php7
head was moved, so we cannot see the vestige of the merge caused by php7
.
Why is there an extra "origin" label on the last of the php7 branch? I would think recent pushes would cause remote to look just like local, with only one "origin" label on the latest commit. Surely remote doesn't consider php7 to be not-yet-merged - that would be horrible, as that code is critical.
That label simply means that currently there are 2 heads -- php7
and origin/php7
-- pointing to that commit.
dashboard is not known by remote at all (https://github.com/OsakaWebbie/kizunadb) - how could that be?
Because dashboard
was created locally and has never been pushed to remote.
I would be happy to delete it (I don't keep old branches for nostalgia), but git branch -d texlabels says: error: branch 'texlabels' not found. The most branchy-looking thing in the log isn't a branch? My head hurts.
You know the existing of the texlabels
head just because you see its name in the commit message. But actually that head was deleted in the past thus at the moment you cannot delete it again.
To answer some more concerns of @OsakaWebbie
The --merged
option is named based on the fact that, in normal development (i.e., you don't abnormally move heads, with git reset
for example), if a head child
can reach to a head parent
, it means that parent
was merged into child
at some point in the past. In other words, child
does inherit parent
.
----------------------- child
/
/
parent
But I empathise with you about this, actually there are complaints about the naming of git
commands and their options.
Back to the story of your php7
head, I think the situation should be clear now.
A merge does not necessarily cause two paths joining into one. Indeed, as you told, since you switched to php7
and appended 46 commits to it, you hadn't appended any commit to master
, so the history before the merge looks like this:
----------------- master
\
----------------- php7
Then you switched back to master
and made the merge: git merge php7
. Because php7
is a child of master
, the result of the merge should be exactly php7
. Thus, git
will simply move master
forward and point it to the commit being pointed by php7
. This kind of merge is called fast-forward. Then you have:
-------------------
\
----------------- php7, master
which essentially is:
-------------------------------------- php7, master
But fast-forward did not happen with the merge of texlabels
head. You created the head, switched to it, coded something and appended some commits. Then you switched back to master
, also coded something and appended some commits. So you have:
----------------- master
\
----------- texlabels
As you see texlabels
is not a child of master
. Hence this cannot be a fast-forward, merging texlabels
into master
will cause:
----------------- (old master) -- master
\ /
----------- texlabels
That's why it is the only branchy-looking thing in the history.
Regarding your two last concerns:
Oh, I didn't realize that a basic push doesn't include branch information. Apparently Github knows about php7 because I no doubt did pushes while it was checked out. (Is that right?)
git push <remote> [<head>]
only pushes the provided <head>
(and its ancestor commits of course). If <head>
is not provided, then the head that is being pointed by HEAD
will be used -- it is php7
in your case. To push all the heads, use --all
option.
But if you're saying that there is some uncertainty about their merge status, is it safe to delete them? (Deleting things sounds scary, but if it's merely a pointer...)
Yes, heads are merely pointers, but please be careful: after deleting a head, some commits may be abandoned -- i.e., they cannot be reached from any head -- and will be cleaned (deleted) by the GC
of git
. If you are sure about what you are deleting, go ahead.
Some more notes:
push -f
is not related here, it causes unexpected things in the remote (e.g., losing some commits), not in the local.git log
shows only the commits that can be reached from HEAD
, use --all
option to show all commits.About the 4 extra commits
It's very likely that at the commit 51738d1 minor edits
you issued a git filter-branch
command to massively modify something about those 4 commits (modify author names -- I guess). Then you had 4 new commits created (from a669fa0 to 3b1c25a). The 4 old commits (from cfcaa51 to 51738d1) are still there because they are still reachable from the heads refs/original/...
. These heads were created by the backing-up mechanism of git filter-branch
.
You are totally safe to delete those 4 extra commits. They are completely unrelated to the 4 "main" commits.