diff --git a/.github/workflows/binaries.yml b/.github/workflows/binaries.yml
index c247088..7fc1cec 100644
--- a/.github/workflows/binaries.yml
+++ b/.github/workflows/binaries.yml
@@ -42,7 +42,8 @@ jobs:
           - os: windows-latest
             asmnasm: C:\Users\runneradmin\nasm\nasm
             output: sointu-track.exe
-            params: -ldflags -H=windowsgui cmd/sointu-track/main.go
+            params: cmd/sointu-track/main.go
+            ldflags: -H=windowsgui
           - os: windows-latest
             asmnasm: C:\Users\runneradmin\nasm\nasm
             output: sointu-compile.exe
@@ -50,7 +51,8 @@ jobs:
           - os: windows-latest
             asmnasm: C:\Users\runneradmin\nasm\nasm
             output: sointu-track-native.exe
-            params: -ldflags -H=windowsgui -tags=native cmd/sointu-track/main.go
+            params: -tags=native cmd/sointu-track/main.go
+            ldflags: -H=windowsgui
           - os: windows-latest
             asmnasm: C:\Users\runneradmin\nasm\nasm
             output: sointu-vsti.dll
@@ -103,6 +105,8 @@ jobs:
         length: 7
     - uses: lukka/get-cmake@latest
     - uses: actions/checkout@v4
+      with:
+        fetch-depth: 0
     - uses: actions/setup-go@v5 # has to be after checkout, see https://medium.com/@s0k0mata/github-actions-and-go-the-new-cache-feature-in-actions-setup-go-v4-and-what-to-watch-out-for-aeea373ed07d
       with:
         go-version: '>=1.21.0'
@@ -122,7 +126,7 @@ jobs:
         ninja sointu
     - name: Build binary
       run: |
-        go build -o ${{ matrix.config.output }} ${{ matrix.config.params }}
+        go build -ldflags "-X github.com/vsariola/sointu/version.Version=$(git describe) ${{ matrix.config.ldflags}}" -o ${{ matrix.config.output }} ${{ matrix.config.params }}
     - name: Upload binary
       uses: actions/upload-artifact@v4
       with:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index b2d849d..f559514 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3,6 +3,12 @@ All notable changes to this project will be documented in this file.
 
 The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
 
+## [Unreleased]
+### Added
+- Include version info in the binaries, as given be `git describe`. This version
+  info is shown as a label in the tracker and can be checked with `-v` flag in
+  the command line tools.
+
 ## [0.4.1]
 ### Added
 - Clicking the parameter slider also selects that parameter ([#112][i112])
diff --git a/cmd/sointu-compile/main.go b/cmd/sointu-compile/main.go
index f5313b3..90480d0 100644
--- a/cmd/sointu-compile/main.go
+++ b/cmd/sointu-compile/main.go
@@ -14,6 +14,7 @@ import (
 	"gopkg.in/yaml.v3"
 
 	"github.com/vsariola/sointu"
+	"github.com/vsariola/sointu/version"
 	"github.com/vsariola/sointu/vm/compiler"
 )
 
@@ -43,8 +44,13 @@ func main() {
 	targetArch := flag.String("arch", runtime.GOARCH, "Target architecture. Defaults to OS architecture. Possible values: 386, amd64, wasm")
 	output16bit := flag.Bool("i", false, "Compiled song should output 16-bit integers, instead of floats.")
 	targetOs := flag.String("os", runtime.GOOS, "Target OS. Defaults to current OS. Possible values: windows, darwin, linux. Anything else is assumed linuxy. Ignored when targeting wasm.")
+	versionFlag := flag.Bool("v", false, "Print version.")
 	flag.Usage = printUsage
 	flag.Parse()
+	if *versionFlag {
+		fmt.Println(version.VersionOrHash)
+		os.Exit(0)
+	}
 	if (flag.NArg() == 0 && !*library) || *help {
 		flag.Usage()
 		os.Exit(0)
diff --git a/cmd/sointu-play/main.go b/cmd/sointu-play/main.go
index bac4fb3..47714f2 100644
--- a/cmd/sointu-play/main.go
+++ b/cmd/sointu-play/main.go
@@ -13,6 +13,7 @@ import (
 
 	"github.com/vsariola/sointu"
 	"github.com/vsariola/sointu/oto"
+	"github.com/vsariola/sointu/version"
 	"github.com/vsariola/sointu/vm/compiler/bridge"
 )
 
@@ -27,8 +28,13 @@ func main() {
 	rawOut := flag.Bool("r", false, "Output the rendered song as .raw file. By default, saves stereo float32 buffer to disk.")
 	wavOut := flag.Bool("w", false, "Output the rendered song as .wav file. By default, saves stereo float32 buffer to disk.")
 	pcm := flag.Bool("c", false, "Convert audio to 16-bit signed PCM when outputting.")
+	versionFlag := flag.Bool("v", false, "Print version.")
 	flag.Usage = printUsage
 	flag.Parse()
+	if *versionFlag {
+		fmt.Println(version.VersionOrHash)
+		os.Exit(0)
+	}
 	if flag.NArg() == 0 || *help {
 		flag.Usage()
 		os.Exit(0)
diff --git a/tracker/gioui/songpanel.go b/tracker/gioui/songpanel.go
index 99e9d7c..8a673f9 100644
--- a/tracker/gioui/songpanel.go
+++ b/tracker/gioui/songpanel.go
@@ -9,6 +9,7 @@ import (
 	"gioui.org/unit"
 	"gioui.org/widget"
 	"github.com/vsariola/sointu/tracker"
+	"github.com/vsariola/sointu/version"
 	"golang.org/x/exp/shiny/materialdesign/icons"
 )
 
@@ -92,7 +93,7 @@ func (t *SongPanel) layoutMenuBar(gtx C, tr *Tracker) D {
 	gtx.Constraints.Max.Y = gtx.Dp(unit.Dp(36))
 	gtx.Constraints.Min.Y = gtx.Dp(unit.Dp(36))
 
-	return layout.Flex{Axis: layout.Horizontal}.Layout(gtx,
+	return layout.Flex{Axis: layout.Horizontal, Alignment: layout.End}.Layout(gtx,
 		layout.Rigid(tr.layoutMenu(gtx, "File", &t.MenuBar[0], &t.Menus[0], unit.Dp(200), t.fileMenuItems...)),
 		layout.Rigid(tr.layoutMenu(gtx, "Edit", &t.MenuBar[1], &t.Menus[1], unit.Dp(200), t.editMenuItems...)),
 	)
@@ -181,5 +182,10 @@ func (t *SongPanel) layoutSongOptions(gtx C, tr *Tracker) D {
 			)
 		}),
 		layout.Rigid(panicBtnStyle.Layout),
+		layout.Flexed(1, func(gtx C) D { return layout.Dimensions{Size: gtx.Constraints.Min} }),
+		layout.Rigid(func(gtx C) D {
+			labelStyle := LabelStyle{Text: version.VersionOrHash, FontSize: unit.Sp(12), Color: mediumEmphasisTextColor, Shaper: tr.Theme.Shaper}
+			return labelStyle.Layout(gtx)
+		}),
 	)
 }
diff --git a/version/version.go b/version/version.go
new file mode 100644
index 0000000..c31eafa
--- /dev/null
+++ b/version/version.go
@@ -0,0 +1,37 @@
+package version
+
+import "runtime/debug"
+
+// You can set the version at build time using something like:
+// go build -ldflags "-X github.com/vsariola/sointu/version.Version=$(git describe --dirty)"
+
+var Version string
+
+var Hash = func() string {
+	if info, ok := debug.ReadBuildInfo(); ok {
+		modified := false
+		for _, setting := range info.Settings {
+			if setting.Key == "vcs.modified" && setting.Value == "true" {
+				modified = true
+				break
+			}
+		}
+		for _, setting := range info.Settings {
+			if setting.Key == "vcs.revision" {
+				shortHash := setting.Value[:7]
+				if modified {
+					return shortHash + "-dirty"
+				}
+				return shortHash
+			}
+		}
+	}
+	return ""
+}()
+
+var VersionOrHash = func() string {
+	if Version != "" {
+		return Version
+	}
+	return Hash
+}()