1

Yes, I know, this question has been asked (and repeatedly answered) before. Unfortunately, the results I'm getting from using those answers don't (seem to) answer the question. Am I using them wrong? Is my repository corrupted? You be the judge.

My journey so far:

  1. From a directory where I've done pushes before, I did a git pull git://git.code.sf.net/p/mingw-w64/mingw-w64 master to make sure I had the most current code. Several updates downloaded, which was not surprising.

  2. Then I did a clean build of the project to make sure my changes would still build. Yup.

  3. I staged, then committed the 2 files to my local repository. So far, so good.

  4. But before I did the push, I wanted to check to ensure I'm only going to push what I intend. I'm still uncomfortable using git, so a bit of checking before affecting the public repository seemed warranted. So (per this) I used git cherry -v to see what my push was about to do:

C:\cygwin64\src\mingw-w64d>git cherry -v
+ 390ef6ea3275003c44a404b3bae83455287271ae dwrite_2.h: Added IDWriteFontFace2 declaration.
+ 563731c44e5515ed373b4af03b5a382c7d5ea843 lib32 msvcrt add mkgmtime exports
+ e05f3e86898d91b870c9c7256efd24c8dd6de9cb Add CreateRemoteThreadEx to 32bit kernel32.def
+ 6734c8e40e69f305ada23afe86c1176a9ae0fc10 winpthreads mem leak fixed(bug 571)
+ c798dc2befb7e0b9d9d940aeeffbc7365b01e36a Add missing symbols to crypt library
+ 6c0ebaa1b404b9f27e1f953a16a7f87063e1079e winstorecompat: Add a GetStartupInfo stub
+ f3e50a97fb4ec3df8969c54bc5a575819dfb5b87 dpapi: Crypt*Data functions are allowed on Win10
+ 0f658a7ad80153970a0c43c6580f892c82e8cc48 uuid: Remove duplicated UUIDs
+ d47421eab0299215a33c7d24252b66fff3579b8a winstorecompat: Add GetConsoleOutputCP replacement
+ c77c0298a70b98edb302a7131ea51e739dd35ac3 winstorecompat: Fix mangling header guard.
+ e2cfbae44eda32aa63477b458f91a907633b334c wincrypt: Unconditionally include dpapi.h
+ 15b43db3ad61bca9c6a4abaf49e5f4e691349ee6 include: SwitchToThread is always available on Win10
+ 8a6d5d945c5c344daa464009e467054f2c7fbd8b crt: Add a WindowsApp.lib mri & associated def files
+ b48e3ac8969dd478efa8bfd129af38f080fd6741 crt: Add IMP symbols for lock/unlock_file
+ ac919255813c22aaad9de8b230216f0a8c39d115 GetThemeFont pFont argument is always UTF-16
+ 4c2df0d02ed71ae07e85f1b35ac857a148cd2b8f Define IN6_IS_ADDR_ macros to conform to Posix Spec
+ a76b799dc76dcdf8630dd48307158a5385a9f2ce Bug 541 - fesetenv was broken

My commit is JUST the last one. The rest appear to be all the stuff I just got from the 'git pull.' So either 'git cherry' doesn't "list what I'm about to push," or I'm about to re-push a bunch of already pushed changes.

  1. Guessing maybe 'cherry' isn't the command I want, I tried git diff --stat origin master (from here. This lists all the files I just got from the git pull. But it DOESN'T list the files in the commit I actually want to push. So again, this isn't telling me what I want to know.

  2. As a last try I did git push --dry-run origin master which shows:

    4c2df0d..a76b799 master -> master

    Now this looks right(-ish). As you can see, a76b799 is my commit. 4c2df0d is the commit right before it. As written, this appears to say the push will send 2 commits. That's better than 17, but to call this a "list of what I'm about to push" seems a stretch.

So, to return to my question: How to tell what 'git push' is going to push?

The answers I'm finding on SO aren't telling me what I want to know. Although it's possible this is due to my using them wrong, or that I've (somehow) mucked up my local repository. Maybe calling push really is about to send all 17 commits? But that's not what 'push --dry-run' seems to say? How would I know which one to believe?!?

It's frustrating that 'trying to find out' what I'm going to push has left me more confused over what's going to get pushed than when I started!

What would an acceptable answer to this question look like? Well, something that would get me this would be a start:

+ a76b799dc76dcdf8630dd48307158a5385a9f2ce Bug 541 - fesetenv was broken

Note that unlike my current 'cherry' output, I'm only listing (what I hope is) the one commit about to be pushed.

Alternately would be something that produces a listing of files that includes the actual files about to be pushed (unlike my current 'git diff' output) and excludes everything else:

mingw-w64-crt/misc/fesetenv.c                    |   2 +-
mingw-w64-crt/misc/feholdexcept.c                |   2 +- 

Finally would be a way to get the patches (or perhaps 1 big patch if there are multiple commits pending?) of the changes about to be pushed.

I'd like to post the actual output I'm getting from all these commands, but it exceeds the max message size for an SO question. It is (temporarily) available for viewing at http://www.limegreensocks.com/mingw-w64/hist.txt. The files in the a76b799 commit are named fesetenv.c and feholdexcept.c.


A thought: Is my git pull syntax wrong?

Community
  • 1
  • 1
David Wohlferd
  • 7,110
  • 2
  • 29
  • 56
  • try this: git diff origin/master..HEAD --stat – felix Dec 23 '16 at 06:51
  • @felix `git diff origin/master..HEAD --stat` does contain feholdexcept.c and fesetenv.c, but it contains a bunch of other files too: `184 files changed, 2161 insertions(+), 104 deletions(-)`. – David Wohlferd Dec 23 '16 at 07:09
  • Why don't you just run `git log --oneline `, where `` is the revision range reported by `git push --dry-run`? – Leon Dec 23 '16 at 08:10

1 Answers1

1

git pull git://git.code.sf.net/p/mingw-w64/mingw-w64 master

Don't do this—or rather, don't do it this way. (In fact I recommend avoiding git pull entirely—it just runs git fetch followed by a second command, and choosing the second command is best done manually for all but the easiest cases—but that's a separate issue. The second command is either git merge or git rebase, and pull defaults to merge, which is usually the wrong one.)

A thought: Is my git pull syntax wrong?

It's not exactly wrong, but it leaves your Git with a problem, which then shows up when you run git cherry. What you wanted here was git pull origin master.

(You can do that now—but don't, or at least, not yet. Instead, try git fetch origin now: git fetch is always safe, while git pull runs a second command that may not do what you want, since what it does depends on what git fetch fetched! If, after git fetch origin, git cherry lists what you expect, then all is well and you're ready to go. If not, it means someone has made further changes upstream at origin and you get the "fun part" of deciding how to deal with that.)

Background: What's going on here

There are basically only two commands1 that have your Git call up another Git so that you can exchange commits and other objects: git fetch and git push. Other commands, including git cherry, rely on remote-tracking items normally left behind by git fetch and git push.

For these remaining commands to work well, you need to be sure that git fetch leaves good tracking information, and for that to happen, git fetch needs to fetch from a named remote.

Sidebar: remotes and remote-tracking branches

A remote is simply a short name, like origin. You can choose any name you like2 that will be memorable. The default name is origin, set up when you make the initial clone, and if you have only one remote you might as well just use that. If you have several remotes, you might call the one origin and the second sfnet, perhaps.

For the rest of this, I'll just assume origin. That's almost always right since there is no reason to change the default, and mostly, nobody does. The name origin is now short for the URL, so you don't have to spell it out anymore: origin means git://git.code.sf.net/p/mingw-w64/mingw-w64. (You can change this with git remote, or also with git config, or even just your editor. Take a look at the file .git/config to see: it will be pretty obvious.)

A remote-tracking branch is a a slightly longer name, starting with the name of one of your remotes. You don't control these names: they're for git fetch and git push to create and update (and remove with --prune), based on what git fetch sees on the other Git, and whether after you try a git push, the other Git accepts your push request. The part after the remote-name is just the name of the branch in that other Git repository, as seen over there. So origin/master is your Git's memory of what the other Git has as its master, from your last fetch, or your last successful push.

When using a direct URL, there is no remote

The problem should now be obvious. When git pull runs git fetch, it gives git fetch the name of the remote. If you run git fetch yourself, you provide the remote. The remote, origin or sfnet or whatever, then supplies the URL and tells fetch where to save the new set of remote-tracking branches.

Without a remote name, git fetch won't update any remote-tracking branches. Your origin/master won't get updated, or maybe even won't exist at all. (If it did not exist, git cherry would have no upstream, so origin/master obviously does exist.)

This means things went wrong when you (via git pull) ran git fetch git://git.code.sf.net/p/...: your Git picked up the new commits, but did not update its own memory of their master. Then git pull used its secret side channel3 to run git merge or git rebase to incorporate the new commits even though there's no permanent record of them. A later git cherry thinks they're your commits because they're not recorded in origin/master.

Running git fetch origin will update your origin/master—to whatever it should be based on what git fetch sees now—and then git cherry will be able to give you good information. You can run git fetch whenever you like, and it may be wise to run it fairly often, since your remote-tracking branches gradually become out of date—at whatever rate that other Git gets updated, of course.

(Note: you can just run git fetch and it will figure out origin for you. The same goes for the second command git pull would run, so instead of git pull <remote> <branch> you can just run git fetch followed by a simple git rebase or git merge, whichever it is you intended. And, for more complex cases, you can run git fetch followed by git rebase origin/<branch>, for instance. The key is to have fetch update all the origin/* remote-tracking branches.)


1Except for git ls-remote. Three! There are three commands when your Git will contact the other Git, when running fetch, push, ls-remote, and show ... er, four. Git's four weapons and fetch, push, ls-remote, and show. And git remote update ... I'll come in again.

2Well, any name that works when embedded within a reference. It's a good idea to stick with all lower-case alphanumerics though. While Git is case-sensitive here, some of the things Git does with these names rely on the underlying operating system, and if it does case-insensitive things with the remote-tracking branch names, it gets messy. So avoiding the name oriGIN makes sure there is never any conflict with origin.

3This side channel is not so secret: it's described in the git fetch documentation. It is a file in the .git repository, named FETCH_HEAD, that acts a bit like the various other *_HEAD files in there, except that it has more fields.

torek
  • 448,244
  • 59
  • 642
  • 775
  • Quoting another Spaniard: *Let me sum up.* What I believe you said was: The `git pull` command I used does NOT mean "update the local repository with all the latest changes from the remote repository," but instead means "get the newest copies of the files from this url." A subtle but important difference. Fixing with `git fetch origin` ran without error, and the other git commands now work as expected. From now on I should use `git pull origin master` to update my local repository. – David Wohlferd Dec 24 '16 at 03:27
  • That's ... a little too summarized. :-) `git pull` is `git fetch` followed by another Git command, no more and no less. The 2nd command is either merge or rebase. The *fetch* step is not about files at all, but about *commits*. Merge and rebase are also much about commits, with the side effect of working with your work-tree files. It's this second step that updates files. Push and fetch are purely about commits, though, and are as close as Git gets to opposites; `pull` is just a convenience shortcut. – torek Dec 24 '16 at 04:06