/ast-log

Just like `git log -p` but for an ast node (function, method, class, ...)

Primary LanguageGo

AST log

Just like git log -p but for an ast node (function, method, class, ...).

The difference from git log -L start,end:file it traces changes based on tree diff instead of text diff.

Usage

ast-log -r <repo-path> -f <file-path>
# find node id in the output

ast-log -r <repo-path> -f <file-path> --id <node-id>

Dependencies

Currently the command depends on bblfshd and expects the server running on 0.0.0.0:9432.

Example output

$ go run main.go -r /Users/smacker/go/src/gopkg.in/src-d/go-git.v4 -f repository.go --id 2611
commit 02335b10dee417d0338bf6ea070feeead18e636b
Author: Jeremy Chambers <jeremy@thehipbot.com>
Date:   Sat Apr 07 14:34:39 2018 -0500

    config: adds branches to config for tracking branches against remotes, updates clone to track when cloning a branch. Fixes #313

    Signed-off-by: Jeremy Chambers <jeremy@thehipbot.com>


--- Original
+++ Current
@@ -51,5 +51,27 @@
 		}
 	}

-	return r.updateRemoteConfigIfNeeded(o, c, ref)
+	if err := r.updateRemoteConfigIfNeeded(o, c, ref); err != nil {
+		return err
+	}
+
+	if ref.Name().IsBranch() {
+		branchRef := ref.Name()
+		branchName := strings.Split(string(branchRef), "refs/heads/")[1]
+
+		b := &config.Branch{
+			Name:  branchName,
+			Merge: branchRef,
+		}
+		if o.RemoteName == "" {
+			b.Remote = "origin"
+		} else {
+			b.Remote = o.RemoteName
+		}
+		if err := r.CreateBranch(b); err != nil {
+			return err
+		}
+	}
+
+	return nil
 }

commit 591aed138177b27b08a90c90e6e074a6cf2dbd00
Author: Michael Rykov <mrykov@gmail.com>
Date:   Mon Jan 15 12:32:53 2018 -0800

    Support for clone without checkout

--- Original
+++ Current
@@ -23,7 +23,7 @@
 		return err
 	}

-	if r.wt != nil {
+	if r.wt != nil && !o.NoCheckout {
 		w, err := r.Worktree()
 		if err != nil {
 			return err

commit caa4dc4729e50e3a10ccd438d02d69fa20f9b766
Author: Máximo Cuadros <mcuadros@gmail.com>
Date:   Thu Nov 23 07:19:39 2017 +0100

    update to go-billy.v4 and go-git-fixtures.v3

    Signed-off-by: Máximo Cuadros <mcuadros@gmail.com>


--- Original
+++ Current
@@ -12,11 +12,12 @@
 		return err
 	}

-	head, err := r.fetchAndUpdateReferences(ctx, &FetchOptions{
+	ref, err := r.fetchAndUpdateReferences(ctx, &FetchOptions{
 		RefSpecs: r.cloneRefSpec(o, c),
 		Depth:    o.Depth,
 		Auth:     o.Auth,
 		Progress: o.Progress,
+		Tags:     o.Tags,
 	}, o.ReferenceName)
 	if err != nil {
 		return err
@@ -28,7 +29,15 @@
 			return err
 		}

-		if err := w.Reset(&ResetOptions{Commit: head.Hash()}); err != nil {
+		head, err := r.Head()
+		if err != nil {
+			return err
+		}
+
+		if err := w.Reset(&ResetOptions{
+			Mode:   MergeReset,
+			Commit: head.Hash(),
+		}); err != nil {
 			return err
 		}

@@ -42,5 +51,5 @@
 		}
 	}

-	return r.updateRemoteConfigIfNeeded(o, c, head)
+	return r.updateRemoteConfigIfNeeded(o, c, ref)
 }

commit e09fa242c1f97547527fa0cb9f6288f9ae17479e
Author: Máximo Cuadros <mcuadros@gmail.com>
Date:   Mon Nov 20 01:55:48 2017 +0100

    plumbing: object, commit.Parent() method

    Signed-off-by: Máximo Cuadros <mcuadros@gmail.com>


--- Original
+++ Current
@@ -12,12 +12,11 @@
 		return err
 	}

-	ref, err := r.fetchAndUpdateReferences(ctx, &FetchOptions{
+	head, err := r.fetchAndUpdateReferences(ctx, &FetchOptions{
 		RefSpecs: r.cloneRefSpec(o, c),
 		Depth:    o.Depth,
 		Auth:     o.Auth,
 		Progress: o.Progress,
-		Tags:     o.Tags,
 	}, o.ReferenceName)
 	if err != nil {
 		return err
@@ -29,15 +28,7 @@
 			return err
 		}

-		head, err := r.Head()
-		if err != nil {
-			return err
-		}
-
-		if err := w.Reset(&ResetOptions{
-			Mode:   MergeReset,
-			Commit: head.Hash(),
-		}); err != nil {
+		if err := w.Reset(&ResetOptions{Commit: head.Hash()}); err != nil {
 			return err
 		}

@@ -51,5 +42,5 @@
 		}
 	}

-	return r.updateRemoteConfigIfNeeded(o, c, ref)
+	return r.updateRemoteConfigIfNeeded(o, c, head)
 }

commit 7cdc44306dd1b3bba4a219bf3c40c5097a505a8e
Author: Máximo Cuadros <mcuadros@gmail.com>
Date:   Mon Sep 04 13:54:02 2017 +0200

    Repository.Clone added Tags option, and set by default AllTags as git does


--- Original
+++ Current
@@ -17,6 +17,7 @@
 		Depth:    o.Depth,
 		Auth:     o.Auth,
 		Progress: o.Progress,
+		Tags:     o.Tags,
 	}, o.ReferenceName)
 	if err != nil {
 		return err

commit f1e58e0d30095cf768ff04d379b5e4145a874be8
Author: Máximo Cuadros <mcuadros@gmail.com>
Date:   Fri Sep 01 17:26:52 2017 +0200

    Worktree.Reset ignore untracked files on Merge mode


--- Original
+++ Current
@@ -12,7 +12,7 @@
 		return err
 	}

-	head, err := r.fetchAndUpdateReferences(ctx, &FetchOptions{
+	ref, err := r.fetchAndUpdateReferences(ctx, &FetchOptions{
 		RefSpecs: r.cloneRefSpec(o, c),
 		Depth:    o.Depth,
 		Auth:     o.Auth,
@@ -28,7 +28,15 @@
 			return err
 		}

-		if err := w.Reset(&ResetOptions{Commit: head.Hash()}); err != nil {
+		head, err := r.Head()
+		if err != nil {
+			return err
+		}
+
+		if err := w.Reset(&ResetOptions{
+			Mode:   MergeReset,
+			Commit: head.Hash(),
+		}); err != nil {
 			return err
 		}

@@ -42,5 +50,5 @@
 		}
 	}

-	return r.updateRemoteConfigIfNeeded(o, c, head)
+	return r.updateRemoteConfigIfNeeded(o, c, ref)
 }

commit 5a7b7af0f793b1c25e9543e8511b767f3b739d67
Author: Miguel Molina <miguel@erizocosmi.co>
Date:   Thu Aug 24 17:35:38 2017 +0200

    dotgit: rewrite the way references are looked up
    Now there's only two ways of getting a reference, by checking under refs/ directory or in packed-refs. refs/ directory is checked using a direct read by reference name and packed refs are cached until they have been changed.

    Signed-off-by: Miguel Molina <miguel@erizocosmi.co>


--- Original
+++ Current
@@ -12,7 +12,7 @@
 		return err
 	}

-	ref, err := r.fetchAndUpdateReferences(ctx, &FetchOptions{
+	head, err := r.fetchAndUpdateReferences(ctx, &FetchOptions{
 		RefSpecs: r.cloneRefSpec(o, c),
 		Depth:    o.Depth,
 		Auth:     o.Auth,
@@ -24,11 +24,6 @@

 	if r.wt != nil {
 		w, err := r.Worktree()
-		if err != nil {
-			return err
-		}
-
-		head, err := r.Head()
 		if err != nil {
 			return err
 		}
@@ -47,5 +42,5 @@
 		}
 	}

-	return r.updateRemoteConfigIfNeeded(o, c, ref)
+	return r.updateRemoteConfigIfNeeded(o, c, head)
 }

commit 17cde59e5ced61adece4741b3a4da947f08fd9dc
Author: Ori Rawlings <orirawlings@gmail.com>
Date:   Wed Aug 23 22:39:25 2017 -0500

    repository: Resolve commit when cloning annotated tag, fixes #557


--- Original
+++ Current
@@ -12,7 +12,7 @@
 		return err
 	}

-	head, err := r.fetchAndUpdateReferences(ctx, &FetchOptions{
+	ref, err := r.fetchAndUpdateReferences(ctx, &FetchOptions{
 		RefSpecs: r.cloneRefSpec(o, c),
 		Depth:    o.Depth,
 		Auth:     o.Auth,
@@ -24,6 +24,11 @@

 	if r.wt != nil {
 		w, err := r.Worktree()
+		if err != nil {
+			return err
+		}
+
+		head, err := r.Head()
 		if err != nil {
 			return err
 		}
@@ -42,5 +47,5 @@
 		}
 	}

-	return r.updateRemoteConfigIfNeeded(o, c, head)
+	return r.updateRemoteConfigIfNeeded(o, c, ref)
 }

commit a0b45cc5508ae48b01799ca800e464888ed598be
Author: Josh Bleecher Snyder <josharian@gmail.com>
Date:   Thu Aug 03 16:46:57 2017 -0700

    plumbing/object: add Commit.FirstParent

    First parents are somewhat special in git.
    There's even a --first-parent flag to 'git log'.

    Add a helper method to look them up.
    This avoids boilerplate and spares the client from
    having to arrange for a handle to the Storer,
    which is stored in the unexported field Commit.s.




--- Original
+++ Current
@@ -5,7 +5,7 @@

 	c := &config.RemoteConfig{
 		Name: o.RemoteName,
-		URL:  o.URL,
+		URLs: []string{o.URL},
 	}

 	if _, err := r.CreateRemote(c); err != nil {

commit c128f5d680f59fd125cafd90f10e39eae5f3a135
Author: Jeremy Stribling <strib@keyba.se>
Date:   Mon Jul 31 15:34:45 2017 -0700

    plumbing: fix pack commands for the file client on Windows

    The default git install on Windows doesn't come with commands for
    receive-pack and upload-pack in the default $PATH.  Instead, use
    --exec-path to find pack executables in that case.


--- Original
+++ Current
@@ -5,7 +5,7 @@

 	c := &config.RemoteConfig{
 		Name: o.RemoteName,
-		URLs: []string{o.URL},
+		URL:  o.URL,
 	}

 	if _, err := r.CreateRemote(c); err != nil {

commit b29ccd9cf64cb3c6d7b3fdc6649d97416f3be734
Author: Manuel Carmona <manu.carmona90@gmail.com>
Date:   Thu Aug 03 09:41:22 2017 +0200

    *: windows support, some more fixes (#533)

    * fixed windows failed test: "134 FAIL: repository_test.go:340: RepositorySuite.TestPlainOpenBareRelativeGitDirFileTrailingGarbage"

    * fixed windows failed test: "143 FAIL: worktree_test.go:367: WorktreeSuite.TestCheckoutIndexOS"

    * fixed windows failed test: "296 FAIL: receive_pack_test.go:36: ReceivePackSuite.TearDownTest"

    * fixed windows failed test: "152 FAIL: worktree_test.go:278: WorktreeSuite.TestCheckoutSymlink"


--- Original
+++ Current
@@ -5,7 +5,7 @@

 	c := &config.RemoteConfig{
 		Name: o.RemoteName,
-		URL:  o.URL,
+		URLs: []string{o.URL},
 	}

 	if _, err := r.CreateRemote(c); err != nil {

commit 5c1a2ec798eb9b78d66b16fbbcbdc3b928d8b496
Author: Máximo Cuadros <mcuadros@gmail.com>
Date:   Wed Aug 02 17:28:02 2017 +0200

    worktree: normalized string comparison tests


--- Original
+++ Current
@@ -5,7 +5,7 @@

 	c := &config.RemoteConfig{
 		Name: o.RemoteName,
-		URLs: []string{o.URL},
+		URL:  o.URL,
 	}

 	if _, err := r.CreateRemote(c); err != nil {

commit 595de2b38d0cee2e0bc92e1a0559f16ccca851dc
Author: Máximo Cuadros <mcuadros@gmail.com>
Date:   Wed Aug 02 14:26:58 2017 +0200

    Remote.Clone fix clone of tags in shallow mode


--- Original
+++ Current
@@ -5,7 +5,7 @@

 	c := &config.RemoteConfig{
 		Name: o.RemoteName,
-		URL:  o.URL,
+		URLs: []string{o.URL},
 	}

 	if _, err := r.CreateRemote(c); err != nil {
@@ -33,7 +33,10 @@
 		}

 		if o.RecurseSubmodules != NoRecurseSubmodules {
-			if err := w.updateSubmodules(o.RecurseSubmodules); err != nil {
+			if err := w.updateSubmodules(&SubmoduleUpdateOptions{
+				RecurseSubmodules: o.RecurseSubmodules,
+				Auth:              o.Auth,
+			}); err != nil {
 				return err
 			}
 		}

commit 171b3a73e7ab7015f9eb8e98965e36dfb8ea9599
Author: Máximo Cuadros <mcuadros@gmail.com>
Date:   Wed Aug 02 13:00:31 2017 +0200

    plumbing: moved `Reference.Is*` methods to `ReferenceName.Is*`


--- Original
+++ Current
@@ -5,7 +5,7 @@

 	c := &config.RemoteConfig{
 		Name: o.RemoteName,
-		URLs: []string{o.URL},
+		URL:  o.URL,
 	}

 	if _, err := r.CreateRemote(c); err != nil {

commit 9488c59834f6a2591910b7b360721cec2c16c548
Author: Santiago M. Mola <santi@mola.io>
Date:   Mon Jul 24 10:51:01 2017 +0200

    config: multiple values in RemoteConfig (URLs and Fetch)

    * Change `URL string` to `URL []string` in `RemoteConfig`, since
      git allows multiple URLs per remote. See:
      http://marc.info/?l=git&m=116231242118202&w=2

    * Fix marshalling of multiple fetch refspecs.


--- Original
+++ Current
@@ -5,7 +5,7 @@

 	c := &config.RemoteConfig{
 		Name: o.RemoteName,
-		URL:  o.URL,
+		URLs: []string{o.URL},
 	}

 	if _, err := r.CreateRemote(c); err != nil {
@@ -33,10 +33,7 @@
 		}

 		if o.RecurseSubmodules != NoRecurseSubmodules {
-			if err := w.updateSubmodules(&SubmoduleUpdateOptions{
-				RecurseSubmodules: o.RecurseSubmodules,
-				Auth:              o.Auth,
-			}); err != nil {
+			if err := w.updateSubmodules(o.RecurseSubmodules); err != nil {
 				return err
 			}
 		}

commit 63b30fba572b7e70833fae4785c6d22f167c6641
Author: Devon Barrett <devon@devonbarrett.net>
Date:   Sat Jul 29 14:12:57 2017 +0200

    reuse Auth method when recursing submodules, fixes #521


--- Original
+++ Current
@@ -33,7 +33,10 @@
 		}

 		if o.RecurseSubmodules != NoRecurseSubmodules {
-			if err := w.updateSubmodules(o.RecurseSubmodules); err != nil {
+			if err := w.updateSubmodules(&SubmoduleUpdateOptions{
+				RecurseSubmodules: o.RecurseSubmodules,
+				Auth:              o.Auth,
+			}); err != nil {
 				return err
 			}
 		}

commit ab590eb89849a0319b8c5a4d7fd980137da7180d
Author: Máximo Cuadros <mcuadros@gmail.com>
Date:   Wed Jul 26 21:46:49 2017 +0200

    worktree: expose underlying filesystem


--- Original
+++ Current
@@ -1,4 +1,4 @@
-func (r *Repository) clone(o *CloneOptions) error {
+func (r *Repository) clone(ctx context.Context, o *CloneOptions) error {
 	if err := o.Validate(); err != nil {
 		return err
 	}
@@ -12,7 +12,7 @@
 		return err
 	}

-	head, err := r.fetchAndUpdateReferences(&FetchOptions{
+	head, err := r.fetchAndUpdateReferences(ctx, &FetchOptions{
 		RefSpecs: r.cloneRefSpec(o, c),
 		Depth:    o.Depth,
 		Auth:     o.Auth,

commit c64eb817d5e5cbaec10dea1342e1ec95721e886b
Author: Santiago M. Mola <santi@mola.io>
Date:   Tue Jul 25 10:08:36 2017 +0200

    packfile: create packfile.Index and reuse it

    There was an internal type (i.e. storage/filesystem.idx) to
    use as in-memory index for packfiles. This was not convenient
    to reuse in the packfile.

    This commit creates a new representation (format/packfile.Index)
    that can be converted to and from idxfile.Idxfile.

    A packfile.Index now contains the functionality that was scattered
    on storage/filesystem.idx and packfile.Decoder's internals.

    storage/filesystem now reuses packfile.Index instances and this
    also results in higher cache hit ratios when resolving deltas.


--- Original
+++ Current
@@ -1,4 +1,4 @@
-func (r *Repository) clone(ctx context.Context, o *CloneOptions) error {
+func (r *Repository) clone(o *CloneOptions) error {
 	if err := o.Validate(); err != nil {
 		return err
 	}
@@ -12,7 +12,7 @@
 		return err
 	}

-	head, err := r.fetchAndUpdateReferences(ctx, &FetchOptions{
+	head, err := r.fetchAndUpdateReferences(&FetchOptions{
 		RefSpecs: r.cloneRefSpec(o, c),
 		Depth:    o.Depth,
 		Auth:     o.Auth,

commit 064051f972e90dd55e6c941f04b58b4a36dfedf1
Author: Máximo Cuadros <mcuadros@gmail.com>
Date:   Wed Jul 26 06:24:47 2017 +0200

    *: package context support in Repository, Remote and Submodule


--- Original
+++ Current
@@ -1 +1,43 @@
+func (r *Repository) clone(ctx context.Context, o *CloneOptions) error {
+	if err := o.Validate(); err != nil {
+		return err
+	}

+	c := &config.RemoteConfig{
+		Name: o.RemoteName,
+		URL:  o.URL,
+	}
+
+	if _, err := r.CreateRemote(c); err != nil {
+		return err
+	}
+
+	head, err := r.fetchAndUpdateReferences(ctx, &FetchOptions{
+		RefSpecs: r.cloneRefSpec(o, c),
+		Depth:    o.Depth,
+		Auth:     o.Auth,
+		Progress: o.Progress,
+	}, o.ReferenceName)
+	if err != nil {
+		return err
+	}
+
+	if r.wt != nil {
+		w, err := r.Worktree()
+		if err != nil {
+			return err
+		}
+
+		if err := w.Reset(&ResetOptions{Commit: head.Hash()}); err != nil {
+			return err
+		}
+
+		if o.RecurseSubmodules != NoRecurseSubmodules {
+			if err := w.updateSubmodules(o.RecurseSubmodules); err != nil {
+				return err
+			}
+		}
+	}
+
+	return r.updateRemoteConfigIfNeeded(o, c, head)
+}

Known issues & TODO

  • Performance

    It works slow as hell. Timing for the log above:

    Total time	43.952412822s	100%
    Go-git operations time	11.821716895s	26%
    Bblfsh parsing time	28.499216239s	64%
    Gum matching time	3.566183643s	8%
    

    Possible solution could be to switch to tree-sitter which is much faster than bblfsh and the tool can take advantage of incremental parsing. Then take a look why go-git operations are so slow and optimize them.

  • Lack of human interface for choosing target node

    Possible solution could be to accept line:char and suggest to choose a node on at this position.

  • Incorrect matching

    In some cases the node can be match "incorrectly" (according to human expectations).

    Possible solution could be to tune ast diff algorithm for this particular case.

Thanks