With two branches getting fetched (master and config), the branch
referenced by FETCH_HEAD is ambiguous.  For example, I have:

  $ cat FETCH_HEAD
  41d7bfa7184cc93c9dac139d1674e9530799e3b0 \
    not-for-merge   branch 'config' of http://nmbug.tethera.net/git/nmbug-tags
  acd379ccb973c45713eee9db177efc530f921954 \
    not-for-merge   branch 'master' of http://nmbug.tethera.net/git/nmbug-tags

(where I wrapped the line by hand).  This means that FETCH_HEAD
references the config branch:

  $ git rev-parse FETCH_HEAD
  41d7bfa7184cc93c9dac139d1674e9530799e3b0

which breaks all of the FETCH_HEAD logic in nmbug (where FETCH_HEAD is
assumed to point to the master branch).

Instead of relying on FETCH_HEAD, use @{upstream} as the
remote-tracking branch that should be merged/diffed/integrated into
HEAD.  @{upstream} was added in Git v1.7.0 (2010-02-12) [1], so
relying on it should be fairly safe.  One tricky bit is that bare
repositories don't set upstream tracking branches by default:

  $ git clone --bare http://nmbug.tethera.net/git/nmbug-tags.git nmbug-bare
  $ cd nmbug-bare
  $ git remote show origin
  * remote origin
    Fetch URL: http://nmbug.tethera.net/git/nmbug-tags.git
    Push  URL: http://nmbug.tethera.net/git/nmbug-tags.git
    HEAD branch: master
    Local refs configured for 'git push':
      config pushes to config (up to date)
      master pushes to master (up to date)

While in a non-bare clone:

  $ git clone http://nmbug.tethera.net/git/nmbug-tags.git
  $ cd nmbug-tags
  $ git remote show origin
  * remote origin
    Fetch URL: http://nmbug.tethera.net/git/nmbug-tags.git
    Push  URL: http://nmbug.tethera.net/git/nmbug-tags.git
    HEAD branch: master
    Remote branches:
      config tracked
      master tracked
    Local branch configured for 'git pull':
      master merges with remote master
    Local ref configured for 'git push':
      master pushes to master (up to date)

>From the clone docs [2]:

  --bare::
        Make a 'bare' Git repository?
        Also the branch heads at the remote are copied directly
        to corresponding local branch heads, without mapping
        them to `refs/remotes/origin/`.  When this option is
        used, neither remote-tracking branches nor the related
        configuration variables are created.

To use @{upstream}, we need to the local vs. remote-tracking
distinction, so this commit adds 'nmbug clone', replacing the
previously suggested --bare clone with a non-bare --no-checkout
--separate-git-dir clone into a temporary work directory.  After
which:

  $ git rev-parse @{upstream}
  acd379ccb973c45713eee9db177efc530f921954

gives us the master-branch commit.  Existing nmbug users will have to
run the configuration tweaks and re-fetch by hand.  If you don't have
any local commits, you could also blow away your NMBGIT repository and
re-clone from scratch:

  $ nmbug clone http://nmbug.tethera.net/git/nmbug-tags.git

Besides removing the ambiguity of FETCH_HEAD, this commit allows users
to configure which upstream branch they want nmbug to track via 'git
config', in case they want to change their upstream repository.

[1]: 
http://git.kernel.org/cgit/git/git.git/tree/Documentation/RelNotes/1.7.0.txt
[2]: http://git.kernel.org/cgit/git/git.git/tree/Documentation/git-clone.txt
---

Changes since v1 [1]:

* Replaced confusing post-clone fetch with a single --no-checkout
  --separate-git-dir clone [2].  This avoids a bare repository's lack of
  remote-tracking branches by not creating a bare repository in the
  first place, while v1 tried to ?fix? the bare repo.

Cheers,
Trevor

[1]: id:80db13662a0313711ca3a91e338a63d35e64a83c.1391898002.git.wking at 
tremily.us
     http://article.gmane.org/gmane.mail.notmuch.general/17154
[2]: id:20140308162633.GM16433 at odin.tremily.us
     http://article.gmane.org/gmane.mail.notmuch.general/17409

 devel/nmbug/nmbug | 45 ++++++++++++++++++++++++++++++++-------------
 1 file changed, 32 insertions(+), 13 deletions(-)

diff --git a/devel/nmbug/nmbug b/devel/nmbug/nmbug
index 90d98b6..d6f5213 100755
--- a/devel/nmbug/nmbug
+++ b/devel/nmbug/nmbug
@@ -26,6 +26,7 @@ my $ESCAPED_RX =      qr{$ESCAPE_CHAR([A-Fa-f0-9]{2})};
 my %command = (
             archive    => \&do_archive,
             checkout   => \&do_checkout,
+            clone      => \&do_clone,
             commit     => \&do_commit,
             fetch      => \&do_fetch,
             help       => \&do_help,
@@ -125,6 +126,15 @@ sub do_archive {
   system ('git', "--git-dir=$NMBGIT", 'archive', 'HEAD');
 }

+sub do_clone {
+  my $repository = shift;
+
+  my $tempwork = tempdir ('/tmp/nmbug-clone.XXXXXX', CLEANUP => 1);
+  system ('git', 'clone', '--no-checkout', '--separate-git-dir', $NMBGIT,
+          $repository, $tempwork) == 0
+    or die "'git clone' exited with nonzero value\n";
+  git ('config', '--unset', 'core.worktree');
+}

 sub is_committed {
   my $status = shift;
@@ -332,21 +342,24 @@ To discard your changes,  run 'nmbug checkout'

 sub do_pull {
   my $remote = shift || 'origin';
+  my $branch = shift || 'master';

   git ( 'fetch', $remote);

-  do_merge ();
+  do_merge ("$remote/$branch");
 }


 sub do_merge {
+  my $commit = shift || '@{upstream}';
+
   insist_committed ();

   my $tempwork = tempdir ('/tmp/nmbug-merge.XXXXXX', CLEANUP => 1);

   git ( { GIT_WORK_TREE => $tempwork }, 'checkout', '-f', 'HEAD');

-  git ( { GIT_WORK_TREE => $tempwork }, 'merge', 'FETCH_HEAD');
+  git ( { GIT_WORK_TREE => $tempwork }, 'merge', $commit);

   do_checkout ();
 }
@@ -407,11 +420,10 @@ sub do_status {


 sub is_unmerged {
+  my $commit = shift || '@{upstream}';

-  return 0 if (! -f $NMBGIT.'/FETCH_HEAD');
-
-  my $fetch_head = git ('rev-parse', 'FETCH_HEAD');
-  my $base = git ( 'merge-base', 'HEAD', 'FETCH_HEAD');
+  my $fetch_head = git ('rev-parse', $commit);
+  my $base = git ( 'merge-base', 'HEAD', $commit);

   return ($base ne $fetch_head);

@@ -473,7 +485,7 @@ sub diff_index {
 sub diff_refs {
   my $filter = shift;
   my $ref1 = shift || 'HEAD';
-  my $ref2 = shift || 'FETCH_HEAD';
+  my $ref2 = shift || '@{upstream}';

   my $fh= git_pipe ( 'diff', "--diff-filter=$filter", '--name-only',
                 $ref1, $ref2);
@@ -561,10 +573,11 @@ git. Any extra arguments are used (one per line) as a 
commit message.

 push local nmbug git state to remote repo

-=item  B<pull> [remote]
+=item  B<pull> [remote] [branch]

 pull (merge) remote repo changes to notmuch. B<pull> is equivalent to
-B<fetch> followed by B<merge>.
+B<fetch> followed by B<merge>.  The default remote is C<origin>, and
+the default branch is C<master>.

 =back

@@ -572,6 +585,12 @@ B<fetch> followed by B<merge>.

 =over 8

+=item B<clone> repository
+
+Create a local nmbug repository from a remote source.  This wraps
+C<git clone>, adding some options to avoid creating a working tree
+while preserving remote-tracking branches and upstreams.
+
 =item B<checkout>

 Update the notmuch database from git. This is mainly useful to discard
@@ -589,12 +608,12 @@ print help [for subcommand]
 =item B<log> [parameters]

 A simple wrapper for git log. After running C<nmbug fetch>, you can
-inspect the changes with C<nmbug log HEAD..FETCH_HEAD>
+inspect the changes with C<nmbug log HEAD..@{upstream}>

-=item B<merge>
+=item B<merge> [commit]

-Merge changes from FETCH_HEAD into HEAD, and load the result into
-notmuch.
+Merge changes from C<commit> into HEAD, and load the result into
+notmuch.  The default commit is C<@{upstream}>.

 =item  B<status>

-- 
1.8.5.2.8.g0f6c0d1

Reply via email to