jus*_*guy 0 git github git-push git-branch
我的组织阻止了推动掌握。相反,我需要在 GitHub 上显式创建一个单独的分支,并将我的代码推送到该分支,然后创建拉取请求。
我的代码位于本地存储库中。我运行过的命令:
git init
git add .
git commit -s -m <my-commit-message>
git remote add origin <repo-URL>
git branch -M main
git pull // not sure if this is necessary
git checkout -b feat/dev // the remote branch name
git push -uf origin:feat/dev main
Run Code Online (Sandbox Code Playgroud)
会发生什么:
错误:feat/dev 似乎不是本地存储库
我做了什么:
git push -uf origin main
会发生什么:
代码被推送到名为 main 的新分支,我无法打开拉取请求,因为这两个分支具有完全不同的提交历史记录。
我做错了什么?
编辑:
在此处添加我的组织所需的 GitHub 步骤(?):
我一直为我的个人项目所做的事情:
git init
git add
git commit
git branch -M main
本地运行git remote add origin
git push -u origin main
这总是将代码推送到主分支,并且工作得很好。
\n\n我的代码在本地存储库中...
\n
您还有一个现有的 GitHub 存储库,其中包含一些提交集?(这是一个问题,但根据这一点以上文本的其余部分,我将假设答案是“是”。)
\n因为 Git 存储库是提交的集合,并且您的目标是添加提交(而不是创建独立的提交),所以您需要从克隆现有存储库开始,而不是创建一个新的空存储库。所以这部分是错误的:
\n\n\nRun Code Online (Sandbox Code Playgroud)\ngit init\n
因为它用于创建一个新的空存储库。(这并不是完全错误,也不是不可挽回的错误:git clone
从运行开始git init
!我们将看看您可以做什么来恢复。)
同时,我先回答一下这个问题:
\n\n\n我做错了什么?
\n
\n\nRun Code Online (Sandbox Code Playgroud)\ngit add .\ngit commit -s -m <my-commit-message>\n
This part is OK, except for one problem: if you created a new, empty repository with the git init
step, this made a single initial commit in this new, previously-empty repository. That\'s not what you wanted. You wanted to add a new commit to an existing repository.
\n\nRun Code Online (Sandbox Code Playgroud)\ngit remote add origin <repo-URL>\n
(This is also something git clone
would have done for you. You do need this step, but using git clone
would make it easier.)
\n\nRun Code Online (Sandbox Code Playgroud)\ngit branch -M main\n
This is only necessary if you made a new, empty repository earlier and when you made your first (and now only) commit, Git chose to create the branch name master
, but you want to use the name main
. You probably don\'t want any of this, really; when you use git clone
, you\'ll get one branch of your own, and it will be based on the branch names in the repository you\'re cloning, which will take care of all of this.
\n\nRun Code Online (Sandbox Code Playgroud)\ngit pull // not sure if this is necessary\n
What git pull
does is two-fold:
It runs git fetch
. That, too, is something git clone
would have done for you. This is appropriate to do.
It runs a second Git command to merge or rebase your work (your new commits) with / onto some existing work ("their" commits as obtained by the git fetch
step). The default action here is git merge
and that\'s not what you wanted, but in any case, pull
requires an upstream setting and you won\'t have one, so this second command just fails entirely. That means it causes no harm either.
\n\nRun Code Online (Sandbox Code Playgroud)\ngit checkout -b feat/dev // the remote branch name\n
The git checkout -b
option creates a new branch name without using any remote-tracking names. This, too, is not what you want. This created a new branch name for your lone root commit: you now have main
and feat/dev
.
\n\nRun Code Online (Sandbox Code Playgroud)\ngit push -uf origin:feat/dev main\n
This won\'t work at all: the syntax for git push
is:
git push <remote> <refspec>\n
Run Code Online (Sandbox Code Playgroud)\nand in your case, the remote
part is just plain origin
. That\'s the name you gave to your git remote add
above.
The somewhat scary term refspec
is Git jargon, and for most users of git push
, is overkill: what goes here is simply a branch name.
\n\nRun Code Online (Sandbox Code Playgroud)\ngit push -uf origin main\n
Be careful with -f
! This will overwrite any existing branch on the other (GitHub) end, if they accept the force option. If this is your own fork of some GitHub repository, though, you won\'t actually damage anything other than your own fork. (But you might damage your fork: if there was a main
there before, now it\'s gone, replaced with your lone commit.)
\n\nCode gets pushed to a new branch named main and I cannot open a pull request for the 2 branches have entirely different commit histories.
\n
Right: this sent, to your GitHub repository, your lone commit on main
.
The exact fix will depend on several things:
\nDo you have your own fork?
\nmain
in the GitHub repository before?If there was a main
and you wrecked it, and it was your own fork, you can definitely recover.
If there was a main
and you wrecked it and this was a shared GitHub repository, someone else may need to fix it. We\'ll leave the "shared repository, someone else needs to fix it" out entirely.
In any case, let\'s start by making a new clone. This isn\'t really required\xe2\x80\x94we could do all the fixing-up in your existing clone\xe2\x80\x94but it\'s probably the best way to go. To make a new clone of your GitHub fork, change to a new empty directory / folder on your laptop (or whatever computer you\'re using) and run:
\ngit clone <github-url>\n
Run Code Online (Sandbox Code Playgroud)\nThis does the git init
/ git remote add
/ git fetch
stuff for you, creating a new Git repository by taking the URL and stripping off any final .git
and leading slash stuff. By doing the clone into an empty directory, when the clone finishes, you\'ll have just one sub-directory here with one name, and that will be the new clone, so it will be really easy to find. (You can move it afterward.)
Your new clone has copied all the commits from the GitHub repository, which I\'m assuming here is your own fork. Now, if you wrecked your fork\'s main
, the next step is to fix that, and to do that we need to use git remote add
to add the shared repository as a second remote. This part gets a little complicated and is only going to be used here for the fixing purpose:
git init\n
Run Code Online (Sandbox Code Playgroud)\n(If you don\'t need to fix anything up, you can skip this set of commands entirely. The git remote rm r2
step above tore down all the extra stuff and your fork should be back to the way it was before you wrecked it. If you wrecked a shared GitHub repo, get someone else to fix it as there\'s no guarantee that any of your own repositories have the right stuff in them any more, but someone else is almost certain to have what\'s needed.)
What you need to know:
\nGit actually finds commits by their big, ugly, random-looking hash IDs. These are impossible for humans to work with, so we just don\'t. We use things like branch names. What the branch names do\xe2\x80\x94what Git gives us when we use them\xe2\x80\x94is that the name turns into the right hash ID. Git needs the hash ID. We give it a name (main
or feat/dev
) and Git looks up the hash ID from that.
Now, the tricky part with git clone
is this:
git clone
creates a new, empty repository (git init
) that has no commits and no branch names;git clone
adds a remote, named origin
, and does a git fetch
, which gets all of some other repository\'s commits; butgit clone
does not create the same branch names in the new repository!Instead, Git takes each of their (the remote\'s) branch names, like main
and develop
and feat/ure
, and renames them. Your own Git repository, on your laptop, winds up with names like origin/main
and origin/develop
and origin/feat/ure
. Each of these is a remote-tracking name and it\'s just a renamed copy of the other guy\'s branch names.
When you run git fetch
, your Git (your Git software running with your repository) reaches out to their Git (their software on their repository, whoever "they" are over at origin
) and finds any new commits they have that you don\'t. Your Git brings those into your repository. Every commit gets a unique hash ID, so these have new unique IDs, never used before; they will never be used for any future commit either, so that the IDs Git sees here now are the right IDs forever. Your Git stuffs the new commits into your repository and updates your remote-tracking names.
This way, your origin/main
holds a memory of where their main
was, the last time your Git reached out to their Git. Your remote-tracking names remember their branch names: both the name (with origin/
stuffed in front) and the hash ID. But these are not your branch names. That means you can create a branch name and not worry that it will get overwritten if someone else creates the same name in their repository.1 Their branch hello
becomes origin/hello
, which can\'t possibly collide with your branch hello
. Just don\'t name any of your branches origin/whatever
.2
Having run the initial git init
, git remote add
, and git fetch
, your git clone
now does one last thing: it creates one branch name for you. The branch name that git clone
creates, in your new clone, is the one you specify with your git clone
command\'s -b
option, when you run:
git clone -b xyz <url>\n
Run Code Online (Sandbox Code Playgroud)\nBut, wait a minute, we didn\'t run with a -b
option. Now what?
Well, absent the -b
option, your Git software asks their (origin\'s) software which branch name their repository suggests. That\'s almost always main
these days (and used to be master
). So that\'s what comes out as the recommendation, and that\'s the one branch name your Git creates, in your repository.
A branch name must select some particular commit. So the commit your Git chooses is the one named by your remote-tracking name that corresponds to the branch name here. If they recommended main
, you have an origin/main
remote-tracking name, remembering their main
. That name specifies one particular commit. That\'s the one particular commit your Git uses to make your name main
.
The end result is that you get one branch in your new clone, matching one branch in the repository you cloned. It\'s all a very roundabout and complicated way of doing something ridiculously simple\xe2\x80\x94which is a good description of a whole lot of things that Git does.
\n1When using GitHub forks, this is not a real problem. But if you use Git the way it was before GitHub came along, it is a real problem: you might pick a branch name like fix-xyz-command
, and Bob might pick the same name for a different fix for that command. So in real world situations, this was a problem, and remote-tracking names solved it. Within the GitHub world, it almost never comes up, though there are more complicated situations where it still can.
2This is technically not a problem either, because your local branch names are in a separate name space. But while Git won\'t get confused if you name a local branch origin/main
, you probably will, so just don\'t do it.
You\'re probably ready now to create your feature branch in your new clone:
\ngit switch -c feat/dev\n
Run Code Online (Sandbox Code Playgroud)\nor:
\ngit checkout -b feat/dev\n
Run Code Online (Sandbox Code Playgroud)\nThese both do exactly the same thing: they create a new name, feat/dev
, that selects the same commit you have out right now (the one from main
, probably). Then, having created this new name, they switch to that branch.
Now you need to get the files from the other repository you made. There are several ways to do that, but one somewhat magical one is this:
\ngit --work-tree=/path/to/wrong/repo add .\n
Run Code Online (Sandbox Code Playgroud)\nA more direct way is to just copy the files from the "wrong" repository\'s working tree into the new one\'s working tree, and then run git add .
as you did earlier.
I always like to run:
\ngit status\n
Run Code Online (Sandbox Code Playgroud)\nand then:
\ngit diff --staged\n
Run Code Online (Sandbox Code Playgroud)\nat this point, to check that I have the right files "staged for commit", and see what I have changed. Only then, having reviewed my work and checked it over for any obvious errors, do I run:
\ngit commit\n
Run Code Online (Sandbox Code Playgroud)\n(or git commit -s
3) and write up a commit message. This updates the current branch (now feat/dev
) with the new commit, and now I can run:
git push -u origin feat/ure\n
Run Code Online (Sandbox Code Playgroud)\nto create branch feat/ure
in my GitHub fork and make a pull request on GitHub (using gh
, the GitHub CLI, or using the web site).
3该-s
选项进行签名提交。对于您或任何人所做的任何 Git 提交,任何人都可以声称自己是他们想要的任何人。我可以做出声称由 Barack Obama 或 Volodomyr Zelenskyy 撰写的承诺。有些人喜欢添加数字签名,使用PGP或GPG或ssh数字签名技术。这些可以(至少在没有量子计算机的情况下)用于验证这些实际上是由您而不是由冒名顶替者完成的。然而,我发现签署的承诺是严重的矫枉过正和痛苦;我更喜欢 Git 项目的简单签署官方发布标签的方法。
归档时间: |
|
查看次数: |
6455 次 |
最近记录: |