Reputation: 163
I wanted to fetch a remote branch of a project from github. However, I forgot to switch branches and when I ran the command, I was in the main branch on my local computer.
The command I ran was: git fetch https:<access_token>github.com/user/repo.git email
The results were:
remote: Enumerating objects: 23, done.
remote: Counting objects: 100% (23/23), done.
remote: Compressing objects: 100% (5/5), done.
remote: Total 14 (delta 8), reused 14 (delta 8), pack-reused 0
Unpacking objects: 100% (14/14), 2.45 KiB | 93.00 KiB/s, done.
From https://github.com/macumhail/otools
* branch email -> FETCH_HEAD
I don't want to merge the "email" branch with main yet. I am a git novice and I'm not sure what I've done. Is there a way to undo the fetch and do I even need to?
Thank you for any ideas.
Upvotes: 1
Views: 490
Reputation: 487755
All is fine.
git fetch https:<access_token>github.com/user/repo.git email
The git fetch
command is how we get commits from some other repository, into our own local repository. Commits are why Git exists, and hence are the all-important part, so this is a perfectly reasonable and normal thing to do.
I am a git novice ...
The good part about being a novice is that you won't have a lot of wrong ideas to un-learn. 😀 The bad part is that Git is complicated, often unnecessarily complicated (or at least so it seems), and Git terminology is weird and confusing. So there's a lot you need to learn to get started.
The first thing to know is that Git is all about commits, wihch means that the second thing to know is just what, exactly, a commit is and does for you.
A Git commit:
is numbered. Unfortunately, instead of the obvious way of numbering them (commit #1 followed by commit #2 followed by #3, etc.), the numbers seem random and are horrible and impossible to remember, like 7c2ef319c52c4997256f5807564523dfd4acdfc7
. You'll probably never want to type in one of these big ugly hexadecimal numbers, but fortunately it's pretty rare to need to (and then you can usually use the mouse to cut-and-paste it).
These numbers are unique: the one I quoted above is for a commit in the Git repository for Git, and it's now "used up" and will never occur again, in any Git repository anywhere, except to hold that particular commit. The way this works is deeply magic (and also flawed, in that Git will someday quit working, but that day is sufficiently far in the future—we hope—that it won't ever actually come).
Git calls these things hash IDs or, more formally, OIDs (object IDs). There are numbers for things that aren't commits, too, but you'll just deal with commit hash IDs, mostly—and even then you'll probably ignore them. But Git needs them. Git can't work without them.
is read-only. No commit, once made, can ever be changed. Fortunately commits are cheap (they take very little space on your hard drive or SSD or whatever, in general) and if you make a bad one you can just throw it out (really, let it expire on its own; commits that you've "throw away" are usually retrievable again for a minimum of 30 days).
holds a full snapshot of every file, saved forever, or for as long as the commit itself continues to exist anyway. Despite this, commits are still cheap. But once you've made a commit, the files you committed can be retrieved from Git. Until you've committed, the files aren't in Git yet, so in general, it's a good idea to make a lot of commits.
(The files inside each commit are magically compressed and de-duplicated internally, which is why commits are tiny even though every commit has a full copy of every file. The fact that everything committed is completely read-only enables this sharing that commits do: since you can't change a committed file, some other commit can re-use the file.)
stores some extra information as well: metadata, or information about the commit itself. This includes the name and email address of the person who made the commit, for instance, and several date-and-time stamps, and so on.
The metadata for any one given commit contains the numbers—the hash IDs—of the previous commit or commits that go with this commit. The result is that Git needs only the latest commit hash ID(s). From the latest commit, Git can work backwards to the second-latest; from the second-latest, Git works backwards to the third-latest, and so on.
In other words, Git works backwards. Keep this in mind at all times: if something seems confusing, it probably is confusing, but Git is very backwards. 😀
Because humans are so bad at hash IDs, Git lets us humans use branch names. A branch name, in Git, simply remembers one hash ID. Whatever hash ID that branch name remembers, that's the latest commit "in" or "on" that branch. Here's a good way for most people to "see" this in their heads:
... <-F <-G <-H <--branch
Here, the branch name branch
contains the raw hash ID—whatever that is—for the latest or last commit we just made. We'll call that commit H
(for Hash). Commit H
contains a full snapshot of every file plus the metadata that says who made commit H
and so on.
The metadata for H
also contains the raw hash ID for some earlier commit, though. We'll call this G
since G
comes before H
. We will say that commit H
points to commit G
. Since commit G
is a commit, it contains a full snapshot and some metadata, and its metadata points to still-earlier commit F
, which contains a snapshot and some metadata and hence points backwards to an even-earlier commit.
So, by us giving Git the name branch
—which name points to H
—Git can find H
, and work backwards to G
and F
and (presumably) E
and so on, all the way back to the very first commit ever.
That's almost all there is to a branch!
Note that if you choose to make a new commit while you are "on" branch branch
, what Git will do is:
H
;So now you will have:
... <-G <-H <-I <--branch
The name branch
will remember your newest commit's hash ID, and from that commit, Git can work backwards to what was the latest commit H
, and so on.
git fetch
What git fetch
does is:
This is what you see here, in this first part of the git fetch
output:
remote: Enumerating objects: 23, done.
remote: Counting objects: 100% (23/23), done.
remote: Compressing objects: 100% (5/5), done.
remote: Total 14 (delta 8), reused 14 (delta 8), pack-reused 0
Unpacking objects: 100% (14/14), 2.45 KiB | 93.00 KiB/s, done.
They found some commits that they had, that you didn't. These eventually joined up, history-wise, to commits that you did have. They send over the ones you didn't have, plus any files needed and so on to go with those commits. That's the objects: ... 23/23
part. The magic of Git sharing enabled them to not send you some other objects; that's the reused 14
part. Your Git received the new stuff and saved it away.
Now, there's one remaining problem. You find commits using your branch names, not the big ugly Git hash IDs. But their branch names are theirs, not yours. Normally, if we're going to get commits from some other Git repeatedly, we have our Git create a name in our repository—something Git calls a remote—by which we remember their repository URL and their branch names.
You skipped this step by using the https://...
URL directly, rather than first creating a remote. So your Git had no remote name to use to save away their branch names and corresponding hash IDs. Your Git therefore used an ancient (2005-era) fallback, that Git still has in it, of saving information in .git/FETCH_HEAD
. That's this last part:
From https://github.com/macumhail/otools
* branch email -> FETCH_HEAD
Your own Git repository now has the right hash ID for their latest email
-branch commit stored in your .git/FETCH_HEAD
file. You can see this hash ID, if you want:
git rev-parse FETCH_HEAD
will dump it out. But you probably should create a name by which you can refer to their commit.
Had you used:
git remote add otools https://<access-token>@github.com/macumhail/otools
(here, I chose the name otools
for your remote: that's your name for their Git repository, and you can pick any name you like here) and then run:
git fetch otools email
you'd have a remote-tracking name otools/email
to refer to their latest email
-branch commit. Remote-tracking names are different from branch names, but they wind up serving much the same purpose.
You can, if you like, do all of this now: create a remote with git remote add
and run the same git fetch
. This time, since your Git repository actually has all their commits already, the git fetch
will go faster and bring over fewer (perhaps no) objects, and then your own Git software will go ahead and create your otools/email
(or whatever/email
) name to remember the hash ID.
But you can just use FETCH_HEAD
, or run git rev-parse FETCH_HEAD
as shown above and cut-and-paste the hash ID. That commit, plus the earlier ones that go with it, will stick around for a while—probably at least 14 to 30 days—for you to inspect it, merge it into your own branches, or whatever you want to do with it. The reason to add a "remote" and use git fetch <remote-name>
instead of working with the raw URL is if you intend to do this more than once, it will save you a lot of effort.
Other than that, everything you've done so far is good!
Upvotes: 1
Reputation: 534893
Not to worry. git fetch
has no effect whatever on your local branches! All it does is bring the "remote-tracking" branches up to date. It makes no different what local branch you are "on" at the time you fetch. Fetching is always good. Fetch early and often — keeping in mind, of course, that this is one of the few Git commands that actually networks with your remote.
Upvotes: 2