Why can't I merge my git dev branch to master even though master only contains an empty README?Undoing a git rebaseGit refusing to merge unrelated histories. What is 'unrelated histories'?How can I know if a branch has been already merged into master?Git for beginners: The definitive practical guideHow to selectively merge or pick changes from another branch in Git?Git workflow and rebase vs merge questionsGit merge reports “Already up-to-date” though there is a differenceMake the current Git branch a master branchHow to replace master branch in Git, entirely, from another branch?What is the best (and safest) way to merge a Git branch into master?How can I delete all Git branches which have been merged?Git merge master into feature branch
Why did Old English lose both thorn and eth?
Delete elements less than the last largest element
What does the multimeter dial do internally?
Why do people prefer metropolitan areas, considering monsters and villains?
How to "add vert" in blender 2.8?
Is there a formal/better word than "skyrocket" for the given context?
Did depressed people far more accurately estimate how many monsters they killed in a video game?
Gory anime with pink haired girl escaping an asylum
Can a landlord force all residents to use the landlord's in-house debit card accounts?
Find out what encryptor name my database is using
What do you call a situation where you have choices but no good choice?
Can the word "desk" be used as a verb?
What term do you use for someone who acts impulsively?
When do flights get cancelled due to fog?
Is this really the Saturn V computer only, or are there other systems here as well?
Clarinets in the Rite of Spring
Draw a diagram with rectangles
I'm feeling like my character doesn't fit the campaign
Moving millions of files to a different directory with specfic name patterns
Users forgotting to regenerate PDF before sending it
How do I talk to my wife about unrealistic expectations?
Intern not wearing safety equipment; how could I have handled this differently?
How do I separate enchants from items?
What is the meaning of "prairie-dog" in this sentence?
Why can't I merge my git dev branch to master even though master only contains an empty README?
Undoing a git rebaseGit refusing to merge unrelated histories. What is 'unrelated histories'?How can I know if a branch has been already merged into master?Git for beginners: The definitive practical guideHow to selectively merge or pick changes from another branch in Git?Git workflow and rebase vs merge questionsGit merge reports “Already up-to-date” though there is a differenceMake the current Git branch a master branchHow to replace master branch in Git, entirely, from another branch?What is the best (and safest) way to merge a Git branch into master?How can I delete all Git branches which have been merged?Git merge master into feature branch
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty margin-bottom:0;
I'm at the end of building my app that has been developed on my dev
branch and would like to now add it to master
for production.
However, when I checkout to master
and run git merge dev
I receive a fatal error of refusing to merge unrelated histories
. Unfortunately, git pull origin master --allow-unrelated-histories
didn't help resolve the error.
This is the status of master
:
git status
shows that my "branch is up to date with 'origin/master'".- The only file in the repo is an empty
README.md
. - GitLab has labelled this a "stale" branch.
- It is a protected branch.
Help me understand why am I not able to merge.
EDIT: I should also mention that git log
produces the following:
commit ac22443836aeaf8abe38aa3761970a4cd3835587 (HEAD -> master, origin/master)
Author: // my info
Date: Fri Dec 21 03:25:26 2018 -0700
Initial commit
(END)
git gitlab
add a comment |
I'm at the end of building my app that has been developed on my dev
branch and would like to now add it to master
for production.
However, when I checkout to master
and run git merge dev
I receive a fatal error of refusing to merge unrelated histories
. Unfortunately, git pull origin master --allow-unrelated-histories
didn't help resolve the error.
This is the status of master
:
git status
shows that my "branch is up to date with 'origin/master'".- The only file in the repo is an empty
README.md
. - GitLab has labelled this a "stale" branch.
- It is a protected branch.
Help me understand why am I not able to merge.
EDIT: I should also mention that git log
produces the following:
commit ac22443836aeaf8abe38aa3761970a4cd3835587 (HEAD -> master, origin/master)
Author: // my info
Date: Fri Dec 21 03:25:26 2018 -0700
Initial commit
(END)
git gitlab
Doesmaster
anddev
have a common ancestor (I mean a common commit parent) ?
– Jona
Mar 25 at 22:50
I went through and it actually didn't seem to share a common ancestor and that may be the crux of the issue. But it looks like a solution that was posted (but then deleted by another user...not sure why) did the trick. Basically,git merge dev --allow-unrelated-histories
.
– Mix Master Mike
Mar 25 at 23:16
How did you set up your local dev environment? Did you clone the repo you want to merge with, and thengit checkout -b dev
to create your dev branch?
– Joe McMahon
Mar 25 at 23:20
@JoeMcMahon that's what I thought I did as that's my modus operandi. But for whatever reason as I went back through my logs, I didn't seedev
branch off ofmaster
or share the same commit ID asmaster
. So this makes me wonder. Even though this was done 3 months ago, it seems like ages. And with the fix I described abovemaster
isahead of 'origin/master' by 720 commits.
– Mix Master Mike
Mar 25 at 23:26
add a comment |
I'm at the end of building my app that has been developed on my dev
branch and would like to now add it to master
for production.
However, when I checkout to master
and run git merge dev
I receive a fatal error of refusing to merge unrelated histories
. Unfortunately, git pull origin master --allow-unrelated-histories
didn't help resolve the error.
This is the status of master
:
git status
shows that my "branch is up to date with 'origin/master'".- The only file in the repo is an empty
README.md
. - GitLab has labelled this a "stale" branch.
- It is a protected branch.
Help me understand why am I not able to merge.
EDIT: I should also mention that git log
produces the following:
commit ac22443836aeaf8abe38aa3761970a4cd3835587 (HEAD -> master, origin/master)
Author: // my info
Date: Fri Dec 21 03:25:26 2018 -0700
Initial commit
(END)
git gitlab
I'm at the end of building my app that has been developed on my dev
branch and would like to now add it to master
for production.
However, when I checkout to master
and run git merge dev
I receive a fatal error of refusing to merge unrelated histories
. Unfortunately, git pull origin master --allow-unrelated-histories
didn't help resolve the error.
This is the status of master
:
git status
shows that my "branch is up to date with 'origin/master'".- The only file in the repo is an empty
README.md
. - GitLab has labelled this a "stale" branch.
- It is a protected branch.
Help me understand why am I not able to merge.
EDIT: I should also mention that git log
produces the following:
commit ac22443836aeaf8abe38aa3761970a4cd3835587 (HEAD -> master, origin/master)
Author: // my info
Date: Fri Dec 21 03:25:26 2018 -0700
Initial commit
(END)
git gitlab
git gitlab
edited Mar 25 at 23:14
Joe McMahon
2,57315 silver badges28 bronze badges
2,57315 silver badges28 bronze badges
asked Mar 25 at 22:33
Mix Master MikeMix Master Mike
1622 silver badges15 bronze badges
1622 silver badges15 bronze badges
Doesmaster
anddev
have a common ancestor (I mean a common commit parent) ?
– Jona
Mar 25 at 22:50
I went through and it actually didn't seem to share a common ancestor and that may be the crux of the issue. But it looks like a solution that was posted (but then deleted by another user...not sure why) did the trick. Basically,git merge dev --allow-unrelated-histories
.
– Mix Master Mike
Mar 25 at 23:16
How did you set up your local dev environment? Did you clone the repo you want to merge with, and thengit checkout -b dev
to create your dev branch?
– Joe McMahon
Mar 25 at 23:20
@JoeMcMahon that's what I thought I did as that's my modus operandi. But for whatever reason as I went back through my logs, I didn't seedev
branch off ofmaster
or share the same commit ID asmaster
. So this makes me wonder. Even though this was done 3 months ago, it seems like ages. And with the fix I described abovemaster
isahead of 'origin/master' by 720 commits.
– Mix Master Mike
Mar 25 at 23:26
add a comment |
Doesmaster
anddev
have a common ancestor (I mean a common commit parent) ?
– Jona
Mar 25 at 22:50
I went through and it actually didn't seem to share a common ancestor and that may be the crux of the issue. But it looks like a solution that was posted (but then deleted by another user...not sure why) did the trick. Basically,git merge dev --allow-unrelated-histories
.
– Mix Master Mike
Mar 25 at 23:16
How did you set up your local dev environment? Did you clone the repo you want to merge with, and thengit checkout -b dev
to create your dev branch?
– Joe McMahon
Mar 25 at 23:20
@JoeMcMahon that's what I thought I did as that's my modus operandi. But for whatever reason as I went back through my logs, I didn't seedev
branch off ofmaster
or share the same commit ID asmaster
. So this makes me wonder. Even though this was done 3 months ago, it seems like ages. And with the fix I described abovemaster
isahead of 'origin/master' by 720 commits.
– Mix Master Mike
Mar 25 at 23:26
Does
master
and dev
have a common ancestor (I mean a common commit parent) ?– Jona
Mar 25 at 22:50
Does
master
and dev
have a common ancestor (I mean a common commit parent) ?– Jona
Mar 25 at 22:50
I went through and it actually didn't seem to share a common ancestor and that may be the crux of the issue. But it looks like a solution that was posted (but then deleted by another user...not sure why) did the trick. Basically,
git merge dev --allow-unrelated-histories
.– Mix Master Mike
Mar 25 at 23:16
I went through and it actually didn't seem to share a common ancestor and that may be the crux of the issue. But it looks like a solution that was posted (but then deleted by another user...not sure why) did the trick. Basically,
git merge dev --allow-unrelated-histories
.– Mix Master Mike
Mar 25 at 23:16
How did you set up your local dev environment? Did you clone the repo you want to merge with, and then
git checkout -b dev
to create your dev branch?– Joe McMahon
Mar 25 at 23:20
How did you set up your local dev environment? Did you clone the repo you want to merge with, and then
git checkout -b dev
to create your dev branch?– Joe McMahon
Mar 25 at 23:20
@JoeMcMahon that's what I thought I did as that's my modus operandi. But for whatever reason as I went back through my logs, I didn't see
dev
branch off of master
or share the same commit ID as master
. So this makes me wonder. Even though this was done 3 months ago, it seems like ages. And with the fix I described above master
is ahead of 'origin/master' by 720 commits.
– Mix Master Mike
Mar 25 at 23:26
@JoeMcMahon that's what I thought I did as that's my modus operandi. But for whatever reason as I went back through my logs, I didn't see
dev
branch off of master
or share the same commit ID as master
. So this makes me wonder. Even though this was done 3 months ago, it seems like ages. And with the fix I described above master
is ahead of 'origin/master' by 720 commits.
– Mix Master Mike
Mar 25 at 23:26
add a comment |
4 Answers
4
active
oldest
votes
If --allow-unrelated-hhistories
was necessary, that means you actually had the equivalent of two different repositories that you merged together.
I suspect this happened because you didn't clone
the original repo first before creating your dev branch and doing work. My deduction from your description is that you did a git init
, checked out a dev
branch, and then added the remote repo as origin
when you wanted to merge (this worked because your local repo had no remotes).
Attempting to merge at that point would get the 'unrelated histories' because the two repos are, in fact not related; the original was created and pushed to GitLab, and a completely separate one was created when you did your git init
to create the local. Cloning the original would create a local repository that was related, because it shared that initial README
commit.
This is, indeed, the only way to fix this issue, and as soon as you push to GitLab, the local and the remote will be in sync -- but you should always clone to avoid the problem in the first place.
Were you the one that suggested runninggit merge dev --allow-unrelated-histories
? Someone did then deleted this solution. But it worked. I want to give credit where credit is due.
– Mix Master Mike
Mar 25 at 23:29
Wasn't me, sorry -- but that was the right answer for this situation. I've used it when creating a mono-repo out of multiple repos, so it's not inherently a bad thing. It's just that, as you say, clone-branch-commit-merge/rebase is better.
– Joe McMahon
Mar 25 at 23:31
much thanks for shedding light on my blunder.
– Mix Master Mike
Mar 25 at 23:36
add a comment |
If, like it was said, master
and dev
doesn't have a common (parent) commit, I would try to create new branch from master
and cherry-pick all commits from dev
into it:git cherry-pick startHash^..endHash
For example git cherry-pick 1234^..5678
.
Then you should be able to merge this new branch into master
add a comment |
You probably checked "[ ] Create repository with a README" when you created the repository.
When master
is really empty, I see the following options
go to gitlab, change the default branch to something else and remove the master branch in the web interface (there, it is possible to delete protected branches). Or,
unprotect
master
Now you can force-push your dev
Branch to gitlab (e.g. git push -f dev:master
).
NOTE: this option is a no-go for branches resp. repositories which are used by other peoples. In this case do:
git fetch gitlab master
git merge -s ours FETCH_HEAD
and push this branch.
For clarification isgit fetch gitlab master
andgit merge -s ours FETCH_HEAD
is executed from mymaster
branch, correct?
– Mix Master Mike
Mar 25 at 23:50
git fetch
can be executed everywhere (even in bare repositories). Forgit merge
you have to checkout the branch which shall becomemaster
.
– ensc
Mar 25 at 23:54
add a comment |
You already fixed (?) this using --allow-unrelated-histories
and there's no real reason not to just leave that. But in case you are still wondering...
What happened, and how you (probably) got here
The first key to using Git is to understand that Git is all about commits. Of course, this also requires that you understand, in a reasonably deep sort of way, what a commit is. What it is, is pretty short and simple: it's a permanent (mostly) and immutable (entirely) snapshot plus some metadata. The snapshot contains all of your files—well, all of them as of the time you made the commit—and the metadata has:
- your name and email address, and the time you made the commit;
- your log message, i.e., why you made this commit; and, crucially,
- the hash ID of the commit that comes just before this commit, defined as the parent of this commit.
Every commit is unique—for many reasons, including the time-stamp mentioned above—and every unique commit gets a unique hash ID. That hash ID, some big ugly string of hexadecimal characters, seems random, but is actually a cryptographic checksum of the contents of the commit. It's also the True Name, as it were, of that commit: that ID means that commit, and only that commit. No other commit will ever have that hash ID. That hash ID will always mean that commit.
Git actually finds the commit by hash ID. So the hash ID is crucial. Of course, it's also impossible for humans to remember. So Git gives us a way to remember the latest hash ID, and that way is a branch name like master
or dev
.
The name only has to remember the last commit because each commit remembers its parent's hash on its own. That is, given a tiny repository with just three commits, where we replace the actual hash IDs with a single uppercase letter, we can draw this:
A <-B <-C <-- master
The name master
remembers the hash ID of C
. C
itself—the actual commit, retrieved by hash ID—remembers the hash ID of B
, and B
itself remembers the hash ID of A
.
When something remembers the hash ID of some other commit, we say that this something points to the commit. So the name master
points to C
, C
points to B
, and B
points to A
. Those three commits—C
, then B
, then A
—are the history in the repository.
Note that A
doesn't point anywhere. It literally can't, because it was the first commit. There was no earlier commit. So it just doesn't, and Git calls this a root commit. All non-empty repositories have to have at least one root commit. Most, probably, have exactly one ... but yours has two.
Normal branching and merging
Let's take a quick look at the more normal way to make branches. Suppose we have just these three commits, pointed-to by master
. We ask Git to make a new branch name, pointing to the same commit as master
:
A--B--C <-- dev (HEAD), master
Both names identify commit C
, so commit C
is on—and is the tip commit of—both branches, and all three commits are on both branches. But now we make a new commit. The process of making a new commit—with the usual edit and git add
and git commit
—makes a new snapshot, adds our name and email and timestamp and so on, uses the current commit C
as the saved hash, and builds the new commit. The new commit gets some big ugly hash ID, but we'll just call it D
:
A--B--C <-- dev (HEAD), master
D
Since D
's parent is C
, D
points back to C
. But now the magic happens: Git writes D
's hash ID into the current branch name—the one HEAD
is attached to—so now we have:
A--B--C <-- master
D <-- dev (HEAD)
and voila, we have a new branch. (Well, we had it before, pointing to C
. Most people don't like to think about it that way though, they want to call D
the branch. In fact, the branch is D-C-B-A
!)
Over time we add some commits to both branches:
A--B--C-----J----K----L <-- master
D--E--F--G--H--I <-- dev
We git checkout master
and git merge dev
. Git will find the merge base commit for us, where dev
and master
diverged. That's obviously commit C
since that's where the two branches rejoin in the past. Git will compare C
vs L
to see what we changed on master
, compare C
vs I
to see what we changed on dev
, and combine the changes. Git applies the combined changes to the snapshot in C
—to the merge base—and makes a new merge commit M
, which goes on our current HEAD
branch as usual, updating that branch name so that master
points to M
:
A--B--C-----J----K----L--M <-- master (HEAD)
/
D--E--F--G--H--I <-- dev
What's special about M
is that it has two backwards links: it goes back to L
, as all commits would, but it has a second parent I
, which is the current tip commit of branch dev
. Other than the two parents, though, it's quite ordinary: it has a snapshot as usual, and our name and email and timestamp and a log message.
Abnormal branching
There's nothing in Git that stops you from making extra root commits. It's just a little bit tricky. Suppose that, somehow, you did this:
A <-- master
B--C--D--...--L <-- dev (HEAD)
Once you have this situation, git checkout master; git merge dev
just gives you an error. That's because the usual method of finding a merge base—starting at the two branch tips and working backwards—never finds a common commit.
Adding --allow-unrelated-histories
tells Git to pretend that there's a special empty commit before both branches:
A <-- master (HEAD)
0
B--C--D--...--L <-- dev
Now Git can diff 0
vs A
to see what you changed on master
, and 0
vs L
to see what they changed on dev
. On master
, you added every file. On dev
, you also added every file. As long as those are different files, the way to combine those two changes is to add the master
files from commit A
to the dev
files from commit L
, apply those changes to the empty null commit, and commit the result, with parents going back to both A
and L
:
A---------------M <-- master (HEAD)
/
B--C--D--...--L <-- dev
How you (probably) got here
There's a git checkout
option, git checkout --orphan
, that sets this state up. But that's probably not what you did. The state this sets up is the same state you're in when you create a new, empty repository with git init
:
[no commits] <-- [no branches]
There are no branches, and yet Git will say that you're on branch master
. You can't be on master
: it doesn't exist. But you are, even though it doesn't exist. The way Git manages this is that it puts the name master
into HEAD
(.git/HEAD
, actually) without first creating a branch named master
. It can't create the branch because a branch name has to contain a valid hash ID, and there aren't any.
So, when you run git commit
, Git detects this anomalous state: that HEAD
says master
but master
doesn't exist. That's what triggers Git to make our root commit A
. Then Git writes A
's hash ID into the branch, which creates the branch, and now we have:
A <-- master (HEAD)
which is just what we wanted.
But suppose, while we're in this weird no-commits-yet state, we run:
git checkout -b dev
This tells Git: Put the name dev
into HEAD
. It does that without complaint, even though there's no master
either. Then we make our first commit, but for no obvious reason, we'll pick B
as its one-letter stand-in for its hash ID:
B <-- dev (HEAD)
Meanwhile, having run git init
here, then git checkout -b dev
, then done something and git commit
, we'll go over to $WebHostingProvider—whether that's GitHub or GitLab or Bitbucket or whatever—and use its make me a new repository clicky buttons. Those usually have an option: create an initial commit with README and/or LICENSE files and such. If that option is checked—or the don't option is unchecked—they go ahead and make a first commit and a master
:
A <-- master (HEAD)
Now you connect your repository to theirs and have your Git download any commits they have that you don't:
A <-- origin/master
B <-- dev (HEAD)
You can now proceed to add lots of commits, never noticing that your dev
branch is not related to their master
branch (which your Git is calling origin/master
).
Later, you run:
git checkout master
Your Git notices that you don't have a master
, but that you do have an origin/master
. So your Git creates a master
for you, pointing to the same commit as origin/master
, and attaches your HEAD
to your new master
:
A <-- master (HEAD), origin/master
B--C--D--...--L <-- dev
and voila, you're in the pickle you were in.
add a comment |
Your Answer
StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");
StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "1"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);
else
createEditor();
);
function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);
);
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55347352%2fwhy-cant-i-merge-my-git-dev-branch-to-master-even-though-master-only-contains-a%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
4 Answers
4
active
oldest
votes
4 Answers
4
active
oldest
votes
active
oldest
votes
active
oldest
votes
If --allow-unrelated-hhistories
was necessary, that means you actually had the equivalent of two different repositories that you merged together.
I suspect this happened because you didn't clone
the original repo first before creating your dev branch and doing work. My deduction from your description is that you did a git init
, checked out a dev
branch, and then added the remote repo as origin
when you wanted to merge (this worked because your local repo had no remotes).
Attempting to merge at that point would get the 'unrelated histories' because the two repos are, in fact not related; the original was created and pushed to GitLab, and a completely separate one was created when you did your git init
to create the local. Cloning the original would create a local repository that was related, because it shared that initial README
commit.
This is, indeed, the only way to fix this issue, and as soon as you push to GitLab, the local and the remote will be in sync -- but you should always clone to avoid the problem in the first place.
Were you the one that suggested runninggit merge dev --allow-unrelated-histories
? Someone did then deleted this solution. But it worked. I want to give credit where credit is due.
– Mix Master Mike
Mar 25 at 23:29
Wasn't me, sorry -- but that was the right answer for this situation. I've used it when creating a mono-repo out of multiple repos, so it's not inherently a bad thing. It's just that, as you say, clone-branch-commit-merge/rebase is better.
– Joe McMahon
Mar 25 at 23:31
much thanks for shedding light on my blunder.
– Mix Master Mike
Mar 25 at 23:36
add a comment |
If --allow-unrelated-hhistories
was necessary, that means you actually had the equivalent of two different repositories that you merged together.
I suspect this happened because you didn't clone
the original repo first before creating your dev branch and doing work. My deduction from your description is that you did a git init
, checked out a dev
branch, and then added the remote repo as origin
when you wanted to merge (this worked because your local repo had no remotes).
Attempting to merge at that point would get the 'unrelated histories' because the two repos are, in fact not related; the original was created and pushed to GitLab, and a completely separate one was created when you did your git init
to create the local. Cloning the original would create a local repository that was related, because it shared that initial README
commit.
This is, indeed, the only way to fix this issue, and as soon as you push to GitLab, the local and the remote will be in sync -- but you should always clone to avoid the problem in the first place.
Were you the one that suggested runninggit merge dev --allow-unrelated-histories
? Someone did then deleted this solution. But it worked. I want to give credit where credit is due.
– Mix Master Mike
Mar 25 at 23:29
Wasn't me, sorry -- but that was the right answer for this situation. I've used it when creating a mono-repo out of multiple repos, so it's not inherently a bad thing. It's just that, as you say, clone-branch-commit-merge/rebase is better.
– Joe McMahon
Mar 25 at 23:31
much thanks for shedding light on my blunder.
– Mix Master Mike
Mar 25 at 23:36
add a comment |
If --allow-unrelated-hhistories
was necessary, that means you actually had the equivalent of two different repositories that you merged together.
I suspect this happened because you didn't clone
the original repo first before creating your dev branch and doing work. My deduction from your description is that you did a git init
, checked out a dev
branch, and then added the remote repo as origin
when you wanted to merge (this worked because your local repo had no remotes).
Attempting to merge at that point would get the 'unrelated histories' because the two repos are, in fact not related; the original was created and pushed to GitLab, and a completely separate one was created when you did your git init
to create the local. Cloning the original would create a local repository that was related, because it shared that initial README
commit.
This is, indeed, the only way to fix this issue, and as soon as you push to GitLab, the local and the remote will be in sync -- but you should always clone to avoid the problem in the first place.
If --allow-unrelated-hhistories
was necessary, that means you actually had the equivalent of two different repositories that you merged together.
I suspect this happened because you didn't clone
the original repo first before creating your dev branch and doing work. My deduction from your description is that you did a git init
, checked out a dev
branch, and then added the remote repo as origin
when you wanted to merge (this worked because your local repo had no remotes).
Attempting to merge at that point would get the 'unrelated histories' because the two repos are, in fact not related; the original was created and pushed to GitLab, and a completely separate one was created when you did your git init
to create the local. Cloning the original would create a local repository that was related, because it shared that initial README
commit.
This is, indeed, the only way to fix this issue, and as soon as you push to GitLab, the local and the remote will be in sync -- but you should always clone to avoid the problem in the first place.
answered Mar 25 at 23:27
Joe McMahonJoe McMahon
2,57315 silver badges28 bronze badges
2,57315 silver badges28 bronze badges
Were you the one that suggested runninggit merge dev --allow-unrelated-histories
? Someone did then deleted this solution. But it worked. I want to give credit where credit is due.
– Mix Master Mike
Mar 25 at 23:29
Wasn't me, sorry -- but that was the right answer for this situation. I've used it when creating a mono-repo out of multiple repos, so it's not inherently a bad thing. It's just that, as you say, clone-branch-commit-merge/rebase is better.
– Joe McMahon
Mar 25 at 23:31
much thanks for shedding light on my blunder.
– Mix Master Mike
Mar 25 at 23:36
add a comment |
Were you the one that suggested runninggit merge dev --allow-unrelated-histories
? Someone did then deleted this solution. But it worked. I want to give credit where credit is due.
– Mix Master Mike
Mar 25 at 23:29
Wasn't me, sorry -- but that was the right answer for this situation. I've used it when creating a mono-repo out of multiple repos, so it's not inherently a bad thing. It's just that, as you say, clone-branch-commit-merge/rebase is better.
– Joe McMahon
Mar 25 at 23:31
much thanks for shedding light on my blunder.
– Mix Master Mike
Mar 25 at 23:36
Were you the one that suggested running
git merge dev --allow-unrelated-histories
? Someone did then deleted this solution. But it worked. I want to give credit where credit is due.– Mix Master Mike
Mar 25 at 23:29
Were you the one that suggested running
git merge dev --allow-unrelated-histories
? Someone did then deleted this solution. But it worked. I want to give credit where credit is due.– Mix Master Mike
Mar 25 at 23:29
Wasn't me, sorry -- but that was the right answer for this situation. I've used it when creating a mono-repo out of multiple repos, so it's not inherently a bad thing. It's just that, as you say, clone-branch-commit-merge/rebase is better.
– Joe McMahon
Mar 25 at 23:31
Wasn't me, sorry -- but that was the right answer for this situation. I've used it when creating a mono-repo out of multiple repos, so it's not inherently a bad thing. It's just that, as you say, clone-branch-commit-merge/rebase is better.
– Joe McMahon
Mar 25 at 23:31
much thanks for shedding light on my blunder.
– Mix Master Mike
Mar 25 at 23:36
much thanks for shedding light on my blunder.
– Mix Master Mike
Mar 25 at 23:36
add a comment |
If, like it was said, master
and dev
doesn't have a common (parent) commit, I would try to create new branch from master
and cherry-pick all commits from dev
into it:git cherry-pick startHash^..endHash
For example git cherry-pick 1234^..5678
.
Then you should be able to merge this new branch into master
add a comment |
If, like it was said, master
and dev
doesn't have a common (parent) commit, I would try to create new branch from master
and cherry-pick all commits from dev
into it:git cherry-pick startHash^..endHash
For example git cherry-pick 1234^..5678
.
Then you should be able to merge this new branch into master
add a comment |
If, like it was said, master
and dev
doesn't have a common (parent) commit, I would try to create new branch from master
and cherry-pick all commits from dev
into it:git cherry-pick startHash^..endHash
For example git cherry-pick 1234^..5678
.
Then you should be able to merge this new branch into master
If, like it was said, master
and dev
doesn't have a common (parent) commit, I would try to create new branch from master
and cherry-pick all commits from dev
into it:git cherry-pick startHash^..endHash
For example git cherry-pick 1234^..5678
.
Then you should be able to merge this new branch into master
answered Mar 25 at 23:33
zdolnyzdolny
3216 silver badges13 bronze badges
3216 silver badges13 bronze badges
add a comment |
add a comment |
You probably checked "[ ] Create repository with a README" when you created the repository.
When master
is really empty, I see the following options
go to gitlab, change the default branch to something else and remove the master branch in the web interface (there, it is possible to delete protected branches). Or,
unprotect
master
Now you can force-push your dev
Branch to gitlab (e.g. git push -f dev:master
).
NOTE: this option is a no-go for branches resp. repositories which are used by other peoples. In this case do:
git fetch gitlab master
git merge -s ours FETCH_HEAD
and push this branch.
For clarification isgit fetch gitlab master
andgit merge -s ours FETCH_HEAD
is executed from mymaster
branch, correct?
– Mix Master Mike
Mar 25 at 23:50
git fetch
can be executed everywhere (even in bare repositories). Forgit merge
you have to checkout the branch which shall becomemaster
.
– ensc
Mar 25 at 23:54
add a comment |
You probably checked "[ ] Create repository with a README" when you created the repository.
When master
is really empty, I see the following options
go to gitlab, change the default branch to something else and remove the master branch in the web interface (there, it is possible to delete protected branches). Or,
unprotect
master
Now you can force-push your dev
Branch to gitlab (e.g. git push -f dev:master
).
NOTE: this option is a no-go for branches resp. repositories which are used by other peoples. In this case do:
git fetch gitlab master
git merge -s ours FETCH_HEAD
and push this branch.
For clarification isgit fetch gitlab master
andgit merge -s ours FETCH_HEAD
is executed from mymaster
branch, correct?
– Mix Master Mike
Mar 25 at 23:50
git fetch
can be executed everywhere (even in bare repositories). Forgit merge
you have to checkout the branch which shall becomemaster
.
– ensc
Mar 25 at 23:54
add a comment |
You probably checked "[ ] Create repository with a README" when you created the repository.
When master
is really empty, I see the following options
go to gitlab, change the default branch to something else and remove the master branch in the web interface (there, it is possible to delete protected branches). Or,
unprotect
master
Now you can force-push your dev
Branch to gitlab (e.g. git push -f dev:master
).
NOTE: this option is a no-go for branches resp. repositories which are used by other peoples. In this case do:
git fetch gitlab master
git merge -s ours FETCH_HEAD
and push this branch.
You probably checked "[ ] Create repository with a README" when you created the repository.
When master
is really empty, I see the following options
go to gitlab, change the default branch to something else and remove the master branch in the web interface (there, it is possible to delete protected branches). Or,
unprotect
master
Now you can force-push your dev
Branch to gitlab (e.g. git push -f dev:master
).
NOTE: this option is a no-go for branches resp. repositories which are used by other peoples. In this case do:
git fetch gitlab master
git merge -s ours FETCH_HEAD
and push this branch.
answered Mar 25 at 23:39
enscensc
4,6769 silver badges15 bronze badges
4,6769 silver badges15 bronze badges
For clarification isgit fetch gitlab master
andgit merge -s ours FETCH_HEAD
is executed from mymaster
branch, correct?
– Mix Master Mike
Mar 25 at 23:50
git fetch
can be executed everywhere (even in bare repositories). Forgit merge
you have to checkout the branch which shall becomemaster
.
– ensc
Mar 25 at 23:54
add a comment |
For clarification isgit fetch gitlab master
andgit merge -s ours FETCH_HEAD
is executed from mymaster
branch, correct?
– Mix Master Mike
Mar 25 at 23:50
git fetch
can be executed everywhere (even in bare repositories). Forgit merge
you have to checkout the branch which shall becomemaster
.
– ensc
Mar 25 at 23:54
For clarification is
git fetch gitlab master
and git merge -s ours FETCH_HEAD
is executed from my master
branch, correct?– Mix Master Mike
Mar 25 at 23:50
For clarification is
git fetch gitlab master
and git merge -s ours FETCH_HEAD
is executed from my master
branch, correct?– Mix Master Mike
Mar 25 at 23:50
git fetch
can be executed everywhere (even in bare repositories). For git merge
you have to checkout the branch which shall become master
.– ensc
Mar 25 at 23:54
git fetch
can be executed everywhere (even in bare repositories). For git merge
you have to checkout the branch which shall become master
.– ensc
Mar 25 at 23:54
add a comment |
You already fixed (?) this using --allow-unrelated-histories
and there's no real reason not to just leave that. But in case you are still wondering...
What happened, and how you (probably) got here
The first key to using Git is to understand that Git is all about commits. Of course, this also requires that you understand, in a reasonably deep sort of way, what a commit is. What it is, is pretty short and simple: it's a permanent (mostly) and immutable (entirely) snapshot plus some metadata. The snapshot contains all of your files—well, all of them as of the time you made the commit—and the metadata has:
- your name and email address, and the time you made the commit;
- your log message, i.e., why you made this commit; and, crucially,
- the hash ID of the commit that comes just before this commit, defined as the parent of this commit.
Every commit is unique—for many reasons, including the time-stamp mentioned above—and every unique commit gets a unique hash ID. That hash ID, some big ugly string of hexadecimal characters, seems random, but is actually a cryptographic checksum of the contents of the commit. It's also the True Name, as it were, of that commit: that ID means that commit, and only that commit. No other commit will ever have that hash ID. That hash ID will always mean that commit.
Git actually finds the commit by hash ID. So the hash ID is crucial. Of course, it's also impossible for humans to remember. So Git gives us a way to remember the latest hash ID, and that way is a branch name like master
or dev
.
The name only has to remember the last commit because each commit remembers its parent's hash on its own. That is, given a tiny repository with just three commits, where we replace the actual hash IDs with a single uppercase letter, we can draw this:
A <-B <-C <-- master
The name master
remembers the hash ID of C
. C
itself—the actual commit, retrieved by hash ID—remembers the hash ID of B
, and B
itself remembers the hash ID of A
.
When something remembers the hash ID of some other commit, we say that this something points to the commit. So the name master
points to C
, C
points to B
, and B
points to A
. Those three commits—C
, then B
, then A
—are the history in the repository.
Note that A
doesn't point anywhere. It literally can't, because it was the first commit. There was no earlier commit. So it just doesn't, and Git calls this a root commit. All non-empty repositories have to have at least one root commit. Most, probably, have exactly one ... but yours has two.
Normal branching and merging
Let's take a quick look at the more normal way to make branches. Suppose we have just these three commits, pointed-to by master
. We ask Git to make a new branch name, pointing to the same commit as master
:
A--B--C <-- dev (HEAD), master
Both names identify commit C
, so commit C
is on—and is the tip commit of—both branches, and all three commits are on both branches. But now we make a new commit. The process of making a new commit—with the usual edit and git add
and git commit
—makes a new snapshot, adds our name and email and timestamp and so on, uses the current commit C
as the saved hash, and builds the new commit. The new commit gets some big ugly hash ID, but we'll just call it D
:
A--B--C <-- dev (HEAD), master
D
Since D
's parent is C
, D
points back to C
. But now the magic happens: Git writes D
's hash ID into the current branch name—the one HEAD
is attached to—so now we have:
A--B--C <-- master
D <-- dev (HEAD)
and voila, we have a new branch. (Well, we had it before, pointing to C
. Most people don't like to think about it that way though, they want to call D
the branch. In fact, the branch is D-C-B-A
!)
Over time we add some commits to both branches:
A--B--C-----J----K----L <-- master
D--E--F--G--H--I <-- dev
We git checkout master
and git merge dev
. Git will find the merge base commit for us, where dev
and master
diverged. That's obviously commit C
since that's where the two branches rejoin in the past. Git will compare C
vs L
to see what we changed on master
, compare C
vs I
to see what we changed on dev
, and combine the changes. Git applies the combined changes to the snapshot in C
—to the merge base—and makes a new merge commit M
, which goes on our current HEAD
branch as usual, updating that branch name so that master
points to M
:
A--B--C-----J----K----L--M <-- master (HEAD)
/
D--E--F--G--H--I <-- dev
What's special about M
is that it has two backwards links: it goes back to L
, as all commits would, but it has a second parent I
, which is the current tip commit of branch dev
. Other than the two parents, though, it's quite ordinary: it has a snapshot as usual, and our name and email and timestamp and a log message.
Abnormal branching
There's nothing in Git that stops you from making extra root commits. It's just a little bit tricky. Suppose that, somehow, you did this:
A <-- master
B--C--D--...--L <-- dev (HEAD)
Once you have this situation, git checkout master; git merge dev
just gives you an error. That's because the usual method of finding a merge base—starting at the two branch tips and working backwards—never finds a common commit.
Adding --allow-unrelated-histories
tells Git to pretend that there's a special empty commit before both branches:
A <-- master (HEAD)
0
B--C--D--...--L <-- dev
Now Git can diff 0
vs A
to see what you changed on master
, and 0
vs L
to see what they changed on dev
. On master
, you added every file. On dev
, you also added every file. As long as those are different files, the way to combine those two changes is to add the master
files from commit A
to the dev
files from commit L
, apply those changes to the empty null commit, and commit the result, with parents going back to both A
and L
:
A---------------M <-- master (HEAD)
/
B--C--D--...--L <-- dev
How you (probably) got here
There's a git checkout
option, git checkout --orphan
, that sets this state up. But that's probably not what you did. The state this sets up is the same state you're in when you create a new, empty repository with git init
:
[no commits] <-- [no branches]
There are no branches, and yet Git will say that you're on branch master
. You can't be on master
: it doesn't exist. But you are, even though it doesn't exist. The way Git manages this is that it puts the name master
into HEAD
(.git/HEAD
, actually) without first creating a branch named master
. It can't create the branch because a branch name has to contain a valid hash ID, and there aren't any.
So, when you run git commit
, Git detects this anomalous state: that HEAD
says master
but master
doesn't exist. That's what triggers Git to make our root commit A
. Then Git writes A
's hash ID into the branch, which creates the branch, and now we have:
A <-- master (HEAD)
which is just what we wanted.
But suppose, while we're in this weird no-commits-yet state, we run:
git checkout -b dev
This tells Git: Put the name dev
into HEAD
. It does that without complaint, even though there's no master
either. Then we make our first commit, but for no obvious reason, we'll pick B
as its one-letter stand-in for its hash ID:
B <-- dev (HEAD)
Meanwhile, having run git init
here, then git checkout -b dev
, then done something and git commit
, we'll go over to $WebHostingProvider—whether that's GitHub or GitLab or Bitbucket or whatever—and use its make me a new repository clicky buttons. Those usually have an option: create an initial commit with README and/or LICENSE files and such. If that option is checked—or the don't option is unchecked—they go ahead and make a first commit and a master
:
A <-- master (HEAD)
Now you connect your repository to theirs and have your Git download any commits they have that you don't:
A <-- origin/master
B <-- dev (HEAD)
You can now proceed to add lots of commits, never noticing that your dev
branch is not related to their master
branch (which your Git is calling origin/master
).
Later, you run:
git checkout master
Your Git notices that you don't have a master
, but that you do have an origin/master
. So your Git creates a master
for you, pointing to the same commit as origin/master
, and attaches your HEAD
to your new master
:
A <-- master (HEAD), origin/master
B--C--D--...--L <-- dev
and voila, you're in the pickle you were in.
add a comment |
You already fixed (?) this using --allow-unrelated-histories
and there's no real reason not to just leave that. But in case you are still wondering...
What happened, and how you (probably) got here
The first key to using Git is to understand that Git is all about commits. Of course, this also requires that you understand, in a reasonably deep sort of way, what a commit is. What it is, is pretty short and simple: it's a permanent (mostly) and immutable (entirely) snapshot plus some metadata. The snapshot contains all of your files—well, all of them as of the time you made the commit—and the metadata has:
- your name and email address, and the time you made the commit;
- your log message, i.e., why you made this commit; and, crucially,
- the hash ID of the commit that comes just before this commit, defined as the parent of this commit.
Every commit is unique—for many reasons, including the time-stamp mentioned above—and every unique commit gets a unique hash ID. That hash ID, some big ugly string of hexadecimal characters, seems random, but is actually a cryptographic checksum of the contents of the commit. It's also the True Name, as it were, of that commit: that ID means that commit, and only that commit. No other commit will ever have that hash ID. That hash ID will always mean that commit.
Git actually finds the commit by hash ID. So the hash ID is crucial. Of course, it's also impossible for humans to remember. So Git gives us a way to remember the latest hash ID, and that way is a branch name like master
or dev
.
The name only has to remember the last commit because each commit remembers its parent's hash on its own. That is, given a tiny repository with just three commits, where we replace the actual hash IDs with a single uppercase letter, we can draw this:
A <-B <-C <-- master
The name master
remembers the hash ID of C
. C
itself—the actual commit, retrieved by hash ID—remembers the hash ID of B
, and B
itself remembers the hash ID of A
.
When something remembers the hash ID of some other commit, we say that this something points to the commit. So the name master
points to C
, C
points to B
, and B
points to A
. Those three commits—C
, then B
, then A
—are the history in the repository.
Note that A
doesn't point anywhere. It literally can't, because it was the first commit. There was no earlier commit. So it just doesn't, and Git calls this a root commit. All non-empty repositories have to have at least one root commit. Most, probably, have exactly one ... but yours has two.
Normal branching and merging
Let's take a quick look at the more normal way to make branches. Suppose we have just these three commits, pointed-to by master
. We ask Git to make a new branch name, pointing to the same commit as master
:
A--B--C <-- dev (HEAD), master
Both names identify commit C
, so commit C
is on—and is the tip commit of—both branches, and all three commits are on both branches. But now we make a new commit. The process of making a new commit—with the usual edit and git add
and git commit
—makes a new snapshot, adds our name and email and timestamp and so on, uses the current commit C
as the saved hash, and builds the new commit. The new commit gets some big ugly hash ID, but we'll just call it D
:
A--B--C <-- dev (HEAD), master
D
Since D
's parent is C
, D
points back to C
. But now the magic happens: Git writes D
's hash ID into the current branch name—the one HEAD
is attached to—so now we have:
A--B--C <-- master
D <-- dev (HEAD)
and voila, we have a new branch. (Well, we had it before, pointing to C
. Most people don't like to think about it that way though, they want to call D
the branch. In fact, the branch is D-C-B-A
!)
Over time we add some commits to both branches:
A--B--C-----J----K----L <-- master
D--E--F--G--H--I <-- dev
We git checkout master
and git merge dev
. Git will find the merge base commit for us, where dev
and master
diverged. That's obviously commit C
since that's where the two branches rejoin in the past. Git will compare C
vs L
to see what we changed on master
, compare C
vs I
to see what we changed on dev
, and combine the changes. Git applies the combined changes to the snapshot in C
—to the merge base—and makes a new merge commit M
, which goes on our current HEAD
branch as usual, updating that branch name so that master
points to M
:
A--B--C-----J----K----L--M <-- master (HEAD)
/
D--E--F--G--H--I <-- dev
What's special about M
is that it has two backwards links: it goes back to L
, as all commits would, but it has a second parent I
, which is the current tip commit of branch dev
. Other than the two parents, though, it's quite ordinary: it has a snapshot as usual, and our name and email and timestamp and a log message.
Abnormal branching
There's nothing in Git that stops you from making extra root commits. It's just a little bit tricky. Suppose that, somehow, you did this:
A <-- master
B--C--D--...--L <-- dev (HEAD)
Once you have this situation, git checkout master; git merge dev
just gives you an error. That's because the usual method of finding a merge base—starting at the two branch tips and working backwards—never finds a common commit.
Adding --allow-unrelated-histories
tells Git to pretend that there's a special empty commit before both branches:
A <-- master (HEAD)
0
B--C--D--...--L <-- dev
Now Git can diff 0
vs A
to see what you changed on master
, and 0
vs L
to see what they changed on dev
. On master
, you added every file. On dev
, you also added every file. As long as those are different files, the way to combine those two changes is to add the master
files from commit A
to the dev
files from commit L
, apply those changes to the empty null commit, and commit the result, with parents going back to both A
and L
:
A---------------M <-- master (HEAD)
/
B--C--D--...--L <-- dev
How you (probably) got here
There's a git checkout
option, git checkout --orphan
, that sets this state up. But that's probably not what you did. The state this sets up is the same state you're in when you create a new, empty repository with git init
:
[no commits] <-- [no branches]
There are no branches, and yet Git will say that you're on branch master
. You can't be on master
: it doesn't exist. But you are, even though it doesn't exist. The way Git manages this is that it puts the name master
into HEAD
(.git/HEAD
, actually) without first creating a branch named master
. It can't create the branch because a branch name has to contain a valid hash ID, and there aren't any.
So, when you run git commit
, Git detects this anomalous state: that HEAD
says master
but master
doesn't exist. That's what triggers Git to make our root commit A
. Then Git writes A
's hash ID into the branch, which creates the branch, and now we have:
A <-- master (HEAD)
which is just what we wanted.
But suppose, while we're in this weird no-commits-yet state, we run:
git checkout -b dev
This tells Git: Put the name dev
into HEAD
. It does that without complaint, even though there's no master
either. Then we make our first commit, but for no obvious reason, we'll pick B
as its one-letter stand-in for its hash ID:
B <-- dev (HEAD)
Meanwhile, having run git init
here, then git checkout -b dev
, then done something and git commit
, we'll go over to $WebHostingProvider—whether that's GitHub or GitLab or Bitbucket or whatever—and use its make me a new repository clicky buttons. Those usually have an option: create an initial commit with README and/or LICENSE files and such. If that option is checked—or the don't option is unchecked—they go ahead and make a first commit and a master
:
A <-- master (HEAD)
Now you connect your repository to theirs and have your Git download any commits they have that you don't:
A <-- origin/master
B <-- dev (HEAD)
You can now proceed to add lots of commits, never noticing that your dev
branch is not related to their master
branch (which your Git is calling origin/master
).
Later, you run:
git checkout master
Your Git notices that you don't have a master
, but that you do have an origin/master
. So your Git creates a master
for you, pointing to the same commit as origin/master
, and attaches your HEAD
to your new master
:
A <-- master (HEAD), origin/master
B--C--D--...--L <-- dev
and voila, you're in the pickle you were in.
add a comment |
You already fixed (?) this using --allow-unrelated-histories
and there's no real reason not to just leave that. But in case you are still wondering...
What happened, and how you (probably) got here
The first key to using Git is to understand that Git is all about commits. Of course, this also requires that you understand, in a reasonably deep sort of way, what a commit is. What it is, is pretty short and simple: it's a permanent (mostly) and immutable (entirely) snapshot plus some metadata. The snapshot contains all of your files—well, all of them as of the time you made the commit—and the metadata has:
- your name and email address, and the time you made the commit;
- your log message, i.e., why you made this commit; and, crucially,
- the hash ID of the commit that comes just before this commit, defined as the parent of this commit.
Every commit is unique—for many reasons, including the time-stamp mentioned above—and every unique commit gets a unique hash ID. That hash ID, some big ugly string of hexadecimal characters, seems random, but is actually a cryptographic checksum of the contents of the commit. It's also the True Name, as it were, of that commit: that ID means that commit, and only that commit. No other commit will ever have that hash ID. That hash ID will always mean that commit.
Git actually finds the commit by hash ID. So the hash ID is crucial. Of course, it's also impossible for humans to remember. So Git gives us a way to remember the latest hash ID, and that way is a branch name like master
or dev
.
The name only has to remember the last commit because each commit remembers its parent's hash on its own. That is, given a tiny repository with just three commits, where we replace the actual hash IDs with a single uppercase letter, we can draw this:
A <-B <-C <-- master
The name master
remembers the hash ID of C
. C
itself—the actual commit, retrieved by hash ID—remembers the hash ID of B
, and B
itself remembers the hash ID of A
.
When something remembers the hash ID of some other commit, we say that this something points to the commit. So the name master
points to C
, C
points to B
, and B
points to A
. Those three commits—C
, then B
, then A
—are the history in the repository.
Note that A
doesn't point anywhere. It literally can't, because it was the first commit. There was no earlier commit. So it just doesn't, and Git calls this a root commit. All non-empty repositories have to have at least one root commit. Most, probably, have exactly one ... but yours has two.
Normal branching and merging
Let's take a quick look at the more normal way to make branches. Suppose we have just these three commits, pointed-to by master
. We ask Git to make a new branch name, pointing to the same commit as master
:
A--B--C <-- dev (HEAD), master
Both names identify commit C
, so commit C
is on—and is the tip commit of—both branches, and all three commits are on both branches. But now we make a new commit. The process of making a new commit—with the usual edit and git add
and git commit
—makes a new snapshot, adds our name and email and timestamp and so on, uses the current commit C
as the saved hash, and builds the new commit. The new commit gets some big ugly hash ID, but we'll just call it D
:
A--B--C <-- dev (HEAD), master
D
Since D
's parent is C
, D
points back to C
. But now the magic happens: Git writes D
's hash ID into the current branch name—the one HEAD
is attached to—so now we have:
A--B--C <-- master
D <-- dev (HEAD)
and voila, we have a new branch. (Well, we had it before, pointing to C
. Most people don't like to think about it that way though, they want to call D
the branch. In fact, the branch is D-C-B-A
!)
Over time we add some commits to both branches:
A--B--C-----J----K----L <-- master
D--E--F--G--H--I <-- dev
We git checkout master
and git merge dev
. Git will find the merge base commit for us, where dev
and master
diverged. That's obviously commit C
since that's where the two branches rejoin in the past. Git will compare C
vs L
to see what we changed on master
, compare C
vs I
to see what we changed on dev
, and combine the changes. Git applies the combined changes to the snapshot in C
—to the merge base—and makes a new merge commit M
, which goes on our current HEAD
branch as usual, updating that branch name so that master
points to M
:
A--B--C-----J----K----L--M <-- master (HEAD)
/
D--E--F--G--H--I <-- dev
What's special about M
is that it has two backwards links: it goes back to L
, as all commits would, but it has a second parent I
, which is the current tip commit of branch dev
. Other than the two parents, though, it's quite ordinary: it has a snapshot as usual, and our name and email and timestamp and a log message.
Abnormal branching
There's nothing in Git that stops you from making extra root commits. It's just a little bit tricky. Suppose that, somehow, you did this:
A <-- master
B--C--D--...--L <-- dev (HEAD)
Once you have this situation, git checkout master; git merge dev
just gives you an error. That's because the usual method of finding a merge base—starting at the two branch tips and working backwards—never finds a common commit.
Adding --allow-unrelated-histories
tells Git to pretend that there's a special empty commit before both branches:
A <-- master (HEAD)
0
B--C--D--...--L <-- dev
Now Git can diff 0
vs A
to see what you changed on master
, and 0
vs L
to see what they changed on dev
. On master
, you added every file. On dev
, you also added every file. As long as those are different files, the way to combine those two changes is to add the master
files from commit A
to the dev
files from commit L
, apply those changes to the empty null commit, and commit the result, with parents going back to both A
and L
:
A---------------M <-- master (HEAD)
/
B--C--D--...--L <-- dev
How you (probably) got here
There's a git checkout
option, git checkout --orphan
, that sets this state up. But that's probably not what you did. The state this sets up is the same state you're in when you create a new, empty repository with git init
:
[no commits] <-- [no branches]
There are no branches, and yet Git will say that you're on branch master
. You can't be on master
: it doesn't exist. But you are, even though it doesn't exist. The way Git manages this is that it puts the name master
into HEAD
(.git/HEAD
, actually) without first creating a branch named master
. It can't create the branch because a branch name has to contain a valid hash ID, and there aren't any.
So, when you run git commit
, Git detects this anomalous state: that HEAD
says master
but master
doesn't exist. That's what triggers Git to make our root commit A
. Then Git writes A
's hash ID into the branch, which creates the branch, and now we have:
A <-- master (HEAD)
which is just what we wanted.
But suppose, while we're in this weird no-commits-yet state, we run:
git checkout -b dev
This tells Git: Put the name dev
into HEAD
. It does that without complaint, even though there's no master
either. Then we make our first commit, but for no obvious reason, we'll pick B
as its one-letter stand-in for its hash ID:
B <-- dev (HEAD)
Meanwhile, having run git init
here, then git checkout -b dev
, then done something and git commit
, we'll go over to $WebHostingProvider—whether that's GitHub or GitLab or Bitbucket or whatever—and use its make me a new repository clicky buttons. Those usually have an option: create an initial commit with README and/or LICENSE files and such. If that option is checked—or the don't option is unchecked—they go ahead and make a first commit and a master
:
A <-- master (HEAD)
Now you connect your repository to theirs and have your Git download any commits they have that you don't:
A <-- origin/master
B <-- dev (HEAD)
You can now proceed to add lots of commits, never noticing that your dev
branch is not related to their master
branch (which your Git is calling origin/master
).
Later, you run:
git checkout master
Your Git notices that you don't have a master
, but that you do have an origin/master
. So your Git creates a master
for you, pointing to the same commit as origin/master
, and attaches your HEAD
to your new master
:
A <-- master (HEAD), origin/master
B--C--D--...--L <-- dev
and voila, you're in the pickle you were in.
You already fixed (?) this using --allow-unrelated-histories
and there's no real reason not to just leave that. But in case you are still wondering...
What happened, and how you (probably) got here
The first key to using Git is to understand that Git is all about commits. Of course, this also requires that you understand, in a reasonably deep sort of way, what a commit is. What it is, is pretty short and simple: it's a permanent (mostly) and immutable (entirely) snapshot plus some metadata. The snapshot contains all of your files—well, all of them as of the time you made the commit—and the metadata has:
- your name and email address, and the time you made the commit;
- your log message, i.e., why you made this commit; and, crucially,
- the hash ID of the commit that comes just before this commit, defined as the parent of this commit.
Every commit is unique—for many reasons, including the time-stamp mentioned above—and every unique commit gets a unique hash ID. That hash ID, some big ugly string of hexadecimal characters, seems random, but is actually a cryptographic checksum of the contents of the commit. It's also the True Name, as it were, of that commit: that ID means that commit, and only that commit. No other commit will ever have that hash ID. That hash ID will always mean that commit.
Git actually finds the commit by hash ID. So the hash ID is crucial. Of course, it's also impossible for humans to remember. So Git gives us a way to remember the latest hash ID, and that way is a branch name like master
or dev
.
The name only has to remember the last commit because each commit remembers its parent's hash on its own. That is, given a tiny repository with just three commits, where we replace the actual hash IDs with a single uppercase letter, we can draw this:
A <-B <-C <-- master
The name master
remembers the hash ID of C
. C
itself—the actual commit, retrieved by hash ID—remembers the hash ID of B
, and B
itself remembers the hash ID of A
.
When something remembers the hash ID of some other commit, we say that this something points to the commit. So the name master
points to C
, C
points to B
, and B
points to A
. Those three commits—C
, then B
, then A
—are the history in the repository.
Note that A
doesn't point anywhere. It literally can't, because it was the first commit. There was no earlier commit. So it just doesn't, and Git calls this a root commit. All non-empty repositories have to have at least one root commit. Most, probably, have exactly one ... but yours has two.
Normal branching and merging
Let's take a quick look at the more normal way to make branches. Suppose we have just these three commits, pointed-to by master
. We ask Git to make a new branch name, pointing to the same commit as master
:
A--B--C <-- dev (HEAD), master
Both names identify commit C
, so commit C
is on—and is the tip commit of—both branches, and all three commits are on both branches. But now we make a new commit. The process of making a new commit—with the usual edit and git add
and git commit
—makes a new snapshot, adds our name and email and timestamp and so on, uses the current commit C
as the saved hash, and builds the new commit. The new commit gets some big ugly hash ID, but we'll just call it D
:
A--B--C <-- dev (HEAD), master
D
Since D
's parent is C
, D
points back to C
. But now the magic happens: Git writes D
's hash ID into the current branch name—the one HEAD
is attached to—so now we have:
A--B--C <-- master
D <-- dev (HEAD)
and voila, we have a new branch. (Well, we had it before, pointing to C
. Most people don't like to think about it that way though, they want to call D
the branch. In fact, the branch is D-C-B-A
!)
Over time we add some commits to both branches:
A--B--C-----J----K----L <-- master
D--E--F--G--H--I <-- dev
We git checkout master
and git merge dev
. Git will find the merge base commit for us, where dev
and master
diverged. That's obviously commit C
since that's where the two branches rejoin in the past. Git will compare C
vs L
to see what we changed on master
, compare C
vs I
to see what we changed on dev
, and combine the changes. Git applies the combined changes to the snapshot in C
—to the merge base—and makes a new merge commit M
, which goes on our current HEAD
branch as usual, updating that branch name so that master
points to M
:
A--B--C-----J----K----L--M <-- master (HEAD)
/
D--E--F--G--H--I <-- dev
What's special about M
is that it has two backwards links: it goes back to L
, as all commits would, but it has a second parent I
, which is the current tip commit of branch dev
. Other than the two parents, though, it's quite ordinary: it has a snapshot as usual, and our name and email and timestamp and a log message.
Abnormal branching
There's nothing in Git that stops you from making extra root commits. It's just a little bit tricky. Suppose that, somehow, you did this:
A <-- master
B--C--D--...--L <-- dev (HEAD)
Once you have this situation, git checkout master; git merge dev
just gives you an error. That's because the usual method of finding a merge base—starting at the two branch tips and working backwards—never finds a common commit.
Adding --allow-unrelated-histories
tells Git to pretend that there's a special empty commit before both branches:
A <-- master (HEAD)
0
B--C--D--...--L <-- dev
Now Git can diff 0
vs A
to see what you changed on master
, and 0
vs L
to see what they changed on dev
. On master
, you added every file. On dev
, you also added every file. As long as those are different files, the way to combine those two changes is to add the master
files from commit A
to the dev
files from commit L
, apply those changes to the empty null commit, and commit the result, with parents going back to both A
and L
:
A---------------M <-- master (HEAD)
/
B--C--D--...--L <-- dev
How you (probably) got here
There's a git checkout
option, git checkout --orphan
, that sets this state up. But that's probably not what you did. The state this sets up is the same state you're in when you create a new, empty repository with git init
:
[no commits] <-- [no branches]
There are no branches, and yet Git will say that you're on branch master
. You can't be on master
: it doesn't exist. But you are, even though it doesn't exist. The way Git manages this is that it puts the name master
into HEAD
(.git/HEAD
, actually) without first creating a branch named master
. It can't create the branch because a branch name has to contain a valid hash ID, and there aren't any.
So, when you run git commit
, Git detects this anomalous state: that HEAD
says master
but master
doesn't exist. That's what triggers Git to make our root commit A
. Then Git writes A
's hash ID into the branch, which creates the branch, and now we have:
A <-- master (HEAD)
which is just what we wanted.
But suppose, while we're in this weird no-commits-yet state, we run:
git checkout -b dev
This tells Git: Put the name dev
into HEAD
. It does that without complaint, even though there's no master
either. Then we make our first commit, but for no obvious reason, we'll pick B
as its one-letter stand-in for its hash ID:
B <-- dev (HEAD)
Meanwhile, having run git init
here, then git checkout -b dev
, then done something and git commit
, we'll go over to $WebHostingProvider—whether that's GitHub or GitLab or Bitbucket or whatever—and use its make me a new repository clicky buttons. Those usually have an option: create an initial commit with README and/or LICENSE files and such. If that option is checked—or the don't option is unchecked—they go ahead and make a first commit and a master
:
A <-- master (HEAD)
Now you connect your repository to theirs and have your Git download any commits they have that you don't:
A <-- origin/master
B <-- dev (HEAD)
You can now proceed to add lots of commits, never noticing that your dev
branch is not related to their master
branch (which your Git is calling origin/master
).
Later, you run:
git checkout master
Your Git notices that you don't have a master
, but that you do have an origin/master
. So your Git creates a master
for you, pointing to the same commit as origin/master
, and attaches your HEAD
to your new master
:
A <-- master (HEAD), origin/master
B--C--D--...--L <-- dev
and voila, you're in the pickle you were in.
answered Mar 26 at 0:16
torektorek
213k21 gold badges276 silver badges361 bronze badges
213k21 gold badges276 silver badges361 bronze badges
add a comment |
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55347352%2fwhy-cant-i-merge-my-git-dev-branch-to-master-even-though-master-only-contains-a%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Does
master
anddev
have a common ancestor (I mean a common commit parent) ?– Jona
Mar 25 at 22:50
I went through and it actually didn't seem to share a common ancestor and that may be the crux of the issue. But it looks like a solution that was posted (but then deleted by another user...not sure why) did the trick. Basically,
git merge dev --allow-unrelated-histories
.– Mix Master Mike
Mar 25 at 23:16
How did you set up your local dev environment? Did you clone the repo you want to merge with, and then
git checkout -b dev
to create your dev branch?– Joe McMahon
Mar 25 at 23:20
@JoeMcMahon that's what I thought I did as that's my modus operandi. But for whatever reason as I went back through my logs, I didn't see
dev
branch off ofmaster
or share the same commit ID asmaster
. So this makes me wonder. Even though this was done 3 months ago, it seems like ages. And with the fix I described abovemaster
isahead of 'origin/master' by 720 commits.
– Mix Master Mike
Mar 25 at 23:26